Skip to content

Commit

Permalink
feat: Add OpenAI
Browse files Browse the repository at this point in the history
  • Loading branch information
Pylogmon committed Aug 31, 2023
1 parent 390f65a commit 227cd34
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/services/translate/bing/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export enum Language {
de = 'de',
it = 'it',
tr = 'tr',
pt = 'pt-pt',
pt_pt = 'pt-pt',
pt_br = 'pt',
vi = 'vi',
id = 'id',
Expand Down
2 changes: 1 addition & 1 deletion src/services/translate/deepl/Config.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ export function Config(props) {
fullWidth
onPress={() => {
setIsLoading(true);
translate('hello', Language.auto, Language.zh_cn, deeplConfig).then(
translate('hello', Language.auto, Language.zh_cn, { config: deeplConfig }).then(
() => {
setIsLoading(false);
setDeeplConfig(deeplConfig, true);
Expand Down
18 changes: 11 additions & 7 deletions src/services/translate/deepl/index.jsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
import { fetch, Body } from '@tauri-apps/api/http';
import { store } from '../../../utils/store';

export async function translate(text, from, to, config = null) {
let deeplConfig = await store.get('deepl');
if (config !== null) {
export async function translate(text, from, to, options = {}) {
const { config } = options;

let deeplConfig = (await store.get('deepl')) ?? {};
if (config !== undefined) {
deeplConfig = config;
}

if (deeplConfig.type === 'free') {
const serviceType = deeplConfig['type'];
if (serviceType === 'free') {
return translate_by_free(text, from, to);
} else if (deeplConfig.type === 'api') {
} else if (serviceType === 'api') {
return translate_by_key(text, from, to, deeplConfig.authKey);
} else {
} else if (serviceType === 'deeplx') {
return translate_by_deeplx(text, from, to, deeplConfig.customUrl);
} else {
return translate_by_free(text, from, to);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/services/translate/google/info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export enum Language {
de = 'de',
it = 'it',
tr = 'tr',
pt = 'pt',
pt_pt = 'pt',
pt_br = 'pt',
vi = 'vi',
id = 'id',
Expand Down
2 changes: 1 addition & 1 deletion src/services/translate/openai/Config.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ export function Config(props) {
color='primary'
onPress={() => {
setIsLoading(true);
translate('hello', Language.auto, Language.zh_cn, openaiConfig).then(
translate('hello', Language.auto, Language.zh_cn, { config: openaiConfig }).then(
() => {
setIsLoading(false);
setOpenaiConfig(openaiConfig, true);
Expand Down
124 changes: 121 additions & 3 deletions src/services/translate/openai/index.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,131 @@
import { fetch, Body } from '@tauri-apps/api/http';
import { store } from '../../../utils/store';

export async function translate(text, from, to, config = null) {
export async function translate(text, from, to, options = {}) {
const { config, setResult } = options;

let openaiConfig = await store.get('openai');
if (config !== null) {
if (config !== undefined) {
openaiConfig = config;
}
let { service, requestPath, model, apiKey, stream } = openaiConfig;

return '';
if (!/https?:\/\/.+/.test(requestPath)) {
requestPath = `https://${requestPath}`;
}
const systemPrompt =
'You are a professional translation engine, please translate the text into a colloquial, professional, elegant and fluent content, without the style of machine translation. You must only translate the text content, never interpret it.';
const userPrompt = `Translate into ${to}:\n"""\n${text}\n"""`;
const headers =
service === 'openai'
? {
'Content-Type': 'application/json',
Authorization: `Bearer ${apiKey}`,
}
: {
'Content-Type': 'application/json',
'api-key': apiKey,
};
let body = {
temperature: 0,
stream: stream,
top_p: 1,
frequency_penalty: 1,
presence_penalty: 1,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
};
if (service === 'openai') {
body['model'] = model;
}
if (stream) {
const res = await window.fetch(requestPath, {
method: 'POST',
headers: headers,
body: JSON.stringify(body),
});
if (res.ok) {
let target = '';
const reader = res.body.getReader();
try {
let temp = '';
while (true) {
const { done, value } = await reader.read();
if (done) {
setResult(target.trim());
return target.trim();
}
const str = new TextDecoder().decode(value);
let datas = str.split('data:');
for (let data of datas) {
if (data.trim() !== '' && data.trim() !== '[DONE]') {
try {
if (temp !== '') {
data = temp + data.trim();
let result = JSON.parse(data.trim());
if (result.choices[0].delta.content) {
target += result.choices[0].delta.content;
if (setResult) {
setResult(target + '_');
} else {
return '[STREAM]';
}
}
temp = '';
} else {
let result = JSON.parse(data.trim());
if (result.choices[0].delta.content) {
target += result.choices[0].delta.content;
if (setResult) {
setResult(target + '_');
} else {
return '[STREAM]';
}
}
}
} catch {
temp = data.trim();
}
}
}
}
} finally {
reader.releaseLock();
}
} else {
throw `Http Request Error\nHttp Status: ${res.status}\n${JSON.stringify(res.data)}`;
}
} else {
let res = await fetch(requestPath, {
method: 'POST',
headers: headers,
body: Body.json(body),
});
if (res.ok) {
let result = res.data;
const { choices } = result;
if (choices) {
let target = choices[0].message.content.trim();
if (target) {
if (target.startsWith('"')) {
target = target.slice(1);
}
if (target.endsWith('"')) {
target = target.slice(0, -1);
}
return target.trim();
} else {
throw JSON.stringify(choices);
}
} else {
throw JSON.stringify(result);
}
} else {
throw `Http Request Error\nHttp Status: ${res.status}\n${JSON.stringify(res.data)}`;
}
}
}

export * from './Config';
Expand Down
14 changes: 13 additions & 1 deletion src/window/Translate/components/TargetArea/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import { sourceLanguageAtom, targetLanguageAtom } from '../LanguageArea';
import { sourceTextAtom, detectLanguageAtom } from '../SourceArea';
import { store } from '../../../../utils/store';

let translateID = [];

export default function TargetArea(props) {
const { name, index, ...drag } = props;
const [result, setResult] = useState('');
Expand All @@ -34,20 +36,30 @@ export default function TargetArea(props) {
}, [sourceText, targetLanguage, sourceLanguage]);

const translate = async () => {
let id = nanoid();
translateID[index] = id;
if (sourceLanguage in LanguageEnum && targetLanguage in LanguageEnum) {
let newTargetLanguage = targetLanguage;
if (sourceLanguage === 'auto' && targetLanguage === detectLanguage) {
newTargetLanguage = await store.get('translate_second_language');
}
setIsLoading(true);
buildinServices[name]
.translate(sourceText, LanguageEnum[sourceLanguage], LanguageEnum[newTargetLanguage])
.translate(sourceText, LanguageEnum[sourceLanguage], LanguageEnum[newTargetLanguage], {
setResult: (v) => {
if (translateID[index] !== id) return;
setResult(v);
setIsLoading(false);
},
})
.then(
(v) => {
if (translateID[index] !== id) return;
setResult(v);
setIsLoading(false);
},
(e) => {
if (translateID[index] !== id) return;
setError(e.toString());
setIsLoading(false);
}
Expand Down

0 comments on commit 227cd34

Please sign in to comment.