fix: 讯飞鉴权签名与官方demo对齐+结束帧+文字修改
- ReportEditor: getXfAuthUrl signatureOrigin去掉引号,Base64改用CryptoJS.enc.Base64.stringify与demo完全一致 - ReportEditor: 第一帧增加dwa: wpgs动态修正参数 - ReportEditor: 停止录音时先发送status:2结束帧再关闭WebSocket - SystemSettings: 标题改为讯飞语音听写Websocket接口配置
This commit is contained in:
@@ -897,11 +897,11 @@ export default function ReportEditor() {
|
|||||||
async function getXfAuthUrl(apiKey: string, apiSecret: string): Promise<string> {
|
async function getXfAuthUrl(apiKey: string, apiSecret: string): Promise<string> {
|
||||||
const host = 'iat-api.xfyun.cn';
|
const host = 'iat-api.xfyun.cn';
|
||||||
const date = new Date().toUTCString();
|
const date = new Date().toUTCString();
|
||||||
const signatureOrigin = `host: "${host}"\ndate: "${date}"\nGET /v2/iat HTTP/1.1`;
|
const signatureOrigin = `host: ${host}\ndate: ${date}\nGET /v2/iat HTTP/1.1`;
|
||||||
const signature = CryptoJS.HmacSHA256(signatureOrigin, apiSecret).toString(CryptoJS.enc.Base64);
|
const signature = CryptoJS.enc.Base64.stringify(CryptoJS.HmacSHA256(signatureOrigin, apiSecret));
|
||||||
const authorizationOrigin = `api_key="${apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
|
const authorizationOrigin = `api_key="${apiKey}", algorithm="hmac-sha256", headers="host date request-line", signature="${signature}"`;
|
||||||
const authorization = btoa(authorizationOrigin);
|
const authorization = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(authorizationOrigin));
|
||||||
return `wss://iat-api.xfyun.cn/v2/iat?authorization=${encodeURIComponent(authorization)}&date=${encodeURIComponent(date)}&host=${encodeURIComponent(host)}`;
|
return `wss://iat-api.xfyun.cn/v2/iat?authorization=${authorization}&date=${date}&host=${host}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function floatTo16BitPCM(input: Float32Array): ArrayBuffer {
|
function floatTo16BitPCM(input: Float32Array): ArrayBuffer {
|
||||||
@@ -925,6 +925,12 @@ export default function ReportEditor() {
|
|||||||
const toggleListening = async () => {
|
const toggleListening = async () => {
|
||||||
if (isListening) {
|
if (isListening) {
|
||||||
setIsListening(false);
|
setIsListening(false);
|
||||||
|
if (xfWsRef.current && xfWsRef.current.readyState === WebSocket.OPEN) {
|
||||||
|
try {
|
||||||
|
const endFrame = { data: { status: 2, format: 'audio/L16;rate=16000', encoding: 'raw', audio: '' } };
|
||||||
|
xfWsRef.current.send(JSON.stringify(endFrame));
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
if (xfWsRef.current) { try { xfWsRef.current.close(); } catch {} xfWsRef.current = null; }
|
if (xfWsRef.current) { try { xfWsRef.current.close(); } catch {} xfWsRef.current = null; }
|
||||||
if (xfAudioContextRef.current) { try { xfAudioContextRef.current.close(); } catch {} xfAudioContextRef.current = null; }
|
if (xfAudioContextRef.current) { try { xfAudioContextRef.current.close(); } catch {} xfAudioContextRef.current = null; }
|
||||||
if (xfMediaStreamRef.current) { xfMediaStreamRef.current.getTracks().forEach(t => t.stop()); xfMediaStreamRef.current = null; }
|
if (xfMediaStreamRef.current) { xfMediaStreamRef.current.getTracks().forEach(t => t.stop()); xfMediaStreamRef.current = null; }
|
||||||
@@ -955,7 +961,7 @@ export default function ReportEditor() {
|
|||||||
const pcmBuffer = floatTo16BitPCM(inputData);
|
const pcmBuffer = floatTo16BitPCM(inputData);
|
||||||
const base64Audio = arrayBufferToBase64(pcmBuffer);
|
const base64Audio = arrayBufferToBase64(pcmBuffer);
|
||||||
const frame: any = { data: { status: frameStatus, format: 'audio/L16;rate=16000', encoding: 'raw', audio: base64Audio } };
|
const frame: any = { data: { status: frameStatus, format: 'audio/L16;rate=16000', encoding: 'raw', audio: base64Audio } };
|
||||||
if (frameStatus === 0) { frame.common = { app_id: xfConfig.appId }; frame.business = { language: 'zh_cn', domain: 'iat', accent: 'mandarin' }; }
|
if (frameStatus === 0) { frame.common = { app_id: xfConfig.appId }; frame.business = { language: 'zh_cn', domain: 'iat', accent: 'mandarin', dwa: 'wpgs' }; }
|
||||||
ws.send(JSON.stringify(frame));
|
ws.send(JSON.stringify(frame));
|
||||||
frameStatus = 1;
|
frameStatus = 1;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -429,7 +429,7 @@ export default function SystemSettings() {
|
|||||||
<div className="flex items-center justify-between mb-6">
|
<div className="flex items-center justify-between mb-6">
|
||||||
<h3 className="text-lg font-bold text-text-main flex items-center gap-2">
|
<h3 className="text-lg font-bold text-text-main flex items-center gap-2">
|
||||||
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-accent"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>
|
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="text-accent"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"/><path d="M19 10v2a7 7 0 0 1-14 0v-2"/><line x1="12" x2="12" y1="19" y2="22"/></svg>
|
||||||
讯飞语音配置
|
讯飞语音听写Websocket接口配置
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="space-y-6">
|
<div className="space-y-6">
|
||||||
|
|||||||
Reference in New Issue
Block a user