diff --git a/public/logo/minimax.svg b/public/logo/minimax.svg new file mode 100644 index 0000000000..25cedb6062 --- /dev/null +++ b/public/logo/minimax.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/i18n/locales/en_US.json b/src/i18n/locales/en_US.json index 425287eab1..471af0e38d 100644 --- a/src/i18n/locales/en_US.json +++ b/src/i18n/locales/en_US.json @@ -274,6 +274,15 @@ "prompt_description": "By customizing the Prompt, you can customize the behavior of OpenAI. $text $from $to $detect will be replaced with the text to be translated, source language, target language and detected language.", "add": "Add Prompt" }, + "minimax": { + "title": "MiniMax", + "request_path": "Request Path", + "api_key": "Api Key", + "model": "Model", + "stream": "Stream Mode", + "prompt_description": "By customizing the Prompt, you can customize the behavior of MiniMax. $text $from $to $detect will be replaced with the text to be translated, source language, target language and detected language.", + "add": "Add Prompt" + }, "geminipro": { "title": "Gemini Pro", "request_path": "Request Path", diff --git a/src/i18n/locales/zh_CN.json b/src/i18n/locales/zh_CN.json index b706528aee..d971a407b3 100644 --- a/src/i18n/locales/zh_CN.json +++ b/src/i18n/locales/zh_CN.json @@ -274,6 +274,15 @@ "prompt_description": "通过自定义Prompt自定义OpenAI行为, $text $from $to $detect 将会被替换为 待翻译文本,源语言,目标语言和检测到的语言。", "add": "添加 Prompt" }, + "minimax": { + "title": "MiniMax", + "request_path": "请求地址", + "api_key": "Api Key", + "model": "模型", + "stream": "流式输出", + "prompt_description": "通过自定义Prompt自定义MiniMax行为, $text $from $to $detect 将会被替换为 待翻译文本,源语言,目标语言和检测到的语言。", + "add": "添加 Prompt" + }, "geminipro": { "title": "Gemini Pro", "request_path": "请求地址", diff --git a/src/services/translate/index.jsx b/src/services/translate/index.jsx index 13d8d6d2a2..afac7dbfe7 100644 --- a/src/services/translate/index.jsx +++ b/src/services/translate/index.jsx @@ -2,6 +2,7 @@ import * as _deepl from './deepl'; import * as _bing from './bing'; import * as _yandex from './yandex'; import * as _openai from './openai'; +import * as _minimax from './minimax'; import * as _google from './google'; import * as _transmart from './transmart'; import * as _alibaba from './alibaba'; @@ -24,6 +25,7 @@ export const deepl = _deepl; export const bing = _bing; export const yandex = _yandex; export const openai = _openai; +export const minimax = _minimax; export const google = _google; export const transmart = _transmart; export const alibaba = _alibaba; diff --git a/src/services/translate/minimax/Config.jsx b/src/services/translate/minimax/Config.jsx new file mode 100644 index 0000000000..12ba91b3e3 --- /dev/null +++ b/src/services/translate/minimax/Config.jsx @@ -0,0 +1,290 @@ +import { Input, Button, Switch, Textarea } from '@nextui-org/react'; +import { DropdownTrigger } from '@nextui-org/react'; +import { MdDeleteOutline } from 'react-icons/md'; +import { DropdownMenu } from '@nextui-org/react'; +import { DropdownItem } from '@nextui-org/react'; +import toast, { Toaster } from 'react-hot-toast'; +import { useTranslation } from 'react-i18next'; +import { Dropdown } from '@nextui-org/react'; +import { open } from '@tauri-apps/api/shell'; +import React, { useState } from 'react'; + +import { useConfig } from '../../../hooks/useConfig'; +import { useToastStyle } from '../../../hooks'; +import { translate } from './index'; +import { Language } from './index'; +import { INSTANCE_NAME_CONFIG_KEY } from '../../../utils/service_instance'; + +// https://platform.minimax.io/docs/api-reference/text-openai-api +const availableModels = ['MiniMax-M3']; + +// MiniMax requires temperature in (0, 1]; 0 is not allowed. +export const defaultRequestArguments = JSON.stringify({ + temperature: 0.8, + top_p: 0.95, +}); + +export function Config(props) { + const { instanceKey, updateServiceList, onClose } = props; + const { t } = useTranslation(); + const [serviceConfig, setServiceConfig] = useConfig( + instanceKey, + { + [INSTANCE_NAME_CONFIG_KEY]: t('services.translate.minimax.title'), + requestPath: 'https://api.minimax.io/v1/chat/completions', + model: 'MiniMax-M3', + apiKey: '', + stream: false, + promptList: [ + { + role: 'system', + content: + '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.', + }, + { role: 'user', content: `Translate into $to:\n"""\n$text\n"""` }, + ], + requestArguments: defaultRequestArguments, + }, + { sync: false } + ); + + const [isLoading, setIsLoading] = useState(false); + + const toastStyle = useToastStyle(); + + return ( + serviceConfig !== null && ( +
{ + e.preventDefault(); + setIsLoading(true); + translate('hello', Language.auto, Language.zh_cn, { config: serviceConfig }).then( + () => { + setIsLoading(false); + setServiceConfig(serviceConfig, true); + updateServiceList(instanceKey); + onClose(); + }, + (e) => { + setIsLoading(false); + toast.error(t('config.service.test_failed') + e.toString(), { style: toastStyle }); + } + ); + }} + > + +
+ { + setServiceConfig({ + ...serviceConfig, + [INSTANCE_NAME_CONFIG_KEY]: value, + }); + }} + /> +
+
+

{t('services.help')}

+ +
+
+ { + setServiceConfig({ + ...serviceConfig, + stream: value, + }); + }} + classNames={{ + base: 'flex flex-row-reverse justify-between w-full max-w-full', + }} + > + {t('services.translate.minimax.stream')} + +
+
+ { + setServiceConfig({ + ...serviceConfig, + requestPath: value, + }); + }} + /> +
+
+ { + setServiceConfig({ + ...serviceConfig, + apiKey: value, + }); + }} + /> +
+
+

{t('services.translate.minimax.model')}

+ + + + + { + setServiceConfig({ + ...serviceConfig, + model: key, + }); + }} + > + {availableModels.map((it) => ( + {it} + ))} + + +
+ +

Prompt List

+

{t('services.translate.minimax.prompt_description')}

+ +
+ {serviceConfig.promptList && + serviceConfig.promptList.map((prompt, index) => { + return ( +
+