|
1584 | 1584 | var micPermissionGranted = false; |
1585 | 1585 | var cachedMicDevices = null; |
1586 | 1586 | var disposeVoiceRecognitionPopover = null; |
| 1587 | + var voiceRecognitionPopoverRenderGeneration = 0; |
1587 | 1588 |
|
1588 | 1589 | /** 请求麦克风权限并缓存设备列表 */ |
1589 | 1590 | async function ensureMicrophonePermission() { |
|
1632 | 1633 | window.renderFloatingMicList = async function (popupArg) { |
1633 | 1634 | var micPopup = popupArg || document.getElementById('live2d-popup-mic') || document.getElementById('vrm-popup-mic') || document.getElementById('mmd-popup-mic'); |
1634 | 1635 | if (!micPopup) return false; |
| 1636 | + var renderGeneration = ++voiceRecognitionPopoverRenderGeneration; |
1635 | 1637 | if (disposeVoiceRecognitionPopover) { |
1636 | | - disposeVoiceRecognitionPopover(); |
| 1638 | + var previousDispose = disposeVoiceRecognitionPopover; |
1637 | 1639 | disposeVoiceRecognitionPopover = null; |
| 1640 | + previousDispose(); |
1638 | 1641 | } |
1639 | 1642 | var popupId = micPopup.id; |
1640 | 1643 | var isPopupAvailable = function () { |
|
1646 | 1649 |
|
1647 | 1650 | try { |
1648 | 1651 | var audioInputs = await ensureMicrophonePermission(); |
1649 | | - if (!isPopupAvailable()) return false; |
| 1652 | + if ( |
| 1653 | + renderGeneration !== voiceRecognitionPopoverRenderGeneration |
| 1654 | + || !isPopupAvailable() |
| 1655 | + ) return false; |
1650 | 1656 | micPopup.innerHTML = ''; |
1651 | 1657 |
|
1652 | 1658 | var hasMicrophoneDevices = audioInputs.length > 0; |
|
1931 | 1937 | }; |
1932 | 1938 | } |
1933 | 1939 |
|
1934 | | - var voiceSettingsPending = false; |
| 1940 | + var voiceSettingsPendingUntilEpoch = null; |
| 1941 | + function markVoiceSettingsPending() { |
| 1942 | + voiceSettingsPendingUntilEpoch = ( |
| 1943 | + Number(S.voiceSessionStartEpoch) || 0 |
| 1944 | + ) + 1; |
| 1945 | + } |
1935 | 1946 | var asrToggle = createVoiceSettingToggle( |
1936 | 1947 | S.independentAsrEnabled === true, |
1937 | 1948 | function (enabled) { |
1938 | 1949 | S.independentAsrEnabled = enabled; |
1939 | | - voiceSettingsPending = true; |
| 1950 | + markVoiceSettingsPending(); |
1940 | 1951 | updateVoiceRecognitionUi(); |
1941 | 1952 | if (window.appSettings && typeof window.appSettings.saveSettings === 'function') { |
1942 | 1953 | window.appSettings.saveSettings(); |
|
2004 | 2015 | S.voiceInputResourceOptimizationEnabled !== false, |
2005 | 2016 | function (enabled) { |
2006 | 2017 | S.voiceInputResourceOptimizationEnabled = enabled; |
2007 | | - voiceSettingsPending = true; |
| 2018 | + markVoiceSettingsPending(); |
2008 | 2019 | updateVoiceRecognitionUi(); |
2009 | 2020 | if (window.appSettings && typeof window.appSettings.saveSettings === 'function') { |
2010 | 2021 | window.appSettings.saveSettings(); |
|
2045 | 2056 | : 'microphone.independentAsrSummaryGeneric', { provider: provider }) |
2046 | 2057 | : ('独立 ASR' + (provider ? ' · ' + provider : ''))) |
2047 | 2058 | : (window.t ? window.t('microphone.voiceRecognitionDisabled') : '当前使用 Omni 原生语音识别'); |
2048 | | - if (voiceSettingsPending) { |
| 2059 | + if (voiceSettingsPendingUntilEpoch !== null) { |
2049 | 2060 | voiceStatus.textContent = window.t |
2050 | 2061 | ? window.t('microphone.voiceRecognitionSettingsPending') |
2051 | 2062 | : '◐ 设置将在下次语音会话生效'; |
|
2184 | 2195 | } |
2185 | 2196 | } |
2186 | 2197 | function onVoiceLifecycleChanged() { updateVoiceRecognitionUi(); } |
| 2198 | + function onVoiceSessionStarted() { |
| 2199 | + if ( |
| 2200 | + voiceSettingsPendingUntilEpoch === null |
| 2201 | + || (Number(S.voiceSessionStartEpoch) || 0) |
| 2202 | + < voiceSettingsPendingUntilEpoch |
| 2203 | + ) return; |
| 2204 | + voiceSettingsPendingUntilEpoch = null; |
| 2205 | + updateVoiceRecognitionUi(); |
| 2206 | + } |
2187 | 2207 | document.addEventListener('pointerdown', onVoiceDocumentPointerDown, true); |
2188 | 2208 | document.addEventListener('keydown', onVoiceDocumentKeyDown, true); |
2189 | 2209 | window.addEventListener('resize', positionVoicePanel); |
2190 | 2210 | window.addEventListener('scroll', positionVoicePanel, true); |
2191 | 2211 | window.addEventListener('voice-input-lifecycle-changed', onVoiceLifecycleChanged); |
| 2212 | + window.addEventListener('neko:voice-session-started', onVoiceSessionStarted); |
2192 | 2213 | var voicePopupObserver = new MutationObserver(function () { |
2193 | 2214 | if (!isPopupAvailable()) closeVoicePanel(true); |
2194 | 2215 | }); |
2195 | 2216 | voicePopupObserver.observe(micPopup, { attributes: true, attributeFilter: ['style', 'class'] }); |
2196 | | - disposeVoiceRecognitionPopover = function () { |
| 2217 | + var voicePopoverDisposed = false; |
| 2218 | + function disposeCurrentVoiceRecognitionPopover() { |
| 2219 | + if (voicePopoverDisposed) return; |
| 2220 | + voicePopoverDisposed = true; |
2197 | 2221 | clearVoiceTimers(); |
2198 | 2222 | voicePopupObserver.disconnect(); |
2199 | 2223 | document.removeEventListener('pointerdown', onVoiceDocumentPointerDown, true); |
2200 | 2224 | document.removeEventListener('keydown', onVoiceDocumentKeyDown, true); |
2201 | 2225 | window.removeEventListener('resize', positionVoicePanel); |
2202 | 2226 | window.removeEventListener('scroll', positionVoicePanel, true); |
2203 | 2227 | window.removeEventListener('voice-input-lifecycle-changed', onVoiceLifecycleChanged); |
| 2228 | + window.removeEventListener('neko:voice-session-started', onVoiceSessionStarted); |
2204 | 2229 | voicePanel.remove(); |
2205 | 2230 | voiceBridge.remove(); |
2206 | | - }; |
| 2231 | + if ( |
| 2232 | + disposeVoiceRecognitionPopover |
| 2233 | + === disposeCurrentVoiceRecognitionPopover |
| 2234 | + ) disposeVoiceRecognitionPopover = null; |
| 2235 | + } |
| 2236 | + disposeVoiceRecognitionPopover = disposeCurrentVoiceRecognitionPopover; |
2207 | 2237 |
|
2208 | 2238 | var sep1b = document.createElement('div'); |
2209 | 2239 | Object.assign(sep1b.style, { height: '1px', backgroundColor: 'var(--neko-popup-separator)', margin: '8px 0' }); |
|
0 commit comments