runtime-config.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. const DEFAULTS = {
  2. parseApiHost: 'https://server.fmode.cn',
  3. parseAppId: 'ncloudmaster',
  4. parseBaseUrl: 'https://server.fmode.cn/api/functions',
  5. douyinApiBaseUrl: 'https://server.fmode.cn/api/voc-social',
  6. transcriptionGatewayBaseUrl: 'https://server.fmode.cn/api/apig/transcription',
  7. qiniuUploadUrl: 'https://up-z2.qiniup.com',
  8. volcSpeechBaseUrl: 'https://openspeech.bytedance.com',
  9. volcTtsProxyBaseUrl: 'https://server.fmode.cn/api/volcengine/tts',
  10. llmBaseUrl: 'http://server.fmode.cn:9999',
  11. quicklyCallbackUrl: 'https://server.fmode.cn/api/functions/cut/onemerge',
  12. quicklyRelayUrl: 'https://server.fmode.cn/api/functions',
  13. };
  14. function env(name, fallback = '') {
  15. const value = process.env[name];
  16. return value === undefined || value === null || value === '' ? fallback : String(value).trim();
  17. }
  18. function firstEnv(names, fallback = '') {
  19. for (const name of names) {
  20. const value = env(name);
  21. if (value) return value;
  22. }
  23. return fallback;
  24. }
  25. function stripTrailingSlash(value) {
  26. return String(value || '').replace(/\/+$/, '');
  27. }
  28. function normalizeBearerToken(token) {
  29. const value = String(token || '').trim();
  30. if (!value) return '';
  31. return /^Bearer\s+/i.test(value) ? value : `Bearer ${value}`;
  32. }
  33. function requireSecret(value, label, names) {
  34. if (String(value || '').trim()) return String(value).trim();
  35. const list = Array.isArray(names) ? names.join('、') : names;
  36. const err = new Error(`未配置 ${label},请设置 ${list}`);
  37. err.statusCode = 400;
  38. throw err;
  39. }
  40. function redact(value) {
  41. const raw = String(value || '').trim();
  42. if (!raw) return '';
  43. if (raw.length <= 10) return `${raw.slice(0, 2)}***`;
  44. return `${raw.slice(0, 6)}***${raw.slice(-4)}`;
  45. }
  46. const config = {
  47. port: Number(env('PORT', '3000')) || 3000,
  48. parseApiHost: stripTrailingSlash(env('PARSE_API_HOST', DEFAULTS.parseApiHost)),
  49. parseAppId: env('PARSE_APP_ID', DEFAULTS.parseAppId),
  50. parseBaseUrl: stripTrailingSlash(env('PARSE_BASE_URL', DEFAULTS.parseBaseUrl)),
  51. douyinApiBaseUrl: stripTrailingSlash(env('DOUYIN_API_BASE_URL', DEFAULTS.douyinApiBaseUrl)),
  52. douyinGatewayMaxAttempts: Math.max(1, Number(env('DOUYIN_GATEWAY_MAX_ATTEMPTS', '4')) || 4),
  53. transcriptionGatewayBaseUrl: stripTrailingSlash(env('IFLYTEK_GATEWAY_BASE_URL', DEFAULTS.transcriptionGatewayBaseUrl)),
  54. qiniu: {
  55. accessKey: firstEnv(['QINIU_AK', 'QINIU_ACCESS_KEY']),
  56. secretKey: firstEnv(['QINIU_SK', 'QINIU_SECRET_KEY']),
  57. bucket: env('QINIU_BUCKET', 'nova-repos'),
  58. cdnDomain: env('QINIU_CDN_DOMAIN', env('QINIU_DOMAIN', 'https://repos.fmode.cn')),
  59. cdnPrefix: env('QINIU_CDN_PREFIX', 'x/openclaw-skills'),
  60. uploadUrl: env('QINIU_UPLOAD_URL', DEFAULTS.qiniuUploadUrl),
  61. },
  62. volc: {
  63. speechBaseUrl: stripTrailingSlash(env('VOLC_SPEECH_BASE_URL', DEFAULTS.volcSpeechBaseUrl)),
  64. ttsProxyBaseUrl: stripTrailingSlash(env('VOLC_TTS_PROXY_BASE_URL', DEFAULTS.volcTtsProxyBaseUrl)),
  65. speechApiKey: firstEnv(['VOLC_SPEECH_API_KEY', 'BYTEDANCE_SPEECH_API_KEY', 'VOICE_CREATION_API_KEY']),
  66. ttsResourceId: env('VOLC_TTS_RESOURCE_ID'),
  67. speechAppKey: firstEnv(['VOLC_SPEECH_APP_KEY', 'VOLC_SPEECH_APP_ID']),
  68. speechAccessKey: env('VOLC_SPEECH_ACCESS_KEY'),
  69. },
  70. quickly: {
  71. appKey: env('QUICKLY_APP_KEY'),
  72. appSecret: env('QUICKLY_APP_SECRET'),
  73. accountId: env('QUICKLY_ACCOUNT_ID'),
  74. callbackUrl: env('QUICKLY_CALLBACK_URL', DEFAULTS.quicklyCallbackUrl),
  75. relayUrl: env('QUICKLY_RELAY_URL', DEFAULTS.quicklyRelayUrl),
  76. },
  77. llm: {
  78. baseUrl: stripTrailingSlash(env('LLM_BASE_URL', DEFAULTS.llmBaseUrl)),
  79. apiKey: env('LLM_API_KEY'),
  80. },
  81. voice: {
  82. defaultToken: normalizeBearerToken(firstEnv(['VOLC_TTS_TOKEN', 'VOICE_TOKEN'])),
  83. },
  84. };
  85. function getVocToken() {
  86. return firstEnv([
  87. 'DOUYIN_API_TOKEN',
  88. 'VOC_TOKEN',
  89. 'TRANSCRIPTION_VOC_TOKEN',
  90. 'VOICE_TOKEN',
  91. 'OPENCLAW_VOC_TOKEN',
  92. 'VOC_SOCIAL_TOKEN',
  93. ]);
  94. }
  95. module.exports = {
  96. ...config,
  97. getVocToken,
  98. normalizeBearerToken,
  99. requireSecret,
  100. redact,
  101. };