From c20769ddaad318cbe5e3efcf9940a6cf403998eb Mon Sep 17 00:00:00 2001 From: Blackjack200 Date: Fri, 21 Nov 2025 10:56:05 +0800 Subject: [PATCH 1/5] feat: implement file upload size configuration and progress tracking --- .../presenter/filePresenter/FilePresenter.ts | 11 +- src/main/presenter/index.ts | 2 +- .../settings/components/CommonSettings.vue | 2 + .../settings/components/KnowledgeFileItem.vue | 46 +++++- .../common/UploadFileSettingsSection.vue | 145 ++++++++++++++++++ src/renderer/src/events.ts | 3 +- src/renderer/src/i18n/en-US/settings.json | 4 +- src/renderer/src/i18n/fa-IR/settings.json | 4 +- src/renderer/src/i18n/fr-FR/settings.json | 4 +- src/renderer/src/i18n/ja-JP/settings.json | 4 +- src/renderer/src/i18n/ko-KR/settings.json | 4 +- src/renderer/src/i18n/pt-BR/settings.json | 4 +- src/renderer/src/i18n/ru-RU/settings.json | 4 +- src/renderer/src/i18n/zh-CN/settings.json | 4 +- src/renderer/src/i18n/zh-HK/settings.json | 4 +- src/renderer/src/i18n/zh-TW/settings.json | 4 +- 16 files changed, 229 insertions(+), 20 deletions(-) create mode 100644 src/renderer/settings/components/common/UploadFileSettingsSection.vue diff --git a/src/main/presenter/filePresenter/FilePresenter.ts b/src/main/presenter/filePresenter/FilePresenter.ts index a3a489a7e..e68beeb77 100644 --- a/src/main/presenter/filePresenter/FilePresenter.ts +++ b/src/main/presenter/filePresenter/FilePresenter.ts @@ -4,7 +4,7 @@ import path from 'path' import { BaseFileAdapter } from './BaseFileAdapter' import { FileAdapterConstructor } from './FileAdapterConstructor' -import { FileOperation } from '../../../shared/presenter' +import { FileOperation, IConfigPresenter } from '../../../shared/presenter' import { detectMimeType, getMimeTypeAdapterMap } from './mime' import { IFilePresenter } from '../../../shared/presenter' import { MessageFile } from '@shared/chat' @@ -21,13 +21,18 @@ import { export class FilePresenter implements IFilePresenter { private userDataPath: string - private maxFileSize: number = 1024 * 1024 * 30 // 30 MB + private configPresenter: IConfigPresenter private tempDir: string private fileValidationService: IFileValidationService - constructor(fileValidationService?: IFileValidationService) { + get maxFileSize(): number { + return this.configPresenter.getSetting('maxFileSize') || 1024 * 1024 * 30 + } + + constructor(configPresenter: IConfigPresenter, fileValidationService?: IFileValidationService) { this.userDataPath = app.getPath('userData') this.tempDir = path.join(this.userDataPath, 'temp') + this.configPresenter = configPresenter this.fileValidationService = fileValidationService || new FileValidationService() // Ensure temp directory exists try { diff --git a/src/main/presenter/index.ts b/src/main/presenter/index.ts index 908319522..1cb9b3d5e 100644 --- a/src/main/presenter/index.ts +++ b/src/main/presenter/index.ts @@ -102,7 +102,7 @@ export class Presenter implements IPresenter { this.mcpPresenter = new McpPresenter(this.configPresenter) this.upgradePresenter = new UpgradePresenter(this.configPresenter) this.shortcutPresenter = new ShortcutPresenter(this.configPresenter) - this.filePresenter = new FilePresenter() + this.filePresenter = new FilePresenter(this.configPresenter) this.syncPresenter = new SyncPresenter(this.configPresenter, this.sqlitePresenter) this.deeplinkPresenter = new DeeplinkPresenter() this.notificationPresenter = new NotificationPresenter() diff --git a/src/renderer/settings/components/CommonSettings.vue b/src/renderer/settings/components/CommonSettings.vue index b5f34af75..c92935813 100644 --- a/src/renderer/settings/components/CommonSettings.vue +++ b/src/renderer/settings/components/CommonSettings.vue @@ -3,6 +3,7 @@
+ - + class="relative group w-6 h-6 flex items-center justify-center" + > + + +
+ {{ Math.floor(progressPercent) }}% {{ progress.completed + progress.error }}/{{ + progress.total + }} +
+
+ { return t(`settings.knowledgeBase.unknown`) } } + +const progress = ref({ completed: 0, error: 0, total: 0 }) +const progressPercent = computed(() => { + if (!progress.value.total) return 0 + return ((progress.value.completed + progress.value.error) / progress.value.total) * 100 +}) + +onMounted(async () => { + window.electron.ipcRenderer.on( + RAG_EVENTS.FILE_PROGRESS, + (_, data: { fileId: string; completed: number; error: number; total: number }) => { + if (props.file.id === data.fileId) { + progress.value = { + completed: data.completed, + error: data.error, + total: data.total + } + } + } + ) +}) + +onBeforeUnmount(() => { + window.electron.ipcRenderer.removeAllListeners(RAG_EVENTS.FILE_PROGRESS) +}) diff --git a/src/renderer/settings/components/common/UploadFileSettingsSection.vue b/src/renderer/settings/components/common/UploadFileSettingsSection.vue new file mode 100644 index 000000000..9b600ce9b --- /dev/null +++ b/src/renderer/settings/components/common/UploadFileSettingsSection.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/renderer/src/events.ts b/src/renderer/src/events.ts index cdbf49a86..6879414d5 100644 --- a/src/renderer/src/events.ts +++ b/src/renderer/src/events.ts @@ -164,7 +164,8 @@ export const DIALOG_EVENTS = { // 知识库事件 export const RAG_EVENTS = { - FILE_UPDATED: 'rag:file-updated' // 文件状态更新 + FILE_UPDATED: 'rag:file-updated', // 文件状态更新 + FILE_PROGRESS: 'rag:file-progress' // 文件进度更新 } // 系统相关事件 export const SYSTEM_EVENTS = { diff --git a/src/renderer/src/i18n/en-US/settings.json b/src/renderer/src/i18n/en-US/settings.json index e19f029d0..1482f96e1 100644 --- a/src/renderer/src/i18n/en-US/settings.json +++ b/src/renderer/src/i18n/en-US/settings.json @@ -59,7 +59,9 @@ }, "notifications": "System Notifications", "notificationsDesc": "When DeepChat is not in the foreground, if a session is generated, a system notification will be sent", - "contentProtection": "Screen capture protection" + "contentProtection": "Screen capture protection", + "fileMaxSize": "File Maximum Size", + "fileMaxSizeHint": "Limits the maximum size of a single uploaded file" }, "data": { "title": "Data Settings", diff --git a/src/renderer/src/i18n/fa-IR/settings.json b/src/renderer/src/i18n/fa-IR/settings.json index 5e2b29d9c..45be39080 100644 --- a/src/renderer/src/i18n/fa-IR/settings.json +++ b/src/renderer/src/i18n/fa-IR/settings.json @@ -59,7 +59,9 @@ }, "notifications": "آگاه‌ساز سامانه", "notificationsDesc": "هنگامی که دیپ‌چت در پیش‌زمینه نیست، اگر نشستی تولید شود، یک آگاه‌ساز سامانه فرستاده خواهد شد", - "traceDebugEnabled": "پیگیری تماس" + "traceDebugEnabled": "پیگیری تماس", + "fileMaxSize": "حداکثر اندازه فایل", + "fileMaxSizeHint": "حداکثر اندازه یک فایل قابل آپلود را محدود می‌کند" }, "data": { "title": "تنظیمات داده", diff --git a/src/renderer/src/i18n/fr-FR/settings.json b/src/renderer/src/i18n/fr-FR/settings.json index 669ce4511..c5451d387 100644 --- a/src/renderer/src/i18n/fr-FR/settings.json +++ b/src/renderer/src/i18n/fr-FR/settings.json @@ -59,7 +59,9 @@ }, "notifications": "Notifications système", "notificationsDesc": "Quand DeepChat est en arrière‑plan, envoyer une notification à la fin d’une réponse", - "traceDebugEnabled": "Suivi des appels" + "traceDebugEnabled": "Suivi des appels", + "fileMaxSize": "Taille maximale du fichier", + "fileMaxSizeHint": "Limite la taille maximale d'un fichier à télécharger" }, "data": { "title": "Paramètres des données", diff --git a/src/renderer/src/i18n/ja-JP/settings.json b/src/renderer/src/i18n/ja-JP/settings.json index 278fab2d8..aef8311e8 100644 --- a/src/renderer/src/i18n/ja-JP/settings.json +++ b/src/renderer/src/i18n/ja-JP/settings.json @@ -59,7 +59,9 @@ }, "notifications": "システム通知", "notificationsDesc": "DeepChatがバックグラウンドのとき、応答が完了すると通知を送信します", - "traceDebugEnabled": "追跡呼び出し" + "traceDebugEnabled": "追跡呼び出し", + "fileMaxSize": "ファイルの最大サイズ", + "fileMaxSizeHint": "アップロードできるファイルの最大サイズを制限します" }, "data": { "title": "データ設定", diff --git a/src/renderer/src/i18n/ko-KR/settings.json b/src/renderer/src/i18n/ko-KR/settings.json index 7e3841ed4..c0328a512 100644 --- a/src/renderer/src/i18n/ko-KR/settings.json +++ b/src/renderer/src/i18n/ko-KR/settings.json @@ -59,7 +59,9 @@ }, "notifications": "시스템 알림", "notificationsDesc": "DeepChat이 전경에 있지 않으면 세션이 생성되면 시스템 알림이 전송됩니다.", - "traceDebugEnabled": "추적 호출" + "traceDebugEnabled": "추적 호출", + "fileMaxSize": "파일 최대 크기", + "fileMaxSizeHint": "단일 파일 업로드의 최대 크기를 제한합니다" }, "data": { "title": "데이터 설정", diff --git a/src/renderer/src/i18n/pt-BR/settings.json b/src/renderer/src/i18n/pt-BR/settings.json index 4008057cd..9ee38d828 100644 --- a/src/renderer/src/i18n/pt-BR/settings.json +++ b/src/renderer/src/i18n/pt-BR/settings.json @@ -59,7 +59,9 @@ "notifications": "Notificações do Sistema", "notificationsDesc": "Quando o DeepChat não estiver em primeiro plano, se uma sessão for gerada, uma notificação do sistema será enviada", "contentProtection": "Proteção contra captura de tela", - "traceDebugEnabled": "Rastreamento de Chamadas" + "traceDebugEnabled": "Rastreamento de Chamadas", + "fileMaxSize": "Tamanho máximo do arquivo", + "fileMaxSizeHint": "Limita o tamanho máximo de um arquivo enviado" }, "data": { "title": "Configurações de Dados", diff --git a/src/renderer/src/i18n/ru-RU/settings.json b/src/renderer/src/i18n/ru-RU/settings.json index 44185e61b..998d502a3 100644 --- a/src/renderer/src/i18n/ru-RU/settings.json +++ b/src/renderer/src/i18n/ru-RU/settings.json @@ -59,7 +59,9 @@ "themeSystem": "Следовать системе", "notifications": "Системное уведомление", "notificationsDesc": "Когда DeepChat не будет на переднем плане, если сгенерируется сеанс, будет отправлено системное уведомление", - "traceDebugEnabled": "Функция отладки Trace" + "traceDebugEnabled": "Функция отладки Trace", + "fileMaxSize": "Максимальный размер файла", + "fileMaxSizeHint": "Ограничивает максимальный размер загружаемого файла" }, "data": { "title": "Настройки данных", diff --git a/src/renderer/src/i18n/zh-CN/settings.json b/src/renderer/src/i18n/zh-CN/settings.json index 985899832..c33e3f304 100644 --- a/src/renderer/src/i18n/zh-CN/settings.json +++ b/src/renderer/src/i18n/zh-CN/settings.json @@ -59,7 +59,9 @@ "loggingRestartNotice": "切换此设置将导致程序重启,请确认是否继续?", "openLogFolder": "打开日志文件夹", "notifications": "系统通知", - "notificationsDesc": "当 DeepChat 不在前台时,如有会话生成完毕会发送系统通知" + "notificationsDesc": "当 DeepChat 不在前台时,如有会话生成完毕会发送系统通知", + "fileMaxSize": "文件最大大小", + "fileMaxSizeHint": "限制单个文件的最大上传大小" }, "data": { "title": "数据设置", diff --git a/src/renderer/src/i18n/zh-HK/settings.json b/src/renderer/src/i18n/zh-HK/settings.json index 8e7d6b8b3..a2ad6a9a7 100644 --- a/src/renderer/src/i18n/zh-HK/settings.json +++ b/src/renderer/src/i18n/zh-HK/settings.json @@ -59,7 +59,9 @@ }, "notifications": "系統通知", "notificationsDesc": "當 DeepChat 不在前台時,如有會話生成完畢會發送系統通知", - "traceDebugEnabled": "Trace 除錯功能" + "traceDebugEnabled": "Trace 除錯功能", + "fileMaxSize": "檔案最大大小", + "fileMaxSizeHint": "限制單個檔案的最大上傳大小" }, "data": { "title": "數據設置", diff --git a/src/renderer/src/i18n/zh-TW/settings.json b/src/renderer/src/i18n/zh-TW/settings.json index 30ae213a8..c1989507d 100644 --- a/src/renderer/src/i18n/zh-TW/settings.json +++ b/src/renderer/src/i18n/zh-TW/settings.json @@ -59,7 +59,9 @@ }, "notifications": "系統通知", "notificationsDesc": "當 DeepChat 不在前台時,如有會話生成完畢會發送系統通知", - "traceDebugEnabled": "Trace 除錯功能" + "traceDebugEnabled": "Trace 除錯功能", + "fileMaxSize": "檔案最大大小", + "fileMaxSizeHint": "限制單個檔案的最大上傳大小" }, "data": { "title": "資料設定", From e30ed9cfb8779e72021117641218ac24cf1fe86e Mon Sep 17 00:00:00 2001 From: Blackjack200 Date: Fri, 21 Nov 2025 10:58:52 +0800 Subject: [PATCH 2/5] fix: correct maxSize comment from 30MB to 1024MB in UploadFileSettingsSection.vue --- src/main/presenter/filePresenter/FilePresenter.ts | 2 +- .../settings/components/common/UploadFileSettingsSection.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/presenter/filePresenter/FilePresenter.ts b/src/main/presenter/filePresenter/FilePresenter.ts index e68beeb77..0675a8990 100644 --- a/src/main/presenter/filePresenter/FilePresenter.ts +++ b/src/main/presenter/filePresenter/FilePresenter.ts @@ -26,7 +26,7 @@ export class FilePresenter implements IFilePresenter { private fileValidationService: IFileValidationService get maxFileSize(): number { - return this.configPresenter.getSetting('maxFileSize') || 1024 * 1024 * 30 + return this.configPresenter.getSetting('maxFileSize') || 1024 * 1024 * 30 //30MB } constructor(configPresenter: IConfigPresenter, fileValidationService?: IFileValidationService) { diff --git a/src/renderer/settings/components/common/UploadFileSettingsSection.vue b/src/renderer/settings/components/common/UploadFileSettingsSection.vue index 9b600ce9b..efcd03be6 100644 --- a/src/renderer/settings/components/common/UploadFileSettingsSection.vue +++ b/src/renderer/settings/components/common/UploadFileSettingsSection.vue @@ -74,7 +74,7 @@ const { t } = useI18n() const configPresenter = usePresenter('configPresenter') const minSize = 1 -const maxSize = 1024 // 30MB +const maxSize = 1024 // 1024MB const fileMaxSize = ref(30) // 默认值 const isEditing = ref(false) From f97fcf8ccb3718fbb7d4087f56dcade582e28dfa Mon Sep 17 00:00:00 2001 From: Blackjack200 Date: Fri, 21 Nov 2025 11:09:23 +0800 Subject: [PATCH 3/5] refactor: update file upload settings and improve error messages --- src/main/presenter/filePresenter/FilePresenter.ts | 2 +- .../settings/components/common/UploadFileSettingsSection.vue | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/presenter/filePresenter/FilePresenter.ts b/src/main/presenter/filePresenter/FilePresenter.ts index 0675a8990..bef6eb1fb 100644 --- a/src/main/presenter/filePresenter/FilePresenter.ts +++ b/src/main/presenter/filePresenter/FilePresenter.ts @@ -26,7 +26,7 @@ export class FilePresenter implements IFilePresenter { private fileValidationService: IFileValidationService get maxFileSize(): number { - return this.configPresenter.getSetting('maxFileSize') || 1024 * 1024 * 30 //30MB + return this.configPresenter.getSetting('maxFileSize') ?? 1024 * 1024 * 30 //30MB } constructor(configPresenter: IConfigPresenter, fileValidationService?: IFileValidationService) { diff --git a/src/renderer/settings/components/common/UploadFileSettingsSection.vue b/src/renderer/settings/components/common/UploadFileSettingsSection.vue index efcd03be6..c8fb9faf8 100644 --- a/src/renderer/settings/components/common/UploadFileSettingsSection.vue +++ b/src/renderer/settings/components/common/UploadFileSettingsSection.vue @@ -87,7 +87,7 @@ const handleChange = async (value: string | number) => { await configPresenter.setSetting('maxFileSize', numValue * 1024 * 1024) fileMaxSize.value = numValue } catch (error) { - console.error('设置文件最大值失败:', error) + console.error('Failed to set max file size:', error) } } } @@ -127,7 +127,7 @@ onMounted(async () => { fileMaxSize.value = saved / 1024 / 1024 } } catch (error) { - console.error('加载文件最大值失败:', error) + console.error('Failed to load max file size:', error) } }) From c7a777a2f13659ffb922b42cf701627d65d652e4 Mon Sep 17 00:00:00 2001 From: Blackjack200 Date: Fri, 21 Nov 2025 11:16:41 +0800 Subject: [PATCH 4/5] refactor: update FilePresenter to use IConfigPresenter and maintain backward compatibility --- test/main/presenter/FilePresenter.test.ts | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/test/main/presenter/FilePresenter.test.ts b/test/main/presenter/FilePresenter.test.ts index d473da8e5..77f01166c 100644 --- a/test/main/presenter/FilePresenter.test.ts +++ b/test/main/presenter/FilePresenter.test.ts @@ -3,9 +3,17 @@ import { FilePresenter } from '../../../src/main/presenter/filePresenter/FilePre import { FileValidationResult, IFileValidationService -} from '../../../src/main/presenter/filePresenter/FileValidationService' +} from '../../../src/main/presenter/configPresenter/IConfigPresenter' + +import { IConfigPresenter } from '../../../src/shared/presenter' // Mock all external dependencies +const mockConfigPresenter: IConfigPresenter = { + getKnowledgeConfigs: vi.fn(), + diffKnowledgeConfigs: vi.fn(), + setKnowledgeConfigs: vi.fn() +} as any + vi.mock('electron', () => ({ app: { getPath: vi.fn().mockReturnValue('/mock/user/data') @@ -59,7 +67,7 @@ describe('FilePresenter Integration with FileValidationService', () => { } // Create FilePresenter with mocked service - filePresenter = new FilePresenter(mockFileValidationService) + filePresenter = new FilePresenter(mockConfigPresenter, mockFileValidationService) }) describe('constructor', () => { @@ -70,12 +78,12 @@ describe('FilePresenter Integration with FileValidationService', () => { getSupportedMimeTypes: vi.fn() } - const presenter = new FilePresenter(customService) + const presenter = new FilePresenter(mockConfigPresenter, customService) expect(presenter).toBeInstanceOf(FilePresenter) }) it('should initialize with default FileValidationService when none provided', () => { - const presenter = new FilePresenter() + const presenter = new FilePresenter(mockConfigPresenter) expect(presenter).toBeInstanceOf(FilePresenter) }) }) @@ -215,7 +223,7 @@ describe('FilePresenter Integration with FileValidationService', () => { it('should maintain backward compatibility', () => { // Ensure new methods don't break existing interface - const presenter = new FilePresenter() + const presenter = new FilePresenter(mockConfigPresenter) expect(presenter).toHaveProperty('validateFileForKnowledgeBase') expect(presenter).toHaveProperty('getSupportedExtensions') }) From 7724f842a22e6205d791a5307407f457cae9c033 Mon Sep 17 00:00:00 2001 From: Blackjack200 Date: Fri, 21 Nov 2025 11:18:51 +0800 Subject: [PATCH 5/5] fix: incorrect test import --- test/main/presenter/FilePresenter.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/main/presenter/FilePresenter.test.ts b/test/main/presenter/FilePresenter.test.ts index 77f01166c..34bc01e34 100644 --- a/test/main/presenter/FilePresenter.test.ts +++ b/test/main/presenter/FilePresenter.test.ts @@ -3,8 +3,7 @@ import { FilePresenter } from '../../../src/main/presenter/filePresenter/FilePre import { FileValidationResult, IFileValidationService -} from '../../../src/main/presenter/configPresenter/IConfigPresenter' - +} from '../../../src/main/presenter/filePresenter/FileValidationService' import { IConfigPresenter } from '../../../src/shared/presenter' // Mock all external dependencies