diff --git a/src/apis/trans.js b/src/apis/trans.js index 0c73902..575dc3e 100644 --- a/src/apis/trans.js +++ b/src/apis/trans.js @@ -240,6 +240,8 @@ const genOpenAI = ({ model, temperature, maxTokens, + customHeader, + customBody, }) => { // 兼容历史上作为systemPrompt的prompt,如果prompt中不包含带翻译文本,则添加文本到prompt末尾 // if (!prompt.includes(INPUT_PLACE_TEXT)) { @@ -254,6 +256,9 @@ const genOpenAI = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); + customBody = JSON.parse("{" + customBody + "}"); + const data = { model, messages: [ @@ -268,6 +273,7 @@ const genOpenAI = ({ ], temperature, max_completion_tokens: maxTokens, + ...customBody, }; const init = { @@ -275,6 +281,7 @@ const genOpenAI = ({ "Content-type": "application/json", Authorization: `Bearer ${key}`, // OpenAI "api-key": key, // Azure OpenAI + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -294,6 +301,8 @@ const genGemini = ({ model, temperature, maxTokens, + customHeader, + customBody, }) => { url = url .replaceAll(INPUT_PLACE_MODEL, model) @@ -307,6 +316,9 @@ const genGemini = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); + customBody = JSON.parse("{" + customBody + "}"); + const data = { system_instruction: { parts: { @@ -325,11 +337,13 @@ const genGemini = ({ // topP: 0.8, // topK: 10, }, + ...customBody, }; const init = { headers: { "Content-type": "application/json", + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -349,6 +363,8 @@ const genGemini2 = ({ model, temperature, maxTokens, + customHeader, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -359,6 +375,9 @@ const genGemini2 = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); + customBody = JSON.parse("{" + customBody + "}"); + const data = { model, messages: [ @@ -373,12 +392,14 @@ const genGemini2 = ({ ], temperature, max_tokens: maxTokens, + ...customBody, }; const init = { headers: { "Content-type": "application/json", Authorization: `Bearer ${key}`, + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -398,6 +419,8 @@ const genClaude = ({ model, temperature, maxTokens, + customHeader, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -408,6 +431,9 @@ const genClaude = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); + customBody = JSON.parse("{" + customBody + "}"); + const data = { model, system: systemPrompt, @@ -419,6 +445,7 @@ const genClaude = ({ ], temperature, max_tokens: maxTokens, + ...customBody, }; const init = { @@ -426,6 +453,7 @@ const genClaude = ({ "Content-type": "application/json", "anthropic-version": "2023-06-01", "x-api-key": key, + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -444,6 +472,8 @@ const genOllama = ({ systemPrompt, userPrompt, model, + customHeader, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -454,17 +484,22 @@ const genOllama = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); + customBody = JSON.parse("{" + customBody + "}"); + const data = { model, system: systemPrompt, prompt: userPrompt, think: think, stream: false, + ...customBody, }; const init = { headers: { "Content-type": "application/json", + ...customHeader, }, method: "POST", body: JSON.stringify(data), diff --git a/src/config/i18n.js b/src/config/i18n.js index cb7de61..805e37d 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -228,6 +228,22 @@ export const I18N = { zh: `请求超时时间 (5000-30000ms)`, en: `Request Timeout Time (5000-30000ms)`, }, + custom_header: { + zh: `自定义Header参数`, + en: `Custom Header Params`, + }, + custom_header_help: { + zh: `使用JSON格式,例如 "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0"`, + en: `Use JSON format, for example "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:141.0) Gecko/20100101 Firefox/141.0"`, + }, + custom_body: { + zh: `自定义Body参数`, + en: `Custom Body Params`, + }, + custom_body_help: { + zh: `使用JSON格式,例如 "top_p": 0.7`, + en: `Use JSON format, for example "top_p": 0.7`, + }, min_translate_length: { zh: `最小翻译字符数 (1-100)`, en: `Minimum number Of Translated Characters (1-100)`, diff --git a/src/config/index.js b/src/config/index.js index c232c2d..0427070 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -563,6 +563,8 @@ const defaultOpenaiApi = { model: "gpt-4", systemPrompt: `You are a professional, authentic machine translation engine.`, userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`, + customHeader: "", + customBody: "", temperature: 0, maxTokens: 256, fetchLimit: 1, @@ -577,6 +579,8 @@ const defaultOllamaApi = { model: "llama3.1", systemPrompt: `You are a professional, authentic machine translation engine.`, userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`, + customHeader: "", + customBody: "", think: false, thinkIgnore: `qwen3,deepseek-r1`, fetchLimit: 1, @@ -677,6 +681,8 @@ export const DEFAULT_TRANS_APIS = { model: "gemini-2.5-flash", systemPrompt: `You are a professional, authentic machine translation engine.`, userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`, + customHeader: "", + customBody: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -691,6 +697,8 @@ export const DEFAULT_TRANS_APIS = { model: "gemini-2.0-flash", systemPrompt: `You are a professional, authentic machine translation engine.`, userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`, + customHeader: "", + customBody: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -705,6 +713,8 @@ export const DEFAULT_TRANS_APIS = { model: "claude-3-haiku-20240307", systemPrompt: `You are a professional, authentic machine translation engine.`, userPrompt: `Translate the following source text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}. Output translation directly without any additional text.\n\nSource Text: ${INPUT_PLACE_TEXT}\n\nTranslated Text:`, + customHeader: "", + customBody: "", temperature: 0, maxTokens: 1024, fetchLimit: 1, diff --git a/src/views/Options/Apis.js b/src/views/Options/Apis.js index 1ca0e05..fe7bacf 100644 --- a/src/views/Options/Apis.js +++ b/src/views/Options/Apis.js @@ -125,6 +125,8 @@ function ApiFields({ translator, api, updateApi, resetApi }) { model = "", systemPrompt = "", userPrompt = "", + customHeader = "", + customBody = "", think = false, thinkIgnore = "", fetchLimit = DEFAULT_FETCH_LIMIT, @@ -274,6 +276,26 @@ function ApiFields({ translator, api, updateApi, resetApi }) { multiline maxRows={10} /> + + )}