feat: 更新音频处理逻辑,添加最后识别文本功能并优化相关提示信息
This commit is contained in:
@@ -7,7 +7,7 @@ import tailwindcss from '@tailwindcss/vite';
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
let target = process.env.VITE_API_URL || 'http://localhost:51015';
|
||||
let target = process.env.VITE_API_URL || 'http://localhost:51515';
|
||||
const apiProxy = { target: target, changeOrigin: true, ws: true, rewriteWsOrigin: true, secure: false, cookieDomainRewrite: 'localhost' };
|
||||
|
||||
let proxy = {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@kevisual/light-code-center",
|
||||
"version": "0.0.1",
|
||||
"version": "0.0.2",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"basename": "/root/light-code-center",
|
||||
@@ -8,7 +8,7 @@
|
||||
"dev": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"pub": "envision deploy ./dist -k light-code-center -v 0.0.1 -u",
|
||||
"pub": "envision deploy ./dist -k light-code-center -v 0.0.2 -u -y y",
|
||||
"ui": "pnpm dlx shadcn@latest add ",
|
||||
"sn": "pnpm dlx shadcn@latest add "
|
||||
},
|
||||
|
||||
@@ -363,7 +363,8 @@ export const VadVoice = () => {
|
||||
addVoice,
|
||||
setError: setStoreError,
|
||||
relatimeParialText,
|
||||
relatimeFinalText
|
||||
relatimeFinalText,
|
||||
lastRecognizedText
|
||||
} = useVoiceStore();
|
||||
const showText = relatimeFinalText || relatimeParialText;
|
||||
// 使用设置 store
|
||||
@@ -399,10 +400,11 @@ export const VadVoice = () => {
|
||||
onSpeechEnd: async (audio) => {
|
||||
try {
|
||||
const wavBuffer = utils.encodeWAV(audio)
|
||||
const audioBlob = new Blob([wavBuffer], { type: 'audio/wav' })
|
||||
const tempUrl = URL.createObjectURL(audioBlob)
|
||||
const relatime = useVoiceStore.getState().relatime;
|
||||
relatime?.sendBase64?.(utils.arrayBufferToBase64(wavBuffer));
|
||||
const audioBlob = new Blob([wavBuffer], { type: 'audio/wav' })
|
||||
const tempUrl = URL.createObjectURL(audioBlob)
|
||||
|
||||
// 从实际音频文件获取准确时长
|
||||
const getDuration = (): Promise<number> => {
|
||||
return new Promise((resolve) => {
|
||||
@@ -413,8 +415,9 @@ export const VadVoice = () => {
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
relatime?.showCostTime?.();
|
||||
const duration = await getDuration();
|
||||
relatime?.showCostTime?.();
|
||||
console.log(`Detected speech end. Duration: ${duration.toFixed(2)}s`);
|
||||
|
||||
// 使用 store 添加语音记录
|
||||
@@ -431,7 +434,9 @@ export const VadVoice = () => {
|
||||
onSpeechRealStart: () => {
|
||||
console.log('VAD real start');
|
||||
setRealListen(true);
|
||||
}
|
||||
const relatime = useVoiceStore.getState().relatime;
|
||||
relatime?.setStartTime?.(Date.now());
|
||||
},
|
||||
});
|
||||
|
||||
ref.current = myvad;
|
||||
@@ -524,8 +529,8 @@ export const VadVoice = () => {
|
||||
voiceList.length === 0 ? (
|
||||
<div className="text-center text-gray-400 text-sm py-8">
|
||||
<div className="mb-2">🎤</div>
|
||||
<div>No recordings yet</div>
|
||||
<div className="text-xs mt-1">Start talking to record</div>
|
||||
<div>暂无录音</div>
|
||||
<div className="text-xs mt-1">开始说话以录音</div>
|
||||
</div>
|
||||
) : (
|
||||
<ShowVoicePlayer data={voiceList} />
|
||||
@@ -537,8 +542,8 @@ export const VadVoice = () => {
|
||||
initializeVAD(listen)
|
||||
}}>
|
||||
<div className="mb-2">🎤</div>
|
||||
<div>Click anywhere to initialize microphone</div>
|
||||
<div className="text-xs mt-1">Browser requires user interaction for microphone access</div>
|
||||
<div>点击任意位置以初始化麦克风</div>
|
||||
<div className="text-xs mt-1">浏览器需要用户交互以访问麦克风</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -576,6 +581,27 @@ export const VadVoice = () => {
|
||||
)}
|
||||
</div>
|
||||
<div className=" ">
|
||||
{lastRecognizedText && (
|
||||
<div className="flex">
|
||||
<div className="text-xs text-gray-400 mt-1 truncate">
|
||||
🕘 上次识别: {lastRecognizedText}
|
||||
</div>
|
||||
<div className="cursor-pointer " onClick={() => {
|
||||
// copy
|
||||
navigator.clipboard.writeText(lastRecognizedText).then(() => {
|
||||
toast.success('已复制', {
|
||||
autoClose: 500,
|
||||
position: 'top-center'
|
||||
});
|
||||
}).catch((error) => {
|
||||
console.error('复制失败:', error);
|
||||
toast.error('复制失败,请手动选择文字复制');
|
||||
});
|
||||
}}>
|
||||
<Copy className='text-gray-400' />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{showText && (
|
||||
<div className="flex">
|
||||
<div className="text-xs text-gray-600 mt-1 truncate">
|
||||
|
||||
@@ -5,6 +5,7 @@ export class Relatime {
|
||||
asr: WSServer
|
||||
ready = false
|
||||
timeoutHandle: NodeJS.Timeout | null = null
|
||||
startTime: number = 0
|
||||
constructor() {
|
||||
// const url = new URL('/ws/asr', "http://localhost:51015")
|
||||
const url = new URL('/ws/asr', window.location.origin)
|
||||
@@ -51,15 +52,20 @@ export class Relatime {
|
||||
}
|
||||
sendBase64(data: string) {
|
||||
if (!this.ready) return;
|
||||
this.asr.ws.send(JSON.stringify({ voice: data, format: 'float32' }));
|
||||
if (this.timeoutHandle) {
|
||||
clearTimeout(this.timeoutHandle);
|
||||
}
|
||||
this.timeoutHandle = setTimeout(() => {
|
||||
this.asr.sendBlankJson()
|
||||
this.timeoutHandle = null;
|
||||
}, 10000); // 5秒钟没有数据则发送空JSON保持连接
|
||||
|
||||
console.log('send 花费时间:', Date.now() - this.startTime);
|
||||
this.asr.ws.send(JSON.stringify({ voice: data, format: 'float32', time: Date.now() }));
|
||||
// if (this.timeoutHandle) {
|
||||
// clearTimeout(this.timeoutHandle);
|
||||
// }
|
||||
// this.timeoutHandle = setTimeout(() => {
|
||||
// this.asr.sendBlankJson()
|
||||
// this.timeoutHandle = null;
|
||||
// }, 20000); // 20秒钟没有数据则发送空JSON保持连接
|
||||
}
|
||||
setStartTime(time: number) {
|
||||
this.startTime = time;
|
||||
}
|
||||
showCostTime() {
|
||||
console.log('当前花费时间:', Date.now() - this.startTime);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ interface VoiceState {
|
||||
setLoading: (loading: boolean) => void;
|
||||
relatime: Relatime;
|
||||
relatimeParialText: string;
|
||||
lastRecognizedText: string;
|
||||
relatimeFinalText: string;
|
||||
setRelatimeParialText: (text: string) => void;
|
||||
setRelatimeFinalText: (text: string) => void;
|
||||
@@ -338,12 +339,14 @@ export const useVoiceStore = create<VoiceState>()(
|
||||
|
||||
relatimeFinalText: '',
|
||||
setRelatimeFinalText: (text: string) => {
|
||||
set({ relatimeFinalText: text, relatimeParialText: '' });
|
||||
const { relatimeFinalText } = get();
|
||||
set(() => ({ relatimeFinalText: text, relatimeParialText: '', lastRecognizedText: relatimeFinalText }));
|
||||
},
|
||||
setRelatimeParialText: (text: string) => {
|
||||
set({ relatimeFinalText: '', relatimeParialText: text });
|
||||
set({ relatimeParialText: text });
|
||||
},
|
||||
relatimeParialText: '',
|
||||
lastRecognizedText: '',
|
||||
}),
|
||||
{
|
||||
name: 'voice-store', // persist key
|
||||
|
||||
Reference in New Issue
Block a user