From 06a7fa03e00ec6a77f39fa5b331c5eb5fa4edc38 Mon Sep 17 00:00:00 2001 From: Suhaha Date: Mon, 13 Apr 2026 20:05:30 +0800 Subject: [PATCH 1/2] Add OpenAI API integration for translation and update environment variables --- markdown-translator/README.md | 3 + markdown-translator/src/aiTranslatorZH.js | 107 +++++++++++++++++++--- 2 files changed, 98 insertions(+), 12 deletions(-) diff --git a/markdown-translator/README.md b/markdown-translator/README.md index 1ce3f29..dd93b93 100644 --- a/markdown-translator/README.md +++ b/markdown-translator/README.md @@ -7,4 +7,7 @@ export \ GOOGLE_APPLICATION_CREDENTIALS=key.json export PROJECT_ID=PROJECT_ID export GLOSSARY_ID=GLOSSARY_ID +export OPENAI_RESPONSES_API_URL=https://YOUR_PROVIDER_URL +export OPENAI_API_KEY=YOUR_API_KEY +export OPENAI_MODEL=gpt-5.4 ``` diff --git a/markdown-translator/src/aiTranslatorZH.js b/markdown-translator/src/aiTranslatorZH.js index 55207e8..3196f60 100644 --- a/markdown-translator/src/aiTranslatorZH.js +++ b/markdown-translator/src/aiTranslatorZH.js @@ -1,12 +1,8 @@ import * as fs from "fs"; import { get_encoding } from "tiktoken"; import { writeFileSync } from "./lib.js"; -import { executeLangLinkTranslator } from "./langlinkClient.js"; import { gcpTranslator } from "./gcpTranslator.js"; -// LangLink 配置 -const LANGLINK_APP_ID = "d57cc1a9-2b2a-45c7-9119-ac798285b2ab"; - // Token 限制配置 const OUTPUT_TOKEN_LIMIT = 60000; const TIKTOKEN_ENCODING = "cl100k_base"; @@ -15,6 +11,12 @@ const TIKTOKEN_ENCODING = "cl100k_base"; const TOKEN_RATIO = 1.8; const INPUT_TOKEN_LIMIT = Math.floor(OUTPUT_TOKEN_LIMIT / TOKEN_RATIO); +const getOpenAIConfig = () => ({ + apiUrl: process.env.OPENAI_RESPONSES_API_URL, + apiKey: process.env.OPENAI_API_KEY, + model: process.env.OPENAI_MODEL, +}); + /** * 计算文本的token数量 * @param {string} text - 要计算的文本 @@ -28,20 +30,101 @@ const countTokens = (text) => { return count; }; +const buildTranslationPrompt = (content, glossary) => `You are a professional technical document translator, specializing in translating English technical documents into accurate and professional Chinese. + +Please translate the following English technical document into Chinese, preserving the original Markdown format and structure: + +English Content: +${content} + +Please follow these requirements strictly: + +Markdown and Code Preservation Rules: +- Absolutely preserve all Markdown structures (headings, lists, tables, links, emphasis, etc.). +- Preserve ALL code blocks exactly as-is: + - Do not modify code. + - Do not summarize, shorten, or replace it with comments like “代码保持不变”. + - Do not add or remove any characters inside code blocks. + - Treat everything between triple backticks \`\`\` as literal text to copy verbatim. +- Keep all filenames, paths, SQL, Java, Go, JSON, YAML, and shell commands unchanged. + +Translation Rules: +- Use precise, professional Chinese technical terminology. +- Maintain logical flow and readability. +- Keep all link URLs unchanged. +- Do not translate text wrapped in bold syntax. +- Translate “you” as “你”, not “您”. +- Insert spaces between Chinese and English text, and between Chinese text and Arabic numerals. +- Translate only the natural-language content. Do not add explanations or extra text. + +Strictly forbidden: +- Do not omit code blocks. +- Do not replace code with placeholders. +- Do not rewrite or format code. +- Do not hallucinate missing content. +- Do not simplify long code samples. + +Glossary Rules: +If you find any of the following keys in the text, do not translate them; simply replace the matching key with the corresponding value: +${JSON.stringify(glossary, null, 2)}`; + +const extractResponseText = (responseBody) => { + if (typeof responseBody.output_text === "string" && responseBody.output_text) { + return responseBody.output_text; + } + + if (!Array.isArray(responseBody.output)) { + throw new Error(`Unexpected OpenAI response shape: ${JSON.stringify(responseBody)}`); + } + + const text = responseBody.output + .flatMap((item) => item.content || []) + .filter((item) => item.type === "output_text") + .map((item) => item.text || "") + .join(""); + + if (!text) { + throw new Error(`OpenAI response does not contain output text: ${JSON.stringify(responseBody)}`); + } + + return text; +}; + /** - * 使用LangLink进行翻译 + * 使用 OpenAI Responses API 进行翻译 * @param {string} content - 要翻译的内容 - * @param {Array} glossary - 词汇表 + * @param {Record} glossary - 词汇表 * @returns {Promise} 翻译结果 */ const translateWithLangLink = async (content, glossary) => { - try { - const result = await executeLangLinkTranslator( - LANGLINK_APP_ID, - content, - glossary + const { apiUrl, apiKey, model } = getOpenAIConfig(); + + if (!apiUrl || !apiKey || !model) { + throw new Error( + "Missing required env vars: OPENAI_RESPONSES_API_URL, OPENAI_API_KEY, OPENAI_MODEL" ); - return result; + } + + try { + const response = await fetch(apiUrl, { + method: "POST", + headers: { + "Content-Type": "application/json", + "api-key": apiKey, + }, + body: JSON.stringify({ + model, + input: buildTranslationPrompt(content, glossary), + max_output_tokens: OUTPUT_TOKEN_LIMIT, + }), + }); + + const responseBody = await response.json(); + if (!response.ok) { + throw new Error(JSON.stringify(responseBody)); + } + + return extractResponseText(responseBody); } catch (error) { console.error("Translation error:", error); throw error; From 4045b7757e10d1d884499e17840b37bfbae2f537 Mon Sep 17 00:00:00 2001 From: Suhaha Date: Mon, 13 Apr 2026 20:15:53 +0800 Subject: [PATCH 2/2] Update README and aiTranslatorZH.js to set default OpenAI model and improve error handling for missing environment variables --- markdown-translator/README.md | 1 + markdown-translator/src/aiTranslatorZH.js | 6 ++---- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/markdown-translator/README.md b/markdown-translator/README.md index dd93b93..a5cc625 100644 --- a/markdown-translator/README.md +++ b/markdown-translator/README.md @@ -9,5 +9,6 @@ export PROJECT_ID=PROJECT_ID export GLOSSARY_ID=GLOSSARY_ID export OPENAI_RESPONSES_API_URL=https://YOUR_PROVIDER_URL export OPENAI_API_KEY=YOUR_API_KEY +# optional, defaults to gpt-5.4 export OPENAI_MODEL=gpt-5.4 ``` diff --git a/markdown-translator/src/aiTranslatorZH.js b/markdown-translator/src/aiTranslatorZH.js index 3196f60..e945c91 100644 --- a/markdown-translator/src/aiTranslatorZH.js +++ b/markdown-translator/src/aiTranslatorZH.js @@ -14,7 +14,7 @@ const INPUT_TOKEN_LIMIT = Math.floor(OUTPUT_TOKEN_LIMIT / TOKEN_RATIO); const getOpenAIConfig = () => ({ apiUrl: process.env.OPENAI_RESPONSES_API_URL, apiKey: process.env.OPENAI_API_KEY, - model: process.env.OPENAI_MODEL, + model: process.env.OPENAI_MODEL || "gpt-5.4", }); /** @@ -100,9 +100,7 @@ const translateWithLangLink = async (content, glossary) => { const { apiUrl, apiKey, model } = getOpenAIConfig(); if (!apiUrl || !apiKey || !model) { - throw new Error( - "Missing required env vars: OPENAI_RESPONSES_API_URL, OPENAI_API_KEY, OPENAI_MODEL" - ); + throw new Error("Missing required env vars: OPENAI_RESPONSES_API_URL, OPENAI_API_KEY"); } try {