添加 OpenRouter 支持 (#300)

* add openrouter provider

* remove package-lock.json
This commit is contained in:
GoldenXPig
2025-08-23 11:01:54 +08:00
committed by GitHub
parent 36c1e40d64
commit 5d5e23482f
4 changed files with 87 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import {
OPT_TRANS_OLLAMA, OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2, OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3, OPT_TRANS_OLLAMA_3,
OPT_TRANS_OPENROUTER,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -316,6 +317,7 @@ export const apiTranslate = async ({
case OPT_TRANS_OPENAI_2: case OPT_TRANS_OPENAI_2:
case OPT_TRANS_OPENAI_3: case OPT_TRANS_OPENAI_3:
case OPT_TRANS_GEMINI_2: case OPT_TRANS_GEMINI_2:
case OPT_TRANS_OPENROUTER:
trText = res?.choices?.map((item) => item.message.content).join(" "); trText = res?.choices?.map((item) => item.message.content).join(" ");
isSame = text === trText; isSame = text === trText;
break; break;

View File

@@ -20,6 +20,7 @@ import {
OPT_TRANS_OLLAMA, OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2, OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3, OPT_TRANS_OLLAMA_3,
OPT_TRANS_OPENROUTER,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -465,6 +466,62 @@ const genClaude = ({
return [url, init]; return [url, init];
}; };
const genOpenRouter = ({
text,
from,
to,
url,
key,
systemPrompt,
userPrompt,
model,
temperature,
maxTokens,
customHeader,
customBody,
}) => {
systemPrompt = systemPrompt
.replaceAll(INPUT_PLACE_FROM, from)
.replaceAll(INPUT_PLACE_TO, to)
.replaceAll(INPUT_PLACE_TEXT, text);
userPrompt = userPrompt
.replaceAll(INPUT_PLACE_FROM, from)
.replaceAll(INPUT_PLACE_TO, to)
.replaceAll(INPUT_PLACE_TEXT, text);
customHeader = parseJsonObj(customHeader);
customBody = parseJsonObj(customBody);
const data = {
model,
messages: [
{
role: "system",
content: systemPrompt,
},
{
role: "user",
content: userPrompt,
},
],
temperature,
max_tokens: maxTokens,
...customBody,
};
const init = {
headers: {
"Content-type": "application/json",
Authorization: `Bearer ${key}`,
...customHeader,
},
method: "POST",
body: JSON.stringify(data),
};
return [url, init];
};
const genOllama = ({ const genOllama = ({
text, text,
from, from,
@@ -587,6 +644,7 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
case OPT_TRANS_OLLAMA: case OPT_TRANS_OLLAMA:
case OPT_TRANS_OLLAMA_2: case OPT_TRANS_OLLAMA_2:
case OPT_TRANS_OLLAMA_3: case OPT_TRANS_OLLAMA_3:
case OPT_TRANS_OPENROUTER:
case OPT_TRANS_NIUTRANS: case OPT_TRANS_NIUTRANS:
case OPT_TRANS_CUSTOMIZE: case OPT_TRANS_CUSTOMIZE:
case OPT_TRANS_CUSTOMIZE_2: case OPT_TRANS_CUSTOMIZE_2:
@@ -638,6 +696,8 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
case OPT_TRANS_OLLAMA_2: case OPT_TRANS_OLLAMA_2:
case OPT_TRANS_OLLAMA_3: case OPT_TRANS_OLLAMA_3:
return genOllama(args); return genOllama(args);
case OPT_TRANS_OPENROUTER:
return genOpenRouter(args);
case OPT_TRANS_CUSTOMIZE: case OPT_TRANS_CUSTOMIZE:
case OPT_TRANS_CUSTOMIZE_2: case OPT_TRANS_CUSTOMIZE_2:
case OPT_TRANS_CUSTOMIZE_3: case OPT_TRANS_CUSTOMIZE_3:

View File

@@ -136,6 +136,7 @@ export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI";
export const OPT_TRANS_OLLAMA = "Ollama"; export const OPT_TRANS_OLLAMA = "Ollama";
export const OPT_TRANS_OLLAMA_2 = "Ollama2"; export const OPT_TRANS_OLLAMA_2 = "Ollama2";
export const OPT_TRANS_OLLAMA_3 = "Ollama3"; export const OPT_TRANS_OLLAMA_3 = "Ollama3";
export const OPT_TRANS_OPENROUTER = "OpenRouter";
export const OPT_TRANS_CUSTOMIZE = "Custom"; export const OPT_TRANS_CUSTOMIZE = "Custom";
export const OPT_TRANS_CUSTOMIZE_2 = "Custom2"; export const OPT_TRANS_CUSTOMIZE_2 = "Custom2";
export const OPT_TRANS_CUSTOMIZE_3 = "Custom3"; export const OPT_TRANS_CUSTOMIZE_3 = "Custom3";
@@ -162,6 +163,7 @@ export const OPT_TRANS_ALL = [
OPT_TRANS_OLLAMA, OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2, OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3, OPT_TRANS_OLLAMA_3,
OPT_TRANS_OPENROUTER,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -331,6 +333,9 @@ export const OPT_LANGS_SPECIAL = {
[OPT_TRANS_OLLAMA_3]: new Map( [OPT_TRANS_OLLAMA_3]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]]) OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
), ),
[OPT_TRANS_OPENROUTER]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
),
[OPT_TRANS_CLOUDFLAREAI]: new Map([ [OPT_TRANS_CLOUDFLAREAI]: new Map([
["auto", ""], ["auto", ""],
["zh-CN", "chinese"], ["zh-CN", "chinese"],
@@ -738,6 +743,22 @@ export const DEFAULT_TRANS_APIS = {
[OPT_TRANS_OLLAMA]: defaultOllamaApi, [OPT_TRANS_OLLAMA]: defaultOllamaApi,
[OPT_TRANS_OLLAMA_2]: defaultOllamaApi, [OPT_TRANS_OLLAMA_2]: defaultOllamaApi,
[OPT_TRANS_OLLAMA_3]: defaultOllamaApi, [OPT_TRANS_OLLAMA_3]: defaultOllamaApi,
[OPT_TRANS_OPENROUTER]: {
url: "https://openrouter.ai/api/v1/chat/completions",
key: "",
model: "openai/gpt-4o",
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,
fetchInterval: 500,
apiName: OPT_TRANS_OPENROUTER,
isDisabled: false,
httpTimeout: DEFAULT_HTTP_TIMEOUT * 2,
},
[OPT_TRANS_CUSTOMIZE]: defaultCustomApi, [OPT_TRANS_CUSTOMIZE]: defaultCustomApi,
[OPT_TRANS_CUSTOMIZE_2]: defaultCustomApi, [OPT_TRANS_CUSTOMIZE_2]: defaultCustomApi,
[OPT_TRANS_CUSTOMIZE_3]: defaultCustomApi, [OPT_TRANS_CUSTOMIZE_3]: defaultCustomApi,

View File

@@ -24,6 +24,7 @@ import {
OPT_TRANS_OLLAMA, OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2, OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3, OPT_TRANS_OLLAMA_3,
OPT_TRANS_OPENROUTER,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -187,6 +188,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) {
OPT_TRANS_OLLAMA, OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2, OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3, OPT_TRANS_OLLAMA_3,
OPT_TRANS_OPENROUTER,
OPT_TRANS_NIUTRANS, OPT_TRANS_NIUTRANS,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
@@ -249,6 +251,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) {
{(translator.startsWith(OPT_TRANS_OPENAI) || {(translator.startsWith(OPT_TRANS_OPENAI) ||
translator.startsWith(OPT_TRANS_OLLAMA) || translator.startsWith(OPT_TRANS_OLLAMA) ||
translator === OPT_TRANS_CLAUDE || translator === OPT_TRANS_CLAUDE ||
translator === OPT_TRANS_OPENROUTER ||
translator.startsWith(OPT_TRANS_GEMINI)) && ( translator.startsWith(OPT_TRANS_GEMINI)) && (
<> <>
<TextField <TextField
@@ -324,6 +327,7 @@ function ApiFields({ translator, api, updateApi, resetApi }) {
{(translator.startsWith(OPT_TRANS_OPENAI) || {(translator.startsWith(OPT_TRANS_OPENAI) ||
translator === OPT_TRANS_CLAUDE || translator === OPT_TRANS_CLAUDE ||
translator === OPT_TRANS_OPENROUTER ||
translator === OPT_TRANS_GEMINI || translator === OPT_TRANS_GEMINI ||
translator === OPT_TRANS_GEMINI_2) && ( translator === OPT_TRANS_GEMINI_2) && (
<> <>