feat: add recipe translation tool with AI translation and settings management

- Add Word document parsing and translation export
- Add database configuration management
- Add AI/LLM translation configuration
- Add translation vocabulary management
- Add export settings (colors, page orientation, headers)
- Separate database and AI configurations
- Add debounced search to prevent database overload
This commit is contained in:
2026-04-12 23:50:54 +08:00
parent 57e119635e
commit a249fb038c
24 changed files with 3383 additions and 70 deletions
+139
View File
@@ -0,0 +1,139 @@
import OpenAI from "openai";
// AI 翻译配置
interface AIConfig {
apiKey: string;
baseUrl?: string;
model?: string;
}
// 默认配置(从环境变量)
function getDefaultConfig(): AIConfig {
return {
apiKey: process.env.AI_API_KEY || "",
baseUrl: process.env.AI_BASE_URL || undefined,
model: process.env.AI_MODEL || "gpt-3.5-turbo",
};
}
// 模块级配置存储
let savedConfig: AIConfig | null = null;
// 设置保存的配置
export function setAIConfig(config: AIConfig) {
savedConfig = config;
}
// 获取配置(优先使用保存的配置)
export function getAIConfig(): AIConfig {
return savedConfig || getDefaultConfig();
}
// 解析翻译结果
function parseTranslation(content: string): string | null {
const patterns = [
/english\s*:\s*['"]([^'"]+)['"]/i,
/english\s*[:\s]+([^,'"\n]+)/i,
/['"]([^'"]+)['"]\s*[,}].*english/i,
/^([^,]+)\s*,\s*english\s*:\s*['"]([^'"]+)['"]/i,
];
for (const pattern of patterns) {
const match = content.match(pattern);
if (match) {
return match[1]?.trim() || null;
}
}
return null;
}
// 翻译单个词组(带重试)
export async function translateWithAI(
word: string,
config?: AIConfig,
maxRetries: number = 3
): Promise<string | null> {
const aiConfig = config || getAIConfig();
if (!aiConfig.apiKey) {
throw new Error("AI API Key 未配置");
}
const client = new OpenAI({
apiKey: aiConfig.apiKey,
baseURL: aiConfig.baseUrl,
});
const prompt = `你是一个专业的中文到英文翻译助手。
任务:将给定的中文词组翻译成英文。
严格要求:
1. 必须严格返回 JSON 格式:{"word":"中文原文","english":"英文翻译"}
2. 不要返回任何其他内容,不要解释
3. 只返回这一行 JSON
4. 翻译要简洁、准确
中文词组:${word}
请立即返回 JSON 结果:`;
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const completion = await client.chat.completions.create({
model: aiConfig.model || "gpt-3.5-turbo",
messages: [
{
role: "system",
content: "你是一个严格遵循指令的翻译助手。必须只返回要求的 JSON 格式,不要返回任何其他内容。",
},
{ role: "user", content: prompt },
],
temperature: 0,
max_tokens: 50,
});
const content = completion.choices[0]?.message?.content || "";
const translation = parseTranslation(content);
if (translation && translation.length > 0) {
return translation;
}
// Fallback: 提取英文单词
const fallbackMatch = content.match(/[a-zA-Z][a-zA-Z\s-]*/);
if (fallbackMatch) {
const fallback = fallbackMatch[0].trim();
if (fallback.length > 1) {
return fallback;
}
}
} catch (error) {
console.error(`Attempt ${attempt + 1} error:`, error);
}
}
return null;
}
// 批量翻译词组
export async function batchTranslateWithAI(
words: string[],
config?: AIConfig
): Promise<Map<string, string>> {
const results = new Map<string, string>();
for (const word of words) {
try {
const translation = await translateWithAI(word, config);
if (translation) {
results.set(word, translation);
}
} catch (error) {
console.error(`Failed to translate "${word}":`, error);
}
}
return results;
}