diff --git a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts index 228398fea7..1665c580de 100644 --- a/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts +++ b/src/renderer/src/aiCore/clients/openai/OpenAIApiClient.ts @@ -46,6 +46,7 @@ import { EFFORT_RATIO, FileTypes, isSystemProvider, + isTranslateAssistant, MCPCallToolResponse, MCPTool, MCPToolResponse, @@ -54,7 +55,6 @@ import { Provider, SystemProviderIds, ToolCallResponse, - TranslateAssistant, WebSearchSource } from '@renderer/types' import { ChunkType, TextStartChunk, ThinkingStartChunk } from '@renderer/types/chunk' @@ -569,13 +569,18 @@ export class OpenAIAPIClient extends OpenAIBaseClient< const extra_body: Record = {} if (isQwenMTModel(model)) { - const targetLanguage = (assistant as TranslateAssistant).targetLanguage - extra_body.translation_options = { - source_lang: 'auto', - target_lang: mapLanguageToQwenMTModel(targetLanguage!) - } - if (!extra_body.translation_options.target_lang) { - throw new Error(t('translate.error.not_supported', { language: targetLanguage?.value })) + if (isTranslateAssistant(assistant)) { + const targetLanguage = assistant.targetLanguage + const translationOptions = { + source_lang: 'auto', + target_lang: mapLanguageToQwenMTModel(targetLanguage) + } as const + if (!translationOptions.target_lang) { + throw new Error(t('translate.error.not_supported', { language: targetLanguage.value })) + } + extra_body.translation_options = translationOptions + } else { + throw new Error(t('translate.error.chat_qwen_mt')) } } diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 5a29fb31a2..385971a816 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -3785,6 +3785,7 @@ }, "empty": "Translation content is empty", "error": { + "chat_qwen_mt": "Qwen MT model cannot be used in chat. Please go to the translation page.", "detect": { "qwen_mt": "QwenMT model cannot be used for language detection", "unknown": "Unknown language detected", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index fa70851685..9ed6cfc726 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -3785,6 +3785,7 @@ }, "empty": "翻訳内容が空です", "error": { + "chat_qwen_mt": "Qwen MT モデルは対話で使用できません。翻訳ページに移動してください", "detect": { "qwen_mt": "QwenMTモデルは言語検出に使用できません", "unknown": "検出された言語は不明です", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 6bb1df6e00..2c5328b2a9 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -3785,6 +3785,7 @@ }, "empty": "Содержимое перевода пусто", "error": { + "chat_qwen_mt": "Модель Qwen MT недоступна для использования в диалоге, перейдите на страницу перевода", "detect": { "qwen_mt": "Модель QwenMT не может использоваться для определения языка", "unknown": "Обнаружен неизвестный язык", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 53ee849746..1f0aa33dd7 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -3785,6 +3785,7 @@ }, "empty": "翻译内容为空", "error": { + "chat_qwen_mt": "Qwen MT 模型不可在对话中使用,请转至翻译页面", "detect": { "qwen_mt": "QwenMT模型不能用于语言检测", "unknown": "检测到未知语言", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 5414005224..3cbae8b2fb 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -3785,6 +3785,7 @@ }, "empty": "翻譯內容為空", "error": { + "chat_qwen_mt": "Qwen MT 模型不可在对话中使用,請轉至翻譯頁面", "detect": { "qwen_mt": "QwenMT模型不能用於語言檢測", "unknown": "檢測到未知語言", diff --git a/src/renderer/src/i18n/translate/el-gr.json b/src/renderer/src/i18n/translate/el-gr.json index 673b449c6d..ff4e4d7331 100644 --- a/src/renderer/src/i18n/translate/el-gr.json +++ b/src/renderer/src/i18n/translate/el-gr.json @@ -3785,6 +3785,7 @@ }, "empty": "Το μεταφρασμένο κείμενο είναι κενό", "error": { + "chat_qwen_mt": "Τα μοντέλα Qwen MT δεν είναι διαθέσιμα για χρήση σε διαλόγους, παρακαλώ μεταβείτε στη σελίδα μετάφρασης", "detect": { "qwen_mt": "Το μοντέλο QwenMT δεν μπορεί να χρησιμοποιηθεί για εντοπισμό γλώσσας", "unknown": "Ανιχνεύθηκε άγνωστη γλώσσα", diff --git a/src/renderer/src/i18n/translate/es-es.json b/src/renderer/src/i18n/translate/es-es.json index 3be80c67b0..6e0f92adf2 100644 --- a/src/renderer/src/i18n/translate/es-es.json +++ b/src/renderer/src/i18n/translate/es-es.json @@ -3785,6 +3785,7 @@ }, "empty": "El contenido de traducción está vacío", "error": { + "chat_qwen_mt": "El modelo Qwen MT no está disponible para uso en conversaciones, por favor vaya a la página de traducción.", "detect": { "qwen_mt": "El modelo QwenMT no se puede utilizar para la detección de idiomas", "unknown": "Se detectó un idioma desconocido", diff --git a/src/renderer/src/i18n/translate/fr-fr.json b/src/renderer/src/i18n/translate/fr-fr.json index 2cf7b9938f..64969cb6cc 100644 --- a/src/renderer/src/i18n/translate/fr-fr.json +++ b/src/renderer/src/i18n/translate/fr-fr.json @@ -3785,6 +3785,7 @@ }, "empty": "Le contenu à traduire est vide", "error": { + "chat_qwen_mt": "Les modèles Qwen MT ne peuvent pas être utilisés dans les conversations, veuillez vous rendre sur la page de traduction.", "detect": { "qwen_mt": "Le modèle QwenMT ne peut pas être utilisé pour la détection de langues", "unknown": "Langue inconnue détectée", diff --git a/src/renderer/src/i18n/translate/pt-pt.json b/src/renderer/src/i18n/translate/pt-pt.json index 4c0989ef7c..d4fbe979b2 100644 --- a/src/renderer/src/i18n/translate/pt-pt.json +++ b/src/renderer/src/i18n/translate/pt-pt.json @@ -3785,6 +3785,7 @@ }, "empty": "O conteúdo de tradução está vazio", "error": { + "chat_qwen_mt": "Modelos Qwen MT não estão disponíveis para uso em conversas. Por favor, vá para a página de tradução.", "detect": { "qwen_mt": "O modelo QwenMT não pode ser usado para detecção de idioma", "unknown": "Idioma desconhecido detectado", diff --git a/src/renderer/src/services/AssistantService.ts b/src/renderer/src/services/AssistantService.ts index f11dba8ec4..fe4c040d0d 100644 --- a/src/renderer/src/services/AssistantService.ts +++ b/src/renderer/src/services/AssistantService.ts @@ -6,6 +6,7 @@ import { MAX_CONTEXT_COUNT, UNLIMITED_CONTEXT_COUNT } from '@renderer/config/constant' +import { isQwenMTModel } from '@renderer/config/models' import { UNKNOWN } from '@renderer/config/translate' import i18n from '@renderer/i18n' import store from '@renderer/store' @@ -52,11 +53,10 @@ export function getDefaultAssistant(): Assistant { } export function getDefaultTranslateAssistant(targetLanguage: TranslateLanguage, text: string): TranslateAssistant { - const translateModel = getTranslateModel() + const model = getTranslateModel() const assistant: Assistant = getDefaultAssistant() - assistant.model = translateModel - if (!assistant.model) { + if (!model) { logger.error('No translate model') throw new Error(i18n.t('translate.error.not_configured')) } @@ -66,15 +66,32 @@ export function getDefaultTranslateAssistant(targetLanguage: TranslateLanguage, throw new Error('Unknown target language') } - assistant.settings = { + const settings = { temperature: 0.7 } - assistant.prompt = store - .getState() - .settings.translateModelPrompt.replaceAll('{{target_language}}', targetLanguage.value) - .replaceAll('{{text}}', text) - return { ...assistant, targetLanguage } + let prompt: string + let content: string + if (isQwenMTModel(model)) { + content = text + prompt = '' + } else { + content = 'follow system instruction' + prompt = store + .getState() + .settings.translateModelPrompt.replaceAll('{{target_language}}', targetLanguage.value) + .replaceAll('{{text}}', text) + } + + const translateAssistant = { + ...assistant, + model, + settings, + prompt, + targetLanguage, + content + } satisfies TranslateAssistant + return translateAssistant } export function getDefaultAssistantSettings() { diff --git a/src/renderer/src/services/TranslateService.ts b/src/renderer/src/services/TranslateService.ts index 1b892bb326..5d09933d46 100644 --- a/src/renderer/src/services/TranslateService.ts +++ b/src/renderer/src/services/TranslateService.ts @@ -15,12 +15,7 @@ import { formatErrorMessage, isAbortError } from '@renderer/utils/error' import { t } from 'i18next' import { hasApiKey } from './ApiService' -import { - getDefaultModel, - getDefaultTranslateAssistant, - getProviderByModel, - getTranslateModel -} from './AssistantService' +import { getDefaultTranslateAssistant, getProviderByModel } from './AssistantService' const logger = loggerService.withContext('TranslateService') interface FetchTranslateProps { @@ -30,11 +25,7 @@ interface FetchTranslateProps { } async function fetchTranslate({ assistant, onResponse, abortKey }: FetchTranslateProps) { - const model = getTranslateModel() || assistant.model || getDefaultModel() - - if (!model) { - throw new Error(t('translate.error.not_configured')) - } + const model = assistant.model const provider = getProviderByModel(model) @@ -58,8 +49,8 @@ async function fetchTranslate({ assistant, onResponse, abortKey }: FetchTranslat const params: CompletionsParams = { callType: 'translate', - messages: 'do', - assistant: { ...assistant, model }, + messages: assistant.content, + assistant, streamOutput: stream, enableReasoning, onResponse, diff --git a/src/renderer/src/types/index.ts b/src/renderer/src/types/index.ts index 515411edbb..0d0c1ef4bc 100644 --- a/src/renderer/src/types/index.ts +++ b/src/renderer/src/types/index.ts @@ -35,10 +35,19 @@ export type Assistant = { regularPhrases?: QuickPhrase[] // Added for regular phrase tags?: string[] // 助手标签 enableMemory?: boolean + // for translate. 更好的做法是定义base assistant,把 Assistant 作为多种不同定义 assistant 的联合类型,但重构代价太大 + content?: string + targetLanguage?: TranslateLanguage } export type TranslateAssistant = Assistant & { - targetLanguage?: TranslateLanguage + model: Model + content: string + targetLanguage: TranslateLanguage +} + +export const isTranslateAssistant = (assistant: Assistant): assistant is TranslateAssistant => { + return (assistant.model && assistant.targetLanguage && typeof assistant.content === 'string') !== undefined } export type AssistantsSortType = 'tags' | 'list'