feat: 添加realtime_dialog和realtime_dialog_external_rag_test项目,更新test2项目
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
require('dotenv').config();
|
||||
const http = require('http');
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const path = require('path');
|
||||
@@ -6,14 +7,11 @@ const db = require('./db');
|
||||
const voiceRoutes = require('./routes/voice');
|
||||
const chatRoutes = require('./routes/chat');
|
||||
const sessionRoutes = require('./routes/session');
|
||||
const { setupNativeVoiceGateway } = require('./services/nativeVoiceGateway');
|
||||
|
||||
// ========== 环境变量校验 ==========
|
||||
function validateEnv() {
|
||||
const required = [
|
||||
{ key: 'VOLC_RTC_APP_ID', desc: 'RTC 应用 ID' },
|
||||
{ key: 'VOLC_RTC_APP_KEY', desc: 'RTC 应用密钥' },
|
||||
{ key: 'VOLC_ACCESS_KEY_ID', desc: '火山引擎 AccessKey ID' },
|
||||
{ key: 'VOLC_SECRET_ACCESS_KEY', desc: '火山引擎 Secret Access Key' },
|
||||
{ key: 'VOLC_S2S_APP_ID', desc: 'S2S 端到端语音 AppID' },
|
||||
{ key: 'VOLC_S2S_TOKEN', desc: 'S2S 端到端语音 Token' },
|
||||
{ key: 'VOLC_ARK_ENDPOINT_ID', desc: '方舟 LLM 推理接入点 ID' },
|
||||
@@ -68,42 +66,11 @@ function validateEnv() {
|
||||
|
||||
// ========== Express 应用 ==========
|
||||
const app = express();
|
||||
const server = http.createServer(app);
|
||||
const PORT = process.env.PORT || 3001;
|
||||
|
||||
app.use(cors());
|
||||
|
||||
// RTC Function Calling 回调不带 Content-Type,必须在标准 body parser 之前手动读取
|
||||
// 全局序列号:在 body 读取前同步分配,确保反映真实请求到达顺序
|
||||
let fcCallbackSeq = 0;
|
||||
app.post('/api/voice/fc_callback', (req, res, next) => {
|
||||
const seq = ++fcCallbackSeq; // 同步分配,在任何异步操作之前
|
||||
if (!req.headers['content-type']) {
|
||||
const chunks = [];
|
||||
req.on('data', (chunk) => chunks.push(chunk));
|
||||
req.on('end', () => {
|
||||
const rawBuf = Buffer.concat(chunks);
|
||||
const raw = rawBuf.toString('utf-8');
|
||||
console.log(`[RawBody] seq=${seq} Read ${rawBuf.length} bytes`);
|
||||
// 将所有回调原始内容追加到日志文件
|
||||
try {
|
||||
const fs = require('fs');
|
||||
fs.appendFileSync('fc_all_callbacks.log', `\n=== SEQ=${seq} TIME=${new Date().toISOString()} BYTES=${rawBuf.length} ===\n${raw}\n`);
|
||||
} catch(e) {}
|
||||
try { req.body = JSON.parse(raw); } catch (e) { console.error('[RawBody] JSON parse failed:', e.message); req.body = { _raw: raw }; }
|
||||
req.body._seq = seq;
|
||||
next();
|
||||
});
|
||||
req.on('error', (err) => {
|
||||
console.error('[RawBody] Error:', err.message);
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
req.body = req.body || {};
|
||||
req.body._seq = seq;
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
app.use(express.json({ limit: '1mb' }));
|
||||
app.use(express.urlencoded({ extended: true, limit: '1mb' }));
|
||||
|
||||
@@ -123,16 +90,8 @@ app.use('/api/voice', voiceRoutes);
|
||||
app.use('/api/chat', chatRoutes);
|
||||
app.use('/api/session', sessionRoutes);
|
||||
|
||||
// 静态文件服务
|
||||
app.use(express.static('../client/dist'));
|
||||
|
||||
// 处理单页应用路由
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../client/dist/index.html'));
|
||||
});
|
||||
|
||||
app.get('/api/health', (req, res) => {
|
||||
const envReady = !process.env.VOLC_RTC_APP_ID?.startsWith('your_');
|
||||
const envReady = !process.env.VOLC_S2S_APP_ID?.startsWith('your_');
|
||||
res.json({
|
||||
status: 'ok',
|
||||
mode: 's2s-hybrid',
|
||||
@@ -149,6 +108,14 @@ app.get('/api/health', (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// 静态文件服务
|
||||
app.use(express.static('../client/dist'));
|
||||
|
||||
// 处理单页应用路由
|
||||
app.get('*', (req, res) => {
|
||||
res.sendFile(path.join(__dirname, '../client/dist/index.html'));
|
||||
});
|
||||
|
||||
// 统一错误处理中间件
|
||||
app.use((err, req, res, _next) => {
|
||||
console.error(`[Error] ${req.method} ${req.path}:`, err.message);
|
||||
@@ -174,7 +141,14 @@ async function start() {
|
||||
console.warn('[DB] Continuing without database — context switching will use in-memory fallback');
|
||||
}
|
||||
|
||||
app.listen(PORT, () => {
|
||||
if (process.env.ENABLE_NATIVE_VOICE_GATEWAY !== 'false') {
|
||||
setupNativeVoiceGateway(server);
|
||||
console.log('[NativeVoice] Gateway enabled at /ws/realtime-dialog');
|
||||
} else {
|
||||
console.log('[NativeVoice] Gateway disabled (ENABLE_NATIVE_VOICE_GATEWAY=false)');
|
||||
}
|
||||
|
||||
server.listen(PORT, () => {
|
||||
console.log('\n========================================');
|
||||
console.log(` 🚀 Voice Chat Backend`);
|
||||
console.log(` 📡 http://localhost:${PORT}`);
|
||||
|
||||
Reference in New Issue
Block a user