diff --git a/src/preload/index.ts b/src/preload/index.ts index 2a2f378fa2..828557865d 100644 --- a/src/preload/index.ts +++ b/src/preload/index.ts @@ -2,7 +2,7 @@ import type { ExtractChunkData } from '@cherrystudio/embedjs-interfaces' import { electronAPI } from '@electron-toolkit/preload' import { IpcChannel } from '@shared/IpcChannel' import { FileType, KnowledgeBaseParams, KnowledgeItem, MCPServer, Shortcut, WebDavConfig } from '@types' -import { contextBridge, ipcRenderer, OpenDialogOptions, shell } from 'electron' +import { contextBridge, ipcRenderer, OpenDialogOptions, shell, webUtils } from 'electron' import { CreateDirectoryOptions } from 'webdav' // Custom APIs for renderer @@ -73,7 +73,8 @@ const api = { download: (url: string) => ipcRenderer.invoke(IpcChannel.File_Download, url), copy: (fileId: string, destPath: string) => ipcRenderer.invoke(IpcChannel.File_Copy, fileId, destPath), binaryImage: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_BinaryImage, fileId), - base64File: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Base64File, fileId) + base64File: (fileId: string) => ipcRenderer.invoke(IpcChannel.File_Base64File, fileId), + getPathForFile: (file: File) => webUtils.getPathForFile(file) }, fs: { read: (path: string) => ipcRenderer.invoke(IpcChannel.Fs_Read, path) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 94ee6c07a9..2866739748 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -163,6 +163,7 @@ "input.estimated_tokens.tip": "Estimated tokens", "input.expand": "Expand", "input.file_not_supported": "Model does not support this file type", + "input.file_error": "Error processing file", "input.generate_image": "Generate image", "input.generate_image_not_supported": "The model does not support generating images.", "input.knowledge_base": "Knowledge Base", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index fef52b7d58..9be762b226 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -163,6 +163,7 @@ "input.estimated_tokens.tip": "推定トークン数", "input.expand": "展開", "input.file_not_supported": "モデルはこのファイルタイプをサポートしません", + "input.file_error": "ファイル処理エラー", "input.generate_image": "画像を生成する", "input.generate_image_not_supported": "モデルは画像の生成をサポートしていません。", "input.knowledge_base": "ナレッジベース", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index bda4157737..f749fb2d01 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -163,6 +163,7 @@ "input.estimated_tokens.tip": "Затраты токенов", "input.expand": "Развернуть", "input.file_not_supported": "Модель не поддерживает этот тип файла", + "input.file_error": "Ошибка обработки файла", "input.generate_image": "Сгенерировать изображение", "input.generate_image_not_supported": "Модель не поддерживает генерацию изображений.", "input.knowledge_base": "База знаний", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 6808ff9b8a..e787498e8b 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -163,6 +163,7 @@ "input.estimated_tokens.tip": "预估 token 数", "input.expand": "展开", "input.file_not_supported": "模型不支持此文件类型", + "input.file_error": "文件处理出错", "input.generate_image": "生成图片", "input.generate_image_not_supported": "模型不支持生成图片", "input.knowledge_base": "知识库", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 02a18f08f5..8b1eff5941 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -163,6 +163,7 @@ "input.estimated_tokens.tip": "預估 Token 數", "input.expand": "展開", "input.file_not_supported": "模型不支援此檔案類型", + "input.file_error": "檔案處理錯誤", "input.generate_image": "生成圖片", "input.generate_image_not_supported": "模型不支援生成圖片", "input.knowledge_base": "知識庫", diff --git a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx index 39621cc85d..552e374e4c 100644 --- a/src/renderer/src/pages/home/Inputbar/Inputbar.tsx +++ b/src/renderer/src/pages/home/Inputbar/Inputbar.tsx @@ -584,27 +584,33 @@ const Inputbar: FC = ({ assistant: _assistant, setActiveTopic, topic }) = if (event.clipboardData?.files && event.clipboardData.files.length > 0) { event.preventDefault() for (const file of event.clipboardData.files) { - if (file.path === '') { - // 图像生成也支持图像编辑 - if (file.type.startsWith('image/') && (isVisionModel(model) || isGenerateImageModel(model))) { - const tempFilePath = await window.api.file.create(file.name) - const arrayBuffer = await file.arrayBuffer() - const uint8Array = new Uint8Array(arrayBuffer) - await window.api.file.write(tempFilePath, uint8Array) - const selectedFile = await window.api.file.get(tempFilePath) - selectedFile && setFiles((prevFiles) => [...prevFiles, selectedFile]) - break - } else { - window.message.info({ - key: 'file_not_supported', - content: t('chat.input.file_not_supported') - }) - } - } + try { + // 使用新的API获取文件路径 + const filePath = window.api.file.getPathForFile(file) - if (file.path) { - if (supportExts.includes(getFileExtension(file.path))) { - const selectedFile = await window.api.file.get(file.path) + // 如果没有路径,可能是剪贴板中的图像数据 + if (!filePath) { + // 图像生成也支持图像编辑 + if (file.type.startsWith('image/') && (isVisionModel(model) || isGenerateImageModel(model))) { + const tempFilePath = await window.api.file.create(file.name) + const arrayBuffer = await file.arrayBuffer() + const uint8Array = new Uint8Array(arrayBuffer) + await window.api.file.write(tempFilePath, uint8Array) + const selectedFile = await window.api.file.get(tempFilePath) + selectedFile && setFiles((prevFiles) => [...prevFiles, selectedFile]) + break + } else { + window.message.info({ + key: 'file_not_supported', + content: t('chat.input.file_not_supported') + }) + } + continue + } + + // 有路径的情况 + if (supportExts.includes(getFileExtension(filePath))) { + const selectedFile = await window.api.file.get(filePath) selectedFile && setFiles((prevFiles) => [...prevFiles, selectedFile]) } else { window.message.info({ @@ -612,6 +618,9 @@ const Inputbar: FC = ({ assistant: _assistant, setActiveTopic, topic }) = content: t('chat.input.file_not_supported') }) } + } catch (error) { + Logger.error('[src/renderer/src/pages/home/Inputbar/Inputbar.tsx] onPaste:', error) + window.message.error(t('chat.input.file_error')) } } return diff --git a/src/renderer/src/utils/input.ts b/src/renderer/src/utils/input.ts index 9c638c2289..6952a24a51 100644 --- a/src/renderer/src/utils/input.ts +++ b/src/renderer/src/utils/input.ts @@ -3,14 +3,27 @@ import { FileType } from '@renderer/types' export const getFilesFromDropEvent = async (e: React.DragEvent): Promise => { if (e.dataTransfer.files.length > 0) { - const results = await Promise.allSettled([...e.dataTransfer.files].map((file) => window.api.file.get(file.path))) + // 使用新的API获取文件路径 + const filePromises = [...e.dataTransfer.files].map(async (file) => { + try { + // 使用新的webUtils.getPathForFile API获取文件路径 + const filePath = window.api.file.getPathForFile(file) + if (filePath) { + return window.api.file.get(filePath) + } + return null + } catch (error) { + Logger.error('[src/renderer/src/utils/input.ts] getFilesFromDropEvent - getPathForFile error:', error) + return null + } + }) + + const results = await Promise.allSettled(filePromises) const list: FileType[] = [] for (const result of results) { - if (result.status === 'fulfilled') { - if (result.value !== null) { - list.push(result.value) - } - } else { + if (result.status === 'fulfilled' && result.value !== null) { + list.push(result.value) + } else if (result.status === 'rejected') { Logger.error('[src/renderer/src/utils/input.ts] getFilesFromDropEvent:', result.reason) } }