isaikr 0.0.1
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/README.md +35 -0
- package/cdn/api.js +19 -0
- package/cdn/character.js +254 -0
- package/cdn/chat.js +33 -0
- package/cdn/code-editor.js +1131 -0
- package/cdn/community-compose.js +270 -0
- package/cdn/games/2048/index.html +12 -0
- package/cdn/games/breakout/index.html +13 -0
- package/cdn/games/clicker/index.html +26 -0
- package/cdn/games/flappy/index.html +11 -0
- package/cdn/games/memory/index.html +34 -0
- package/cdn/games/pong/index.html +13 -0
- package/cdn/games/reaction/index.html +38 -0
- package/cdn/games/runner/index.html +11 -0
- package/cdn/games/snake/index.html +11 -0
- package/cdn/games/tetris/index.html +14 -0
- package/cdn/games/whack/index.html +8 -0
- package/cdn/go.js +126 -0
- package/cdn/go2.js +127 -0
- package/cdn/header3_behavior.js +1167 -0
- package/cdn/header3_layout.js +1004 -0
- package/cdn/header3_layout.js.bak +1004 -0
- package/cdn/header3_style.css +3524 -0
- package/cdn/header3_style.css.bak +3514 -0
- package/cdn/lang.js +198 -0
- package/cdn/loading.js +143 -0
- package/cdn/loading2.js +144 -0
- package/cdn/local-model.js +2941 -0
- package/cdn/main.js +4 -0
- package/cdn/main_asset.js +1849 -0
- package/cdn/main_asset.js.bak +6999 -0
- package/cdn/main_index.css +287 -0
- package/cdn/re_board3.css +733 -0
- package/cdn/re_board3.js +734 -0
- package/cdn/re_chat_tts.js +652 -0
- package/cdn/re_local_runtime.js +2246 -0
- package/cdn/re_local_runtime.js.bak +2246 -0
- package/cdn/re_share.js +577 -0
- package/cdn/re_voice.js +542 -0
- package/cdn/utils.js +36 -0
- package/cdn/view.js +321 -0
- package/header3_behavior.js +804 -0
- package/header3_layout.js +998 -0
- package/header3_style.css +2740 -0
- package/index.js +0 -0
- package/lang.js +179 -0
- package/main_asset.js +2416 -0
- package/main_index.css +274 -0
- package/package.json +14 -0
- package/re_chat_tts.js +1419 -0
- package/re_voice.js +430 -0
package/re_voice.js
ADDED
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
function getIsaiVoiceSettingsSafe() {
|
|
2
|
+
const settings = (typeof window.getIsaiVoiceSettings === 'function')
|
|
3
|
+
? (window.getIsaiVoiceSettings() || {})
|
|
4
|
+
: (window.ISAI_VOICE_SETTINGS || {});
|
|
5
|
+
|
|
6
|
+
const merged = Object.assign({
|
|
7
|
+
ttsEngine: 'browser',
|
|
8
|
+
recognitionLang: 'auto',
|
|
9
|
+
speechLang: 'auto',
|
|
10
|
+
voiceName: '',
|
|
11
|
+
rate: 1,
|
|
12
|
+
pitch: 1,
|
|
13
|
+
volume: 1
|
|
14
|
+
}, settings || {});
|
|
15
|
+
merged.ttsEngine = 'browser';
|
|
16
|
+
return merged;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function stopSupertonicPlayback() {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalizeIsaiVoiceLang(langCode) {
|
|
24
|
+
const raw = String(langCode || '').trim();
|
|
25
|
+
const fallback = (typeof LANG !== 'undefined' && LANG === 'ko') ? 'ko-KR' : (navigator.language || 'en-US');
|
|
26
|
+
if (!raw || raw === 'auto') return fallback;
|
|
27
|
+
if (raw.includes('-')) return raw;
|
|
28
|
+
|
|
29
|
+
const map = {
|
|
30
|
+
ko: 'ko-KR',
|
|
31
|
+
en: 'en-US',
|
|
32
|
+
ja: 'ja-JP',
|
|
33
|
+
zh: 'zh-CN',
|
|
34
|
+
es: 'es-ES',
|
|
35
|
+
fr: 'fr-FR',
|
|
36
|
+
de: 'de-DE',
|
|
37
|
+
ru: 'ru-RU',
|
|
38
|
+
pt: 'pt-PT',
|
|
39
|
+
hi: 'hi-IN'
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return map[raw] || fallback;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function resolveSpeechVoiceByName(name, langCode) {
|
|
46
|
+
const voices = window.speechSynthesis && typeof window.speechSynthesis.getVoices === 'function'
|
|
47
|
+
? window.speechSynthesis.getVoices()
|
|
48
|
+
: [];
|
|
49
|
+
|
|
50
|
+
if (!voices.length) return null;
|
|
51
|
+
|
|
52
|
+
const voiceName = String(name || '').trim();
|
|
53
|
+
if (voiceName) {
|
|
54
|
+
const exactMatch = voices.find((voice) => voice.name === voiceName);
|
|
55
|
+
if (exactMatch) return exactMatch;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const normalizedLang = String(langCode || '').toLowerCase();
|
|
59
|
+
const langPrefix = normalizedLang.split('-')[0];
|
|
60
|
+
return voices.find((voice) => String(voice.lang || '').toLowerCase() === normalizedLang)
|
|
61
|
+
|| voices.find((voice) => String(voice.lang || '').toLowerCase().startsWith(`${langPrefix}-`))
|
|
62
|
+
|| voices[0]
|
|
63
|
+
|| null;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function updateRecognitionLang() {
|
|
67
|
+
if (!recognition) return;
|
|
68
|
+
|
|
69
|
+
let targetLangCode = 'en-US';
|
|
70
|
+
|
|
71
|
+
if (currentMode === 'translate') {
|
|
72
|
+
const leftEl = document.getElementById('trans-select-left');
|
|
73
|
+
const rightEl = document.getElementById('trans-select-right');
|
|
74
|
+
const leftVal = leftEl ? leftEl.value : 'English';
|
|
75
|
+
const rightVal = rightEl ? rightEl.value : 'Korean';
|
|
76
|
+
|
|
77
|
+
if (translationSide === 'left') {
|
|
78
|
+
targetLangCode = langMap[leftVal] || 'en-US';
|
|
79
|
+
} else {
|
|
80
|
+
targetLangCode = langMap[rightVal] || 'ko-KR';
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
const settings = getIsaiVoiceSettingsSafe();
|
|
84
|
+
targetLangCode = normalizeIsaiVoiceLang(settings.recognitionLang);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
recognition.lang = targetLangCode;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function beginListeningForSide(side) {
|
|
91
|
+
translationSide = side;
|
|
92
|
+
setTimeout(() => {
|
|
93
|
+
try {
|
|
94
|
+
isVoiceListening = true;
|
|
95
|
+
if (typeof setVoiceState === 'function') setVoiceState(side, 'recording');
|
|
96
|
+
if (recognition) {
|
|
97
|
+
updateRecognitionLang();
|
|
98
|
+
recognition.start();
|
|
99
|
+
} else {
|
|
100
|
+
initVoiceMode();
|
|
101
|
+
}
|
|
102
|
+
} catch (error) {
|
|
103
|
+
initVoiceMode();
|
|
104
|
+
}
|
|
105
|
+
}, 100);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function initVoiceMode() {
|
|
109
|
+
window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
|
110
|
+
|
|
111
|
+
if (!window.SpeechRecognition) {
|
|
112
|
+
if (typeof showToast === 'function') showToast('Browser does not support Speech Recognition.');
|
|
113
|
+
if (typeof setMode === 'function') setMode('chat');
|
|
114
|
+
if (typeof setVoiceState === 'function') setVoiceState('left', 'idle');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (!recognition) {
|
|
119
|
+
recognition = new SpeechRecognition();
|
|
120
|
+
recognition.continuous = true;
|
|
121
|
+
recognition.interimResults = true;
|
|
122
|
+
|
|
123
|
+
recognition.onstart = function () {
|
|
124
|
+
isVoiceListening = true;
|
|
125
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide, 'recording');
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
recognition.onend = function () {
|
|
129
|
+
const activeVoiceMode = (currentMode === 'voice' || currentMode === 'translate');
|
|
130
|
+
if (activeVoiceMode && isVoiceListening && !isVoiceProcessing) {
|
|
131
|
+
try {
|
|
132
|
+
updateRecognitionLang();
|
|
133
|
+
recognition.start();
|
|
134
|
+
return;
|
|
135
|
+
} catch (error) {}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
isVoiceListening = false;
|
|
139
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide, 'idle');
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
recognition.onresult = function (event) {
|
|
143
|
+
if (isVoiceProcessing) return;
|
|
144
|
+
|
|
145
|
+
let interim = '';
|
|
146
|
+
let final = '';
|
|
147
|
+
|
|
148
|
+
for (let i = event.resultIndex; i < event.results.length; i += 1) {
|
|
149
|
+
if (event.results[i].isFinal) final += event.results[i][0].transcript;
|
|
150
|
+
else interim += event.results[i][0].transcript;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const input = document.getElementById('prompt-input');
|
|
154
|
+
if (!input) return;
|
|
155
|
+
|
|
156
|
+
if (interim) {
|
|
157
|
+
input.value = interim;
|
|
158
|
+
input.style.opacity = '0.7';
|
|
159
|
+
if (typeof handleInput === 'function') handleInput(input);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (!final) return;
|
|
163
|
+
|
|
164
|
+
input.value = final.trim();
|
|
165
|
+
input.style.opacity = '1';
|
|
166
|
+
if (typeof handleInput === 'function') handleInput(input);
|
|
167
|
+
|
|
168
|
+
if (!input.value) return;
|
|
169
|
+
|
|
170
|
+
if (recognition) recognition.stop();
|
|
171
|
+
|
|
172
|
+
if (currentMode === 'translate') {
|
|
173
|
+
performTranslationRequest(input.value, translationSide);
|
|
174
|
+
} else {
|
|
175
|
+
performVoiceConversationRequest(input.value);
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
recognition.onerror = function (event) {
|
|
180
|
+
if (typeof console !== 'undefined' && console.error) console.error('Mic Error:', event.error);
|
|
181
|
+
if (event.error === 'not-allowed' && typeof showToast === 'function') {
|
|
182
|
+
showToast('Microphone permission denied.');
|
|
183
|
+
}
|
|
184
|
+
isVoiceListening = false;
|
|
185
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide, 'idle');
|
|
186
|
+
if ((event.error === 'not-allowed' || event.error === 'service-not-allowed') && typeof setMode === 'function') {
|
|
187
|
+
setMode('chat');
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
updateRecognitionLang();
|
|
193
|
+
|
|
194
|
+
try {
|
|
195
|
+
isVoiceListening = true;
|
|
196
|
+
recognition.start();
|
|
197
|
+
} catch (error) {
|
|
198
|
+
if (typeof console !== 'undefined' && console.log) console.log('Recognition start ignored', error);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
async function performVoiceConversationRequest(text) {
|
|
203
|
+
isVoiceProcessing = true;
|
|
204
|
+
if (typeof setVoiceState === 'function') setVoiceState('left', 'processing');
|
|
205
|
+
|
|
206
|
+
const input = document.getElementById('prompt-input');
|
|
207
|
+
const userText = String(text || '').trim();
|
|
208
|
+
if (!userText) {
|
|
209
|
+
isVoiceProcessing = false;
|
|
210
|
+
if (typeof setVoiceState === 'function') setVoiceState('left', 'idle');
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (input) {
|
|
215
|
+
input.value = '';
|
|
216
|
+
input.style.opacity = '1';
|
|
217
|
+
if (typeof handleInput === 'function') handleInput(input);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (typeof appendMsg === 'function') appendMsg('user', userText);
|
|
221
|
+
if (typeof startExperience === 'function') startExperience();
|
|
222
|
+
if (typeof showLoader === 'function') showLoader(true);
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
let finalPrompt = userText;
|
|
226
|
+
let sysPrompt = (typeof SYSTEM_PROMPTS !== 'undefined' && SYSTEM_PROMPTS[LANG])
|
|
227
|
+
? SYSTEM_PROMPTS[LANG]
|
|
228
|
+
: 'You are a helpful AI.';
|
|
229
|
+
|
|
230
|
+
if (typeof activeApp !== 'undefined' && activeApp && activeApp.system_prompt) {
|
|
231
|
+
sysPrompt = activeApp.system_prompt;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (typeof window.buildIsaiSystemPrompt === 'function') {
|
|
235
|
+
sysPrompt = window.buildIsaiSystemPrompt(sysPrompt);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const history = Array.isArray(chatHistory) ? chatHistory.slice(-6) : [];
|
|
239
|
+
const response = await fetch('?action=ai_chat', {
|
|
240
|
+
method: 'POST',
|
|
241
|
+
body: JSON.stringify({ prompt: finalPrompt, history: history, system_prompt: sysPrompt })
|
|
242
|
+
});
|
|
243
|
+
const data = await response.json();
|
|
244
|
+
|
|
245
|
+
if (!data || !data.response) {
|
|
246
|
+
throw new Error(data && data.error ? data.error : 'Voice chat failed');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const bubbleHtml = (typeof parseMarkdownLocal === 'function')
|
|
250
|
+
? parseMarkdownLocal(data.response, true)
|
|
251
|
+
: data.response;
|
|
252
|
+
|
|
253
|
+
if (typeof appendMsg === 'function') appendMsg('ai', bubbleHtml);
|
|
254
|
+
|
|
255
|
+
const historyResult = String(data.response).replace(/<think>[\s\S]*?(<\/think>|$)/gi, '').trim();
|
|
256
|
+
if (Array.isArray(chatHistory)) {
|
|
257
|
+
chatHistory.push(
|
|
258
|
+
{ role: 'user', content: userText },
|
|
259
|
+
{ role: 'assistant', content: historyResult }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
if (typeof scrollBottom === 'function') scrollBottom();
|
|
264
|
+
speakText(data.response);
|
|
265
|
+
} catch (error) {
|
|
266
|
+
isVoiceProcessing = false;
|
|
267
|
+
if (typeof appendMsg === 'function') appendMsg('error', `Voice Error: ${error.message || error}`);
|
|
268
|
+
if (typeof setVoiceState === 'function') setVoiceState('left', 'idle');
|
|
269
|
+
} finally {
|
|
270
|
+
if (typeof showLoader === 'function') showLoader(false);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function performTranslationRequest(text, side) {
|
|
275
|
+
isVoiceProcessing = true;
|
|
276
|
+
if (typeof setVoiceState === 'function') setVoiceState(side, 'processing');
|
|
277
|
+
|
|
278
|
+
const input = document.getElementById('prompt-input');
|
|
279
|
+
const userText = String(text || '').trim();
|
|
280
|
+
if (!userText) {
|
|
281
|
+
isVoiceProcessing = false;
|
|
282
|
+
if (typeof setVoiceState === 'function') setVoiceState(side, 'idle');
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (input) {
|
|
287
|
+
input.value = '';
|
|
288
|
+
input.style.opacity = '1';
|
|
289
|
+
if (typeof handleInput === 'function') handleInput(input);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (typeof appendMsg === 'function') appendMsg('user', userText);
|
|
293
|
+
|
|
294
|
+
const leftLang = document.getElementById('trans-select-left')?.value || 'English';
|
|
295
|
+
const rightLang = document.getElementById('trans-select-right')?.value || 'Korean';
|
|
296
|
+
const targetLangName = side === 'left' ? rightLang : leftLang;
|
|
297
|
+
|
|
298
|
+
try {
|
|
299
|
+
const res = await fetch('?action=ai_translate', {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
body: JSON.stringify({ text: userText, target_lang: targetLangName })
|
|
302
|
+
});
|
|
303
|
+
const data = await res.json();
|
|
304
|
+
|
|
305
|
+
let resultText = data.response || '';
|
|
306
|
+
try {
|
|
307
|
+
const clean = String(data.response || '').replace(/```json/g, '').replace(/```/g, '').trim();
|
|
308
|
+
const parsed = JSON.parse(clean);
|
|
309
|
+
resultText = parsed.text || resultText;
|
|
310
|
+
} catch (error) {}
|
|
311
|
+
|
|
312
|
+
if (typeof appendMsg === 'function') {
|
|
313
|
+
appendMsg('ai', `<div class="text-lg font-bold text-blue-300 leading-relaxed">${resultText}</div>`);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
const targetCode = langMap[targetLangName] || 'en-US';
|
|
317
|
+
speakText(resultText, targetCode);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
if (typeof console !== 'undefined' && console.error) console.error(error);
|
|
320
|
+
isVoiceProcessing = false;
|
|
321
|
+
if (isVoiceListening) {
|
|
322
|
+
try {
|
|
323
|
+
if (recognition) recognition.start();
|
|
324
|
+
} catch (restartError) {}
|
|
325
|
+
if (typeof setVoiceState === 'function') setVoiceState(side, 'recording');
|
|
326
|
+
} else if (typeof setVoiceState === 'function') {
|
|
327
|
+
setVoiceState(side, 'idle');
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function stopVoiceMode(fullExit = true) {
|
|
333
|
+
if (recognition) {
|
|
334
|
+
if (fullExit) {
|
|
335
|
+
recognition.onend = null;
|
|
336
|
+
recognition.abort();
|
|
337
|
+
recognition = null;
|
|
338
|
+
} else {
|
|
339
|
+
recognition.stop();
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
isVoiceListening = false;
|
|
344
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide || 'left', 'idle');
|
|
345
|
+
|
|
346
|
+
const input = document.getElementById('prompt-input');
|
|
347
|
+
if (input) {
|
|
348
|
+
input.placeholder = '';
|
|
349
|
+
input.style.opacity = '1';
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (fullExit) {
|
|
353
|
+
isVoiceProcessing = false;
|
|
354
|
+
stopSupertonicPlayback();
|
|
355
|
+
window.speechSynthesis.cancel();
|
|
356
|
+
if (typeof window.stopIsaiTtsPreview === 'function') {
|
|
357
|
+
window.stopIsaiTtsPreview();
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
function speakText(text, langCode = null) {
|
|
363
|
+
if (currentMode !== 'voice' && currentMode !== 'translate') return;
|
|
364
|
+
|
|
365
|
+
stopSupertonicPlayback();
|
|
366
|
+
window.speechSynthesis.cancel();
|
|
367
|
+
isVoiceProcessing = true;
|
|
368
|
+
if (recognition) recognition.stop();
|
|
369
|
+
|
|
370
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide || 'left', 'processing');
|
|
371
|
+
|
|
372
|
+
const cleanText = String(text || '')
|
|
373
|
+
.replace(/```[\s\S]*?```/g, '')
|
|
374
|
+
.replace(/[*#`\[\]]/g, '')
|
|
375
|
+
.replace(/<[^>]*>?/gm, '');
|
|
376
|
+
|
|
377
|
+
const settings = getIsaiVoiceSettingsSafe();
|
|
378
|
+
const utterance = new SpeechSynthesisUtterance(cleanText);
|
|
379
|
+
const resolvedLang = normalizeIsaiVoiceLang(langCode || settings.speechLang);
|
|
380
|
+
const selectedVoice = resolveSpeechVoiceByName(settings.voiceName, resolvedLang);
|
|
381
|
+
|
|
382
|
+
utterance.lang = selectedVoice && selectedVoice.lang ? selectedVoice.lang : resolvedLang;
|
|
383
|
+
utterance.rate = Math.max(0.7, Math.min(1.4, parseFloat(settings.rate) || 1));
|
|
384
|
+
utterance.pitch = Math.max(0.6, Math.min(1.6, parseFloat(settings.pitch) || 1));
|
|
385
|
+
utterance.volume = Math.max(0, Math.min(1, parseFloat(settings.volume) || 1));
|
|
386
|
+
if (selectedVoice) utterance.voice = selectedVoice;
|
|
387
|
+
|
|
388
|
+
utterance.onend = () => {
|
|
389
|
+
isVoiceProcessing = false;
|
|
390
|
+
if (currentMode === 'voice' || currentMode === 'translate') {
|
|
391
|
+
beginListeningForSide(translationSide || 'left');
|
|
392
|
+
} else if (typeof updateSubmitIcon === 'function') {
|
|
393
|
+
updateSubmitIcon('mic');
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
utterance.onerror = () => {
|
|
398
|
+
isVoiceProcessing = false;
|
|
399
|
+
if (currentMode === 'voice' || currentMode === 'translate') {
|
|
400
|
+
if (typeof setVoiceState === 'function') setVoiceState(translationSide || 'left', 'idle');
|
|
401
|
+
} else if (typeof updateSubmitIcon === 'function') {
|
|
402
|
+
updateSubmitIcon('mic');
|
|
403
|
+
}
|
|
404
|
+
};
|
|
405
|
+
|
|
406
|
+
window.speechSynthesis.speak(utterance);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function updateSubmitIcon(state, side = 'right') {
|
|
410
|
+
if (typeof setVoiceState === 'function') {
|
|
411
|
+
setVoiceState('left', state === 'mic' || state === 'default' ? 'idle' : state);
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const btn = document.getElementById('btn-submit-left');
|
|
416
|
+
const icon = document.getElementById('icon-submit-left');
|
|
417
|
+
|
|
418
|
+
if (!btn || !icon) return;
|
|
419
|
+
|
|
420
|
+
if (state === 'recording') {
|
|
421
|
+
icon.className = 'ri-voiceprint-line text-lg text-white animate-mic-breath';
|
|
422
|
+
btn.style.backgroundColor = '#ef4444';
|
|
423
|
+
} else if (state === 'processing') {
|
|
424
|
+
icon.className = 'ri-voiceprint-line text-lg text-white animate-spin';
|
|
425
|
+
btn.style.backgroundColor = '';
|
|
426
|
+
} else {
|
|
427
|
+
icon.className = 'ri-voiceprint-line text-lg text-white';
|
|
428
|
+
btn.style.backgroundColor = '';
|
|
429
|
+
}
|
|
430
|
+
}
|