Ivan000 commited on
Commit
7937e65
1 Parent(s): 875db35

Create index.html

Browse files
Files changed (1) hide show
  1. index.html +851 -0
index.html ADDED
@@ -0,0 +1,851 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <html><head><base href="https://voice-gemma-ai.example.com/">
2
+ <meta charset="UTF-8">
3
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
4
+ <title>AI Voice Assistant with Advanced Generation Capabilities</title>
5
+ <style>
6
+ body {
7
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
8
+ margin: 0;
9
+ padding: 0;
10
+ display: flex;
11
+ flex-direction: column;
12
+ min-height: 100vh;
13
+ background-color: #1a1a1a;
14
+ color: #ffffff;
15
+ }
16
+ .assistant-container {
17
+ flex: 1;
18
+ width: 90%;
19
+ max-width: 800px;
20
+ margin: 20px auto;
21
+ background-color: #2a2a2a;
22
+ border-radius: 20px;
23
+ box-shadow: 0 0 20px rgba(0,0,0,0.3);
24
+ overflow: hidden;
25
+ display: flex;
26
+ flex-direction: column;
27
+ }
28
+ .assistant-header {
29
+ background-color: #3a3a3a;
30
+ color: #4a90e2;
31
+ padding: 20px;
32
+ text-align: center;
33
+ font-size: 28px;
34
+ font-weight: bold;
35
+ }
36
+ .visualization-area {
37
+ flex-grow: 1;
38
+ display: flex;
39
+ justify-content: center;
40
+ align-items: center;
41
+ background-color: #222222;
42
+ position: relative;
43
+ overflow: hidden;
44
+ height: 300px;
45
+ }
46
+ .animation-container {
47
+ width: 200px;
48
+ height: 200px;
49
+ position: relative;
50
+ }
51
+ .circle {
52
+ position: absolute;
53
+ border-radius: 50%;
54
+ transition: all 0.5s ease;
55
+ }
56
+ .idle .circle {
57
+ width: 20px;
58
+ height: 20px;
59
+ background-color: #4a90e2;
60
+ opacity: 0.7;
61
+ }
62
+ .idle .circle:nth-child(1) { top: 40%; left: 20%; animation: pulse 2s infinite; }
63
+ .idle .circle:nth-child(2) { top: 60%; left: 40%; animation: pulse 2s infinite 0.3s; }
64
+ .idle .circle:nth-child(3) { top: 40%; left: 60%; animation: pulse 2s infinite 0.6s; }
65
+ .idle .circle:nth-child(4) { top: 60%; left: 80%; animation: pulse 2s infinite 0.9s; }
66
+
67
+ @keyframes pulse {
68
+ 0% { transform: scale(1); }
69
+ 50% { transform: scale(1.2); }
70
+ 100% { transform: scale(1); }
71
+ }
72
+
73
+ .listening .circle {
74
+ width: 30px;
75
+ height: 30px;
76
+ background-color: #4a90e2;
77
+ }
78
+ .listening .circle:nth-child(1) { top: 50%; left: 10%; animation: wave 1s infinite; }
79
+ .listening .circle:nth-child(2) { top: 50%; left: 30%; animation: wave 1s infinite 0.2s; }
80
+ .listening .circle:nth-child(3) { top: 50%; left: 50%; animation: wave 1s infinite 0.4s; }
81
+ .listening .circle:nth-child(4) { top: 50%; left: 70%; animation: wave 1s infinite 0.6s; }
82
+
83
+ @keyframes wave {
84
+ 0%, 100% { transform: translateY(0); }
85
+ 50% { transform: translateY(-20px); }
86
+ }
87
+
88
+ .generating .circle, .loading .circle {
89
+ width: 40px;
90
+ height: 40px;
91
+ background-color: #4a90e2;
92
+ }
93
+ .generating .circle:nth-child(1), .loading .circle:nth-child(1) { top: 50%; left: 20%; animation: rotate 2s infinite linear; }
94
+ .generating .circle:nth-child(2), .loading .circle:nth-child(2) { top: 30%; left: 50%; animation: rotate 2s infinite linear 0.5s; }
95
+ .generating .circle:nth-child(3), .loading .circle:nth-child(3) { top: 70%; left: 50%; animation: rotate 2s infinite linear 1s; }
96
+ .generating .circle:nth-child(4), .loading .circle:nth-child(4) { top: 50%; left: 80%; animation: rotate 2s infinite linear 1.5s; }
97
+
98
+ @keyframes rotate {
99
+ 0% { transform: rotate(0deg); }
100
+ 100% { transform: rotate(360deg); }
101
+ }
102
+
103
+ .speaking .circle {
104
+ width: 50px;
105
+ height: 50px;
106
+ background-color: #4a90e2;
107
+ }
108
+ .speaking .circle:nth-child(1) { top: 40%; left: 20%; animation: bounce 0.5s infinite alternate; }
109
+ .speaking .circle:nth-child(2) { top: 60%; left: 40%; animation: bounce 0.5s infinite alternate 0.1s; }
110
+ .speaking .circle:nth-child(3) { top: 40%; left: 60%; animation: bounce 0.5s infinite alternate 0.2s; }
111
+ .speaking .circle:nth-child(4) { top: 60%; left: 80%; animation: bounce 0.5s infinite alternate 0.3s; }
112
+
113
+ @keyframes bounce {
114
+ 0% { transform: translateY(0); }
115
+ 100% { transform: translateY(-20px); }
116
+ }
117
+
118
+ .controls {
119
+ display: flex;
120
+ justify-content: center;
121
+ padding: 20px;
122
+ background-color: #2a2a2a;
123
+ }
124
+ .control-button {
125
+ background-color: #4a90e2;
126
+ color: white;
127
+ border: none;
128
+ padding: 15px 30px;
129
+ margin: 0 10px;
130
+ border-radius: 50px;
131
+ cursor: pointer;
132
+ font-size: 18px;
133
+ transition: all 0.3s ease;
134
+ }
135
+ .control-button:hover {
136
+ background-color: #3a7bc8;
137
+ transform: scale(1.05);
138
+ }
139
+ .control-button:active {
140
+ transform: scale(0.95);
141
+ }
142
+ .control-button:disabled {
143
+ background-color: #999;
144
+ cursor: not-allowed;
145
+ }
146
+ .settings-button {
147
+ position: absolute;
148
+ top: 20px;
149
+ right: 20px;
150
+ background-color: transparent;
151
+ color: #4a90e2;
152
+ border: none;
153
+ font-size: 24px;
154
+ cursor: pointer;
155
+ }
156
+ .modal {
157
+ display: none;
158
+ position: fixed;
159
+ z-index: 1;
160
+ left: 0;
161
+ top: 0;
162
+ width: 100%;
163
+ height: 100%;
164
+ overflow: auto;
165
+ background-color: rgba(0,0,0,0.6);
166
+ }
167
+ .modal-content {
168
+ background-color: #2a2a2a;
169
+ margin: 15% auto;
170
+ padding: 20px;
171
+ border: 1px solid #3a3a3a;
172
+ width: 80%;
173
+ max-width: 500px;
174
+ border-radius: 10px;
175
+ color: #ffffff;
176
+ }
177
+ .close {
178
+ color: #aaa;
179
+ float: right;
180
+ font-size: 28px;
181
+ font-weight: bold;
182
+ }
183
+ .close:hover,
184
+ .close:focus {
185
+ color: #4a90e2;
186
+ text-decoration: none;
187
+ cursor: pointer;
188
+ }
189
+ #api-key, #language-select, #model-select, #tts-select, #system-prompt {
190
+ width: 100%;
191
+ padding: 10px;
192
+ margin: 10px 0;
193
+ border-radius: 5px;
194
+ border: 1px solid #3a3a3a;
195
+ background-color: #222222;
196
+ color: #ffffff;
197
+ }
198
+ #api-key {
199
+ -webkit-text-security: disc;
200
+ text-security: disc;
201
+ }
202
+ #save-settings, #reset-default {
203
+ background-color: #4a90e2;
204
+ color: white;
205
+ border: none;
206
+ padding: 10px 20px;
207
+ margin: 10px 5px 0 0;
208
+ border-radius: 5px;
209
+ cursor: pointer;
210
+ }
211
+ .chat-history {
212
+ background-color: #2a2a2a;
213
+ padding: 20px;
214
+ border-radius: 0 0 20px 20px;
215
+ max-height: 400px;
216
+ overflow-y: auto;
217
+ }
218
+ .chat-entry {
219
+ margin-bottom: 15px;
220
+ padding: 10px;
221
+ border-radius: 10px;
222
+ background-color: #3a3a3a;
223
+ }
224
+ .user-message {
225
+ color: #4a90e2;
226
+ font-weight: bold;
227
+ }
228
+ .ai-response {
229
+ color: #ffffff;
230
+ }
231
+ .status-message {
232
+ color: #ffa500;
233
+ font-style: italic;
234
+ }
235
+ #language-display, #model-display, #tts-display {
236
+ text-align: center;
237
+ padding: 5px;
238
+ font-size: 16px;
239
+ color: #4a90e2;
240
+ }
241
+ .generated-image {
242
+ max-width: 100%;
243
+ height: auto;
244
+ margin-top: 10px;
245
+ border-radius: 10px;
246
+ box-shadow: 0 0 10px rgba(0,0,0,0.3);
247
+ }
248
+ .music-player {
249
+ background-color: #3a3a3a;
250
+ border-radius: 10px;
251
+ padding: 15px;
252
+ margin-top: 15px;
253
+ }
254
+ .music-player audio {
255
+ width: 100%;
256
+ margin-top: 10px;
257
+ }
258
+ .music-controls {
259
+ display: flex;
260
+ justify-content: space-between;
261
+ margin-top: 10px;
262
+ }
263
+ .music-control-button {
264
+ background-color: #4a90e2;
265
+ color: white;
266
+ border: none;
267
+ padding: 5px 10px;
268
+ border-radius: 5px;
269
+ cursor: pointer;
270
+ }
271
+ .timer-container {
272
+ display: flex;
273
+ justify-content: center;
274
+ align-items: center;
275
+ margin-top: 10px;
276
+ }
277
+ .timer {
278
+ width: 60px;
279
+ height: 60px;
280
+ border-radius: 50%;
281
+ background: conic-gradient(#4a90e2 0deg, #2a2a2a 0deg);
282
+ display: flex;
283
+ justify-content: center;
284
+ align-items: center;
285
+ font-size: 20px;
286
+ font-weight: bold;
287
+ color: #ffffff;
288
+ }
289
+ #chat-log-checkbox, #auto-translate-checkbox {
290
+ margin-right: 5px;
291
+ }
292
+
293
+ #model-select option[disabled] {
294
+ font-weight: bold;
295
+ color: #4a90e2;
296
+ background-color: #3a3a3a;
297
+ }
298
+ </style>
299
+ </head>
300
+ <body>
301
+ <div class="assistant-container">
302
+ <div class="assistant-header">
303
+ AI Voice Assistant with Advanced Generation Capabilities
304
+ </div>
305
+ <div id="language-display">Current Language: Not set</div>
306
+ <div id="model-display">Current Model: Not set</div>
307
+ <div id="tts-display">Current TTS: Not set</div>
308
+ <div class="visualization-area">
309
+ <div class="animation-container idle">
310
+ <div class="circle"></div>
311
+ <div class="circle"></div>
312
+ <div class="circle"></div>
313
+ <div class="circle"></div>
314
+ </div>
315
+ </div>
316
+ <div class="timer-container">
317
+ <div class="timer" id="cooldown-timer">20</div>
318
+ </div>
319
+ <div class="controls">
320
+ <button id="start-button" class="control-button">Start Listening</button>
321
+ <button id="stop-button" class="control-button" style="display: none;">Stop Listening</button>
322
+ </div>
323
+ <div class="chat-history" id="chat-history"></div>
324
+ </div>
325
+
326
+ <button class="settings-button" id="settings-button">⚙️</button>
327
+
328
+ <div id="settings-modal" class="modal">
329
+ <div class="modal-content">
330
+ <span class="close">&times;</span>
331
+ <h2>Settings</h2>
332
+ <label for="api-key">API Key:</label>
333
+ <input type="password" id="api-key" placeholder="Enter your Hugging Face API key">
334
+ <label for="language-select">Language:</label>
335
+ <select id="language-select">
336
+ <option value="en-US">English 🇺🇸</option>
337
+ <option value="ru-RU">Russian 🇷🇺</option>
338
+ </select>
339
+ <label for="model-select">Model:</label>
340
+ <select id="model-select">
341
+ <option disabled>Text Generation Models</option>
342
+ <option value="google/gemma-2b-it">Gemma 2B IT 🤖</option>
343
+ <option value="mistralai/Mixtral-8x7B-Instruct-v0.1">Mixtral 8x7B 🌪��</option>
344
+ <option value="HuggingFaceTB/SmolLM-1.7B-Instruct">SmolLM 1.7B 🐣</option>
345
+ <option value="mistralai/Mistral-Nemo-Instruct-2407">Mistral Nemo 🗣️</option>
346
+ <option value="01-ai/Yi-1.5-34B-Chat">Yi 1.5 34B 🧠</option>
347
+ <option value="NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO">Nous Hermes 2 Mixtral 🦉</option>
348
+ <option value="stabilityai/stablelm-2-zephyr-1_6b">StableLM Zephyr 1.6B 🌟</option>
349
+ <option value="microsoft/Phi-3-mini-4k-instruct">Phi-3 Mini 4K 🧠</option>
350
+ <option value="microsoft/DialoGPT-medium">DialoGPT Medium 💬</option>
351
+ <option value="google/gemma-1.1-7b-it">Gemma 1.1 7B IT 🧠</option>
352
+ <option value="google/gemma-2-27b-it">Gemma 2 27B IT 🧠</option>
353
+ <option value="meta-llama/Meta-Llama-3-8B-Instruct">Meta-Llama 3 8B Instruct 🦙</option>
354
+ <option value="codellama/CodeLlama-34b-Instruct-hf">CodeLlama 34B Instruct 💻</option>
355
+ <option disabled>Image Generation Models</option>
356
+ <option value="CompVis/stable-diffusion-v1-4">Stable Diffusion 🎨</option>
357
+ <option value="dreamlike-art/dreamlike-photoreal-2.0">Dreamlike Photoreal 📷</option>
358
+ <option value="openskyml/soviet-diffusion-xl">Soviet Diffusion XL 🎨</option>
359
+ <option value="black-forest-labs/FLUX.1-dev">FLUX.1 Dev 🖼️</option>
360
+ <option value="dataautogpt3/OpenDalleV1.1">OpenDalle V1.1 🎭</option>
361
+ <option value="black-forest-labs/FLUX.1-schnell">FLUX.1 Schnell 🌠</option>
362
+ <option disabled>Music Generation Models</option>
363
+ <option value="facebook/musicgen-small">MusicGen 🎵</option>
364
+ </select>
365
+ <label for="tts-select">Text-to-Speech:</label>
366
+ <select id="tts-select">
367
+ <option value="standard">Standard 🔊</option>
368
+ <option value="espnet/kan-bayashi_ljspeech_vits">kan-bayashi 🎙️</option>
369
+ <option value="facebook/mms-tts-eng">mms-tts-eng 🗣️</option>
370
+ <option value="wasmdashai/vits-eng-us-ljs">VITS ENG US LJS 🎤</option>
371
+ </select>
372
+ <label for="system-prompt">System Prompt (optional):</label>
373
+ <textarea id="system-prompt" placeholder="Enter optional system prompt"></textarea>
374
+ <div>
375
+ <label for="auto-translate-checkbox">
376
+ <input type="checkbox" id="auto-translate-checkbox"> Enable Auto-Translation (for image and music generation)
377
+ </label>
378
+ </div>
379
+ <div>
380
+ <label for="chat-log-checkbox">
381
+ <input type="checkbox" id="chat-log-checkbox"> Enable Chat Logging
382
+ </label>
383
+ </div>
384
+ <button id="save-settings">Save</button>
385
+ <button id="reset-default">Reset to Default</button>
386
+ </div>
387
+ </div>
388
+
389
+ <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
390
+ <script>
391
+ const startButton = document.getElementById('start-button');
392
+ const stopButton = document.getElementById('stop-button');
393
+ const settingsButton = document.getElementById('settings-button');
394
+ const settingsModal = document.getElementById('settings-modal');
395
+ const closeButton = document.getElementsByClassName('close')[0];
396
+ const apiKeyInput = document.getElementById('api-key');
397
+ const languageSelect = document.getElementById('language-select');
398
+ const modelSelect = document.getElementById('model-select');
399
+ const ttsSelect = document.getElementById('tts-select');
400
+ const systemPromptInput = document.getElementById('system-prompt');
401
+ const saveSettingsButton = document.getElementById('save-settings');
402
+ const resetDefaultButton = document.getElementById('reset-default');
403
+ const animationContainer = document.querySelector('.animation-container');
404
+ const chatHistory = document.getElementById('chat-history');
405
+ const languageDisplay = document.getElementById('language-display');
406
+ const modelDisplay = document.getElementById('model-display');
407
+ const ttsDisplay = document.getElementById('tts-display');
408
+ const cooldownTimer = document.getElementById('cooldown-timer');
409
+
410
+ const defaultApiKey = '';
411
+ const defaultLanguage = 'en-US';
412
+ const defaultModel = 'meta-llama/Meta-Llama-3-8B-Instruct';
413
+ const defaultTts = 'standard';
414
+ let apiKey = localStorage.getItem('huggingface_api_key') || defaultApiKey;
415
+ let selectedLanguage = localStorage.getItem('selected_language') || defaultLanguage;
416
+ let selectedModel = localStorage.getItem('selected_model') || defaultModel;
417
+ let selectedTts = localStorage.getItem('selected_tts') || defaultTts;
418
+ let systemPrompt = localStorage.getItem('system_prompt') || '';
419
+ let chatLoggingEnabled = localStorage.getItem('chat_logging_enabled') === 'true';
420
+ let autoTranslateEnabled = localStorage.getItem('auto_translate_enabled') === 'true';
421
+
422
+ const translationModel = 'Helsinki-NLP/opus-mt-ru-en';
423
+
424
+ async function translateText(text) {
425
+ try {
426
+ const response = await axios.post(`https://api-inference.huggingface.co/models/${translationModel}`, {
427
+ inputs: text
428
+ }, {
429
+ headers: {
430
+ 'Authorization': `Bearer ${apiKey}`,
431
+ 'Content-Type': 'application/json'
432
+ }
433
+ });
434
+ return response.data[0].translation_text;
435
+ } catch (error) {
436
+ console.error('Translation error:', error);
437
+ return text; // Return original text if translation fails
438
+ }
439
+ }
440
+
441
+ let recognition;
442
+ let isListening = false;
443
+ let cooldownActive = false;
444
+ let cooldownSeconds = 20;
445
+
446
+ function setAnimationState(state) {
447
+ animationContainer.className = `animation-container ${state}`;
448
+ }
449
+
450
+ function addChatEntry(userMessage, aiResponse, isStatus = false, imageUrl = null, audioUrl = null) {
451
+ if (!chatLoggingEnabled) {
452
+ chatHistory.innerHTML = ''; // Clear all previous entries
453
+ }
454
+
455
+ const chatEntry = document.createElement('div');
456
+ chatEntry.className = 'chat-entry';
457
+ let content = `
458
+ <div class="user-message">You: ${userMessage}</div>
459
+ <div class="${isStatus ? 'status-message' : 'ai-response'}">AI: ${aiResponse}</div>
460
+ `;
461
+ if (imageUrl) {
462
+ content += `<img src="${imageUrl}" alt="Generated Image" class="generated-image">`;
463
+ }
464
+ if (audioUrl) {
465
+ content += `
466
+ <div class="music-player">
467
+ <audio controls>
468
+ <source src="${audioUrl}" type="audio/wav">
469
+ Your browser does not support the audio element.
470
+ </audio>
471
+ <div class="music-controls">
472
+ <button class="music-control-button" onclick="document.querySelector('audio').play()">Play</button>
473
+ <button class="music-control-button" onclick="document.querySelector('audio').pause()">Pause</button>
474
+ <button class="music-control-button" onclick="document.querySelector('audio').currentTime = 0">Restart</button>
475
+ </div>
476
+ </div>
477
+ `;
478
+ }
479
+ chatEntry.innerHTML = content;
480
+ chatHistory.insertBefore(chatEntry, chatHistory.firstChild);
481
+ }
482
+
483
+ function initializeSpeechRecognition() {
484
+ if ('webkitSpeechRecognition' in window) {
485
+ recognition = new webkitSpeechRecognition();
486
+ recognition.continuous = false;
487
+ recognition.interimResults = false;
488
+ recognition.lang = selectedLanguage;
489
+
490
+ recognition.onstart = function() {
491
+ isListening = true;
492
+ startButton.style.display = 'none';
493
+ stopButton.style.display = 'inline-block';
494
+ setAnimationState('listening');
495
+ };
496
+
497
+ recognition.onend = function() {
498
+ isListening = false;
499
+ startButton.style.display = 'inline-block';
500
+ stopButton.style.display = 'none';
501
+ setAnimationState('idle');
502
+ startCooldown();
503
+ };
504
+
505
+ recognition.onresult = async function(event) {
506
+ const transcript = event.results[0][0].transcript;
507
+ console.log('You said: ' + transcript);
508
+
509
+ setAnimationState('generating');
510
+ addChatEntry(transcript, "Processing your request...", true);
511
+
512
+ let processedText = transcript;
513
+ const isImageOrMusicModel = selectedModel.includes('stable-diffusion') ||
514
+ selectedModel.includes('dreamlike-photoreal') ||
515
+ selectedModel.includes('soviet-diffusion') ||
516
+ selectedModel.includes('FLUX') ||
517
+ selectedModel.includes('OpenDalle') ||
518
+ selectedModel.includes('musicgen');
519
+
520
+ if (autoTranslateEnabled && selectedLanguage === 'ru-RU' && isImageOrMusicModel) {
521
+ processedText = await translateText(transcript);
522
+ console.log('Translated text:', processedText);
523
+ }
524
+
525
+ try {
526
+ if (isImageOrMusicModel) {
527
+ if (selectedModel.includes('musicgen')) {
528
+ const audioUrl = await generateMusic(processedText);
529
+ addChatEntry(transcript, "Here's the generated music:", false, null, audioUrl);
530
+ } else {
531
+ const imageUrl = await generateImage(processedText);
532
+ addChatEntry(transcript, "Here's the generated image:", false, imageUrl);
533
+ }
534
+ } else {
535
+ const response = await makeApiRequest(processedText);
536
+ handleApiResponse(transcript, response);
537
+ }
538
+ } catch (error) {
539
+ console.error('Error:', error);
540
+ handleApiError(transcript, error);
541
+ }
542
+ };
543
+ } else {
544
+ console.log('Web Speech API is not supported in this browser.');
545
+ startButton.disabled = true;
546
+ startButton.textContent = 'Speech Recognition Not Supported';
547
+ }
548
+ }
549
+
550
+ async function makeApiRequest(transcript) {
551
+ let userMessage = transcript;
552
+ if (systemPrompt) {
553
+ userMessage = `${systemPrompt}\n\n${transcript}`;
554
+ }
555
+
556
+ return axios.post(`https://api-inference.huggingface.co/models/${selectedModel}/v1/chat/completions`, {
557
+ model: selectedModel,
558
+ messages: [{"role": "user", "content": userMessage}],
559
+ max_tokens: 500,
560
+ stream: false
561
+ }, {
562
+ headers: {
563
+ 'Authorization': `Bearer ${apiKey}`,
564
+ 'Content-Type': 'application/json'
565
+ }
566
+ });
567
+ }
568
+
569
+ async function generateImage(prompt) {
570
+ const response = await axios.post(`https://api-inference.huggingface.co/models/${selectedModel}`, {
571
+ inputs: prompt
572
+ }, {
573
+ headers: {
574
+ 'Authorization': `Bearer ${apiKey}`,
575
+ 'Content-Type': 'application/json'
576
+ },
577
+ responseType: 'arraybuffer'
578
+ });
579
+
580
+ const blob = new Blob([response.data], { type: 'image/jpeg' });
581
+ return URL.createObjectURL(blob);
582
+ }
583
+
584
+ async function generateMusic(prompt) {
585
+ const response = await axios.post('https://api-inference.huggingface.co/models/facebook/musicgen-small', {
586
+ inputs: prompt
587
+ }, {
588
+ headers: {
589
+ 'Authorization': `Bearer ${apiKey}`,
590
+ 'Content-Type': 'application/json'
591
+ },
592
+ responseType: 'arraybuffer'
593
+ });
594
+
595
+ const blob = new Blob([response.data], { type: 'audio/wav' });
596
+ return URL.createObjectURL(blob);
597
+ }
598
+
599
+ function handleApiResponse(transcript, response) {
600
+ if (response.status === 503 && response.data.error.includes("is currently loading")) {
601
+ setAnimationState('loading');
602
+ addChatEntry(transcript, "Model is loading. Please wait...", true);
603
+ setTimeout(() => checkModelStatus(transcript), 5000);
604
+ } else {
605
+ let aiResponse;
606
+ if (response.data.choices && response.data.choices[0].message) {
607
+ aiResponse = response.data.choices[0].message.content;
608
+ } else if (response.data.generated_text) {
609
+ aiResponse = response.data.generated_text;
610
+ } else {
611
+ aiResponse = "Sorry, I couldn't generate a response.";
612
+ }
613
+ console.log('AI response:', aiResponse);
614
+ addChatEntry(transcript, aiResponse);
615
+ setAnimationState('speaking');
616
+ speakResponse(aiResponse);
617
+ }
618
+ }
619
+
620
+ function handleApiError(transcript, error) {
621
+ let errorMessage = 'An error occurred while processing your request.';
622
+ if (error.response) {
623
+ errorMessage = `Server Error: ${error.response.status} - ${error.response.data.error || error.response.statusText}`;
624
+ } else if (error.request) {
625
+ errorMessage = 'No response received from the server. Please check your internet connection.';
626
+ } else {
627
+ errorMessage = `Error: ${error.message}`;
628
+ }
629
+ addChatEntry(transcript, errorMessage, true);
630
+ setAnimationState('idle');
631
+ }
632
+
633
+ async function checkModelStatus(transcript) {
634
+ try {
635
+ const response = await makeApiRequest(transcript);
636
+ handleApiResponse(transcript, response);
637
+ } catch (error) {
638
+ if (error.response && error.response.status === 503) {
639
+ addChatEntry(transcript, "Model is still loading. Checking again...", true);
640
+ setTimeout(() => checkModelStatus(transcript), 5000);
641
+ } else {
642
+ handleApiError(transcript, error);
643
+ }
644
+ }
645
+ }
646
+
647
+ async function speakResponse(text) {
648
+ if (selectedTts === 'standard') {
649
+ const utterance = new SpeechSynthesisUtterance(text);
650
+ utterance.lang = selectedLanguage;
651
+ utterance.onend = function() {
652
+ setAnimationState('idle');
653
+ };
654
+ speechSynthesis.speak(utterance);
655
+ } else {
656
+ try {
657
+ const response = await axios.post(`https://api-inference.huggingface.co/models/${selectedTts}`, {
658
+ inputs: text
659
+ }, {
660
+ headers: {
661
+ 'Authorization': `Bearer ${apiKey}`,
662
+ 'Content-Type': 'application/json'
663
+ },
664
+ responseType: 'arraybuffer'
665
+ });
666
+
667
+ const audioContext = new (window.AudioContext || window.webkitAudioContext)();
668
+ const audioBuffer = await audioContext.decodeAudioData(response.data);
669
+ const source = audioContext.createBufferSource();
670
+ source.buffer = audioBuffer;
671
+ source.connect(audioContext.destination);
672
+ source.onended = function() {
673
+ setAnimationState('idle');
674
+ };
675
+ source.start();
676
+ } catch (error) {
677
+ console.error('Error with AI TTS:', error);
678
+ const utterance = new SpeechSynthesisUtterance(text);
679
+ utterance.lang = selectedLanguage;
680
+ utterance.onend = function() {
681
+ setAnimationState('idle');
682
+ };
683
+ speechSynthesis.speak(utterance);
684
+ }
685
+ }
686
+ }
687
+
688
+ function startCooldown() {
689
+ cooldownActive = true;
690
+ startButton.disabled = true;
691
+ cooldownSeconds = 20;
692
+ updateCooldownTimer();
693
+ const cooldownInterval = setInterval(() => {
694
+ cooldownSeconds--;
695
+ updateCooldownTimer();
696
+ if (cooldownSeconds <= 0) {
697
+ clearInterval(cooldownInterval);
698
+ cooldownActive = false;
699
+ startButton.disabled = false;
700
+ cooldownTimer.style.background = 'conic-gradient(#4a90e2 360deg, #2a2a2a 360deg)';
701
+ cooldownTimer.textContent = '20';
702
+ }
703
+ }, 1000);
704
+ }
705
+
706
+ function updateCooldownTimer() {
707
+ const progress = (20 - cooldownSeconds) / 20 * 360;
708
+ cooldownTimer.style.background = `conic-gradient(#4a90e2 ${progress}deg, #2a2a2a ${progress}deg)`;
709
+ cooldownTimer.textContent = cooldownSeconds;
710
+ }
711
+
712
+ startButton.addEventListener('click', function() {
713
+ if (!cooldownActive && recognition) {
714
+ recognition.start();
715
+ }
716
+ });
717
+
718
+ stopButton.addEventListener('click', function() {
719
+ if (recognition) {
720
+ recognition.stop();
721
+ }
722
+ });
723
+
724
+ settingsButton.onclick = function() {
725
+ settingsModal.style.display = "block";
726
+ apiKeyInput.value = apiKey;
727
+ languageSelect.value = selectedLanguage;
728
+ setInitialModelValue();
729
+ ttsSelect.value = selectedTts;
730
+ systemPromptInput.value = systemPrompt;
731
+ document.getElementById('auto-translate-checkbox').checked = autoTranslateEnabled;
732
+ document.getElementById('chat-log-checkbox').checked = chatLoggingEnabled;
733
+ }
734
+
735
+ closeButton.onclick = function() {
736
+ settingsModal.style.display = "none";
737
+ }
738
+
739
+ window.onclick = function(event) {
740
+ if (event.target == settingsModal) {
741
+ settingsModal.style.display = "none";
742
+ }
743
+ }
744
+
745
+ saveSettingsButton.onclick = function() {
746
+ apiKey = apiKeyInput.value.trim();
747
+ selectedLanguage = languageSelect.value;
748
+ selectedModel = modelSelect.value;
749
+ selectedTts = ttsSelect.value;
750
+ systemPrompt = systemPromptInput.value.trim();
751
+ autoTranslateEnabled = document.getElementById('auto-translate-checkbox').checked;
752
+ chatLoggingEnabled = document.getElementById('chat-log-checkbox').checked;
753
+ localStorage.setItem('huggingface_api_key', apiKey);
754
+ localStorage.setItem('selected_language', selectedLanguage);
755
+ localStorage.setItem('selected_model', selectedModel);
756
+ localStorage.setItem('selected_tts', selectedTts);
757
+ localStorage.setItem('system_prompt', systemPrompt);
758
+ localStorage.setItem('auto_translate_enabled', autoTranslateEnabled);
759
+ localStorage.setItem('chat_logging_enabled', chatLoggingEnabled);
760
+ settingsModal.style.display = "none";
761
+ updateLanguageDisplay();
762
+ updateModelDisplay();
763
+ updateTtsDisplay();
764
+ initializeSpeechRecognition();
765
+ addChatEntry("Update Settings", "Settings updated successfully!");
766
+ if (!chatLoggingEnabled) {
767
+ clearChatHistoryExceptLast();
768
+ }
769
+ }
770
+
771
+ function clearChatHistoryExceptLast() {
772
+ const chatEntries = chatHistory.getElementsByClassName('chat-entry');
773
+ if (chatEntries.length > 1) {
774
+ for (let i = chatEntries.length - 1; i > 0; i--) {
775
+ chatHistory.removeChild(chatEntries[i]);
776
+ }
777
+ }
778
+ }
779
+
780
+ resetDefaultButton.onclick = function() {
781
+ apiKey = defaultApiKey;
782
+ selectedLanguage = defaultLanguage;
783
+ selectedModel = defaultModel;
784
+ selectedTts = defaultTts;
785
+ systemPrompt = '';
786
+ autoTranslateEnabled = false;
787
+ chatLoggingEnabled = true;
788
+ apiKeyInput.value = apiKey;
789
+ languageSelect.value = selectedLanguage;
790
+ modelSelect.value = selectedModel;
791
+ ttsSelect.value = selectedTts;
792
+ systemPromptInput.value = systemPrompt;
793
+ document.getElementById('auto-translate-checkbox').checked = autoTranslateEnabled;
794
+ document.getElementById('chat-log-checkbox').checked = chatLoggingEnabled;
795
+ localStorage.setItem('huggingface_api_key', apiKey);
796
+ localStorage.setItem('selected_language', selectedLanguage);
797
+ localStorage.setItem('selected_model', selectedModel);
798
+ localStorage.setItem('selected_tts', selectedTts);
799
+ localStorage.setItem('system_prompt', systemPrompt);
800
+ localStorage.setItem('auto_translate_enabled', autoTranslateEnabled);
801
+ localStorage.setItem('chat_logging_enabled', chatLoggingEnabled);
802
+ updateLanguageDisplay();
803
+ updateModelDisplay();
804
+ updateTtsDisplay();
805
+ initializeSpeechRecognition();
806
+ addChatEntry("Reset Settings", "Settings reset to default.");
807
+ }
808
+
809
+ function updateLanguageDisplay() {
810
+ const languageName = languageSelect.options[languageSelect.selectedIndex].text;
811
+ languageDisplay.textContent = `Current Language: ${languageName}`;
812
+ }
813
+
814
+ function updateModelDisplay() {
815
+ const modelName = modelSelect.options[modelSelect.selectedIndex].text;
816
+ modelDisplay.textContent = `Current Model: ${modelName}`;
817
+ }
818
+
819
+ function updateTtsDisplay() {
820
+ const ttsName = ttsSelect.options[ttsSelect.selectedIndex].text;
821
+ ttsDisplay.textContent = `Current TTS: ${ttsName}`;
822
+ }
823
+
824
+ function setInitialModelValue() {
825
+ const storedModel = localStorage.getItem('selected_model');
826
+ if (storedModel) {
827
+ const option = modelSelect.querySelector(`option[value="${storedModel}"]`);
828
+ if (option && !option.disabled) {
829
+ modelSelect.value = storedModel;
830
+ } else {
831
+ modelSelect.value = modelSelect.querySelector('option:not([disabled])').value;
832
+ }
833
+ } else {
834
+ modelSelect.value = modelSelect.querySelector('option:not([disabled])').value;
835
+ }
836
+ }
837
+
838
+ apiKeyInput.value = apiKey;
839
+ languageSelect.value = selectedLanguage;
840
+ setInitialModelValue();
841
+ ttsSelect.value = selectedTts;
842
+ systemPromptInput.value = systemPrompt;
843
+ updateLanguageDisplay();
844
+ updateModelDisplay();
845
+ updateTtsDisplay();
846
+ document.getElementById('auto-translate-checkbox').checked = autoTranslateEnabled;
847
+ document.getElementById('chat-log-checkbox').checked = chatLoggingEnabled;
848
+ setAnimationState('idle');
849
+ initializeSpeechRecognition();
850
+ </script>
851
+ </body></html>