tts.controller.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. import Router from '@koa/router';
  2. import { Context } from 'koa';
  3. import * as TtsService from './tts.service';
  4. import { BadRequestError } from '../../middleware/errorHandler';
  5. import { optionalAuth } from '../../middleware/auth';
  6. import { usageLimitMiddleware, checkWordLimit } from '../../middleware/usageLimit';
  7. import { User } from '../../models/User';
  8. import { Audio } from '../../models/Audio';
  9. const router = new Router();
  10. // 获取可用音色列表
  11. router.get('/voices', async (ctx: Context) => {
  12. const voices = TtsService.getVoices();
  13. ctx.body = {
  14. code: 0,
  15. message: 'success',
  16. data: { voices },
  17. };
  18. });
  19. // 测试 MongoDB 连接
  20. router.get('/test-db', async (ctx: Context) => {
  21. try {
  22. const count = await Audio.countDocuments();
  23. ctx.body = {
  24. code: 0,
  25. message: 'success',
  26. data: { count, connectionState: 'connected' },
  27. };
  28. } catch (error: any) {
  29. ctx.body = {
  30. code: 500,
  31. message: 'error',
  32. data: { error: error.message },
  33. };
  34. }
  35. });
  36. // 生成音频
  37. router.post(
  38. '/generate',
  39. optionalAuth,
  40. async (ctx: Context) => {
  41. const userId = ctx.state.user?.userId;
  42. const { text, voiceId, voiceParams } = ctx.request.body as {
  43. text: string;
  44. voiceId: string;
  45. voiceParams?: { speed?: number; pitch?: number; volume?: number };
  46. };
  47. // 参数验证
  48. if (!text || text.trim().length === 0) {
  49. throw new BadRequestError('请输入要转换的文本');
  50. }
  51. if (!voiceId) {
  52. throw new BadRequestError('请选择音色');
  53. }
  54. // 检查字数限制(测试模式:无限制)
  55. const wordCount = text.length;
  56. const quota = ctx.state.userQuota || { dailyLimit: -1, wordLimit: -1 };
  57. if (quota.wordLimit !== -1 && wordCount > quota.wordLimit) {
  58. throw new BadRequestError(`文本字数超出限制(${quota.wordLimit}字)`);
  59. }
  60. // 默认参数
  61. const params = {
  62. speed: voiceParams?.speed || 1.0,
  63. pitch: voiceParams?.pitch || 0,
  64. volume: voiceParams?.volume || 50,
  65. };
  66. // 生成音频
  67. const result = await TtsService.generateAudio(userId, text, voiceId, params);
  68. // 如果用户已登录,更新使用次数
  69. if (userId) {
  70. const user = await User.findById(userId);
  71. if (user) {
  72. user.dailyUsage += 1;
  73. await user.save();
  74. }
  75. }
  76. ctx.body = {
  77. code: 0,
  78. message: '音频生成成功',
  79. data: result,
  80. };
  81. }
  82. );
  83. // 预览音色
  84. router.post('/preview', async (ctx: Context) => {
  85. const { voiceId, voiceParams } = ctx.request.body as {
  86. voiceId: string;
  87. voiceParams?: { speed?: number; pitch?: number; volume?: number };
  88. };
  89. if (!voiceId) {
  90. throw new BadRequestError('请选择音色');
  91. }
  92. // 返回预览文本
  93. ctx.body = {
  94. code: 0,
  95. message: 'success',
  96. data: {
  97. previewText: '这是一段预览文本,用于试听音色效果。',
  98. voiceId,
  99. },
  100. };
  101. });
  102. export default router;