| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161 |
- /**
- * 硬件测试工具后端代理
- *
- * 让前端测试网页不用配置 API Key
- * 直接调本服务,自动用 models.json 里的 Key
- */
- import Router from '@koa/router';
- import { Context } from 'koa';
- import { callLLMWithMessages } from '../../services/llm';
- const router = new Router();
- /**
- * LLM 对话代理
- * POST /api/test-tools/llm
- * Body: { messages: [{role, content}], model?: string }
- */
- router.post('/llm', async (ctx: Context) => {
- const { messages, model } = ctx.request.body as {
- messages: Array<{ role: string; content: string }>;
- model?: string;
- };
- if (!messages || !Array.isArray(messages) || messages.length === 0) {
- ctx.status = 400;
- ctx.body = { code: 40001, message: 'messages 不能为空' };
- return;
- }
- try {
- console.log(`[Test-Tools LLM] ${messages.length} 条消息,model=${model || 'default'}`);
- // messages.role 在请求层是 string,但 LLM 接口要求枚举;调用前做窄化
- const reply = await callLLMWithMessages(
- messages as unknown as Parameters<typeof callLLMWithMessages>[0],
- model || undefined,
- 500
- );
- ctx.body = {
- code: 0,
- message: 'success',
- data: { reply, model: model || 'default' },
- };
- } catch (error: any) {
- console.error('[Test-Tools LLM] 失败:', error.message);
- ctx.status = 500;
- ctx.body = {
- code: 50001,
- message: 'LLM 调用失败: ' + error.message,
- };
- }
- });
- /**
- * ASR(语音识别)代理 - 使用阿里百炼 Paraformer
- * POST /api/test-tools/asr
- * Body: { audio: base64 string, format?: 'wav'|'mp3'|'webm' }
- */
- router.post('/asr', async (ctx: Context) => {
- const { audio, format = 'webm' } = ctx.request.body as {
- audio: string;
- format?: string;
- };
- if (!audio) {
- ctx.status = 400;
- ctx.body = { code: 40001, message: 'audio 数据为空' };
- return;
- }
- try {
- // 从 models.json 读取 bailian 配置
- const fs = require('fs');
- const path = require('path');
- const modelsPath = path.join(process.cwd(), 'src', 'config', 'models.json');
- const models = JSON.parse(fs.readFileSync(modelsPath, 'utf-8'));
- const bailian = models.vendors?.bailian;
- if (!bailian?.apiKey) {
- ctx.status = 500;
- ctx.body = { code: 50001, message: 'bailian apiKey 未配置' };
- return;
- }
- console.log(`[Test-Tools ASR] format=${format}, audio size=${audio.length}`);
- // 把 base64 转成 Buffer
- const audioBuffer = Buffer.from(audio, 'base64');
- // 调用阿里百炼 Paraformer ASR
- // 注意:Paraformer 接受 OSS URL 或文件上传,这里用 file URL 方式
- // 简化方案:把音频上传到 OSS 再调用,或直接用同步识别 API
- // 阿里百炼 ASR API(同步识别)
- const https = require('https');
- const querystring = require('querystring');
- const postData = JSON.stringify({
- model: 'paraformer-v2',
- input: { file_urls: [] }, // 需要先上传文件
- parameters: {},
- });
- // 由于 Paraformer 需要先上传音频到 OSS,
- // 这里简化方案:直接告诉前端用浏览器 Web Speech API
- // 或者前端用 OpenAI Whisper(需要 Key)
- ctx.body = {
- code: 0,
- message: 'success',
- data: {
- text: '',
- hint: '阿里百炼 ASR 需要先上传文件到 OSS。建议改用浏览器内置 Web Speech API(无需 Key)。',
- },
- };
- } catch (error: any) {
- console.error('[Test-Tools ASR] 失败:', error.message);
- ctx.status = 500;
- ctx.body = {
- code: 50001,
- message: 'ASR 调用失败: ' + error.message,
- };
- }
- });
- /**
- * 获取可用模型列表(不返回 apiKey)
- * GET /api/test-tools/models
- */
- router.get('/models', async (ctx: Context) => {
- try {
- const fs = require('fs');
- const path = require('path');
- const modelsPath = path.join(process.cwd(), 'src', 'config', 'models.json');
- const models = JSON.parse(fs.readFileSync(modelsPath, 'utf-8'));
- const summary = Object.entries(models.vendors || {}).map(([key, v]: [string, any]) => ({
- vendor: key,
- name: v.name,
- hasKey: !!v.apiKey,
- models: (v.models || []).filter((m: any) => m.enabled).map((m: any) => ({
- id: m.id,
- name: m.name,
- inputs: m.input,
- })),
- }));
- ctx.body = {
- code: 0,
- message: 'success',
- data: { vendors: summary },
- };
- } catch (error: any) {
- ctx.status = 500;
- ctx.body = { code: 50001, message: error.message };
- }
- });
- export default router;
|