服务端配置
2437字约8分钟
2024-11-7
基础配置
port
- 类型:
number
- 默认值:
8080
- 必填:否
- 说明: 服务端口号
使用案例
const serverConfig = {
port: 8080, // 设置服务端口号
};
devLog
- 类型:
number
- 默认值:
1
- 必填:否
- 说明: 日志输出模式
0
: 不输出(线上模式)1
: 普通输出2
: 详细输出
使用案例
const serverConfig = {
devLog: 1, // 设置日志输出模式为普通输出
};
iatDu
- 类型:
string
- 默认值:
-
- 必填:否
- 说明: 语音识别开始前"嘟"的提示音音频流地址,只支持本地 mp3 文件, 请使用 16k 或者 24k 音频,推荐 16k
使用案例
import path from 'path'
// 下面地址是在你的项目根目录放一个 ./du.mp3,你也可以根据情况自行修改地址
const serverConfig = {
iatDu: path.join(__dirname, './du.mp3'), // 设置语音识别开始前的音频流地址
};
llm_qa_number
- 类型:
number
- 默认值:
5
- 必填:否
- 说明: LLM 对话历史保留回合数,一问一答为一回合
使用案例
const serverConfig = {
llm_qa_number: 5, // 设置LLM对话历史保留回合数
};
客户端配置生成
gen_client_config
- 类型:
(params: Record<string, any>) => Promise<ConfigResponse>
- 必填:是
- 说明: 生成客户端配置,包括语音识别、TTS、LLM等服务配置
- 参数:
params.send_error_to_client
: 向客户端发送错误信息的函数params.ws
: WebSocket对象params.client_params
: 客户端配置参数
- 返回值:
- 成功时返回配置对象
- 失败时返回
{ success: false, message: string }
详细内置接入的平台见:内置的各平台使用教程
使用案例
const config = {
gen_client_config: async (params) => {
// 生成客户端配置
return {
iat_server: "xun_fei",
iat_config: {
appid: "xxx",
apiSecret: "xxx",
apiKey: "xxx",
vad_eos: 1500,
// iat_server 中可配置的其他配置项...
},
llm_server: "xun_fei",
llm_config: {
appid: "xxx",
apiSecret: "xxx",
apiKey: "xxx",
llm: "v4.0",
// llm_server 中可配置的其他配置项...
},
tts_server: "xun_fei",
tts_config: {
appid: "xxx",
apiSecret: "xxx",
apiKey: "xxx",
is_clone: false, // 是否为克隆的音色
// tts_server 中可配置的其他配置项...
},
connected_reply: "已成功连接服务器",
f_reply: "你好",
sleep_reply: "我先休息了哦,有需要再叫我",
llm_init_messages: [
{ role: 'system', content: '你是小明同学,是一个无所不能的智能助手。' },
],
// 指令配置
intention: [
{
// 关键词
key: ["帮我开灯", "开灯", "打开灯"],
// 向客户端发送的指令
instruct: "device_open_001",
message: "开啦!还有什么需要帮助的吗?"
},
{
// 关键词
key: ["帮我关灯", "关灯", "关闭灯"],
// 向客户端发送的指令
instruct: "device_close_001",
message: "关啦!还有什么需要帮助的吗?"
},
{
// 关键词
key: ["退下吧", "退下"],
// 内置的睡眠指令
instruct: "__sleep__",
message: "我先退下了,有需要再叫我。"
},
{
// 调到指定音量
key: async (text = "") => {
const pattern = /音量调到(\d+)\%/;
// 查找匹配项
const match = text.match(pattern);
if (match) {
return true;
}
},
instruct: ({ text }) => {
const pattern = /音量调到(\d+)\%/;
const match = text.match(pattern);
const volumeLevel = match[1];
console.log("音量设置为:", volumeLevel);
// 直接传给业务服务,业务服务可再传给硬件,这样硬件就可以进行调整音量了
// ...
},
message: "好的"
},
{
/**
* 正则匹配
* 如:播放音乐最后的倔强
* 返回匹配的字符串为匹配成功
*/
key: async (text = "", llm_historys) => {
const regex = /^(播放音乐)(.*)$/;
const match = text.match(regex);
if (match) {
const songName = match[2];
console.log("音乐名称:", songName);
return songName;
} else {
return false;
}
},
// 向客户端发送的指令
instruct: "__play_music__",
message: "好的!",
/**
* 用于返回音频地址和播放进度
* 目前只支持 mp3、wav 格式
* @param {String} name 是歌曲名称
* @return {number} seek 进度: (以秒为单位)
* @return {message} 找不到数据时的TTS
*/
music_server: async (name, { user_config }) => {
return {
url:"https://xiaomingio.top/music.mp3",
seek: 0,
message: message
};
},
/**
* 当音频结束后的回调
* @param {object} arg.break_second 停止时的进度,单位秒。也就是用户播放了到了多少秒(seek+play_time)
* @param {object} arg.play_time 实际播放音频的时间,单位秒。
* @param {object} arg.seek 音频开始播放时间,其实也就是 music_server 函数中返回的 seek 值
* @param {object} arg.start_time 开始播放音频的 Unix 毫秒数时间戳
* @param {object} arg.end_time 结束播放音频的 Unix 毫秒数时间戳
* @param {object} arg.event 结束原因: "user_break" 用户打断 | play_end 播放完毕 | foo 未知事件
*/
on_end: (arg) => {
// 请求业务服务器保存进度信息 ...
console.log(arg);
}
},
// 其他...
],
};
},
};
鉴权配置
auth
- 类型:
(params: AuthParams) => Promise<AuthResponse>
- 必填:否
- 说明: 客户端鉴权函数,
client_params
是客户端在服务配置中的params
。 每个对话都会走一次,所以一定要保证速度,建议使用缓存技术解决。 - 参数:
{ type: "connect" | "start_session"; // 鉴权场景 send_error_to_client: (code: number, message: string) => void; ws: WebSocket; client_params: { api_key: string; ext1: string; ext2: string; } }
- 返回值:
- 成功:
{ success: true }
- 失败:
{ success: false, message: string }
- 成功:
使用案例
const config = {
auth: async (params) => {
if (params.client_params.api_key === "valid_api_key") {
return { success: true }; // 鉴权成功
} else {
params.send_error_to_client(401, "无效的API密钥");
return { success: false, message: "无效的API密钥" }; // 鉴权失败
}
},
};
参数控制
llm_params_set
- 类型:
(params: Record<string, any>) => Record<string, any>
- 必填:否
- 说明: 控制 LLM 参数,如温度等
使用案例
const config = {
llm_params_set: (params) => {
// 修改默认的 LLM 参数, 必须返回 params 数据
return { ...params, temperature: 0.8 };
},
};
tts_params_set
- 类型:
(params: Record<string, any>) => Record<string, any>
- 必填:否
- 说明: 控制 TTS 参数,如说话人、音量、语速等
使用案例
const config = {
tts_params_set: (params) => {
// 修改默认的 TTS 参数, 必须返回 params 数据
return { ...params, volume: 5, speed: 1.0 };
},
};
事件回调
onDeviceConnect
- 类型:
(arg: DeviceConnectArg) => void
- 必填:否
- 说明: 新设备连接时的回调
- 参数:
{ device_id: string; // 设备ID client_version: string; // 客户端版本 instance: Instance // ESP-AI 实例 }
使用案例
const config = {
onDeviceConnect: (arg) => {
console.log(`设备 ${arg.device_id} 已连接,客户端版本:${arg.client_version}`);
},
};
onIAT
- 类型:
(arg: IATArg) => void
- 必填:否
- 说明: 语音识别请求前的回调(注意,这是转换前,所以什么都拿不到,只能获取到麦克风pcm)
使用案例
const config = {
onIAT: (arg) => {
console.log(`设备 ${arg.device_id} 发起语音识别请求`);
},
};
onIATcb
- 类型:
(arg: IATCallbackArg) => void
- 必填:否
- 说明: 语音识别过程中的回调
- 参数:
{ device_id: string; // 设备ID text: string; // 识别文本 instance: Instance // ESP-AI 实例 sendToClient: () => void; // 发送到客户端的函数 } /** * iat 回调: 语音识别过程中的回调 * @param {string} device_id 设备id * @param {string} text 语音转的文字 * @param {()=>void} sendToClient 调用这个方法后可以直接将文字发送到客户端,客户端使用 onEvent 接收、 * * ***** 调用 sendToClient() 后,客户端代码向下面这样写即可接收到音频流 **** * void on_command(String command_id, String data) { * if (command_id == "on_iat_cb") { * // some code... * } * } * void setup() { * ... * esp_ai.onEvent(on_command); * } */
使用案例
const config = {
onIATcb: (arg) => {
console.log(`设备 ${arg.device_id} 识别到文本:${arg.text}`);
arg.sendToClient();
},
};
onTTS
- 类型:
(arg: TTSArg) => void
- 必填:否
- 说明: TTS 转换前的回调
- 参数:
{ device_id: string; // 设备ID tts_task_id: string; // TTS任务ID text: string; // 待转换文本 instance: Instance // ESP-AI 实例 sendToClient: () => void; // 发送到客户端的函数 }
onTTScb
- 类型:
(arg: TTSCallbackArg) => void
- 必填:否
- 说明: TTS 转换完成的回调
- 参数:
{ device_id: string; // 设备ID is_over: boolean; // 是否完成 audio: Buffer; // 音频流, mp3 格式, 使用 base64 格式进行封装。自行解码为二进制即可。 instance: Instance // ESP-AI 实例 sendToClient: () => void; // 发送到客户端的函数 }
使用案例
const config = {
onTTScb: (arg) => {
console.log(arg.audio)
// 调用这个方法后可以直接将文字发送到客户端,客户端使用 onEvent 接收、
// arg.sendToClient();
//
// 客户端接收代码如下:
// void on_command(String command_id, String data) {
// if (command_id == "on_tts_cb") {
// // some code...
// }
// }
// void setup() {
// ...
// esp_ai.onEvent(on_command);
// }
},
};
onLLM
- 类型:
(arg: LLMArg) => void
- 必填:否
- 说明: LLM 服务调用前的回调
onLLMcb
- 类型:
(arg: LLMCallbackArg) => void
- 必填:否
- 说明: LLM 推理完成的回调
- 参数:
{ device_id: string; // 设备ID text: string; // 大语言模型推理出来的文本片段 is_over: boolean; // 是否推理完毕 llm_historys: Record<string, any>[]; // 对话历史 instance: Instance // ESP-AI 实例 sendToClient: () => void; // 发送到客户端的函数 }
使用案例
const config = {
onLLMcb: (arg) => {
console.log(arg.text)
// 调用这个方法后可以直接将文字发送到客户端,客户端使用 onEvent 接收、
// arg.sendToClient();
//
// 客户端接收代码如下:
// void on_command(String command_id, String data) {
// if (command_id == "on_llm_cb") {
// // some code...
// }
// }
// void setup() {
// ...
// esp_ai.onEvent(on_command);
// }
},
};
插件系统
plugins
- 类型:
Plugin[]
- 必填:否
- 说明: 插件配置
使用案例
const config = {
plugins: [
// 引入插件,注意:使用插件时必须按插件文档中要求的配置项来配置插件
// 如这个插件:https://github.com/wangzongming/esp-ai-plugin-tts-aliyun
require("esp-ai-plugin-tts-aliyun")
],
};
日志配置
logs
- 类型:
LogConfig
- 必填:否
- 说明: 自定义日志输出配置
- 配置结构:
{ info?: () => void; // 普通消息 error?: () => void; // 错误消息 }
使用案例
const config = {
logs: {
info: () => {
console.log("普通日志信息");
},
error: () => {
console.error("错误日志信息");
},
},
};
服务压力测试数据
测试环境:
- 服务商: 腾讯云
- CPU: 2核
- 内存: 2G
- 带宽: 4MB
- 硬盘: SSD 50GB
连接测试结果
连接数量 | 成功量 | 失败量 | 并发瞬间服务情况 | 连接后服务情况 |
---|---|---|---|---|
1000 | 1000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
2000 | 2000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
3000 | 3000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
4000 | 3806 | 194(5%) | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
5000 | 4685 | 315(6.7%) | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
6000 | 4030 | 1970(32%) | CPU:100%, MEM:1.6GB | CPU:4%, MEM:1.5GB |
10000 | 52 | 服务崩溃 | - | - |
音频流测试结果
测试条件:
- 音频大小: 10KB
- 分片大小: 2048字节
- 每连接消息数: 6次
连接数量 | 连接成功量 | 应发消息 | 实发消息 | 失败量 | 并发瞬间服务情况 | 连接后服务情况 |
---|---|---|---|---|---|---|
100 | 922 | 600 | 600 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
500 | 500 | 3000 | 3000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
1000 | 1000 | 6000 | 6000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
2000 | 2000 | 12000 | 12000 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |
3000 | 2982 | 18000 | 2982 | 0 | CPU:100%, MEM:1.5GB | CPU:4%, MEM:1.5GB |