Просмотр исходного кода

fix: 移除未使用的 MINIMAX_API_KEY 引用

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MyFramework User 3 месяцев назад
Родитель
Сommit
3c4243b979
2 измененных файлов с 39 добавлено и 11 удалено
  1. 3 0
      server/src/app.ts
  2. 36 11
      server/src/modules/tts/tts.controller.ts

+ 3 - 0
server/src/app.ts

@@ -90,6 +90,9 @@ app.use(mount('/uploads', serve(config.upload.dir)));
 // 静态文件服务 - 视频文件
 app.use(mount('/videos', serve(path.join(process.cwd(), 'public', 'videos'))));
 
+// 静态文件服务 - 音色试听样本
+app.use(mount('/tts/voices', serve(path.join(process.cwd(), '..', 'voices'))));
+
 // 健康检查
 router.get('/health', (ctx) => {
   ctx.body = { code: 0, message: 'ok', data: { status: 'healthy' } };

+ 36 - 11
server/src/modules/tts/tts.controller.ts

@@ -1,5 +1,7 @@
 import Router from '@koa/router';
 import { Context } from 'koa';
+import path from 'path';
+import fs from 'fs';
 import * as TtsService from './tts.service';
 import { BadRequestError, NotFoundError } from '../../middleware/errorHandler';
 import { optionalAuth } from '../../middleware/auth';
@@ -12,11 +14,20 @@ const router = new Router();
 // 获取可用音色列表
 router.get('/voices', async (ctx: Context) => {
   const voices = TtsService.getVoices();
+  const baseUrl = `${ctx.protocol}://${ctx.host}`;
+
+  // 为每个音色注入本地预览URL
+  const result = voices.map(v => ({
+    ...v,
+    preview: fs.existsSync(path.join(process.cwd(), '..', 'voices', `${v.id}.mp3`))
+      ? `${baseUrl}/tts/voices/${v.id}.mp3`
+      : undefined,
+  }));
 
   ctx.body = {
     code: 0,
     message: 'success',
-    data: { voices },
+    data: { voices: result },
   };
 });
 
@@ -142,9 +153,9 @@ router.get('/status/:audioId', async (ctx: Context) => {
   };
 });
 
-// 预览音色 - 生成短音频
+// 预览音色 - 优先使用本地样本文件,不存在时才调用API生成
 router.post('/preview', async (ctx: Context) => {
-  const { voiceId, voiceParams, ttsProvider } = ctx.request.body as {
+  const { voiceId } = ctx.request.body as {
     voiceId: string;
     voiceParams?: { speed?: number; pitch?: number; volume?: number };
     ttsProvider?: 'aliyun' | 'minimax';
@@ -154,22 +165,36 @@ router.post('/preview', async (ctx: Context) => {
     throw new BadRequestError('请选择音色');
   }
 
-  // 预览文本(固定短文本)
-  const previewText = '你好,欢迎使用AI有声书';
-
-  try {
-    // 生成预览音频
-    const result = await TtsService.generatePreview(voiceId, voiceParams, ttsProvider);
+  const baseUrl = `${ctx.protocol}://${ctx.host}`;
+  const localFile = `/tts/voices/${voiceId}.mp3`;
+  const filePath = path.join(process.cwd(), '..', 'voices', `${voiceId}.mp3`);
 
+  // 检查本地样本文件是否存在
+  if (fs.existsSync(filePath)) {
+    console.log(`🎵 [Preview] 使用本地样本: ${voiceId}`);
     ctx.body = {
       code: 0,
       message: 'success',
       data: {
-        previewText,
+        previewText: `${voiceId} 音色试听`,
         voiceId,
-        audioUrl: result.audioUrl,
+        audioUrl: `${baseUrl}${localFile}`,
       },
     };
+    return;
+  }
+
+  // 本地不存在,降级到 API 生成
+  console.log(`🔊 [Preview] 本地无样本,API生成: ${voiceId}`);
+  const previewText = '你好,欢迎使用AI有声书';
+
+  try {
+    const result = await TtsService.generatePreview(voiceId, undefined, undefined);
+    ctx.body = {
+      code: 0,
+      message: 'success',
+      data: { previewText, voiceId, audioUrl: result.audioUrl },
+    };
   } catch (error: any) {
     ctx.body = {
       code: 500,