feat: added translation functionality and chinese support

This commit is contained in:
kangfenmao 2024-10-31 12:11:30 +08:00
parent fb564733e4
commit 79f6d598ab
9 changed files with 90 additions and 8 deletions

View File

@ -0,0 +1,70 @@
import { TranslationOutlined } from '@ant-design/icons'
import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { fetchTranslate } from '@renderer/services/ApiService'
import { getDefaultTopic, getDefaultTranslateAssistant } from '@renderer/services/AssistantService'
import { getUserMessage } from '@renderer/services/MessagesService'
import { Button } from 'antd'
import { FC, useState } from 'react'
import { useTranslation } from 'react-i18next'
interface Props {
text?: string
onTranslated: (translatedText: string) => void
disabled?: boolean
style?: React.CSSProperties
}
const TranslateButton: FC<Props> = ({ text, onTranslated, disabled, style }) => {
const { t } = useTranslation()
const { translateModel } = useDefaultModel()
const [isTranslating, setIsTranslating] = useState(false)
const handleTranslate = async () => {
if (!text?.trim()) return
if (!translateModel) {
window.message.error({
content: t('translate.error.not_configured'),
key: 'translate-message'
})
return
}
// 先复制原文到剪贴板
await navigator.clipboard.writeText(text)
setIsTranslating(true)
try {
const assistant = getDefaultTranslateAssistant('english', text)
const message = getUserMessage({
assistant,
topic: getDefaultTopic('default'),
type: 'text'
})
const translatedText = await fetchTranslate({ message, assistant })
onTranslated(translatedText)
} catch (error) {
console.error('Translation failed:', error)
window.message.error({
content: t('translate.error.failed'),
key: 'translate-message'
})
} finally {
setIsTranslating(false)
}
}
return (
<Button
icon={<TranslationOutlined />}
onClick={handleTranslate}
disabled={disabled || isTranslating}
loading={isTranslating}
style={style}
size="small"
/>
)
}
export default TranslateButton

View File

@ -1,9 +1,9 @@
import i18n from 'i18next' import i18n from 'i18next'
import { initReactI18next } from 'react-i18next' import { initReactI18next } from 'react-i18next'
import enUS from './en-us.json' import enUS from './locales/en-us.json'
import zhCN from './zh-cn.json' import zhCN from './locales/zh-cn.json'
import zhTW from './zh-tw.json' import zhTW from './locales/zh-tw.json'
const resources = { const resources = {
'en-US': enUS, 'en-US': enUS,

View File

@ -1 +0,0 @@

View File

@ -8,6 +8,7 @@ import ImageSize16_9 from '@renderer/assets/images/paintings/image-size-16-9.svg
import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar' import { Navbar, NavbarCenter, NavbarRight } from '@renderer/components/app/Navbar'
import { VStack } from '@renderer/components/Layout' import { VStack } from '@renderer/components/Layout'
import Scrollbar from '@renderer/components/Scrollbar' import Scrollbar from '@renderer/components/Scrollbar'
import TranslateButton from '@renderer/components/TranslateButton'
import { TEXT_TO_IMAGES_MODELS } from '@renderer/config/models' import { TEXT_TO_IMAGES_MODELS } from '@renderer/config/models'
import { useTheme } from '@renderer/context/ThemeProvider' import { useTheme } from '@renderer/context/ThemeProvider'
import { usePaintings } from '@renderer/hooks/usePaintings' import { usePaintings } from '@renderer/hooks/usePaintings'
@ -386,6 +387,12 @@ const PaintingsPage: FC = () => {
/> />
<Toolbar> <Toolbar>
<ToolbarMenu> <ToolbarMenu>
<TranslateButton
text={textareaRef.current?.resizableTextArea?.textArea?.value}
onTranslated={(translatedText) => updatePaintingState({ prompt: translatedText })}
disabled={isLoading}
style={{ marginRight: 6 }}
/>
<SendMessageButton sendMessage={onGenerate} disabled={isLoading} /> <SendMessageButton sendMessage={onGenerate} disabled={isLoading} />
</ToolbarMenu> </ToolbarMenu>
</Toolbar> </Toolbar>

View File

@ -5,7 +5,7 @@ import { isLocalAi } from '@renderer/config/env'
import db from '@renderer/databases' import db from '@renderer/databases'
import { useDefaultModel } from '@renderer/hooks/useAssistant' import { useDefaultModel } from '@renderer/hooks/useAssistant'
import { fetchTranslate } from '@renderer/services/ApiService' import { fetchTranslate } from '@renderer/services/ApiService'
import { getDefaultAssistant } from '@renderer/services/AssistantService' import { getDefaultTranslateAssistant } from '@renderer/services/AssistantService'
import { Assistant, Message } from '@renderer/types' import { Assistant, Message } from '@renderer/types'
import { runAsyncFunction, uuid } from '@renderer/utils' import { runAsyncFunction, uuid } from '@renderer/utils'
import { Button, Select, Space } from 'antd' import { Button, Select, Space } from 'antd'
@ -104,9 +104,7 @@ const TranslatePage: FC = () => {
return return
} }
const assistant: Assistant = getDefaultAssistant() const assistant: Assistant = getDefaultTranslateAssistant(targetLanguage, text)
assistant.model = translateModel
assistant.prompt = `Translate from input language to ${targetLanguage}, provide the translation result directly without any explanation, keep original format. If the target language is the same as the source language, do not translate. The text to be translated is as follows:\n\n ${text}`
const message: Message = { const message: Message = {
id: uuid(), id: uuid(),

View File

@ -19,6 +19,14 @@ export function getDefaultAssistant(): Assistant {
} }
} }
export function getDefaultTranslateAssistant(targetLanguage: string, text: string): Assistant {
const translateModel = getTranslateModel()
const assistant: Assistant = getDefaultAssistant()
assistant.model = translateModel
assistant.prompt = `Translate from input language to ${targetLanguage}, provide the translation result directly without any explanation, keep original format. If the target language is the same as the source language, do not translate. The text to be translated is as follows:\n\n ${text}`
return assistant
}
export function getDefaultAssistantSettings() { export function getDefaultAssistantSettings() {
return store.getState().assistants.defaultAssistant.settings return store.getState().assistants.defaultAssistant.settings
} }