| 122 | ): Promise<string> { |
| 123 | const base = trimBase(provider.base_url); |
| 124 | // 火山等 API 的 base_url 已包含版本路径(如 /api/v3),无需再添加 /v1 |
| 125 | const url = base.match(/\/v\d+$/) ? `${base}/chat/completions` : `${base}/v1/chat/completions`; |
| 126 | const headers: Record<string, string> = { "Content-Type": "application/json" }; |
| 127 | |
| 128 | if (provider.auth_method === "bearer_token") { |
| 129 | headers["Authorization"] = `Bearer ${provider.api_key}`; |
| 130 | } else if (provider.auth_method === "api_key_header") { |
| 131 | headers["X-API-Key"] = provider.api_key; |
| 132 | } |
| 133 | |
| 134 | const params: Record<string, string> = {}; |
| 135 | if (provider.auth_method === "query_param") { |
| 136 | params["key"] = provider.api_key; |
| 137 | } |
| 138 | |
| 139 | const response = await axios.post( |
| 140 | url, |
| 141 | { |
| 142 | model: provider.model, |
| 143 | messages: [{ role: "user", content: `${prompt}\n\n${content}` }], |
| 144 | max_tokens: 4096 |
| 145 | }, |
| 146 | { headers, params, timeout } |
| 147 | ); |
| 148 | |
| 149 | return response.data?.choices?.[0]?.message?.content || ""; |
| 150 | } |
| 151 | |
| 152 | async function callGemini( |
| 153 | provider: Provider, |
| 154 | prompt: string, |
| 155 | content: string, |
| 156 | timeout: number |
| 157 | ): Promise<string> { |
| 158 | const url = `${trimBase(provider.base_url)}/v1beta/models/${provider.model}:generateContent`; |
| 159 | const headers: Record<string, string> = { "Content-Type": "application/json" }; |
| 160 | const params: Record<string, string> = {}; |