Add MindSpace page live edit, chat skills, and H5 deploy tooling.
Introduce page edit sessions with draft preview and patch API, chat skill picker, user memory profile, h5ApiBase resolution, voice WAV transport, and scripts for 105/g2 deployment and Plaza local dev. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { transcribeOneShot } from '../voice/asrTransport';
|
||||
import { mapMicError } from '../voice/audioAnalyser';
|
||||
import { shouldFallbackToServerAsr, shouldPreferServerAsr } from '../voice/capabilities';
|
||||
import { MicCapture } from '../voice/micCapture';
|
||||
import { waitForMicRelease } from '../voice/micSession';
|
||||
import { createLiveSpeechRecognition, isSpeechRecognitionSupported } from '../voice/speechRecognition';
|
||||
@@ -18,7 +19,9 @@ export function useVoiceSession({
|
||||
const [phase, setPhase] = useState<VoiceSessionPhase>('idle');
|
||||
const [text, setText] = useState('');
|
||||
const [analyser, setAnalyser] = useState<AnalyserNode | null>(null);
|
||||
const [liveRecognition, setLiveRecognition] = useState(isSpeechRecognitionSupported());
|
||||
const [liveRecognition, setLiveRecognition] = useState(
|
||||
isSpeechRecognitionSupported() && !shouldPreferServerAsr(),
|
||||
);
|
||||
|
||||
const committedRef = useRef('');
|
||||
const interimRef = useRef('');
|
||||
@@ -65,6 +68,26 @@ export function useVoiceSession({
|
||||
setPhase((current) => (current === 'transcribing' ? current : 'ready'));
|
||||
}, []);
|
||||
|
||||
const startServerAsrCapture = useCallback(
|
||||
async (sessionId: number) => {
|
||||
recognitionRef.current?.abort();
|
||||
recognitionRef.current = null;
|
||||
const capture = new MicCapture();
|
||||
captureRef.current = capture;
|
||||
await capture.start();
|
||||
if (sessionRef.current !== sessionId) {
|
||||
await capture.cancel();
|
||||
captureRef.current = null;
|
||||
return false;
|
||||
}
|
||||
setAnalyser(capture.levelAnalyser);
|
||||
setLiveRecognition(false);
|
||||
setPhase('listening');
|
||||
return true;
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const finishFallbackRecording = useCallback(async () => {
|
||||
const duration = Date.now() - startedAtRef.current;
|
||||
const capture = captureRef.current;
|
||||
@@ -115,7 +138,7 @@ export function useVoiceSession({
|
||||
if (sessionRef.current !== sessionId) return;
|
||||
|
||||
startedAtRef.current = Date.now();
|
||||
const useLiveSpeech = isSpeechRecognitionSupported();
|
||||
const useLiveSpeech = isSpeechRecognitionSupported() && !shouldPreferServerAsr();
|
||||
|
||||
if (useLiveSpeech) {
|
||||
const recognition = createLiveSpeechRecognition({
|
||||
@@ -128,9 +151,26 @@ export function useVoiceSession({
|
||||
interimRef.current = '';
|
||||
syncDisplayText();
|
||||
},
|
||||
onError: (message) => onError?.(message),
|
||||
onError: (message) => {
|
||||
if (shouldFallbackToServerAsr(message)) {
|
||||
void startServerAsrCapture(sessionId)
|
||||
.then((ok) => {
|
||||
if (!ok) return;
|
||||
onError?.('实时识别不可用,已切换为录音识别,说完后点「完成识别」');
|
||||
})
|
||||
.catch((err) => onError?.(mapMicError(err)));
|
||||
return;
|
||||
}
|
||||
onError?.(message);
|
||||
},
|
||||
});
|
||||
if (!recognition) throw new Error('当前浏览器不支持实时语音识别');
|
||||
if (!recognition) {
|
||||
if (MicCapture.isSupported()) {
|
||||
const ok = await startServerAsrCapture(sessionId);
|
||||
if (ok) return;
|
||||
}
|
||||
throw new Error('当前浏览器不支持实时语音识别');
|
||||
}
|
||||
recognitionRef.current = recognition;
|
||||
recognition.start();
|
||||
if (sessionRef.current !== sessionId) {
|
||||
@@ -166,7 +206,7 @@ export function useVoiceSession({
|
||||
return () => {
|
||||
void cleanup();
|
||||
};
|
||||
}, [active, cleanup, onError, resetSession, syncDisplayText]);
|
||||
}, [active, cleanup, onError, resetSession, startServerAsrCapture, syncDisplayText]);
|
||||
|
||||
const updateText = useCallback((value: string) => {
|
||||
userEditedRef.current = true;
|
||||
|
||||
Reference in New Issue
Block a user