@@ -8,7 +8,7 @@ import { useInterrupt } from '@/components/canvas/live2d';
88import { audioTaskQueue } from '@/utils/task-queue' ;
99import { useSendAudio } from '@/hooks/utils/use-send-audio' ;
1010import { SubtitleContext } from './subtitle-context' ;
11- import { AiStateContext } from './ai-state-context' ;
11+ import { AiStateContext , AiState } from './ai-state-context' ;
1212import { useLocalStorage } from '@/hooks/utils/use-local-storage' ;
1313import { toaster } from '@/components/ui/toaster' ;
1414
@@ -108,7 +108,7 @@ export function VADProvider({ children }: { children: React.ReactNode }) {
108108 // Refs for VAD instance and state
109109 const vadRef = useRef < MicVAD | null > ( null ) ;
110110 const previousTriggeredProbabilityRef = useRef ( 0 ) ;
111- const previousAiStateRef = useRef < string > ( 'idle' ) ;
111+ const previousAiStateRef = useRef < AiState > ( 'idle' ) ;
112112
113113 // Persistent state management
114114 const [ micOn , setMicOn ] = useLocalStorage ( 'micOn' , DEFAULT_VAD_STATE . micOn ) ;
@@ -144,7 +144,7 @@ export function VADProvider({ children }: { children: React.ReactNode }) {
144144 // Refs for callback stability
145145 const interruptRef = useRef ( interrupt ) ;
146146 const sendAudioPartitionRef = useRef ( sendAudioPartition ) ;
147- const aiStateRef = useRef < string > ( aiState ) ;
147+ const aiStateRef = useRef < AiState > ( aiState ) ;
148148 const setSubtitleTextRef = useRef ( setSubtitleText ) ;
149149 const setAiStateRef = useRef ( setAiState ) ;
150150
@@ -195,21 +195,25 @@ export function VADProvider({ children }: { children: React.ReactNode }) {
195195 * Handle speech start event (initial detection)
196196 */
197197 const handleSpeechStart = useCallback ( ( ) => {
198- console . log ( 'Speech started - entering listening state' ) ;
199- // Save current AI state before changing to listening
198+ console . log ( 'Speech started - saving current state' ) ;
199+ // Save current AI state but DON'T change to listening yet
200200 previousAiStateRef . current = aiStateRef . current ;
201201 isProcessingRef . current = true ;
202- setAiStateRef . current ( 'listening' ) ;
202+ // Don't change state here - wait for onSpeechRealStart
203203 } , [ ] ) ;
204204
205205 /**
206206 * Handle real speech start event (confirmed speech)
207207 */
208208 const handleSpeechRealStart = useCallback ( ( ) => {
209- console . log ( 'Real speech confirmed - interrupting AI if needed' ) ;
210- if ( aiStateRef . current === 'thinking-speaking' ) {
209+ console . log ( 'Real speech confirmed - checking if need to interrupt' ) ;
210+ // Check if we need to interrupt based on the PREVIOUS state (before speech started)
211+ if ( previousAiStateRef . current === 'thinking-speaking' ) {
212+ console . log ( 'Interrupting AI speech due to user speaking' ) ;
211213 interruptRef . current ( ) ;
212214 }
215+ // Now change to listening state
216+ setAiStateRef . current ( 'listening' ) ;
213217 } , [ ] ) ;
214218
215219 /**
@@ -238,6 +242,7 @@ export function VADProvider({ children }: { children: React.ReactNode }) {
238242 setPreviousTriggeredProbability ( 0 ) ;
239243 sendAudioPartitionRef . current ( audio ) ;
240244 isProcessingRef . current = false ;
245+ setAiStateRef . current ( "thinking-speaking" ) ;
241246 } , [ ] ) ;
242247
243248 /**
0 commit comments