index.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.config = void 0;
  7. const dotenv_1 = __importDefault(require("dotenv"));
  8. const path_1 = __importDefault(require("path"));
  9. const fs_1 = __importDefault(require("fs"));
  10. // 使用 process.cwd() 获取项目根目录(server目录)
  11. const projectRoot = process.cwd();
  12. dotenv_1.default.config({ path: path_1.default.resolve(projectRoot, '.env') });
  13. // 加载模型配置
  14. const modelsConfig = JSON.parse(fs_1.default.readFileSync(path_1.default.join(__dirname, 'models.json'), 'utf-8'));
  15. // 获取所有模型(扁平化)
  16. function getAllModels() {
  17. const models = [];
  18. for (const [vendorKey, vendor] of Object.entries(modelsConfig.vendors)) {
  19. for (const model of vendor.models) {
  20. models.push({
  21. ...model,
  22. vendor: vendorKey,
  23. vendorName: vendor.name,
  24. baseUrl: vendor.baseUrl,
  25. apiKey: vendor.apiKey,
  26. apiType: vendor.apiType,
  27. });
  28. }
  29. }
  30. return models;
  31. }
  32. // 获取启用的模型
  33. function getEnabledModels() {
  34. return getAllModels().filter((m) => m.enabled);
  35. }
  36. // 根据 ID 获取模型配置
  37. function getModel(id) {
  38. return getAllModels().find((m) => m.id === id);
  39. }
  40. // 根据类型获取模型列表 (text, tts, image, video)
  41. function getModelsByType(type) {
  42. return getAllModels().filter((m) => m.input?.includes(type) && m.enabled);
  43. }
  44. // 检查模型是否可切换(根据错误类型判断是否需要切换)
  45. function shouldSwitchModel(error) {
  46. if (!error)
  47. return false;
  48. const message = error?.message || error?.error?.message || '';
  49. // 限流、余额不足、服务不可用、模型不支持等错误需要切换
  50. const switchableErrors = [
  51. 'rate limit', 'quota', 'token', 'balance', 'insufficient',
  52. 'invalid model', 'model not found', 'model not support',
  53. '429', '403', '502', '503', '504',
  54. 'too many requests', '请求过于频繁'
  55. ];
  56. return switchableErrors.some(e => message.toLowerCase().includes(e));
  57. }
  58. // 获取下一个可用模型(用于自动切换)
  59. function getNextModel(currentModelId, type) {
  60. const models = getModelsByType(type);
  61. const currentIndex = models.findIndex((m) => m.id === currentModelId);
  62. if (currentIndex === -1 || currentIndex >= models.length - 1) {
  63. return null; // 没有下一个模型
  64. }
  65. return models[currentIndex + 1].id;
  66. }
  67. exports.config = {
  68. port: parseInt(process.env.PORT || '3000', 10),
  69. nodeEnv: process.env.NODE_ENV || 'development',
  70. mongodb: {
  71. uri: process.env.MONGODB_URI || 'mongodb://localhost:27017/audio-book',
  72. },
  73. jwt: {
  74. // 临时硬编码,确保登录和验证一致
  75. secret: 'my-jwt-secret-key-2024',
  76. expiresIn: process.env.JWT_EXPIRES_IN || '7d',
  77. },
  78. // 阿里云百炼 DashScope TTS
  79. dashscope: {
  80. apiKey: process.env.DASHSCOPE_API_KEY || '',
  81. model: process.env.DASHSCOPE_MODEL || 'qwen3-tts-instruct-flash',
  82. voice: process.env.DASHSCOPE_VOICE || 'Cherry',
  83. // 可用 TTS 模型列表(随机选用)
  84. ttsModels: (process.env.DASHSCOPE_TTS_MODELS || 'qwen3-tts-instruct-flash').split(',').filter(Boolean),
  85. // 长文本模式使用 WebSocket 实时合成
  86. useRealtime: process.env.DASHSCOPE_USE_REALTIME === 'true',
  87. realtimeModel: process.env.DASHSCOPE_REALTIME_MODEL || 'qwen3-tts-instruct-flash-realtime',
  88. },
  89. // 模型配置(统一管理)
  90. models: {
  91. vendors: modelsConfig.vendors,
  92. list: getAllModels(),
  93. enabled: getEnabledModels(),
  94. getModel,
  95. getModelsByType,
  96. shouldSwitchModel,
  97. getNextModel,
  98. textGeneration: {
  99. defaultModel: modelsConfig.textGeneration.defaultModel,
  100. },
  101. tts: {
  102. defaultModel: modelsConfig.tts.defaultModel,
  103. defaultVoice: modelsConfig.tts.defaultVoice,
  104. },
  105. },
  106. upload: {
  107. dir: path_1.default.join(process.cwd(), 'uploads'),
  108. maxSize: 50 * 1024 * 1024, // 50MB
  109. },
  110. };