193 lines
5.1 KiB
JavaScript
193 lines
5.1 KiB
JavaScript
import fs from 'fs';
|
|
import path from 'path';
|
|
import { fileURLToPath } from 'url';
|
|
|
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
const DATA_DIR = path.join(__dirname, '..', 'data');
|
|
const CONFIG_FILE = path.join(DATA_DIR, 'config.json');
|
|
|
|
export const PROVIDERS = [
|
|
{
|
|
id: 'openrouter',
|
|
name: 'OpenRouter',
|
|
baseUrl: 'https://openrouter.ai/api/v1',
|
|
models: [
|
|
{ id: 'minimax/minimax-m2.5', name: 'Minimax M2.5' },
|
|
{ id: 'google/gemini-2.5-flash-preview', name: 'Gemini 2.5 Flash' },
|
|
{ id: 'google/gemini-2.5-pro-preview', name: 'Gemini 2.5 Pro' },
|
|
{ id: 'deepseek/deepseek-chat-v3-0324', name: 'DeepSeek V3' },
|
|
{ id: 'deepseek/deepseek-r1', name: 'DeepSeek R1' },
|
|
{ id: 'qwen/qwen-2.5-72b-instruct', name: 'Qwen 2.5 72B' },
|
|
{ id: 'openai/gpt-4o-mini', name: 'GPT-4o Mini' },
|
|
{ id: 'openai/gpt-4o', name: 'GPT-4o' },
|
|
{ id: 'anthropic/claude-3.5-sonnet', name: 'Claude 3.5 Sonnet' },
|
|
],
|
|
},
|
|
{
|
|
id: 'openai',
|
|
name: 'OpenAI',
|
|
baseUrl: 'https://api.openai.com/v1',
|
|
models: [
|
|
{ id: 'gpt-4o-mini', name: 'GPT-4o Mini' },
|
|
{ id: 'gpt-4o', name: 'GPT-4o' },
|
|
{ id: 'gpt-4.1-mini', name: 'GPT-4.1 Mini' },
|
|
{ id: 'gpt-4.1', name: 'GPT-4.1' },
|
|
{ id: 'o3-mini', name: 'o3-mini' },
|
|
],
|
|
},
|
|
{
|
|
id: 'deepseek',
|
|
name: 'DeepSeek',
|
|
baseUrl: 'https://api.deepseek.com',
|
|
models: [
|
|
{ id: 'deepseek-chat', name: 'DeepSeek V3' },
|
|
{ id: 'deepseek-reasoner', name: 'DeepSeek R1' },
|
|
],
|
|
},
|
|
{
|
|
id: 'qwen',
|
|
name: '通义千问 (Qwen)',
|
|
baseUrl: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
|
|
models: [
|
|
{ id: 'qwen-plus', name: 'Qwen Plus' },
|
|
{ id: 'qwen-turbo', name: 'Qwen Turbo' },
|
|
{ id: 'qwen-max', name: 'Qwen Max' },
|
|
{ id: 'qwen-long', name: 'Qwen Long' },
|
|
],
|
|
},
|
|
{
|
|
id: 'siliconflow',
|
|
name: 'SiliconFlow (硅基流动)',
|
|
baseUrl: 'https://api.siliconflow.cn/v1',
|
|
models: [
|
|
{ id: 'deepseek-ai/DeepSeek-V3', name: 'DeepSeek V3' },
|
|
{ id: 'deepseek-ai/DeepSeek-R1', name: 'DeepSeek R1' },
|
|
{ id: 'Qwen/Qwen2.5-72B-Instruct', name: 'Qwen 2.5 72B' },
|
|
{ id: 'THUDM/glm-4-9b-chat', name: 'GLM-4 9B' },
|
|
],
|
|
},
|
|
{
|
|
id: 'zhipu',
|
|
name: '智谱 AI (GLM)',
|
|
baseUrl: 'https://open.bigmodel.cn/api/paas/v4',
|
|
models: [
|
|
{ id: 'glm-4-flash', name: 'GLM-4 Flash' },
|
|
{ id: 'glm-4-plus', name: 'GLM-4 Plus' },
|
|
{ id: 'glm-4', name: 'GLM-4' },
|
|
],
|
|
},
|
|
{
|
|
id: 'moonshot',
|
|
name: 'Moonshot (Kimi)',
|
|
baseUrl: 'https://api.moonshot.cn/v1',
|
|
models: [
|
|
{ id: 'moonshot-v1-8k', name: 'Moonshot V1 8K' },
|
|
{ id: 'moonshot-v1-32k', name: 'Moonshot V1 32K' },
|
|
{ id: 'moonshot-v1-128k', name: 'Moonshot V1 128K' },
|
|
],
|
|
},
|
|
{
|
|
id: 'groq',
|
|
name: 'Groq',
|
|
baseUrl: 'https://api.groq.com/openai/v1',
|
|
models: [
|
|
{ id: 'llama-3.3-70b-versatile', name: 'Llama 3.3 70B' },
|
|
{ id: 'gemma2-9b-it', name: 'Gemma 2 9B' },
|
|
{ id: 'mixtral-8x7b-32768', name: 'Mixtral 8x7B' },
|
|
],
|
|
},
|
|
{
|
|
id: 'custom',
|
|
name: '自定义 (OpenAI 兼容)',
|
|
baseUrl: '',
|
|
models: [],
|
|
},
|
|
];
|
|
|
|
const DEFAULT_CONFIG = {
|
|
provider: '',
|
|
apiKey: '',
|
|
baseUrl: '',
|
|
model: '',
|
|
customModels: [],
|
|
};
|
|
|
|
let _config = null;
|
|
|
|
export function loadConfig() {
|
|
if (_config) return _config;
|
|
try {
|
|
if (fs.existsSync(CONFIG_FILE)) {
|
|
const raw = fs.readFileSync(CONFIG_FILE, 'utf-8');
|
|
_config = { ...DEFAULT_CONFIG, ...JSON.parse(raw) };
|
|
} else {
|
|
_config = { ...DEFAULT_CONFIG };
|
|
}
|
|
} catch {
|
|
_config = { ...DEFAULT_CONFIG };
|
|
}
|
|
return _config;
|
|
}
|
|
|
|
export function saveConfig(newConfig) {
|
|
_config = { ...DEFAULT_CONFIG, ..._config, ...newConfig };
|
|
try {
|
|
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(_config, null, 2), 'utf-8');
|
|
} catch (err) {
|
|
console.error('保存配置失败:', err.message);
|
|
}
|
|
return _config;
|
|
}
|
|
|
|
export function getConfig() {
|
|
return loadConfig();
|
|
}
|
|
|
|
export function isConfigured() {
|
|
const cfg = loadConfig();
|
|
return !!(cfg.apiKey && cfg.baseUrl && cfg.model);
|
|
}
|
|
|
|
export function getApiKey() {
|
|
return loadConfig().apiKey || '';
|
|
}
|
|
|
|
export function getBaseUrl() {
|
|
return loadConfig().baseUrl || '';
|
|
}
|
|
|
|
export function getCurrentModel() {
|
|
return loadConfig().model || '';
|
|
}
|
|
|
|
export function setCurrentModel(modelId) {
|
|
const cfg = loadConfig();
|
|
cfg.model = modelId;
|
|
saveConfig(cfg);
|
|
console.log(`🤖 AI 模型已切换为: ${modelId}`);
|
|
return true;
|
|
}
|
|
|
|
export function getAvailableModels() {
|
|
const cfg = loadConfig();
|
|
const provider = PROVIDERS.find(p => p.id === cfg.provider);
|
|
const presetModels = provider?.models || [];
|
|
const customModels = (cfg.customModels || []).map(m =>
|
|
typeof m === 'string' ? { id: m, name: m } : m
|
|
);
|
|
return [...presetModels, ...customModels];
|
|
}
|
|
|
|
export function getSafeConfig() {
|
|
const cfg = loadConfig();
|
|
return {
|
|
provider: cfg.provider,
|
|
apiKey: cfg.apiKey ? `${cfg.apiKey.slice(0, 8)}****${cfg.apiKey.slice(-4)}` : '',
|
|
baseUrl: cfg.baseUrl,
|
|
model: cfg.model,
|
|
customModels: cfg.customModels || [],
|
|
hasKey: !!cfg.apiKey,
|
|
};
|
|
}
|