@mooncompany/uplink-chat 0.5.2 → 0.32.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +14 -1
- package/README.md +105 -3
- package/bin/uplink.js +3 -0
- package/middleware/error-handler.js +1 -0
- package/package.json +89 -5
- package/public/css/agents.1fd7567a.css +1499 -0
- package/public/css/app.bc7e7484.css +2819 -0
- package/public/css/artifacts.css +488 -0
- package/public/css/commands.css +77 -0
- package/public/css/connection.css +131 -0
- package/public/css/cron-panel.css +364 -0
- package/public/css/dashboard.css +233 -0
- package/public/css/developer.css +342 -0
- package/public/css/files.css +123 -0
- package/public/css/markdown.css +156 -0
- package/public/css/message-actions.css +285 -0
- package/public/css/mobile.css +614 -0
- package/public/css/panels-unified.css +485 -0
- package/public/css/premium.css +415 -0
- package/public/css/realtime.css +189 -0
- package/public/css/satellites.7fa72088.css +632 -0
- package/public/css/settings-redesign.css +1322 -0
- package/public/css/shortcuts.css +185 -0
- package/public/css/split-view.4bc23474.css +858 -0
- package/public/css/themes.css +387 -0
- package/public/css/timestamps.css +54 -0
- package/public/css/variables.css +81 -0
- package/public/dist/bundle.493af136.js +1 -0
- package/public/favicon-256.png +0 -0
- package/public/icon-192.png +0 -0
- package/public/icon-512.png +0 -0
- package/public/img/icons/icon-alert-triangle.svg +17 -0
- package/public/img/icons/icon-brain.svg +20 -0
- package/public/img/icons/icon-brand-python.svg +19 -0
- package/public/img/icons/icon-camera.svg +16 -0
- package/public/img/icons/icon-chart-bar.svg +18 -0
- package/public/img/icons/icon-check.svg +15 -0
- package/public/img/icons/icon-circle-check.svg +16 -0
- package/public/img/icons/icon-clipboard.svg +16 -0
- package/public/img/icons/icon-cloud.svg +15 -0
- package/public/img/icons/icon-confetti.svg +24 -0
- package/public/img/icons/icon-device-mobile.svg +17 -0
- package/public/img/icons/icon-diamond.svg +16 -0
- package/public/img/icons/icon-file-text.svg +19 -0
- package/public/img/icons/icon-file-type-css.svg +19 -0
- package/public/img/icons/icon-file-type-csv.svg +19 -0
- package/public/img/icons/icon-file-type-doc.svg +19 -0
- package/public/img/icons/icon-file-type-html.svg +23 -0
- package/public/img/icons/icon-file-type-js.svg +18 -0
- package/public/img/icons/icon-file-type-pdf.svg +20 -0
- package/public/img/icons/icon-file-zip.svg +22 -0
- package/public/img/icons/icon-file.svg +16 -0
- package/public/img/icons/icon-folder.svg +15 -0
- package/public/img/icons/icon-headphones.svg +17 -0
- package/public/img/icons/icon-hourglass.svg +18 -0
- package/public/img/icons/icon-keyboard.svg +22 -0
- package/public/img/icons/icon-link.svg +17 -0
- package/public/img/icons/icon-lock-open.svg +17 -0
- package/public/img/icons/icon-lock.svg +17 -0
- package/public/img/icons/icon-mail.svg +16 -0
- package/public/img/icons/icon-message-dots.svg +18 -0
- package/public/img/icons/icon-microphone-2.svg +16 -0
- package/public/img/icons/icon-microphone.svg +18 -0
- package/public/img/icons/icon-movie.svg +22 -0
- package/public/img/icons/icon-music.svg +18 -0
- package/public/img/icons/icon-palette.svg +18 -0
- package/public/img/icons/icon-paperclip.svg +15 -0
- package/public/img/icons/icon-pencil.svg +16 -0
- package/public/img/icons/icon-photo.svg +18 -0
- package/public/img/icons/icon-presentation.svg +19 -0
- package/public/img/icons/icon-robot.svg +23 -0
- package/public/img/icons/icon-rocket.svg +17 -0
- package/public/img/icons/icon-satellite.svg +20 -0
- package/public/img/icons/icon-settings.svg +16 -0
- package/public/img/icons/icon-shield-lock.svg +17 -0
- package/public/img/icons/icon-sparkles.svg +15 -0
- package/public/img/icons/icon-star-filled.svg +11 -0
- package/public/img/icons/icon-tool.svg +15 -0
- package/public/img/icons/icon-trash.svg +19 -0
- package/public/img/icons/icon-volume.svg +17 -0
- package/public/img/icons/icon-world.svg +19 -0
- package/public/img/icons/icon-x.svg +16 -0
- package/public/img/logo.svg +13 -0
- package/public/img/wordmark.svg +35 -0
- package/public/index.html +1195 -0
- package/public/js/agents-data.js +1 -0
- package/public/js/agents-ui.js +1 -0
- package/public/js/agents.js +1 -0
- package/public/js/app.js +1 -0
- package/public/js/appearance-settings.js +1 -0
- package/public/js/artifacts.js +1 -0
- package/public/js/audio-pcm-processor.js +1 -0
- package/public/js/audio-queue.js +1 -0
- package/public/js/bootstrap.js +1 -0
- package/public/js/chat.js +1 -0
- package/public/js/commands.js +1 -0
- package/public/js/connection-api.js +1 -0
- package/public/js/connection.js +1 -0
- package/public/js/context-tracker.js +1 -0
- package/public/js/core.js +1 -0
- package/public/js/cron-panel.js +1 -0
- package/public/js/dashboard.js +1 -0
- package/public/js/developer.js +1 -0
- package/public/js/encryption.js +1 -0
- package/public/js/errors.js +1 -0
- package/public/js/event-bus.js +1 -0
- package/public/js/fetch-utils.js +1 -0
- package/public/js/file-handler.js +1 -0
- package/public/js/files.js +1 -0
- package/public/js/gateway-chat.js +1 -0
- package/public/js/logger.js +1 -0
- package/public/js/markdown.js +1 -0
- package/public/js/message-actions.js +1 -0
- package/public/js/message-renderer.js +1 -0
- package/public/js/missed-messages.js +1 -0
- package/public/js/mobile-debug.js +1 -0
- package/public/js/notifications.js +1 -0
- package/public/js/offline-queue.js +1 -0
- package/public/js/onboarding.js +1 -0
- package/public/js/panels.js +1 -0
- package/public/js/premium.js +1 -0
- package/public/js/primary-header.js +1 -0
- package/public/js/realtime-voice.js +1 -0
- package/public/js/satellite-sync.js +1 -0
- package/public/js/satellite-ui.js +1 -0
- package/public/js/satellites.js +1 -0
- package/public/js/settings.js +1 -0
- package/public/js/shortcuts.js +1 -0
- package/public/js/split-chat.js +1 -0
- package/public/js/split-resize.js +1 -0
- package/public/js/splitview.js +1 -0
- package/public/js/storage.js +1 -0
- package/public/js/streaming-handler.js +1 -0
- package/public/js/stt-settings.js +1 -0
- package/public/js/themes.js +1 -0
- package/public/js/timestamps.js +1 -0
- package/public/js/tts-settings.js +1 -0
- package/public/js/ui.js +1 -0
- package/public/js/update-notifier.js +1 -0
- package/public/js/utils/constants.js +1 -0
- package/public/js/utils/icons.js +1 -0
- package/public/js/utils/sanitize.js +1 -0
- package/public/js/utils/sse-parser.js +1 -0
- package/public/js/vad.js +1 -0
- package/public/js/vendor/dompurify.min.js +2 -0
- package/public/js/voice-settings-v2.js +1 -0
- package/public/js/voice.js +1 -0
- package/public/manifest.json +66 -0
- package/public/moon_texture.jpg +0 -0
- package/public/sw.js +1 -0
- package/public/three.min.js +6 -0
- package/public/u-icon.png +0 -0
- package/server/channel.js +1 -0
- package/server/chat.js +1 -0
- package/server/config-store.js +1 -0
- package/server/config.js +1 -0
- package/server/context.js +1 -0
- package/server/gateway-api-proxy.js +1 -0
- package/server/gateway-commands.js +1 -0
- package/server/gateway-proxy.js +1 -0
- package/server/index.js +1 -0
- package/server/logger.js +1 -0
- package/server/message-store.js +1 -0
- package/server/middleware/auth.js +1 -0
- package/server/middleware.js +1 -0
- package/server/openclaw-discover.js +1 -0
- package/server/premium/index.js +1 -0
- package/server/premium/license.js +1 -0
- package/server/realtime/bridge.js +1 -0
- package/server/realtime/index.js +1 -0
- package/server/realtime/tts-stream.js +1 -0
- package/server/routes/agents.js +1 -0
- package/server/routes/artifacts.js +1 -0
- package/server/routes/chat.js +1 -0
- package/server/routes/config-settings.js +1 -0
- package/server/routes/config.js +1 -0
- package/server/routes/cron.js +1 -0
- package/server/routes/files.js +1 -0
- package/server/routes/index.js +1 -0
- package/server/routes/media.js +1 -0
- package/server/routes/missed-messages.js +1 -0
- package/server/routes/premium.js +1 -0
- package/server/routes/push.js +1 -0
- package/server/routes/satellite.js +1 -0
- package/server/routes/status.js +1 -0
- package/server/routes/stt.js +1 -0
- package/server/routes/voice.js +1 -0
- package/server/routes/webhooks.js +1 -0
- package/server/routes.js +1 -0
- package/server/runtime-config.js +1 -0
- package/server/share.js +1 -0
- package/server/stt/faster-whisper.js +1 -0
- package/server/stt/groq.js +1 -0
- package/server/stt/index.js +1 -0
- package/server/stt/openai.js +1 -0
- package/server/sync.js +1 -0
- package/server/tailscale-https.js +1 -0
- package/server/tts.js +1 -0
- package/server/update-checker.js +1 -0
- package/server/utils/filename.js +1 -0
- package/server/utils.js +1 -0
- package/server/watchdog.js +3 -0
- package/server/websocket/broadcast.js +1 -0
- package/server/websocket/connections.js +1 -0
- package/server/websocket/index.js +1 -0
- package/server/websocket/routing.js +1 -0
- package/server/websocket/sync.js +1 -0
- package/server.js +1 -0
- package/utils/detect-tool-usage.js +1 -0
- package/utils/errors.js +1 -0
- package/utils/html-escape.js +1 -0
- package/utils/id-sanitize.js +1 -0
- package/utils/response.js +1 -0
- package/utils/with-retry.js +1 -0
- package/index.js +0 -2
|
@@ -0,0 +1,1195 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
|
6
|
+
<meta name="mobile-web-app-capable" content="yes">
|
|
7
|
+
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
8
|
+
<meta name="theme-color" content="#000000">
|
|
9
|
+
<meta name="apple-mobile-web-app-status-bar-style" content="black">
|
|
10
|
+
<link rel="icon" type="image/png" href="/u-icon.png">
|
|
11
|
+
<link rel="apple-touch-icon" sizes="192x192" href="/icon-192.png?v=2">
|
|
12
|
+
<link rel="apple-touch-icon" sizes="512x512" href="/icon-512.png?v=2">
|
|
13
|
+
<link rel="manifest" href="/manifest.json">
|
|
14
|
+
<title>Uplink</title>
|
|
15
|
+
<link href="https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;500;600;700&family=Space+Mono:wght@400;700&display=swap" rel="stylesheet">
|
|
16
|
+
<script src="/three.min.js"></script>
|
|
17
|
+
<link rel="stylesheet" href="/css/variables.css">
|
|
18
|
+
<link rel="stylesheet" href="/css/app.bc7e7484.css">
|
|
19
|
+
<link rel="stylesheet" href="/css/commands.css">
|
|
20
|
+
<link rel="stylesheet" href="/css/developer.css">
|
|
21
|
+
<link rel="stylesheet" href="/css/agents.1fd7567a.css">
|
|
22
|
+
<!-- waveform.css removed: replaced by audio-player-bar -->
|
|
23
|
+
<link rel="stylesheet" href="/css/dashboard.css">
|
|
24
|
+
<link rel="stylesheet" href="/css/files.css">
|
|
25
|
+
<link rel="stylesheet" href="/css/themes.css">
|
|
26
|
+
<link rel="stylesheet" href="/css/premium.css">
|
|
27
|
+
<link rel="stylesheet" href="/css/shortcuts.css">
|
|
28
|
+
<link rel="stylesheet" href="/css/timestamps.css">
|
|
29
|
+
<link rel="stylesheet" href="/css/markdown.css">
|
|
30
|
+
<link rel="stylesheet" href="/css/connection.css">
|
|
31
|
+
<link rel="stylesheet" href="/css/satellites.7fa72088.css">
|
|
32
|
+
<link rel="stylesheet" href="/css/panels-unified.css">
|
|
33
|
+
<link rel="stylesheet" href="/css/message-actions.css">
|
|
34
|
+
<link rel="stylesheet" href="/css/split-view.4bc23474.css">
|
|
35
|
+
<link rel="stylesheet" href="/css/mobile.css">
|
|
36
|
+
<link rel="stylesheet" href="/css/artifacts.css">
|
|
37
|
+
<link rel="stylesheet" href="/css/cron-panel.css">
|
|
38
|
+
<link rel="stylesheet" href="/css/realtime.css">
|
|
39
|
+
<link rel="stylesheet" href="/css/settings-redesign.css?v=2">
|
|
40
|
+
|
|
41
|
+
<!-- Mobile debug panel - uncomment to enable
|
|
42
|
+
<script src="/js/mobile-debug.js"></script>
|
|
43
|
+
-->
|
|
44
|
+
<!-- cache-bust: v20260205075805 -->
|
|
45
|
+
<!-- Apply theme before render to prevent flash — CSS-only fallback + JS enhancement -->
|
|
46
|
+
<style id="theme-flash-guard">
|
|
47
|
+
/* Hide body until theme is applied — JS removes this immediately */
|
|
48
|
+
html:not([data-theme]) body { visibility: hidden; }
|
|
49
|
+
</style>
|
|
50
|
+
<script>
|
|
51
|
+
(function() {
|
|
52
|
+
try {
|
|
53
|
+
var s = JSON.parse(localStorage.getItem('uplink-settings') || '{}');
|
|
54
|
+
if (s.theme) {
|
|
55
|
+
document.documentElement.setAttribute('data-theme', s.theme);
|
|
56
|
+
} else {
|
|
57
|
+
document.documentElement.setAttribute('data-theme', 'midnight');
|
|
58
|
+
}
|
|
59
|
+
} catch(e) {
|
|
60
|
+
document.documentElement.setAttribute('data-theme', 'midnight');
|
|
61
|
+
}
|
|
62
|
+
})();
|
|
63
|
+
</script>
|
|
64
|
+
<script src="js/vendor/dompurify.min.js"></script>
|
|
65
|
+
</head>
|
|
66
|
+
<body>
|
|
67
|
+
<!-- Banner killer: removes reconnection banner + paddingTop from any cached JS version -->
|
|
68
|
+
<script>
|
|
69
|
+
(function(){
|
|
70
|
+
var k=function(){
|
|
71
|
+
var b=document.getElementById('reconnection-banner');
|
|
72
|
+
if(b){b.remove();document.body.style.paddingTop='';}
|
|
73
|
+
};
|
|
74
|
+
k();
|
|
75
|
+
var o=new MutationObserver(k);
|
|
76
|
+
o.observe(document.body||document.documentElement,{childList:true,subtree:true});
|
|
77
|
+
setTimeout(function(){o.disconnect();},30000);
|
|
78
|
+
})();
|
|
79
|
+
</script>
|
|
80
|
+
<!-- Skip link for screen readers -->
|
|
81
|
+
<a href="#messages" class="skip-link">Skip to main content</a>
|
|
82
|
+
|
|
83
|
+
<!-- Onboarding Screen -->
|
|
84
|
+
<div class="overlay-screen" id="onboardingScreen">
|
|
85
|
+
<div class="overlay-card">
|
|
86
|
+
<div class="overlay-header">
|
|
87
|
+
<div class="overlay-logo"><img src="/img/logo.svg?v=2" width="120" height="120" alt="Uplink" aria-hidden="true"></div>
|
|
88
|
+
<h1 class="overlay-title">Uplink</h1>
|
|
89
|
+
<p class="overlay-subtitle">Connect to your AI assistant</p>
|
|
90
|
+
</div>
|
|
91
|
+
|
|
92
|
+
<div class="form-group">
|
|
93
|
+
<label class="form-label">Your Name</label>
|
|
94
|
+
<input type="text" class="form-input" id="onboardUserName" placeholder="Your name" autocomplete="off">
|
|
95
|
+
<p class="form-hint">How should your assistant address you?</p>
|
|
96
|
+
</div>
|
|
97
|
+
|
|
98
|
+
<div class="form-group">
|
|
99
|
+
<label class="form-label">Assistant Name</label>
|
|
100
|
+
<input type="text" class="form-input" id="onboardBotName" placeholder="Assistant" autocomplete="off">
|
|
101
|
+
<p class="form-hint">What should we call your assistant?</p>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
<div class="form-group">
|
|
105
|
+
<label class="form-label">Gateway URL</label>
|
|
106
|
+
<div class="url-input-group">
|
|
107
|
+
<input type="url" class="form-input" id="onboardGatewayUrl" placeholder="http://127.0.0.1:23248" autocomplete="off">
|
|
108
|
+
<span class="url-status" id="urlStatus"></span>
|
|
109
|
+
</div>
|
|
110
|
+
<p class="form-hint">Your OpenClaw gateway address</p>
|
|
111
|
+
<div class="setting-desc" style="font-size: 0.8rem; margin-top: 0.25rem; opacity: 0.7;">OpenClaw Gateway handles AI model routing. <a href="https://docs.openclaw.ai" target="_blank" rel="noopener" style="color: var(--accent-color, #60a5fa);">Learn more</a></div>
|
|
112
|
+
<p class="form-error" id="urlError"></p>
|
|
113
|
+
</div>
|
|
114
|
+
|
|
115
|
+
<div class="form-group">
|
|
116
|
+
<label class="form-label">Gateway Token</label>
|
|
117
|
+
<input type="password" class="form-input" id="onboardGatewayToken" placeholder="Your gateway authentication token" autocomplete="off">
|
|
118
|
+
<p class="form-hint">Found in your OpenClaw config.yaml</p>
|
|
119
|
+
</div>
|
|
120
|
+
|
|
121
|
+
<div class="encrypt-toggle-row">
|
|
122
|
+
<div>
|
|
123
|
+
<div class="encrypt-label">Voice responses</div>
|
|
124
|
+
<div class="encrypt-desc">Play audio when assistant replies</div>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="toggle on" id="onboardVoiceToggle" tabindex="0" role="switch" aria-checked="true" aria-label="Toggle voice responses"></div>
|
|
127
|
+
</div>
|
|
128
|
+
|
|
129
|
+
<div class="encrypt-toggle-row">
|
|
130
|
+
<div>
|
|
131
|
+
<div class="encrypt-label">Encrypt chat history</div>
|
|
132
|
+
<div class="encrypt-desc">Protect local messages with a password</div>
|
|
133
|
+
</div>
|
|
134
|
+
<div class="toggle" id="onboardEncryptToggle" tabindex="0" role="switch" aria-checked="false" aria-label="Toggle chat encryption"></div>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div class="password-fields" id="onboardPasswordFields">
|
|
138
|
+
<div class="form-group">
|
|
139
|
+
<label class="form-label">Password</label>
|
|
140
|
+
<input type="password" class="form-input" id="onboardPassword" placeholder="Enter password" autocomplete="new-password">
|
|
141
|
+
</div>
|
|
142
|
+
<div class="form-group">
|
|
143
|
+
<label class="form-label">Confirm Password</label>
|
|
144
|
+
<input type="password" class="form-input" id="onboardPasswordConfirm" placeholder="Confirm password" autocomplete="new-password">
|
|
145
|
+
<p class="form-error" id="passwordError"></p>
|
|
146
|
+
</div>
|
|
147
|
+
</div>
|
|
148
|
+
|
|
149
|
+
<button class="btn-primary" id="onboardSubmit">Get Started</button>
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
|
|
153
|
+
<!-- Unlock Screen -->
|
|
154
|
+
<div class="overlay-screen" id="unlockScreen">
|
|
155
|
+
<div class="overlay-card">
|
|
156
|
+
<div class="overlay-header">
|
|
157
|
+
<div class="overlay-logo"><img src="/img/logo.svg?v=2" width="120" height="120" alt="Uplink" aria-hidden="true"></div>
|
|
158
|
+
<h1 class="overlay-title" id="unlockBotName">Assistant</h1>
|
|
159
|
+
<p class="overlay-subtitle">Enter your encryption password to access your chat history</p>
|
|
160
|
+
</div>
|
|
161
|
+
|
|
162
|
+
<div class="form-group">
|
|
163
|
+
<input type="password" class="form-input" id="unlockPassword" placeholder="Password" autocomplete="current-password" aria-label="Password to unlock chat">
|
|
164
|
+
<p class="form-error" id="unlockError"></p>
|
|
165
|
+
</div>
|
|
166
|
+
|
|
167
|
+
<button class="btn-primary" id="unlockSubmit">Unlock</button>
|
|
168
|
+
|
|
169
|
+
<span class="forgot-link" id="forgotLink">Forgot password?</span>
|
|
170
|
+
<p class="setting-desc" style="color: var(--error);"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 9v4"/><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0"/><path d="M12 16h.01"/></svg> This will permanently delete all encrypted chat history.</p>
|
|
171
|
+
|
|
172
|
+
<div class="forgot-confirm" id="forgotConfirm">
|
|
173
|
+
<p>This will clear your local chat history.</p>
|
|
174
|
+
<p class="reassurance"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10"/></svg> Your assistant still remembers everything — only the browser history is lost.</p>
|
|
175
|
+
<div class="forgot-buttons">
|
|
176
|
+
<button class="btn-cancel" id="forgotCancel">Cancel</button>
|
|
177
|
+
<button class="btn-danger" id="forgotReset">Clear & Reset</button>
|
|
178
|
+
</div>
|
|
179
|
+
</div>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
|
|
183
|
+
<div id="stars"></div>
|
|
184
|
+
|
|
185
|
+
<!-- Layout wrapper for split view -->
|
|
186
|
+
<div class="layout-wrapper">
|
|
187
|
+
<div class="app">
|
|
188
|
+
<!-- Header -->
|
|
189
|
+
<header class="header">
|
|
190
|
+
<div class="header-left">
|
|
191
|
+
<img src="/img/wordmark.svg?v=2" class="header-wordmark" id="logoRefresh" title="Click to refresh chat" role="button" tabindex="0" aria-label="Refresh chat" alt="Uplink">
|
|
192
|
+
<div class="status-badge" id="connectionBadge" title="Connection status">
|
|
193
|
+
<span class="status-dot"></span>
|
|
194
|
+
<span id="status" class="sr-only">Offline</span>
|
|
195
|
+
</div>
|
|
196
|
+
<div class="status-badge encryption-badge" id="encryptionBadge" style="display: none;">
|
|
197
|
+
<span><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"/><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"/><path d="M8 11v-4a4 4 0 1 1 8 0v4"/></svg></span>
|
|
198
|
+
<span>Encrypted</span>
|
|
199
|
+
</div>
|
|
200
|
+
<div class="status-badge connection-mode-badge" id="connectionModeBadge" style="display: none;">
|
|
201
|
+
<span class="mode-dot"></span>
|
|
202
|
+
<span class="mode-text">Direct</span>
|
|
203
|
+
</div>
|
|
204
|
+
</div>
|
|
205
|
+
<div class="header-center" id="headerModeToggle">
|
|
206
|
+
<button class="header-mode-btn active" id="headerTextMode" title="Text mode" aria-label="Switch to text mode">
|
|
207
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
208
|
+
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
|
|
209
|
+
</svg>
|
|
210
|
+
</button>
|
|
211
|
+
<button class="header-mode-btn" id="splitViewBtn" title="Split View" aria-label="Split View">
|
|
212
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
213
|
+
<rect x="3" y="3" width="18" height="18" rx="2"/>
|
|
214
|
+
<line x1="12" y1="3" x2="12" y2="21"/>
|
|
215
|
+
</svg>
|
|
216
|
+
</button>
|
|
217
|
+
<button class="header-mode-btn" id="headerVoiceMode" title="Voice mode" aria-label="Switch to voice mode">
|
|
218
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
219
|
+
<path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/><path d="M19 10v2a7 7 0 01-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/>
|
|
220
|
+
</svg>
|
|
221
|
+
</button>
|
|
222
|
+
</div>
|
|
223
|
+
<div class="header-right">
|
|
224
|
+
<button class="header-btn" id="satellitesBtn" title="Satellites" aria-label="Satellites">
|
|
225
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24">
|
|
226
|
+
<path d="M4 10a7.31 7.31 0 0 0 10 10Z"/><path d="m9 15 3-3"/><path d="M17 13a6 6 0 0 0-6-6"/><path d="M21 13A10 10 0 0 0 11 3"/>
|
|
227
|
+
</svg>
|
|
228
|
+
</button>
|
|
229
|
+
<button class="header-btn" id="artifactsBtn" title="Artifacts" aria-label="Artifacts">
|
|
230
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
231
|
+
<path d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/>
|
|
232
|
+
</svg>
|
|
233
|
+
</button>
|
|
234
|
+
<button class="header-btn" id="activityBtn" title="Activity" aria-label="Activity">
|
|
235
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
236
|
+
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>
|
|
237
|
+
</svg>
|
|
238
|
+
</button>
|
|
239
|
+
<button class="header-btn" id="settingsBtn" title="Settings" aria-label="Settings">
|
|
240
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
241
|
+
<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/>
|
|
242
|
+
</svg>
|
|
243
|
+
</button>
|
|
244
|
+
<button class="header-btn" id="refreshBtn" title="Hard refresh" aria-label="Hard refresh">
|
|
245
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
246
|
+
<polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/>
|
|
247
|
+
</svg>
|
|
248
|
+
</button>
|
|
249
|
+
</div>
|
|
250
|
+
</header>
|
|
251
|
+
|
|
252
|
+
<!-- Settings panel -->
|
|
253
|
+
<div class="settings-panel panel" id="settingsPanel">
|
|
254
|
+
<div class="settings-panel-header">
|
|
255
|
+
<span class="settings-panel-title">SETTINGS</span>
|
|
256
|
+
<button class="settings-panel-close" id="settingsCloseBtn" title="Close" aria-label="Close settings">×</button>
|
|
257
|
+
</div>
|
|
258
|
+
<div class="settings-panel-content">
|
|
259
|
+
|
|
260
|
+
<!-- â•â•â• General â•â•â• -->
|
|
261
|
+
<div class="settings-section" data-section="general">
|
|
262
|
+
<button class="settings-section-header" aria-expanded="true" aria-controls="section-general">
|
|
263
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 010 2.83 2 2 0 01-2.83 0l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-2 2 2 2 0 01-2-2v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83 0 2 2 0 010-2.83l.06-.06a1.65 1.65 0 00.33-1.82 1.65 1.65 0 00-1.51-1H3a2 2 0 01-2-2 2 2 0 012-2h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 010-2.83 2 2 0 012.83 0l.06.06a1.65 1.65 0 001.82.33H9a1.65 1.65 0 001-1.51V3a2 2 0 012-2 2 2 0 012 2v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 0 2 2 0 010 2.83l-.06.06a1.65 1.65 0 00-.33 1.82V9a1.65 1.65 0 001.51 1H21a2 2 0 012 2 2 2 0 01-2 2h-.09a1.65 1.65 0 00-1.51 1z"/></svg></span>
|
|
264
|
+
<span class="settings-section-title">General</span>
|
|
265
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
266
|
+
</button>
|
|
267
|
+
<div class="settings-section-body" id="section-general">
|
|
268
|
+
<div class="panel-row setting-row">
|
|
269
|
+
<div>
|
|
270
|
+
<div class="setting-label">Assistant name</div>
|
|
271
|
+
<div class="setting-desc">Name of your assistant</div>
|
|
272
|
+
</div>
|
|
273
|
+
<input type="text" class="setting-input" id="agentNameInput" value="Assistant" aria-label="Assistant name">
|
|
274
|
+
</div>
|
|
275
|
+
</div>
|
|
276
|
+
</div>
|
|
277
|
+
|
|
278
|
+
<!-- â•â•â• Appearance â•â•â• -->
|
|
279
|
+
<div class="settings-section" data-section="appearance">
|
|
280
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-appearance">
|
|
281
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="13.5" cy="6.5" r="2.5"/><path d="M19.5 12c0 5.25-3.36 9.5-7.5 9.5S4.5 17.25 4.5 12 7.86 2.5 12 2.5"/><path d="M12 2.5c1.5 2 2.5 4.5 2.5 7"/></svg></span>
|
|
282
|
+
<span class="settings-section-title">Appearance</span>
|
|
283
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
284
|
+
</button>
|
|
285
|
+
<div class="settings-section-body collapsed" id="section-appearance">
|
|
286
|
+
<div class="panel-row setting-row">
|
|
287
|
+
<div>
|
|
288
|
+
<div class="setting-label">Theme</div>
|
|
289
|
+
<div class="setting-desc">Color scheme</div>
|
|
290
|
+
</div>
|
|
291
|
+
<!-- Hidden select kept for compatibility with existing JS -->
|
|
292
|
+
<select class="setting-select" id="themeSelect" aria-label="Theme" style="display:none">
|
|
293
|
+
<option value="midnight">Midnight</option>
|
|
294
|
+
<option value="daylight">Daylight</option>
|
|
295
|
+
<option value="ember">Ember</option>
|
|
296
|
+
<option value="forest">Forest</option>
|
|
297
|
+
<option value="noir">Noir</option>
|
|
298
|
+
</select>
|
|
299
|
+
<div class="theme-picker" id="themePicker" role="listbox" aria-label="Theme"></div>
|
|
300
|
+
</div>
|
|
301
|
+
<div class="panel-row setting-row">
|
|
302
|
+
<div>
|
|
303
|
+
<div class="setting-label">Text size</div>
|
|
304
|
+
<div class="setting-desc">Adjust message font size</div>
|
|
305
|
+
</div>
|
|
306
|
+
<select class="setting-select" id="textSizeSelect" aria-label="Text size">
|
|
307
|
+
<option value="small">Small</option>
|
|
308
|
+
<option value="medium" selected>Medium</option>
|
|
309
|
+
<option value="large">Large</option>
|
|
310
|
+
</select>
|
|
311
|
+
</div>
|
|
312
|
+
</div>
|
|
313
|
+
</div>
|
|
314
|
+
|
|
315
|
+
<!-- â•â•â• Connection â•â•â• -->
|
|
316
|
+
<div class="settings-section" data-section="connection">
|
|
317
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-connection">
|
|
318
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg></span>
|
|
319
|
+
<span class="settings-section-title">Connection</span>
|
|
320
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
321
|
+
</button>
|
|
322
|
+
<div class="settings-section-body collapsed" id="section-connection">
|
|
323
|
+
<div class="panel-row setting-row">
|
|
324
|
+
<div>
|
|
325
|
+
<div class="setting-label">Gateway URL</div>
|
|
326
|
+
<div class="setting-desc">Your bot's gateway address</div>
|
|
327
|
+
</div>
|
|
328
|
+
<input type="url" class="setting-input setting-input-wide" id="gatewayUrlInput" placeholder="http://127.0.0.1:23248" aria-label="Gateway URL">
|
|
329
|
+
</div>
|
|
330
|
+
<div class="panel-row setting-row">
|
|
331
|
+
<div>
|
|
332
|
+
<div class="setting-label">Auth Token</div>
|
|
333
|
+
<div class="setting-desc">Required when server auth is enabled</div>
|
|
334
|
+
</div>
|
|
335
|
+
<input type="password" class="setting-input setting-input-wide" id="authTokenInput" placeholder="Enter auth token" aria-label="Auth Token" autocomplete="off">
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
</div>
|
|
339
|
+
|
|
340
|
+
<!-- â•â•â• Server â•â•â• -->
|
|
341
|
+
<div class="settings-section" data-section="server">
|
|
342
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-server">
|
|
343
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"/><rect x="2" y="14" width="20" height="8" rx="2" ry="2"/><line x1="6" y1="6" x2="6.01" y2="6"/><line x1="6" y1="18" x2="6.01" y2="18"/></svg></span>
|
|
344
|
+
<span class="settings-section-title">Server</span>
|
|
345
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
346
|
+
</button>
|
|
347
|
+
<div class="settings-section-body collapsed" id="section-server">
|
|
348
|
+
<div class="panel-row setting-row">
|
|
349
|
+
<div>
|
|
350
|
+
<div class="setting-label">Auto-Restart (Watchdog)</div>
|
|
351
|
+
<div class="setting-desc">Automatically restart the server if it crashes</div>
|
|
352
|
+
</div>
|
|
353
|
+
<label class="toggle-switch" aria-label="Toggle watchdog">
|
|
354
|
+
<input type="checkbox" id="watchdogToggle" checked>
|
|
355
|
+
<span class="toggle-slider"></span>
|
|
356
|
+
</label>
|
|
357
|
+
</div>
|
|
358
|
+
<div class="panel-row setting-row">
|
|
359
|
+
<div>
|
|
360
|
+
<div class="setting-label">Network Access</div>
|
|
361
|
+
<div class="setting-desc">Allow connections from other devices (LAN/Tailscale)</div>
|
|
362
|
+
</div>
|
|
363
|
+
<label class="toggle-switch" aria-label="Toggle network access">
|
|
364
|
+
<input type="checkbox" id="networkAccessToggle">
|
|
365
|
+
<span class="toggle-slider"></span>
|
|
366
|
+
</label>
|
|
367
|
+
</div>
|
|
368
|
+
<div class="panel-row setting-row setting-hidden" id="serverRestartRow">
|
|
369
|
+
<div>
|
|
370
|
+
<div class="setting-label setting-label-accent">Restart required</div>
|
|
371
|
+
<div class="setting-desc">Changes take effect after restart</div>
|
|
372
|
+
</div>
|
|
373
|
+
<button class="setting-btn setting-btn-primary" id="serverRestartBtn">Restart Server</button>
|
|
374
|
+
</div>
|
|
375
|
+
</div>
|
|
376
|
+
</div>
|
|
377
|
+
|
|
378
|
+
<!-- â•â•â• Voice & TTS â•â•â• -->
|
|
379
|
+
<div class="settings-section" data-section="voice">
|
|
380
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-voice">
|
|
381
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polygon points="11 5 6 9 2 9 2 15 6 15 11 19 11 5"/><path d="M19.07 4.93a10 10 0 010 14.14M15.54 8.46a5 5 0 010 7.07"/></svg></span>
|
|
382
|
+
<span class="settings-section-title">Voice & TTS</span>
|
|
383
|
+
<span class="premium-lock-icon setting-hidden" id="voicePremiumLock" title="Requires Premium"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 13a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v6a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2v-6"/><path d="M11 16a1 1 0 1 0 2 0a1 1 0 0 0 -2 0"/><path d="M8 11v-4a4 4 0 1 1 8 0v4"/></svg></span>
|
|
384
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
385
|
+
</button>
|
|
386
|
+
<div class="settings-section-body collapsed" id="section-voice">
|
|
387
|
+
<!-- ── Voice Responses toggle ── -->
|
|
388
|
+
<div class="panel-row setting-row">
|
|
389
|
+
<div>
|
|
390
|
+
<div class="setting-label">Voice responses</div>
|
|
391
|
+
<div class="setting-desc">Play audio when assistant replies</div>
|
|
392
|
+
</div>
|
|
393
|
+
<div class="toggle on" id="audioToggle" tabindex="0" role="switch" aria-checked="true" aria-label="Toggle voice responses"></div>
|
|
394
|
+
</div>
|
|
395
|
+
|
|
396
|
+
<!-- ── Voice Mode cards ── -->
|
|
397
|
+
<div class="panel-row setting-row">
|
|
398
|
+
<div class="setting-full-width">
|
|
399
|
+
<div class="setting-desc" style="margin-bottom: var(--space-2)">How to interact with voice</div>
|
|
400
|
+
<div class="voice-mode-cards">
|
|
401
|
+
<div class="voice-mode-card" data-mode="push-to-talk" role="radio" tabindex="0" aria-checked="false">
|
|
402
|
+
<div class="voice-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 5a3 3 0 0 1 3 -3a3 3 0 0 1 3 3v5a3 3 0 0 1 -3 3a3 3 0 0 1 -3 -3l0 -5"/><path d="M5 10a7 7 0 0 0 14 0"/><path d="M8 21l8 0"/><path d="M12 17l0 4"/></svg></div>
|
|
403
|
+
<div class="voice-mode-content">
|
|
404
|
+
<div class="voice-mode-title">Push-to-talk</div>
|
|
405
|
+
<div class="voice-mode-desc">Hold to record, release to send</div>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
<div class="voice-mode-card" data-mode="agent-voice" role="radio" tabindex="0" aria-checked="false">
|
|
409
|
+
<div class="voice-mode-icon"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15.5 13a3.5 3.5 0 0 0 -3.5 3.5v1a3.5 3.5 0 0 0 7 0v-1.8"/><path d="M8.5 13a3.5 3.5 0 0 1 3.5 3.5v1a3.5 3.5 0 0 1 -7 0v-1.8"/><path d="M17.5 16a3.5 3.5 0 0 0 0 -7h-.5"/><path d="M19 9.3v-2.8a3.5 3.5 0 0 0 -7 0"/><path d="M6.5 16a3.5 3.5 0 0 1 0 -7h.5"/><path d="M5 9.3v-2.8a3.5 3.5 0 0 1 7 0v10"/></svg></div>
|
|
410
|
+
<div class="voice-mode-content">
|
|
411
|
+
<div class="voice-mode-title">Agent Voice</div>
|
|
412
|
+
<div class="voice-mode-desc">Talk to Assistant — full tools & memory</div>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
</div>
|
|
418
|
+
|
|
419
|
+
<!-- ── Quick Setup Card ── -->
|
|
420
|
+
<div class="v2-setup-card" id="v2SetupCard">
|
|
421
|
+
<div class="v2-setup-header">
|
|
422
|
+
<span class="v2-setup-title">Quick Setup</span>
|
|
423
|
+
<span class="v2-setup-banner" id="v2SetupBanner" style="display:none" aria-live="polite">
|
|
424
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="20 6 9 17 4 12"/></svg>
|
|
425
|
+
All set
|
|
426
|
+
</span>
|
|
427
|
+
</div>
|
|
428
|
+
<div class="v2-setup-rows">
|
|
429
|
+
<div class="v2-setup-row" id="v2SetupRow-stt" role="button" tabindex="0" aria-label="Configure speech recognition">
|
|
430
|
+
<span class="v2-setup-dot" id="v2SetupDot-stt" data-state="empty"></span>
|
|
431
|
+
<div class="v2-setup-row-content">
|
|
432
|
+
<span class="v2-setup-row-label" id="v2SetupLabel-stt">Your Voice</span>
|
|
433
|
+
<span class="v2-setup-row-sub" id="v2SetupSub-stt">No provider selected — tap to configure</span>
|
|
434
|
+
</div>
|
|
435
|
+
<svg class="v2-setup-row-arrow" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
436
|
+
</div>
|
|
437
|
+
<div class="v2-setup-row" id="v2SetupRow-tts" role="button" tabindex="0" data-muted="true" aria-label="Configure voice responses">
|
|
438
|
+
<span class="v2-setup-dot" id="v2SetupDot-tts" data-state="off"></span>
|
|
439
|
+
<div class="v2-setup-row-content">
|
|
440
|
+
<span class="v2-setup-row-label" id="v2SetupLabel-tts">Agent Voice</span>
|
|
441
|
+
<span class="v2-setup-row-sub" id="v2SetupSub-tts">Off — enable above to configure</span>
|
|
442
|
+
</div>
|
|
443
|
+
<svg class="v2-setup-row-arrow" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
444
|
+
</div>
|
|
445
|
+
</div>
|
|
446
|
+
</div>
|
|
447
|
+
|
|
448
|
+
<!-- ── Your Voice accordion (STT) ── -->
|
|
449
|
+
<div class="v2-accordion" data-accordion-id="stt">
|
|
450
|
+
<button class="v2-accordion-header" aria-expanded="false" aria-controls="v2AccordionBody-stt" tabindex="0">
|
|
451
|
+
<span class="v2-accordion-icon">
|
|
452
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 5a3 3 0 0 1 3 -3a3 3 0 0 1 3 3v5a3 3 0 0 1 -3 3a3 3 0 0 1 -3 -3l0 -5"/><path d="M5 10a7 7 0 0 0 14 0"/><path d="M8 21l8 0"/><path d="M12 17l0 4"/></svg>
|
|
453
|
+
</span>
|
|
454
|
+
<div class="v2-accordion-header-content">
|
|
455
|
+
<span class="v2-accordion-title">Your Voice</span>
|
|
456
|
+
<span class="v2-accordion-summary">Speech recognition (STT)</span>
|
|
457
|
+
</div>
|
|
458
|
+
<svg class="v2-accordion-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
459
|
+
</button>
|
|
460
|
+
<div class="v2-accordion-body" id="v2AccordionBody-stt">
|
|
461
|
+
<div class="v2-accordion-body-inner">
|
|
462
|
+
<div class="panel-row setting-row" id="sttProviderRow">
|
|
463
|
+
<div>
|
|
464
|
+
<div class="setting-label">STT Provider</div>
|
|
465
|
+
<div class="setting-desc" id="sttProviderDesc">Speech recognition service</div>
|
|
466
|
+
</div>
|
|
467
|
+
<select class="setting-select" id="sttProviderSelect" aria-label="STT Provider">
|
|
468
|
+
<option value="none">None</option>
|
|
469
|
+
<option value="openai">OpenAI Whisper (Cloud)</option>
|
|
470
|
+
<option value="groq">Groq (Cloud, Free)</option>
|
|
471
|
+
<option value="faster-whisper">Faster-Whisper (Local)</option>
|
|
472
|
+
</select>
|
|
473
|
+
</div>
|
|
474
|
+
|
|
475
|
+
<!-- OpenAI STT Config -->
|
|
476
|
+
<div class="stt-provider-config setting-hidden" id="sttConfig-openai">
|
|
477
|
+
<div class="panel-row setting-row">
|
|
478
|
+
<div>
|
|
479
|
+
<div class="setting-label">Model</div>
|
|
480
|
+
<div class="setting-desc">OpenAI Whisper model</div>
|
|
481
|
+
</div>
|
|
482
|
+
<select class="setting-select" id="openaiSttModelSelect" aria-label="OpenAI STT Model">
|
|
483
|
+
<option value="whisper-1" selected>Whisper v1</option>
|
|
484
|
+
</select>
|
|
485
|
+
</div>
|
|
486
|
+
<div class="panel-row setting-row" id="openaiSttKeyStatus">
|
|
487
|
+
<div>
|
|
488
|
+
<div class="setting-label">API Key</div>
|
|
489
|
+
<div class="setting-desc" id="openaiSttKeyDesc">Uses OpenAI key from Agent Voice settings</div>
|
|
490
|
+
</div>
|
|
491
|
+
</div>
|
|
492
|
+
</div>
|
|
493
|
+
|
|
494
|
+
<!-- Groq STT Config -->
|
|
495
|
+
<div class="stt-provider-config setting-hidden" id="sttConfig-groq">
|
|
496
|
+
<div class="panel-row setting-row">
|
|
497
|
+
<div class="setting-full-width">
|
|
498
|
+
<div class="setting-label">API Key</div>
|
|
499
|
+
<div class="setting-desc" id="groqKeyStatus">Enter your API key from console.groq.com</div>
|
|
500
|
+
<div class="setting-input-group">
|
|
501
|
+
<input type="password" class="setting-input setting-input-mono" id="groqKeyInput" placeholder="gsk_xxxxxxxxxxxxxxxx">
|
|
502
|
+
<button class="setting-btn setting-btn-primary" id="groqKeySaveBtn">Save</button>
|
|
503
|
+
</div>
|
|
504
|
+
</div>
|
|
505
|
+
</div>
|
|
506
|
+
<div class="panel-row setting-row">
|
|
507
|
+
<div>
|
|
508
|
+
<div class="setting-label">Model</div>
|
|
509
|
+
<div class="setting-desc">Groq STT model</div>
|
|
510
|
+
</div>
|
|
511
|
+
<select class="setting-select" id="groqSttModelSelect" aria-label="Groq STT Model">
|
|
512
|
+
<option value="whisper-large-v3-turbo" selected>Whisper Large v3 Turbo</option>
|
|
513
|
+
<option value="whisper-large-v3">Whisper Large v3</option>
|
|
514
|
+
</select>
|
|
515
|
+
</div>
|
|
516
|
+
</div>
|
|
517
|
+
|
|
518
|
+
<!-- Faster-Whisper STT Config -->
|
|
519
|
+
<div class="stt-provider-config setting-hidden" id="sttConfig-faster-whisper">
|
|
520
|
+
<div class="panel-row setting-row">
|
|
521
|
+
<div class="setting-full-width">
|
|
522
|
+
<div class="setting-label">Server URL</div>
|
|
523
|
+
<div class="setting-desc" id="fasterWhisperStatus">Local faster-whisper-server address</div>
|
|
524
|
+
<div class="setting-input-group">
|
|
525
|
+
<input type="text" class="setting-input setting-input-mono" id="fasterWhisperUrlInput" placeholder="http://localhost:8000">
|
|
526
|
+
<button class="setting-btn setting-btn-primary" id="fasterWhisperSaveBtn">Save</button>
|
|
527
|
+
</div>
|
|
528
|
+
</div>
|
|
529
|
+
</div>
|
|
530
|
+
</div>
|
|
531
|
+
|
|
532
|
+
<!-- STT Test -->
|
|
533
|
+
<div class="panel-row setting-row setting-hidden" id="sttTestRow">
|
|
534
|
+
<div>
|
|
535
|
+
<div class="setting-label">Test STT</div>
|
|
536
|
+
<div class="setting-desc" id="sttTestStatus">Verify your configuration works</div>
|
|
537
|
+
</div>
|
|
538
|
+
<button class="setting-btn setting-btn-secondary" id="sttTestBtn">Test</button>
|
|
539
|
+
</div>
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
</div>
|
|
543
|
+
|
|
544
|
+
<!-- ── Agent Voice accordion (TTS) ── -->
|
|
545
|
+
<div class="v2-accordion" data-accordion-id="tts">
|
|
546
|
+
<button class="v2-accordion-header" aria-expanded="false" aria-controls="v2AccordionBody-tts" tabindex="0">
|
|
547
|
+
<span class="v2-accordion-icon">
|
|
548
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M15 8a5 5 0 0 1 0 8"/><path d="M17.7 5a9 9 0 0 1 0 14"/><path d="M6 15h-2a1 1 0 0 1 -1 -1v-4a1 1 0 0 1 1 -1h2l3.5 -4.5a.8 .8 0 0 1 1.5 .5v14a.8 .8 0 0 1 -1.5 .5l-3.5 -4.5"/></svg>
|
|
549
|
+
</span>
|
|
550
|
+
<div class="v2-accordion-header-content">
|
|
551
|
+
<span class="v2-accordion-title">Agent Voice</span>
|
|
552
|
+
<span class="v2-accordion-summary">Text-to-speech (TTS)</span>
|
|
553
|
+
</div>
|
|
554
|
+
<svg class="v2-accordion-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
555
|
+
</button>
|
|
556
|
+
<div class="v2-accordion-body" id="v2AccordionBody-tts">
|
|
557
|
+
<div class="v2-accordion-body-inner">
|
|
558
|
+
<div class="panel-row setting-row" id="ttsProviderRow">
|
|
559
|
+
<div>
|
|
560
|
+
<div class="setting-label">TTS Provider</div>
|
|
561
|
+
<div class="setting-desc" id="ttsProviderDesc">Voice synthesis service</div>
|
|
562
|
+
</div>
|
|
563
|
+
<select class="setting-select" id="ttsProviderSelect" aria-label="TTS Provider">
|
|
564
|
+
<option value="none">None</option>
|
|
565
|
+
<option value="elevenlabs">ElevenLabs (Cloud)</option>
|
|
566
|
+
<option value="openai">OpenAI TTS (Cloud)</option>
|
|
567
|
+
<option value="edge" id="edgeTtsOption">Edge TTS (Free)</option>
|
|
568
|
+
<option value="piper">Piper (Local)</option>
|
|
569
|
+
<option value="local">XTTS (Local, GPU)</option>
|
|
570
|
+
</select>
|
|
571
|
+
</div>
|
|
572
|
+
|
|
573
|
+
<!-- ElevenLabs Config -->
|
|
574
|
+
<div class="tts-provider-config setting-hidden" id="ttsConfig-elevenlabs">
|
|
575
|
+
<div class="panel-row setting-row">
|
|
576
|
+
<div class="setting-full-width">
|
|
577
|
+
<div class="setting-label">API Key</div>
|
|
578
|
+
<div class="setting-desc" id="elevenLabsKeyStatus">Enter your API key from elevenlabs.io</div>
|
|
579
|
+
<div class="setting-input-group">
|
|
580
|
+
<input type="password" class="setting-input setting-input-mono" id="elevenLabsKeyInput" placeholder="xi-xxxxxxxxxxxxxxxx">
|
|
581
|
+
<button class="setting-btn setting-btn-primary" id="elevenLabsSaveBtn">Save</button>
|
|
582
|
+
</div>
|
|
583
|
+
</div>
|
|
584
|
+
</div>
|
|
585
|
+
<div class="panel-row setting-row setting-hidden" id="elevenLabsVoiceRow">
|
|
586
|
+
<div>
|
|
587
|
+
<div class="setting-label">Voice</div>
|
|
588
|
+
<div class="setting-desc">Select ElevenLabs voice</div>
|
|
589
|
+
</div>
|
|
590
|
+
<select class="setting-select" id="elevenLabsVoiceSelect" aria-label="ElevenLabs Voice">
|
|
591
|
+
<option value="">Loading voices...</option>
|
|
592
|
+
</select>
|
|
593
|
+
</div>
|
|
594
|
+
</div>
|
|
595
|
+
|
|
596
|
+
<!-- OpenAI TTS Config -->
|
|
597
|
+
<div class="tts-provider-config setting-hidden" id="ttsConfig-openai">
|
|
598
|
+
<div class="panel-row setting-row">
|
|
599
|
+
<div class="setting-full-width">
|
|
600
|
+
<div class="setting-label">API Key</div>
|
|
601
|
+
<div class="setting-desc" id="openaiKeyStatus">Enter your OpenAI API key</div>
|
|
602
|
+
<div class="setting-input-group">
|
|
603
|
+
<input type="password" class="setting-input setting-input-mono" id="openaiKeyInput" placeholder="sk-xxxxxxxxxxxxxxxx">
|
|
604
|
+
<button class="setting-btn setting-btn-primary" id="openaiKeySaveBtn">Save</button>
|
|
605
|
+
</div>
|
|
606
|
+
</div>
|
|
607
|
+
</div>
|
|
608
|
+
<div class="panel-row setting-row">
|
|
609
|
+
<div>
|
|
610
|
+
<div class="setting-label">Voice</div>
|
|
611
|
+
<div class="setting-desc">OpenAI TTS voice</div>
|
|
612
|
+
</div>
|
|
613
|
+
<select class="setting-select" id="openaiTtsVoiceSelect" aria-label="OpenAI TTS Voice">
|
|
614
|
+
<option value="alloy">Alloy</option>
|
|
615
|
+
<option value="ash">Ash</option>
|
|
616
|
+
<option value="coral">Coral</option>
|
|
617
|
+
<option value="echo">Echo</option>
|
|
618
|
+
<option value="fable">Fable</option>
|
|
619
|
+
<option value="nova" selected>Nova</option>
|
|
620
|
+
<option value="onyx">Onyx</option>
|
|
621
|
+
<option value="sage">Sage</option>
|
|
622
|
+
<option value="shimmer">Shimmer</option>
|
|
623
|
+
</select>
|
|
624
|
+
</div>
|
|
625
|
+
<div class="panel-row setting-row">
|
|
626
|
+
<div>
|
|
627
|
+
<div class="setting-label">Model</div>
|
|
628
|
+
<div class="setting-desc">Quality vs speed</div>
|
|
629
|
+
</div>
|
|
630
|
+
<select class="setting-select" id="openaiTtsModelSelect" aria-label="OpenAI TTS Model">
|
|
631
|
+
<option value="tts-1">Standard (tts-1)</option>
|
|
632
|
+
<option value="tts-1-hd">HD (tts-1-hd)</option>
|
|
633
|
+
<option value="gpt-4o-mini-tts">GPT-4o Mini TTS</option>
|
|
634
|
+
</select>
|
|
635
|
+
</div>
|
|
636
|
+
</div>
|
|
637
|
+
|
|
638
|
+
<!-- Edge TTS Config -->
|
|
639
|
+
<div class="tts-provider-config setting-hidden" id="ttsConfig-edge">
|
|
640
|
+
<div class="panel-row setting-row" id="edgeTtsStatus">
|
|
641
|
+
<div>
|
|
642
|
+
<div class="setting-label">Status</div>
|
|
643
|
+
<div class="setting-desc" id="edgeTtsStatusDesc">Checking...</div>
|
|
644
|
+
</div>
|
|
645
|
+
<span class="status-indicator" id="edgeTtsStatusDot"></span>
|
|
646
|
+
</div>
|
|
647
|
+
<div class="panel-row setting-row" id="edgeTtsVoiceRow">
|
|
648
|
+
<div>
|
|
649
|
+
<div class="setting-label">Voice</div>
|
|
650
|
+
<div class="setting-desc">Microsoft Edge TTS voice</div>
|
|
651
|
+
</div>
|
|
652
|
+
<select class="setting-select" id="edgeTtsVoiceSelect" aria-label="Edge TTS Voice">
|
|
653
|
+
<option value="">Loading voices...</option>
|
|
654
|
+
</select>
|
|
655
|
+
</div>
|
|
656
|
+
</div>
|
|
657
|
+
|
|
658
|
+
<!-- Piper Config -->
|
|
659
|
+
<div class="tts-provider-config setting-hidden" id="ttsConfig-piper">
|
|
660
|
+
<div class="panel-row setting-row">
|
|
661
|
+
<div>
|
|
662
|
+
<div class="setting-label">Status</div>
|
|
663
|
+
<div class="setting-desc" id="piperStatusDesc">Checking...</div>
|
|
664
|
+
</div>
|
|
665
|
+
<span class="status-indicator" id="piperStatusDot"></span>
|
|
666
|
+
</div>
|
|
667
|
+
</div>
|
|
668
|
+
|
|
669
|
+
<!-- XTTS Config -->
|
|
670
|
+
<div class="tts-provider-config setting-hidden" id="ttsConfig-local">
|
|
671
|
+
<div class="panel-row setting-row">
|
|
672
|
+
<div class="setting-full-width">
|
|
673
|
+
<div class="setting-label">Server URL</div>
|
|
674
|
+
<div class="setting-desc">XTTS server address (e.g. http://localhost:8020)</div>
|
|
675
|
+
<div class="setting-input-group">
|
|
676
|
+
<input type="url" class="setting-input setting-input-mono" id="localTtsUrlInput" placeholder="http://localhost:8020">
|
|
677
|
+
<button class="setting-btn setting-btn-primary" id="localTtsSaveBtn">Save</button>
|
|
678
|
+
</div>
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
</div>
|
|
682
|
+
</div>
|
|
683
|
+
</div>
|
|
684
|
+
</div>
|
|
685
|
+
|
|
686
|
+
<!-- ── Advanced accordion ── -->
|
|
687
|
+
<div class="v2-accordion" data-accordion-id="advanced">
|
|
688
|
+
<button class="v2-accordion-header" aria-expanded="false" aria-controls="v2AccordionBody-advanced" tabindex="0">
|
|
689
|
+
<span class="v2-accordion-icon">
|
|
690
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065"/><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"/></svg>
|
|
691
|
+
</span>
|
|
692
|
+
<div class="v2-accordion-header-content">
|
|
693
|
+
<span class="v2-accordion-title">Advanced</span>
|
|
694
|
+
<span class="v2-accordion-summary">Speech detection & tuning</span>
|
|
695
|
+
</div>
|
|
696
|
+
<svg class="v2-accordion-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="9 18 15 12 9 6"/></svg>
|
|
697
|
+
</button>
|
|
698
|
+
<div class="v2-accordion-body" id="v2AccordionBody-advanced">
|
|
699
|
+
<div class="v2-accordion-body-inner">
|
|
700
|
+
<div class="panel-row setting-row" style="flex-direction:column;align-items:stretch;gap:var(--space-3)">
|
|
701
|
+
<div style="display:flex;justify-content:space-between;align-items:center">
|
|
702
|
+
<div>
|
|
703
|
+
<div class="setting-label">Speech Detection</div>
|
|
704
|
+
<div class="setting-desc">How quickly it detects you stopped talking</div>
|
|
705
|
+
</div>
|
|
706
|
+
<span id="vadSensitivityValue" style="font-size:var(--text-xs);color:var(--text-muted);font-variant-numeric:tabular-nums;font-weight:600">0.4s</span>
|
|
707
|
+
</div>
|
|
708
|
+
<div style="display:flex;align-items:center;gap:var(--space-3)">
|
|
709
|
+
<span style="font-size:var(--text-xs);color:var(--text-dim)">Fast</span>
|
|
710
|
+
<input type="range" id="vadSensitivitySlider" min="200" max="1500" step="100" value="400" aria-label="Speech detection speed">
|
|
711
|
+
<span style="font-size:var(--text-xs);color:var(--text-dim)">Patient</span>
|
|
712
|
+
</div>
|
|
713
|
+
</div>
|
|
714
|
+
</div>
|
|
715
|
+
</div>
|
|
716
|
+
</div>
|
|
717
|
+
|
|
718
|
+
<!-- ── Legacy / compat stubs (hidden, keep JS from erroring) ── -->
|
|
719
|
+
<div style="display:none" aria-hidden="true">
|
|
720
|
+
<div class="panel-row setting-row" id="realtimeKeyRow">
|
|
721
|
+
<div style="flex:1">
|
|
722
|
+
<div class="setting-label">OpenAI API Key</div>
|
|
723
|
+
<div class="setting-desc" id="realtimeKeyStatus">Required for real-time voice</div>
|
|
724
|
+
</div>
|
|
725
|
+
<div style="display:flex;gap:6px;align-items:center">
|
|
726
|
+
<input type="password" class="setting-input setting-input-mono" id="realtimeKeyInput" placeholder="sk-..." style="width:160px">
|
|
727
|
+
<button class="setting-btn setting-btn-primary" id="realtimeKeySaveBtn">Save</button>
|
|
728
|
+
</div>
|
|
729
|
+
</div>
|
|
730
|
+
<div class="panel-row setting-row" id="realtimeVoiceRow">
|
|
731
|
+
<div><div class="setting-label">Real-time Voice</div></div>
|
|
732
|
+
<select class="setting-select" id="realtimeVoiceSelect" aria-label="Real-time Voice">
|
|
733
|
+
<option value="marin">Marin (recommended)</option>
|
|
734
|
+
<option value="cedar">Cedar (recommended)</option>
|
|
735
|
+
<option value="alloy">Alloy</option>
|
|
736
|
+
<option value="ash">Ash</option>
|
|
737
|
+
<option value="coral">Coral</option>
|
|
738
|
+
<option value="echo">Echo</option>
|
|
739
|
+
<option value="sage">Sage</option>
|
|
740
|
+
<option value="shimmer">Shimmer</option>
|
|
741
|
+
<option value="verse">Verse</option>
|
|
742
|
+
</select>
|
|
743
|
+
</div>
|
|
744
|
+
<div id="pushToTalkSettings"></div>
|
|
745
|
+
<div id="agentVoiceSettings"></div>
|
|
746
|
+
<select id="pttSttProviderSelect" aria-label="PTT STT Provider">
|
|
747
|
+
<option value="none">None</option>
|
|
748
|
+
<option value="openai">OpenAI Whisper</option>
|
|
749
|
+
<option value="groq">Groq (Free)</option>
|
|
750
|
+
<option value="faster-whisper">Faster-Whisper (Local)</option>
|
|
751
|
+
</select>
|
|
752
|
+
<select id="agentVoiceSttProviderSelect" aria-label="Agent STT Provider">
|
|
753
|
+
<option value="none">None</option>
|
|
754
|
+
<option value="openai">OpenAI Whisper</option>
|
|
755
|
+
<option value="groq">Groq (Free)</option>
|
|
756
|
+
<option value="faster-whisper">Faster-Whisper (Local)</option>
|
|
757
|
+
</select>
|
|
758
|
+
<select id="agentVoiceTtsEngineSelect" aria-label="Agent TTS Engine">
|
|
759
|
+
<option value="openai">OpenAI TTS</option>
|
|
760
|
+
<option value="edge">Edge TTS (Free)</option>
|
|
761
|
+
</select>
|
|
762
|
+
<select id="agentVoiceTtsVoiceSelect" aria-label="Agent TTS Voice">
|
|
763
|
+
<option value="alloy">Alloy</option>
|
|
764
|
+
<option value="ash">Ash</option>
|
|
765
|
+
<option value="coral">Coral</option>
|
|
766
|
+
<option value="echo">Echo</option>
|
|
767
|
+
<option value="fable">Fable</option>
|
|
768
|
+
<option value="nova" selected>Nova</option>
|
|
769
|
+
<option value="onyx">Onyx</option>
|
|
770
|
+
<option value="sage">Sage</option>
|
|
771
|
+
<option value="shimmer">Shimmer</option>
|
|
772
|
+
</select>
|
|
773
|
+
<button id="agentVoiceSttToggle" aria-expanded="false" aria-controls="agentVoiceSttPanel"></button>
|
|
774
|
+
<div id="agentVoiceSttPanel"></div>
|
|
775
|
+
<button id="voiceAdvancedBtn" aria-expanded="false" aria-controls="voiceAdvancedPanel"></button>
|
|
776
|
+
<div class="voice-advanced-expander" id="voiceAdvancedExpander">
|
|
777
|
+
<span id="voiceAdvancedHint"></span>
|
|
778
|
+
</div>
|
|
779
|
+
<div id="voiceContextPanels">
|
|
780
|
+
<div class="voice-subgroup voice-context-hidden" id="voiceOutputSubgroup" data-voice-context="advanced"></div>
|
|
781
|
+
<div class="voice-subgroup voice-context-hidden" id="voiceInputSubgroup" data-voice-context="advanced"></div>
|
|
782
|
+
</div>
|
|
783
|
+
</div>
|
|
784
|
+
|
|
785
|
+
|
|
786
|
+
|
|
787
|
+
</div>
|
|
788
|
+
</div>
|
|
789
|
+
|
|
790
|
+
<!-- â•â•â• Notifications â•â•â• -->
|
|
791
|
+
<div class="settings-section" data-section="notifications">
|
|
792
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-notifications">
|
|
793
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M18 8A6 6 0 006 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 01-3.46 0"/></svg></span>
|
|
794
|
+
<span class="settings-section-title">Notifications</span>
|
|
795
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
796
|
+
</button>
|
|
797
|
+
<div class="settings-section-body collapsed" id="section-notifications">
|
|
798
|
+
<!-- Push notification toggle injected by notifications.js -->
|
|
799
|
+
<div id="notificationSettingsSlot"></div>
|
|
800
|
+
</div>
|
|
801
|
+
</div>
|
|
802
|
+
|
|
803
|
+
<!-- â•â•â• Privacy â•â•â• -->
|
|
804
|
+
<div class="settings-section" data-section="privacy">
|
|
805
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-privacy">
|
|
806
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg></span>
|
|
807
|
+
<span class="settings-section-title">Privacy</span>
|
|
808
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
809
|
+
</button>
|
|
810
|
+
<div class="settings-section-body collapsed" id="section-privacy">
|
|
811
|
+
<div class="panel-row setting-row">
|
|
812
|
+
<div>
|
|
813
|
+
<div class="setting-label">Encrypt history</div>
|
|
814
|
+
<div class="setting-desc">Password-protect local chat</div>
|
|
815
|
+
</div>
|
|
816
|
+
<div class="toggle" id="encryptToggle" tabindex="0" role="switch" aria-checked="false" aria-label="Toggle chat encryption"></div>
|
|
817
|
+
</div>
|
|
818
|
+
<div class="panel-row setting-row setting-hidden" id="changePasswordRow">
|
|
819
|
+
<div>
|
|
820
|
+
<div class="setting-label">Change password</div>
|
|
821
|
+
<div class="setting-desc">Update encryption password</div>
|
|
822
|
+
</div>
|
|
823
|
+
<button class="setting-btn setting-btn-secondary" id="changePasswordBtn">Change</button>
|
|
824
|
+
</div>
|
|
825
|
+
<div class="panel-row setting-row setting-hidden" id="syncRow">
|
|
826
|
+
<div>
|
|
827
|
+
<div class="setting-label"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M6.657 18c-2.572 0 -4.657 -2.007 -4.657 -4.483c0 -2.475 2.085 -4.482 4.657 -4.482c.393 -1.762 1.794 -3.2 3.675 -3.773c1.88 -.572 3.956 -.193 5.444 1c1.488 1.19 2.162 3.007 1.77 4.769h.99c1.913 0 3.464 1.56 3.464 3.486c0 1.927 -1.551 3.487 -3.465 3.487h-11.878"/></svg> Sync across devices</div>
|
|
828
|
+
<div class="setting-desc" id="syncStatus">Same password syncs to same account</div>
|
|
829
|
+
</div>
|
|
830
|
+
<div class="setting-input-group">
|
|
831
|
+
<button class="setting-btn setting-btn-primary" id="syncPushBtn">Push</button>
|
|
832
|
+
<button class="setting-btn setting-btn-secondary" id="syncPullBtn">Pull</button>
|
|
833
|
+
</div>
|
|
834
|
+
</div>
|
|
835
|
+
<div class="panel-row setting-row">
|
|
836
|
+
<div>
|
|
837
|
+
<div class="setting-label">Clear chat</div>
|
|
838
|
+
<div class="setting-desc">Remove local chat history</div>
|
|
839
|
+
</div>
|
|
840
|
+
<button class="setting-btn setting-btn-secondary" id="settingsClearBtn">Clear</button>
|
|
841
|
+
</div>
|
|
842
|
+
</div>
|
|
843
|
+
</div>
|
|
844
|
+
|
|
845
|
+
<!-- â•â•â• Premium â•â•â• -->
|
|
846
|
+
<div class="settings-section" data-section="premium">
|
|
847
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-premium">
|
|
848
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></span>
|
|
849
|
+
<span class="settings-section-title">Premium</span>
|
|
850
|
+
<span class="premium-badge setting-hidden" id="premiumActiveBadge">Active</span>
|
|
851
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
852
|
+
</button>
|
|
853
|
+
<div class="settings-section-body collapsed" id="section-premium">
|
|
854
|
+
<!-- Free state -->
|
|
855
|
+
<div id="premiumFreeState">
|
|
856
|
+
<div class="premium-promo">
|
|
857
|
+
<div class="premium-promo-title">⬡ Uplink Premium</div>
|
|
858
|
+
<div class="premium-promo-desc">Unlock voice chat, all themes, agent management & more.</div>
|
|
859
|
+
<div class="premium-promo-price">$5 — one time, forever yours.</div>
|
|
860
|
+
<div class="premium-promo-actions">
|
|
861
|
+
<a class="setting-btn setting-btn-primary premium-buy-btn" id="premiumBuyBtn" href="https://store.moonco.pro" target="_blank" rel="noopener">Buy License</a>
|
|
862
|
+
<button class="setting-btn setting-btn-secondary" id="premiumEnterKeyBtn">Enter Key</button>
|
|
863
|
+
</div>
|
|
864
|
+
</div>
|
|
865
|
+
<div class="premium-key-entry setting-hidden" id="premiumKeyEntry">
|
|
866
|
+
<div class="setting-full-width">
|
|
867
|
+
<div class="setting-label">License Key</div>
|
|
868
|
+
<div class="setting-desc" id="premiumKeyStatus">Paste your license key below</div>
|
|
869
|
+
<div class="setting-input-group">
|
|
870
|
+
<input type="text" class="setting-input setting-input-mono" id="premiumKeyInput" placeholder="UPL-XXXXX-XXXXX-XXXXX-XXXXX" autocomplete="off" spellcheck="false">
|
|
871
|
+
<button class="setting-btn setting-btn-primary" id="premiumActivateBtn">Activate</button>
|
|
872
|
+
</div>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
</div>
|
|
876
|
+
<!-- Active state -->
|
|
877
|
+
<div id="premiumActiveState" class="setting-hidden">
|
|
878
|
+
<div class="panel-row setting-row">
|
|
879
|
+
<div>
|
|
880
|
+
<div class="setting-label">Status</div>
|
|
881
|
+
<div class="setting-desc premium-active-text"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l5 5l10 -10"/></svg> Uplink Premium is active</div>
|
|
882
|
+
</div>
|
|
883
|
+
</div>
|
|
884
|
+
<div class="panel-row setting-row">
|
|
885
|
+
<div>
|
|
886
|
+
<div class="setting-label setting-label-danger">Deactivate</div>
|
|
887
|
+
<div class="setting-desc">Remove license and revert to free</div>
|
|
888
|
+
</div>
|
|
889
|
+
<button class="setting-btn setting-btn-secondary" id="premiumDeactivateBtn">Deactivate</button>
|
|
890
|
+
</div>
|
|
891
|
+
</div>
|
|
892
|
+
</div>
|
|
893
|
+
</div>
|
|
894
|
+
|
|
895
|
+
<!-- â•â•â• About â•â•â• -->
|
|
896
|
+
<div class="settings-section" data-section="about">
|
|
897
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-about">
|
|
898
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg></span>
|
|
899
|
+
<span class="settings-section-title">About</span>
|
|
900
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
901
|
+
</button>
|
|
902
|
+
<div class="settings-section-body collapsed" id="section-about">
|
|
903
|
+
<div class="panel-row setting-row">
|
|
904
|
+
<div>
|
|
905
|
+
<div class="setting-label">Uplink</div>
|
|
906
|
+
<div class="setting-desc" id="aboutVersion">Loading...</div>
|
|
907
|
+
</div>
|
|
908
|
+
</div>
|
|
909
|
+
<div class="panel-row setting-row" id="aboutGatewayRow">
|
|
910
|
+
<div>
|
|
911
|
+
<div class="setting-label">Gateway</div>
|
|
912
|
+
<div class="setting-desc" id="aboutGatewayStatus">Checking...</div>
|
|
913
|
+
</div>
|
|
914
|
+
<span class="status-indicator" id="aboutGatewayDot"></span>
|
|
915
|
+
</div>
|
|
916
|
+
<div class="panel-row setting-row desktop-only">
|
|
917
|
+
<div>
|
|
918
|
+
<div class="setting-label">Keyboard shortcuts</div>
|
|
919
|
+
<div class="setting-desc">View available shortcuts</div>
|
|
920
|
+
</div>
|
|
921
|
+
<button class="setting-btn setting-btn-secondary" id="showShortcutsBtn">View</button>
|
|
922
|
+
</div>
|
|
923
|
+
</div>
|
|
924
|
+
</div>
|
|
925
|
+
|
|
926
|
+
<!-- â•â•â• Danger Zone â•â•â• -->
|
|
927
|
+
<div class="settings-section settings-section-danger" data-section="danger">
|
|
928
|
+
<button class="settings-section-header" aria-expanded="false" aria-controls="section-danger">
|
|
929
|
+
<span class="settings-section-icon"><svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></span>
|
|
930
|
+
<span class="settings-section-title">Danger Zone</span>
|
|
931
|
+
<span class="settings-section-chevron"><svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg></span>
|
|
932
|
+
</button>
|
|
933
|
+
<div class="settings-section-body collapsed" id="section-danger">
|
|
934
|
+
<div class="panel-row setting-row">
|
|
935
|
+
<div>
|
|
936
|
+
<div class="setting-label setting-label-danger">Clear Cache & Reload</div>
|
|
937
|
+
<div class="setting-desc">Clears localStorage, service workers, and cached files — then reloads</div>
|
|
938
|
+
</div>
|
|
939
|
+
<button class="setting-btn setting-btn-danger" id="clearCacheBtn">Clear Cache</button>
|
|
940
|
+
</div>
|
|
941
|
+
<div class="panel-row setting-row">
|
|
942
|
+
<div>
|
|
943
|
+
<div class="setting-label setting-label-danger">Logout</div>
|
|
944
|
+
<div class="setting-desc">Clear all data and return to setup</div>
|
|
945
|
+
</div>
|
|
946
|
+
<button class="setting-btn setting-btn-danger" id="logoutBtn">Logout</button>
|
|
947
|
+
</div>
|
|
948
|
+
</div>
|
|
949
|
+
</div>
|
|
950
|
+
|
|
951
|
+
</div><!-- end settings-panel-content -->
|
|
952
|
+
</div>
|
|
953
|
+
|
|
954
|
+
<!-- Artifacts panel -->
|
|
955
|
+
<div class="artifacts-panel panel" id="artifactsPanel">
|
|
956
|
+
<div class="panel-header artifacts-panel-header">
|
|
957
|
+
<div class="artifacts-tab-bar" id="artifactsTabBar">
|
|
958
|
+
<button class="artifacts-tab active" data-tab="artifacts">Artifacts</button>
|
|
959
|
+
<button class="artifacts-tab" data-tab="cron">Cron</button>
|
|
960
|
+
</div>
|
|
961
|
+
<div class="artifacts-header-actions" id="artifactsHeaderActions">
|
|
962
|
+
<button class="artifacts-panel-refresh" id="artifactsRefreshBtn" title="Refresh" aria-label="Refresh artifacts">
|
|
963
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
964
|
+
<polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/>
|
|
965
|
+
</svg>
|
|
966
|
+
</button>
|
|
967
|
+
<button class="panel-close" id="artifactsCloseBtn" title="Close" aria-label="Close artifacts">×</button>
|
|
968
|
+
</div>
|
|
969
|
+
<div class="artifacts-header-actions" id="cronHeaderActions" style="display: none;">
|
|
970
|
+
<button class="artifacts-panel-refresh" id="cronRefreshBtn" title="Refresh" aria-label="Refresh cron runs">
|
|
971
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
972
|
+
<polyline points="23 4 23 10 17 10"/><path d="M20.49 15a9 9 0 11-2.12-9.36L23 10"/>
|
|
973
|
+
</svg>
|
|
974
|
+
</button>
|
|
975
|
+
<button class="panel-close" id="cronCloseBtn" title="Close" aria-label="Close panel">×</button>
|
|
976
|
+
</div>
|
|
977
|
+
</div>
|
|
978
|
+
<div class="panel-content artifacts-panel-content">
|
|
979
|
+
<!-- Artifacts tab content -->
|
|
980
|
+
<div id="artifactsTabContent">
|
|
981
|
+
<input type="text" class="artifacts-search" id="artifactsSearch" placeholder="Search artifacts..." aria-label="Search artifacts">
|
|
982
|
+
<div class="artifacts-list" id="artifactsList">
|
|
983
|
+
<!-- List populated by JS -->
|
|
984
|
+
</div>
|
|
985
|
+
<div class="artifacts-reader" id="artifactsReader" style="display: none;">
|
|
986
|
+
<div class="artifacts-reader-toolbar">
|
|
987
|
+
<button class="artifacts-reader-back" id="readerBackBtn" aria-label="Back to list">
|
|
988
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
989
|
+
<line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/>
|
|
990
|
+
</svg>
|
|
991
|
+
Back
|
|
992
|
+
</button>
|
|
993
|
+
<button class="artifacts-reader-download" id="readerDownloadBtn" aria-label="Download artifact">
|
|
994
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
995
|
+
<path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>
|
|
996
|
+
</svg>
|
|
997
|
+
Download
|
|
998
|
+
</button>
|
|
999
|
+
</div>
|
|
1000
|
+
<h3 class="artifacts-reader-title" id="readerTitle"></h3>
|
|
1001
|
+
<div class="artifacts-reader-content" id="readerContent"></div>
|
|
1002
|
+
</div>
|
|
1003
|
+
</div>
|
|
1004
|
+
<!-- Cron tab content -->
|
|
1005
|
+
<div id="cronTabContent" style="display: none;">
|
|
1006
|
+
<div class="cron-list" id="cronList">
|
|
1007
|
+
<!-- Populated by JS -->
|
|
1008
|
+
</div>
|
|
1009
|
+
<div class="cron-detail" id="cronDetail" style="display: none;">
|
|
1010
|
+
<div class="cron-detail-toolbar">
|
|
1011
|
+
<button class="artifacts-reader-back" id="cronDetailBackBtn" aria-label="Back to cron list">
|
|
1012
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
1013
|
+
<line x1="19" y1="12" x2="5" y2="12"/><polyline points="12 19 5 12 12 5"/>
|
|
1014
|
+
</svg>
|
|
1015
|
+
Back
|
|
1016
|
+
</button>
|
|
1017
|
+
</div>
|
|
1018
|
+
<h3 class="cron-detail-title" id="cronDetailTitle"></h3>
|
|
1019
|
+
<div class="cron-detail-content" id="cronDetailContent"></div>
|
|
1020
|
+
</div>
|
|
1021
|
+
</div>
|
|
1022
|
+
</div>
|
|
1023
|
+
</div>
|
|
1024
|
+
|
|
1025
|
+
<!-- ARIA live regions for screen reader announcements -->
|
|
1026
|
+
<div id="sr-announcer" class="sr-only" aria-live="polite" aria-atomic="true"></div>
|
|
1027
|
+
<div id="connection-status-region" class="sr-only" aria-live="polite" aria-atomic="true"></div>
|
|
1028
|
+
|
|
1029
|
+
<!-- Split chat container: wraps primary + secondary chat areas -->
|
|
1030
|
+
<div class="split-chat-container" id="splitChatContainer">
|
|
1031
|
+
|
|
1032
|
+
<!-- Primary chat pane -->
|
|
1033
|
+
<div class="split-pane-primary" id="splitPrimary">
|
|
1034
|
+
|
|
1035
|
+
<!-- Primary chat header (matches splitSecondary header) -->
|
|
1036
|
+
<div class="split-primary-header" id="splitPrimaryHeader">
|
|
1037
|
+
<div class="split-primary-info">
|
|
1038
|
+
<img class="split-primary-icon" id="splitPrimaryIcon" src="/img/agents/main.png" alt="Agent avatar">
|
|
1039
|
+
<span class="split-primary-name" id="splitPrimaryName"></span>
|
|
1040
|
+
<svg class="split-primary-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
|
|
1041
|
+
<div class="context-badge" id="contextBadge" role="status" aria-label="Context window usage">
|
|
1042
|
+
<div class="context-bar" id="contextBar">
|
|
1043
|
+
<div class="context-bar-fill" id="contextBarFill"></div>
|
|
1044
|
+
</div>
|
|
1045
|
+
<span class="context-text" id="contextText"></span>
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
</div>
|
|
1049
|
+
|
|
1050
|
+
<!-- Main content area -->
|
|
1051
|
+
<main id="messages" class="messages" aria-label="Chat messages" aria-live="polite" aria-atomic="false">
|
|
1052
|
+
<div class="empty-state" id="emptyState">
|
|
1053
|
+
<svg fill="none" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24">
|
|
1054
|
+
<path d="M8.625 12a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H8.25m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0H12m4.125 0a.375.375 0 11-.75 0 .375.375 0 01.75 0zm0 0h-.375M21 12c0 4.556-4.03 8.25-9 8.25a9.764 9.764 0 01-2.555-.337A5.972 5.972 0 015.41 20.97a5.969 5.969 0 01-.474-.065 4.48 4.48 0 00.978-2.025c.09-.457-.133-.901-.467-1.226C3.93 16.178 3 14.189 3 12c0-4.556 4.03-8.25 9-8.25s9 3.694 9 8.25z"/>
|
|
1055
|
+
</svg>
|
|
1056
|
+
<h3>Start a conversation</h3>
|
|
1057
|
+
<p>Type a message or switch to voice mode</p>
|
|
1058
|
+
</div>
|
|
1059
|
+
</main>
|
|
1060
|
+
|
|
1061
|
+
<!-- Bottom dock: input + mode tabs -->
|
|
1062
|
+
<div class="bottom-dock">
|
|
1063
|
+
<div class="input-area">
|
|
1064
|
+
<!-- Image preview -->
|
|
1065
|
+
<div class="image-preview" id="imagePreview">
|
|
1066
|
+
<img id="previewImg" alt="Image attachment preview" style="display:none">
|
|
1067
|
+
<button class="preview-remove" id="removePreview" title="Remove attachment" aria-label="Remove attachment"><svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M18 6l-12 12"/><path d="M6 6l12 12"/></svg></button>
|
|
1068
|
+
</div>
|
|
1069
|
+
|
|
1070
|
+
<!-- Text input - no form to avoid autofill triggers -->
|
|
1071
|
+
<div class="text-input-row active" id="textInputRow">
|
|
1072
|
+
<input type="file" id="fileInput" aria-label="Attach file">
|
|
1073
|
+
<div class="input-actions">
|
|
1074
|
+
<label for="fileInput" class="input-btn" title="Attach file" aria-label="Attach file">
|
|
1075
|
+
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
|
1076
|
+
<path d="M21.44 11.05l-9.19 9.19a6 6 0 01-8.49-8.49l9.19-9.19a4 4 0 015.66 5.66l-9.2 9.19a2 2 0 01-2.83-2.83l8.49-8.48"/>
|
|
1077
|
+
</svg>
|
|
1078
|
+
</label>
|
|
1079
|
+
</div>
|
|
1080
|
+
<textarea class="text-field" id="textInput" placeholder="Message your assistant..." rows="1" autocomplete="off" enterkeyhint="enter" aria-label="Message input"></textarea>
|
|
1081
|
+
<button type="button" class="send-btn" id="sendBtn" title="Send message" aria-label="Send message">
|
|
1082
|
+
<svg fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
|
1083
|
+
<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
|
1084
|
+
</svg>
|
|
1085
|
+
</button>
|
|
1086
|
+
</div>
|
|
1087
|
+
|
|
1088
|
+
<!-- Voice input with orbiting rings -->
|
|
1089
|
+
<div class="voice-input-row" id="voiceInputRow">
|
|
1090
|
+
<div class="voice-orb-container">
|
|
1091
|
+
<div class="voice-ring voice-ring-1"></div>
|
|
1092
|
+
<div class="voice-ring voice-ring-2"></div>
|
|
1093
|
+
<button class="voice-btn" id="voiceBtn" title="Hold to talk. Double-tap for hands-free mode. Spacebar to start/stop recording." aria-label="Voice input. Hold to record, double tap for hands-free mode, or press spacebar when in voice mode">
|
|
1094
|
+
<canvas id="moonCanvas"></canvas>
|
|
1095
|
+
</button>
|
|
1096
|
+
</div>
|
|
1097
|
+
<div class="voice-timer" id="voiceTimer">0:00</div>
|
|
1098
|
+
<div class="voice-status" id="voiceStatus"></div>
|
|
1099
|
+
<!-- Real-time voice UI elements -->
|
|
1100
|
+
<div class="realtime-indicator" id="realtimeIndicator" style="display:none">
|
|
1101
|
+
<span class="realtime-dot"></span>
|
|
1102
|
+
<span class="realtime-timer" id="realtimeTimer">0:00</span>
|
|
1103
|
+
</div>
|
|
1104
|
+
<div class="realtime-transcript" id="realtimeTranscript" style="display:none"></div>
|
|
1105
|
+
</div>
|
|
1106
|
+
</div>
|
|
1107
|
+
|
|
1108
|
+
<!-- Mode tabs - below input -->
|
|
1109
|
+
<div class="mode-tabs" role="tablist" aria-label="Input mode selection">
|
|
1110
|
+
<button class="mode-tab active" id="textModeTab" role="tab" aria-selected="true" aria-controls="textInputRow" tabindex="0">
|
|
1111
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
|
1112
|
+
<path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/>
|
|
1113
|
+
</svg>
|
|
1114
|
+
Text
|
|
1115
|
+
</button>
|
|
1116
|
+
<button class="mode-tab" id="voiceModeTab" role="tab" aria-selected="false" aria-controls="voiceInputRow" tabindex="-1">
|
|
1117
|
+
<svg width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24" aria-hidden="true">
|
|
1118
|
+
<path d="M12 1a3 3 0 00-3 3v8a3 3 0 006 0V4a3 3 0 00-3-3z"/><path d="M19 10v2a7 7 0 01-14 0v-2"/><line x1="12" y1="19" x2="12" y2="23"/><line x1="8" y1="23" x2="16" y2="23"/>
|
|
1119
|
+
</svg>
|
|
1120
|
+
Voice
|
|
1121
|
+
</button>
|
|
1122
|
+
</div>
|
|
1123
|
+
</div><!-- end bottom-dock -->
|
|
1124
|
+
|
|
1125
|
+
</div><!-- end split-pane-primary -->
|
|
1126
|
+
|
|
1127
|
+
<!-- Split view: drag handle -->
|
|
1128
|
+
<div class="split-drag-handle" id="splitDragHandle" style="display: none;" aria-label="Resize split view"></div>
|
|
1129
|
+
|
|
1130
|
+
<!-- Split view: secondary chat pane -->
|
|
1131
|
+
<div class="split-pane-secondary" id="splitSecondary" style="display: none;">
|
|
1132
|
+
<div class="split-secondary-header">
|
|
1133
|
+
<div class="split-secondary-info" id="splitSecondarySwitch" role="button" tabindex="0" title="Switch session" aria-label="Switch session">
|
|
1134
|
+
<span class="split-secondary-icon agent-avatar-emoji" id="splitSecondaryIcon"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ui-icon" aria-hidden="true"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M6 6a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v4a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2l0 -4"/><path d="M12 2v2"/><path d="M9 12v9"/><path d="M15 12v9"/><path d="M5 16l4 -2"/><path d="M15 14l4 2"/><path d="M9 18h6"/><path d="M10 8v.01"/><path d="M14 8v.01"/></svg></span>
|
|
1135
|
+
<span class="split-secondary-name" id="splitSecondaryName">Select Agent</span>
|
|
1136
|
+
<svg class="split-secondary-chevron" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 12 15 18 9"/></svg>
|
|
1137
|
+
<div class="context-badge split-context-badge" id="splitContextBadge" role="status" aria-label="Context window usage" style="display: none;">
|
|
1138
|
+
<div class="context-bar" id="splitContextBar">
|
|
1139
|
+
<div class="context-bar-fill" id="splitContextBarFill"></div>
|
|
1140
|
+
</div>
|
|
1141
|
+
<span class="context-text" id="splitContextText"></span>
|
|
1142
|
+
</div>
|
|
1143
|
+
</div>
|
|
1144
|
+
<button class="split-secondary-close" id="splitSecondaryClose" title="Close split view" aria-label="Close split view">×</button>
|
|
1145
|
+
</div>
|
|
1146
|
+
<div class="split-secondary-messages" id="splitSecondaryMessages">
|
|
1147
|
+
<div class="messages-spacer"></div>
|
|
1148
|
+
</div>
|
|
1149
|
+
<div class="split-secondary-input">
|
|
1150
|
+
<div class="split-input-row">
|
|
1151
|
+
<textarea class="split-text-field" id="splitSecondaryInput" placeholder="Message..." rows="1" aria-label="Message input for secondary chat"></textarea>
|
|
1152
|
+
<button class="split-send-btn" id="splitSecondarySend" aria-label="Send message">
|
|
1153
|
+
<svg width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24">
|
|
1154
|
+
<line x1="22" y1="2" x2="11" y2="13"/><polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
|
1155
|
+
</svg>
|
|
1156
|
+
</button>
|
|
1157
|
+
</div>
|
|
1158
|
+
</div>
|
|
1159
|
+
</div>
|
|
1160
|
+
|
|
1161
|
+
</div><!-- end split-chat-container -->
|
|
1162
|
+
|
|
1163
|
+
</div><!-- end .app -->
|
|
1164
|
+
|
|
1165
|
+
<!-- Side panel for split view (desktop) -->
|
|
1166
|
+
<div class="side-panel" id="sidePanel">
|
|
1167
|
+
<div class="side-panel-header">
|
|
1168
|
+
<h3 id="sidePanelTitle">Panel</h3>
|
|
1169
|
+
<button class="side-panel-close" id="sidePanelClose" aria-label="Close side panel">×</button>
|
|
1170
|
+
</div>
|
|
1171
|
+
<div class="side-panel-content" id="sidePanelContent"></div>
|
|
1172
|
+
</div>
|
|
1173
|
+
|
|
1174
|
+
</div><!-- end layout-wrapper -->
|
|
1175
|
+
|
|
1176
|
+
<!-- Audio Player Bar -->
|
|
1177
|
+
<div class="audio-player-bar" id="audioPlayerBar" style="display: none;">
|
|
1178
|
+
<button class="audio-player-play" id="audioPlayerPlay" aria-label="Play/Pause">
|
|
1179
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path id="audioPlayerIcon" d="M6 4l15 8-15 8V4z"/></svg>
|
|
1180
|
+
</button>
|
|
1181
|
+
<div class="audio-player-progress" id="audioPlayerProgress">
|
|
1182
|
+
<div class="audio-player-bar-fill" id="audioPlayerFill"></div>
|
|
1183
|
+
</div>
|
|
1184
|
+
<span class="audio-player-time" id="audioPlayerTime">0:00</span>
|
|
1185
|
+
<button class="audio-player-close" id="audioPlayerClose" aria-label="Close audio player">×</button>
|
|
1186
|
+
<audio id="audio" playsinline></audio>
|
|
1187
|
+
</div>
|
|
1188
|
+
|
|
1189
|
+
<!-- Bundled client application (built by esbuild from public/js/app.js) -->
|
|
1190
|
+
<script src="/dist/bundle.493af136.js" defer></script>
|
|
1191
|
+
<script src="/js/voice-settings-v2.js?v=3" defer></script>
|
|
1192
|
+
|
|
1193
|
+
</body>
|
|
1194
|
+
</html>
|
|
1195
|
+
|