168 lines
6.1 KiB
JavaScript
168 lines
6.1 KiB
JavaScript
const express = require('express');
|
||
const router = express.Router();
|
||
const { v4: uuidv4 } = require('uuid');
|
||
const ToolExecutor = require('../services/toolExecutor');
|
||
const DEFAULT_TOOLS = require('../config/tools');
|
||
const db = require('../db');
|
||
|
||
const directSessions = new Map();
|
||
|
||
router.get('/config', (req, res) => {
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
models: [
|
||
{ value: '1.2.1.0', label: 'O2.0(推荐,精品音质)' },
|
||
{ value: 'O', label: 'O(基础版)' },
|
||
{ value: '2.2.0.0', label: 'SC2.0(推荐,声音复刻)' },
|
||
{ value: 'SC', label: 'SC(基础版)' },
|
||
],
|
||
speakers: [
|
||
{ value: 'zh_female_vv_jupiter_bigtts', label: 'VV(活泼女声)', series: 'O' },
|
||
{ value: 'zh_female_xiaohe_jupiter_bigtts', label: '小禾(甜美女声·台湾口音)', series: 'O' },
|
||
{ value: 'zh_male_yunzhou_jupiter_bigtts', label: '云舟(沉稳男声)', series: 'O' },
|
||
{ value: 'zh_male_xiaotian_jupiter_bigtts', label: '小天(磁性男声)', series: 'O' },
|
||
{ value: 'saturn_common_female_1', label: 'Saturn 女声1', series: 'SC2.0' },
|
||
{ value: 'saturn_common_male_1', label: 'Saturn 男声1', series: 'SC2.0' },
|
||
{ value: 'ICL_common_female_1', label: 'ICL 女声1', series: 'SC' },
|
||
{ value: 'ICL_common_male_1', label: 'ICL 男声1', series: 'SC' },
|
||
],
|
||
tools: DEFAULT_TOOLS.map((t) => ({
|
||
name: t.function.name,
|
||
description: t.function.description,
|
||
})),
|
||
},
|
||
});
|
||
});
|
||
|
||
router.post('/direct/session', async (req, res) => {
|
||
try {
|
||
const { userId, sessionId } = req.body || {};
|
||
const sid = sessionId || uuidv4();
|
||
const directSession = {
|
||
sessionId: sid,
|
||
userId: userId || null,
|
||
startTime: Date.now(),
|
||
direct: true,
|
||
};
|
||
directSessions.set(sid, directSession);
|
||
await db.createSession(sid, userId || null, 'voice');
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
sessionId: sid,
|
||
userId: userId || null,
|
||
},
|
||
});
|
||
} catch (error) {
|
||
console.error('[DirectVoice] Create session failed:', error.message);
|
||
res.status(500).json({ success: false, error: error.message });
|
||
}
|
||
});
|
||
|
||
router.post('/direct/message', async (req, res) => {
|
||
try {
|
||
const { sessionId, role, text, source, toolName } = req.body || {};
|
||
if (!sessionId || !text || !source) {
|
||
return res.status(400).json({ success: false, error: 'sessionId, text and source are required' });
|
||
}
|
||
await db.addMessage(sessionId, role === 'user' ? 'user' : 'assistant', text, source, toolName || null);
|
||
res.json({ success: true });
|
||
} catch (error) {
|
||
console.error('[DirectVoice] Add message failed:', error.message);
|
||
res.status(500).json({ success: false, error: error.message });
|
||
}
|
||
});
|
||
|
||
router.post('/diag', (req, res) => {
|
||
try {
|
||
const { sessionId, roomId, type, payload } = req.body || {};
|
||
console.log(`[Diag] type=${type || 'unknown'} session=${sessionId || '-'} room=${roomId || '-'} payload=${JSON.stringify(payload || {})}`);
|
||
res.json({ success: true });
|
||
} catch (error) {
|
||
console.error('[Diag] Error:', error.message);
|
||
res.status(500).json({ success: false, error: error.message });
|
||
}
|
||
});
|
||
|
||
router.post('/direct/query', async (req, res) => {
|
||
try {
|
||
const { sessionId, query, appendUserMessage } = req.body || {};
|
||
if (!sessionId) {
|
||
return res.status(400).json({ success: false, error: 'sessionId is required' });
|
||
}
|
||
const context = await db.getHistoryForLLM(sessionId, 20).catch(() => []);
|
||
const cleanQuery = (query || '').trim();
|
||
if (appendUserMessage && cleanQuery) {
|
||
await db.addMessage(sessionId, 'user', cleanQuery, 'voice_asr').catch(() => null);
|
||
}
|
||
const result = await ToolExecutor.execute('search_knowledge', { query: cleanQuery }, context);
|
||
let contentText = JSON.stringify(result);
|
||
if (result && result.results && Array.isArray(result.results)) {
|
||
contentText = result.results.map((item) => item.content || JSON.stringify(item)).join('\n');
|
||
} else if (result && result.error) {
|
||
contentText = result.error;
|
||
} else if (typeof result === 'string') {
|
||
contentText = result;
|
||
}
|
||
const ragItems = result && result.results && Array.isArray(result.results) && result.results.length > 0
|
||
? result.results.map((item) => ({
|
||
title: item.title || '知识库结果',
|
||
content: item.content || JSON.stringify(item),
|
||
}))
|
||
: [{
|
||
title: '知识库结果',
|
||
content: contentText,
|
||
}];
|
||
await db.addMessage(sessionId, 'assistant', contentText, 'voice_tool', 'search_knowledge', {
|
||
route: 'search_knowledge',
|
||
original_text: cleanQuery,
|
||
tool_name: 'search_knowledge',
|
||
tool_args: { query: cleanQuery },
|
||
source: result?.source || null,
|
||
original_query: result?.original_query || cleanQuery,
|
||
rewritten_query: result?.rewritten_query || null,
|
||
hit: typeof result?.hit === 'boolean' ? result.hit : null,
|
||
reason: result?.reason || null,
|
||
error_type: result?.errorType || null,
|
||
latency_ms: result?.latency_ms || null,
|
||
}).catch(() => null);
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
sessionId,
|
||
query: cleanQuery,
|
||
contentText,
|
||
ragItems,
|
||
ragJson: JSON.stringify(ragItems),
|
||
},
|
||
});
|
||
} catch (error) {
|
||
console.error('[DirectVoice] Query failed:', error.message);
|
||
res.status(500).json({ success: false, error: error.message });
|
||
}
|
||
});
|
||
|
||
router.post('/direct/stop', async (req, res) => {
|
||
try {
|
||
const { sessionId } = req.body || {};
|
||
if (!sessionId) {
|
||
return res.status(400).json({ success: false, error: 'sessionId is required' });
|
||
}
|
||
directSessions.delete(sessionId);
|
||
const messages = await db.getMessages(sessionId).catch(() => []);
|
||
res.json({
|
||
success: true,
|
||
data: {
|
||
sessionId,
|
||
messageCount: messages.length,
|
||
},
|
||
});
|
||
} catch (error) {
|
||
console.error('[DirectVoice] Stop session failed:', error.message);
|
||
res.status(500).json({ success: false, error: error.message });
|
||
}
|
||
});
|
||
|
||
module.exports = router;
|