69 lines
2.9 KiB
TypeScript
69 lines
2.9 KiB
TypeScript
const DEEPSEEK_BASE = process.env.DEEPSEEK_BASE_URL || "https://api.deepseek.com";
|
|||
|
|
const DEEPSEEK_KEY = process.env.DEEPSEEK_API_KEY || "";
|
||
|
|
const DEEPSEEK_MODEL = process.env.DEEPSEEK_MODEL || "deepseek-chat";
|
||
|
|
const DEEPSEEK_ANTHROPIC = process.env.DEEPSEEK_ANTHROPIC === "true";
|
||
|
|
|
||
|
|
export async function aiChat(
|
||
|
|
systemPrompt: string,
|
||
|
|
userMessage: string
|
||
|
|
): Promise<string> {
|
||
|
|
if (!DEEPSEEK_KEY) throw new Error("DeepSeek API key not configured");
|
||
|
|
|
||
|
|
let url: string;
|
||
|
|
let headers: Record<string, string>;
|
||
|
|
let body: Record<string, unknown>;
|
||
|
|
|
||
|
|
if (DEEPSEEK_ANTHROPIC) {
|
||
|
|
// Anthropic Messages API
|
||
|
|
url = `${DEEPSEEK_BASE}/v1/messages`;
|
||
|
|
headers = {
|
||
|
|
"Content-Type": "application/json",
|
||
|
|
"x-api-key": DEEPSEEK_KEY,
|
||
|
|
"anthropic-version": "2023-06-01",
|
||
|
|
};
|
||
|
|
body = {
|
||
|
|
model: DEEPSEEK_MODEL,
|
||
|
|
max_tokens: 2048,
|
||
|
|
system: systemPrompt,
|
||
|
|
messages: [{ role: "user", content: userMessage }],
|
||
|
|
};
|
||
|
|
} else {
|
||
|
|
// OpenAI-compatible API (default)
|
||
|
|
url = `${DEEPSEEK_BASE}/v1/chat/completions`;
|
||
|
|
headers = {
|
||
|
|
"Content-Type": "application/json",
|
||
|
|
Authorization: `Bearer ${DEEPSEEK_KEY}`,
|
||
|
|
};
|
||
|
|
body = {
|
||
|
|
model: DEEPSEEK_MODEL,
|
||
|
|
temperature: 0.7,
|
||
|
|
max_tokens: 2048,
|
||
|
|
messages: [
|
||
|
|
{ role: "system", content: systemPrompt },
|
||
|
|
{ role: "user", content: userMessage },
|
||
|
|
],
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
const res = await fetch(url, { method: "POST", headers, body: JSON.stringify(body) });
|
||
|
|
|
||
|
|
if (!res.ok) {
|
||
|
|
const err = await res.json().catch(() => ({}));
|
||
|
|
throw new Error((err as { error?: { message?: string } }).error?.message || `API error: ${res.status}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
const data = await res.json();
|
||
|
|
// Anthropic format or OpenAI format
|
||
|
|
const text = data?.content?.[0]?.text || data?.choices?.[0]?.message?.content || "";
|
||
|
|
if (!text) throw new Error("AI returned empty response");
|
||
|
|
return text;
|
||
|
|
}
|
||
|
|
|
||
|
|
export const AI_PROMPTS = {
|
||
|
|
polish: "你是一个文字润色助手。请润色以下文字,使其更流畅、更有文采,但保持原意和语气不变。直接返回润色后的文字,不要加任何解释。",
|
||
|
|
expand: "你是一个写作助手。请扩写以下文字,增加更多细节和论述,使其更充实。保持原风格和语气。直接返回扩写后的文字,不要加任何解释。",
|
||
|
|
shorten: "你是一个写作助手。请缩写以下文字,保留核心信息,删除冗余。直接返回缩写后的文字,不要加任何解释。",
|
||
|
|
fix: "你是一个文字校对助手。请修正以下文字中的错别字、语法错误和标点问题。直接返回修正后的文字,不要加任何解释。",
|
||
|
|
summary: "根据以下文章标题和内容,生成一个简短的摘要(100字以内)。直接返回摘要,不要加任何解释。\n\n标题:{title}\n\n内容片段:{content}",
|
||
|
|
tags: "根据以下文章标题和内容,提取3-5个中文标签(用顿号分隔)。只返回标签,不要加解释。\n\n标题:{title}\n\n内容片段:{content}",
|
||
|
|
};
|