Skip to content

Commit

Permalink
feat: implement automatic text translation functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
kangfenmao committed Dec 3, 2024
1 parent a9d4a08 commit f5d37a4
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 29 deletions.
13 changes: 8 additions & 5 deletions electron-builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,11 @@ electronDownload:
afterSign: scripts/notarize.js
releaseInfo:
releaseNotes: |
支持清除应用缓存
支持编辑翻译模型提示词
支持使用搜索内容快速创建助手
支持编辑模型是否为视觉模型
界面样式优化和错误修复
输入内容支持快速翻译成英文
输出内容支持翻译成其他语言
快速敲击3次空格翻译
支持自定义快捷键
支持关闭对话自动重命名
修复 Gemini 自定义域名不生效问题
画图支持生成 Seed 种子词
修复 Markdown 渲染错误导致应用崩溃
45 changes: 24 additions & 21 deletions src/renderer/src/pages/home/Messages/MessageMenubar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,27 +69,30 @@ const MessageMenubar: FC<Props> = (props) => {
editedText && onEditMessage?.({ ...message, content: editedText })
}, [message, onEditMessage])

const handleTranslate = async (language: string) => {
if (isTranslating) return

onEditMessage?.({ ...message, translatedContent: t('translate.processing') })

setIsTranslating(true)

try {
const translatedText = await translateText(message.content, language)
onEditMessage?.({ ...message, translatedContent: translatedText })
} catch (error) {
console.error('Translation failed:', error)
window.message.error({
content: t('translate.error.failed'),
key: 'translate-message'
})
onEditMessage?.({ ...message, translatedContent: undefined })
} finally {
setIsTranslating(false)
}
}
const handleTranslate = useCallback(
async (language: string) => {
if (isTranslating) return

onEditMessage?.({ ...message, translatedContent: t('translate.processing') })

setIsTranslating(true)

try {
const translatedText = await translateText(message.content, language)
onEditMessage?.({ ...message, translatedContent: translatedText })
} catch (error) {
console.error('Translation failed:', error)
window.message.error({
content: t('translate.error.failed'),
key: 'translate-message'
})
onEditMessage?.({ ...message, translatedContent: undefined })
} finally {
setIsTranslating(false)
}
},
[isTranslating, message, onEditMessage, t]
)

const dropdownItems = useMemo(
() => [
Expand Down
63 changes: 60 additions & 3 deletions src/renderer/src/pages/paintings/PaintingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,19 @@ import { useTheme } from '@renderer/context/ThemeProvider'
import { usePaintings } from '@renderer/hooks/usePaintings'
import { useAllProviders } from '@renderer/hooks/useProvider'
import { useRuntime } from '@renderer/hooks/useRuntime'
import { useSettings } from '@renderer/hooks/useSettings'
import AiProvider from '@renderer/providers/AiProvider'
import { getProviderByModel } from '@renderer/services/AssistantService'
import FileManager from '@renderer/services/FileManager'
import { translateText } from '@renderer/services/TranslateService'
import { useAppDispatch } from '@renderer/store'
import { DEFAULT_PAINTING } from '@renderer/store/paintings'
import { setGenerating } from '@renderer/store/runtime'
import { FileType, Painting } from '@renderer/types'
import { getErrorMessage } from '@renderer/utils'
import { Button, Input, InputNumber, Radio, Select, Slider, Tooltip } from 'antd'
import TextArea from 'antd/es/input/TextArea'
import { FC, useRef, useState } from 'react'
import { FC, useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'

Expand Down Expand Up @@ -232,6 +234,59 @@ const PaintingsPage: FC = () => {
setCurrentImageIndex(0)
}

const { autoTranslateWithSpace } = useSettings()
const [spaceClickCount, setSpaceClickCount] = useState(0)
const [isTranslating, setIsTranslating] = useState(false)
const spaceClickTimer = useRef<NodeJS.Timeout>()

const translate = async () => {
if (isTranslating) {
return
}

if (!painting.prompt) {
return
}

try {
setIsTranslating(true)
const translatedText = await translateText(painting.prompt, 'english')
updatePaintingState({ prompt: translatedText })
} catch (error) {
console.error('Translation failed:', error)
} finally {
setIsTranslating(false)
}
}

const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (autoTranslateWithSpace && event.key === ' ') {
setSpaceClickCount((prev) => prev + 1)

if (spaceClickTimer.current) {
clearTimeout(spaceClickTimer.current)
}

spaceClickTimer.current = setTimeout(() => {
setSpaceClickCount(0)
}, 200)

if (spaceClickCount === 2) {
setSpaceClickCount(0)
setIsTranslating(true)
translate()
}
}
}

useEffect(() => {
return () => {
if (spaceClickTimer.current) {
clearTimeout(spaceClickTimer.current)
}
}
}, [])

return (
<Container>
<Navbar>
Expand Down Expand Up @@ -362,14 +417,16 @@ const PaintingsPage: FC = () => {
disabled={isLoading}
value={painting.prompt}
onChange={(e) => updatePaintingState({ prompt: e.target.value })}
placeholder={t('paintings.prompt_placeholder')}
placeholder={isTranslating ? t('paintings.translating') : t('paintings.prompt_placeholder')}
onKeyDown={handleKeyDown}
/>
<Toolbar>
<ToolbarMenu>
<TranslateButton
text={textareaRef.current?.resizableTextArea?.textArea?.value}
onTranslated={(translatedText) => updatePaintingState({ prompt: translatedText })}
disabled={isLoading}
disabled={isLoading || isTranslating}
isLoading={isTranslating}
style={{ marginRight: 6, borderRadius: '50%' }}
/>
<SendMessageButton sendMessage={onGenerate} disabled={isLoading} />
Expand Down

0 comments on commit f5d37a4

Please sign in to comment.