fix: 解决聊天页面图片复制失败的问题和点击编辑回复的时候,不显示图片url的问题 (#4496)
* fix: 解决聊天页面图片复制失败的问题和点击编辑回复的时候,不显示图片url的问题 * fix: 解决chat模式,gemini-2.0-flash-exp-image-generation返回base64图片,无法复制的问题 * fix(MessageImage): Update the image copying feature to process base64 and URL formatted images based on their type --------- Co-authored-by: magicdmer <magicdmer@163.com> Co-authored-by: eeee0717 <chentao020717Work@outlook.com>
This commit is contained in:
parent
10efa444bf
commit
f7f7d2bde8
@ -36,34 +36,50 @@ const MessageImage: FC<Props> = ({ message }) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复制 base64 图片到剪贴板
|
// 复制图片到剪贴板
|
||||||
const onCopy = async (imageBase64: string) => {
|
const onCopy = async (type: string, image: string) => {
|
||||||
try {
|
try {
|
||||||
const base64Data = imageBase64.split(',')[1]
|
switch (type) {
|
||||||
const mimeType = imageBase64.split(';')[0].split(':')[1]
|
case 'base64': {
|
||||||
|
// 处理 base64 格式的图片
|
||||||
|
const parts = image.split(';base64,')
|
||||||
|
if (parts.length === 2) {
|
||||||
|
const mimeType = parts[0].replace('data:', '')
|
||||||
|
const base64Data = parts[1]
|
||||||
const byteCharacters = atob(base64Data)
|
const byteCharacters = atob(base64Data)
|
||||||
const byteArrays: Uint8Array[] = []
|
const byteArrays: Uint8Array[] = []
|
||||||
|
|
||||||
for (let i = 0; i < byteCharacters.length; i += 512) {
|
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
|
||||||
const slice = byteCharacters.slice(i, i + 512)
|
const slice = byteCharacters.slice(offset, offset + 512)
|
||||||
|
|
||||||
const byteNumbers = new Array(slice.length)
|
const byteNumbers = new Array(slice.length)
|
||||||
for (let j = 0; j < slice.length; j++) {
|
for (let i = 0; i < slice.length; i++) {
|
||||||
byteNumbers[j] = slice.charCodeAt(j)
|
byteNumbers[i] = slice.charCodeAt(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
const byteArray = new Uint8Array(byteNumbers)
|
const byteArray = new Uint8Array(byteNumbers)
|
||||||
byteArrays.push(byteArray)
|
byteArrays.push(byteArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
const blob = new Blob(byteArrays, { type: mimeType })
|
const blob = new Blob(byteArrays, { type: mimeType })
|
||||||
|
await navigator.clipboard.write([new ClipboardItem({ [mimeType]: blob })])
|
||||||
|
} else {
|
||||||
|
throw new Error('无效的 base64 图片格式')
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'url':
|
||||||
|
{
|
||||||
|
// 处理 URL 格式的图片
|
||||||
|
const response = await fetch(image)
|
||||||
|
const blob = await response.blob()
|
||||||
|
|
||||||
await navigator.clipboard.write([
|
await navigator.clipboard.write([
|
||||||
new ClipboardItem({
|
new ClipboardItem({
|
||||||
[blob.type]: blob
|
[blob.type]: blob
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
window.message.success(t('message.copy.success'))
|
window.message.success(t('message.copy.success'))
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -95,7 +111,7 @@ const MessageImage: FC<Props> = ({ message }) => {
|
|||||||
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
|
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
|
||||||
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
|
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
|
||||||
<UndoOutlined onClick={onReset} />
|
<UndoOutlined onClick={onReset} />
|
||||||
<CopyOutlined onClick={() => onCopy(image)} />
|
<CopyOutlined onClick={() => onCopy(message.metadata?.generateImage?.type!, image)} />
|
||||||
<DownloadOutlined onClick={() => onDownload(image, index)} />
|
<DownloadOutlined onClick={() => onDownload(image, index)} />
|
||||||
</ToobarWrapper>
|
</ToobarWrapper>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -112,6 +112,14 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
|
|
||||||
let textToEdit = message.content
|
let textToEdit = message.content
|
||||||
|
|
||||||
|
// 如果是包含图片的消息,添加图片的 markdown 格式
|
||||||
|
if (message.metadata?.generateImage?.images) {
|
||||||
|
const imageMarkdown = message.metadata.generateImage.images
|
||||||
|
.map((image, index) => ``)
|
||||||
|
.join('\n')
|
||||||
|
textToEdit = `${textToEdit}\n\n${imageMarkdown}`
|
||||||
|
}
|
||||||
|
|
||||||
if (message.role === 'assistant' && message.model && isReasoningModel(message.model)) {
|
if (message.role === 'assistant' && message.model && isReasoningModel(message.model)) {
|
||||||
const processedMessage = withMessageThought(clone(message))
|
const processedMessage = withMessageThought(clone(message))
|
||||||
textToEdit = processedMessage.content
|
textToEdit = processedMessage.content
|
||||||
@ -135,8 +143,40 @@ const MessageMenubar: FC<Props> = (props) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (editedText && editedText !== textToEdit) {
|
if (editedText && editedText !== textToEdit) {
|
||||||
await editMessage(message.id, { content: editedText })
|
// 解析编辑后的文本,提取图片 URL
|
||||||
resendMessage && handleResendUserMessage({ ...message, content: editedText })
|
const imageRegex = /!\[image-\d+\]\((.*?)\)/g
|
||||||
|
const imageUrls: string[] = []
|
||||||
|
let match
|
||||||
|
let content = editedText
|
||||||
|
|
||||||
|
while ((match = imageRegex.exec(editedText)) !== null) {
|
||||||
|
imageUrls.push(match[1])
|
||||||
|
content = content.replace(match[0], '')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新消息内容,保留图片信息
|
||||||
|
await editMessage(message.id, {
|
||||||
|
content: content.trim(),
|
||||||
|
metadata: {
|
||||||
|
...message.metadata,
|
||||||
|
generateImage: imageUrls.length > 0 ? {
|
||||||
|
type: 'url',
|
||||||
|
images: imageUrls
|
||||||
|
} : undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
resendMessage && handleResendUserMessage({
|
||||||
|
...message,
|
||||||
|
content: content.trim(),
|
||||||
|
metadata: {
|
||||||
|
...message.metadata,
|
||||||
|
generateImage: imageUrls.length > 0 ? {
|
||||||
|
type: 'url',
|
||||||
|
images: imageUrls
|
||||||
|
} : undefined
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}, [message, editMessage, handleResendUserMessage, t])
|
}, [message, editMessage, handleResendUserMessage, t])
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user