mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-31 16:49:07 +08:00
修复DMXAPI文生成画bug
This commit is contained in:
parent
2f312d68a0
commit
adef817e86
@ -3,7 +3,7 @@ import FileManager from '@renderer/services/FileManager'
|
|||||||
import { Painting } from '@renderer/types'
|
import { Painting } from '@renderer/types'
|
||||||
import { download } from '@renderer/utils/download'
|
import { download } from '@renderer/utils/download'
|
||||||
import { Button, Dropdown, Spin } from 'antd'
|
import { Button, Dropdown, Spin } from 'antd'
|
||||||
import { FC } from 'react'
|
import React, { FC } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
@ -17,6 +17,7 @@ interface ArtboardProps {
|
|||||||
onNextImage: () => void
|
onNextImage: () => void
|
||||||
onCancel: () => void
|
onCancel: () => void
|
||||||
retry?: (painting: Painting) => void
|
retry?: (painting: Painting) => void
|
||||||
|
imageCover?: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
const Artboard: FC<ArtboardProps> = ({
|
const Artboard: FC<ArtboardProps> = ({
|
||||||
@ -26,7 +27,8 @@ const Artboard: FC<ArtboardProps> = ({
|
|||||||
onPrevImage,
|
onPrevImage,
|
||||||
onNextImage,
|
onNextImage,
|
||||||
onCancel,
|
onCancel,
|
||||||
retry
|
retry,
|
||||||
|
imageCover
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
@ -108,8 +110,10 @@ const Artboard: FC<ArtboardProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div>{t('paintings.image_placeholder')}</div>
|
imageCover ?
|
||||||
)}
|
imageCover:
|
||||||
|
(<div>{t('paintings.image_placeholder')}</div>)
|
||||||
|
)}
|
||||||
</ImagePlaceholder>
|
</ImagePlaceholder>
|
||||||
)}
|
)}
|
||||||
{isLoading && (
|
{isLoading && (
|
||||||
|
|||||||
@ -9,9 +9,7 @@ import { useTheme } from '@renderer/context/ThemeProvider'
|
|||||||
import { usePaintings } from '@renderer/hooks/usePaintings'
|
import { usePaintings } from '@renderer/hooks/usePaintings'
|
||||||
import { useAllProviders } from '@renderer/hooks/useProvider'
|
import { useAllProviders } from '@renderer/hooks/useProvider'
|
||||||
import { useRuntime } from '@renderer/hooks/useRuntime'
|
import { useRuntime } from '@renderer/hooks/useRuntime'
|
||||||
import { useSettings } from '@renderer/hooks/useSettings'
|
|
||||||
import FileManager from '@renderer/services/FileManager'
|
import FileManager from '@renderer/services/FileManager'
|
||||||
import { translateText } from '@renderer/services/TranslateService'
|
|
||||||
import { useAppDispatch } from '@renderer/store'
|
import { useAppDispatch } from '@renderer/store'
|
||||||
import { setGenerating } from '@renderer/store/runtime'
|
import { setGenerating } from '@renderer/store/runtime'
|
||||||
import type { FileType, PaintingsState } from '@renderer/types'
|
import type { FileType, PaintingsState } from '@renderer/types'
|
||||||
@ -176,7 +174,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// API请求函数
|
// API请求函数
|
||||||
const callApi = async (requestConfig: { endpoint: string; body: any }) => {
|
const callApi = async (requestConfig: { endpoint: string; body: any }, controller: AbortController) => {
|
||||||
const { endpoint, body } = requestConfig
|
const { endpoint, body } = requestConfig
|
||||||
const headers = {}
|
const headers = {}
|
||||||
|
|
||||||
@ -191,7 +189,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
const response = await fetch(endpoint, {
|
const response = await fetch(endpoint, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers,
|
headers,
|
||||||
body
|
body,
|
||||||
|
signal: controller.signal
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -239,6 +238,10 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onGenerate = async () => {
|
const onGenerate = async () => {
|
||||||
|
// 如果已经在生成过程中,直接返回
|
||||||
|
if (isLoading) {
|
||||||
|
return
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
// 获取提示词
|
// 获取提示词
|
||||||
const prompt = textareaRef.current?.resizableTextArea?.textArea?.value || ''
|
const prompt = textareaRef.current?.resizableTextArea?.textArea?.value || ''
|
||||||
@ -254,26 +257,28 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
centered: true
|
centered: true
|
||||||
})
|
})
|
||||||
if (!confirmed) return
|
if (!confirmed) return
|
||||||
await FileManager.deleteFiles(painting.files)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setIsLoading(true)
|
||||||
|
|
||||||
// 设置请求状态
|
// 设置请求状态
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
setAbortController(controller)
|
setAbortController(controller)
|
||||||
setIsLoading(true)
|
|
||||||
dispatch(setGenerating(true))
|
dispatch(setGenerating(true))
|
||||||
|
|
||||||
// 准备请求配置
|
// 准备请求配置
|
||||||
const requestConfig = prepareRequestConfig(prompt, painting)
|
const requestConfig = prepareRequestConfig(prompt, painting)
|
||||||
|
|
||||||
// 发送API请求
|
// 发送API请求
|
||||||
const urls = await callApi(requestConfig)
|
const urls = await callApi(requestConfig, controller)
|
||||||
|
|
||||||
// 下载图像
|
// 下载图像
|
||||||
if (urls.length > 0) {
|
if (urls.length > 0) {
|
||||||
const downloadedFiles = await downloadImages(urls)
|
const downloadedFiles = await downloadImages(urls)
|
||||||
const validFiles = downloadedFiles.filter((file): file is FileType => file !== null)
|
const validFiles = downloadedFiles.filter((file): file is FileType => file !== null)
|
||||||
|
|
||||||
|
// 删除之前的图片
|
||||||
|
await FileManager.deleteFiles(painting.files)
|
||||||
// 保存文件并更新状态
|
// 保存文件并更新状态
|
||||||
await FileManager.addFiles(validFiles)
|
await FileManager.addFiles(validFiles)
|
||||||
updatePaintingState({ files: validFiles, urls })
|
updatePaintingState({ files: validFiles, urls })
|
||||||
@ -325,51 +330,8 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
setCurrentImageIndex(0)
|
setCurrentImageIndex(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
const { autoTranslateWithSpace } = useSettings()
|
|
||||||
const [spaceClickCount, setSpaceClickCount] = useState(0)
|
|
||||||
const [isTranslating, setIsTranslating] = useState(false)
|
|
||||||
const spaceClickTimer = useRef<NodeJS.Timeout>(null)
|
const spaceClickTimer = useRef<NodeJS.Timeout>(null)
|
||||||
|
|
||||||
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().then(() => {})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleProviderChange = (providerId: string) => {
|
const handleProviderChange = (providerId: string) => {
|
||||||
const routeName = location.pathname.split('/').pop()
|
const routeName = location.pathname.split('/').pop()
|
||||||
if (providerId !== routeName) {
|
if (providerId !== routeName) {
|
||||||
@ -481,21 +443,21 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
</SliderContainer>
|
</SliderContainer>
|
||||||
</LeftContainer>
|
</LeftContainer>
|
||||||
<MainContainer>
|
<MainContainer>
|
||||||
{painting?.urls?.length > 0 || DMXAPIPaintings?.length > 1 ? (
|
<Artboard
|
||||||
<Artboard
|
painting={painting}
|
||||||
painting={painting}
|
isLoading={isLoading}
|
||||||
isLoading={isLoading}
|
currentImageIndex={currentImageIndex}
|
||||||
currentImageIndex={currentImageIndex}
|
onPrevImage={prevImage}
|
||||||
onPrevImage={prevImage}
|
onNextImage={nextImage}
|
||||||
onNextImage={nextImage}
|
onCancel={onCancel}
|
||||||
onCancel={onCancel}
|
imageCover={
|
||||||
/>
|
painting?.urls?.length > 0 || DMXAPIPaintings?.length > 1 ? null : (
|
||||||
) : (
|
<EmptyImgBox>
|
||||||
<EmptyImgBox>
|
<EmptyImg></EmptyImg>
|
||||||
<EmptyImg></EmptyImg>
|
</EmptyImgBox>
|
||||||
</EmptyImgBox>
|
)
|
||||||
)}
|
}
|
||||||
|
/>
|
||||||
<InputContainer>
|
<InputContainer>
|
||||||
<Textarea
|
<Textarea
|
||||||
ref={textareaRef}
|
ref={textareaRef}
|
||||||
@ -504,8 +466,7 @@ const DmxapiPage: FC<{ Options: string[] }> = ({ Options }) => {
|
|||||||
value={painting.prompt}
|
value={painting.prompt}
|
||||||
spellCheck={false}
|
spellCheck={false}
|
||||||
onChange={(e) => updatePaintingState({ prompt: e.target.value })}
|
onChange={(e) => updatePaintingState({ prompt: e.target.value })}
|
||||||
placeholder={isTranslating ? t('paintings.translating') : t('paintings.prompt_placeholder')}
|
placeholder={t('paintings.prompt_placeholder')}
|
||||||
onKeyDown={handleKeyDown}
|
|
||||||
/>
|
/>
|
||||||
<Toolbar>
|
<Toolbar>
|
||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user