Compare commits

...

6 Commits

Author SHA1 Message Date
Gabe Yuan
5d44ff4913 v1.8.9 2024-04-28 22:23:53 +08:00
Gabe Yuan
4c9aa66048 feat: support ollama api 2024-04-28 21:45:20 +08:00
Gabe Yuan
b6a09b99ab feat: support ollama api 2024-04-28 21:43:20 +08:00
Gabe Yuan
3a0dcb1a52 feat: add more openai translator 2024-04-28 16:58:09 +08:00
Gabe Yuan
5015503b4c feat: hide transbox header when mouseleave 2024-04-28 14:56:49 +08:00
Gabe Yuan
16423feea4 fix: update readme 2024-04-21 22:21:29 +08:00
12 changed files with 137 additions and 15 deletions

2
.env
View File

@@ -2,7 +2,7 @@ GENERATE_SOURCEMAP=false
REACT_APP_NAME=KISS Translator REACT_APP_NAME=KISS Translator
REACT_APP_NAME_CN=简约翻译 REACT_APP_NAME_CN=简约翻译
REACT_APP_VERSION=1.8.8 REACT_APP_VERSION=1.8.9
REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator REACT_APP_HOMEPAGE=https://github.com/fishjar/kiss-translator

View File

@@ -1,5 +1,7 @@
# KISS Translator # KISS Translator
English | [简体中文](README.md)
A simple, open source [bilingual translation extension & Greasemonkey script](https://github.com/fishjar/kiss-translator). A simple, open source [bilingual translation extension & Greasemonkey script](https://github.com/fishjar/kiss-translator).
[kiss-translator.webm](https://github.com/fishjar/kiss-translator/assets/1157624/f7ba8a5c-e4a8-4d5a-823a-5c5c67a0a47f) [kiss-translator.webm](https://github.com/fishjar/kiss-translator/assets/1157624/f7ba8a5c-e4a8-4d5a-823a-5c5c67a0a47f)

View File

@@ -1,5 +1,7 @@
# 简约翻译 # 简约翻译
[English](README.en.md) | 简体中文
一个简约、开源的 [双语对照翻译扩展 & 油猴脚本](https://github.com/fishjar/kiss-translator)。 一个简约、开源的 [双语对照翻译扩展 & 油猴脚本](https://github.com/fishjar/kiss-translator)。
[kiss-translator.webm](https://github.com/fishjar/kiss-translator/assets/1157624/f7ba8a5c-e4a8-4d5a-823a-5c5c67a0a47f) [kiss-translator.webm](https://github.com/fishjar/kiss-translator/assets/1157624/f7ba8a5c-e4a8-4d5a-823a-5c5c67a0a47f)

View File

@@ -112,6 +112,8 @@ const userscriptWebpack = (config, env) => {
// @connect 127.0.0.1:3000 // @connect 127.0.0.1:3000
// @connect localhost:1188 // @connect localhost:1188
// @connect 127.0.0.1:1188 // @connect 127.0.0.1:1188
// @connect localhost:11434
// @connect 127.0.0.1:11434
// @run-at document-end // @run-at document-end
// ==/UserScript== // ==/UserScript==

View File

@@ -1,7 +1,7 @@
{ {
"name": "kiss-translator", "name": "kiss-translator",
"description": "A minimalist bilingual translation Extension & Greasemonkey Script", "description": "A minimalist bilingual translation Extension & Greasemonkey Script",
"version": "1.8.8", "version": "1.8.9",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"private": true, "private": true,
"dependencies": { "dependencies": {

View File

@@ -2,7 +2,7 @@
"manifest_version": 2, "manifest_version": 2,
"name": "__MSG_app_name__", "name": "__MSG_app_name__",
"description": "__MSG_app_description__", "description": "__MSG_app_description__",
"version": "1.8.8", "version": "1.8.9",
"default_locale": "en", "default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator", "homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -2,7 +2,7 @@
"manifest_version": 3, "manifest_version": 3,
"name": "__MSG_app_name__", "name": "__MSG_app_name__",
"description": "__MSG_app_description__", "description": "__MSG_app_description__",
"version": "1.8.8", "version": "1.8.9",
"default_locale": "en", "default_locale": "en",
"author": "Gabe<yugang2002@gmail.com>", "author": "Gabe<yugang2002@gmail.com>",
"homepage_url": "https://github.com/fishjar/kiss-translator", "homepage_url": "https://github.com/fishjar/kiss-translator",

View File

@@ -10,8 +10,13 @@ import {
OPT_TRANS_BAIDU, OPT_TRANS_BAIDU,
OPT_TRANS_TENCENT, OPT_TRANS_TENCENT,
OPT_TRANS_OPENAI, OPT_TRANS_OPENAI,
OPT_TRANS_OPENAI_2,
OPT_TRANS_OPENAI_3,
OPT_TRANS_GEMINI, OPT_TRANS_GEMINI,
OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CLOUDFLAREAI,
OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -244,6 +249,8 @@ export const apiTranslate = async ({
isSame = text === trText; isSame = text === trText;
break; break;
case OPT_TRANS_OPENAI: case OPT_TRANS_OPENAI:
case OPT_TRANS_OPENAI_2:
case OPT_TRANS_OPENAI_3:
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;
@@ -257,6 +264,12 @@ export const apiTranslate = async ({
trText = res?.result?.translated_text; trText = res?.result?.translated_text;
isSame = text === trText; isSame = text === trText;
break; break;
case OPT_TRANS_OLLAMA:
case OPT_TRANS_OLLAMA_2:
case OPT_TRANS_OLLAMA_3:
trText = res?.response;
isSame = text === trText;
break;
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

@@ -9,8 +9,13 @@ import {
OPT_TRANS_BAIDU, OPT_TRANS_BAIDU,
OPT_TRANS_TENCENT, OPT_TRANS_TENCENT,
OPT_TRANS_OPENAI, OPT_TRANS_OPENAI,
OPT_TRANS_OPENAI_2,
OPT_TRANS_OPENAI_3,
OPT_TRANS_GEMINI, OPT_TRANS_GEMINI,
OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CLOUDFLAREAI,
OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -243,6 +248,32 @@ const genGemini = ({ text, from, to, url, key, prompt, model }) => {
return [input, init]; return [input, init];
}; };
const genOllama = ({ text, from, to, url, key, prompt, model }) => {
prompt = prompt
.replaceAll(INPUT_PLACE_FROM, from)
.replaceAll(INPUT_PLACE_TO, to)
.replaceAll(INPUT_PLACE_TEXT, text);
const data = {
model,
prompt,
stream: false,
};
const init = {
headers: {
"Content-type": "application/json",
},
method: "POST",
body: JSON.stringify(data),
};
if (key) {
init.headers.Authorization = `Bearer ${key}`;
}
return [url, init];
};
const genCloudflareAI = ({ text, from, to, url, key }) => { const genCloudflareAI = ({ text, from, to, url, key }) => {
const data = { const data = {
text, text,
@@ -317,8 +348,13 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
switch (translator) { switch (translator) {
case OPT_TRANS_DEEPL: case OPT_TRANS_DEEPL:
case OPT_TRANS_OPENAI: case OPT_TRANS_OPENAI:
case OPT_TRANS_OPENAI_2:
case OPT_TRANS_OPENAI_3:
case OPT_TRANS_GEMINI: case OPT_TRANS_GEMINI:
case OPT_TRANS_CLOUDFLAREAI: case OPT_TRANS_CLOUDFLAREAI:
case OPT_TRANS_OLLAMA:
case OPT_TRANS_OLLAMA_2:
case OPT_TRANS_OLLAMA_3:
case OPT_TRANS_NIUTRANS: case OPT_TRANS_NIUTRANS:
args.key = keyPick(translator, args.key, keyMap); args.key = keyPick(translator, args.key, keyMap);
break; break;
@@ -346,11 +382,17 @@ export const genTransReq = ({ translator, text, from, to }, apiSetting) => {
case OPT_TRANS_TENCENT: case OPT_TRANS_TENCENT:
return genTencent(args); return genTencent(args);
case OPT_TRANS_OPENAI: case OPT_TRANS_OPENAI:
case OPT_TRANS_OPENAI_2:
case OPT_TRANS_OPENAI_3:
return genOpenAI(args); return genOpenAI(args);
case OPT_TRANS_GEMINI: case OPT_TRANS_GEMINI:
return genGemini(args); return genGemini(args);
case OPT_TRANS_CLOUDFLAREAI: case OPT_TRANS_CLOUDFLAREAI:
return genCloudflareAI(args); return genCloudflareAI(args);
case OPT_TRANS_OLLAMA:
case OPT_TRANS_OLLAMA_2:
case OPT_TRANS_OLLAMA_3:
return genOllama(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

@@ -104,8 +104,13 @@ export const OPT_TRANS_NIUTRANS = "NiuTrans";
export const OPT_TRANS_BAIDU = "Baidu"; export const OPT_TRANS_BAIDU = "Baidu";
export const OPT_TRANS_TENCENT = "Tencent"; export const OPT_TRANS_TENCENT = "Tencent";
export const OPT_TRANS_OPENAI = "OpenAI"; export const OPT_TRANS_OPENAI = "OpenAI";
export const OPT_TRANS_OPENAI_2 = "OpenAI2";
export const OPT_TRANS_OPENAI_3 = "OpenAI3";
export const OPT_TRANS_GEMINI = "Gemini"; export const OPT_TRANS_GEMINI = "Gemini";
export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI"; export const OPT_TRANS_CLOUDFLAREAI = "CloudflareAI";
export const OPT_TRANS_OLLAMA = "Ollama";
export const OPT_TRANS_OLLAMA_2 = "Ollama2";
export const OPT_TRANS_OLLAMA_3 = "Ollama3";
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";
@@ -121,8 +126,13 @@ export const OPT_TRANS_ALL = [
OPT_TRANS_DEEPLX, OPT_TRANS_DEEPLX,
OPT_TRANS_NIUTRANS, OPT_TRANS_NIUTRANS,
OPT_TRANS_OPENAI, OPT_TRANS_OPENAI,
OPT_TRANS_OPENAI_2,
OPT_TRANS_OPENAI_3,
OPT_TRANS_GEMINI, OPT_TRANS_GEMINI,
OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CLOUDFLAREAI,
OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_CUSTOMIZE_2, OPT_TRANS_CUSTOMIZE_2,
OPT_TRANS_CUSTOMIZE_3, OPT_TRANS_CUSTOMIZE_3,
@@ -254,9 +264,24 @@ export const OPT_LANGS_SPECIAL = {
[OPT_TRANS_OPENAI]: new Map( [OPT_TRANS_OPENAI]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]]) OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
), ),
[OPT_TRANS_OPENAI_2]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
),
[OPT_TRANS_OPENAI_3]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
),
[OPT_TRANS_GEMINI]: new Map( [OPT_TRANS_GEMINI]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]]) OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
), ),
[OPT_TRANS_OLLAMA]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
),
[OPT_TRANS_OLLAMA_2]: new Map(
OPT_LANGS_FROM.map(([key, val]) => [key, val.split(" - ")[0]])
),
[OPT_TRANS_OLLAMA_3]: 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"],
@@ -464,6 +489,22 @@ const defaultCustomApi = {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
}; };
const defaultOpenaiApi = {
url: "https://api.openai.com/v1/chat/completions",
key: "",
model: "gpt-4",
prompt: `You will be provided with a sentence in ${INPUT_PLACE_FROM}, and your task is to translate it into ${INPUT_PLACE_TO}.`,
fetchLimit: 1,
fetchInterval: 500,
};
const defaultOllamaApi = {
url: "http://localhost:11434/api/generate",
key: "",
model: "llama3",
prompt: `Translate the following text from ${INPUT_PLACE_FROM} to ${INPUT_PLACE_TO}:\n\n${INPUT_PLACE_TEXT}`,
fetchLimit: 1,
fetchInterval: 500,
};
export const DEFAULT_TRANS_APIS = { export const DEFAULT_TRANS_APIS = {
[OPT_TRANS_GOOGLE]: { [OPT_TRANS_GOOGLE]: {
url: "https://translate.googleapis.com/translate_a/single", url: "https://translate.googleapis.com/translate_a/single",
@@ -507,14 +548,9 @@ export const DEFAULT_TRANS_APIS = {
fetchLimit: DEFAULT_FETCH_LIMIT, fetchLimit: DEFAULT_FETCH_LIMIT,
fetchInterval: DEFAULT_FETCH_INTERVAL, fetchInterval: DEFAULT_FETCH_INTERVAL,
}, },
[OPT_TRANS_OPENAI]: { [OPT_TRANS_OPENAI]: defaultOpenaiApi,
url: "https://api.openai.com/v1/chat/completions", [OPT_TRANS_OPENAI_2]: defaultOpenaiApi,
key: "", [OPT_TRANS_OPENAI_3]: defaultOpenaiApi,
model: "gpt-4",
prompt: `You will be provided with a sentence in ${INPUT_PLACE_FROM}, and your task is to translate it into ${INPUT_PLACE_TO}.`,
fetchLimit: 1,
fetchInterval: 500,
},
[OPT_TRANS_GEMINI]: { [OPT_TRANS_GEMINI]: {
url: "https://generativelanguage.googleapis.com/v1/models", url: "https://generativelanguage.googleapis.com/v1/models",
key: "", key: "",
@@ -529,6 +565,9 @@ export const DEFAULT_TRANS_APIS = {
fetchLimit: 1, fetchLimit: 1,
fetchInterval: 500, fetchInterval: 500,
}, },
[OPT_TRANS_OLLAMA]: defaultOllamaApi,
[OPT_TRANS_OLLAMA_2]: defaultOllamaApi,
[OPT_TRANS_OLLAMA_3]: defaultOllamaApi,
[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

@@ -11,8 +11,13 @@ import {
OPT_TRANS_BAIDU, OPT_TRANS_BAIDU,
OPT_TRANS_TENCENT, OPT_TRANS_TENCENT,
OPT_TRANS_OPENAI, OPT_TRANS_OPENAI,
OPT_TRANS_OPENAI_2,
OPT_TRANS_OPENAI_3,
OPT_TRANS_GEMINI, OPT_TRANS_GEMINI,
OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CLOUDFLAREAI,
OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3,
OPT_TRANS_CUSTOMIZE, OPT_TRANS_CUSTOMIZE,
OPT_TRANS_NIUTRANS, OPT_TRANS_NIUTRANS,
URL_KISS_PROXY, URL_KISS_PROXY,
@@ -133,7 +138,7 @@ function ApiFields({ translator }) {
}); });
}; };
const buildinTranslators = [ const builtinTranslators = [
OPT_TRANS_MICROSOFT, OPT_TRANS_MICROSOFT,
OPT_TRANS_DEEPLFREE, OPT_TRANS_DEEPLFREE,
OPT_TRANS_BAIDU, OPT_TRANS_BAIDU,
@@ -143,8 +148,13 @@ function ApiFields({ translator }) {
const mulkeysTranslators = [ const mulkeysTranslators = [
OPT_TRANS_DEEPL, OPT_TRANS_DEEPL,
OPT_TRANS_OPENAI, OPT_TRANS_OPENAI,
OPT_TRANS_OPENAI_2,
OPT_TRANS_OPENAI_3,
OPT_TRANS_GEMINI, OPT_TRANS_GEMINI,
OPT_TRANS_CLOUDFLAREAI, OPT_TRANS_CLOUDFLAREAI,
OPT_TRANS_OLLAMA,
OPT_TRANS_OLLAMA_2,
OPT_TRANS_OLLAMA_3,
OPT_TRANS_NIUTRANS, OPT_TRANS_NIUTRANS,
]; ];
@@ -164,7 +174,7 @@ function ApiFields({ translator }) {
return ( return (
<Stack spacing={3}> <Stack spacing={3}>
{!buildinTranslators.includes(translator) && ( {!builtinTranslators.includes(translator) && (
<> <>
<TextField <TextField
size="small" size="small"
@@ -191,7 +201,9 @@ function ApiFields({ translator }) {
</> </>
)} )}
{(translator === OPT_TRANS_OPENAI || translator === OPT_TRANS_GEMINI) && ( {(translator.startsWith(OPT_TRANS_OPENAI) ||
translator.startsWith(OPT_TRANS_OLLAMA) ||
translator === OPT_TRANS_GEMINI) && (
<> <>
<TextField <TextField
size="small" size="small"

View File

@@ -25,6 +25,7 @@ import DictCont from "./DictCont";
import SugCont from "./SugCont"; import SugCont from "./SugCont";
import CopyBtn from "./CopyBtn"; import CopyBtn from "./CopyBtn";
import { isValidWord } from "../../libs/utils"; import { isValidWord } from "../../libs/utils";
import { isMobile } from "../../libs/mobile";
function Header({ function Header({
setShowPopup, setShowPopup,
@@ -34,7 +35,12 @@ function Header({
setHideClickAway, setHideClickAway,
followSelection, followSelection,
setFollowSelection, setFollowSelection,
mouseHover,
}) { }) {
if (!isMobile && simpleStyle && !mouseHover) {
return;
}
return ( return (
<Box <Box
className="KT-transbox-header" className="KT-transbox-header"
@@ -263,6 +269,7 @@ export default function TranBox({
setFollowSelection, setFollowSelection,
extStyles, extStyles,
}) { }) {
const [mouseHover, setMouseHover] = useState(false);
return ( return (
<SettingProvider> <SettingProvider>
<ThemeProvider styles={extStyles}> <ThemeProvider styles={extStyles}>
@@ -280,9 +287,12 @@ export default function TranBox({
setHideClickAway={setHideClickAway} setHideClickAway={setHideClickAway}
followSelection={followSelection} followSelection={followSelection}
setFollowSelection={setFollowSelection} setFollowSelection={setFollowSelection}
mouseHover={mouseHover}
/> />
} }
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
onMouseEnter={() => setMouseHover(true)}
onMouseLeave={() => setMouseHover(false)}
> >
<TranForm <TranForm
text={text} text={text}