From be6e34ba5230be7bdc5265e31a23447bcf09c304 Mon Sep 17 00:00:00 2001 From: FlyLoongZ <60963681+FlyLoongZ@users.noreply.github.com> Date: Mon, 11 Aug 2025 12:12:03 +0800 Subject: [PATCH 1/3] feat: Add AI API Custom Params --- src/apis/trans.js | 20 ++++++++++++++++++++ src/config/i18n.js | 8 ++++++++ src/config/index.js | 5 +++++ src/views/Options/Apis.js | 11 +++++++++++ 4 files changed, 44 insertions(+) diff --git a/src/apis/trans.js b/src/apis/trans.js index 0c73902..62b70b9 100644 --- a/src/apis/trans.js +++ b/src/apis/trans.js @@ -240,6 +240,7 @@ const genOpenAI = ({ model, temperature, maxTokens, + apiCustomParams, }) => { // 兼容历史上作为systemPrompt的prompt,如果prompt中不包含带翻译文本,则添加文本到prompt末尾 // if (!prompt.includes(INPUT_PLACE_TEXT)) { @@ -254,6 +255,8 @@ const genOpenAI = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + const data = { model, messages: [ @@ -268,6 +271,7 @@ const genOpenAI = ({ ], temperature, max_completion_tokens: maxTokens, + ...apiCustomParams, }; const init = { @@ -294,6 +298,7 @@ const genGemini = ({ model, temperature, maxTokens, + apiCustomParams, }) => { url = url .replaceAll(INPUT_PLACE_MODEL, model) @@ -307,6 +312,8 @@ const genGemini = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + const data = { system_instruction: { parts: { @@ -325,6 +332,7 @@ const genGemini = ({ // topP: 0.8, // topK: 10, }, + ...apiCustomParams, }; const init = { @@ -349,6 +357,7 @@ const genGemini2 = ({ model, temperature, maxTokens, + apiCustomParams, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -359,6 +368,8 @@ const genGemini2 = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + const data = { model, messages: [ @@ -373,6 +384,7 @@ const genGemini2 = ({ ], temperature, max_tokens: maxTokens, + ...apiCustomParams, }; const init = { @@ -398,6 +410,7 @@ const genClaude = ({ model, temperature, maxTokens, + apiCustomParams, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -408,6 +421,8 @@ const genClaude = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + const data = { model, system: systemPrompt, @@ -419,6 +434,7 @@ const genClaude = ({ ], temperature, max_tokens: maxTokens, + ...apiCustomParams, }; const init = { @@ -444,6 +460,7 @@ const genOllama = ({ systemPrompt, userPrompt, model, + apiCustomParams, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -454,12 +471,15 @@ const genOllama = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + const data = { model, system: systemPrompt, prompt: userPrompt, think: think, stream: false, + ...apiCustomParams, }; const init = { diff --git a/src/config/i18n.js b/src/config/i18n.js index cb7de61..487e1c7 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -228,6 +228,14 @@ export const I18N = { zh: `请求超时时间 (5000-30000ms)`, en: `Request Timeout Time (5000-30000ms)`, }, + api_custom_params: { + zh: `API自定义参数`, + en: `API Custom Params`, + }, + api_custom_params_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..1273ebc 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -563,6 +563,7 @@ 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:`, + apiCustomParams: "", temperature: 0, maxTokens: 256, fetchLimit: 1, @@ -577,6 +578,7 @@ 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:`, + apiCustomParams: "", think: false, thinkIgnore: `qwen3,deepseek-r1`, fetchLimit: 1, @@ -677,6 +679,7 @@ 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:`, + apiCustomParams: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -691,6 +694,7 @@ 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:`, + apiCustomParams: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -705,6 +709,7 @@ 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:`, + apiCustomParams: "", temperature: 0, maxTokens: 1024, fetchLimit: 1, diff --git a/src/views/Options/Apis.js b/src/views/Options/Apis.js index 1ca0e05..1bc3b88 100644 --- a/src/views/Options/Apis.js +++ b/src/views/Options/Apis.js @@ -125,6 +125,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) { model = "", systemPrompt = "", userPrompt = "", + apiCustomParams = "", think = false, thinkIgnore = "", fetchLimit = DEFAULT_FETCH_LIMIT, @@ -274,6 +275,16 @@ function ApiFields({ translator, api, updateApi, resetApi }) { multiline maxRows={10} /> + )} From e1f902c203bc3ef8bcdd8b91469e220552389eaa Mon Sep 17 00:00:00 2001 From: FlyLoongZ <60963681+FlyLoongZ@users.noreply.github.com> Date: Mon, 11 Aug 2025 16:03:30 +0800 Subject: [PATCH 2/3] Rename apiCustomParams to customBody --- src/apis/trans.js | 30 +++++++++++++++--------------- src/config/i18n.js | 6 +++--- src/config/index.js | 10 +++++----- src/views/Options/Apis.js | 6 +++--- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/apis/trans.js b/src/apis/trans.js index 62b70b9..ba5b4f8 100644 --- a/src/apis/trans.js +++ b/src/apis/trans.js @@ -240,7 +240,7 @@ const genOpenAI = ({ model, temperature, maxTokens, - apiCustomParams, + customBody, }) => { // 兼容历史上作为systemPrompt的prompt,如果prompt中不包含带翻译文本,则添加文本到prompt末尾 // if (!prompt.includes(INPUT_PLACE_TEXT)) { @@ -255,7 +255,7 @@ const genOpenAI = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); - apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + customBody = JSON.parse("{" + customBody + "}"); const data = { model, @@ -271,7 +271,7 @@ const genOpenAI = ({ ], temperature, max_completion_tokens: maxTokens, - ...apiCustomParams, + ...customBody, }; const init = { @@ -298,7 +298,7 @@ const genGemini = ({ model, temperature, maxTokens, - apiCustomParams, + customBody, }) => { url = url .replaceAll(INPUT_PLACE_MODEL, model) @@ -312,7 +312,7 @@ const genGemini = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); - apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + customBody = JSON.parse("{" + customBody + "}"); const data = { system_instruction: { @@ -332,7 +332,7 @@ const genGemini = ({ // topP: 0.8, // topK: 10, }, - ...apiCustomParams, + ...customBody, }; const init = { @@ -357,7 +357,7 @@ const genGemini2 = ({ model, temperature, maxTokens, - apiCustomParams, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -368,7 +368,7 @@ const genGemini2 = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); - apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + customBody = JSON.parse("{" + customBody + "}"); const data = { model, @@ -384,7 +384,7 @@ const genGemini2 = ({ ], temperature, max_tokens: maxTokens, - ...apiCustomParams, + ...customBody, }; const init = { @@ -410,7 +410,7 @@ const genClaude = ({ model, temperature, maxTokens, - apiCustomParams, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -421,7 +421,7 @@ const genClaude = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); - apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + customBody = JSON.parse("{" + customBody + "}"); const data = { model, @@ -434,7 +434,7 @@ const genClaude = ({ ], temperature, max_tokens: maxTokens, - ...apiCustomParams, + ...customBody, }; const init = { @@ -460,7 +460,7 @@ const genOllama = ({ systemPrompt, userPrompt, model, - apiCustomParams, + customBody, }) => { systemPrompt = systemPrompt .replaceAll(INPUT_PLACE_FROM, from) @@ -471,7 +471,7 @@ const genOllama = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); - apiCustomParams = JSON.parse("{" + apiCustomParams + "}"); + customBody = JSON.parse("{" + customBody + "}"); const data = { model, @@ -479,7 +479,7 @@ const genOllama = ({ prompt: userPrompt, think: think, stream: false, - ...apiCustomParams, + ...customBody, }; const init = { diff --git a/src/config/i18n.js b/src/config/i18n.js index 487e1c7..fb05652 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -228,11 +228,11 @@ export const I18N = { zh: `请求超时时间 (5000-30000ms)`, en: `Request Timeout Time (5000-30000ms)`, }, - api_custom_params: { - zh: `API自定义参数`, + custom_body: { + zh: `自定义Body参数`, en: `API Custom Params`, }, - api_custom_params_help: { + custom_body_help: { zh: `使用JSON格式,例如 "top_p": 0.7`, en: `Use JSON format, for example "top_p": 0.7`, }, diff --git a/src/config/index.js b/src/config/index.js index 1273ebc..184535c 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -563,7 +563,7 @@ 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:`, - apiCustomParams: "", + customBody: "", temperature: 0, maxTokens: 256, fetchLimit: 1, @@ -578,7 +578,7 @@ 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:`, - apiCustomParams: "", + customBody: "", think: false, thinkIgnore: `qwen3,deepseek-r1`, fetchLimit: 1, @@ -679,7 +679,7 @@ 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:`, - apiCustomParams: "", + customBody: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -694,7 +694,7 @@ 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:`, - apiCustomParams: "", + customBody: "", temperature: 0, maxTokens: 2048, fetchLimit: 1, @@ -709,7 +709,7 @@ 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:`, - apiCustomParams: "", + customBody: "", temperature: 0, maxTokens: 1024, fetchLimit: 1, diff --git a/src/views/Options/Apis.js b/src/views/Options/Apis.js index 1bc3b88..f64ebaf 100644 --- a/src/views/Options/Apis.js +++ b/src/views/Options/Apis.js @@ -125,7 +125,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) { model = "", systemPrompt = "", userPrompt = "", - apiCustomParams = "", + customBody = "", think = false, thinkIgnore = "", fetchLimit = DEFAULT_FETCH_LIMIT, @@ -278,8 +278,8 @@ function ApiFields({ translator, api, updateApi, resetApi }) { Date: Mon, 11 Aug 2025 16:28:23 +0800 Subject: [PATCH 3/3] feat: Add AI API Custom Header --- src/apis/trans.js | 15 +++++++++++++++ src/config/i18n.js | 10 +++++++++- src/config/index.js | 5 +++++ src/views/Options/Apis.js | 15 +++++++++++++-- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/apis/trans.js b/src/apis/trans.js index ba5b4f8..575dc3e 100644 --- a/src/apis/trans.js +++ b/src/apis/trans.js @@ -240,6 +240,7 @@ const genOpenAI = ({ model, temperature, maxTokens, + customHeader, customBody, }) => { // 兼容历史上作为systemPrompt的prompt,如果prompt中不包含带翻译文本,则添加文本到prompt末尾 @@ -255,6 +256,7 @@ const genOpenAI = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); customBody = JSON.parse("{" + customBody + "}"); const data = { @@ -279,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), @@ -298,6 +301,7 @@ const genGemini = ({ model, temperature, maxTokens, + customHeader, customBody, }) => { url = url @@ -312,6 +316,7 @@ const genGemini = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); customBody = JSON.parse("{" + customBody + "}"); const data = { @@ -338,6 +343,7 @@ const genGemini = ({ const init = { headers: { "Content-type": "application/json", + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -357,6 +363,7 @@ const genGemini2 = ({ model, temperature, maxTokens, + customHeader, customBody, }) => { systemPrompt = systemPrompt @@ -368,6 +375,7 @@ const genGemini2 = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); customBody = JSON.parse("{" + customBody + "}"); const data = { @@ -391,6 +399,7 @@ const genGemini2 = ({ headers: { "Content-type": "application/json", Authorization: `Bearer ${key}`, + ...customHeader, }, method: "POST", body: JSON.stringify(data), @@ -410,6 +419,7 @@ const genClaude = ({ model, temperature, maxTokens, + customHeader, customBody, }) => { systemPrompt = systemPrompt @@ -421,6 +431,7 @@ const genClaude = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); customBody = JSON.parse("{" + customBody + "}"); const data = { @@ -442,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), @@ -460,6 +472,7 @@ const genOllama = ({ systemPrompt, userPrompt, model, + customHeader, customBody, }) => { systemPrompt = systemPrompt @@ -471,6 +484,7 @@ const genOllama = ({ .replaceAll(INPUT_PLACE_TO, to) .replaceAll(INPUT_PLACE_TEXT, text); + customHeader = JSON.parse("{" + customHeader + "}"); customBody = JSON.parse("{" + customBody + "}"); const data = { @@ -485,6 +499,7 @@ const genOllama = ({ 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 fb05652..805e37d 100644 --- a/src/config/i18n.js +++ b/src/config/i18n.js @@ -228,9 +228,17 @@ 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: `API Custom Params`, + en: `Custom Body Params`, }, custom_body_help: { zh: `使用JSON格式,例如 "top_p": 0.7`, diff --git a/src/config/index.js b/src/config/index.js index 184535c..0427070 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -563,6 +563,7 @@ 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, @@ -578,6 +579,7 @@ 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`, @@ -679,6 +681,7 @@ 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, @@ -694,6 +697,7 @@ 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, @@ -709,6 +713,7 @@ 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, diff --git a/src/views/Options/Apis.js b/src/views/Options/Apis.js index f64ebaf..fe7bacf 100644 --- a/src/views/Options/Apis.js +++ b/src/views/Options/Apis.js @@ -125,6 +125,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) { model = "", systemPrompt = "", userPrompt = "", + customHeader = "", customBody = "", think = false, thinkIgnore = "", @@ -277,13 +278,23 @@ function ApiFields({ translator, api, updateApi, resetApi }) { /> + )}