34 lines
1.5 KiB
TypeScript
34 lines
1.5 KiB
TypeScript
import { loadSettings } from "../settings";
|
||
import { RuntimeError } from "../engine/types";
|
||
|
||
export interface ChatMessage { role: "system" | "user" | "assistant"; content: string }
|
||
|
||
export function getAiConfig(): { baseUrl: string; apiKey: string; model: string } {
|
||
return loadSettings().aiConfig;
|
||
}
|
||
|
||
export function requireAiConfig() {
|
||
const config = getAiConfig();
|
||
if (!config.baseUrl || !config.model) {
|
||
throw new RuntimeError("ai_not_configured", "AI 服务未配置", { recommendation: "到 设置 → AI 服务 填写 Base URL 与模型名(兼容 OpenAI 协议)" });
|
||
}
|
||
return config;
|
||
}
|
||
|
||
export async function chatCompletion(messages: ChatMessage[], options: { temperature?: number } = {}): Promise<string> {
|
||
const config = requireAiConfig();
|
||
const base = config.baseUrl.replace(/\/+$/, "");
|
||
const response = await fetch(base + "/chat/completions", {
|
||
signal: AbortSignal.timeout(170000),
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json", Authorization: "Bearer " + config.apiKey },
|
||
body: JSON.stringify({ model: config.model, messages, temperature: options.temperature ?? 0.3 })
|
||
});
|
||
if (!response.ok) {
|
||
const detail = (await response.text()).slice(0, 300);
|
||
throw new RuntimeError("ai_request_failed", "AI 请求失败(HTTP " + response.status + "):" + detail);
|
||
}
|
||
const data = (await response.json()) as { choices?: Array<{ message?: { content?: string } }> };
|
||
return data.choices?.[0]?.message?.content ?? "";
|
||
}
|