fix(test2): 修复语音欢迎语时序与重复回答持久化
This commit is contained in:
@@ -16,11 +16,29 @@ const {
|
||||
normalizeTextForSpeech,
|
||||
splitTextForSpeech,
|
||||
estimateSpeechDurationMs,
|
||||
shouldForceKnowledgeRoute,
|
||||
resolveReply,
|
||||
} = require('./realtimeDialogRouting');
|
||||
|
||||
const sessions = new Map();
|
||||
|
||||
const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
|
||||
|
||||
function resetIdleTimer(session) {
|
||||
clearTimeout(session.idleTimer);
|
||||
session.lastActivityAt = Date.now();
|
||||
session.idleTimer = setTimeout(() => {
|
||||
session.idleTimer = null;
|
||||
console.log(`[NativeVoice] idle timeout (${IDLE_TIMEOUT_MS / 1000}s) session=${session.sessionId}`);
|
||||
sendJson(session.client, { type: 'idle_timeout', timeout: IDLE_TIMEOUT_MS });
|
||||
setTimeout(() => {
|
||||
if (session.client && session.client.readyState === WebSocket.OPEN) {
|
||||
session.client.close();
|
||||
}
|
||||
}, 2000);
|
||||
}, IDLE_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
function sendJson(ws, payload) {
|
||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(JSON.stringify(payload));
|
||||
@@ -33,7 +51,7 @@ function buildStartSessionPayload(options) {
|
||||
extra: {},
|
||||
},
|
||||
tts: {
|
||||
speaker: options.speaker || 'zh_female_vv_jupiter_bigtts',
|
||||
speaker: options.speaker || process.env.VOLC_S2S_SPEAKER_ID || 'zh_female_vv_jupiter_bigtts',
|
||||
audio_config: {
|
||||
channel: 1,
|
||||
format: 'pcm_s16le',
|
||||
@@ -42,12 +60,12 @@ function buildStartSessionPayload(options) {
|
||||
},
|
||||
dialog: {
|
||||
dialog_id: '',
|
||||
bot_name: options.botName || '豆包',
|
||||
system_role: normalizeTextForSpeech(options.systemRole || '你是一个企业知识库语音助手,请优先依据 external_rag 给出的内容回答。'),
|
||||
speaking_style: normalizeTextForSpeech(options.speakingStyle || '请使用清晰、自然、简洁的口吻。'),
|
||||
bot_name: options.botName || '大沃',
|
||||
system_role: normalizeTextForSpeech(options.systemRole || '你是大沃,一个德国PM健康事业的智能语音助手。你对PM-FitLine细胞营养素产品、一成系统、招商合作非常熟悉。请优先依据 external_rag 给出的内容回答。无论是闲聊还是引用知识库内容,都要保持一样的说话风格,不要切换成朗读语气。用户进来时请自然地打个招呼,像朋友聊天一样,不要用客服话术。'),
|
||||
speaking_style: normalizeTextForSpeech(options.speakingStyle || '说话像朋友聊天一样自然轻松,语气亲切活泼,不要像客服念稿。即使引用知识库内容也要用聊天的语气说出来,不要切换成播音腔或朗读语气。'),
|
||||
extra: {
|
||||
input_mod: 'audio',
|
||||
model: 'O',
|
||||
model: options.modelVersion || 'O',
|
||||
strict_audit: false,
|
||||
audit_response: '抱歉,这个问题我暂时无法回答。',
|
||||
},
|
||||
@@ -92,6 +110,7 @@ function persistUserSpeech(session, text) {
|
||||
session.lastPersistedUserText = cleanText;
|
||||
session.lastPersistedUserAt = now;
|
||||
session.latestUserText = cleanText;
|
||||
resetIdleTimer(session);
|
||||
db.addMessage(session.sessionId, 'user', cleanText, 'voice_asr').catch((e) => console.warn('[NativeVoice][DB] add user failed:', e.message));
|
||||
sendJson(session.client, {
|
||||
type: 'subtitle',
|
||||
@@ -112,6 +131,7 @@ function persistAssistantSpeech(session, text, { source = 'voice_bot', toolName
|
||||
}
|
||||
session.lastPersistedAssistantText = cleanText;
|
||||
session.lastPersistedAssistantAt = now;
|
||||
resetIdleTimer(session);
|
||||
if (persistToDb) {
|
||||
db.addMessage(session.sessionId, 'assistant', cleanText, source, toolName, meta).catch((e) => console.warn('[NativeVoice][DB] add assistant failed:', e.message));
|
||||
}
|
||||
@@ -203,48 +223,47 @@ async function sendSpeechText(session, speechText) {
|
||||
}));
|
||||
}
|
||||
|
||||
function sendGreeting(session) {
|
||||
const greetingText = normalizeTextForSpeech(session.greetingText || '你好,我是你的智能语音助手,有什么可以帮你的吗?');
|
||||
if (!greetingText || session.hasSentGreeting) {
|
||||
if (!session.readySent) {
|
||||
session.readySent = true;
|
||||
sendJson(session.client, { type: 'ready' });
|
||||
}
|
||||
function sendReady(session) {
|
||||
if (session.readySent) {
|
||||
return;
|
||||
}
|
||||
session.readySent = true;
|
||||
sendJson(session.client, { type: 'ready' });
|
||||
}
|
||||
|
||||
function sendGreeting(session) {
|
||||
if (session.hasSentGreeting) {
|
||||
sendReady(session);
|
||||
return;
|
||||
}
|
||||
session.hasSentGreeting = true;
|
||||
persistAssistantSpeech(session, greetingText, { source: 'voice_bot', persistToDb: false });
|
||||
clearTimeout(session.readyTimer);
|
||||
session.readyTimer = setTimeout(() => {
|
||||
session.readyTimer = null;
|
||||
if (!session.readySent) {
|
||||
session.readySent = true;
|
||||
sendJson(session.client, { type: 'ready' });
|
||||
}
|
||||
}, estimateSpeechDurationMs(greetingText) + 300);
|
||||
const playGreeting = () => {
|
||||
session.pendingGreetingAck = true;
|
||||
clearTimeout(session.greetingAckTimer);
|
||||
session.greetingAckTimer = setTimeout(() => {
|
||||
session.greetingAckTimer = null;
|
||||
if (session.pendingGreetingAck && session.greetingRetryCount < 1) {
|
||||
session.greetingRetryCount += 1;
|
||||
console.warn(`[NativeVoice] greeting ack timeout, retry session=${session.sessionId}`);
|
||||
playGreeting();
|
||||
}
|
||||
}, 2000);
|
||||
sendSpeechText(session, greetingText).catch((error) => {
|
||||
session.pendingGreetingAck = false;
|
||||
clearTimeout(session.greetingAckTimer);
|
||||
session.greetingAckTimer = null;
|
||||
session.hasSentGreeting = false;
|
||||
console.warn('[NativeVoice] greeting failed:', error.message);
|
||||
});
|
||||
};
|
||||
const greetingText = session.greetingText || '嗨,你好呀!我是大沃,你的专属智能助手。关于德国PM产品、一成系统、招商合作,随时问我就好~';
|
||||
console.log(`[NativeVoice] sendGreeting session=${session.sessionId} text=${JSON.stringify(greetingText.slice(0, 80))}`);
|
||||
sendJson(session.client, {
|
||||
type: 'subtitle',
|
||||
role: 'assistant',
|
||||
text: greetingText,
|
||||
isFinal: true,
|
||||
source: 'voice_bot',
|
||||
sequence: `greeting_${Date.now()}`,
|
||||
});
|
||||
persistAssistantSpeech(session, greetingText, { source: 'voice_bot' });
|
||||
clearTimeout(session.greetingTimer);
|
||||
clearTimeout(session.readyTimer);
|
||||
session.greetingTimer = setTimeout(() => {
|
||||
session.greetingTimer = null;
|
||||
playGreeting();
|
||||
sendSpeechText(session, greetingText)
|
||||
.then(() => {
|
||||
session.readyTimer = setTimeout(() => {
|
||||
session.readyTimer = null;
|
||||
sendReady(session);
|
||||
}, Math.max(1200, Math.min(estimateSpeechDurationMs(greetingText) + 300, 8000)));
|
||||
})
|
||||
.catch((error) => {
|
||||
session.hasSentGreeting = false;
|
||||
sendReady(session);
|
||||
console.warn('[NativeVoice] greeting speech failed:', error.message);
|
||||
});
|
||||
}, 800);
|
||||
}
|
||||
|
||||
@@ -275,10 +294,20 @@ async function processReply(session, text) {
|
||||
}
|
||||
session.processingReply = true;
|
||||
sendJson(session.client, { type: 'assistant_pending', active: true });
|
||||
console.log(`[NativeVoice] processReply start session=${session.sessionId} text=${JSON.stringify(cleanText.slice(0, 120))}`);
|
||||
const isKnowledgeCandidate = shouldForceKnowledgeRoute(cleanText);
|
||||
if (isKnowledgeCandidate) {
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'processing' });
|
||||
}
|
||||
console.log(`[NativeVoice] processReply start session=${session.sessionId} text=${JSON.stringify(cleanText.slice(0, 120))} blocked=${session.blockUpstreamAudio} kbCandidate=${isKnowledgeCandidate}`);
|
||||
try {
|
||||
const { delivery, speechText, ragItems, source, toolName, routeDecision, responseMeta } = await resolveReply(session.sessionId, session, cleanText);
|
||||
if (delivery === 'upstream_chat') {
|
||||
if (isKnowledgeCandidate) {
|
||||
console.log(`[NativeVoice] processReply kb-nohit retrigger session=${session.sessionId}`);
|
||||
await sendExternalRag(session, [{ title: '用户问题', content: cleanText }]);
|
||||
} else {
|
||||
session.blockUpstreamAudio = false;
|
||||
}
|
||||
session.awaitingUpstreamReply = true;
|
||||
session.pendingAssistantSource = 'voice_bot';
|
||||
session.pendingAssistantToolName = null;
|
||||
@@ -287,6 +316,10 @@ async function processReply(session, text) {
|
||||
return;
|
||||
}
|
||||
if (delivery === 'external_rag') {
|
||||
if (!session.blockUpstreamAudio) {
|
||||
session.blockUpstreamAudio = true;
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'knowledge_hit' });
|
||||
}
|
||||
session.awaitingUpstreamReply = true;
|
||||
session.pendingAssistantSource = source;
|
||||
session.pendingAssistantToolName = toolName;
|
||||
@@ -301,26 +334,32 @@ async function processReply(session, text) {
|
||||
session.chatTTSUntil = 0;
|
||||
return;
|
||||
}
|
||||
session.isSendingChatTTSText = true;
|
||||
session.chatTTSUntil = Date.now() + 30000;
|
||||
console.log(`[NativeVoice] processReply resolved session=${session.sessionId} route=${routeDecision?.route || 'unknown'} delivery=local_tts source=${source} tool=${toolName || 'chat'} speechLen=${speechText.length}`);
|
||||
persistAssistantSpeech(session, speechText, { source, toolName, meta: responseMeta });
|
||||
session.directSpeakUntil = Date.now() + estimateSpeechDurationMs(speechText);
|
||||
await sendSpeechText(session, speechText);
|
||||
console.log(`[NativeVoice] processReply resolved session=${session.sessionId} route=${routeDecision?.route || 'unknown'} delivery=local_rag source=${source} tool=${toolName || 'chat'} speechLen=${speechText.length}`);
|
||||
session.awaitingUpstreamReply = true;
|
||||
session.pendingAssistantSource = source;
|
||||
session.pendingAssistantToolName = toolName;
|
||||
session.pendingAssistantMeta = responseMeta;
|
||||
await sendExternalRag(session, [{ title: '回复内容', content: speechText }]);
|
||||
} catch (error) {
|
||||
console.error('[NativeVoice] processReply failed:', error.message);
|
||||
sendJson(session.client, { type: 'error', error: error.message });
|
||||
} finally {
|
||||
session.processingReply = false;
|
||||
if (!session.awaitingUpstreamReply) {
|
||||
session.blockUpstreamAudio = false;
|
||||
}
|
||||
if (!session.awaitingUpstreamReply) {
|
||||
sendJson(session.client, { type: 'assistant_pending', active: false });
|
||||
}
|
||||
const pending = session.queuedUserText;
|
||||
session.queuedUserText = '';
|
||||
if (pending && pending !== cleanText && (!session.directSpeakUntil || Date.now() >= session.directSpeakUntil)) {
|
||||
setTimeout(() => processReply(session, pending).catch((err) => {
|
||||
console.error('[NativeVoice] queued processReply failed:', err.message);
|
||||
}), 200);
|
||||
setTimeout(() => {
|
||||
session.blockUpstreamAudio = true;
|
||||
processReply(session, pending).catch((err) => {
|
||||
console.error('[NativeVoice] queued processReply failed:', err.message);
|
||||
});
|
||||
}, 200);
|
||||
} else if (pending && pending !== cleanText) {
|
||||
const waitMs = Math.max(200, session.directSpeakUntil - Date.now() + 200);
|
||||
clearTimeout(session.queuedReplyTimer);
|
||||
@@ -328,6 +367,7 @@ async function processReply(session, text) {
|
||||
session.queuedReplyTimer = null;
|
||||
const queuedText = session.queuedUserText || pending;
|
||||
session.queuedUserText = '';
|
||||
session.blockUpstreamAudio = true;
|
||||
processReply(session, queuedText).catch((err) => {
|
||||
console.error('[NativeVoice] delayed queued processReply failed:', err.message);
|
||||
});
|
||||
@@ -346,9 +386,14 @@ function handleUpstreamMessage(session, data) {
|
||||
}
|
||||
|
||||
if (message.type === MsgType.AUDIO_ONLY_SERVER) {
|
||||
if (session.isSendingChatTTSText && session.currentTtsType === 'default') {
|
||||
if (session.blockUpstreamAudio) {
|
||||
if (!session._audioBlockLogOnce) {
|
||||
session._audioBlockLogOnce = true;
|
||||
console.log(`[NativeVoice] audio blocked (blockUpstream) session=${session.sessionId} ttsType=${session.currentTtsType}`);
|
||||
}
|
||||
return;
|
||||
}
|
||||
session._audioBlockLogOnce = false;
|
||||
if (session.client && session.client.readyState === WebSocket.OPEN) {
|
||||
session.client.send(message.payload, { binary: true });
|
||||
}
|
||||
@@ -369,10 +414,8 @@ function handleUpstreamMessage(session, data) {
|
||||
if (message.event === 150) {
|
||||
session.upstreamReady = true;
|
||||
console.log(`[NativeVoice] upstream ready session=${session.sessionId}`);
|
||||
if (!session.readySent) {
|
||||
session.readySent = true;
|
||||
sendJson(session.client, { type: 'ready' });
|
||||
}
|
||||
resetIdleTimer(session);
|
||||
sendGreeting(session);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -383,6 +426,10 @@ function handleUpstreamMessage(session, data) {
|
||||
clearTimeout(session.greetingAckTimer);
|
||||
session.greetingAckTimer = null;
|
||||
}
|
||||
if (session.blockUpstreamAudio && payload?.tts_type && payload.tts_type !== 'default') {
|
||||
session.blockUpstreamAudio = false;
|
||||
console.log(`[NativeVoice] unblock audio on ttsType=${payload.tts_type} session=${session.sessionId}`);
|
||||
}
|
||||
console.log(`[NativeVoice] upstream tts_event session=${session.sessionId} ttsType=${payload?.tts_type || ''}`);
|
||||
sendJson(session.client, { type: 'tts_event', payload });
|
||||
return;
|
||||
@@ -391,7 +438,7 @@ function handleUpstreamMessage(session, data) {
|
||||
const isLocalChatTTSTextActive = !!session.isSendingChatTTSText && (session.chatTTSUntil || 0) > Date.now();
|
||||
|
||||
if (message.event === 351) {
|
||||
if (isLocalChatTTSTextActive) {
|
||||
if (isLocalChatTTSTextActive || session.blockUpstreamAudio) {
|
||||
session.assistantStreamBuffer = '';
|
||||
session.assistantStreamReplyId = '';
|
||||
return;
|
||||
@@ -401,31 +448,31 @@ function handleUpstreamMessage(session, data) {
|
||||
const pendingAssistantMeta = session.pendingAssistantMeta || null;
|
||||
session.awaitingUpstreamReply = false;
|
||||
sendJson(session.client, { type: 'assistant_pending', active: false });
|
||||
flushAssistantStream(session, {
|
||||
source: pendingAssistantSource,
|
||||
toolName: pendingAssistantToolName,
|
||||
meta: pendingAssistantMeta,
|
||||
});
|
||||
session.pendingAssistantSource = null;
|
||||
session.pendingAssistantToolName = null;
|
||||
session.pendingAssistantMeta = null;
|
||||
const assistantText = extractUserText(payload);
|
||||
if (assistantText) {
|
||||
session.assistantStreamBuffer = '';
|
||||
session.assistantStreamReplyId = '';
|
||||
console.log(`[NativeVoice] upstream assistant session=${session.sessionId} text=${JSON.stringify(assistantText.slice(0, 120))}`);
|
||||
persistAssistantSpeech(session, assistantText, {
|
||||
source: pendingAssistantSource,
|
||||
toolName: pendingAssistantToolName,
|
||||
meta: pendingAssistantMeta,
|
||||
});
|
||||
session.pendingAssistantSource = null;
|
||||
session.pendingAssistantToolName = null;
|
||||
session.pendingAssistantMeta = null;
|
||||
} else {
|
||||
flushAssistantStream(session, {
|
||||
source: pendingAssistantSource,
|
||||
toolName: pendingAssistantToolName,
|
||||
meta: pendingAssistantMeta,
|
||||
});
|
||||
}
|
||||
session.pendingAssistantSource = null;
|
||||
session.pendingAssistantToolName = null;
|
||||
session.pendingAssistantMeta = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (message.event === 550) {
|
||||
if (isLocalChatTTSTextActive) {
|
||||
if (isLocalChatTTSTextActive || session.blockUpstreamAudio) {
|
||||
return;
|
||||
}
|
||||
if (session.awaitingUpstreamReply) {
|
||||
@@ -445,7 +492,14 @@ function handleUpstreamMessage(session, data) {
|
||||
session.assistantStreamReplyId = '';
|
||||
return;
|
||||
}
|
||||
if (session.blockUpstreamAudio) {
|
||||
session.assistantStreamBuffer = '';
|
||||
session.assistantStreamReplyId = '';
|
||||
console.log(`[NativeVoice] blocked response ended (559), keeping block session=${session.sessionId}`);
|
||||
return;
|
||||
}
|
||||
session.awaitingUpstreamReply = false;
|
||||
session.blockUpstreamAudio = false;
|
||||
sendJson(session.client, { type: 'assistant_pending', active: false });
|
||||
flushAssistantStream(session, {
|
||||
source: session.pendingAssistantSource || 'voice_bot',
|
||||
@@ -463,6 +517,21 @@ function handleUpstreamMessage(session, data) {
|
||||
if (text) {
|
||||
console.log(`[NativeVoice] upstream partial session=${session.sessionId} text=${JSON.stringify(text.slice(0, 120))}`);
|
||||
session.latestUserText = text;
|
||||
// 用户开口说话时立即打断 AI 播放
|
||||
if (session.directSpeakUntil && Date.now() < session.directSpeakUntil) {
|
||||
console.log(`[NativeVoice] user barge-in (partial) session=${session.sessionId}`);
|
||||
session.directSpeakUntil = 0;
|
||||
session.isSendingChatTTSText = false;
|
||||
session.chatTTSUntil = 0;
|
||||
clearTimeout(session.chatTTSTimer);
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'user_bargein' });
|
||||
} else if (session.isSendingChatTTSText && (session.chatTTSUntil || 0) > Date.now()) {
|
||||
console.log(`[NativeVoice] user barge-in chatTTS (partial) session=${session.sessionId}`);
|
||||
session.isSendingChatTTSText = false;
|
||||
session.chatTTSUntil = 0;
|
||||
clearTimeout(session.chatTTSTimer);
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'user_bargein' });
|
||||
}
|
||||
sendJson(session.client, {
|
||||
type: 'subtitle',
|
||||
role: 'user',
|
||||
@@ -483,8 +552,16 @@ function handleUpstreamMessage(session, data) {
|
||||
session.isSendingChatTTSText = false;
|
||||
session.chatTTSUntil = 0;
|
||||
clearTimeout(session.chatTTSTimer);
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'user_bargein' });
|
||||
} else if (session.isSendingChatTTSText && (session.chatTTSUntil || 0) > Date.now()) {
|
||||
console.log(`[NativeVoice] user interrupt chatTTS during speaking session=${session.sessionId}`);
|
||||
session.isSendingChatTTSText = false;
|
||||
session.chatTTSUntil = 0;
|
||||
clearTimeout(session.chatTTSTimer);
|
||||
sendJson(session.client, { type: 'tts_reset', reason: 'user_bargein' });
|
||||
}
|
||||
if (persistUserSpeech(session, finalText)) {
|
||||
session.blockUpstreamAudio = true;
|
||||
processReply(session, finalText).catch((error) => {
|
||||
console.error('[NativeVoice] processReply error:', error.message);
|
||||
});
|
||||
@@ -520,8 +597,9 @@ function attachClientHandlers(session) {
|
||||
session.botName = parsed.botName || '豆包';
|
||||
session.systemRole = parsed.systemRole || '你是一个企业知识库语音助手,请优先依据 external_rag 给出的内容回答。';
|
||||
session.speakingStyle = parsed.speakingStyle || '请使用清晰、自然、简洁的口吻。';
|
||||
session.speaker = parsed.speaker || 'zh_female_vv_jupiter_bigtts';
|
||||
session.greetingText = parsed.greetingText || session.greetingText || '你好,我是你的智能语音助手,有什么可以帮你的吗?';
|
||||
session.speaker = parsed.speaker || process.env.VOLC_S2S_SPEAKER_ID || 'zh_female_vv_jupiter_bigtts';
|
||||
session.modelVersion = parsed.modelVersion || 'O';
|
||||
session.greetingText = parsed.greetingText || session.greetingText || '嗨,你好呀!我是大沃,你的专属智能助手。关于德国PM产品、一成系统、招商合作,随时问我就好~';
|
||||
session.userId = parsed.userId || session.userId || null;
|
||||
session.upstream = createUpstreamConnection(session);
|
||||
loadHandoffSummaryForVoice(session).catch((error) => {
|
||||
@@ -548,6 +626,7 @@ function attachClientHandlers(session) {
|
||||
clearTimeout(session.greetingTimer);
|
||||
clearTimeout(session.greetingAckTimer);
|
||||
clearTimeout(session.readyTimer);
|
||||
clearTimeout(session.idleTimer);
|
||||
if (session.upstream && session.upstream.readyState === WebSocket.OPEN) {
|
||||
session.upstream.close();
|
||||
}
|
||||
@@ -580,12 +659,19 @@ function createUpstreamConnection(session) {
|
||||
});
|
||||
|
||||
upstream.on('error', (error) => {
|
||||
console.error('[NativeVoice] upstream error:', error.message);
|
||||
sendJson(session.client, { type: 'error', error: error.message });
|
||||
console.error('[NativeVoice] upstream ws error:', error.message);
|
||||
sendJson(session.client, { type: 'error', error: `语音服务连接异常: ${error.message}` });
|
||||
});
|
||||
|
||||
upstream.on('close', () => {
|
||||
sendJson(session.client, { type: 'closed' });
|
||||
upstream.on('close', (code) => {
|
||||
console.log(`[NativeVoice] upstream closed session=${session.sessionId} code=${code}`);
|
||||
session.upstreamReady = false;
|
||||
sendJson(session.client, { type: 'upstream_closed', code });
|
||||
setTimeout(() => {
|
||||
if (session.client && session.client.readyState === WebSocket.OPEN) {
|
||||
session.client.close();
|
||||
}
|
||||
}, 3000);
|
||||
});
|
||||
|
||||
return upstream;
|
||||
@@ -601,6 +687,7 @@ function createSession(client, sessionId) {
|
||||
latestUserText: '',
|
||||
queuedUserText: '',
|
||||
processingReply: false,
|
||||
blockUpstreamAudio: false,
|
||||
directSpeakUntil: 0,
|
||||
queuedReplyTimer: null,
|
||||
lastPersistedAssistantText: '',
|
||||
@@ -608,11 +695,12 @@ function createSession(client, sessionId) {
|
||||
assistantStreamBuffer: '',
|
||||
assistantStreamReplyId: '',
|
||||
currentTtsType: '',
|
||||
botName: '豆包',
|
||||
systemRole: '你是一个企业知识库语音助手,请优先依据 external_rag 给出的内容回答。',
|
||||
speakingStyle: '请使用清晰、自然、简洁的口吻。',
|
||||
speaker: 'zh_female_vv_jupiter_bigtts',
|
||||
greetingText: '你好,我是你的智能语音助手,有什么可以帮你的吗?',
|
||||
botName: '大沃',
|
||||
systemRole: '你是大沃,一个德国PM健康事业的智能语音助手。你对PM-FitLine细胞营养素产品、一成系统、招商合作非常熟悉。请优先依据 external_rag 给出的内容回答。用户进来时请自然地打个招呼,像朋友聊天一样,不要用客服话术。',
|
||||
speakingStyle: '说话像朋友聊天一样自然轻松,语气亲切活泼,不要像客服念稿。',
|
||||
speaker: process.env.VOLC_S2S_SPEAKER_ID || 'zh_female_vv_jupiter_bigtts',
|
||||
modelVersion: 'O',
|
||||
greetingText: '嗨,你好呀!我是大沃,你的专属智能助手。关于德国PM产品、一成系统、招商合作,随时问我就好~',
|
||||
hasSentGreeting: false,
|
||||
greetingTimer: null,
|
||||
greetingAckTimer: null,
|
||||
@@ -626,6 +714,8 @@ function createSession(client, sessionId) {
|
||||
pendingAssistantSource: null,
|
||||
pendingAssistantToolName: null,
|
||||
pendingAssistantMeta: null,
|
||||
idleTimer: null,
|
||||
lastActivityAt: Date.now(),
|
||||
};
|
||||
sessions.set(sessionId, session);
|
||||
attachClientHandlers(session);
|
||||
|
||||
Reference in New Issue
Block a user