File size: 5,478 Bytes
7ce979b 8602f0b 7ce979b 58d2e5a 8602f0b 58d2e5a 7ce979b 8602f0b 1f1edd2 7ce979b 8602f0b 8e4faae 7ce979b 8602f0b 04355f4 7ce979b 58d2e5a 8602f0b f3bbc51 7ce979b f3bbc51 7ce979b 8602f0b 7ce979b 1f1edd2 8602f0b 7ce979b 1f1edd2 7ce979b |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
/**
* 多 API 配置和路由
* 根据模型名称自动选择正确的 API 端点和密钥
*/
/**
* 清理 API 密钥 - 移除换行符、空格等特殊字符
*/
function cleanApiKey(key) {
if (!key) return null;
return String(key).trim().replace(/\r?\n/g, '').replace(/\s+/g, '');
}
// API 配置
const API_CONFIGS = {
// Google Gemini
gemini: {
baseUrl: 'https://generativelanguage.googleapis.com/v1',
apiKey: cleanApiKey(process.env.GEMINI_API_KEY),
models: [
'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite',
'gemini-2.0-flash', 'gemini-2.0-flash-001', 'gemini-2.0-flash-lite', 'gemini-2.0-flash-lite-001',
// 保留旧模型名称以兼容
'gemini-1.5-pro', 'gemini-1.5-flash', 'gemini-pro', 'gemini-3-pro-preview'
],
format: 'gemini', // 使用 Gemini 原生格式
},
// OpenAI (ChatGPT)
openai: {
baseUrl: 'https://api.openai.com/v1',
apiKey: cleanApiKey(process.env.OPENAI_API_KEY),
models: [
'gpt-5.1', 'gpt-5-mini', 'gpt-5-nano',
'gpt-4.1', 'gpt-4.1-mini', 'gpt-4.1-nano',
'gpt-4', 'gpt-4-turbo', 'gpt-4o', 'gpt-4o-mini', 'gpt-3.5-turbo' // 保留旧模型以兼容
],
format: 'openai', // 使用 OpenAI 格式
},
// Grok (xAI)
grok: {
baseUrl: 'https://api.x.ai/v1',
apiKey: cleanApiKey(process.env.GROK_API_KEY),
models: [
'grok-4-0709', 'grok-4-1-fast-reasoning', 'grok-4-1-fast-non-reasoning',
'grok-4-fast-reasoning', 'grok-4-fast-non-reasoning',
'grok-3', 'grok-3-mini', 'grok-code-fast-1',
'grok-4', 'grok-4-auto', 'grok-beta' // 保留旧名称以兼容
],
format: 'openai', // Grok 使用 OpenAI 兼容格式
},
// Claude (Anthropic)
claude: {
baseUrl: 'https://api.anthropic.com/v1',
apiKey: cleanApiKey(process.env.CLAUDE_API_KEY),
models: [
'claude-opus-4-5', 'claude-sonnet-4-5', 'claude-haiku-4-20250514',
'claude-opus-4-1', 'claude-opus-4', 'claude-sonnet-4',
'claude-3-5-sonnet-20241022', 'claude-3-5-sonnet-20240620',
'claude-3-opus-20240229', 'claude-3-5-haiku-20241022',
'claude-3-sonnet-20240229', 'claude-3-haiku-20240307'
],
format: 'claude', // 使用 Claude 格式
},
};
/**
* 根据模型名称获取 API 配置
*/
export function getApiConfigForModel(modelName) {
// 检查每个 API 提供商的模型列表
for (const [provider, config] of Object.entries(API_CONFIGS)) {
if (config.models.includes(modelName)) {
return { ...config, provider };
}
}
// 默认使用 Gemini
return { ...API_CONFIGS.gemini, provider: 'gemini' };
}
/**
* 构建 API 请求
*/
export function buildApiRequest(modelName, systemPrompt, userPrompt, temperature = 0.7) {
const config = getApiConfigForModel(modelName);
if (config.format === 'gemini') {
// Google Gemini 格式 - 使用 v1 API
// v1 API 使用 models/{model}:generateContent 格式
if (!config.apiKey) {
throw new Error('GEMINI_API_KEY not configured');
}
const geminiModel = modelName.replace('-latest', ''); // 移除 -latest 后缀
return {
url: `${config.baseUrl}/models/${geminiModel}:generateContent?key=${config.apiKey}`,
headers: { 'Content-Type': 'application/json' },
body: {
contents: [{
parts: [{
text: `${systemPrompt}\n\n${userPrompt}`
}]
}],
generationConfig: {
temperature: temperature,
}
}
};
} else if (config.format === 'claude') {
// Claude 格式
if (!config.apiKey) {
throw new Error('CLAUDE_API_KEY not configured');
}
return {
url: `${config.baseUrl}/messages`,
headers: {
'Content-Type': 'application/json',
'x-api-key': config.apiKey,
'anthropic-version': '2023-06-01',
},
body: {
model: modelName,
max_tokens: 8192,
temperature: temperature,
messages: [
{ role: 'user', content: `${systemPrompt}\n\n${userPrompt}` }
]
}
};
} else {
// OpenAI 兼容格式 (OpenAI, Grok)
// GPT-5 系列模型只支持 temperature=1(默认值)
const isGPT5 = modelName.startsWith('gpt-5');
const requestBody = {
model: modelName,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
};
// 只有非 GPT-5 模型才设置 temperature
if (!isGPT5) {
requestBody.temperature = temperature;
}
// 确保 API 密钥存在
if (!config.apiKey) {
throw new Error(`API key not configured for ${config.provider || 'unknown provider'}`);
}
return {
url: `${config.baseUrl}/chat/completions`,
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${config.apiKey}`,
},
body: requestBody
};
}
}
/**
* 解析 API 响应
*/
export function parseApiResponse(responseJson, modelName) {
const config = getApiConfigForModel(modelName);
if (config.format === 'gemini') {
// Google Gemini 响应格式
return responseJson.candidates?.[0]?.content?.parts?.[0]?.text || null;
} else if (config.format === 'claude') {
// Claude 响应格式
return responseJson.content?.[0]?.text || null;
} else {
// OpenAI 兼容格式
return responseJson.choices?.[0]?.message?.content || null;
}
}
export default API_CONFIGS;
|