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 {
|
||||
const base64Data = imageBase64.split(',')[1]
|
||||
const mimeType = imageBase64.split(';')[0].split(':')[1]
|
||||
|
||||
switch (type) {
|
||||
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 byteArrays: Uint8Array[] = []
|
||||
|
||||
for (let i = 0; i < byteCharacters.length; i += 512) {
|
||||
const slice = byteCharacters.slice(i, i + 512)
|
||||
|
||||
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
|
||||
const slice = byteCharacters.slice(offset, offset + 512)
|
||||
const byteNumbers = new Array(slice.length)
|
||||
for (let j = 0; j < slice.length; j++) {
|
||||
byteNumbers[j] = slice.charCodeAt(j)
|
||||
for (let i = 0; i < slice.length; i++) {
|
||||
byteNumbers[i] = slice.charCodeAt(i)
|
||||
}
|
||||
|
||||
const byteArray = new Uint8Array(byteNumbers)
|
||||
byteArrays.push(byteArray)
|
||||
}
|
||||
|
||||
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([
|
||||
new ClipboardItem({
|
||||
[blob.type]: blob
|
||||
})
|
||||
])
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
window.message.success(t('message.copy.success'))
|
||||
} catch (error) {
|
||||
@ -95,7 +111,7 @@ const MessageImage: FC<Props> = ({ message }) => {
|
||||
<ZoomOutOutlined disabled={scale === 1} onClick={onZoomOut} />
|
||||
<ZoomInOutlined disabled={scale === 50} onClick={onZoomIn} />
|
||||
<UndoOutlined onClick={onReset} />
|
||||
<CopyOutlined onClick={() => onCopy(image)} />
|
||||
<CopyOutlined onClick={() => onCopy(message.metadata?.generateImage?.type!, image)} />
|
||||
<DownloadOutlined onClick={() => onDownload(image, index)} />
|
||||
</ToobarWrapper>
|
||||
)
|
||||
|
||||
@ -112,6 +112,14 @@ const MessageMenubar: FC<Props> = (props) => {
|
||||
|
||||
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)) {
|
||||
const processedMessage = withMessageThought(clone(message))
|
||||
textToEdit = processedMessage.content
|
||||
@ -135,8 +143,40 @@ const MessageMenubar: FC<Props> = (props) => {
|
||||
})
|
||||
|
||||
if (editedText && editedText !== textToEdit) {
|
||||
await editMessage(message.id, { content: editedText })
|
||||
resendMessage && handleResendUserMessage({ ...message, content: editedText })
|
||||
// 解析编辑后的文本,提取图片 URL
|
||||
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])
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user