Integrate product-ws voice demo on port 8000 alongside REST API.
Add src/voice Pipecat pipeline, browser demo at /voice-demo, and config/voice.json. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
158
static/voice-demo/index.html
Normal file
158
static/voice-demo/index.html
Normal file
@@ -0,0 +1,158 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>VA Voice Chat — /ws-product</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main class="app">
|
||||
<header class="app__header">
|
||||
<div class="brand">
|
||||
<span class="brand__dot" aria-hidden="true"></span>
|
||||
<h1>VA Voice Chat</h1>
|
||||
</div>
|
||||
|
||||
<div class="connection">
|
||||
<label class="connection__field">
|
||||
<span>WebSocket URL</span>
|
||||
<input
|
||||
id="ws-url"
|
||||
type="text"
|
||||
placeholder="ws://host/ws-product"
|
||||
spellcheck="false"
|
||||
autocomplete="off"
|
||||
/>
|
||||
</label>
|
||||
<button id="connect-btn" class="btn btn--primary" type="button">
|
||||
Connect
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="status">
|
||||
<span id="status-dot" class="status__dot status__dot--idle"></span>
|
||||
<span id="status-text" class="status__text">Disconnected</span>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="app__body">
|
||||
<div class="app__main">
|
||||
<section class="chat" aria-label="Conversation history">
|
||||
<div id="chat-log" class="chat__log" role="log" aria-live="polite">
|
||||
<div class="chat__empty">
|
||||
<p>Connect to the engine, enable your mic, and start talking.</p>
|
||||
<p class="chat__hint">
|
||||
Audio is streamed as PCM16 mono @ 16 kHz over
|
||||
<code>/ws-product</code>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<footer class="controls" aria-label="Chat controls">
|
||||
<div class="meter" aria-hidden="true">
|
||||
<div id="meter-fill" class="meter__fill"></div>
|
||||
</div>
|
||||
|
||||
<form id="composer" class="composer" autocomplete="off">
|
||||
<textarea
|
||||
id="text-input"
|
||||
class="composer__input"
|
||||
rows="1"
|
||||
placeholder="Type a message, or use the mic…"
|
||||
disabled
|
||||
></textarea>
|
||||
<button
|
||||
id="send-btn"
|
||||
class="btn btn--primary composer__send"
|
||||
type="submit"
|
||||
disabled
|
||||
title="Send message (Enter)"
|
||||
>
|
||||
Send
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<div class="controls__row">
|
||||
<label class="device-picker">
|
||||
<span class="device-picker__label">Microphone</span>
|
||||
<select id="mic-select" class="device-picker__select" disabled>
|
||||
<option value="">Default microphone</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<button
|
||||
id="mic-btn"
|
||||
class="mic-btn"
|
||||
type="button"
|
||||
disabled
|
||||
aria-pressed="false"
|
||||
title="Mic is off"
|
||||
>
|
||||
<svg
|
||||
class="mic-btn__icon"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
height="24"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M12 14a3 3 0 0 0 3-3V6a3 3 0 1 0-6 0v5a3 3 0 0 0 3 3Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
<path
|
||||
d="M19 11a1 1 0 1 0-2 0 5 5 0 0 1-10 0 1 1 0 1 0-2 0 7 7 0 0 0 6 6.92V21a1 1 0 1 0 2 0v-3.08A7 7 0 0 0 19 11Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<span class="mic-btn__label">Enable mic</span>
|
||||
</button>
|
||||
|
||||
<div class="indicators">
|
||||
<span id="mic-indicator" class="indicator">
|
||||
<span class="indicator__dot indicator__dot--mic"></span>
|
||||
<span class="indicator__label">Mic</span>
|
||||
</span>
|
||||
<span id="bot-indicator" class="indicator">
|
||||
<span class="indicator__dot indicator__dot--bot"></span>
|
||||
<span class="indicator__label">Bot</span>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<button id="clear-btn" class="btn btn--ghost" type="button">
|
||||
Clear
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<p class="hint">
|
||||
Press <kbd>Enter</kbd> to send, <kbd>Shift</kbd>+<kbd>Enter</kbd>
|
||||
for newline. Sending text will interrupt the bot if it's speaking.
|
||||
Browser echo cancellation is on; use headphones if echo persists.
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<section class="ws-log" aria-label="WebSocket log">
|
||||
<div class="ws-log__header">
|
||||
<div class="ws-log__header-left">
|
||||
<h2>WebSocket Log</h2>
|
||||
<div class="ws-log__legend" aria-hidden="true">
|
||||
<span class="ws-log__legend-item ws-log__legend-item--send">Send</span>
|
||||
<span class="ws-log__legend-item ws-log__legend-item--recv">Recv</span>
|
||||
</div>
|
||||
</div>
|
||||
<button id="clear-ws-log-btn" class="btn btn--ghost" type="button">
|
||||
Clear log
|
||||
</button>
|
||||
</div>
|
||||
<div id="ws-log" class="ws-log__body" role="log" aria-live="polite">
|
||||
<div class="ws-log__empty">No websocket events yet.</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<script type="module" src="./app.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user