From c7df103950cefa8c0f709f59e0808112ec1cd23a Mon Sep 17 00:00:00 2001 From: Gabe Yuan Date: Thu, 21 Dec 2023 14:15:14 +0800 Subject: [PATCH] feat: add gemini translator --- README.en.md | 2 +- README.md | 2 +- config-overrides.js | 1 + src/apis/index.js | 5 +++++ src/config/index.js | 12 ++++++++++++ src/libs/req.js | 35 +++++++++++++++++++++++++++++++++++ src/views/Options/Apis.js | 3 ++- 7 files changed, 57 insertions(+), 3 deletions(-) diff --git a/README.en.md b/README.en.md index 9fff5cc..19afa5b 100644 --- a/README.en.md +++ b/README.en.md @@ -12,7 +12,7 @@ A simple, open source [bilingual translation extension & Greasemonkey script](ht - [x] Chrome/Edge/Firefox/Kiwi - [ ] Safari - [x] Supports multiple translation services - - [x] Google/Microsoft/DeepL/OpenAI/CloudflareAI/Baidu/Tencent + - [x] Google/Microsoft/DeepL/OpenAI/Gemini/CloudflareAI/Baidu/Tencent - [x] Custom translation interface - [x] Covers common translation scenarios - [x] Web bilingual translation diff --git a/README.md b/README.md index 0ace37a..50cc2b1 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ - [x] Chrome/Edge/Firefox/Kiwi - [ ] Safari - [x] 支持多种翻译服务 - - [x] Google/Microsoft/DeepL/OpenAI/CloudflareAI/Baidu/Tencent + - [x] Google/Microsoft/DeepL/OpenAI/Gemini/CloudflareAI/Baidu/Tencent - [x] 自定义翻译接口 - [x] 覆盖常见翻译场景 - [x] 网页双语对照翻译 diff --git a/config-overrides.js b/config-overrides.js index fc0bcbf..af43f06 100644 --- a/config-overrides.js +++ b/config-overrides.js @@ -98,6 +98,7 @@ const userscriptWebpack = (config, env) => { // @connect api.deepl.com // @connect www2.deepl.com // @connect api.openai.com +// @connect generativelanguage.googleapis.com // @connect openai.azure.com // @connect workers.dev // @connect github.io diff --git a/src/apis/index.js b/src/apis/index.js index 3c84d3f..8ccb9ad 100644 --- a/src/apis/index.js +++ b/src/apis/index.js @@ -9,6 +9,7 @@ import { OPT_TRANS_BAIDU, OPT_TRANS_TENCENT, OPT_TRANS_OPENAI, + OPT_TRANS_GEMINI, OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CUSTOMIZE, URL_CACHE_TRAN, @@ -181,6 +182,10 @@ export const apiTranslate = async ({ trText = res?.choices?.[0].message.content; isSame = text === trText; break; + case OPT_TRANS_GEMINI: + trText = res?.candidates?.[0].content.parts[0].text; + isSame = text === trText; + break; case OPT_TRANS_CLOUDFLAREAI: trText = res?.result?.translated_text; isSame = text === trText; diff --git a/src/config/index.js b/src/config/index.js index c3fc4c8..3c0315f 100644 --- a/src/config/index.js +++ b/src/config/index.js @@ -94,6 +94,7 @@ export const OPT_TRANS_DEEPLFREE = "DeepLFree"; export const OPT_TRANS_BAIDU = "Baidu"; export const OPT_TRANS_TENCENT = "Tencent"; export const OPT_TRANS_OPENAI = "OpenAI"; +export const OPT_TRANS_GEMINI = "Gemini"; export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI"; export const OPT_TRANS_CUSTOMIZE = "Custom"; export const OPT_TRANS_ALL = [ @@ -105,6 +106,7 @@ export const OPT_TRANS_ALL = [ OPT_TRANS_BAIDU, OPT_TRANS_TENCENT, OPT_TRANS_OPENAI, + OPT_TRANS_GEMINI, OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CUSTOMIZE, ]; @@ -227,6 +229,9 @@ export const OPT_LANGS_SPECIAL = { [OPT_TRANS_OPENAI]: new Map( OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]]) ), + [OPT_TRANS_GEMINI]: new Map( + OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]]) + ), [OPT_TRANS_CLOUDFLAREAI]: new Map([ ["auto", ""], ["zh-CN", "chinese"], @@ -308,6 +313,7 @@ export const DEFAULT_FETCH_INTERVAL = 100; // 默认任务间隔时间 export const PROMPT_PLACE_FROM = "{{from}}"; // 占位符 export const PROMPT_PLACE_TO = "{{to}}"; // 占位符 +export const PROMPT_PLACE_TEXT = "{{text}}"; // 占位符 export const DEFAULT_COLOR = "#209CEE"; // 默认高亮背景色/线条颜色 @@ -388,6 +394,12 @@ export const DEFAULT_TRANS_APIS = { model: "gpt-4", prompt: `You will be provided with a sentence in ${PROMPT_PLACE_FROM}, and your task is to translate it into ${PROMPT_PLACE_TO}.`, }, + [OPT_TRANS_GEMINI]: { + url: "https://generativelanguage.googleapis.com/v1/models", + key: "", + model: "gemini-pro", + prompt: `Translate the following text from ${PROMPT_PLACE_FROM} to ${PROMPT_PLACE_TO}:\n\n${PROMPT_PLACE_TEXT}`, + }, [OPT_TRANS_CLOUDFLAREAI]: { url: "https://api.cloudflare.com/client/v4/accounts/{ACCOUNT_ID}/ai/run/@cf/meta/m2m100-1.2b", key: "", diff --git a/src/libs/req.js b/src/libs/req.js index b3b5ab9..4fd0057 100644 --- a/src/libs/req.js +++ b/src/libs/req.js @@ -8,12 +8,14 @@ import { OPT_TRANS_BAIDU, OPT_TRANS_TENCENT, OPT_TRANS_OPENAI, + OPT_TRANS_GEMINI, OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CUSTOMIZE, URL_MICROSOFT_TRAN, URL_TENCENT_TRANSMART, PROMPT_PLACE_FROM, PROMPT_PLACE_TO, + PROMPT_PLACE_TEXT, } from "../config"; import { msAuth } from "./auth"; import { genDeeplFree } from "../apis/deepl"; @@ -178,6 +180,37 @@ const genOpenAI = ({ text, from, to, url, key, prompt, model }) => { return [url, init]; }; +const genGemini = ({ text, from, to, url, key, prompt, model }) => { + prompt = prompt + .replaceAll(PROMPT_PLACE_FROM, from) + .replaceAll(PROMPT_PLACE_TO, to) + .replaceAll(PROMPT_PLACE_TEXT, text); + + const data = { + contents: [ + { + // role: "user", + parts: [ + { + text: prompt, + }, + ], + }, + ], + }; + + const input = `${url}/${model}:generateContent?key=${key}`; + const init = { + headers: { + "Content-type": "application/json", + }, + method: "POST", + body: JSON.stringify(data), + }; + + return [input, init]; +}; + const genCloudflareAI = ({ text, from, to, url, key }) => { const data = { text, @@ -241,6 +274,8 @@ export const newTransReq = ({ translator, text, from, to }, apiSetting) => { return genTencent(args); case OPT_TRANS_OPENAI: return genOpenAI(args); + case OPT_TRANS_GEMINI: + return genGemini(args); case OPT_TRANS_CLOUDFLAREAI: return genCloudflareAI(args); case OPT_TRANS_CUSTOMIZE: diff --git a/src/views/Options/Apis.js b/src/views/Options/Apis.js index 4030c8c..52d982f 100644 --- a/src/views/Options/Apis.js +++ b/src/views/Options/Apis.js @@ -9,6 +9,7 @@ import { OPT_TRANS_BAIDU, OPT_TRANS_TENCENT, OPT_TRANS_OPENAI, + OPT_TRANS_GEMINI, OPT_TRANS_CUSTOMIZE, URL_KISS_PROXY, } from "../../config"; @@ -115,7 +116,7 @@ function ApiFields({ translator }) { /> )} - {translator === OPT_TRANS_OPENAI && ( + {(translator === OPT_TRANS_OPENAI || translator === OPT_TRANS_GEMINI) && ( <>