Files
bigwo/test2/server/services/volcengine.js
2026-03-12 12:47:56 +08:00

133 lines
4.9 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { Signer } = require('@volcengine/openapi');
const fetch = require('node-fetch');
const { AccessToken, privileges } = require('../lib/token');
class VolcengineService {
constructor() {
this.baseUrl = 'https://rtc.volcengineapi.com';
this.service = 'rtc';
this.region = 'cn-north-1';
this.version = '2024-12-01';
}
async startVoiceChat(config) {
console.log('[Volcengine] Starting voice chat (S2S端到端 + LLM混合, API v2024-12-01)');
console.log('[Volcengine] RoomId:', config.RoomId);
// ProviderParams 可能是 JSON 字符串或对象
let pp = config.Config.S2SConfig?.ProviderParams;
if (typeof pp === 'string') {
try { pp = JSON.parse(pp); } catch (e) { pp = {}; }
}
console.log('[Volcengine] S2S AppId:', pp?.app?.appid);
console.log('[Volcengine] S2S model:', pp?.dialog?.extra?.model);
console.log('[Volcengine] S2S speaker:', pp?.tts?.speaker);
console.log('[Volcengine] ProviderParams type:', typeof config.Config.S2SConfig?.ProviderParams);
console.log('[Volcengine] LLM EndPointId:', config.Config.LLMConfig?.EndPointId);
console.log('[Volcengine] Tools:', config.Config.LLMConfig?.Tools?.length || 0);
console.log('[Volcengine] Full request body:', JSON.stringify(config, null, 2));
const result = await this._callOpenAPI('StartVoiceChat', config);
console.log('[Volcengine] StartVoiceChat response:', JSON.stringify(result, null, 2));
return result;
}
async updateVoiceChat(params) {
console.log('[Volcengine] Updating voice chat (v2024-12-01)');
console.log('[Volcengine] UpdateVoiceChat params:', JSON.stringify(params, null, 2));
const result = await this._callOpenAPI('UpdateVoiceChat', params);
console.log('[Volcengine] UpdateVoiceChat response:', JSON.stringify(result, null, 2));
return result;
}
async stopVoiceChat(params) {
console.log('[Volcengine] Stopping voice chat, RoomId:', params.RoomId);
return this._callOpenAPI('StopVoiceChat', params);
}
/**
* 生成 RTC 入房 Token
* 使用官方 AccessToken 库https://github.com/volcengine/rtc-aigc-demo/blob/main/Server/token.js
*/
generateRTCToken(roomId, userId) {
const appId = process.env.VOLC_RTC_APP_ID;
const appKey = process.env.VOLC_RTC_APP_KEY;
if (!appId || !appKey || appKey === 'your_rtc_app_key') {
console.warn('[Volcengine] RTC AppKey not configured, returning placeholder token');
return `placeholder_token_${roomId}_${userId}_${Date.now()}`;
}
const token = new AccessToken(appId, appKey, roomId, userId);
const expireTime = Math.floor(Date.now() / 1000) + 24 * 3600; // 24 小时有效
token.expireTime(expireTime);
token.addPrivilege(privileges.PrivPublishStream, 0);
token.addPrivilege(privileges.PrivSubscribeStream, 0);
const serialized = token.serialize();
console.log(`[Volcengine] RTC Token generated for room=${roomId}, user=${userId}`);
return serialized;
}
async _callOpenAPI(action, body, versionOverride) {
const ak = process.env.VOLC_ACCESS_KEY_ID;
const sk = process.env.VOLC_SECRET_ACCESS_KEY;
const version = versionOverride || this.version;
if (!ak || !sk || ak === 'your_access_key_id') {
console.warn(`[Volcengine] Credentials not configured, returning mock response for ${action}`);
return this._mockResponse(action, body);
}
// 与官方 rtc-aigc-demo 完全一致的签名方式
const openApiRequestData = {
region: this.region,
method: 'POST',
params: {
Action: action,
Version: version,
},
headers: {
Host: 'rtc.volcengineapi.com',
'Content-type': 'application/json',
},
body,
};
const signer = new Signer(openApiRequestData, this.service);
signer.addAuthorization({ accessKeyId: ak, secretKey: sk });
const url = `${this.baseUrl}?Action=${action}&Version=${version}`;
console.log(`[Volcengine] ${action} calling:`, url);
try {
const response = await fetch(url, {
method: 'POST',
headers: openApiRequestData.headers,
body: JSON.stringify(body),
});
const data = await response.json();
if (data?.ResponseMetadata?.Error) {
const err = data.ResponseMetadata.Error;
throw new Error(`${action} failed: ${err.Code} - ${err.Message}`);
}
return data;
} catch (error) {
console.error(`[Volcengine] ${action} error:`, error.message);
throw error;
}
}
/**
* Mock 响应(开发阶段凭证未配置时使用)
*/
_mockResponse(action, params) {
console.log(`[Volcengine][MOCK] ${action} called with:`, JSON.stringify(params, null, 2).substring(0, 500));
return {
ResponseMetadata: { RequestId: `mock-${Date.now()}`, Action: action },
Result: { Message: 'Mock response - credentials not configured' },
};
}
}
module.exports = new VolcengineService();