|
|
import dotenv from 'dotenv'; |
|
|
import fs from 'fs'; |
|
|
import crypto from 'crypto'; |
|
|
import log from '../utils/logger.js'; |
|
|
import { deepMerge } from '../utils/deepMerge.js'; |
|
|
import { getConfigPaths } from '../utils/paths.js'; |
|
|
import { |
|
|
DEFAULT_SERVER_PORT, |
|
|
DEFAULT_SERVER_HOST, |
|
|
DEFAULT_HEARTBEAT_INTERVAL, |
|
|
DEFAULT_TIMEOUT, |
|
|
DEFAULT_RETRY_TIMES, |
|
|
DEFAULT_MAX_REQUEST_SIZE, |
|
|
DEFAULT_MAX_IMAGES, |
|
|
MODEL_LIST_CACHE_TTL, |
|
|
DEFAULT_GENERATION_PARAMS |
|
|
} from '../constants/index.js'; |
|
|
|
|
|
|
|
|
let generatedCredentials = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function getAdminCredentials() { |
|
|
const username = process.env.ADMIN_USERNAME; |
|
|
const password = process.env.ADMIN_PASSWORD; |
|
|
const jwtSecret = process.env.JWT_SECRET; |
|
|
|
|
|
|
|
|
if (username && password && jwtSecret) { |
|
|
return { username, password, jwtSecret }; |
|
|
} |
|
|
|
|
|
|
|
|
if (!generatedCredentials) { |
|
|
generatedCredentials = { |
|
|
username: username || crypto.randomBytes(8).toString('hex'), |
|
|
password: password || crypto.randomBytes(16).toString('base64').replace(/[+/=]/g, ''), |
|
|
jwtSecret: jwtSecret || crypto.randomBytes(32).toString('hex') |
|
|
}; |
|
|
|
|
|
|
|
|
if (!username || !password) { |
|
|
log.warn('═══════════════════════════════════════════════════════════'); |
|
|
log.warn('⚠️ 未配置管理员账号密码,已自动生成随机凭据:'); |
|
|
log.warn(` 用户名: ${generatedCredentials.username}`); |
|
|
log.warn(` 密码: ${generatedCredentials.password}`); |
|
|
log.warn('═══════════════════════════════════════════════════════════'); |
|
|
log.warn('⚠️ 重启后凭据将重新生成!建议在 .env 文件中配置:'); |
|
|
log.warn(' ADMIN_USERNAME=你的用户名'); |
|
|
log.warn(' ADMIN_PASSWORD=你的密码'); |
|
|
log.warn(' JWT_SECRET=你的密钥'); |
|
|
log.warn('═══════════════════════════════════════════════════════════'); |
|
|
} else if (!jwtSecret) { |
|
|
log.warn('⚠️ 未配置 JWT_SECRET,已生成随机密钥(重启后登录会话将失效)'); |
|
|
} |
|
|
} |
|
|
|
|
|
return generatedCredentials; |
|
|
} |
|
|
|
|
|
const { envPath, configJsonPath } = getConfigPaths(); |
|
|
|
|
|
|
|
|
const DEFAULT_SYSTEM_INSTRUCTION = '你是聊天机器人,名字叫萌萌,如同名字这般,你的性格是软软糯糯萌萌哒的,专门为用户提供聊天和情绪价值,协助进行小说创作或者角色扮演'; |
|
|
|
|
|
|
|
|
if (!fs.existsSync(envPath)) { |
|
|
const defaultEnvContent = `# 敏感配置(只在 .env 中配置) |
|
|
# 如果不配置以下三项,系统会自动生成随机凭据并在启动时显示 |
|
|
# API_KEY=your-api-key |
|
|
# ADMIN_USERNAME=your-username |
|
|
# ADMIN_PASSWORD=your-password |
|
|
# JWT_SECRET=your-jwt-secret |
|
|
|
|
|
# 可选配置 |
|
|
# PROXY=http://127.0.0.1:7890 |
|
|
SYSTEM_INSTRUCTION=${DEFAULT_SYSTEM_INSTRUCTION} |
|
|
# IMAGE_BASE_URL=http://your-domain.com |
|
|
`; |
|
|
fs.writeFileSync(envPath, defaultEnvContent, 'utf8'); |
|
|
log.info('✓ 已创建 .env 文件,包含默认萌萌系统提示词'); |
|
|
} |
|
|
|
|
|
|
|
|
let jsonConfig = {}; |
|
|
if (fs.existsSync(configJsonPath)) { |
|
|
jsonConfig = JSON.parse(fs.readFileSync(configJsonPath, 'utf8')); |
|
|
} |
|
|
|
|
|
|
|
|
dotenv.config({ path: envPath }); |
|
|
|
|
|
|
|
|
export function getProxyConfig() { |
|
|
|
|
|
if (process.env.PROXY) { |
|
|
return process.env.PROXY; |
|
|
} |
|
|
|
|
|
|
|
|
const systemProxy = process.env.HTTPS_PROXY || |
|
|
process.env.https_proxy || |
|
|
process.env.HTTP_PROXY || |
|
|
process.env.http_proxy || |
|
|
process.env.ALL_PROXY || |
|
|
process.env.all_proxy; |
|
|
|
|
|
if (systemProxy) { |
|
|
log.info(`使用系统代理: ${systemProxy}`); |
|
|
} |
|
|
|
|
|
return systemProxy || null; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function buildConfig(jsonConfig) { |
|
|
return { |
|
|
server: { |
|
|
port: jsonConfig.server?.port || DEFAULT_SERVER_PORT, |
|
|
host: jsonConfig.server?.host || DEFAULT_SERVER_HOST, |
|
|
heartbeatInterval: jsonConfig.server?.heartbeatInterval || DEFAULT_HEARTBEAT_INTERVAL, |
|
|
memoryThreshold: jsonConfig.server?.memoryThreshold || 100 |
|
|
}, |
|
|
cache: { |
|
|
modelListTTL: jsonConfig.cache?.modelListTTL || MODEL_LIST_CACHE_TTL |
|
|
}, |
|
|
rotation: { |
|
|
strategy: jsonConfig.rotation?.strategy || 'round_robin', |
|
|
requestCount: jsonConfig.rotation?.requestCount || 10 |
|
|
}, |
|
|
imageBaseUrl: process.env.IMAGE_BASE_URL || null, |
|
|
maxImages: jsonConfig.other?.maxImages || DEFAULT_MAX_IMAGES, |
|
|
api: { |
|
|
url: jsonConfig.api?.url || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:streamGenerateContent?alt=sse', |
|
|
modelsUrl: jsonConfig.api?.modelsUrl || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:fetchAvailableModels', |
|
|
noStreamUrl: jsonConfig.api?.noStreamUrl || 'https://daily-cloudcode-pa.sandbox.googleapis.com/v1internal:generateContent', |
|
|
host: jsonConfig.api?.host || 'daily-cloudcode-pa.sandbox.googleapis.com', |
|
|
userAgent: jsonConfig.api?.userAgent || 'antigravity/1.11.3 windows/amd64' |
|
|
}, |
|
|
defaults: { |
|
|
temperature: jsonConfig.defaults?.temperature ?? DEFAULT_GENERATION_PARAMS.temperature, |
|
|
top_p: jsonConfig.defaults?.topP ?? DEFAULT_GENERATION_PARAMS.top_p, |
|
|
top_k: jsonConfig.defaults?.topK ?? DEFAULT_GENERATION_PARAMS.top_k, |
|
|
max_tokens: jsonConfig.defaults?.maxTokens ?? DEFAULT_GENERATION_PARAMS.max_tokens, |
|
|
thinking_budget: jsonConfig.defaults?.thinkingBudget ?? DEFAULT_GENERATION_PARAMS.thinking_budget |
|
|
}, |
|
|
security: { |
|
|
maxRequestSize: jsonConfig.server?.maxRequestSize || DEFAULT_MAX_REQUEST_SIZE, |
|
|
apiKey: process.env.API_KEY || null |
|
|
}, |
|
|
admin: getAdminCredentials(), |
|
|
useNativeAxios: jsonConfig.other?.useNativeAxios !== false, |
|
|
timeout: jsonConfig.other?.timeout || DEFAULT_TIMEOUT, |
|
|
retryTimes: Number.isFinite(jsonConfig.other?.retryTimes) ? jsonConfig.other.retryTimes : DEFAULT_RETRY_TIMES, |
|
|
proxy: getProxyConfig(), |
|
|
systemInstruction: process.env.SYSTEM_INSTRUCTION || '', |
|
|
skipProjectIdFetch: jsonConfig.other?.skipProjectIdFetch === true, |
|
|
useContextSystemPrompt: jsonConfig.other?.useContextSystemPrompt === true, |
|
|
passSignatureToClient: jsonConfig.other?.passSignatureToClient === true |
|
|
}; |
|
|
} |
|
|
|
|
|
const config = buildConfig(jsonConfig); |
|
|
|
|
|
log.info('✓ 配置加载成功'); |
|
|
|
|
|
export default config; |
|
|
|
|
|
export function getConfigJson() { |
|
|
if (fs.existsSync(configJsonPath)) { |
|
|
return JSON.parse(fs.readFileSync(configJsonPath, 'utf8')); |
|
|
} |
|
|
return {}; |
|
|
} |
|
|
|
|
|
export function saveConfigJson(data) { |
|
|
const existing = getConfigJson(); |
|
|
const merged = deepMerge(existing, data); |
|
|
fs.writeFileSync(configJsonPath, JSON.stringify(merged, null, 2), 'utf8'); |
|
|
} |