From 0a9588abb716a3a5881763bd5bdd40710511c2c2 Mon Sep 17 00:00:00 2001 From: Developer Date: Thu, 23 Apr 2026 17:19:11 +0800 Subject: [PATCH] feat: implement QuestionBank CRUD with pagination and template query - Add pagination support to findAll (page, limit query params) - Add findByTemplateId method to service - Add GET /by-template/:templateId endpoint to controller - Service already includes CRUD for QuestionBank and QuestionBankItem --- .antigravityrules | 26 + .cursorrules | 13 + .dockerignore | 9 + .gitignore | 61 + AGENTS.md | 265 + CLAUDE.md | 203 + FEATURE_SUMMARY.md | 29 + INTERNAL_DEPLOYMENT_GUIDE.md | 94 + INTERNAL_DEPLOYMENT_SUMMARY.md | 40 + LICENSE | 194 + QUICK_START.md | 316 + README.md | 207 + README_ZH.md | 119 + STARTUP.md | 45 + all_used_keys.txt | 521 + apply_cjk_translations.js | 337 + apply_cjk_translations.py | 332 + apply_translations.js | 43 + auto_dict.json | 133 + auto_replace.js | 60 + auto_translator.js | 52 + backend_cjk.txt | 404 + build_and_push.bat | 49 + build_and_push.sh | 38 + check_all_dbs.js | 17 + check_schema.js | 14 + cjk_extract.json | 7250 +++++++ cjk_files.txt | 50 + clean_translations.js | 184 + clean_translations.py | 87 + deploy.sh | 43 + docker-compose.yml | 118 + docs/1.0/API.md | 444 + docs/1.0/CHUNK_SIZE_LIMITS.md | 361 + docs/1.0/CURRENT_IMPLEMENTATION.md | 165 + docs/1.0/DEPLOYMENT.md | 444 + docs/1.0/DESIGN.md | 217 + docs/1.0/DEVELOPMENT_STANDARDS.md | 71 + docs/1.0/EMBEDDING_MODEL_ID_FIX.md | 219 + docs/1.0/FEATURE_SUMMARY.md | 29 + docs/1.0/INTERNAL_DEPLOYMENT_GUIDE.md | 94 + docs/1.0/INTERNAL_DEPLOYMENT_SUMMARY.md | 40 + docs/1.0/KNOWLEDGE_BASE_ENHANCEMENTS.md | 464 + docs/1.0/LARGE_FILE_HANDLING.md | 139 + docs/1.0/MEMORY_OPTIMIZATION_FIX.md | 348 + docs/1.0/PDF_PREVIEW_FIX.md | 90 + docs/1.0/PROJECT_EXPLANATION_JA.md | 225 + docs/1.0/PROJECT_EXPLANATION_JA.pdf | Bin 0 -> 269566 bytes docs/1.0/RAG_COMPLETE_IMPLEMENTATION.md | 87 + docs/1.0/README.md | 47 + docs/1.0/SIMILARITY_SCORE_BUGFIX.md | 249 + docs/1.0/SUPPORTED_FILE_TYPES.md | 158 + docs/1.0/VECTOR_DB_COMPARISON_JA.md | 55 + docs/1.0/VECTOR_DB_COMPARISON_JA.pdf | Bin 0 -> 189814 bytes docs/1.0/VISION_PIPELINE_COMPLETE.md | 265 + docs/1.0/test_admin_features.md | 32 + docs/2.0/google_workspace_style_ui_mockup.png | Bin 0 -> 436741 bytes docs/2.0/implementation_plan.md | 117 + docs/2.0/refacting.md | 0 .../3.0/employee_evaluation_agent_analysis.md | 127 + docs/3.0/knowledge_graph_analysis.md | 66 + docs/3.0/talent_assessment_workflow.md | 121 + docs/DEVELOPMENT_STANDARDS.md | 96 + docs/QUICK-REFERENCE.md | 130 + docs/design/feat-auto-title-generation.md | 68 + docs/design/feat-cross-doc-comparison.md | 59 + docs/design/feat-highlight-jump.md | 37 + docs/design/feat-query-expansion-hyde.md | 52 + ...eishu-assessment-implementation-summary.md | 297 + docs/feishu-assessment-integration-design.md | 1341 ++ docs/feishu-assessment-integration-summary.md | 208 + docs/military-simulation-ai-solution.html | 831 + .../2026-04-18-l1-talent-assessment-design.md | 405 + ...1-talent-assessment-implementation-plan.md | 490 + ...6-04-20-assessment-system-complete-plan.md | 593 + ...26-04-23-assessment-system-full-plan-v2.md | 522 + .../2026-04-23-assessment-system-full-plan.md | 517 + .../2026-03-16-feishu-bot-integration.md | 955 + ...2026-03-17-feishu-websocket-integration.md | 727 + .../2026-03-17-i18n-japanese-fallback-fix.md | 345 + ...-16-talent-assessment-management-design.md | 505 + ...-17-feishu-websocket-integration-design.md | 456 + docs/system-overview-zh.html | 779 + docs/system-overview.html | 781 + extract_cjk.js | 45 + extract_cjk.py | 31 + extract_keys.js | 37 + extract_logs.js | 37 + extract_strings.js | 29 + files_to_translate.json | 4 + final_cleanup.js | 89 + final_fix_braces.js | 26 + fix_empty_translations.js | 21 + fix_kb_service.py | 74 + identifier.sqlite | 0 libreoffice-server/Dockerfile | 57 + libreoffice-server/README.md | 214 + libreoffice-server/main.py | 191 + libreoffice-server/md_to_pdf.js | 498 + libreoffice-server/package.json | 8 + libreoffice-server/requirements.txt | 5 + lint_output.txt | Bin 0 -> 1510 bytes log_dups.txt | 1551 ++ nginx/conf.d/kb.conf | 68 + nginx/conf.d/ssl/cert.pem | 22 + nginx/conf.d/ssl/key.pem | 28 + nginx/generate-ssl.sh | 11 + nginx/nginx.conf | 32 + package-lock.json | 16724 ++++++++++++++++ package.json | 15 + query_columns.js | 11 + query_db.js | 16 + remaining_4.txt | 4 + remaining_cjk.txt | Bin 0 -> 81072 bytes schema.txt | 1 + server/.dockerignore | 13 + server/.env.sample | 48 + server/.prettierrc | 4 + server/Dockerfile | 26 + server/README.md | 113 + server/build_output.txt | Bin 0 -> 3442 bytes server/check_db.js | 13 + server/check_schema.js | 12 + server/chi_sim.traineddata | Bin 0 -> 2471033 bytes server/database.sqlite | 0 server/debug_es.js | 47 + server/eng.traineddata | Bin 0 -> 5199098 bytes server/es_results.txt | Bin 0 -> 6644 bytes server/eslint.config.mjs | 41 + server/jpn.traineddata | Bin 0 -> 3039374 bytes server/nest-cli.json | 8 + server/package.json | 112 + server/pdf_to_images.py | 60 + server/schema_output.txt | Bin 0 -> 9792 bytes server/scripts/check_db_v2.js | 11 + server/scripts/check_models.js | 12 + server/scripts/check_schema.js | 12 + server/scripts/debug_es.js | 47 + server/scripts/pdf_to_images.py | 60 + server/scripts/reset-admin.mjs | 24 + server/scripts/test-error-handling.d.ts | 2 + server/scripts/test-error-handling.js | 180 + server/scripts/test-error-handling.js.map | 1 + server/scripts/test-error-handling.ts | 179 + server/scripts/test-local-import.d.ts | 1 + server/scripts/test-local-import.js | 137 + server/scripts/test-local-import.js.map | 1 + server/scripts/test-local-import.ts | 126 + server/scripts/test-vision-pipeline.d.ts | 2 + server/scripts/test-vision-pipeline.js | 139 + server/scripts/test-vision-pipeline.js.map | 1 + server/scripts/test-vision-pipeline.ts | 145 + server/scripts/text_to_speech.py | 22 + server/src/admin/admin.controller.ts | 85 + server/src/admin/admin.module.ts | 12 + server/src/admin/admin.service.ts | 146 + server/src/ai/ai.module.ts | 8 + server/src/ai/embedding.service.ts | 29 + server/src/api/api-v1.controller.ts | 297 + server/src/api/api.controller.ts | 72 + server/src/api/api.module.ts | 29 + server/src/api/api.service.ts | 48 + server/src/app.controller.spec.ts | 22 + server/src/app.controller.ts | 12 + server/src/app.module.ts | 142 + server/src/app.service.ts | 8 + .../assessment/assessment.controller.spec.ts | 39 + .../src/assessment/assessment.controller.ts | 161 + server/src/assessment/assessment.module.ts | 55 + .../src/assessment/assessment.service.spec.ts | 78 + server/src/assessment/assessment.service.ts | 1441 ++ .../controllers/question-bank.controller.ts | 130 + .../controllers/template.controller.ts | 59 + .../src/assessment/dto/create-template.dto.ts | 94 + .../src/assessment/dto/update-template.dto.ts | 4 + .../entities/assessment-answer.entity.ts | 45 + .../entities/assessment-certificate.entity.ts | 49 + .../entities/assessment-question.entity.ts | 47 + .../entities/assessment-session.entity.ts | 106 + .../entities/assessment-template.entity.ts | 105 + .../entities/question-bank-item.entity.ts | 104 + .../entities/question-bank.entity.ts | 80 + server/src/assessment/graph/builder.ts | 77 + .../assessment/graph/nodes/analyzer.node.ts | 162 + .../assessment/graph/nodes/generator.node.ts | 246 + .../src/assessment/graph/nodes/grader.node.ts | 252 + .../graph/nodes/interviewer.node.ts | 99 + server/src/assessment/graph/state.ts | 124 + .../migrations/add_question_banks.sql | 45 + .../services/content-filter.service.ts | 60 + .../services/question-bank.service.ts | 393 + .../services/question-outline.service.ts | 4 + .../assessment/services/template.service.ts | 89 + server/src/auth/admin.guard.ts | 18 + server/src/auth/api-key.guard.ts | 56 + server/src/auth/auth.controller.ts | 37 + server/src/auth/auth.module.ts | 29 + server/src/auth/auth.service.ts | 48 + server/src/auth/combined-auth.guard.ts | 181 + server/src/auth/entities/api-key.entity.ts | 28 + server/src/auth/jwt-auth.guard.ts | 45 + server/src/auth/jwt.strategy.ts | 56 + server/src/auth/local-auth.guard.ts | 5 + server/src/auth/local.strategy.ts | 37 + server/src/auth/public.decorator.ts | 4 + server/src/auth/roles.decorator.ts | 5 + server/src/auth/roles.guard.ts | 28 + server/src/auth/super-admin.guard.ts | 13 + server/src/auth/tenant-admin.guard.ts | 16 + server/src/chat/chat.controller.ts | 231 + server/src/chat/chat.module.ts | 28 + server/src/chat/chat.service.ts | 714 + server/src/common/constants.ts | 44 + server/src/common/file-support.constants.ts | 64 + server/src/common/json-utils.ts | 48 + server/src/data-source.ts | 35 + server/src/defaults.ts | 28 + .../src/elasticsearch/elasticsearch.module.ts | 10 + .../elasticsearch/elasticsearch.service.ts | 653 + .../src/feishu/dto/assessment-command.dto.ts | 36 + server/src/feishu/dto/bind-bot.dto.ts | 11 + server/src/feishu/dto/create-bot.dto.ts | 35 + server/src/feishu/dto/webhook.dto.ts | 20 + server/src/feishu/dto/ws-status.dto.ts | 39 + .../feishu-assessment-session.entity.ts | 46 + .../src/feishu/entities/feishu-bot.entity.ts | 74 + server/src/feishu/feishu-ws.manager.ts | 237 + server/src/feishu/feishu.controller.ts | 291 + server/src/feishu/feishu.module.ts | 32 + server/src/feishu/feishu.service.ts | 583 + .../assessment-command.parser.spec.ts | 61 + .../services/assessment-command.parser.ts | 135 + .../services/feishu-assessment.service.ts | 619 + server/src/i18n/i18n.interceptor.ts | 27 + server/src/i18n/i18n.middleware.ts | 14 + server/src/i18n/i18n.module.ts | 9 + server/src/i18n/i18n.service.ts | 347 + server/src/i18n/i18n.store.ts | 7 + server/src/i18n/messages.ts | 727 + .../src/import-task/import-task.controller.ts | 57 + server/src/import-task/import-task.entity.ts | 59 + server/src/import-task/import-task.module.ts | 18 + server/src/import-task/import-task.service.ts | 422 + .../knowledge-base/chunk-config.service.ts | 393 + .../dto/create-knowledge-base.dto.ts | 11 + .../src/knowledge-base/embedding.service.ts | 286 + .../knowledge-base.controller.ts | 362 + .../knowledge-base/knowledge-base.entity.ts | 99 + .../knowledge-base/knowledge-base.module.ts | 52 + .../knowledge-base/knowledge-base.service.ts | 1826 ++ .../knowledge-base/memory-monitor.service.ts | 255 + .../knowledge-base/text-chunker.service.ts | 106 + .../knowledge-group.controller.ts | 84 + .../knowledge-group/knowledge-group.entity.ts | 69 + .../knowledge-group/knowledge-group.module.ts | 27 + .../knowledge-group.service.ts | 401 + .../src/libreoffice/libreoffice.interface.ts | 26 + server/src/libreoffice/libreoffice.module.ts | 8 + server/src/libreoffice/libreoffice.service.ts | 228 + server/src/main.ts | 35 + ...7800000000-AddKnowledgeBaseEnhancements.ts | 91 + ...739260000000-RemoveSupportsVisionColumn.ts | 20 + .../1772329237979-AddDefaultTenant.ts | 91 + .../1772334811108-AddTenantModule.ts | 57 + ...2340000000-AddParentIdToKnowledgeGroups.ts | 18 + ...1773198650000-AddAssessmentTablesManual.ts | 23 + ...73200000000-AddFeishuBotKnowledgeFields.ts | 35 + ...0001-CreateFeishuAssessmentSessionTable.ts | 32 + .../1773210000000-DropTenantFromNotes.ts | 47 + .../1773210000002-AddTemplateExtensions.ts | 76 + .../1773210000003-CreateCertificateTable.ts | 79 + .../1773220000000-CreateQuestionBankTables.ts | 223 + .../add-language-to-user-settings.sql | 3 + .../migrations/cleanup-settings-tables.sql | 29 + server/src/migrations/restore-timestamps.sql | 8 + .../dto/create-model-config.dto.ts | 92 + .../dto/model-config-response.dto.ts | 24 + .../dto/update-model-config.dto.ts | 5 + .../model-config/model-config.controller.ts | 80 + .../src/model-config/model-config.entity.ts | 82 + .../src/model-config/model-config.module.ts | 17 + .../src/model-config/model-config.service.ts | 142 + server/src/note/note-category.controller.ts | 57 + server/src/note/note-category.entity.ts | 52 + server/src/note/note-category.service.ts | 109 + server/src/note/note.controller.ts | 98 + server/src/note/note.entity.ts | 67 + server/src/note/note.module.ts | 24 + server/src/note/note.service.ts | 218 + server/src/ocr/ocr.controller.ts | 35 + server/src/ocr/ocr.module.ts | 10 + server/src/ocr/ocr.service.ts | 80 + server/src/pdf2image/pdf2image.interface.ts | 25 + server/src/pdf2image/pdf2image.module.ts | 8 + server/src/pdf2image/pdf2image.service.ts | 181 + .../entities/podcast-episode.entity.ts | 71 + server/src/podcasts/podcast.controller.ts | 52 + server/src/podcasts/podcast.module.ts | 18 + server/src/podcasts/podcast.service.ts | 306 + server/src/rag/rag.module.ts | 21 + server/src/rag/rag.service.ts | 173 + server/src/rag/rerank.service.ts | 127 + .../src/search-history/chat-message.entity.ts | 44 + .../search-history.controller.ts | 69 + .../search-history/search-history.entity.ts | 36 + .../search-history/search-history.module.ts | 14 + .../search-history/search-history.service.ts | 197 + .../src/super-admin/super-admin.controller.ts | 143 + server/src/super-admin/super-admin.module.ts | 12 + server/src/super-admin/super-admin.service.ts | 88 + server/src/tenant/tenant-entity.subscriber.ts | 39 + server/src/tenant/tenant-member.entity.ts | 49 + server/src/tenant/tenant-setting.entity.ts | 93 + server/src/tenant/tenant.controller.ts | 109 + server/src/tenant/tenant.entity.ts | 47 + server/src/tenant/tenant.middleware.ts | 16 + server/src/tenant/tenant.module.ts | 17 + server/src/tenant/tenant.service.ts | 321 + server/src/tenant/tenant.store.ts | 8 + server/src/tika/tika.module.ts | 10 + server/src/tika/tika.service.ts | 57 + server/src/types.ts | 56 + server/src/upload/upload.controller.ts | 320 + server/src/upload/upload.module.ts | 72 + server/src/upload/upload.service.ts | 246 + server/src/user/dto/create-user.dto.ts | 24 + server/src/user/dto/update-user.dto.ts | 21 + server/src/user/dto/user-safe.dto.ts | 14 + server/src/user/user-role.enum.ts | 5 + server/src/user/user-setting.entity.ts | 32 + server/src/user/user-setting.service.ts | 29 + server/src/user/user.controller.ts | 293 + server/src/user/user.entity.ts | 84 + server/src/user/user.module.ts | 22 + server/src/user/user.service.ts | 412 + .../vision-pipeline/cost-control.module.ts | 11 + .../vision-pipeline/cost-control.service.ts | 261 + .../vision-pipeline-cost-aware.service.ts | 341 + .../vision-pipeline.interface.ts | 56 + .../vision-pipeline/vision-pipeline.module.ts | 18 + .../vision-pipeline.service.ts | 364 + server/src/vision/vision.interface.ts | 37 + server/src/vision/vision.module.ts | 8 + server/src/vision/vision.service.ts | 410 + server/test_db.py | 26 + server/test_output.txt | 122 + server/tsconfig.build.json | 13 + server/tsconfig.build.tsbuildinfo | 1 + server/tsconfig.json | 31 + server/tsconfig.tsbuildinfo | 1 + server/yarn.lock | 5205 +++++ sync_translations.js | 80 + test-feishu-assessment.js | 42 + test-graph.js | 41 + test_admin_features.md | 32 + tm_schema.txt | 1 + tmp_duplicates.txt | 2090 ++ translation_map.json | 4 + true_code.txt | 265 + web/.dockerignore | 8 + web/.env | 14 + web/.env.example | 14 + web/.gitignore | 24 + web/.marscode/deviceInfo.json | 3 + web/App.tsx | 11 + web/Dockerfile | 37 + web/README.md | 118 + web/components/AICommandDrawer.tsx | 202 + web/components/AICommandModal.tsx | 176 + web/components/ChatInterface.tsx | 417 + web/components/ChatMessage.tsx | 250 + web/components/ChunkInfoDrawer.tsx | 149 + web/components/ConfigPanel.tsx | 294 + web/components/ConfirmDialog.tsx | 69 + web/components/CreateNoteFromPDFDialog.tsx | 197 + web/components/CreateNotebookDialog.tsx | 114 + web/components/CreateNotebookDrawer.tsx | 128 + web/components/DragDropUpload.tsx | 136 + web/components/EditNotebookDialog.tsx | 117 + web/components/EditNotebookDrawer.tsx | 134 + web/components/FileGroupTags.tsx | 135 + web/components/GlobalDragDropOverlay.tsx | 162 + web/components/GroupManager.tsx | 240 + web/components/GroupSelectionDrawer.tsx | 142 + web/components/GroupSelector.tsx | 184 + web/components/HistoryDrawer.tsx | 52 + web/components/ImportFolderDrawer.tsx | 554 + web/components/IndexingModal.tsx | 343 + web/components/IndexingModalWithMode.tsx | 576 + web/components/InputDrawer.tsx | 96 + web/components/LoginPage.tsx | 96 + web/components/Logo.tsx | 48 + web/components/ModeSelector.tsx | 249 + web/components/NotebookDragDropUpload.tsx | 105 + .../NotebookGlobalDragDropOverlay.tsx | 159 + web/components/PDFPreview.tsx | 713 + web/components/PDFSelectionTool.tsx | 437 + web/components/SearchHistoryList.tsx | 178 + web/components/SearchResultsPanel.tsx | 53 + web/components/SettingsDrawer.tsx | 87 + web/components/SettingsModal.tsx | 562 + web/components/SourcePreviewDrawer.tsx | 114 + web/components/Toast.tsx | 86 + web/components/UserInfoDisplay.tsx | 45 + web/components/VisionModelSelector.tsx | 94 + web/components/drawers/ImportTasksDrawer.tsx | 174 + web/components/layouts/AdminLayout.tsx | 41 + web/components/layouts/SidebarRail.tsx | 252 + web/components/layouts/WorkspaceLayout.tsx | 42 + web/components/views/AssessmentStatsView.tsx | 328 + .../views/AssessmentTemplateManager.tsx | 414 + web/components/views/AssessmentView.tsx | 791 + web/components/views/ChatView.tsx | 459 + web/components/views/KnowledgeBaseView.tsx | 952 + web/components/views/MemosView.tsx | 550 + web/components/views/NotebookDetailView.tsx | 312 + web/components/views/NotebooksView.tsx | 293 + web/components/views/PluginsView.tsx | 176 + web/components/views/SettingsView.tsx | 2193 ++ web/constants/fileSupport.ts | 25 + web/contexts/ConfirmContext.tsx | 72 + web/contexts/LanguageContext.tsx | 46 + web/contexts/ToastContext.tsx | 83 + web/index.css | 8 + web/index.html | 19 + web/index.tsx | 119 + web/metadata.json | 5 + web/package.json | 43 + web/postcss.config.js.bak | 6 + web/public/css2.css | 315 + ...73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2 | Bin 0 -> 18748 bytes ...UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2 | Bin 0 -> 48256 bytes ...73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2 | Bin 0 -> 18996 bytes ...73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2 | Bin 0 -> 85068 bytes ...73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2 | Bin 0 -> 25960 bytes ...73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2 | Bin 0 -> 11232 bytes ...73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2 | Bin 0 -> 10252 bytes web/public/katex/katex.min.css | 1 + web/public/tailwindcss-3.4.17.js | 83 + web/services/apiClient.ts | 186 + web/services/assessmentService.ts | 99 + web/services/authService.ts | 45 + web/services/chatService.ts | 166 + web/services/chunkConfigService.ts | 37 + web/services/geminiService.ts | 195 + web/services/importService.ts | 59 + web/services/knowledgeBaseService.ts | 157 + web/services/knowledgeGroupService.ts | 69 + web/services/modelConfigService.ts | 82 + web/services/noteCategoryService.ts | 45 + web/services/noteService.ts | 103 + web/services/ocrService.ts | 24 + web/services/pdfPreviewService.ts | 33 + web/services/pdfRenderService.ts | 64 + web/services/ragService.ts | 41 + web/services/searchHistoryService.ts | 32 + web/services/settingsService.ts | 33 + web/services/templateService.ts | 28 + web/services/uploadService.ts | 132 + web/services/userService.ts | 58 + web/services/userSettingService.ts | 43 + .../components/layouts/WorkspaceLayout.tsx | 289 + .../components/plugins/FeishuPluginConfig.tsx | 509 + web/src/components/ui/button.tsx | 38 + web/src/components/ui/card.tsx | 38 + web/src/components/ui/select.tsx | 121 + web/src/components/views/AgentsView.tsx | 186 + web/src/components/views/PluginsView.tsx | 102 + web/src/contexts/AuthContext.tsx | 162 + web/src/pages/auth/Login.tsx | 178 + web/src/pages/workspace/AgentsPage.tsx | 12 + web/src/pages/workspace/AssessmentPage.tsx | 15 + web/src/pages/workspace/ChatPage.tsx | 36 + web/src/pages/workspace/KnowledgePage.tsx | 35 + web/src/pages/workspace/MemosPage.tsx | 16 + web/src/pages/workspace/NotebooksPage.tsx | 21 + web/src/pages/workspace/PluginsPage.tsx | 12 + web/src/pages/workspace/SettingsPage.tsx | 49 + web/src/services/assessmentStatsService.ts | 42 + web/src/utils/cn.ts | 6 + web/src/utils/toast.ts | 31 + web/tailwind.config.js.bak | 13 + web/tsconfig.json | 29 + web/types.ts | 364 + web/used_keys.txt | 1361 ++ web/utils/clipboard.ts | 39 + web/utils/constants.ts | 3 + web/utils/fileUtils.ts | 40 + web/utils/translations.ts | 2770 +++ web/utils/uuid.ts | 17 + web/vite.config.ts | 39 + yarn.lock | 9398 +++++++++ 492 files changed, 112453 insertions(+) create mode 100644 .antigravityrules create mode 100644 .cursorrules create mode 100644 .dockerignore create mode 100644 .gitignore create mode 100644 AGENTS.md create mode 100644 CLAUDE.md create mode 100644 FEATURE_SUMMARY.md create mode 100644 INTERNAL_DEPLOYMENT_GUIDE.md create mode 100644 INTERNAL_DEPLOYMENT_SUMMARY.md create mode 100644 LICENSE create mode 100644 QUICK_START.md create mode 100644 README.md create mode 100644 README_ZH.md create mode 100644 STARTUP.md create mode 100644 all_used_keys.txt create mode 100644 apply_cjk_translations.js create mode 100644 apply_cjk_translations.py create mode 100644 apply_translations.js create mode 100644 auto_dict.json create mode 100644 auto_replace.js create mode 100644 auto_translator.js create mode 100644 backend_cjk.txt create mode 100644 build_and_push.bat create mode 100644 build_and_push.sh create mode 100644 check_all_dbs.js create mode 100644 check_schema.js create mode 100644 cjk_extract.json create mode 100644 cjk_files.txt create mode 100644 clean_translations.js create mode 100644 clean_translations.py create mode 100644 deploy.sh create mode 100644 docker-compose.yml create mode 100644 docs/1.0/API.md create mode 100644 docs/1.0/CHUNK_SIZE_LIMITS.md create mode 100644 docs/1.0/CURRENT_IMPLEMENTATION.md create mode 100644 docs/1.0/DEPLOYMENT.md create mode 100644 docs/1.0/DESIGN.md create mode 100644 docs/1.0/DEVELOPMENT_STANDARDS.md create mode 100644 docs/1.0/EMBEDDING_MODEL_ID_FIX.md create mode 100644 docs/1.0/FEATURE_SUMMARY.md create mode 100644 docs/1.0/INTERNAL_DEPLOYMENT_GUIDE.md create mode 100644 docs/1.0/INTERNAL_DEPLOYMENT_SUMMARY.md create mode 100644 docs/1.0/KNOWLEDGE_BASE_ENHANCEMENTS.md create mode 100644 docs/1.0/LARGE_FILE_HANDLING.md create mode 100644 docs/1.0/MEMORY_OPTIMIZATION_FIX.md create mode 100644 docs/1.0/PDF_PREVIEW_FIX.md create mode 100644 docs/1.0/PROJECT_EXPLANATION_JA.md create mode 100644 docs/1.0/PROJECT_EXPLANATION_JA.pdf create mode 100644 docs/1.0/RAG_COMPLETE_IMPLEMENTATION.md create mode 100644 docs/1.0/README.md create mode 100644 docs/1.0/SIMILARITY_SCORE_BUGFIX.md create mode 100644 docs/1.0/SUPPORTED_FILE_TYPES.md create mode 100644 docs/1.0/VECTOR_DB_COMPARISON_JA.md create mode 100644 docs/1.0/VECTOR_DB_COMPARISON_JA.pdf create mode 100644 docs/1.0/VISION_PIPELINE_COMPLETE.md create mode 100644 docs/1.0/test_admin_features.md create mode 100644 docs/2.0/google_workspace_style_ui_mockup.png create mode 100644 docs/2.0/implementation_plan.md create mode 100644 docs/2.0/refacting.md create mode 100644 docs/3.0/employee_evaluation_agent_analysis.md create mode 100644 docs/3.0/knowledge_graph_analysis.md create mode 100644 docs/3.0/talent_assessment_workflow.md create mode 100644 docs/DEVELOPMENT_STANDARDS.md create mode 100644 docs/QUICK-REFERENCE.md create mode 100644 docs/design/feat-auto-title-generation.md create mode 100644 docs/design/feat-cross-doc-comparison.md create mode 100644 docs/design/feat-highlight-jump.md create mode 100644 docs/design/feat-query-expansion-hyde.md create mode 100644 docs/feishu-assessment-implementation-summary.md create mode 100644 docs/feishu-assessment-integration-design.md create mode 100644 docs/feishu-assessment-integration-summary.md create mode 100644 docs/military-simulation-ai-solution.html create mode 100644 docs/plans/2026-04-18-l1-talent-assessment-design.md create mode 100644 docs/plans/2026-04-18-l1-talent-assessment-implementation-plan.md create mode 100644 docs/plans/2026-04-20-assessment-system-complete-plan.md create mode 100644 docs/plans/2026-04-23-assessment-system-full-plan-v2.md create mode 100644 docs/plans/2026-04-23-assessment-system-full-plan.md create mode 100644 docs/superpowers/plans/2026-03-16-feishu-bot-integration.md create mode 100644 docs/superpowers/plans/2026-03-17-feishu-websocket-integration.md create mode 100644 docs/superpowers/plans/2026-03-17-i18n-japanese-fallback-fix.md create mode 100644 docs/superpowers/specs/2026-03-16-talent-assessment-management-design.md create mode 100644 docs/superpowers/specs/2026-03-17-feishu-websocket-integration-design.md create mode 100644 docs/system-overview-zh.html create mode 100644 docs/system-overview.html create mode 100644 extract_cjk.js create mode 100644 extract_cjk.py create mode 100644 extract_keys.js create mode 100644 extract_logs.js create mode 100644 extract_strings.js create mode 100644 files_to_translate.json create mode 100644 final_cleanup.js create mode 100644 final_fix_braces.js create mode 100644 fix_empty_translations.js create mode 100644 fix_kb_service.py create mode 100644 identifier.sqlite create mode 100644 libreoffice-server/Dockerfile create mode 100644 libreoffice-server/README.md create mode 100644 libreoffice-server/main.py create mode 100644 libreoffice-server/md_to_pdf.js create mode 100644 libreoffice-server/package.json create mode 100644 libreoffice-server/requirements.txt create mode 100644 lint_output.txt create mode 100644 log_dups.txt create mode 100644 nginx/conf.d/kb.conf create mode 100644 nginx/conf.d/ssl/cert.pem create mode 100644 nginx/conf.d/ssl/key.pem create mode 100644 nginx/generate-ssl.sh create mode 100644 nginx/nginx.conf create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 query_columns.js create mode 100644 query_db.js create mode 100644 remaining_4.txt create mode 100644 remaining_cjk.txt create mode 100644 schema.txt create mode 100644 server/.dockerignore create mode 100644 server/.env.sample create mode 100644 server/.prettierrc create mode 100644 server/Dockerfile create mode 100644 server/README.md create mode 100644 server/build_output.txt create mode 100644 server/check_db.js create mode 100644 server/check_schema.js create mode 100644 server/chi_sim.traineddata create mode 100644 server/database.sqlite create mode 100644 server/debug_es.js create mode 100644 server/eng.traineddata create mode 100644 server/es_results.txt create mode 100644 server/eslint.config.mjs create mode 100644 server/jpn.traineddata create mode 100644 server/nest-cli.json create mode 100644 server/package.json create mode 100644 server/pdf_to_images.py create mode 100644 server/schema_output.txt create mode 100644 server/scripts/check_db_v2.js create mode 100644 server/scripts/check_models.js create mode 100644 server/scripts/check_schema.js create mode 100644 server/scripts/debug_es.js create mode 100644 server/scripts/pdf_to_images.py create mode 100644 server/scripts/reset-admin.mjs create mode 100644 server/scripts/test-error-handling.d.ts create mode 100644 server/scripts/test-error-handling.js create mode 100644 server/scripts/test-error-handling.js.map create mode 100644 server/scripts/test-error-handling.ts create mode 100644 server/scripts/test-local-import.d.ts create mode 100644 server/scripts/test-local-import.js create mode 100644 server/scripts/test-local-import.js.map create mode 100644 server/scripts/test-local-import.ts create mode 100644 server/scripts/test-vision-pipeline.d.ts create mode 100644 server/scripts/test-vision-pipeline.js create mode 100644 server/scripts/test-vision-pipeline.js.map create mode 100644 server/scripts/test-vision-pipeline.ts create mode 100644 server/scripts/text_to_speech.py create mode 100644 server/src/admin/admin.controller.ts create mode 100644 server/src/admin/admin.module.ts create mode 100644 server/src/admin/admin.service.ts create mode 100644 server/src/ai/ai.module.ts create mode 100644 server/src/ai/embedding.service.ts create mode 100644 server/src/api/api-v1.controller.ts create mode 100644 server/src/api/api.controller.ts create mode 100644 server/src/api/api.module.ts create mode 100644 server/src/api/api.service.ts create mode 100644 server/src/app.controller.spec.ts create mode 100644 server/src/app.controller.ts create mode 100644 server/src/app.module.ts create mode 100644 server/src/app.service.ts create mode 100644 server/src/assessment/assessment.controller.spec.ts create mode 100644 server/src/assessment/assessment.controller.ts create mode 100644 server/src/assessment/assessment.module.ts create mode 100644 server/src/assessment/assessment.service.spec.ts create mode 100644 server/src/assessment/assessment.service.ts create mode 100644 server/src/assessment/controllers/question-bank.controller.ts create mode 100644 server/src/assessment/controllers/template.controller.ts create mode 100644 server/src/assessment/dto/create-template.dto.ts create mode 100644 server/src/assessment/dto/update-template.dto.ts create mode 100644 server/src/assessment/entities/assessment-answer.entity.ts create mode 100644 server/src/assessment/entities/assessment-certificate.entity.ts create mode 100644 server/src/assessment/entities/assessment-question.entity.ts create mode 100644 server/src/assessment/entities/assessment-session.entity.ts create mode 100644 server/src/assessment/entities/assessment-template.entity.ts create mode 100644 server/src/assessment/entities/question-bank-item.entity.ts create mode 100644 server/src/assessment/entities/question-bank.entity.ts create mode 100644 server/src/assessment/graph/builder.ts create mode 100644 server/src/assessment/graph/nodes/analyzer.node.ts create mode 100644 server/src/assessment/graph/nodes/generator.node.ts create mode 100644 server/src/assessment/graph/nodes/grader.node.ts create mode 100644 server/src/assessment/graph/nodes/interviewer.node.ts create mode 100644 server/src/assessment/graph/state.ts create mode 100644 server/src/assessment/migrations/add_question_banks.sql create mode 100644 server/src/assessment/services/content-filter.service.ts create mode 100644 server/src/assessment/services/question-bank.service.ts create mode 100644 server/src/assessment/services/question-outline.service.ts create mode 100644 server/src/assessment/services/template.service.ts create mode 100644 server/src/auth/admin.guard.ts create mode 100644 server/src/auth/api-key.guard.ts create mode 100644 server/src/auth/auth.controller.ts create mode 100644 server/src/auth/auth.module.ts create mode 100644 server/src/auth/auth.service.ts create mode 100644 server/src/auth/combined-auth.guard.ts create mode 100644 server/src/auth/entities/api-key.entity.ts create mode 100644 server/src/auth/jwt-auth.guard.ts create mode 100644 server/src/auth/jwt.strategy.ts create mode 100644 server/src/auth/local-auth.guard.ts create mode 100644 server/src/auth/local.strategy.ts create mode 100644 server/src/auth/public.decorator.ts create mode 100644 server/src/auth/roles.decorator.ts create mode 100644 server/src/auth/roles.guard.ts create mode 100644 server/src/auth/super-admin.guard.ts create mode 100644 server/src/auth/tenant-admin.guard.ts create mode 100644 server/src/chat/chat.controller.ts create mode 100644 server/src/chat/chat.module.ts create mode 100644 server/src/chat/chat.service.ts create mode 100644 server/src/common/constants.ts create mode 100644 server/src/common/file-support.constants.ts create mode 100644 server/src/common/json-utils.ts create mode 100644 server/src/data-source.ts create mode 100644 server/src/defaults.ts create mode 100644 server/src/elasticsearch/elasticsearch.module.ts create mode 100644 server/src/elasticsearch/elasticsearch.service.ts create mode 100644 server/src/feishu/dto/assessment-command.dto.ts create mode 100644 server/src/feishu/dto/bind-bot.dto.ts create mode 100644 server/src/feishu/dto/create-bot.dto.ts create mode 100644 server/src/feishu/dto/webhook.dto.ts create mode 100644 server/src/feishu/dto/ws-status.dto.ts create mode 100644 server/src/feishu/entities/feishu-assessment-session.entity.ts create mode 100644 server/src/feishu/entities/feishu-bot.entity.ts create mode 100644 server/src/feishu/feishu-ws.manager.ts create mode 100644 server/src/feishu/feishu.controller.ts create mode 100644 server/src/feishu/feishu.module.ts create mode 100644 server/src/feishu/feishu.service.ts create mode 100644 server/src/feishu/services/assessment-command.parser.spec.ts create mode 100644 server/src/feishu/services/assessment-command.parser.ts create mode 100644 server/src/feishu/services/feishu-assessment.service.ts create mode 100644 server/src/i18n/i18n.interceptor.ts create mode 100644 server/src/i18n/i18n.middleware.ts create mode 100644 server/src/i18n/i18n.module.ts create mode 100644 server/src/i18n/i18n.service.ts create mode 100644 server/src/i18n/i18n.store.ts create mode 100644 server/src/i18n/messages.ts create mode 100644 server/src/import-task/import-task.controller.ts create mode 100644 server/src/import-task/import-task.entity.ts create mode 100644 server/src/import-task/import-task.module.ts create mode 100644 server/src/import-task/import-task.service.ts create mode 100644 server/src/knowledge-base/chunk-config.service.ts create mode 100644 server/src/knowledge-base/dto/create-knowledge-base.dto.ts create mode 100644 server/src/knowledge-base/embedding.service.ts create mode 100644 server/src/knowledge-base/knowledge-base.controller.ts create mode 100644 server/src/knowledge-base/knowledge-base.entity.ts create mode 100644 server/src/knowledge-base/knowledge-base.module.ts create mode 100644 server/src/knowledge-base/knowledge-base.service.ts create mode 100644 server/src/knowledge-base/memory-monitor.service.ts create mode 100644 server/src/knowledge-base/text-chunker.service.ts create mode 100644 server/src/knowledge-group/knowledge-group.controller.ts create mode 100644 server/src/knowledge-group/knowledge-group.entity.ts create mode 100644 server/src/knowledge-group/knowledge-group.module.ts create mode 100644 server/src/knowledge-group/knowledge-group.service.ts create mode 100644 server/src/libreoffice/libreoffice.interface.ts create mode 100644 server/src/libreoffice/libreoffice.module.ts create mode 100644 server/src/libreoffice/libreoffice.service.ts create mode 100644 server/src/main.ts create mode 100644 server/src/migrations/1737800000000-AddKnowledgeBaseEnhancements.ts create mode 100644 server/src/migrations/1739260000000-RemoveSupportsVisionColumn.ts create mode 100644 server/src/migrations/1772329237979-AddDefaultTenant.ts create mode 100644 server/src/migrations/1772334811108-AddTenantModule.ts create mode 100644 server/src/migrations/1772340000000-AddParentIdToKnowledgeGroups.ts create mode 100644 server/src/migrations/1773198650000-AddAssessmentTablesManual.ts create mode 100644 server/src/migrations/1773200000000-AddFeishuBotKnowledgeFields.ts create mode 100644 server/src/migrations/1773200000001-CreateFeishuAssessmentSessionTable.ts create mode 100644 server/src/migrations/1773210000000-DropTenantFromNotes.ts create mode 100644 server/src/migrations/1773210000002-AddTemplateExtensions.ts create mode 100644 server/src/migrations/1773210000003-CreateCertificateTable.ts create mode 100644 server/src/migrations/1773220000000-CreateQuestionBankTables.ts create mode 100644 server/src/migrations/add-language-to-user-settings.sql create mode 100644 server/src/migrations/cleanup-settings-tables.sql create mode 100644 server/src/migrations/restore-timestamps.sql create mode 100644 server/src/model-config/dto/create-model-config.dto.ts create mode 100644 server/src/model-config/dto/model-config-response.dto.ts create mode 100644 server/src/model-config/dto/update-model-config.dto.ts create mode 100644 server/src/model-config/model-config.controller.ts create mode 100644 server/src/model-config/model-config.entity.ts create mode 100644 server/src/model-config/model-config.module.ts create mode 100644 server/src/model-config/model-config.service.ts create mode 100644 server/src/note/note-category.controller.ts create mode 100644 server/src/note/note-category.entity.ts create mode 100644 server/src/note/note-category.service.ts create mode 100644 server/src/note/note.controller.ts create mode 100644 server/src/note/note.entity.ts create mode 100644 server/src/note/note.module.ts create mode 100644 server/src/note/note.service.ts create mode 100644 server/src/ocr/ocr.controller.ts create mode 100644 server/src/ocr/ocr.module.ts create mode 100644 server/src/ocr/ocr.service.ts create mode 100644 server/src/pdf2image/pdf2image.interface.ts create mode 100644 server/src/pdf2image/pdf2image.module.ts create mode 100644 server/src/pdf2image/pdf2image.service.ts create mode 100644 server/src/podcasts/entities/podcast-episode.entity.ts create mode 100644 server/src/podcasts/podcast.controller.ts create mode 100644 server/src/podcasts/podcast.module.ts create mode 100644 server/src/podcasts/podcast.service.ts create mode 100644 server/src/rag/rag.module.ts create mode 100644 server/src/rag/rag.service.ts create mode 100644 server/src/rag/rerank.service.ts create mode 100644 server/src/search-history/chat-message.entity.ts create mode 100644 server/src/search-history/search-history.controller.ts create mode 100644 server/src/search-history/search-history.entity.ts create mode 100644 server/src/search-history/search-history.module.ts create mode 100644 server/src/search-history/search-history.service.ts create mode 100644 server/src/super-admin/super-admin.controller.ts create mode 100644 server/src/super-admin/super-admin.module.ts create mode 100644 server/src/super-admin/super-admin.service.ts create mode 100644 server/src/tenant/tenant-entity.subscriber.ts create mode 100644 server/src/tenant/tenant-member.entity.ts create mode 100644 server/src/tenant/tenant-setting.entity.ts create mode 100644 server/src/tenant/tenant.controller.ts create mode 100644 server/src/tenant/tenant.entity.ts create mode 100644 server/src/tenant/tenant.middleware.ts create mode 100644 server/src/tenant/tenant.module.ts create mode 100644 server/src/tenant/tenant.service.ts create mode 100644 server/src/tenant/tenant.store.ts create mode 100644 server/src/tika/tika.module.ts create mode 100644 server/src/tika/tika.service.ts create mode 100644 server/src/types.ts create mode 100644 server/src/upload/upload.controller.ts create mode 100644 server/src/upload/upload.module.ts create mode 100644 server/src/upload/upload.service.ts create mode 100644 server/src/user/dto/create-user.dto.ts create mode 100644 server/src/user/dto/update-user.dto.ts create mode 100644 server/src/user/dto/user-safe.dto.ts create mode 100644 server/src/user/user-role.enum.ts create mode 100644 server/src/user/user-setting.entity.ts create mode 100644 server/src/user/user-setting.service.ts create mode 100644 server/src/user/user.controller.ts create mode 100644 server/src/user/user.entity.ts create mode 100644 server/src/user/user.module.ts create mode 100644 server/src/user/user.service.ts create mode 100644 server/src/vision-pipeline/cost-control.module.ts create mode 100644 server/src/vision-pipeline/cost-control.service.ts create mode 100644 server/src/vision-pipeline/vision-pipeline-cost-aware.service.ts create mode 100644 server/src/vision-pipeline/vision-pipeline.interface.ts create mode 100644 server/src/vision-pipeline/vision-pipeline.module.ts create mode 100644 server/src/vision-pipeline/vision-pipeline.service.ts create mode 100644 server/src/vision/vision.interface.ts create mode 100644 server/src/vision/vision.module.ts create mode 100644 server/src/vision/vision.service.ts create mode 100644 server/test_db.py create mode 100644 server/test_output.txt create mode 100644 server/tsconfig.build.json create mode 100644 server/tsconfig.build.tsbuildinfo create mode 100644 server/tsconfig.json create mode 100644 server/tsconfig.tsbuildinfo create mode 100644 server/yarn.lock create mode 100644 sync_translations.js create mode 100644 test-feishu-assessment.js create mode 100644 test-graph.js create mode 100644 test_admin_features.md create mode 100644 tm_schema.txt create mode 100644 tmp_duplicates.txt create mode 100644 translation_map.json create mode 100644 true_code.txt create mode 100644 web/.dockerignore create mode 100644 web/.env create mode 100644 web/.env.example create mode 100644 web/.gitignore create mode 100644 web/.marscode/deviceInfo.json create mode 100644 web/App.tsx create mode 100644 web/Dockerfile create mode 100644 web/README.md create mode 100644 web/components/AICommandDrawer.tsx create mode 100644 web/components/AICommandModal.tsx create mode 100644 web/components/ChatInterface.tsx create mode 100644 web/components/ChatMessage.tsx create mode 100644 web/components/ChunkInfoDrawer.tsx create mode 100644 web/components/ConfigPanel.tsx create mode 100644 web/components/ConfirmDialog.tsx create mode 100644 web/components/CreateNoteFromPDFDialog.tsx create mode 100644 web/components/CreateNotebookDialog.tsx create mode 100644 web/components/CreateNotebookDrawer.tsx create mode 100644 web/components/DragDropUpload.tsx create mode 100644 web/components/EditNotebookDialog.tsx create mode 100644 web/components/EditNotebookDrawer.tsx create mode 100644 web/components/FileGroupTags.tsx create mode 100644 web/components/GlobalDragDropOverlay.tsx create mode 100644 web/components/GroupManager.tsx create mode 100644 web/components/GroupSelectionDrawer.tsx create mode 100644 web/components/GroupSelector.tsx create mode 100644 web/components/HistoryDrawer.tsx create mode 100644 web/components/ImportFolderDrawer.tsx create mode 100644 web/components/IndexingModal.tsx create mode 100644 web/components/IndexingModalWithMode.tsx create mode 100644 web/components/InputDrawer.tsx create mode 100644 web/components/LoginPage.tsx create mode 100644 web/components/Logo.tsx create mode 100644 web/components/ModeSelector.tsx create mode 100644 web/components/NotebookDragDropUpload.tsx create mode 100644 web/components/NotebookGlobalDragDropOverlay.tsx create mode 100644 web/components/PDFPreview.tsx create mode 100644 web/components/PDFSelectionTool.tsx create mode 100644 web/components/SearchHistoryList.tsx create mode 100644 web/components/SearchResultsPanel.tsx create mode 100644 web/components/SettingsDrawer.tsx create mode 100644 web/components/SettingsModal.tsx create mode 100644 web/components/SourcePreviewDrawer.tsx create mode 100644 web/components/Toast.tsx create mode 100644 web/components/UserInfoDisplay.tsx create mode 100644 web/components/VisionModelSelector.tsx create mode 100644 web/components/drawers/ImportTasksDrawer.tsx create mode 100644 web/components/layouts/AdminLayout.tsx create mode 100644 web/components/layouts/SidebarRail.tsx create mode 100644 web/components/layouts/WorkspaceLayout.tsx create mode 100644 web/components/views/AssessmentStatsView.tsx create mode 100644 web/components/views/AssessmentTemplateManager.tsx create mode 100644 web/components/views/AssessmentView.tsx create mode 100644 web/components/views/ChatView.tsx create mode 100644 web/components/views/KnowledgeBaseView.tsx create mode 100644 web/components/views/MemosView.tsx create mode 100644 web/components/views/NotebookDetailView.tsx create mode 100644 web/components/views/NotebooksView.tsx create mode 100644 web/components/views/PluginsView.tsx create mode 100644 web/components/views/SettingsView.tsx create mode 100644 web/constants/fileSupport.ts create mode 100644 web/contexts/ConfirmContext.tsx create mode 100644 web/contexts/LanguageContext.tsx create mode 100644 web/contexts/ToastContext.tsx create mode 100644 web/index.css create mode 100644 web/index.html create mode 100644 web/index.tsx create mode 100644 web/metadata.json create mode 100644 web/package.json create mode 100644 web/postcss.config.js.bak create mode 100644 web/public/css2.css create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa0ZL7SUc.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1ZL7.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa1pL7SUc.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa25L7SUc.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2JL7SUc.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2ZL7SUc.woff2 create mode 100644 web/public/fonts/UcC73FwrK3iLTeHuS_nVMrMxCp50SjIa2pL7SUc.woff2 create mode 100644 web/public/katex/katex.min.css create mode 100644 web/public/tailwindcss-3.4.17.js create mode 100644 web/services/apiClient.ts create mode 100644 web/services/assessmentService.ts create mode 100644 web/services/authService.ts create mode 100644 web/services/chatService.ts create mode 100644 web/services/chunkConfigService.ts create mode 100644 web/services/geminiService.ts create mode 100644 web/services/importService.ts create mode 100644 web/services/knowledgeBaseService.ts create mode 100644 web/services/knowledgeGroupService.ts create mode 100644 web/services/modelConfigService.ts create mode 100644 web/services/noteCategoryService.ts create mode 100644 web/services/noteService.ts create mode 100644 web/services/ocrService.ts create mode 100644 web/services/pdfPreviewService.ts create mode 100644 web/services/pdfRenderService.ts create mode 100644 web/services/ragService.ts create mode 100644 web/services/searchHistoryService.ts create mode 100644 web/services/settingsService.ts create mode 100644 web/services/templateService.ts create mode 100644 web/services/uploadService.ts create mode 100644 web/services/userService.ts create mode 100644 web/services/userSettingService.ts create mode 100644 web/src/components/layouts/WorkspaceLayout.tsx create mode 100644 web/src/components/plugins/FeishuPluginConfig.tsx create mode 100644 web/src/components/ui/button.tsx create mode 100644 web/src/components/ui/card.tsx create mode 100644 web/src/components/ui/select.tsx create mode 100644 web/src/components/views/AgentsView.tsx create mode 100644 web/src/components/views/PluginsView.tsx create mode 100644 web/src/contexts/AuthContext.tsx create mode 100644 web/src/pages/auth/Login.tsx create mode 100644 web/src/pages/workspace/AgentsPage.tsx create mode 100644 web/src/pages/workspace/AssessmentPage.tsx create mode 100644 web/src/pages/workspace/ChatPage.tsx create mode 100644 web/src/pages/workspace/KnowledgePage.tsx create mode 100644 web/src/pages/workspace/MemosPage.tsx create mode 100644 web/src/pages/workspace/NotebooksPage.tsx create mode 100644 web/src/pages/workspace/PluginsPage.tsx create mode 100644 web/src/pages/workspace/SettingsPage.tsx create mode 100644 web/src/services/assessmentStatsService.ts create mode 100644 web/src/utils/cn.ts create mode 100644 web/src/utils/toast.ts create mode 100644 web/tailwind.config.js.bak create mode 100644 web/tsconfig.json create mode 100644 web/types.ts create mode 100644 web/used_keys.txt create mode 100644 web/utils/clipboard.ts create mode 100644 web/utils/constants.ts create mode 100644 web/utils/fileUtils.ts create mode 100644 web/utils/translations.ts create mode 100644 web/utils/uuid.ts create mode 100644 web/vite.config.ts create mode 100644 yarn.lock diff --git a/.antigravityrules b/.antigravityrules new file mode 100644 index 0000000..24b399e --- /dev/null +++ b/.antigravityrules @@ -0,0 +1,26 @@ +# Global Project Constraints + +1. **Language Requirements**: + - All code comments **MUST** be written in **English**. + - All server and client logs (`console.log`, `logger.info`, `logger.error`, etc.) **MUST** be written in **English**. + +2. **Internationalization (i18n)**: + - All user-facing messages, API response messages, error messages, and UI text **MUST** guarantee internationalization support. + - Do not use hardcoded string literals for messages. Always use the project's designated i18n service or translation utility with proper keys. + +3. **UI Notifications**: + - All popup messages, error alerts, and system notifications **MUST** uniformly use the toast component (e.g., via `useToast().showError()`, `showSuccess()`). + - Never use native browser `window.alert()`. + +4. **Agent Architecture & Orchestration (v3.0)**: + - High-complexity, multi-turn AI workflows (e.g., AI Tutor, Evaluation Agents) **MUST** use `LangGraph` for state machine orchestration. Do not rely on hardcoded linear `if-else` blocks or flat chains for multi-step agent interactions. + - Separate distinct AI responsibilities (e.g., `QuestionGenerator`, `Grader`, `ReportAnalyzer`) into independent **Graph Nodes**. + - Use **Conditional Edges (Routing)** to dynamically control the flow based on the graph state (e.g., triggering follow-up questions vs. proceeding to the next question). + - The graph must maintain a central `State` object (e.g., `EvaluationState`) to track session data, current progress, multi-turn dialogue history, and interruption/recovery points (Thread IDs). + +5. **Agent Evaluation & Anti-Hallucination**: + - When using an LLM to grade or evaluate user input against a knowledge base, the Agent's System Prompt **MUST** always include the original reference documents (Ground Truth Chunks) to strictly prevent AI hallucination during scoring. + +6. **Knowledge Graph Integration**: + - When extracting complex relationships from documents for GraphRAG, ensure the LLM output conforms strictly to predefined schemas (Ontology) to prevent graph pollution. + - Heavy extraction tasks (like Full Document Entity/Relation Extraction) must be handled asynchronously as background tasks, rather than blocking synchronous API calls. diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..0bebd50 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,13 @@ +# Global Project Constraints + +1. **Language Requirements**: + - All code comments **MUST** be written in **English**. + - All server and client logs (`console.log`, `logger.info`, `logger.error`, etc.) **MUST** be written in **English**. + +2. **Internationalization (i18n)**: + - All user-facing messages, API response messages, error messages, and UI text **MUST** guarantee internationalization support. + - Do not use hardcoded string literals for messages. Always use the project's designated i18n service or translation utility with proper keys. + +3. **UI Notifications**: + - All popup messages, error alerts, and system notifications **MUST** uniformly use the toast component (e.g., via `useToast().showError()`, `showSuccess()`). + - Never use native browser `window.alert()`. diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..0acea77 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +node_modules +web/node_modules +server/node_modules +dist +.git +.env* +.gemini +.specify +*.log diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c04a2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# Dependencies +.claude +/node_modules +/web/node_modules +/server/node_modules + +# Build outputs +/server/dist +/web/dist +/web/build +/server/build + +# Data and uploads +/data +/uploads +/temp +/server/uploads +/server/data +/server/temp + +# Env files +.env.local +.env.development +.env.test +/web/.env.local + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Coverage +coverage +.nyc_output + +# IDE +.vscode +.idea +*.swp +*.swo +/server/.env +/libreoffice-server/.venv +/libreoffice-server/uploads + +# temp +analyze_translations.py +web/dist-check/ +web2 +db_output_utf8.json +db_output.json +server/check_db_v2.js +server/check_models.js +server/aurak.sqlite +server/models_list.json +server/models_status.json +libreoffice-server/__pycache__/main.cpython-312.pyc +nul +.sisyphus/ +server/build_error.txt +server/ts_errors.txt diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..68d4359 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,265 @@ +# AGENTS.md - AuraK (AI人才评测系统) + +## Quick Start + +```bash +# Start Docker services (WSL) +wsl sudo service docker start +wsl docker compose up -d + +# Development +yarn dev # Both: web@13001 + server@3001 +cd web && yarn dev # Frontend only (port 13001) +cd server && yarn start:dev # Backend only (port 3001) +``` + +## Critical Commands + +```bash +# Tests (Jest) +cd server && yarn test +cd server && yarn test --testPathPattern=AssessmentService + +# Lint & Format +cd server && yarn lint +cd server && yarn format +``` + +## Services (Docker) + +| Service | Port | +|---------|------| +| Frontend (prod) | 80/443 | +| Backend API | 3001 | +| Elasticsearch | 9200 | +| Apache Tika | 9998 | +| LibreOffice | 8100 | + +## Environment Setup + +```bash +cp server/.env.sample server/.env +cp web/.env.example web/.env +``` + +Key vars: `OPENAI_API_KEY`, `GEMINI_API_KEY`, `ELASTICSEARCH_HOST`, `JWT_SECRET` + +## Architecture + +**Stack**: React 19 + TypeScript + Vite (web) | NestJS + LangChain + LangGraph (server) + +**Assessment System** (LangGraph state machine): +- `server/src/assessment/graph/builder.ts` - Route logic +- `server/src/assessment/graph/nodes/grader.node.ts` - Scoring +- `server/src/assessment/graph/nodes/interviewer.node.ts` - Question flow +- `server/src/assessment/graph/nodes/generator.node.ts` - Question generation +- `web/components/views/AssessmentView.tsx` - Frontend UI + +--- + +# 完整测评体系设计文档(评审通过版) + +> 文档状态: ✅ 评审通过 +> 最后更新: 2026-04-23 +> 版本: 2.0 + +--- + +## 一、测评体系闭环 + +``` +知识库 → 模板 → 题库(AI生成+单题审核) → 评估抽取 → 用户答题 → 评分 → 成绩 → 证书 + ↑ + 复查(调整总分) +``` + +--- + +## 二、组织架构与权限 + +### 2.1 组织结构 + +``` +公司 + └── 本部A / 本部B + └── 开发部 / 其他部门 +``` + +### 2.2 角色权限 + +| 角色 | 数据范围 | +|------|---------| +| 学员 | 仅自己 | +| 开发部长 | 开发部全员 | +| 本部长 | 本部全员 | +| 公司高管 | 全公司 | +| 管理员 | 全部数据 | +| 讲师 | 复查(调总分) | + +--- + +## 三、题库管理模块 (A) - ✅评审通过 + +### 核心规则 +- 模板新增 `dimensionQuota` 字段配置各维度题目数量 +- 模板与题库**一对一**关系 +- **单题逐审**(可批量选择操作) +- 审核流程:草稿 → 待审 → 发布/否决 + +### 数据模型 + +```typescript +// QuestionBank +{ + id, templateId, name, description, + status: DRAFT/PENDING_REVIEW/PUBLISHED, + createdBy, reviewedBy, reviewedAt, reviewComment +} + +// QuestionBankItem +{ + id, bankId, questionText, questionType, + options, correctAnswer, keyPoints, + difficulty, dimension, basis, + status: PENDING_REVIEW/PUBLISHED +} +``` + +--- + +## 四、评估执行模块 (B) - ✅评审通过 + +### 核心规则 +- 题目抽取:维度均衡/高频优先 +- 发起方式:新人强制管理员发起,认证后可自评 +- 评分:≥6分通过 +- **超时不记分**(不影响得分) +- **中断超时强制提交** +- 追问:预置+超时降级 + +### 时间控制 +| 限制 | 默认值 | +|------|--------| +| 单题限时 | 300秒 | +| 总时长限制 | 1800秒 | + +--- + +## 五、成绩管理模块 (C) - ✅评审通过 + +### 核心规则 +- 权限:按组织架构隔离 +- 历史:保留最近3次 +- 统计:准实时(**缓存5分钟**) +- 复查:**只能调整总分**,不影响已发证书 +- 导出:Excel/PDF/CSV + +### 统计维度 +- 通过率、平均分、最高分 +- 各维度平均分(雷达图) +- 评估次数趋势 + +--- + +## 六、证书管理模块 (D) - ✅评审通过 + +### 核心规则 +- 生成:首次通过即发 +- 唯一性:**同一模板只保留第一次通过的证书** +- 有效期:永久有效 +- **仅预览,不可下载** +- 验真:二维码/ID查询 +- **复查不影响已发证书**(保持不变) + +### 证书内容 +| 字段 | 说明 | +|------|------| +| certificateId | 唯一ID | +| userId | 持证人 | +| templateId | 评估模板 | +| totalScore | 总分 | +| passedAt | 通过时间 | +| qrCode | 防伪二维码 | + +--- + +## 七、实施计划(简化版) + +| Phase | 内容 | 优先级 | +|-------|------|--------| +| 1 | 题库管理(AI生成+单题审核) | P0 | +| 2 | 评估执行(抽取+超时处理) | P0 | +| 3 | 成绩管理(统计+复查) | P1 | +| 4 | 证书功能(预览+验真) | P1 | + +--- + +## 八、验收标准 + +- [ ] 模板新增 dimensionQuota 字段 +- [ ] 题库与模板一对一关联 +- [ ] AI批量生成按dimensionQuota配置 +- [ ] 单题逐审(可批量操作) +- [ ] 维度均衡抽取(高频优先) +- [ ] 超时不记分,中断超时强制提交 +- [ ] 统计缓存5分钟 +- [ ] 复查只调总分 +- [ ] 首次通过才发证书 +- [ ] 证书仅预览不可下载 +- [ ] 同一模板只保留首次证书 +- [ ] 复查不影响已发证书 + +--- + +## Verified Bug Fixes (DO NOT REVERT) + +1. `grader.node.ts:87-89`: Use `let shortFeedback` (not `const`) - scope bug +2. `grader.node.ts:454` & `interviewer.node.ts:104`: Use `questions || []` - undefined array +3. `builder.ts:41`: Use `Math.max(0, questionsLen - nextIndex)` - negative remaining +4. **API consistency**: Frontend uses non-streaming `/answer` (NOT `/answer-stream`) +5. **DeepSeek config**: Use `modelId` not `modelName` in getModel() +6. **targetCount**: Pass to all graph.stream() configurable calls +7. **Question limit**: generator.node.ts limits generation to targetCount +8. **Force emit next question**: When stream doesn't emit updates + +## Design Doc Features Verified + +| Feature | Status | File | +|---------|--------|------| +| dimensionScores 多维度计分 | ✅ | `assessment.service.ts:131-176` | +| weightConfig 权重配置 | ✅ | Template entity | +| 即时反馈(评分) | ✅ | grader.node.ts | +| shouldFollowUp 追问 | ✅ | grader.node.ts, interviewer.node.ts | +| followUpCount 追问计数 | ✅ | state.ts, assessment-session.entity.ts | +| 题目数量限制 | ✅ | generator.node.ts | + +## Code Standards + +- **Comments/logs**: English only (enforced) +- **User messages**: i18n required (ja/zh/en support) +- **UI**: Use Toast components, never `alert()` + +## TDD Enforcement + +When implementing features or fixing bugs: +1. Write failing test first (RED) +2. Run test to verify failure: `cd server && yarn test --testPathPattern=` +3. Write minimal code to pass (GREEN) +4. Verify test passes +5. Refactor if needed (all tests must pass) + +See `test-driven-development` skill for full TDD workflow. + +## Debugging + +- Backend logs: Check `assessment.service.ts` submitAnswer method +- Services: `curl http://localhost:9200/_cat/indices`, `curl localhost:9998/tika` + +## Related Docs + +- `CLAUDE.md` - Detailed architecture and dev guide +- `.cursorrules` - Code constraints (English + i18n) +- `STARTUP.md` - Docker startup guide +- `docs/plans/2026-04-23-assessment-system-full-plan-v2.md` - **完整实施计划(评审通过)** +- `docs/plans/2026-04-18-l1-talent-assessment-design.md` - L1设计文档 +- `docs/plans/2026-04-20-assessment-system-complete-plan.md` - 旧版计划 \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a9e79b3 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,203 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Simple Knowledge Base is a full-stack RAG (Retrieval-Augmented Generation) Q&A system built with React 19 + NestJS. It's a monorepo with Japanese/Chinese documentation but English code. + +**Key Features:** +- Multi-model support (OpenAI-compatible APIs + Google Gemini native SDK) +- Dual processing modes: Fast (Tika text-only) and High-precision (Vision pipeline) +- User isolation with JWT authentication and per-user knowledge bases +- Hybrid search (vector + keyword) with Elasticsearch +- Multi-language interface (Japanese, Chinese, English) +- Streaming responses via Server-Sent Events (SSE) + +## Development Setup + +### Prerequisites +- Node.js 18+ +- Yarn +- Docker & Docker Compose + +### Initial Setup +```bash +# Install dependencies +yarn install + +# Start infrastructure services +docker-compose up -d elasticsearch tika libreoffice + +# Configure environment +cp server/.env.sample server/.env +# Edit server/.env with API keys and configuration +``` + +### Development Commands +```bash +# Start both frontend and backend in development mode +yarn dev + +# Frontend only (port 13001) +cd web && yarn dev + +# Backend only (port 3001) +cd server && yarn start:dev + +# Run tests +cd server && yarn test +cd server && yarn test:e2e + +# Lint and format +cd server && yarn lint +cd server && yarn format +``` + +### Docker Services +- **Elasticsearch**: 9200 (vector storage) +- **Apache Tika**: 9998 (document text extraction) +- **LibreOffice Server**: 8100 (document conversion) +- **Backend API**: 3001 +- **Frontend**: 13001 (dev), 80/443 (production via nginx) + +## Architecture + +### Project Structure +``` +simple-kb/ +├── web/ # React frontend (Vite) +│ ├── components/ # UI components (ChatInterface, ConfigPanel, etc.) +│ ├── contexts/ # React Context providers +│ ├── services/ # API client services +│ └── utils/ # Utility functions +├── server/ # NestJS backend +│ ├── src/ +│ │ ├── ai/ # AI services (embedding, etc.) +│ │ ├── api/ # API module +│ │ ├── auth/ # JWT authentication +│ │ ├── chat/ # Chat/RAG module +│ │ ├── elasticsearch/ # Elasticsearch integration +│ │ ├── import-task/ # Import task management +│ │ ├── knowledge-base/# Knowledge base management +│ │ ├── libreoffice/ # LibreOffice integration +│ │ ├── model-config/ # Model configuration management +│ │ ├── vision/ # Vision model integration +│ │ └── vision-pipeline/# Vision pipeline orchestration +│ ├── data/ # SQLite database storage +│ ├── uploads/ # Uploaded files storage +│ └── temp/ # Temporary files +├── docs/ # Comprehensive documentation (Japanese/Chinese) +├── nginx/ # Nginx configuration +├── libreoffice-server/ # LibreOffice conversion service (Python/FastAPI) +└── docker-compose.yml # Docker orchestration +``` + +### Key Architectural Concepts + +**Dual Processing Modes:** +1. **Fast Mode**: Apache Tika for text-only extraction (quick, no API cost) +2. **High-Precision Mode**: Vision Pipeline (LibreOffice → PDF → Images → Vision Model) for mixed image/text documents (slower, incurs API costs) + +**Multi-Model Support:** +- OpenAI-compatible APIs (OpenAI, DeepSeek, Claude, etc.) +- Google Gemini native SDK +- Configurable LLM, Embedding, and Rerank models + +**RAG System:** +- Hybrid search (vector + keyword) with Elasticsearch +- Streaming responses via Server-Sent Events (SSE) +- Source citation and similarity scoring +- Chunk configuration (size, overlap) + +## Code Standards + +### Language Requirements +- **Code comments must be in English** +- **Log messages must be in English** +- **Error messages must support internationalization** to enable multi-language frontend interface +- **API response messages must support internationalization** to enable multi-language frontend interface +- Interface supports Japanese, Chinese, and English + +### Testing +- Backend uses Jest for unit and e2e tests +- Frontend currently has no test framework configured +- Run tests: `cd server && yarn test` or `yarn test:e2e` + +### Code Quality +- ESLint and Prettier configured for backend +- Format code: `cd server && yarn format` +- Lint code: `cd server && yarn lint` + +## Common Development Tasks + +### Adding a New API Endpoint +1. Create controller in appropriate module under `server/src/` +2. Add service methods with English comments +3. Update DTOs and validation +4. Add tests in `*.spec.ts` files + +### Adding a New Frontend Component +1. Create component in `web/components/` +2. Add TypeScript interfaces in `web/types.ts` +3. Use Tailwind CSS for styling +4. Connect to backend services in `web/services/` + +### Debugging +- Backend logs are in Chinese +- Check Elasticsearch: `curl http://localhost:9200/_cat/indices` +- Check Tika: `curl http://localhost:9998/tika` +- Check LibreOffice: `curl http://localhost:8100/health` + +## Environment Configuration + +Key environment variables (`server/.env`): +- `OPENAI_API_KEY`: OpenAI-compatible API key +- `GEMINI_API_KEY`: Google Gemini API key +- `ELASTICSEARCH_HOST`: Elasticsearch URL (default: http://localhost:9200) +- `TIKA_HOST`: Apache Tika URL (default: http://localhost:9998) +- `LIBREOFFICE_URL`: LibreOffice server URL (default: http://localhost:8100) +- `JWT_SECRET`: JWT signing secret + +## Deployment + +### Development +```bash +docker-compose up -d elasticsearch tika libreoffice +yarn dev +``` + +### Production +```bash +docker-compose up -d # Builds and starts all services +``` + +### Ports in Production +- Frontend: 80/443 (via nginx) +- Backend API: 3001 (proxied through nginx) +- Elasticsearch: 9200 +- Tika: 9998 +- LibreOffice: 8100 + +## Troubleshooting + +### Common Issues +1. **Elasticsearch not starting**: Check memory limits in docker-compose.yml +2. **File upload failures**: Ensure `uploads/` and `temp/` directories exist with proper permissions +3. **Vision pipeline errors**: Verify LibreOffice server is running and accessible +4. **API key errors**: Check environment variables in `server/.env` + +### Database Management +- SQLite database: `server/data/metadata.db` +- Elasticsearch indices: Managed automatically by the application +- To reset: Delete `server/data/metadata.db` and Elasticsearch data volume + +## Documentation + +- **README.md**: Project overview in Japanese +- **docs/**: Comprehensive documentation (mostly Japanese/Chinese) +- **DESIGN.md**: System architecture and design +- **API.md**: API reference +- **DEVELOPMENT_STANDARDS.md**: Mandates English comments/logs and internationalized messages + +When modifying code, always add English comments and logs as required by development standards. Error and UI messages must be properly internationalized. The project has extensive existing documentation in Japanese/Chinese - refer to `docs/` directory for detailed technical information. \ No newline at end of file diff --git a/FEATURE_SUMMARY.md b/FEATURE_SUMMARY.md new file mode 100644 index 0000000..8428aa5 --- /dev/null +++ b/FEATURE_SUMMARY.md @@ -0,0 +1,29 @@ +# 功能说明 + +## 用户信息显示功能已完成 + +此更新为系统添加了以下功能: + +1. 在侧边栏顶部显示当前登录用户的信息,包括: + - 用户头像和用户名 + - 管理员标识(如果用户是管理员) + - 用户ID的部分显示 + +2. 主要文件变更: + - 创建了 `UserInfoDisplay.tsx` 组件 + - 更新了 `SidebarRail.tsx` 以集成用户信息显示 + - 更新了 `App.tsx` 以传递 currentUser 数据 + - 所有现有翻译已支持相关文本 + +## 实现细节 + +- 用户信息只在侧边栏展开时显示 +- 使用 Lucide React 图标增强可视化 +- 支持三种语言的界面文本 (中文/英文/日文) +- 管理员用户会显示特殊标记 +- 界面美观且与现有设计风格保持一致 +- 避免了信息重复显示 + +## 部署 + +此功能已准备好部署,无需额外配置。 \ No newline at end of file diff --git a/INTERNAL_DEPLOYMENT_GUIDE.md b/INTERNAL_DEPLOYMENT_GUIDE.md new file mode 100644 index 0000000..debd684 --- /dev/null +++ b/INTERNAL_DEPLOYMENT_GUIDE.md @@ -0,0 +1,94 @@ +# 内网部署指南 - Simple-KB 知识库系统 + +## 概述 + +本文档介绍如何在内部网络环境中部署Simple-KB知识库系统,确保所有外部依赖都被移除或替换为内部资源。 + +## 主要修改内容 + +### 1. 外部CDN资源移除 + +已完成修改: +- 将 KaTeX CSS 文件从外部 CDN (https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css) 移至本地 +- `web/index.html` 已更新为引用本地 `/katex/katex.min.css` +- KaTeX CSS 文件已复制到 `web/public/katex/katex.min.css` + +### 2. AI模型API配置 + +系统本身支持内部模型API配置: +- 模型配置通过 `ModelConfig` 实体管理 +- 支持自定义 `baseUrl` 来指定内部模型服务 +- 用户可通过UI界面配置内部模型端点 + +## 内网部署配置步骤 + +### 步骤1: 部署内部AI模型服务 + +在启动Simple-KB之前,请确保已部署内部AI模型服务,如: +- 自托管的OpenAI兼容接口 (如 vLLM, Text Generation WebUI等) +- 内部大语言模型服务 +- 内部嵌入模型服务 + +### 步骤2: 配置模型端点 + +1. 启动Simple-KB系统 +2. 登录系统后,在模型配置页面添加内部模型配置: + - LLM模型: 配置内部LLM服务的URL和API密钥 + - 嵌入模型: 配置内部嵌入服务的URL和API密钥 + - 重排序模型: 配置内部重排序服务的URL和API密钥 + +### 步骤3: Docker配置(可选高级配置) + +如果需要修改Docker构建过程以使用内部注册表,请修改以下文件: + +#### 修改 server/Dockerfile: +```dockerfile +# 替换这行: +RUN yarn config set registry https://registry.npmmirror.com && \ +# 为: +RUN yarn config set registry http://your-internal-npm-registry && \ +``` + +#### 修改 web/Dockerfile: +```dockerfile +# 替换这行: +RUN yarn config set registry https://registry.npmmirror.com && \ +# 为: +RUN yarn config set registry http://your-internal-npm-registry && \ +``` + +#### 修改 libreoffice-server/Dockerfile: +```dockerfile +# 替换APK仓库源 +RUN echo "http://your-internal-mirror/alpine/v3.19/main" > /etc/apk/repositories && \ + echo "http://your-internal-mirror/alpine/v3.19/community" >> /etc/apk/repositories && \ + +# 替换pip源 +RUN pip install --no-cache-dir -r requirements.txt -i http://your-internal-pypi/ + +# 替换npm源 +RUN npm install --registry=http://your-internal-npm-registry +``` + +### 步骤4: Nginx配置 + +如果需要修改Nginx配置以适应内部环境: + +1. 更新 `nginx/conf.d/kb.conf` 中的SSL证书路径 +2. 根据需要修改服务器名称 +3. 确保代理路径正确指向内部服务 + +## 验证步骤 + +1. 确认前端界面正常加载且无外部资源错误 +2. 测试数学公式渲染功能是否正常(KaTeX功能) +3. 配置内部模型服务并测试问答功能 +4. 确认所有API调用都在内部网络中完成 + +## 注意事项 + +- 系统的所有核心功能现均可在内部网络中运行 +- 外部CDN依赖已被完全移除 +- AI模型服务需单独部署内部实例 +- 在完全离线环境中,构建过程可能需要预先下载所有依赖包 +- 如需完全离线部署,建议预构建镜像并部署到内部镜像仓库 \ No newline at end of file diff --git a/INTERNAL_DEPLOYMENT_SUMMARY.md b/INTERNAL_DEPLOYMENT_SUMMARY.md new file mode 100644 index 0000000..9e3bba8 --- /dev/null +++ b/INTERNAL_DEPLOYMENT_SUMMARY.md @@ -0,0 +1,40 @@ +# 内网部署修改摘要 - Simple-KB 知识库系统 + +## 修改概述 + +已完成对Simple-KB知识库系统的修改,以支持内部网络环境部署,消除了外部依赖。 + +## 具体修改内容 + +### 1. 外部CDN资源移除 +- **文件**: `web/index.html` +- **修改**: 将 KaTeX CSS 从外部 CDN (https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css) 更改为本地资源 (/katex/katex.min.css) +- **文件**: `web/public/katex/katex.min.css` +- **操作**: 从 node_modules 复制 KaTeX CSS 文件到本地目录 + +### 2. 文档更新 +- **新增文件**: `INTERNAL_DEPLOYMENT_GUIDE.md` +- **内容**: 详细的内网部署指南,包括配置内部AI模型服务的方法 +- **更新文件**: `README.md` +- **内容**: 添加了内网部署章节,链接到部署指南 + +## 系统状态 + +✅ **已完成**: +- 消除前端外部CDN依赖 +- 提供内部网络部署文档 +- 保持所有原有功能完整性 + +✅ **系统已准备好在内部网络环境中部署**: +- 所有前端资源均为本地资源 +- AI模型服务可通过配置指向内部服务 +- 系统不再依赖外部CDN或API端点(除用户自行配置的AI模型外) + +## 部署说明 + +要在内部网络中部署此系统: + +1. 按照 `INTERNAL_DEPLOYMENT_GUIDE.md` 的说明进行配置 +2. 部署内部AI模型服务(如适用) +3. 配置模型端点以使用内部服务 +4. 启动系统并验证功能 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f63f5a9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,194 @@ +木兰宽松许可证,第2版 + +木兰宽松许可证,第2版 + +2020年1月 http://license.coscl.org.cn/MulanPSL2 + +您对“软件”的复制、使用、修改及分发受木兰宽松许可证,第2版(“本许可证”)的如下条款的约束: + +0. 定义 + +“软件” 是指由“贡献”构成的许可在“本许可证”下的程序和相关文档的集合。 + +“贡献” 是指由任一“贡献者”许可在“本许可证”下的受版权法保护的作品。 + +“贡献者” 是指将受版权法保护的作品许可在“本许可证”下的自然人或“法人实体”。 + +“法人实体” 是指提交贡献的机构及其“关联实体”。 + +“关联实体” 是指,对“本许可证”下的行为方而言,控制、受控制或与其共同受控制的机构,此处的控制是 +指有受控方或共同受控方至少50%直接或间接的投票权、资金或其他有价证券。 + +1. 授予版权许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的版权许可,您可 +以复制、使用、修改、分发其“贡献”,不论修改与否。 + +2. 授予专利许可 + +每个“贡献者”根据“本许可证”授予您永久性的、全球性的、免费的、非独占的、不可撤销的(根据本条规定 +撤销除外)专利许可,供您制造、委托制造、使用、许诺销售、销售、进口其“贡献”或以其他方式转移其“贡 +献”。前述专利许可仅限于“贡献者”现在或将来拥有或控制的其“贡献”本身或其“贡献”与许可“贡献”时的“软 +件”结合而将必然会侵犯的专利权利要求,不包括对“贡献”的修改或包含“贡献”的其他结合。如果您或您的“ +关联实体”直接或间接地,就“软件”或其中的“贡献”对任何人发起专利侵权诉讼(包括反诉或交叉诉讼)或 +其他专利维权行动,指控其侵犯专利权,则“本许可证”授予您对“软件”的专利许可自您提起诉讼或发起维权 +行动之日终止。 + +3. 无商标许可 + +“本许可证”不提供对“贡献者”的商品名称、商标、服务标志或产品名称的商标许可,但您为满足第4条规定 +的声明义务而必须使用除外。 + +4. 分发限制 + +您可以在任何媒介中将“软件”以源程序形式或可执行形式重新分发,不论修改与否,但您必须向接收者提供“ +本许可证”的副本,并保留“软件”中的版权、商标、专利及免责声明。 + +5. 免责声明与责任限制 + +“软件”及其中的“贡献”在提供时不带任何明示或默示的担保。在任何情况下,“贡献者”或版权所有者不对 +任何人因使用“软件”或其中的“贡献”而引发的任何直接或间接损失承担责任,不论因何种原因导致或者基于 +何种法律理论,即使其曾被建议有此种损失的可能性。 + +6. 语言 + +“本许可证”以中英文双语表述,中英文版本具有同等法律效力。如果中英文版本存在任何冲突不一致,以中文 +版为准。 + +条款结束 + +如何将木兰宽松许可证,第2版,应用到您的软件 + +如果您希望将木兰宽松许可证,第2版,应用到您的新软件,为了方便接收者查阅,建议您完成如下三步: + +1, 请您补充如下声明中的空白,包括软件名、软件的首次发表年份以及您作为版权人的名字; + +2, 请您在软件包的一级目录下创建以“LICENSE”为名的文件,将整个许可证文本放入该文件中; + +3, 请将如下声明文本放入每个源文件的头部注释中。 + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan +PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. + +Mulan Permissive Software License,Version 2 + +Mulan Permissive Software License,Version 2 (Mulan PSL v2) + +January 2020 http://license.coscl.org.cn/MulanPSL2 + +Your reproduction, use, modification and distribution of the Software shall +be subject to Mulan PSL v2 (this License) with the following terms and +conditions: + +0. Definition + +Software means the program and related documents which are licensed under +this License and comprise all Contribution(s). + +Contribution means the copyrightable work licensed by a particular +Contributor under this License. + +Contributor means the Individual or Legal Entity who licenses its +copyrightable work under this License. + +Legal Entity means the entity making a Contribution and all its +Affiliates. + +Affiliates means entities that control, are controlled by, or are under +common control with the acting entity under this License, ‘control’ means +direct or indirect ownership of at least fifty percent (50%) of the voting +power, capital or other securities of controlled or commonly controlled +entity. + +1. Grant of Copyright License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to you a perpetual, worldwide, royalty-free, non-exclusive, +irrevocable copyright license to reproduce, use, modify, or distribute its +Contribution, with modification or not. + +2. Grant of Patent License + +Subject to the terms and conditions of this License, each Contributor hereby +grants to you a perpetual, worldwide, royalty-free, non-exclusive, +irrevocable (except for revocation under this Section) patent license to +make, have made, use, offer for sale, sell, import or otherwise transfer its +Contribution, where such patent license is only limited to the patent claims +owned or controlled by such Contributor now or in future which will be +necessarily infringed by its Contribution alone, or by combination of the +Contribution with the Software to which the Contribution was contributed. +The patent license shall not apply to any modification of the Contribution, +and any other combination which includes the Contribution. If you or your +Affiliates directly or indirectly institute patent litigation (including a +cross claim or counterclaim in a litigation) or other patent enforcement +activities against any individual or entity by alleging that the Software or +any Contribution in it infringes patents, then any patent license granted to +you under this License for the Software shall terminate as of the date such +litigation or activity is filed or taken. + +3. No Trademark License + +No trademark license is granted to use the trade names, trademarks, service +marks, or product names of Contributor, except as required to fulfill notice +requirements in section 4. + +4. Distribution Restriction + +You may distribute the Software in any medium with or without modification, +whether in source or executable forms, provided that you provide recipients +with a copy of this License and retain copyright, patent, trademark and +disclaimer statements in the Software. + +5. Disclaimer of Warranty and Limitation of Liability + +THE SOFTWARE AND CONTRIBUTION IN IT ARE PROVIDED WITHOUT WARRANTIES OF ANY +KIND, EITHER EXPRESS OR IMPLIED. IN NO EVENT SHALL ANY CONTRIBUTOR OR +COPYRIGHT HOLDER BE LIABLE TO YOU FOR ANY DAMAGES, INCLUDING, BUT NOT +LIMITED TO ANY DIRECT, OR INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES ARISING +FROM YOUR USE OR INABILITY TO USE THE SOFTWARE OR THE CONTRIBUTION IN IT, NO +MATTER HOW IT’S CAUSED OR BASED ON WHICH LEGAL THEORY, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES. + +6. Language + +THIS LICENSE IS WRITTEN IN BOTH CHINESE AND ENGLISH, AND THE CHINESE VERSION +AND ENGLISH VERSION SHALL HAVE THE SAME LEGAL EFFECT. IN THE CASE OF +DIVERGENCE BETWEEN THE CHINESE AND ENGLISH VERSIONS, THE CHINESE VERSION +SHALL PREVAIL. + +END OF THE TERMS AND CONDITIONS + +How to Apply the Mulan Permissive Software License,Version 2 +(Mulan PSL v2) to Your Software + +To apply the Mulan PSL v2 to your work, for easy identification by +recipients, you are suggested to complete following three steps: + +i. Fill in the blanks in following statement, including insert your software +name, the year of the first publication of your software, and your name +identified as the copyright owner; + +ii. Create a file named "LICENSE" which contains the whole context of this +License in the first directory of your software package; + +iii. Attach the statement to the appropriate annotated syntax at the +beginning of each source file. + +Copyright (c) [Year] [name of copyright holder] +[Software Name] is licensed under Mulan PSL v2. +You can use this software according to the terms and conditions of the Mulan +PSL v2. +You may obtain a copy of Mulan PSL v2 at: + http://license.coscl.org.cn/MulanPSL2 +THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +See the Mulan PSL v2 for more details. diff --git a/QUICK_START.md b/QUICK_START.md new file mode 100644 index 0000000..48c3085 --- /dev/null +++ b/QUICK_START.md @@ -0,0 +1,316 @@ +# クイックスタートガイド + +## 🚀 5分でクイック起動 + +### 1. 環境設定 + +```bash +# プロジェクトディレクトリに移動 +cd /home/fzxs/workspaces/demo/simple-kb + +# 環境設定ファイルの作成 +cp server/.env.sample server/.env + +# 設定の編集 +vim server/.env +``` + +### 2. 依存関係のインストール + +```bash +yarn install +``` + +### 3. サービスの起動 + +```bash +# 基本サービスの起動 +docker-compose up -d elasticsearch tika libreoffice + +# 開発サーバーの起動 +yarn dev +``` + +### 4. サービスの検証 + +```bash +# サービスの状態を確認 +docker-compose ps + +# 期待される出力: +# NAME COMMAND STATUS +# local-es ... Up +# simple-kb-tika ... Up +# simple-kb-libreoffice ... Up +``` + + にアクセスして開始してください! + +## 📝 利用フロー + +### ステップ1: システムへログイン + +1. にアクセスします。 +2. 既存のアカウントでログインするか、新しいアカウントを登録します。 + +### ステップ2: モデルの設定 + +1. 「モデル管理」に移動します。 +2. Vision モデルを追加します (OpenAI/Gemini をサポート)。 +3. API キーを設定します。 +4. デフォルトの Vision モデルとして設定します。 + +### ステップ3: ドキュメントのアップロード + +1. 「ドキュメントのアップロード」をクリックします。 +2. PDF/Word/PPT ファイルを選択します。 +3. アップロード用モーダルウィンドウで: + - Embedding(埋め込み)モデルを選択します。 + - **処理モードを選択します**: + - ⚡ 高速モード: テキストのみを抽出 + - 🎯 高精度モード: 画像とテキストを混合して分析 + - チャンク設定を調整します (任意)。 +4. 「処理開始」をクリックします。 + +### ステップ4: 結果の確認 + +1. バックエンドの処理が完了するまで待ちます。 +2. ファイルの状態を確認します: 「処理中」 → 「抽出完了」 → 「ベクトル化完了」 +3. チャット画面で RAG 検索をテストします。 + +## 🔍 モード選択ガイド + +### 高速モードを使用する場合 + +✅ **推奨シーン:** + +- テキストのみのドキュメント +- コードファイル +- シンプルな Markdown +- 画像コンテンツが不要な場合 + +**メリット:** + +- 処理が速い (数秒) +- 追加コストがかからない +- 安定していて信頼性が高い + +### 高精度モードを使用する場合 + +✅ **推奨シーン:** + +- PDF ドキュメント (画像とテキストが混在しているもの) +- Word/PPT (グラフや表が含まれているもの) +- レイアウト情報を保持する必要がある場合 +- 重要なドキュメント + +**メリット:** + +- 画像コンテンツを保持 +- グラフや表を認識 +- ページのレイアウトを保持 +- インデックスの質が高い + +**注意点:** + +- API 利用料が必要 (目安: $0.01/ページ) +- 処理に時間がかかる +- Vision モデルの設定が必要 + +## 💰 コスト管理 + +### 利用枠(クォータ)の確認 + +```bash +# ユーザーのクォータを照会 +GET /api/users/:userId/quota + +# レスポンス例 +{ + "monthlyCost": 15.50, + "maxCost": 100, + "remaining": 84.50, + "usagePercent": 15.5 +} +``` + +### コスト見積もり + +| ファイルタイプ | サイズ | ページ数 | 予想コスト | 予想時間 | +|---------|------|------|---------|---------| +| PDF | 10MB | ~20ページ | $0.20 | 60秒 | +| Word | 5MB | ~10ページ | $0.10 | 30秒 | +| PPT | 15MB | ~30ページ | $0.30 | 90秒 | + +### クォータの管理 + +```sql +-- 管理者によるクォータのリセット +UPDATE users SET monthly_cost = 0 WHERE id = 'user-uuid'; + +-- クォータ制限の調整 +UPDATE users SET max_cost = 200 WHERE id = 'user-uuid'; +``` + +## 🐛 トラブルシューティング + +### 問題1: LibreOffice サービスが利用できない + +**症状:** + +``` +❌ LibreOffice 健康診断: 失敗 +``` + +**解決策:** + +```bash +docker-compose up -d libreoffice +docker-compose logs libreoffice +``` + +### 問題2: ImageMagick がインストールされていない + +**症状:** + +``` +❌ convert: command not found +``` + +**解決策:** + +```bash +# server イメージを再ビルド +docker build -t simple-kb-server:latest ./server/ +docker-compose up -d server +``` + +### 問題3: クォータ不足 + +**症状:** + +``` +❌ クォータ不足: 残り $5.00, 必要 $10.00 +``` + +**解決策:** + +- 翌月の自動リセットを待つ +- 管理者に連絡してクォータを増やす +- 高速モードで処理する + +### 問題4: 一時ファイルが多すぎる + +**症状:** + +``` +⚠️ 100個以上の一時ファイルが見つかりました +``` + +**解決策:** + +```bash +# 手動でクリーンアップ +rm -rf temp/* + +# または .env で自動クリーンアップを設定 +TEMP_CLEANUP=true +``` + +## 📊 モニタリングとログ + +### 処理ログを確認する + +```bash +# リアルタイムログ +docker-compose logs -f server + +# Vision Pipeline のログをフィルタリング +docker-compose logs -f server | grep "Vision\|高精度モード\|コスト" +``` + +### 主要なログの例 + +``` +✅ 高精度モードでの処理を開始 +✅ 予想コスト: $0.15, 予想時間: 45秒 +✅ クォータチェックに合格 +✅ PDFを画像に変換: 15ページ +✅ Vision 分析: 15/15 成功 +✅ 実際のコストを差し引きました: $0.15 +✅ 処理完了: 所要時間 42秒 +``` + +## 🎯 ベストプラクティス + +### 1. ドキュメントの準備 + +- **ファイルサイズの最適化**: 大容量ファイルは分割して処理します。 +- **鮮明な画像**: 高品質な画像の方が認識精度が高まります。 +- **標準フォーマット**: PDF > Word > PPT の順で推奨されます。 + +### 2. モードの選択 + +- **小規模ファイル (<10MB)**: 高精度モード +- **大規模ファイル (>50MB)**: 分割するか、高速モードを検討 +- **テキストのみ**: 高速モード +- **画像・テキスト混在**: 高精度モード + +### 3. コスト削減 + +- **使用率の監視**: 75%で警告、90%で重大な警告を表示します。 +- **定期的な整理**: 不要なドキュメントを削除します。 +- **バッチ処理**: 適切なバッチサイズを使用して効率化します。 + +### 4. パフォーマンスの最適化 + +- **チャンクサイズ**: 200-500 トークン +- **オーバーラップ率**: 10-20% +- **バッチサイズ**: 50-100 + +## 📞 テクニカルサポート + +### ドキュメントの参照 + +- 詳細な実装: `docs/VISION_PIPELINE_IMPLEMENTATION.md` +- API ドキュメント: `VISION_PIPELINE_SUMMARY.md` +- テストスクリプト: `server/test-*.ts` + +### デバッグツール + +```bash +# LibreOffice のテスト +curl http://localhost:8100/health + +# Tika のテスト +curl http://localhost:9998 + +# Elasticsearch のテスト +curl http://localhost:9200 + +# コンテナの状態を確認 +docker-compose ps +``` + +## ✅ チェックリスト + +起動前のチェック項目: + +- [ ] Docker と Docker Compose がインストールされている +- [ ] ポート 80, 3001, 8100, 9200, 9998 が他で使用されていない +- [ ] server/.env が設定されている +- [ ] Vision モデルの API キーが用意されている +- [ ] 少なくとも 4GB のメモリが使用可能 +- [ ] 十分なディスク容量がある (>5GB) + +使用前のチェック項目: + +- [ ] すべてのサービスの状態が Up になっている +- [ ] Vision モデルが設定されている +- [ ] Embedding(埋め込み)モデルが設定されている +- [ ] クォータが十分にある +- [ ] テスト用ファイルが用意されている + +--- + +**完了です!** これで Vision Pipeline システムを使用して、画像とテキストが混在したドキュメントを処理する準備が整いました!🎉 diff --git a/README.md b/README.md new file mode 100644 index 0000000..6db3b05 --- /dev/null +++ b/README.md @@ -0,0 +1,207 @@ +# AuraK + +AuraK is a multi-tenant intelligent AI knowledge base platform. Built with React + NestJS, it's a full-stack RAG (Retrieval-Augmented Generation) system with external API support, RBAC, and tenant isolation. + +## ✨ Features + +- 🔐 **User System**: Complete user registration, login, and permission management +- 🤖 **Multi-Model Support**: OpenAI-compatible interfaces + Google Gemini native support +- 📚 **Intelligent Knowledge Base**: Document upload, chunking, vectorization, hybrid search +- 💬 **Streaming Chat**: Real-time display of processing status and generated content +- 🔍 **Citation Tracking**: Clear display of source documents and related segments for answers +- 🌍 **Multi-Language Support**: Japanese, Chinese, and English for interface and AI responses +- 👁️ **Vision Capabilities**: Supports multimodal models for image processing +- ⚙️ **Flexible Configuration**: User-specific API keys and inference parameter customization +- 🎯 **Dual-Mode Processing**: Fast mode (Tika) + High-precision mode (Vision Pipeline) +- 💰 **Cost Management**: User quota management and cost estimation + +## 🏗️ Tech Stack + +### Frontend + +- **Framework**: React 19 + TypeScript + Vite +- **Styling**: Tailwind CSS +- **Icons**: Lucide React +- **State Management**: React Context + +### Backend + +- **Framework**: NestJS + TypeScript +- **AI Framework**: LangChain +- **Database**: SQLite (metadata) + Elasticsearch (vector storage) +- **File Processing**: Apache Tika + Vision Pipeline +- **Authentication**: JWT +- **Document Conversion**: LibreOffice + ImageMagick + +## 🏢 Internal Network Deployment + +This system supports deployment in internal networks. Main modifications include: + +- **External Resources**: KaTeX CSS moved from external CDN to local resources +- **AI Models**: Supports configuring internal AI model services without external API access +- **Build Configuration**: Dockerfiles can be configured to use internal image registries + +See [Internal Deployment Guide](INTERNAL_DEPLOYMENT_GUIDE.md) for detailed configuration instructions. + +## 🚀 Quick Start + +### Prerequisites + +- Node.js 18+ +- Yarn +- Docker & Docker Compose + +### 1. Clone the Project + +```bash +git clone +cd simple-kb +``` + +### 2. Install Dependencies + +```bash +yarn install +``` + +### 3. Start Basic Services + +```bash +docker-compose up -d elasticsearch tika libreoffice +``` + +### 4. Configure Environment Variables + +```bash +# Backend environment setup +cp server/.env.sample server/.env +# Edit server/.env file (set API keys, etc.) + +# Frontend environment setup +cp web/.env.example web/.env +# Edit web/.env file (modify frontend settings as needed) +``` + +See the comments in `server/.env.sample` and `web/.env.example` for detailed configuration. + +### 5. Start Development Server + +```bash +yarn dev +``` + +Access http://localhost:5173 to get started! + +## 📖 User Guide + +### 1. User Registration/Login + +- Account registration is required for first-time use. +- Each user has their own independent knowledge base and model settings. + +### 2. AI Model Configuration + +- Add AI models from "Model Management". +- Supports OpenAI, DeepSeek, Claude and other compatible interfaces. +- Supports Google Gemini native interface. +- Configure LLM, Embedding, and Rerank models. + +### 3. Document Upload + +- Supports various formats: PDF, Word, PPT, Excel, etc. +- Choose between Fast mode (text-only) or High-precision mode (image + text mixed). +- Adjustable chunk size and overlap for documents. +- Select embedding model for vectorization. + +### 4. Start Intelligent Q&A + +- Ask questions based on uploaded documents. +- View search and generation process in real-time. +- Check answer sources and related document fragments. + +## 🔧 Configuration Guide + +### Model Settings + +- **LLM Model**: Used for dialogue generation (e.g., GPT-4, Gemini-1.5-Pro) +- **Embedding Model**: Used for document vectorization (e.g., text-embedding-3-small) +- **Rerank Model**: Used for re-ranking search results (optional) + +### Inference Parameters + +- **Temperature**: Controls answer randomness (0-1) +- **Max Tokens**: Maximum output length +- **Top K**: Number of document segments to search +- **Similarity Threshold**: Filters low-relevance content + +## 📁 Project Structure + +``` +simple-kb/ +├── web/ # Frontend application +│ ├── components/ # React components +│ ├── services/ # API services +│ ├── contexts/ # React Context +│ └── utils/ # Utility functions +├── server/ # Backend application +│ ├── src/ +│ │ ├── auth/ # Authentication module +│ │ ├── chat/ # Chat module +│ │ ├── knowledge-base/ # Knowledge base module +│ │ ├── model-config/ # Model configuration module +│ │ └── user/ # User module +│ └── data/ # Data storage +├── docs/ # Project documentation +└── docker-compose.yml # Docker configuration +``` + +## 📚 Documentation + +- [System Design Document](docs/DESIGN.md) +- [Current Implementation Status](docs/CURRENT_IMPLEMENTATION.md) +- [API Documentation](docs/API.md) +- [Deployment Guide](docs/DEPLOYMENT.md) +- [RAG Feature Implementation](docs/rag_complete_implementation.md) + +## 🐳 Docker Deployment + +### Development Environment + +```bash +# Start basic services +docker-compose up -d elasticsearch tika + +# Local development +yarn dev +``` + +### Production Environment + +```bash +# Build and start all services +docker-compose up -d +``` + +## 🤝 Contributing + +1. Fork the project +2. Create a feature branch (`git checkout -b feature/AmazingFeature`) +3. Commit your changes (`git commit -m 'Add some AmazingFeature'`) +4. Push to the branch (`git push origin feature/AmazingFeature`) +5. Open a Pull Request + +## 📄 License + +This project is provided under the MIT license. See the [LICENSE](LICENSE) file for details. + +## 🙏 Acknowledgments + +- [LangChain](https://langchain.com/) - AI application development framework +- [NestJS](https://nestjs.com/) - Node.js backend framework +- [React](https://react.dev/) - Frontend UI framework +- [Elasticsearch](https://www.elastic.co/) - Search and analytics engine +- [Apache Tika](https://tika.apache.org/) - Document parsing tool + +## 📞 Support + +For questions or suggestions, please submit an [Issue](../../issues) or contact the maintainers. diff --git a/README_ZH.md b/README_ZH.md new file mode 100644 index 0000000..06594b9 --- /dev/null +++ b/README_ZH.md @@ -0,0 +1,119 @@ +# AuraK:企业级全栈智能 AI 知识平台 + +AuraK 是一个基于 **React 19** 与 **NestJS** 构建的现代化企业级 AI 知识库与人才评价系统。它不仅提供了高度可扩展的 RAG(检索增强生成)能力,还深度集成了多租户管理、交互式评价工作流及飞书办公生态。 + +--- + +## ✨ 核心特性 + +### 🔐 企业级多租户与权限 +- **租户隔离**:严格的数据与资源租户级物理隔离,支持独立域名/子域名挂载。 +- **RBAC 权限管理**:预置超级管理员、租户管理员、普通用户等多种角色。 +- **成员管理**:支持租户内成员邀请、权限分配与配额限制。 + +### 📚 智能知识路由与管理 +- **层级化分组**:支持知识库文件的文件夹式层级管理(Knowledge Groups),轻松应对海量文档。 +- **双模式处理流水线**: + - **快速模式 (Fast)**:基于 Apache Tika,极速提取海量纯文本。 + - **高精度模式 (High-Precision)**:集成了 **Vision Pipeline**,利用多模态模型识别复杂 PDF/图片中的图文混合内容。 +- **格式全支持**:原生支持 PDF, Word, PPT, Excel, TXT, Markdown 以及各类图片格式。 + +### 📊 交互式人才评价 (Assessment) +- **LangGraph 工作流**:基于图结构的 AI 对话逻辑,实现逻辑严密的自动化面试与素质评价。 +- **落地式出题 (Grounded Q&A)**:基于 RAG 技术,从自有知识库中根据关键词精准提取素材生成专业题目。 +- **加权智能评分**:支持 Standard (1.0), Advanced (1.5), Specialist (2.0) 三级难度权重的自动化综合评分。 +- **多语言评价**:支持中、英、日三语同步测评。 + +### 🤖 深度飞书办公集成 +- **免公网 WebSocket 机器人**:支持通过飞书长连接(WebSocket)直接接入企业内网,无需公网 IP 或域名映射。 +- **互动消息卡片**:在飞书中实时展示 AI 思考过程、检索来源及测评进度。 +- **移动端评价**:用户可直接在飞书聊天窗口完成完整的人才评价流程。 + +### 🚀 高级 RAG 性能优化 +- **混合检索 (Hybrid Search)**:结合 Elasticsearch 的 BM25 关键词检索与高维度向量检索,大幅提升首选片段准确率。 +- **智能重排序 (Rerank)**:内置 Rerank 模型二次校验,确保生成内容的真实性与相关性。 +- **SSE 流式响应**:秒级首屏响应,实时展示知识检索状态与生成进度。 + +### 🛠️ 生产力增强工具 +- **播客生成 (Podcasts)**:一键将长文档转化为播客形式的音频摘要。 +- **智能笔记 (Notes)**:支持对知识库内容记录分类笔记。 +- **搜索历史溯源**:完整的聊天历史记录与引用文档回溯。 + +--- + +## 🏗️ 技术架构 + +### 前端 (Web) +- **核心**:React 19 + TypeScript + Vite +- **UI/样式**:Tailwind CSS + Lucide React +- **交互**:React Context + SSE Streaming + Framer Motion (微动画) + +### 后端 (Server) +- **框架**:NestJS (Node.js) + TypeScript +- **AI 引擎**:LangChain + **LangGraph** (评价工作流) +- **存储**:SQLite (元数据) + **Elasticsearch** (向量与全文检索) +- **处理层**:Apache Tika + Vision Pipeline + LibreOffice (文档转换) +- **通信**:Feishu WebSocket Manager + SSE + +--- + +## 🏢 内网部署支持 + +AuraK 专为私有化部署设计: +- **资源本地化**:KaTeX、字体等静态资源完全本地化,无需访问 CDN。 +- **私有模型接入**:支持接入各类 OpenAI 兼容格式的内网私有化模型服务。 +- **容器化部署**:提供完整的 Docker Compose 一键启动方案,支持私有镜像仓库。 + +详细指南请参考 [内网部署手册](INTERNAL_DEPLOYMENT_GUIDE.md)。 + +--- + +## 🚀 快速开始 + +### 1. 准备工作 +- Node.js 18+ +- Yarn +- Docker & Docker Compose + +### 2. 克隆与安装 +```bash +git clone +cd auraAuraK +yarn install +``` + +### 3. 启动周边服务 +```bash +docker-compose up -d elasticsearch tika libreoffice +``` + +### 4. 环境配置 +分别修改 `server/.env` 和 `web/.env`。 + +### 5. 启动项目 +```bash +yarn dev +``` +访问 `http://localhost:5173` 开始体验! + +--- + +## 📁 项目目录 +``` +auraAuraK/ +├── web/ # 前端 React 应用 +├── server/ # 后端 NestJS 应用 +│ ├── src/ +│ │ ├── tenant/ # 多租户管理 +│ │ ├── assessment/ # 合才评价 (LangGraph) +│ │ ├── feishu/ # 飞书集成 +│ │ ├── knowledge-group/# 知识库分组 +│ │ └── chat/ # RAG 核心逻辑 +├── docs/ # 技术方案与 API 文档 +└── docker-compose.yml # 全栈部署配置 +``` + +--- + +## 📄 开源协议 +本项目采用 MIT 协议。详见 [LICENSE](LICENSE) 文件。 diff --git a/STARTUP.md b/STARTUP.md new file mode 100644 index 0000000..942acb1 --- /dev/null +++ b/STARTUP.md @@ -0,0 +1,45 @@ +# AuraK 启动手册 + +## 快速启动 + +```bash +cd D:\AuraK +wsl sudo service docker start +wsl docker compose up -d +``` + +## 检查状态 + +```bash +wsl docker ps +``` + +## 访问地址 + +| 服务 | 地址 | +|------|------| +| 前端 | http://localhost | +| 后端API | http://localhost:3001 | +| Elasticsearch | http://localhost:9200 | +| Tika | http://localhost:9998 | +| LibreOffice | http://localhost:8100 | + +##常用命令 + +```bash +# 停止服务 +wsl docker compose down + +# 重启服务 +wsl docker compose restart + +# 查看日志 +wsl docker compose logs -f server +wsl docker compose logs -f web +``` + +## 注意事项 + +- 需要先启动WSL中的Docker服务:`wsl sudo service docker start` +- 再运行docker compose +- 如果WSL中缺少镜像,会自动从Docker Hub拉取 \ No newline at end of file diff --git a/all_used_keys.txt b/all_used_keys.txt new file mode 100644 index 0000000..29b01d7 --- /dev/null +++ b/all_used_keys.txt @@ -0,0 +1,521 @@ +2d +Authorization +a +actionFailed +actions +addFile +addUser +admin +agentDesc +agentTitle +aiAssistant +aiCommandsApplyResult +aiCommandsCustom +aiCommandsCustomPlaceholder +aiCommandsError +aiCommandsGenerating +aiCommandsGoBack +aiCommandsModalApply +aiCommandsModalBasedOnSelection +aiCommandsModalCustom +aiCommandsModalCustomPlaceholder +aiCommandsModalPreset +aiCommandsModalResult +aiCommandsPreset +aiCommandsReferenceContext +aiCommandsReset +aiCommandsResult +aiCommandsStartGeneration +aiDisclaimer +all +allDocuments +allFormats +allKnowledgeGroups +allNotes +analyzing +analyzingFile +analyzingImage +apiError +associateKnowledgeGroup +autoAdjustChunk +autoAdjustOverlap +autoAdjustOverlapMin +back +backToWorkspace +baseApi +broad +browseFiles +browseManageFiles +btnChat +cancel +canvas +categories +category +categoryCreated +categoryDesc +categoryName +changePassword +changeUserPassword +chatDesc +chatHyperparameters +chatTitle +chatWithGroup +checkPDFStatusFailed +chunkConfig +chunkIndex +chunkInfo +chunkNumber +chunkOverlap +chunkSize +citationSources +clearFailed +clickToSelectAndNote +clickToSelectFolder +configured +confirm +confirmChange +confirmChangeEmbeddingModel +confirmClear +confirmClearKB +confirmDeleteCategory +confirmDeleteFile +confirmDeleteGroup +confirmDeleteHistory +confirmDeleteNote +confirmDeleteNotebook +confirmDeleteUser +confirmPassword +confirmPreciseCost +confirmRegeneratePDF +confirmRemoveFileFromGroup +confirmTitle +confirmUnsupportedFile +contentLength +contentOCR +conversionFailed +convertingInProgress +convertingPDF +copied +copy +copyContent +copySuccess +create +createAgent +createCategory +createCategoryBtn +createFailed +createFailedRetry +createGroupDesc +createNotebook +createNotebookTitle +createNow +createPDFNote +createUserFailed +createdAt +creating +creatingRegularUser +creative +ctx +currentPassword +daysAgo +defaultBadge +defaultForUploads +defaultLLMModel +defaultSettingFailed +defaultTenant +defaultVisionModel +delete +deleteFailed +deleteHistoryFailed +deleteHistorySuccess +deleteUser +deleteUserFailed +descPlaceholder +dimensions +dims +directoryLabel +documentsAndText +domainOptional +done +downloadPDF +downloadPDFFailed +dragDropUploadDesc +dragDropUploadTitle +dragToSelect +dropAnywhere +dropToIngest +editCategory +editNote +editNotebookTitle +editUserRole +embeddingModel +embeddingModelWarning +enableHyDE +enableHybridSearch +enableQueryExpansion +enableReranking +enterNamePlaceholder +enterNewPassword +enterNoteTitle +enterPageNumber +envLimitWeaker +error +errorGeneric +errorLabel +errorLoadData +errorMessage +errorNoModel +errorSaveFailed +errorTitleContentRequired +errorUploadFile +exampleResearch +exitFullscreen +exitSelectionMode +expandMenu +extractingText +failedToAddToGroup +failedToCreateCategory +failedToDeleteCategory +failedToRemoveFromGroup +failedToSaveSettings +fastMode +fastModeDesc +fastModeFeatures +featureUpdated +fileAddedToGroup +fileDeleted +fileRemovedFromGroup +fileSizeLimitExceeded +files +fillTargetName +filterGroupFiles +filterLowResults +filterNotesPlaceholder +fullTextSearch +fullscreenDisplay +geminiError +generalSettings +generalSettingsSubtitle +generatePDFPreviewButton +getUserListFailed +globalNoSpecificGroup +globalTenantControl +goToAdmin +groupCreated +groupDeleted +groupUpdated +groups +headerHyperparams +headerModelSelection +headerRetrieval +hidePreview +historyMessages +historyTitle +hybridSearchDesc +hybridVectorWeight +hybridVectorWeightDesc +hybridWeight +hydeDesc +idxCancel +idxDesc +idxEmbeddingModel +idxFiles +idxMethod +idxModalTitle +idxStart +imagesAndVision +importComplete +importFolder +importFolderTip +importFolderTitle +importToCurrentGroup +importedFromLocalFolder +indexingChunkingConfig +indexingConfigDesc +indexingConfigTitle +info +installPlugin +installedPlugin +kbCleared +kbManagement +kbManagementDesc +kbSettingsSaved +kbSettingsSubtitle +langEn +langJa +langZh +languageSettings +lblEmbedding +lblMaxTokens +lblRerank +lblRerankRef +lblTargetGroup +lblTemperature +lblTopK +loadFailed +loadHistoryFailed +loadLimitsFailed +loadMore +loadVisionModelFailed +loading +loadingHistoriesFailed +loadingPDF +loadingUserData +loginButton +loginDesc +loginError +loginRequired +loginTitle +loginToUpload +logout +matchScore +max +maxBatchSize +maxChunkSize +maxInput +maxOverlapSize +maxResponseTokens +maxValueMsg +min +mmAddBtn +mmCancel +mmEdit +mmEmpty +mmErrorBaseUrlRequired +mmErrorModelIdRequired +mmErrorNameRequired +mmErrorNotAuthenticated +mmFormApiKey +mmFormApiKeyPlaceholder +mmFormBaseUrl +mmFormModelId +mmFormName +mmFormType +mmSave +mmTitle +model +modelConfiguration +modelDisabled +modelEnabled +modelLimitsInfo +modelManagement +modelManagementSubtitle +modifySettings +name +nameHelp +namePlaceholder +navAgent +navCatalog +navChat +navKnowledge +navKnowledgeGroups +navNotebook +navPlugin +navTenants +needLogin +newChat +newGroup +newNote +newPassword +newPasswordMinLength +newTenant +next +nextStep +noContentToPreview +noDescriptionProvided +noFiles +noFilesDesc +noFilesFound +noGroups +noGroupsFound +noHistory +noHistoryDesc +noKnowledgeGroups +noNotesFound +noRerankModel +noTextExtracted +noVisionModels +none +noneUncategorized +noteCreatedFailed +noteCreatedSuccess +noteTitlePlaceholder +notebookDesc +notebooks +notebooksDesc +onlyAdminCanModify +openInNewWindow +openPDFInNewTabFailed +operational +optimizationTips +orgManagement +overlapRatioLimit +page +password +passwordChangeFailed +passwordChangeSuccess +passwordMinLength +passwordMismatch +passwordPlaceholder +pdfConversionError +pdfConversionFailed +pdfLoadError +pdfLoadFailed +pdfPreview +pdfPreviewReady +pendingFiles +personalNotebook +placeholderEmpty +placeholderNewGroup +placeholderText +placeholderWithFiles +pleaseSelect +pleaseSelectKnowledgeGroupFirst +pleaseWait +pluginBy +pluginCommunity +pluginConfig +pluginDesc +pluginOfficial +pluginTitle +position +precise +preciseMode +preciseModeDesc +preciseModeFeatures +preparingPDFConversion +preview +previewHeader +previewNotSupported +previous +processingMode +pureText +pureVector +queryExpansionDesc +readFailed +readingFailed +recommendationMsg +recommendationReason +reconfigureDesc +reconfigureFile +reconfigureTitle +regeneratePDF +releaseToIngest +requestRegenerationFailed +rerankModel +rerankSimilarityThreshold +rerankingDesc +resetZoom +retrievalSearchSettings +retry +roleRegularUser +roleTenantAdmin +save +saveChanges +saveNote +saveVisionModelFailed +saving +screenshotPreview +searchAgent +searchGroupsPlaceholder +searchPlaceholder +searchPlugin +searchResults +secureIngestion +secureProcessing +selectCategory +selectEmbedding +selectEmbeddingFirst +selectEmbeddingModel +selectFolderTip +selectKnowledgeGroup +selectKnowledgeGroups +selectLLM +selectLLMModel +selectOrganization +selectPageNumber +selectVisionModel +selectedFilesCount +selectedGroupsCount +settings +shortDescription +showPreview +showingRange +sidebarDesc +sidebarTitle +similarityThreshold +sourcePreview +startByCreatingNote +startProcessing +startWritingPlaceholder +statusIndexingDesc +statusReadyDesc +statusRunning +statusStopped +strict +subFolderPlaceholder +submitFailed +success +successNoteCreated +successNoteDeleted +successNoteUpdated +successUploadFile +supportedFormatsInfo +switchLanguage +systemConfiguration +systemHealth +systemUsers +tabSettings +targetRole +temperature +tenantsSubtitle +textarea +tipChunkTooLarge +tipMaxValues +tipOverlapSmall +tipPreciseCost +title +topK +totalChunks +totalTenants +typeEmbedding +typeLLM +typeRerank +typeVision +uncategorized +uncategorizedFiles +unknownError +unknownGroup +unsupportedFileType +updateFailedRetry +updatePlugin +updateUserFailed +updatedAtPrefix +uploadErrors +uploadFailed +uploadWarning +uploading +user +userAddedToOrganization +userCreatedSuccess +userDeletedSuccessfully +userDemotedFromAdmin +userList +userManagement +userManagementSubtitle +userPromotedToAdmin +username +usernamePlaceholder +vectorSimilarityThreshold +viewHistory +visionModelHelp +visionModelSettings +visualVision +warning +welcomeMessage +x-api-key +x-tenant-id +x-user-language +yesterday +zoomIn +zoomOut \ No newline at end of file diff --git a/apply_cjk_translations.js b/apply_cjk_translations.js new file mode 100644 index 0000000..9e9c74b --- /dev/null +++ b/apply_cjk_translations.js @@ -0,0 +1,337 @@ +const fs = require('fs'); +const path = require('path'); + +const directories = ['d:/workspace/AuraK/web', 'd:/workspace/AuraK/server/src']; +const excludeDirs = ['node_modules', '.git', 'dist', '.next', 'dist-check', 'docs', 'data']; +const extensions = ['.ts', '.tsx', '.js', '.jsx']; + +const translations = { + // ChatInterface.tsx + "履歴メッセージの読み込みを処理": "Handle loading of history messages", + "履歴メッセージが読み込まれたことを親コンポーネントに通知": "Notify parent component that history messages have been loaded", + "デバウンス機構:500ms以内の重複送信を防止": "Debounce mechanism: prevent duplicate submissions within 500ms", + "入力欄を即座にクリアして高さをリセットし、重複送信を防止": "Instantly clear input field and reset height to prevent duplicate submission", + "フォーカスを外す": "Remove focus", + "初期ボットメッセージを追加": "Add initial bot message", + "グループフィルタを渡す": "Pass group filter", + "ファイルフィルタを渡す": "Pass file filter", + "履歴IDを渡す": "Pass history ID", + "Rerankスイッチを渡す": "Pass Rerank switch", + "RerankモデルIDを渡す": "Pass Rerank model ID", + "温度パラメータを渡す": "Pass temperature parameter", + "最大トークン数を渡す": "Pass max tokens", + "Top-Kパラメータを渡す": "Pass Top-K parameter", + "類似度しきい値を渡す": "Pass similarity threshold", + "Rerankしきい値を渡す": "Pass Rerank threshold", + "クエリ拡張を渡す": "Pass query expansion", + "HyDEを渡す": "Pass HyDE", + + // CreateNoteFromPDFDialog.tsx + "ナレッジグループが選択されているか確認": "Check if knowledge group is selected", + "使用 toast 提示用户先选择知识组": "Use toast to prompt user to select a knowledge group first", + + // FileGroupTags.tsx + "カスタムイベントを監視してグループセレクターを開く": "Monitor custom events to open group selector", + "正しい方法:すべてのグループID(既存 + 新規)を渡す": "Correct method: pass all group IDs (existing + new)", + + // GroupManager.tsx + "分组列表": "Group list", + "个文件": " files", + "创建按钮": "Create button", + "创建/编辑模态框": "Create/Edit modal", + "颜色标识": "Color indicator", + + // GroupSelector.tsx + "选择分组范围": "Select group scope", + "全部分组": "All groups", + "已选 ": "Selected ", + " 个分组": " groups", + "搜索分组...": "Search groups...", + "未找到相关分组": "No related groups found", + "暂无分组": "No groups", + + // IndexingModalWithMode.tsx + "ユーザーによる手動選択をマーク": "Mark manual selection by user", + + // InputDrawer.tsx + "确定": "Confirm", + "取消": "Cancel", + + // SidebarRail.tsx + "ナビゲーション項目": "Navigation items", + "現在のルートに基づいてアクティブなタブを決定": "Determine active tab based on current route", + + // ModeSelector.tsx + "処理モード選択コンポーネント": "Processing mode selection component", + "ファイルアップロード時に高速モードまたは精密モードを選択するために使用": "Used to select fast or precise mode when uploading files", + "推薦されたモードを自動選択": "Automatically select recommended mode", + "処理モードの選択": "Select processing mode", + "分析中...": "Analyzing...", + "模式推荐信息": "Mode recommendation info", + "推奨:": "Recommended:", + "模式选择": "Mode selection", + "高速モード": "Fast Mode", + "テキストを単純に抽出、高速、プレーンテキストドキュメントに最適": "Simple text extraction, fast, ideal for plain text documents", + "高速": "Fast", + "追加コストなし": "No additional cost", + "テキスト情報のみ処理": "Processes text information only", + "精密モード": "Precise Mode", + "内容を正確に認識し、完全な情報を保持": "Accurately recognizes content and retains full information", + "画像/表を認識": "Recognizes images/tables", + "レイアウト情報を保持": "Retains layout information", + "図文混合コンテンツ": "Mixed image and text content", + "API費用が必要": "API cost required", + "処理時間が長い": "Long processing time", + + // PDFPreview.tsx + "ズームレベルの状態を追加": "Add zoom level state", + "現在のレンダリングタスクを保存": "Save current rendering task", + "ダウンロード用にpdfUrlを設定": "Set pdfUrl for download", + "PDFデータを取得してblob URLを作成": "Fetch PDF data and create blob URL", + "PDF文書の読み込みとレンダリングを開始": "Start fetching and rendering PDF document", + "ページ切り替えまたはズームレベル変更時に再レンダリング": "Re-render on page change or zoom level change", + "ステータスがpendingの場合、変換を能動的にトリガー": "Actively trigger conversion if status is pending", + "PDF URLにアクセスして変換をトリガー": "Access PDF URL to trigger conversion", + "進行中のレンダリングタスクが存在する場合、キャンセルする": "Cancel rendering task if one is in progress", + "ページめくり後のスクロール位置調整": "Adjust scroll position after page turn", + "pdfUrlが既にある場合、直接ダウンロード": "Directly download if pdfUrl already exists", + "pdfUrlがない場合、直接取得してダウンロードを試みる": "Try fetching and downloading if pdfUrl does not exist", + "pdfUrlがない場合、直接取得して開くことを試みる": "Try fetching and opening if pdfUrl does not exist", + "状態をリセットして再読み込みをトリガー": "Reset state and trigger reload", + "連続ページめくりを防止": "Prevent rapid page turning", + "下にスクロールして次のページへ": "Scroll down for next page", + "上にスクロールして前のページへ": "Scroll up for previous page", + "头部": "Header", + "内容区域": "Content Area", + "エラーを無視し、デフォルト状態を使用": "Ignore error and use default state", + + // PDFSelectionTool.tsx + "オプションのズームレベルパラメータ": "Optional zoom level parameter", + "デフォルトのズームレベルは1.0": "Default zoom level is 1.0", + "コンテナに対する実際の座標を使用": "Use actual coordinates relative to container", + + // SettingsModal.tsx + "モデル一覧を再取得するためにページをリロード": "Reload page to fetch model list again", + "言語セクション": "Language section", + "中文": "Chinese", + "日本語": "Japanese", + "サイドバー": "Sidebar", + "コンテンツエリア": "Content Area", + + // Toast.tsx + "等待动画完成": "Wait for animation to complete", + + // ChatView.tsx + "历史记录按钮": "History button", + "新建对话按钮": "New chat button", + "知识库增强功能模态框": "Knowledge base enhancement features modal", + + // SettingsView.tsx + "ユーザー一覧の取得(ユーザータブがアクティブな場合)": "Fetch user list (if users tab is active)", + "一般タブのハンドラー": "General tab handlers", + "ユーザータブのハンドラー": "Users tab handlers", + "ユーザーリストを再取得": "Re-fetch user list", + "モデルタブのハンドラー": "Models tab handlers", + "レンダリング関数": "Rendering functions", + "パスワード変更セクション": "Change password section", + "语言设置セクション": "Language settings section", + + // ToastContext.tsx + "相同消息去重:如果已存在相同的消息(类型和内容相同),则先移除旧的": "Deduplicate identical messages: discard old one if current type and content are the same", + + // apiClient.ts + "新しい API 呼び出し方法、{ data, status } を返す": "New API call method, returns { data, status }", + + // chatService.ts + "追加: 選択された LLM ID": "Added: Selected LLM ID", + "追加: 選択されたグループ": "Added: Selected groups", + "追加: 選択されたファイル": "Added: Selected files", + "追加: 会話履歴 ID": "Added: Conversation history ID", + "追加: Rerank を有効にする": "Added: Enable Rerank", + "追加: Rerank モデル ID": "Added: Rerank model ID", + "追加: temperature パラメータ": "Added: temperature parameter", + "追加: maxTokens パラメータ": "Added: maxTokens parameter", + "追加: topK パラメータ": "Added: topK parameter", + "追加: similarityThreshold パラメータ": "Added: similarityThreshold parameter", + "追加: rerankSimilarityThreshold パラメータ": "Added: rerankSimilarityThreshold parameter", + "追加: enableQueryExpansion": "Added: enableQueryExpansion", + "追加: enableHyDE": "Added: enableHyDE", + "追加": "Added", + "グループフィルタパラメータを渡す": "Pass group filter parameters", + "ファイルフィルタパラメータを渡す": "Pass file filter parameters", + "履歴 ID を渡す": "Pass history ID", + "temperature パラメータを渡す": "Pass temperature parameter", + "maxTokens パラメータを渡す": "Pass maxTokens parameter", + "topK パラメータを渡す": "Pass topK parameter", + "similarityThreshold パラメータを渡す": "Pass similarityThreshold parameter", + "rerankSimilarityThreshold パラメータを渡す": "Pass rerankSimilarityThreshold parameter", + "enableQueryExpansion を渡す": "Pass enableQueryExpansion", + "enableHyDE を渡す": "Pass enableHyDE", + "リクエストに失敗しました": "Request failed", + "サーバーエラー": "Server error", + "レスポンスストリームを読み取れません": "Cannot read response stream", + "ネットワークエラー": "Network error", + + // chunkConfigService.ts + "チャンク設定サービス - チャンク設定の制限の取得と検証に使用": "Chunk configuration service - Used to fetch and validate chunk configuration limits", + "最大チャンクサイズ": "Max chunk size", + "最大重複サイズ": "Max overlap size", + "最小重複サイズ": "Min overlap size", + "デフォルトチャンクサイズ": "Default chunk size", + "デフォルト重複サイズ": "Default overlap size", + "モデル情報": "Model info", + "モデル名": "Model name", + "モデル入力制限": "Model input limit", + "モデルバッチ制限": "Model batch limit", + "期待されるベクトル次元数": "Expected vector dimensions", + "チャンク設定の制限を取得": "Fetch chunk configuration limits", + "埋め込みモデルID": "Embedding model ID", + "認証トークン": "Auth token", + "設定制限情報": "Configuration limit info", + "チャンク設定が有効かどうかを検証": "Validate if chunk configuration is valid", + "チャンクサイズ": "Chunk size", + "重複サイズ": "Overlap size", + "設定制限": "Config limits", + "検証結果とエラー情報": "Validation results and error info", + "チャンクサイズの検証": "Validate chunk size", + "が上限": " exceeds limit ", + "を超えています": "", + "が最小値": " is below minimum ", + "未満です": "", + "重複サイズの検証": "Validate overlap size", + "がチャンクサイズの50%": " exceeds 50% of chunk size ", + "表示用に制限情報をフォーマット": "Format limit info for display", + "モデル:": "Model:", + "チャンク上限:": "Max Chunk:", + "重複上限:": "Max Overlap:", + "バッチ制限:": "Batch Limit:", + "ベクトル次元:": "Vector Dimensions:", + + // geminiService.ts + "请始终使用中文回答。": "Please always answer in English.", + "常に日本語で答えてください。": "Please always answer in English.", + "RAG検索(知識ベースファイルがある場合)": "RAG search (when knowledge base files exist)", + "検索ステータスがリセットされていることを確認": "Ensure search status is reset", + "APIキーはオプションです - ローカルモデルを許可します": "API key is optional - allow local models", + "より詳細なエラー情報を提供": "Provide more detailed error information", + "ネットワーク接続に失敗しました。サーバーの状態を確認してください": "Network connection failed. Please check server status", + + // knowledgeGroupService.ts + "すべてのグループを取得": "Fetch all groups", + "グループを作成": "Create group", + "グループを更新": "Update group", + "グループを削除": "Delete group", + "グループ内のファイルを取得": "Fetch files in group", + "ファイルをグループに追加": "Add file to group", + "グループからファイルを削除": "Remove file from group", + + // noteService.ts + "すべてのノートを取得(オプションでグループによるフィルタリングが可能)": "Fetch all notes (optional group filtering)", + "ノートを作成": "Create note", + "ノートを更新": "Update note", + "ノートを削除": "Delete note", + "ノートを知識ベースにインデックス(ベクトル化)": "Index note to knowledge base (vectorize)", + + // ocrService.ts + "OCR サービス - 画像テキスト認識関連の処理を担当": "OCR Service - Handles image text recognition", + "画像内のテキストを認識": "Recognize text in image", + + // pdfPreviewService.ts + "PDFプレビューサービス - PDFファイルのプレビュー状態と変換処理の管理を担当": "PDF Preview Service - Manages PDF preview state and conversion processing", + "PDFファイルがプレビュー可能か(画像に変換済みか)を確認": "Check if PDF file is previewable (converted to image)", + "ファイル情報またはPDF URL": "File info or PDF URL", + "認証状態用のトークン": "Auth token", + "変換状態": "Conversion state", + "存在しない場合はPDFの画像変換をトリガー": "Trigger PDF image conversion if not exists", + "この時点で変換ジョブがキューに追加されたとみなす": "At this point, assume conversion job has been queued", + + // ragService.ts + "RAG(Retrieval-Augmented Generation)サービス": "RAG (Retrieval-Augmented Generation) Service", + "ベクトル検索、ハイブリッド検索、再ランキング機能を提供": "Provides vector search, hybrid search, and reranking functionalities", + "チャンクテキスト": "Chunk text", + "スコア(類似度)": "Score (similarity)", + "ソースファイルのID": "Source file ID", + "ソースファイルの元の名前": "Original source file name", + "チャンクのインデックス": "Chunk index", + "チャンクのメタデータ": "Chunk metadata", + "検索結果": "Search results", + "元のユーザーの質問": "Original user question", + "拡張されたクエリ(クエリ拡張が有効な場合)": "Expanded queries (if query expansion is enabled)", + "ベクトル検索を実行": "Execute vector search", + "質問テキスト": "Question text", + "使用する埋め込みモデルのID": "Embedding model ID to use", + "オプションのフィルタ(グループ等)": "Optional filters (groups, etc)", + "再ランキングモデルを実行": "Execute reranking model", + "検索パラメーター": "Search parameters", + + // searchHistoryService.ts + "検索とチャットの履歴を管理するサービス": "Service for managing search and chat history", + "最新の履歴から順に取得": "Fetch history in descending order", + "ページ番号": "Page number", + "1ページあたりの件数": "Items per page", + "指定したIDの履歴詳細(メッセージを含む)を取得": "Fetch history details (including messages) for specific ID", + "新しい履歴エントリを作成": "Create new history entry", + "最初のメッセージから生成されたタイトル": "Title generated from first message", + "指定した履歴を削除": "Delete specified history", + "既存の履歴を更新(タイトル等)": "Update existing history (title, etc)", + "更新するデータ": "Data to update", + + // uploadService.ts + "チャンク設定付きでファイルをアップロード": "Upload file with chunk configuration", + "アップロードするファイル": "File to upload", + "テキストコンテンツを直接アップロードして処理": "Directly upload and process text content", + "テキストコンテンツ": "Text content", + "アップロード用のタイトル/ファイル名": "Title/filename for upload", + "チャンク設定": "Chunk configuration", + "ファイルモードの推奨を取得": "Get recommended file mode", + + // Other Server files + "コストを重視したVision Pipelineを使用して画像をテキストに変換": "Convert image to text using cost-aware Vision Pipeline", + + // translation_map.json + " `💰 推定コスト: $${estimatedCost.toFixed(2)}, 推定時間: ${duration.toFixed(1)}s`\n )": " `💰 Estimated cost: $${estimatedCost.toFixed(2)}, Estimated time: ${duration.toFixed(1)}s`\n )", + " this.logger.log(`💰 推定コスト: $${estimatedCost.toFixed(2)}, 推定時間: ${duration.toFixed(1)}s`);": " this.logger.log(`💰 Estimated cost: $${estimatedCost.toFixed(2)}, Estimated time: ${duration.toFixed(1)}s`);", + "チャンクサイズ ${chunkSize} が上限 ${limits.maxChunkSize} を超えています": "Chunk size ${chunkSize} exceeds maximum limit ${limits.maxChunkSize}", + "チャンクサイズ ${chunkSize} が最小値 50 未満です": "Chunk size ${chunkSize} is below minimum 50", + "重複サイズ ${chunkOverlap} が上限 ${limits.maxOverlapSize} を超えています": "Overlap size ${chunkOverlap} exceeds maximum limit ${limits.maxOverlapSize}", + "重複サイズ ${chunkOverlap} がチャンクサイズの50% (${maxOverlapByRatio}) を超えています": "Overlap size ${chunkOverlap} exceeds 50% of chunk size (${maxOverlapByRatio})" +}; + +function walkSync(currentDirPath, callback) { + fs.readdirSync(currentDirPath).forEach((name) => { + const filePath = path.join(currentDirPath, name); + const stat = fs.statSync(filePath); + if (stat.isFile()) { + callback(filePath); + } else if (stat.isDirectory() && !excludeDirs.includes(name)) { + walkSync(filePath, callback); + } + }); +} + +let modifiedCount = 0; + +directories.forEach(d => { + walkSync(d, (filePath) => { + if (extensions.some(ext => filePath.endsWith(ext))) { + try { + let content = fs.readFileSync(filePath, 'utf-8'); + let originalContent = content; + + for (const [key, value] of Object.entries(translations)) { + content = content.split(key).join(value); + } + + if (content !== originalContent) { + fs.writeFileSync(filePath, content, 'utf-8'); + console.log(`Updated: ${filePath}`); + modifiedCount++; + } + } catch (e) { + console.error(`Error reading ${filePath}: `, e); + } + } + }); +}); + +console.log(`Updated ${modifiedCount} files`); diff --git a/apply_cjk_translations.py b/apply_cjk_translations.py new file mode 100644 index 0000000..8199e85 --- /dev/null +++ b/apply_cjk_translations.py @@ -0,0 +1,332 @@ +import os +import re + +directories = ['d:/workspace/AuraK/web', 'd:/workspace/AuraK/server/src'] +exclude_dirs = ['node_modules', '.git', 'dist', '.next', 'dist-check', 'docs', 'data'] +extensions = ['.ts', '.tsx', '.js', '.jsx'] + +cjk_pattern = re.compile(r'[\u4e00-\u9fff\u3040-\u309f\u30a0-\u30ff]+') + +translations = { + # ChatInterface.tsx + "履歴メッセージの読み込みを処理": "Handle loading of history messages", + "履歴メッセージが読み込まれたことを親コンポーネントに通知": "Notify parent component that history messages have been loaded", + "デバウンス機構:500ms以内の重複送信を防止": "Debounce mechanism: prevent duplicate submissions within 500ms", + "入力欄を即座にクリアして高さをリセットし、重複送信を防止": "Instantly clear input field and reset height to prevent duplicate submission", + "フォーカスを外す": "Remove focus", + "初期ボットメッセージを追加": "Add initial bot message", + "グループフィルタを渡す": "Pass group filter", + "ファイルフィルタを渡す": "Pass file filter", + "履歴IDを渡す": "Pass history ID", + "Rerankスイッチを渡す": "Pass Rerank switch", + "RerankモデルIDを渡す": "Pass Rerank model ID", + "温度パラメータを渡す": "Pass temperature parameter", + "最大トークン数を渡す": "Pass max tokens", + "Top-Kパラメータを渡す": "Pass Top-K parameter", + "類似度しきい値を渡す": "Pass similarity threshold", + "Rerankしきい値を渡す": "Pass Rerank threshold", + "クエリ拡張を渡す": "Pass query expansion", + "HyDEを渡す": "Pass HyDE", + + # CreateNoteFromPDFDialog.tsx + "ナレッジグループが選択されているか確認": "Check if knowledge group is selected", + "使用 toast 提示用户先选择知识组": "Use toast to prompt user to select a knowledge group first", + + # FileGroupTags.tsx + "カスタムイベントを監視してグループセレクターを開く": "Monitor custom events to open group selector", + "正しい方法:すべてのグループID(既存 + 新規)を渡す": "Correct method: pass all group IDs (existing + new)", + + # GroupManager.tsx + "分组列表": "Group list", + "个文件": " files", + "创建按钮": "Create button", + "创建/编辑模态框": "Create/Edit modal", + "颜色标识": "Color indicator", + + # GroupSelector.tsx + "选择分组范围": "Select group scope", + "全部分组": "All groups", + "已选": "Selected", + "个分组": " groups", + "搜索分组...": "Search groups...", + "未找到相关分组": "No related groups found", + "暂无分组": "No groups", + + # IndexingModalWithMode.tsx + "ユーザーによる手動選択をマーク": "Mark manual selection by user", + + # InputDrawer.tsx + "确定": "Confirm", + "取消": "Cancel", + + # SidebarRail.tsx + "ナビゲーション項目": "Navigation items", + "現在のルートに基づいてアクティブなタブを決定": "Determine active tab based on current route", + + # ModeSelector.tsx + "処理モード選択コンポーネント": "Processing mode selection component", + "ファイルアップロード時に高速モードまたは精密モードを選択するために使用": "Used to select fast or precise mode when uploading files", + "推薦されたモードを自動選択": "Automatically select recommended mode", + "処理モードの選択": "Select processing mode", + "分析中...": "Analyzing...", + "模式推荐信息": "Mode recommendation info", + "推奨:": "Recommended:", + "模式选择": "Mode selection", + "高速モード": "Fast Mode", + "テキストを単純に抽出、高速、プレーンテキストドキュメントに最適": "Simple text extraction, fast, ideal for plain text documents", + "高速": "Fast", + "追加コストなし": "No additional cost", + "テキスト情報のみ処理": "Processes text information only", + "精密モード": "Precise Mode", + "内容を正確に認識し、完全な情報を保持": "Accurately recognizes content and retains full information", + "画像/表を認識": "Recognizes images/tables", + "レイアウト情報を保持": "Retains layout information", + "図文混合コンテンツ": "Mixed image and text content", + "API費用が必要": "API cost required", + "処理時間が長い": "Long processing time", + + # PDFPreview.tsx + "ズームレベルの状態を追加": "Add zoom level state", + "現在のレンダリングタスクを保存": "Save current rendering task", + "ダウンロード用にpdfUrlを設定": "Set pdfUrl for download", + "PDFデータを取得してblob URLを作成": "Fetch PDF data and create blob URL", + "PDF文書の読み込みとレンダリングを開始": "Start fetching and rendering PDF document", + "ページ切り替えまたはズームレベル変更時に再レンダリング": "Re-render on page change or zoom level change", + "ステータスがpendingの場合、変換を能動的にトリガー": "Actively trigger conversion if status is pending", + "PDF URLにアクセスして変換をトリガー": "Access PDF URL to trigger conversion", + "進行中のレンダリングタスクが存在する場合、キャンセルする": "Cancel rendering task if one is in progress", + "ページめくり後のスクロール位置調整": "Adjust scroll position after page turn", + "pdfUrlが既にある場合、直接ダウンロード": "Directly download if pdfUrl already exists", + "pdfUrlがない場合、直接取得してダウンロードを試みる": "Try fetching and downloading if pdfUrl does not exist", + "pdfUrlがない場合、直接取得して開くことを試みる": "Try fetching and opening if pdfUrl does not exist", + "状態をリセットして再読み込みをトリガー": "Reset state and trigger reload", + "連続ページめくりを防止": "Prevent rapid page turning", + "下にスクロールして次のページへ": "Scroll down for next page", + "上にスクロールして前のページへ": "Scroll up for previous page", + "头部": "Header", + "内容区域": "Content Area", + "エラーを無視し、デフォルト状態を使用": "Ignore error and use default state", + + # PDFSelectionTool.tsx + "オプションのズームレベルパラメータ": "Optional zoom level parameter", + "デフォルトのズームレベルは1.0": "Default zoom level is 1.0", + "コンテナに対する実際の座標を使用": "Use actual coordinates relative to container", + + # SettingsModal.tsx + "モデル一覧を再取得するためにページをリロード": "Reload page to fetch model list again", + "言語セクション": "Language section", + "中文": "Chinese", + "日本語": "Japanese", + "サイドバー": "Sidebar", + "コンテンツエリア": "Content Area", + + # Toast.tsx + "等待动画完成": "Wait for animation to complete", + + # ChatView.tsx + "历史记录按钮": "History button", + "新建对话按钮": "New chat button", + "知识库增强功能模态框": "Knowledge base enhancement features modal", + + # SettingsView.tsx + "ユーザー一覧の取得(ユーザータブがアクティブな場合)": "Fetch user list (if users tab is active)", + "一般タブのハンドラー": "General tab handlers", + "ユーザータブのハンドラー": "Users tab handlers", + "ユーザーリストを再取得": "Re-fetch user list", + "モデルタブのハンドラー": "Models tab handlers", + "レンダリング関数": "Rendering functions", + "パスワード変更セクション": "Change password section", + "语言设置セクション": "Language settings section", + + # ToastContext.tsx + "相同消息去重:如果已存在相同的消息(类型和内容相同),则先移除旧的": "Deduplicate identical messages: discard old one if current type and content are the same", + + # apiClient.ts + "新しい API 呼び出し方法、{ data, status } を返す": "New API call method, returns { data, status }", + + # chatService.ts + "追加: 選択された LLM ID": "Added: Selected LLM ID", + "追加: 選択されたグループ": "Added: Selected groups", + "追加: 選択されたファイル": "Added: Selected files", + "追加: 会話履歴 ID": "Added: Conversation history ID", + "追加: Rerank を有効にする": "Added: Enable Rerank", + "追加: Rerank モデル ID": "Added: Rerank model ID", + "追加: temperature パラメータ": "Added: temperature parameter", + "追加: maxTokens パラメータ": "Added: maxTokens parameter", + "追加: topK パラメータ": "Added: topK parameter", + "追加: similarityThreshold パラメータ": "Added: similarityThreshold parameter", + "追加: rerankSimilarityThreshold パラメータ": "Added: rerankSimilarityThreshold parameter", + "追加: enableQueryExpansion": "Added: enableQueryExpansion", + "追加: enableHyDE": "Added: enableHyDE", + "追加": "Added", + "グループフィルタパラメータを渡す": "Pass group filter parameters", + "ファイルフィルタパラメータを渡す": "Pass file filter parameters", + "履歴 ID を渡す": "Pass history ID", + "temperature パラメータを渡す": "Pass temperature parameter", + "maxTokens パラメータを渡す": "Pass maxTokens parameter", + "topK パラメータを渡す": "Pass topK parameter", + "similarityThreshold パラメータを渡す": "Pass similarityThreshold parameter", + "rerankSimilarityThreshold パラメータを渡す": "Pass rerankSimilarityThreshold parameter", + "enableQueryExpansion を渡す": "Pass enableQueryExpansion", + "enableHyDE を渡す": "Pass enableHyDE", + "リクエストに失敗しました": "Request failed", + "サーバーエラー": "Server error", + "レスポンスストリームを読み取れません": "Cannot read response stream", + "ネットワークエラー": "Network error", + + # chunkConfigService.ts + "チャンク設定サービス - チャンク設定の制限の取得と検証に使用": "Chunk configuration service - Used to fetch and validate chunk configuration limits", + "最大チャンクサイズ": "Max chunk size", + "最大重複サイズ": "Max overlap size", + "最小重複サイズ": "Min overlap size", + "デフォルトチャンクサイズ": "Default chunk size", + "デフォルト重複サイズ": "Default overlap size", + "モデル情報": "Model info", + "モデル名": "Model name", + "モデル入力制限": "Model input limit", + "モデルバッチ制限": "Model batch limit", + "期待されるベクトル次元数": "Expected vector dimensions", + "チャンク設定の制限を取得": "Fetch chunk configuration limits", + "埋め込みモデルID": "Embedding model ID", + "認証トークン": "Auth token", + "設定制限情報": "Configuration limit info", + "チャンク設定が有効かどうかを検証": "Validate if chunk configuration is valid", + "チャンクサイズ": "Chunk size", + "重複サイズ": "Overlap size", + "設定制限": "Config limits", + "検証結果とエラー情報": "Validation results and error info", + "チャンクサイズの検証": "Validate chunk size", + "が上限": " exceeds limit ", + "を超えています": "", + "が最小値": " is below minimum ", + "未満です": "", + "重複サイズの検証": "Validate overlap size", + "がチャンクサイズの50%": " exceeds 50% of chunk size ", + "表示用に制限情報をフォーマット": "Format limit info for display", + "モデル:": "Model:", + "チャンク上限:": "Max Chunk:", + "重複上限:": "Max Overlap:", + "バッチ制限:": "Batch Limit:", + "ベクトル次元:": "Vector Dimensions:", + + # geminiService.ts + "请始终使用中文回答。": "Please always answer in English.", + "常に日本語で答えてください。": "Please always answer in English.", + "RAG検索(知識ベースファイルがある場合)": "RAG search (when knowledge base files exist)", + "検索ステータスがリセットされていることを確認": "Ensure search status is reset", + "APIキーはオプションです - ローカルモデルを許可します": "API key is optional - allow local models", + "より詳細なエラー情報を提供": "Provide more detailed error information", + "ネットワーク接続に失敗しました。サーバーの状態を確認してください": "Network connection failed. Please check server status", + + # knowledgeGroupService.ts + "すべてのグループを取得": "Fetch all groups", + "グループを作成": "Create group", + "グループを更新": "Update group", + "グループを削除": "Delete group", + "グループ内のファイルを取得": "Fetch files in group", + "ファイルをグループに追加": "Add file to group", + "グループからファイルを削除": "Remove file from group", + + # noteService.ts + "すべてのノートを取得(オプションでグループによるフィルタリングが可能)": "Fetch all notes (optional group filtering)", + "ノートを作成": "Create note", + "ノートを更新": "Update note", + "ノートを削除": "Delete note", + "ノートを知識ベースにインデックス(ベクトル化)": "Index note to knowledge base (vectorize)", + + # ocrService.ts + "OCR サービス - 画像テキスト認識関連の処理を担当": "OCR Service - Handles image text recognition", + "画像内のテキストを認識": "Recognize text in image", + + # pdfPreviewService.ts + "PDFプレビューサービス - PDFファイルのプレビュー状態と変換処理の管理を担当": "PDF Preview Service - Manages PDF preview state and conversion processing", + "PDFファイルがプレビュー可能か(画像に変換済みか)を確認": "Check if PDF file is previewable (converted to image)", + "ファイル情報またはPDF URL": "File info or PDF URL", + "認証状態用のトークン": "Auth token", + "変換状態": "Conversion state", + "存在しない場合はPDFの画像変換をトリガー": "Trigger PDF image conversion if not exists", + "この時点で変換ジョブがキューに追加されたとみなす": "At this point, assume conversion job has been queued", + + # ragService.ts + "RAG(Retrieval-Augmented Generation)サービス": "RAG (Retrieval-Augmented Generation) Service", + "ベクトル検索、ハイブリッド検索、再ランキング機能を提供": "Provides vector search, hybrid search, and reranking functionalities", + "チャンクテキスト": "Chunk text", + "スコア(類似度)": "Score (similarity)", + "ソースファイルのID": "Source file ID", + "ソースファイルの元の名前": "Original source file name", + "チャンクのインデックス": "Chunk index", + "チャンクのメタデータ": "Chunk metadata", + "検索結果": "Search results", + "元のユーザーの質問": "Original user question", + "拡張されたクエリ(クエリ拡張が有効な場合)": "Expanded queries (if query expansion is enabled)", + "ベクトル検索を実行": "Execute vector search", + "質問テキスト": "Question text", + "使用する埋め込みモデルのID": "Embedding model ID to use", + "オプションのフィルタ(グループ等)": "Optional filters (groups, etc)", + "再ランキングモデルを実行": "Execute reranking model", + "検索パラメーター": "Search parameters", + + # searchHistoryService.ts + "検索とチャットの履歴を管理するサービス": "Service for managing search and chat history", + "最新の履歴から順に取得": "Fetch history in descending order", + "ページ番号": "Page number", + "1ページあたりの件数": "Items per page", + "指定したIDの履歴詳細(メッセージを含む)を取得": "Fetch history details (including messages) for specific ID", + "新しい履歴エントリを作成": "Create new history entry", + "最初のメッセージから生成されたタイトル": "Title generated from first message", + "指定した履歴を削除": "Delete specified history", + "既存の履歴を更新(タイトル等)": "Update existing history (title, etc)", + "更新するデータ": "Data to update", + + # uploadService.ts + "チャンク設定付きでファイルをアップロード": "Upload file with chunk configuration", + "アップロードするファイル": "File to upload", + "テキストコンテンツを直接アップロードして処理": "Directly upload and process text content", + "テキストコンテンツ": "Text content", + "アップロード用のタイトル/ファイル名": "Title/filename for upload", + "チャンク設定": "Chunk configuration", + "ファイルモードの推奨を取得": "Get recommended file mode", + + # api-v1.controller.ts + # Other Server files + "コストを重視したVision Pipelineを使用して画像をテキストに変換": "Convert image to text using cost-aware Vision Pipeline", + + # translation_map.json entries + " `💰 推定コスト: $${estimatedCost.toFixed(2)}, 推定時間: ${duration.toFixed(1)}s`\n )": " `💰 Estimated cost: $${estimatedCost.toFixed(2)}, Estimated time: ${duration.toFixed(1)}s`\n )", + " this.logger.log(`💰 推定コスト: $${estimatedCost.toFixed(2)}, 推定時間: ${duration.toFixed(1)}s`);": " this.logger.log(`💰 Estimated cost: $${estimatedCost.toFixed(2)}, Estimated time: ${duration.toFixed(1)}s`);", + "チャンクサイズ ${chunkSize} が上限 ${limits.maxChunkSize} を超えています": "Chunk size ${chunkSize} exceeds maximum limit ${limits.maxChunkSize}", + "チャンクサイズ ${chunkSize} が最小値 50 未満です": "Chunk size ${chunkSize} is below minimum 50", + "重複サイズ ${chunkOverlap} が上限 ${limits.maxOverlapSize} を超えています": "Overlap size ${chunkOverlap} exceeds maximum limit ${limits.maxOverlapSize}", + "重複サイズ ${chunkOverlap} がチャンクサイズの50% (${maxOverlapByRatio}) を超えています": "Overlap size ${chunkOverlap} exceeds 50% of chunk size (${maxOverlapByRatio})" +} + +def translate_file(filepath): + try: + with open(filepath, 'r', encoding='utf-8') as f: + content = f.read() + + original_content = content + + # Replace exact matches from translations dict + for k, v in translations.items(): + content = content.replace(k, v) + + # Also clean up any loose CJK comments by replacing them with a generic English comment + # Find all lines with // and CJK + def replace_generic_cjk(match): + return "// Translated comment or string" + + if content != original_content: + with open(filepath, 'w', encoding='utf-8') as f: + f.write(content) + print(f"Updated: {filepath}") + except Exception as e: + print(f"Failed to process {filepath}: {e}") + +for d in directories: + for root, dirs, files in os.walk(d): + dirs[:] = [dir for dir in dirs if dir not in exclude_dirs] + for file in files: + if any(file.endswith(ext) for ext in extensions): + filepath = os.path.join(root, file) + translate_file(filepath) diff --git a/apply_translations.js b/apply_translations.js new file mode 100644 index 0000000..93c078c --- /dev/null +++ b/apply_translations.js @@ -0,0 +1,43 @@ +const fs = require('fs'); + +const files = require('./files_to_translate.json'); +const translationMap = require('./translation_map.json'); + +let totalReplaced = 0; + +files.forEach(file => { + let content = fs.readFileSync(file, 'utf8'); + let originalContent = content; + + // Replace simple strings + const simpleStringRegex = /((?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*)(['"])(.*?[\u4e00-\u9fa5]+.*?)\2/g; + content = content.replace(simpleStringRegex, (match, prefix, quote, innerString) => { + if (translationMap[innerString]) { + totalReplaced++; + return prefix + quote + translationMap[innerString] + quote; + } + return match; + }); + + // Replace template literals + const templateRegex = /((?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*)\`([\s\S]*?)\`/g; + content = content.replace(templateRegex, (match, prefix, innerString) => { + if (/[\\u4e00-\\u9fa5]/.test(innerString) && translationMap[innerString]) { + totalReplaced++; + return prefix + '`' + translationMap[innerString] + '`'; + } + // If no direct match, check if there's an exact match in the map + if (translationMap[innerString]) { + totalReplaced++; + return prefix + '`' + translationMap[innerString] + '`'; + } + return match; + }); + + if (content !== originalContent) { + fs.writeFileSync(file, content, 'utf8'); + console.log('Updated ' + file); + } +}); + +console.log('Total replacements made: ' + totalReplaced); diff --git a/auto_dict.json b/auto_dict.json new file mode 100644 index 0000000..6da83e3 --- /dev/null +++ b/auto_dict.json @@ -0,0 +1,133 @@ +{ + "console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无');": "console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无');", + "`data: ${JSON.stringify({ type: 'error', data: '请在模型管理中添加LLM模型并配置API密钥' })}\\n\\n`,": "`data: ${JSON.stringify({ type: 'error', data: 'Please add LLM model and configure API key in model management' })}\\n\\n`,", + "`data: ${JSON.stringify({ type: 'error', data: error.message || '服务器错误' })}\\n\\n`,": "`data: ${JSON.stringify({ type: 'error', data: error.message || 'Server Error' })}\\n\\n`,", + "`data: ${JSON.stringify({ type: 'error', data: '未找到LLM模型配置' })}\\n\\n`,": "`data: ${JSON.stringify({ type: 'error', data: 'LLM model configuration not found' })}\\n\\n`,", + "console.log('ユーザーID:', userId);": "console.log('User ID:', userId);", + "console.log('API Key プレフィックス:', modelConfig.apiKey?.substring(0, 10) + '...');": "console.log('API Key prefix:', modelConfig.apiKey?.substring(0, 10) + '...');", + "提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善してください。": "Correct or improve the provided text content based on your instructions.", + "挨拶や結びの言葉(「わかりました、こちらが...」など)は含めず、修正後の内容のみを直接出力してください。": "Please do not include any greetings or closing words (such as \"Okay, this is...\") and directly output only the revised content.", + "コンテキスト(現在の内容):": "Context (current contents):", + "ユーザーの指示:": "User instructions:", + "1. **段落与结构**:": "1. **Paragraph and Structure**:", + "- 使用清晰的段落分隔,每个要点之间空一行": "- Use clear paragraph separation with a blank line between each bullet point", + "- 使用标题(## 或 ###)组织长回答": "- Use headings (## or ###) to organize long answers", + "2. **文本格式**:": "2. **Text Format**:", + "- 使用 **粗体** 强调重要概念和关键词": "- Use **bold** to emphasize important concepts and keywords", + "- 使用列表(- 或 1.)组织多个要点": "- Use lists (- or 1.) to organize multiple points", + "- 使用 \\`代码\\` 标记技术术语、命令、文件名": "- Use \\`code\\` to mark technical terms, commands, file names", + "3. **代码展示**:": "3. **Code display**:", + "- 使用代码块展示代码,并指定语言:": "- Use code blocks to display code and specify the language:", + "return \"示例\"": "return \"example\"", + "- 支持语言:python, javascript, typescript, java, bash, sql 等": "- Supported languages: python, javascript, typescript, java, bash, sql, etc.", + "4. **图表与可视化**:": "4. **Charts and Visualization**:", + "- 使用 Mermaid 语法绘制流程图、序列图等:": "- Use Mermaid syntax to draw flowcharts, sequence diagrams, etc.:", + "A[开始] --> B[处理]": "A[Start] --> B[Process]", + "B --> C[结束]": "B --> C[end]", + "- 适用场景:流程、架构、状态机、时序图": "- Applicable scenarios: process, architecture, state machine, sequence diagram", + "5. **其他要求**:": "5. **Other requirements**:", + "- 回答精炼准确": "- Answer concisely and accurately", + "- 多步骤操作使用有序列表": "- Use ordered lists for multi-step operations", + "- 对比类信息建议用表格展示(如果适用)": "- It is recommended to display comparative information in tables (if applicable)", + "ナレッジベースの内容:": "Knowledge base contents:", + "会話履歴:": "Conversation history:", + "ユーザーの質問:{question}": "User question: {question}", + "1. **段落と構造**:": "1. **Paragraphs and Structure**:", + "- 明確な段落分けを使用し、要点間に空行を入れる": "- Use clear paragraphing and leave blank lines between main points", + "- 長い回答には見出し(## または ###)を使用": "- Use headings (## or ###) for long answers", + "2. **テキスト書式**:": "2. **Text Format**:", + "- 重要な概念やキーワードを強調するために **太字** を使用": "- Use **bold** to highlight important concepts and keywords", + "- 複数のポイントを整理するためにリスト(- または 1.)を使用": "- Use lists (- or 1.) to organize multiple points", + "- 技術用語、コマンド、ファイル名をマークするために \\`コード\\` を使用": "- Use \\`code\\` to mark technical terms, commands, and file names", + "3. **コード表示**:": "3. **Code display**:", + "- 言語を指定してコードブロックを使用:": "- Use code blocks by specifying language:", + "return \"例\"": "return \"Example\"", + "- 対応言語:python, javascript, typescript, java, bash, sql など": "- Supported languages: python, javascript, typescript, java, bash, sql, etc.", + "4. **図表とチャート**:": "4. **Diagrams and Charts**:", + "- フローチャート、シーケンス図などに Mermaid 構文を使用:": "- Use Mermaid syntax for flowcharts, sequence diagrams, etc:", + "A[開始] --> B[処理]": "A[Start] --> B[Process]", + "B --> C[終了]": "B --> C[End]", + "- 使用例:プロセスフロー、アーキテクチャ図、状態図、シーケンス図": "- Usage examples: process flow, architecture diagram, state diagram, sequence diagram", + "5. **その他の要件**:": "5. **Other Requirements**:", + "- 簡潔で明確な回答を心がける": "- Keep your answers concise and clear", + "- 複数のステップがある場合は番号付きリストを使用": "- Use numbered lists when there are multiple steps", + "- 比較情報には表を使用(該当する場合)": "- Use tables for comparative information (if applicable)", + "インテリジェントアシスタントとして、ユーザーの質問に答えてください。": "Become an intelligent assistant and answer users' questions.", + "只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。": "Only the title text is returned. Do not include any explanatory text or leading words (such as \"The title is:\").", + "语言:Chinese": "Language: Chinese", + "文本内容:": "Text content:", + "タイトルテキストのみを返してください。説明文や前置き(例:「タイトルは:」)は含めないでください。": "Please return only the title text. Do not include descriptive text or prefaces (e.g. \"The title is:\").", + "言語:Japanese": "Language: Japanese", + "テキスト:": "text:", + "return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。": "return `Based on the following conversation snippet, generate a short, descriptive title (no more than 50 characters) summarizing the topic of the discussion.", + "只返回标题文本。不要包含任何前导词。": "Only the title text is returned. Do not include any leading words.", + "用户: ${userMessage}": "User: ${userMessage}", + "助手: ${aiResponse}`;": "Helper: ${aiResponse}`;", + "return `以下の会話スニペットに基づいて、トピックを要約する短く説明的なタイトル(最大50文字)を生成してください。": "return `Generate a short, descriptive title (up to 50 characters) that summarizes the topic based on the conversation snippet below.", + "タイトルのみを返してください。前置きは不要です。": "Please return only the title. No preface necessary.", + "ユーザー: ${userMessage}": "User: ${userMessage}", + "アシスタント: ${aiResponse}`;": "Assistant: ${aiResponse}`;", + "const providerName = modelConfig.providerName || '不明';": "const providerName = modelConfig.providerName || '不明';", + "` - プロバイダー: ${providerName}\\n` +": "` - Provider: ${providerName}\\n` +", + "` - Token制限: ${maxInputTokens}\\n` +": "` - Token limit: ${maxInputTokens}\\n` +", + "` - ベクトルモデルか: ${isVectorModel}`,": "` - Vector model: ${isVectorModel}`,", + "`Chunk size: ${chunkSize} tokens (制限: ${limits.maxInputTokens})`,": "`Chunk size: ${chunkSize} tokens (制限: ${limits.maxInputTokens})`,", + "`重なりサイズ: ${chunkOverlap} tokens`,": "`Overlap size: ${chunkOverlap} tokens`,", + "`バッチサイズ: ${limits.maxBatchSize}`,": "`Batch size: ${limits.maxBatchSize}`,", + "throw new Error(`埋め込みモデル設定 ${embeddingModelConfigId} が見つかりません`);": "throw new Error(`Embedded model configuration ${embeddingModelConfigId} not found`);", + "throw new Error(`モデル ${modelConfig.name} は無効化されているため、埋め込みベクトルを生成できません`);": "throw new Error(`Unable to generate embedding vector because model ${modelConfig.name} is disabled`);", + "throw new Error(`モデル ${modelConfig.name} に baseUrl が設定されていません`);": "throw new Error(`baseUrl not set for model ${modelConfig.name}`);", + "`総計 ${totalLength} 文字、平均 ${Math.round(avgLength)} 文字、` +": "`Total ${totalLength} characters, average ${Math.round(avgLength)} characters, ` +", + "`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens`": "`Model limit: ${modelConfig.maxInputTokens || 8192} tokens`", + "`テキスト長がモデルの制限。` +": "`Text length is a limitation of the model. ` +", + "`現在: ${texts.length} 個のテキストで計 ${totalLength} 文字、` +": "`Currently: ${texts.length} texts totaling ${totalLength} characters, ` +", + "`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens。` +": "`Model limit: ${modelConfig.maxInputTokens || 8192} tokens. ` +", + "`アドバイス: Chunk sizeまたはバッチサイズを小さくしてください`": "`Advice: Reduce chunk size or batch size`", + "this.logger.error(`リクエストパラメータ: model=${modelConfig.modelId}, inputLength=${texts[0]?.length}`);": "this.logger.error(`Request parameters: model=${modelConfig.modelId}, inputLength=${texts[0]?.length}`);", + "throw new Error(`埋め込み API の呼び出しに失敗しました: ${response.statusText} - ${errorText}`);": "throw new Error(`Embedded API call failed: ${response.statusText} - ${errorText}`);", + "if (error.message && (error.message.includes('context length') || error.message.includes('コンテキスト長 exceeds limit ') || error.message.includes('コンテキスト長 exceeds limit '))) {": "if (error.message && (error.message.includes('context length') || error.message.includes('context length exceeds limit ') || error.message.includes('context length exceeds limit '))) {", + "throw new NotFoundException('ファイルが存在しません');": "throw new NotFoundException('File does not exist');", + "throw new Error(`メモリ待機がタイムアウトしました: 現在 ${this.getMemoryUsage().heapUsed}MB > ${this.MAX_MEMORY_MB * 0.85}MB`);": "throw new Error(`Memory wait timed out: Currently ${this.getMemoryUsage().heapUsed}MB > ${this.MAX_MEMORY_MB * 0.85}MB`);", + "throw new Error(`ファイルが存在しません: ${filePath}`);": "throw new Error(`File does not exist: ${filePath}`);", + "throw new Error('変換がタイムアウトしました。ファイルが大きすぎる可能性があります');": "throw new Error('Conversion timed out. File may be too large');", + "throw new Error(`変換に失敗しました: ${detail}`);": "throw new Error(`Conversion failed: ${detail}`);", + "throw new Error(`変換に失敗しました: ${lastError.message}`);": "throw new Error(`Conversion failed: ${lastError.message}`);", + "throw new Error('LibreOffice サービスが実行されていません。サービスの状態を確認してください');": "throw new Error('LibreOffice service is not running. Please check the status of the service');", + "throw new Error('LibreOffice サービスとの接続が切断されました。サービスが不安定である可能性があります');": "throw new Error('The connection to the LibreOffice service has been lost. The service may be unstable');", + "@Min(1, { message: 'ベクトル次元の最小値は 1 です' })": "@Min(1, { message: 'The minimum value of the vector dimension is 1' })", + "@Max(4096, { message: 'ベクトル次元の最大値は 4096 です(Elasticsearch の制限)' })": "@Max(4096, { message: 'The maximum vector dimension is 4096 (Elasticsearch limit)' })", + "throw new Error(`PDF ファイルが存在しません: ${pdfPath}`);": "throw new Error(`PDF file does not exist: ${pdfPath}`);", + "throw new Error('PDF のページ数を取得できません');": "throw new Error('Unable to get page number of PDF');", + "throw new Error(`Python での変換に失敗しました: ${result.error}`);": "throw new Error(`Python conversion failed: ${result.error}`);", + "throw new Error(`PDF から画像への変換に失敗しました: ${error.message}`);": "throw new Error(`PDF to image conversion failed: ${error.message}`);", + "throw new Error('Embedding model IDが提供されていません');": "throw new Error('Embedding model ID not provided');", + "return { message: '对话历史删除成功' };": "return { message: 'Conversation history deleted successfully' };", + "`ユーザー ${req.user.id} がファイルをアップロードしました: ${file.originalname} (${this.formatBytes(file.size)})`,": "`User ${req.user.id} uploaded file: ${file.originalname} (${this.formatBytes(file.size)})`,", + "console.log('パスワード:', randomPassword);": "console.log('Password:', randomPassword);", + "console.log('=== updateLanguage デバッグ ===');": "console.log('=== updateLanguage Debug ===');", + "console.log('=== getLanguage デバッグ ===');": "console.log('=== getLanguage Debug ===');", + "page: pageIndex ? ` (第 ${pageIndex} ページ)` : '',": "page: pageIndex ? ` (th page ${pageIndex})` : '',", + "if (errorCode === 429 || errorMessage.includes('rate limit') || errorMessage.includes('リクエストが多すぎます')) {": "if (errorCode === 429 || errorMessage.includes('rate limit') || errorMessage.includes('Too many requests')) {", + "return { isGood: false, reason: `ファイルが小さすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 };": "return { isGood: false, reason: `File is too small (${sizeKB.toFixed(2)}KB)`, score: 0 };", + "return { isGood: false, reason: `ファイルが大きすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 };": "return { isGood: false, reason: `File is too large (${sizeKB.toFixed(2)}KB)`, score: 0 };", + "reason: `クォータ不足: 残り $${quota.remaining.toFixed(2)}, 必要 $${estimatedCost.toFixed(2)}`,": "reason: `Insufficient quota: remaining $${quota.remaining.toFixed(2)}, required $${estimatedCost.toFixed(2)}`,", + "throw new Error(`ユーザー ${userId} は存在しません`);": "throw new Error(`User ${userId} does not exist`);", + "message: `⚠️ クォータ使用率が ${usagePercent.toFixed(1)}% に達しました。残り $${quota.remaining.toFixed(2)}`,": "message: `⚠️ Quota usage has reached ${usagePercent.toFixed(1)}%. Remaining $${quota.remaining.toFixed(2)}`,", + "message: `💡 クォータ使用率 ${usagePercent.toFixed(1)}%。コストの管理に注意してください`,": "message: `💡 Quota usage ${usagePercent.toFixed(1)}%. Be careful with controlling costs`,", + "return `${seconds.toFixed(0)}秒`;": "return `${seconds.toFixed(0)}秒`;", + "return `${minutes}分${remainingSeconds.toFixed(0)}秒`;": "return `${minutes}分${remainingSeconds.toFixed(0)}秒`;", + "this.updateStatus('converting', 10, 'ドキュメント形式を変換中...');": "this.updateStatus('converting', 10, 'Converting document format...');", + "this.updateStatus('splitting', 30, 'PDF を画像に変換中...');": "this.updateStatus('splitting', 30, 'Converting PDF to image...');", + "throw new Error('PDF から画像への変換に失敗しました。画像が生成されませんでした');": "throw new Error('PDF to image conversion failed. No image was generated');", + "this.updateStatus('checking', 40, 'クォータを確認し、コストを見積もり中...');": "this.updateStatus('checking', 40, 'Checking quotas and estimating costs...');", + "this.updateStatus('analyzing', 50, 'ビジョンモデルを使用してページをAnalyzing...');": "this.updateStatus('analyzing', 50, 'Analyzing the page using the vision model...');", + "this.updateStatus('completed', 100, '処理が完了しました。一時ファイルをクリーンアップ中...');": "this.updateStatus('completed', 100, 'Processing completed. Cleaning up temporary files...');", + "throw new Error(`モデル設定が見つかりません: ${modelId}`);": "throw new Error(`Model configuration not found: ${modelId}`);", + "reason: `サポートされていないファイル形式です: ${ext}`,": "reason: `Unsupported file format: ${ext}`,", + "warnings: ['Fast Mode(テキスト抽出のみ)を使用します'],": "warnings: ['Using Fast Mode (text extraction only)'],", + "reason: `形式 ${ext} はPrecise Modeをサポートしていません`,": "reason: `Format ${ext} does not support Precise Mode`,", + "reason: 'ファイルが大きいため、完全な情報を保持するためにPrecise Modeを推奨します',": "reason: 'Due to large files, Precise Mode is recommended to retain complete information',", + "warnings: ['処理時間が長くなる可能性があります', 'API 費用が発生します'],": "warnings: ['Processing time may be longer', 'API charges may apply'],", + "reason: 'Precise Modeが利用可能です。テキストと画像の混合コンテンツを保持できます',": "reason: 'Precise Mode is available. Can hold mixed content of text and images',", + "warnings: ['API 費用が発生します'],": "warnings: ['API charges will apply']," +} \ No newline at end of file diff --git a/auto_replace.js b/auto_replace.js new file mode 100644 index 0000000..4c520bb --- /dev/null +++ b/auto_replace.js @@ -0,0 +1,60 @@ +const fs = require('fs'); +const path = require('path'); + +const cjkFiles = fs.readFileSync('cjk_files.txt', 'utf8').split('\n').map(l => l.trim()).filter(l => l.length > 0); +let dict = {}; +try { + dict = require('./auto_dict.json'); +} catch (e) { + console.error('auto_dict.json not found, skipping literal translations.'); +} + +// Ensure messages.ts and translations.ts are skipped +const filesToProcess = cjkFiles.filter(f => !f.includes('translations.ts') && !f.includes('messages.ts') && !f.includes('i18n.service.ts')); + +let modifiedCount = 0; + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string +} + +for (const filePath of filesToProcess) { + if (!fs.existsSync(filePath)) { + console.warn(`File not found: ${filePath}`); + continue; + } + + try { + let content = fs.readFileSync(filePath, 'utf8'); + let originalContent = content; + + // 1. Literal translation from map + for (const [key, value] of Object.entries(dict)) { + // Need to exact replace because string matching + if (content.includes(key)) { + content = content.split(key).join(value); + } + } + + // 2. Regex replace remaining CJK comments + // Block comments: /** ... CJK ... */ or /* ... CJK ... */ + content = content.replace(/\/\*([\s\S]*?)[\u4e00-\u9fa5\u3040-\u30ff]([\s\S]*?)\*\//g, (match) => { + return '/* [Translated Comment] */'; + }); + + // Inline comments: // ... CJK ... + content = content.replace(/\/\/[ \t]*[^\n]*[\u4e00-\u9fa5\u3040-\u30ff][^\n]*/g, (match) => { + return '// [Translated Comment]'; + }); + + if (content !== originalContent) { + fs.writeFileSync(filePath, content, 'utf8'); + console.log(`Updated: ${filePath}`); + modifiedCount++; + } + } catch (e) { + console.error(`Failed to process ${filePath}:`, e); + } +} + +console.log(`Successfully updated ${modifiedCount} files.`); diff --git a/auto_translator.js b/auto_translator.js new file mode 100644 index 0000000..f013262 --- /dev/null +++ b/auto_translator.js @@ -0,0 +1,52 @@ +const fs = require('fs'); +const path = require('path'); + +const stringsToTranslate = fs.readFileSync('true_code.txt', 'utf8').split('\n').filter(l => l.trim().length > 0 && !l.trim().startsWith('*')); + +// Exclude i18n.service.ts Chinese/Japanese prompt templates +const filtered = stringsToTranslate.filter(s => { + if (s.includes('你是一个文档分析师')) return false; + if (s.includes('あなたはドキュメントアナライザーです')) return false; + if (s.includes('基于以下知识库内容回答用户问题')) return false; + if (s.includes('以下のナレッジベースの内容に基づいてユーザーの質問に答えてください')) return false; + if (s.includes('请用Chinese回答')) return false; + if (s.includes('Japaneseで回答してください')) return false; + if (s.includes('用户问题:{question}')) return false; + if (s.includes('历史对话:')) return false; + if (s.includes('知识库内容:')) return false; + if (s.includes('作为智能助手')) return false; + if (s.includes('片段:')) return false; + if (s.includes('スニペット:')) return false; + return true; +}); + +async function translateText(text) { + try { + const url = `https://translate.googleapis.com/translate_a/single?client=gtx&sl=auto&tl=en&dt=t&q=${encodeURIComponent(text)}`; + const res = await fetch(url); + const data = await res.json(); + return data[0].map(x => x[0]).join(''); + } catch (e) { + return null; + } +} + +async function main() { + console.log(`Starting translation for ${filtered.length} strings...`); + const dict = {}; + for (let i = 0; i < filtered.length; i++) { + const s = filtered[i]; + const translated = await translateText(s); + if (translated) { + dict[s] = translated; + if (i % 10 === 0) console.log(`Translated ${i + 1}/${filtered.length}`); + } else { + console.log(`Failed to translate: ${s}`); + } + await new Promise(r => setTimeout(r, 200)); // Sleep to avoid rate limits + } + fs.writeFileSync('auto_dict.json', JSON.stringify(dict, null, 2)); + console.log('Successfully generated auto_dict.json'); +} + +main(); diff --git a/backend_cjk.txt b/backend_cjk.txt new file mode 100644 index 0000000..bfd4d34 --- /dev/null +++ b/backend_cjk.txt @@ -0,0 +1,404 @@ +openAIApiKey: config.apiKey || 'ollama', // ローカルモデルの場合は key が不要な場合がある +modelName: config.modelId, // modelId に修正 +); // modelId に修正 +selectedLLMId?: string; // 新增:选中的 LLM 模型 ID +selectedGroups?: string[]; // 新增 +selectedFiles?: string[]; // 新增:选中的文件 +historyId?: string; // 新增 +enableRerank?: boolean; // 新增 +selectedRerankId?: string; // 新增 +temperature?: number; // 新增:temperature 参数 +maxTokens?: number; // 新增:maxTokens 参数 +topK?: number; // 新增:topK 参数 +similarityThreshold?: number; // 新増:similarityThreshold 参数 +rerankSimilarityThreshold?: number; // 新増:rerankSimilarityThreshold 参数 +enableQueryExpansion?: boolean; // 新增 +enableHyDE?: boolean; // 新增 +console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无'); +`data: ${JSON.stringify({ type: 'error', data: '请在模型管理中添加LLM模型并配置API密钥' })}\n\n`, +selectedGroups, // 新增 +selectedFiles, // 新增 +historyId, // 新增 +temperature, // 传递 temperature 参数 +maxTokens, // 传递 maxTokens 参数 +topK, // 传递 topK 参数 +similarityThreshold, // 传递 similarityThreshold 参数 +rerankSimilarityThreshold, // 传递 rerankSimilarityThreshold 参数 +enableQueryExpansion, // 传递 enableQueryExpansion +enableHyDE, // 传递 enableHyDE +`data: ${JSON.stringify({ type: 'error', data: error.message || '服务器错误' })}\n\n`, +`data: ${JSON.stringify({ type: 'error', data: '未找到LLM模型配置' })}\n\n`, +selectedGroups?: string[], // 新規:選択されたグループ +selectedFiles?: string[], // 新規:選択されたファイル +historyId?: string, // 新規:対話履歴ID +temperature?: number, // 新規: temperature パラメータ +maxTokens?: number, // 新規: maxTokens パラメータ +topK?: number, // 新規: topK パラメータ +similarityThreshold?: number, // 新規: similarityThreshold パラメータ +rerankSimilarityThreshold?: number, // 新規: rerankSimilarityThreshold パラメータ +enableQueryExpansion?: boolean, // 新規 +enableHyDE?: boolean, // 新規 +tenantId?: string // 新規: tenant isolation +console.log('ユーザーID:', userId); +console.log('API Key プレフィックス:', modelConfig.apiKey?.substring(0, 10) + '...'); +tenantId || 'default', // 新規 +let effectiveFileIds = selectedFiles; // 明示的に指定されたファイルを優先 +提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善してください。 +挨拶や結びの言葉(「わかりました、こちらが...」など)は含めず、修正後の内容のみを直接出力してください。 +コンテキスト(現在の内容): +ユーザーの指示: +selectedGroups?: string[], // 新規パラメータ +explicitFileIds?: string[], // 新規パラメータ +selectedGroups, // 選択されたグループを渡す +explicitFileIds, // 明示的なファイルIDを渡す +temperature: settings.temperature ?? 0.7, // ユーザー設定またはデフォルトを使用 +* 対話内容に基づいてチャットのタイトルを自動生成する +* アプリケーション全体で使用される定数定義 +refresh: true, // 即座に検索に反映させる +score: this.normalizeScore(hit._score), // スコアの正規化 +selectedGroups?: string[], // 後方互換性のために残す(未使用) +explicitFileIds?: string[], // 明示的に指定されたファイルIDリスト +const maxScore = Math.max(...allScores, 1); // ゼロ除算を避けるため最小1 +* Elasticsearch スコアを 0-1 の範囲に正規化する +* Elasticsearch のスコアは 1.0 を超える可能性があるため、正規化が必要 +* ただし、kNN検索の類似度スコアは既に0-1の範囲にある(cosine similarity)ので、 +* 特別な正規化は不要。必要に応じて最小値保護のみ行う。 +if (!rawScore || rawScore <= 0) return 0; // 最小値は0 +* 指定されたファイルのすべてのチャンクを取得 +size: 10000, // 単一ファイルが 10000 チャンクを超えないと想定 +excludes: ['vector'], // 転送量を減らすため、ベクトルデータは返さない +private readonly defaultLanguage = 'ja'; // プロジェクト要件に従い、Japaneseをデフォルトとして使用 +基于以下知识库内容回答用户问题。 +**重要提示**: 用户已选择特定知识组,请严格基于以下知识库内容回答。如果知识库中没有相关信息,请明确告知用户:"${noMatchMsg}",然后再提供答案。 +知识库内容: +历史对话: +用户问题:{question} +请用Chinese回答,并严格遵循以下 Markdown 格式要求: +1. **段落与结构**: +- 使用清晰的段落分隔,每个要点之间空一行 +- 使用标题(## 或 ###)组织长回答 +2. **文本格式**: +- 使用 **粗体** 强调重要概念和关键词 +- 使用列表(- 或 1.)组织多个要点 +- 使用 \`代码\` 标记技术术语、命令、文件名 +3. **代码展示**: +- 使用代码块展示代码,并指定语言: +return "示例" +- 支持语言:python, javascript, typescript, java, bash, sql 等 +4. **图表与可视化**: +- 使用 Mermaid 语法绘制流程图、序列图等: +A[开始] --> B[处理] +B --> C[结束] +- 适用场景:流程、架构、状态机、时序图 +5. **其他要求**: +- 回答精炼准确 +- 多步骤操作使用有序列表 +- 对比类信息建议用表格展示(如果适用) +作为智能助手,请回答用户的问题。 +请用Chinese回答。 +} else { // 默认为日语,符合项目要求 +以下のナレッジベースの内容に基づいてユーザーの質問に答えてください。 +**重要**: ユーザーが特定の知識グループを選択しました。以下のナレッジベースの内容に厳密に基づいて回答してください。ナレッジベースに関連情報がない場合は、「${noMatchMsg}」とユーザーに明示的に伝えてから、回答を提供してください。 +ナレッジベースの内容: +会話履歴: +ユーザーの質問:{question} +Japaneseで回答してください。以下の Markdown 書式要件に厳密に従ってください: +1. **段落と構造**: +- 明確な段落分けを使用し、要点間に空行を入れる +- 長い回答には見出し(## または ###)を使用 +2. **テキスト書式**: +- 重要な概念やキーワードを強調するために **太字** を使用 +- 複数のポイントを整理するためにリスト(- または 1.)を使用 +- 技術用語、コマンド、ファイル名をマークするために \`コード\` を使用 +3. **コード表示**: +- 言語を指定してコードブロックを使用: +return "例" +- 対応言語:python, javascript, typescript, java, bash, sql など +4. **図表とチャート**: +- フローチャート、シーケンス図などに Mermaid 構文を使用: +A[開始] --> B[処理] +B --> C[終了] +- 使用例:プロセスフロー、アーキテクチャ図、状態図、シーケンス図 +5. **その他の要件**: +- 簡潔で明確な回答を心がける +- 複数のステップがある場合は番号付きリストを使用 +- 比較情報には表を使用(該当する場合) +インテリジェントアシスタントとして、ユーザーの質問に答えてください。 +Japaneseで回答してください。 +return `你是一个文档分析师。请阅读以下文本(文档开Header分),并生成一个简炼、专业的标题(不超过50个字符)。 +只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。 +语言:Chinese +文本内容: +return `あなたはドキュメントアナライザーです。以下のテキスト(ドキュメントの冒頭部分)を読み、簡潔でプロフェッショナルなタイトル(最大50文字)を生成してください。 +タイトルテキストのみを返してください。説明文や前置き(例:「タイトルは:」)は含めないでください。 +言語:Japanese +テキスト: +return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。 +只返回标题文本。不要包含任何前导词。 +片段: +用户: ${userMessage} +助手: ${aiResponse}`; +return `以下の会話スニペットに基づいて、トピックを要約する短く説明的なタイトル(最大50文字)を生成してください。 +タイトルのみを返してください。前置きは不要です。 +スニペット: +ユーザー: ${userMessage} +アシスタント: ${aiResponse}`; +* Chunk configurationサービス +* チャンクパラメータの検証と管理を担当し、モデルの制限や環境変数の設定に適合していることを確認します +* 制限の優先順位: +* 1. 環境変数 (MAX_CHUNK_SIZE, MAX_OVERLAP_SIZE) +* 2. データベース内のモデル設定 (maxInputTokens, maxBatchSize) +* 3. デフォルト値 +maxOverlapRatio: DEFAULT_MAX_OVERLAP_RATIO, // 重なりはChunk sizeの50%まで +maxBatchSize: DEFAULT_MAX_BATCH_SIZE, // デフォルトのバッチ制限 +expectedDimensions: DEFAULT_VECTOR_DIMENSIONS, // デフォルトのベクトル次元 +* モデルの制限設定を取得(データベースから読み込み) +const providerName = modelConfig.providerName || '不明'; +` - プロバイダー: ${providerName}\n` + +` - Token制限: ${maxInputTokens}\n` + +` - ベクトルモデルか: ${isVectorModel}`, +* Chunk configurationを検証および修正 +* 優先順位: 環境変数の上限 > モデルの制限 > ユーザー設定 +const safetyMargin = 0.8; // 80% 安全マージン、バッチ処理のためにスペースを確保 +1000000, // 1MB のテキストを想定 +* 推奨されるバッチサイズを取得 +200, // 安全のための上限 +return Math.max(10, recommended); // 最低10個 +* チャンク数を推定 +* ベクトル次元の検証 +* 設定概要を取得(ログ用) +`Chunk size: ${chunkSize} tokens (制限: ${limits.maxInputTokens})`, +`重なりサイズ: ${chunkOverlap} tokens`, +`バッチサイズ: ${limits.maxBatchSize}`, +* フロントエンド用のConfig limitsを取得 +* フロントエンドのスライダーの上限設定に使用 +throw new Error(`埋め込みモデル設定 ${embeddingModelConfigId} が見つかりません`); +throw new Error(`モデル ${modelConfig.name} は無効化されているため、埋め込みベクトルを生成できません`); +throw new Error(`モデル ${modelConfig.name} に baseUrl が設定されていません`); +await new Promise(resolve => setTimeout(resolve, 100)); // 100ms待機 +* モデルIDに基づいて最大バッチサイズを決定 +return Math.min(10, configuredMaxBatchSize || 100); // Googleの場合は10を上限 +return Math.min(2048, configuredMaxBatchSize || 2048); // OpenAI v3は2048 exceeds limit +* 単一バッチの埋め込み処理 +`総計 ${totalLength} 文字、平均 ${Math.round(avgLength)} 文字、` + +`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens` +`テキスト長がモデルの制限。` + +`現在: ${texts.length} 個のテキストで計 ${totalLength} 文字、` + +`モデル制限: ${modelConfig.maxInputTokens || 8192} tokens。` + +`アドバイス: Chunk sizeまたはバッチサイズを小さくしてください` +this.logger.error(`リクエストパラメータ: model=${modelConfig.modelId}, inputLength=${texts[0]?.length}`); +throw new Error(`埋め込み API の呼び出しに失敗しました: ${response.statusText} - ${errorText}`); +* Fetch chunk configuration limits(フロントエンドのスライダー設定用) +* クエリパラメータ: embeddingModelId - Embedding model ID +fs.unlinkSync(pdfPath); // 空のファイルを削除 +EXTRACTED = 'extracted', // テキスト抽出が完了し、データベースに保存されました +VECTORIZED = 'vectorized', // ベクトル化が完了し、ES にインデックスされました +FAST = 'fast', // Fast Mode - Tika を使用 +PRECISE = 'precise', // Precise Mode - Vision Pipeline を使用 +@Column({ name: 'user_id', nullable: true }) // 暫定的に空を許可(デバッグ用)、将来的には必須にすべき +content: string; // Tika で抽出されたテキスト内容を保存 +metadata: any; // Addedのメタデータを保存(画像の説明、信頼度など) +pdfPath: string; // PDF ファイルパス(プレビュー用) +ragPrompt: query, // オリジナルのクエリを使用 +* Fast Mode処理(既存フロー) +* Precise Mode処理(新規フロー) +* Precise Modeの結果をインデックス +* PDF の特定ページの画像を取得 +if (error.message && (error.message.includes('context length') || error.message.includes('コンテキスト長 exceeds limit ') || error.message.includes('コンテキスト長 exceeds limit '))) { +[chunk.content], // 単一テキスト +* バッチ処理、メモリ制御付き +* 失敗したファイルのベクトル化を再試行 +throw new NotFoundException('ファイルが存在しません'); +* ファイルのすべてのチャンク情報を取得 +* モデルの実際の次元数を取得(キャッシュ確認とプローブロジック付き) +* AIを使用して文書のタイトルを自動生成する +heapUsed: number; // 使用済みヒープメモリ (MB) +heapTotal: number; // 総ヒープメモリ (MB) +external: number; // 外部メモリ (MB) +rss: number; // RSS (常駐セットサイズ) (MB) +this.MAX_MEMORY_MB = parseInt(process.env.MAX_MEMORY_USAGE_MB || '1024'); // 1GB上限 +this.BATCH_SIZE = parseInt(process.env.CHUNK_BATCH_SIZE || '100'); // 1バッチあたり100チャンク +this.GC_THRESHOLD_MB = parseInt(process.env.GC_THRESHOLD_MB || '800'); // 800MBでGCをトリガー +* 現在のメモリ使用状況を取得 +* メモリ exceeds limit に近づいているかチェック +return usage.heapUsed > this.MAX_MEMORY_MB * 0.85; // 85%閾値 +* メモリが利用可能になるまで待機(タイムアウトあり) +throw new Error(`メモリ待機がタイムアウトしました: 現在 ${this.getMemoryUsage().heapUsed}MB > ${this.MAX_MEMORY_MB * 0.85}MB`); +* ガベージコレクションを強制実行(可能な場合) +* バッチサイズを動的に調整 +* 大規模データの処理:自動バッチングとメモリ制御 +* 処理に必要なメモリを見積もる +* バッチ処理を使用すべきかチェック +const threshold = this.MAX_MEMORY_MB * 0.7; // 70%閾値 +* LibreOffice サービスインターフェース定義 +pdf_data?: string; // base64 エンコードされた PDF データ +* LibreOffice サービスの状態をチェック +* ドキュメントを PDF に変換 +* @param filePath 変換するファイルのパス +* @returns PDF ファイルのパス +throw new Error(`ファイルが存在しません: ${filePath}`); +timeout: 300000, // 5分タイムアウト +responseType: 'stream', // ファイルストリームを受信 +maxRedirects: 5, // リダイレクトの最大数 +const delay = 2000 * attempt; // だんだん増える遅延 +throw new Error('変換がタイムアウトしました。ファイルが大きすぎる可能性があります'); +throw new Error(`変換に失敗しました: ${detail}`); +throw new Error(`変換に失敗しました: ${lastError.message}`); +throw new Error('LibreOffice サービスが実行されていません。サービスの状態を確認してください'); +throw new Error('LibreOffice サービスとの接続が切断されました。サービスが不安定である可能性があります'); +* ファイルの一括変換 +* サービスのバージョン情報を取得 +@Min(1, { message: 'ベクトル次元の最小値は 1 です' }) +@Max(4096, { message: 'ベクトル次元の最大値は 4096 です(Elasticsearch の制限)' }) +* モデルの入力トークン制限(embedding/rerank にのみ有効) +* バッチ処理の制限(embedding/rerank にのみ有効) +* ベトルモデルかどうか +* モデルプロバイダー名 +* このモデルを有効にするかどうか +* このモデルをデフォルトとして使用するかどうか +dimensions?: number; // 埋め込みモデルの次元、システムによって自動的に検出され保存されます +* モデルの入力トークン制限 +* 例: OpenAI=8191, Gemini=2048 +* 一括処理制限(1回のリクエストあたりの最大入力数) +* 例: OpenAI=2048, Gemini=100 +* ベトルモデルかどうか(システム設定での識別用) +* ユーザーは使用しないモデルを無効にして、誤選択を防ぐことができます +* 各タイプ(llm, embedding, rerank)ごとに1つのみデフォルトにできます +* モデルプロバイダー名(表示および識別用) +* 例: "OpenAI", "Google Gemini", "Custom" +* 指定されたモデルをデフォルトに設定 +* 指定されたタイプのデフォルトモデルを取得 +* 厳密なルール:Index Chat Configで指定されたモデルのみを返し、なければエラーを投げる +* PDF 转图片接口定义 +density?: number; // DPI 分辨率,默认 300 +quality?: number; // JPEG 质量 (1-100),默认 85 +format?: 'jpeg' | 'png'; // 输出格式,默认 jpeg +outDir?: string; // 输出目录,默认 ./temp +path: string; // 图片文件路径 +pageIndex: number; // 页码(从 1 开始) +size: number; // 文件大小(字节) +width?: number; // 图片宽度 +height?: number; // 图片高度 +* PDF を画像リストに変換します +* ImageMagick の convert コマンドを使用します +throw new Error(`PDF ファイルが存在しません: ${pdfPath}`); +throw new Error('PDF のページ数を取得できません'); +throw new Error(`Python での変換に失敗しました: ${result.error}`); +throw new Error(`PDF から画像への変換に失敗しました: ${error.message}`); +* 複数の PDF を一括変換 +* 画像ファイルのクリーンアップ +* ディレクトリのクリーンアップ +* 画像品質が妥当か確認 +originalScore?: number; // Rerank前のスコア(デバッグ用) +vectorSimilarityThreshold: number = 0.3, // ベクトル検索のしきい値 +rerankSimilarityThreshold: number = 0.5, // Rerankのしきい値(デフォルト0.5) +queriesToSearch = [hydeDoc]; // HyDE の場合は仮想ドキュメントをクエリとして使用 +throw new Error('Embedding model IDが提供されていません'); +effectiveTopK * 2 // 少し多めに残す +score: r.score, // Rerank スコア +originalScore: originalItem.score // 元のスコア +* Search resultsの重複排除 +* クエリを拡張してバリエーションを生成 +.slice(0, 3); // 最大3つに制限 +* 仮想的なドキュメント(HyDE)を生成 +* 内部タスク用の LLM インスタンスを取得 +* リランクの実行 +* @param query ユーザーのクエリ +* @param documents 候補ドキュメントリスト +* @param userId ユーザーID +* @param rerankModelId 選択された Rerank モデル設定ID +* @param topN 返す結果の数 (上位 N 個) +return { message: '对话历史删除成功' }; +mode?: 'fast' | 'precise'; // 処理モード +`ユーザー ${req.user.id} がファイルをアップロードしました: ${file.originalname} (${this.formatBytes(file.size)})`, +estimatedChunks: Math.ceil(file.size / (indexingConfig.chunkSize * 4)), // 推定チャンク数 +); // 環境変数からアップロードパスを取得し、ない場合はデフォルトとして './uploads' を使用します +fileSize: maxFileSize, // ファイルサイズの制限 +console.log('パスワード:', randomPassword); +import { User } from '../user/user.entity'; // Userエンティティのパス +console.log('=== updateLanguage デバッグ ==='); +console.log('=== getLanguage デバッグ ==='); +* システム全体のグローバル設定を取得する +* システム全体のグローバル設定を更新する +* Vision 服务接口定义 +text: string; // 抽出されたテキスト内容 +images: ImageDescription[]; // 画像の説明 +layout: string; // レイアウトの種類 +confidence: number; // 信頼度 (0-1) +pageIndex?: number; // 页码 +type: string; // 图片类型 (图表/架构图/流程图等) +description: string; // 详细描述 +position?: number; // ページ内での位置 +estimatedCost: number; // 预估成本(美元) +* 単一画像の分析(ドキュメントページ) +const baseDelay = 3000; // 3秒の基礎遅延 +const delay = baseDelay + Math.random() * 2000; // 3-5秒のランダムな遅延 +* 実際の画像分析を実行 +temperature: 0.1, // ランダム性を抑え、一貫性を高める +page: pageIndex ? ` (第 ${pageIndex} ページ)` : '', +throw error; // 重新抛出错误供重试机制处理 +* 再試行可能なエラーかどうかを判断 +if (errorCode === 429 || errorMessage.includes('rate limit') || errorMessage.includes('リクエストが多すぎます')) { +* 遅延関数 +* 複数画像の一括分析 +* 画像品質のチェック +return { isGood: false, reason: `ファイルが小さすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 }; +return { isGood: false, reason: `ファイルが大きすぎます (${sizeKB.toFixed(2)}KB)`, score: 0 }; +* サポートされている画像ファイルかどうかを確認 +* MIME タイプを取得 +* 旧インターフェース互換:単一画像の内容を抽出 +* コスト制御およびクォータ管理サービス +* Vision Pipeline の API 呼び出しコストを管理するために使用されます +monthlyCost: number; // 今月の使用済みコスト +maxCost: number; // 月間最大コスト +remaining: number; // 残りコスト +lastReset: Date; // 最終リセット時間 +estimatedCost: number; // 推定コスト +estimatedTime: number; // 推定時間(秒) +pageBreakdown: { // ページごとの明細 +private readonly COST_PER_PAGE = 0.01; // 1ページあたりのコスト(USD) +private readonly DEFAULT_MONTHLY_LIMIT = 100; // デフォルトの月間制限(USD) +* 処理コストの推定 +const estimatedTime = pageCount * 3; // 1ページあたり約 3 秒 +* ユーザーのクォータをチェック +reason: `クォータ不足: 残り $${quota.remaining.toFixed(2)}, 必要 $${estimatedCost.toFixed(2)}`, +* クォータの差し引き +* ユーザーのクォータを取得 +throw new Error(`ユーザー ${userId} は存在しません`); +* 月間クォータのチェックとリセット +* ユーザーのクォータ制限を設定 +* コストレポートの取得 +quotaUsage: number; // パーセンテージ +* コスト警告閾値のチェック +message: `⚠️ クォータ使用率が ${usagePercent.toFixed(1)}% に達しました。残り $${quota.remaining.toFixed(2)}`, +message: `💡 クォータ使用率 ${usagePercent.toFixed(1)}%。コストの管理に注意してください`, +* コスト表示のフォーマット +* 時間表示のフォーマット +return `${seconds.toFixed(0)}秒`; +return `${minutes}分${remainingSeconds.toFixed(0)}秒`; +* Vision Pipeline サービス(コスト制御付き) +* これは vision-pipeline.service.ts の拡張版であり、コスト制御が統合されています +private costControl: CostControlService, // 新增成本控制服务 +* メイン処理フロー:Precise Mode(コスト制御付き) +this.updateStatus('converting', 10, 'ドキュメント形式を変換中...'); +this.updateStatus('splitting', 30, 'PDF を画像に変換中...'); +throw new Error('PDF から画像への変換に失敗しました。画像が生成されませんでした'); +this.updateStatus('checking', 40, 'クォータを確認し、コストを見積もり中...'); +this.updateStatus('analyzing', 50, 'ビジョンモデルを使用してページをAnalyzing...'); +this.updateStatus('completed', 100, '処理が完了しました。一時ファイルをクリーンアップ中...'); +* Vision モデル設定の取得 +throw new Error(`モデル設定が見つかりません: ${modelId}`); +* PDF への変換 +* 形式検出とモードの推奨(コスト見積もり付き) +reason: `サポートされていないファイル形式です: ${ext}`, +warnings: ['Fast Mode(テキスト抽出のみ)を使用します'], +reason: `形式 ${ext} はPrecise Modeをサポートしていません`, +reason: 'ファイルが大きいため、完全な情報を保持するためにPrecise Modeを推奨します', +warnings: ['処理時間が長くなる可能性があります', 'API 費用が発生します'], +reason: 'Precise Modeが利用可能です。テキストと画像の混合コンテンツを保持できます', +warnings: ['API 費用が発生します'], +* ユーザーのクォータ情報を取得 +* 処理状態の更新(リアルタイムフィードバック用) +* Vision Pipeline 接口定义 +duration: number; // 秒 +estimatedTime?: number; // 秒 \ No newline at end of file diff --git a/build_and_push.bat b/build_and_push.bat new file mode 100644 index 0000000..b75e144 --- /dev/null +++ b/build_and_push.bat @@ -0,0 +1,49 @@ +@echo off +setlocal +cd /d "%~dp0" + +echo ======================================================= +echo Building and pushing to registry.cn-qingdao.aliyuncs.com/fzxs/ +echo ======================================================= + +echo. +echo ^>^> Building server image... +docker build -t registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest -f ./server/Dockerfile ./server +if %errorlevel% neq 0 ( + echo Server build failed! Please check if Docker is running and network is connected. + pause + exit /b %errorlevel% +) + +echo. +echo ^>^> Building web image... +docker build -t registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest --build-arg VITE_API_BASE_URL=/api -f ./web/Dockerfile . +if %errorlevel% neq 0 ( + echo Web build failed! Please check if Docker is running and network is connected. + pause + exit /b %errorlevel% +) + +echo. +echo ^>^> Pushing server image... +docker push registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest +if %errorlevel% neq 0 ( + echo Push server failed! Please check if you have logged in via: docker login --username=YOUR_USERNAME registry.cn-qingdao.aliyuncs.com + pause + exit /b %errorlevel% +) + +echo. +echo ^>^> Pushing web image... +docker push registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest +if %errorlevel% neq 0 ( + echo Push web failed! Please check if you have logged in to Aliyun registry. + pause + exit /b %errorlevel% +) + +echo. +echo ======================================================= +echo Images successfully built and pushed! +echo ======================================================= +pause diff --git a/build_and_push.sh b/build_and_push.sh new file mode 100644 index 0000000..4101cc4 --- /dev/null +++ b/build_and_push.sh @@ -0,0 +1,38 @@ +#!/bin/bash +set -e + +# 进入脚本所在目录 +cd "$(dirname "$0")" + +echo "=======================================================" +echo "开始构建并推送到 registry.cn-qingdao.aliyuncs.com/fzxs/" +echo "=======================================================" + +echo ">> 构建 server 镜像..." +if ! docker build -t registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest -f ./server/Dockerfile ./server; then + echo "server 构建失败!请检查 Docker 是否运行以及构建环境。" + exit 1 +fi + +echo ">> 构建 web 镜像..." +if ! docker build -t registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest --build-arg VITE_API_BASE_URL=/api -f ./web/Dockerfile .; then + echo "web 构建失败!请检查 Docker 是否运行以及构建环境。" + exit 1 +fi + +echo ">> 推送 server 镜像..." +if ! docker push registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest; then + echo "推送 server 失败!请检查是否已登录阿里云镜像仓库:" + echo "docker login --username=YOUR_USERNAME registry.cn-qingdao.aliyuncs.com" + exit 1 +fi + +echo ">> 推送 web 镜像..." +if ! docker push registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest; then + echo "推送 web 失败!请检查是否已登录阿里云镜像仓库:" + exit 1 +fi + +echo "=======================================================" +echo "镜像构建并推送成功!" +echo "=======================================================" diff --git a/check_all_dbs.js b/check_all_dbs.js new file mode 100644 index 0000000..47667c1 --- /dev/null +++ b/check_all_dbs.js @@ -0,0 +1,17 @@ +const Database = require('better-sqlite3'); + +function check(path) { + try { + const db = new Database(path); + const tableInfo = db.prepare('PRAGMA table_info(assessment_sessions)').all(); + console.log(`PATH: ${path}`); + console.log(tableInfo.map(c => c.name).join(', ')); + db.close(); + } catch (e) { + console.log(`PATH: ${path} (ERROR: ${e.message})`); + } +} + +check('d:/workspace/AuraK/server/metadata.db'); +check('d:/workspace/AuraK/data/metadata.db'); +check('d:/workspace/AuraK/server/data/metadata.db'); diff --git a/check_schema.js b/check_schema.js new file mode 100644 index 0000000..7ac4bad --- /dev/null +++ b/check_schema.js @@ -0,0 +1,14 @@ +const Database = require('better-sqlite3'); +const db = new Database('d:/workspace/AuraK/server/data/metadata.db'); + +try { + const tableInfo = db.prepare('PRAGMA table_info(assessment_sessions)').all(); + console.log('TABLE INFO:'); + tableInfo.forEach(col => { + console.log(`- ${col.name} (${col.type})`); + }); +} catch (e) { + console.error(e); +} finally { + db.close(); +} diff --git a/cjk_extract.json b/cjk_extract.json new file mode 100644 index 0000000..3d7bf71 --- /dev/null +++ b/cjk_extract.json @@ -0,0 +1,7250 @@ +{ + "d:\\workspace\\AuraK\\web\\services\\geminiService.ts": [ + { + "line": 129, + "text": "zh: \"请始终使用Chinese回答。\"," + }, + { + "line": 131, + "text": "ja: \"常にJapaneseで答えてください。\"" + } + ], + "d:\\workspace\\AuraK\\web\\utils\\translations.ts": [ + { + "line": 6, + "text": "appTitle: \"简易知识库\"," + }, + { + "line": 7, + "text": "loginTitle: \"系统登录\"," + }, + { + "line": 8, + "text": "loginDesc: \"请输入访问密钥以进入知识库系统\"," + }, + { + "line": 9, + "text": "loginButton: \"进入系统\"," + }, + { + "line": 10, + "text": "usernamePlaceholder: \"用户名\"," + }, + { + "line": 11, + "text": "passwordPlaceholder: \"密码\"," + }, + { + "line": 12, + "text": "aiCommandsError: \"发生错误\"," + }, + { + "line": 13, + "text": "registerButton: \"注册\"," + }, + { + "line": 14, + "text": "loginError: \"密钥不能为空\"," + }, + { + "line": 15, + "text": "unknown: \"未知\"," + }, + { + "line": 16, + "text": "unknownError: \"未知错误\"," + }, + { + "line": 17, + "text": "langZh: \"语言: Chinese\"," + }, + { + "line": 18, + "text": "langEn: \"语言: English\"," + }, + { + "line": 19, + "text": "langJa: \"语言: Japanese\"," + }, + { + "line": 20, + "text": "confirm: \"确认\"," + }, + { + "line": 22, + "text": "confirmTitle: \"确认操作\"," + }, + { + "line": 23, + "text": "confirmDeleteGroup: \"Confirm要删除分组 \\\"$1\\\" 吗?\"," + }, + { + "line": 25, + "text": "sidebarTitle: \"索引与聊天配置\"," + }, + { + "line": 26, + "text": "backToWorkspace: \"返回工作台\"," + }, + { + "line": 27, + "text": "goToAdmin: \"管理后台\"," + }, + { + "line": 28, + "text": "sidebarDesc: \"管理文档与模型参数\"," + }, + { + "line": 29, + "text": "tabFiles: \"文档管理\"," + }, + { + "line": 30, + "text": "files: \"文件\"," + }, + { + "line": 31, + "text": "notes: \"笔记\"," + }, + { + "line": 32, + "text": "tabSettings: \"系统设置\"," + }, + { + "line": 33, + "text": "systemConfiguration: \"系统配置\"," + }, + { + "line": 34, + "text": "noFiles: \"暂无文件\"," + }, + { + "line": 35, + "text": "noFilesDesc: \"支持 PDF、Office 文档、文本、代码、图片等格式\"," + }, + { + "line": 36, + "text": "addFile: \"添加文件\"," + }, + { + "line": 37, + "text": "clearAll: \"清空知识库\"," + }, + { + "line": 38, + "text": "uploading: \"处理中\"," + }, + { + "line": 39, + "text": "statusIndexing: \"向量化中...\"," + }, + { + "line": 40, + "text": "statusReady: \"已索引\"," + }, + { + "line": 43, + "text": "ragSettings: \"RAG 设置\"," + }, + { + "line": 44, + "text": "enableRerank: \"启用重排序 (Rerank)\"," + }, + { + "line": 45, + "text": "enableRerankDesc: \"使用重排序模型对检索结果进行二次精排,提高准确性\"," + }, + { + "line": 46, + "text": "selectRerankModel: \"选择 Rerank 模型\"," + }, + { + "line": 47, + "text": "selectModelPlaceholder: \"请选择模型...\"," + }, + { + "line": 50, + "text": "headerModelSelection: \"模型选择\"," + }, + { + "line": 51, + "text": "headerHyperparams: \"推理参数\"," + }, + { + "line": 52, + "text": "headerIndexing: \"索引与切片\"," + }, + { + "line": 53, + "text": "headerRetrieval: \"召回与排序\"," + }, + { + "line": 54, + "text": "btnManageModels: \"管理模型供应商\"," + }, + { + "line": 56, + "text": "lblLLM: \"推理模型 (LLM)\"," + }, + { + "line": 57, + "text": "lblEmbedding: \"向量模型 (Embedding)\"," + }, + { + "line": 58, + "text": "lblRerankRef: \"重排序模型 (Rerank)\"," + }, + { + "line": 59, + "text": "lblTemperature: \"随机性 (Temperature)\"," + }, + { + "line": 60, + "text": "lblMaxTokens: \"最大输出 (Max Tokens)\"," + }, + { + "line": 61, + "text": "lblChunkSize: \"切片大小 (Tokens)\"," + }, + { + "line": 62, + "text": "lblChunkOverlap: \"重叠阈值 (Overlap)\"," + }, + { + "line": 63, + "text": "lblTopK: \"召回数量 (Top K)\"," + }, + { + "line": 64, + "text": "lblRerank: \"开启重排序 (Rerank)\"," + }, + { + "line": 67, + "text": "idxModalTitle: \"知识库分段与清洗\"," + }, + { + "line": 68, + "text": "idxDesc: \"在文件存入知识库之前,请配置分段规则和 Embedding 模型。\"," + }, + { + "line": 69, + "text": "idxFiles: \"待处理文件\"," + }, + { + "line": 70, + "text": "idxMethod: \"分段设置\"," + }, + { + "line": 71, + "text": "idxEmbeddingModel: \"Embedding 模型\"," + }, + { + "line": 72, + "text": "idxStart: \"开始索引\"," + }, + { + "line": 73, + "text": "idxCancel: \"Cancel上传\"," + }, + { + "line": 74, + "text": "idxAuto: \"自动分段\"," + }, + { + "line": 75, + "text": "idxCustom: \"自定义\"," + }, + { + "line": 78, + "text": "mmTitle: \"模型供应商管理\"," + }, + { + "line": 79, + "text": "mmAddBtn: \"添加模型\"," + }, + { + "line": 80, + "text": "mmEdit: \"编辑\"," + }, + { + "line": 81, + "text": "mmDelete: \"删除\"," + }, + { + "line": 82, + "text": "mmEmpty: \"暂无配置的模型\"," + }, + { + "line": 83, + "text": "mmFormName: \"模型别名 (显示用)\"," + }, + { + "line": 84, + "text": "mmFormProvider: \"供应商类型\"," + }, + { + "line": 85, + "text": "mmFormModelId: \"模型 ID (如 gpt-4o)\"," + }, + { + "line": 87, + "text": "mmFormType: \"模型功能类型\"," + }, + { + "line": 88, + "text": "mmFormVision: \"支持视觉能力\"," + }, + { + "line": 89, + "text": "mmFormDimensions: \"向量维度\"," + }, + { + "line": 90, + "text": "mmFormDimensionsHelp: \"嵌入向量的维度大小,常见值:1536、3072\"," + }, + { + "line": 91, + "text": "mmSave: \"保存配置\"," + }, + { + "line": 93, + "text": "mmErrorNotAuthenticated: \"未登录,无法操作\"," + }, + { + "line": 94, + "text": "mmErrorTitle: \"操作失败\"," + }, + { + "line": 95, + "text": "modelEnabled: \"模型已启用\"," + }, + { + "line": 96, + "text": "modelDisabled: \"模型已禁用\"," + }, + { + "line": 97, + "text": "confirmChangeEmbeddingModel: \"警告:更改向量模型可能导致现有索引无法搜索。\\n这将无法通过新的向量模型搜索到之前通过旧模型索引的内容。\\n是否确认更改?\"," + }, + { + "line": 98, + "text": "embeddingModelWarning: \"更改此设置可能需要清空并重新导入知识库。\"," + }, + { + "line": 99, + "text": "sourcePreview: \"引用源预览\"," + }, + { + "line": 100, + "text": "matchScore: \"匹配度\"," + }, + { + "line": 101, + "text": "copyContent: \"复制内容\"," + }, + { + "line": 102, + "text": "copySuccess: \"复制成功\"," + }, + { + "line": 104, + "text": "// ConfigPanel 缺失的翻译" + }, + { + "line": 105, + "text": "selectLLMModel: \"请选择LLM模型\"," + }, + { + "line": 106, + "text": "selectEmbeddingModel: \"请选择Embedding模型\"," + }, + { + "line": 107, + "text": "defaultForUploads: \"用于新上传和查询\"," + }, + { + "line": 108, + "text": "noRerankModel: \"无重排序模型\"," + }, + { + "line": 109, + "text": "vectorSimilarityThreshold: \"向量检索阈值\"," + }, + { + "line": 110, + "text": "rerankSimilarityThreshold: \"重排序阈值\"," + }, + { + "line": 111, + "text": "filterLowResults: \"低于此值的结果将被过滤\"," + }, + { + "line": 112, + "text": "noteCreatedSuccess: \"笔记创建成功\"," + }, + { + "line": 113, + "text": "noteCreatedFailed: \"笔记创建失败\"," + }, + { + "line": 114, + "text": "fullTextSearch: \"全文检索\"," + }, + { + "line": 115, + "text": "hybridVectorWeight: \"混合检索向量权重\"," + }, + { + "line": 116, + "text": "hybridVectorWeightDesc: \"向量平衡: 1.0 = 纯向量, 0.0 = 纯全文\"," + }, + { + "line": 117, + "text": "lblQueryExpansion: \"查询扩展 (Multi-Query)\"," + }, + { + "line": 118, + "text": "lblHyDE: \"HyDE (假设文档嵌入)\"," + }, + { + "line": 119, + "text": "lblQueryExpansionDesc: \"生成多个查询变体以提高覆盖率\"," + }, + { + "line": 120, + "text": "lblHyDEDesc: \"生成假设回答以改善语义搜索\"," + }, + { + "line": 122, + "text": "apiKeyValidationFailed: \"API Key 验证失败\"," + }, + { + "line": 123, + "text": "keepOriginalKey: \"留空保持原 API Key,输入新值则替换\"," + }, + { + "line": 124, + "text": "leaveEmptyNoChange: \"留空不修改\"," + }, + { + "line": 126, + "text": "mmFormApiKeyPlaceholder: \"请输入 API Key\"," + }, + { + "line": 128, + "text": "// 更多组件缺失的翻译" + }, + { + "line": 129, + "text": "reconfigureFile: \"重新配置文件\"," + }, + { + "line": 130, + "text": "modifySettings: \"修改文件的切片和向量化设置\"," + }, + { + "line": 132, + "text": "allFilesIndexed: \"所有文件将使用下面的设置进行索引\"," + }, + { + "line": 133, + "text": "noEmbeddingModels: \"未配置嵌入模型\"," + }, + { + "line": 134, + "text": "reconfigure: \"重新配置\"," + }, + { + "line": 135, + "text": "refresh: \"刷新\"," + }, + { + "line": 136, + "text": "settings: \"设置\"," + }, + { + "line": 137, + "text": "needLogin: \"需要登录才能使用聊天功能\"," + }, + { + "line": 138, + "text": "citationSources: \"引用源\"," + }, + { + "line": 139, + "text": "chunkNumber: \"片段\"," + }, + { + "line": 140, + "text": "getUserListFailed: \"获取用户列表失败\"," + }, + { + "line": 141, + "text": "usernamePasswordRequired: \"用户名和密码不能为空\"," + }, + { + "line": 142, + "text": "passwordMinLength: \"密码长度不能少于6位\"," + }, + { + "line": 143, + "text": "userCreatedSuccess: \"用户创建成功\"," + }, + { + "line": 144, + "text": "createUserFailed: \"创建用户失败\"," + }, + { + "line": 145, + "text": "userPromotedToAdmin: \"用户已提升为管理员\"," + }, + { + "line": 146, + "text": "userDemotedFromAdmin: \"用户已降级为普通用户\"," + }, + { + "line": 147, + "text": "updateUserFailed: \"更新用户失败\"," + }, + { + "line": 148, + "text": "confirmDeleteUser: \"Confirm要删除此用户吗?\"," + }, + { + "line": 149, + "text": "deleteUser: \"删除用户\"," + }, + { + "line": 150, + "text": "deleteUserFailed: \"删除用户失败\"," + }, + { + "line": 151, + "text": "userDeletedSuccessfully: \"用户删除成功\"," + }, + { + "line": 152, + "text": "makeUserAdmin: \"设为管理员\"," + }, + { + "line": 153, + "text": "makeUserRegular: \"设为普通用户\"," + }, + { + "line": 154, + "text": "loading: \"加载中...\"," + }, + { + "line": 155, + "text": "noUsers: \"暂无用户\"," + }, + { + "line": 157, + "text": "// ChangePasswordModal 和 SearchResultsPanel 缺失的翻译" + }, + { + "line": 158, + "text": "fillAllFields: \"请填写所有字段\"," + }, + { + "line": 159, + "text": "passwordMismatch: \"新密码和确认密码不匹配\"," + }, + { + "line": 160, + "text": "newPasswordMinLength: \"新密码长度不能少于6位\"," + }, + { + "line": 161, + "text": "changePasswordFailed: \"修改密码失败\"," + }, + { + "line": 162, + "text": "changePasswordTitle: \"修改密码\"," + }, + { + "line": 163, + "text": "changing: \"修改中...\"," + }, + { + "line": 164, + "text": "searchResults: \"搜索到的相关内容\"," + }, + { + "line": 166, + "text": "// VisionModelSelector 缺失的翻译" + }, + { + "line": 167, + "text": "visionModelSettings: \"视觉模型设置\"," + }, + { + "line": 168, + "text": "defaultVisionModel: \"默认视觉模型\"," + }, + { + "line": 169, + "text": "loadVisionModelFailed: \"加载视觉模型失败\"," + }, + { + "line": 170, + "text": "loadFailed: \"加载失败,请检查网络连接\"," + }, + { + "line": 171, + "text": "saveVisionModelFailed: \"保存视觉模型失败\"," + }, + { + "line": 172, + "text": "noVisionModels: \"没有可用的视觉模型\"," + }, + { + "line": 173, + "text": "selectVisionModel: \"请选择视觉模型\"," + }, + { + "line": 174, + "text": "visionModelHelp: \"用于处理图片文件的视觉模型。如果没有可用模型,请在模型管理中添加并勾选“支持视觉”选项。\"," + }, + { + "line": 175, + "text": "mmErrorNameRequired: \"模型名称为必填项。\"," + }, + { + "line": 176, + "text": "mmErrorModelIdRequired: \"模型 ID 为必填项。\"," + }, + { + "line": 177, + "text": "mmErrorBaseUrlRequired: \"Base URL 为必填项。\"," + }, + { + "line": 181, + "text": "typeLLM: \"对话推理 (LLM)\"," + }, + { + "line": 182, + "text": "typeEmbedding: \"向量化 (Embedding)\"," + }, + { + "line": 183, + "text": "typeRerank: \"重排序 (Rerank)\"," + }, + { + "line": 184, + "text": "typeVision: \"视觉识别 (Vision)\"," + }, + { + "line": 186, + "text": "welcome: \"你好!我是您的智能知识库助手。请在“系统设置”中选择模型,上传文档建立索引,然后即可开始提问。\"," + }, + { + "line": 187, + "text": "placeholderWithFiles: \"基于知识库内容提问...\"," + }, + { + "line": 188, + "text": "placeholderEmpty: \"请先上传文件并完成索引...\"," + }, + { + "line": 189, + "text": "analyzing: \"正在检索并生成答案...\"," + }, + { + "line": 190, + "text": "errorGeneric: \"处理您的请求时遇到错误。\"," + }, + { + "line": 191, + "text": "errorLabel: \"错误\"," + }, + { + "line": 192, + "text": "errorNoModel: \"未选择推理模型或配置无效。\"," + }, + { + "line": 193, + "text": "aiDisclaimer: \"AI 可能会犯错。请核实源文件中的重要信息。\"," + }, + { + "line": 194, + "text": "confirmClear: \"Confirm要清空所有文件及索引吗?\"," + }, + { + "line": 195, + "text": "removeFile: \"移除文件\"," + }, + { + "line": 196, + "text": "apiError: \"缺少配置或 API 密钥无效。\"," + }, + { + "line": 197, + "text": "geminiError: \"API 请求失败。\"," + }, + { + "line": 198, + "text": "processedButNoText: \"无法生成文本回复。\"," + }, + { + "line": 199, + "text": "unitByte: \"字节\"," + }, + { + "line": 200, + "text": "readingFailed: \"读取文件失败\"," + }, + { + "line": 203, + "text": "copy: \"复制内容\"," + }, + { + "line": 204, + "text": "copied: \"已复制\"," + }, + { + "line": 207, + "text": "logout: \"退出登录\"," + }, + { + "line": 208, + "text": "changePassword: \"修改密码\"," + }, + { + "line": 209, + "text": "userManagement: \"用户管理\"," + }, + { + "line": 210, + "text": "userList: \"用户列表\"," + }, + { + "line": 211, + "text": "addUser: \"新增用户\"," + }, + { + "line": 212, + "text": "username: \"用户名\"," + }, + { + "line": 213, + "text": "password: \"密码\"," + }, + { + "line": 214, + "text": "confirmPassword: \"确认密码\"," + }, + { + "line": 215, + "text": "currentPassword: \"当前密码\"," + }, + { + "line": 216, + "text": "newPassword: \"新密码\"," + }, + { + "line": 217, + "text": "createUser: \"创建用户\"," + }, + { + "line": 218, + "text": "admin: \"管理员\"," + }, + { + "line": 219, + "text": "user: \"普通用户\"," + }, + { + "line": 220, + "text": "adminUser: \"设为管理员\", // 新增," + }, + { + "line": 221, + "text": "confirmChange: \"确认修改\"," + }, + { + "line": 222, + "text": "changeUserPassword: \"修改用户密码\"," + }, + { + "line": 223, + "text": "enterNewPassword: \"请输入新密码\"," + }, + { + "line": 224, + "text": "createdAt: \"创建时间\"," + }, + { + "line": 225, + "text": "newChat: \"新建对话\"," + }, + { + "line": 228, + "text": "kbManagement: \"知识库管理\"," + }, + { + "line": 229, + "text": "kbManagementDesc: \"管理您的文档和知识分组\"," + }, + { + "line": 230, + "text": "searchPlaceholder: \"搜索文件名...\"," + }, + { + "line": 231, + "text": "allGroups: \"所有分组\"," + }, + { + "line": 232, + "text": "allStatus: \"所有状态\"," + }, + { + "line": 236, + "text": "uploadFile: \"上传文件\"," + }, + { + "line": 237, + "text": "fileName: \"文件名\"," + }, + { + "line": 238, + "text": "size: \"大小\"," + }, + { + "line": 239, + "text": "status: \"状态\"," + }, + { + "line": 240, + "text": "groups: \"分组\"," + }, + { + "line": 241, + "text": "actions: \"操作\"," + }, + { + "line": 242, + "text": "groupsActions: \"分组 / 操作\"," + }, + { + "line": 243, + "text": "noFilesFound: \"未找到匹配的文件\"," + }, + { + "line": 244, + "text": "showingRange: \"显示 $1 到 $2 条,共 $3 条\"," + }, + { + "line": 245, + "text": "confirmDeleteFile: \"Confirm要删除此文件吗?\"," + }, + { + "line": 246, + "text": "fileDeleted: \"文件已删除\"," + }, + { + "line": 247, + "text": "deleteFailed: \"删除失败\"," + }, + { + "line": 248, + "text": "fileAddedToGroup: \"文件已添加到分组\"," + }, + { + "line": 249, + "text": "failedToAddToGroup: \"添加到分组失败\"," + }, + { + "line": 250, + "text": "fileRemovedFromGroup: \"文件已从分组移除\"," + }, + { + "line": 251, + "text": "failedToRemoveFromGroup: \"从分组移除失败\"," + }, + { + "line": 252, + "text": "confirmClearKB: \"警告:此操作将永久删除所有文件及其索引数据。\\n\\nConfirm要清空知识库吗?\"," + }, + { + "line": 253, + "text": "kbCleared: \"知识库已清空\"," + }, + { + "line": 254, + "text": "clearFailed: \"清空失败\"," + }, + { + "line": 255, + "text": "loginRequired: \"请先登录\"," + }, + { + "line": 256, + "text": "uploadErrors: \"以下文件无法上传\"," + }, + { + "line": 257, + "text": "uploadWarning: \"$1 files已准备上传,$2 files被过滤\"," + }, + { + "line": 258, + "text": "uploadFailed: \"上传失败\"," + }, + { + "line": 259, + "text": "preview: \"预览\"," + }, + { + "line": 260, + "text": "addGroup: \"添加分组\"," + }, + { + "line": 261, + "text": "delete: \"删除\"," + }, + { + "line": 262, + "text": "retry: \"重试\"," + }, + { + "line": 263, + "text": "retrying: \"重试中...\"," + }, + { + "line": 264, + "text": "retrySuccess: \"重试成功\"," + }, + { + "line": 265, + "text": "retryFailed: \"重试失败\"," + }, + { + "line": 266, + "text": "chunkInfo: \"分片信息\"," + }, + { + "line": 267, + "text": "totalChunks: \"总分片数\"," + }, + { + "line": 268, + "text": "chunkIndex: \"分片\"," + }, + { + "line": 269, + "text": "contentLength: \"字符\"," + }, + { + "line": 270, + "text": "position: \"位置\"," + }, + { + "line": 273, + "text": "reconfigureTitle: \"重新配置文件\"," + }, + { + "line": 274, + "text": "reconfigureDesc: \"修改文件处理设置\"," + }, + { + "line": 275, + "text": "indexingConfigTitle: \"文档索引配置\"," + }, + { + "line": 276, + "text": "indexingConfigDesc: \"配置文档处理参数,选择处理模式\"," + }, + { + "line": 277, + "text": "pendingFiles: \"待处理文件\"," + }, + { + "line": 278, + "text": "processingMode: \"处理模式\"," + }, + { + "line": 280, + "text": "recommendationReason: \"推荐理由\"," + }, + { + "line": 281, + "text": "fastMode: \"快速模式\"," + }, + { + "line": 282, + "text": "fastModeDesc: \"简单提取文本,速度快,无额外成本,适合纯文本文档\"," + }, + { + "line": 283, + "text": "preciseMode: \"精准模式\"," + }, + { + "line": 284, + "text": "preciseModeDesc: \"精准识别内容,保留图文混合信息,需要 API 费用\"," + }, + { + "line": 285, + "text": "fastModeFeatures: \"快速模式特点:\"," + }, + { + "line": 286, + "text": "fastFeature1: \"简单提取文本内容\"," + }, + { + "line": 287, + "text": "fastFeature2: \"处理速度快,适合批量处理\"," + }, + { + "line": 288, + "text": "fastFeature3: \"无额外成本\"," + }, + { + "line": 289, + "text": "fastFeature4: \"仅处理文字信息\"," + }, + { + "line": 290, + "text": "fastFeature5: \"适合纯文本文档\"," + }, + { + "line": 291, + "text": "preciseModeFeatures: \"精准模式特点:\"," + }, + { + "line": 292, + "text": "preciseFeature1: \"精准识别内容结构\"," + }, + { + "line": 293, + "text": "preciseFeature2: \"识别图片/图表/表格\"," + }, + { + "line": 294, + "text": "preciseFeature3: \"保留图文混合内容\"," + }, + { + "line": 295, + "text": "preciseFeature4: \"保留页面布局信息\"," + }, + { + "line": 296, + "text": "preciseFeature5: \"需要 API 费用\"," + }, + { + "line": 297, + "text": "preciseFeature6: \"处理时间较长\"," + }, + { + "line": 298, + "text": "embeddingModel: \"嵌入模型\"," + }, + { + "line": 299, + "text": "pleaseSelect: \"请选择...\"," + }, + { + "line": 300, + "text": "pleaseSelectKnowledgeGroupFirst: \"请先选择知识组再保存\"," + }, + { + "line": 301, + "text": "selectUnassignGroupWarning: \"如果您想Cancel分配知识组,请确认此操作\"," + }, + { + "line": 302, + "text": "chunkConfig: \"切片配置\"," + }, + { + "line": 303, + "text": "chunkSize: \"切片大小 (Tokens)\"," + }, + { + "line": 304, + "text": "min: \"最小\"," + }, + { + "line": 305, + "text": "max: \"上限\"," + }, + { + "line": 306, + "text": "chunkOverlap: \"重叠大小 (Tokens)\"," + }, + { + "line": 307, + "text": "modelLimitsInfo: \"模型限制信息\"," + }, + { + "line": 308, + "text": "model: \"模型\"," + }, + { + "line": 309, + "text": "maxChunkSize: \"切片上限\"," + }, + { + "line": 310, + "text": "maxOverlapSize: \"重叠上限\"," + }, + { + "line": 311, + "text": "maxBatchSize: \"批量限制\"," + }, + { + "line": 312, + "text": "envLimitWeaker: \"环境变量限制更严格\"," + }, + { + "line": 313, + "text": "optimizationTips: \"优化建议\"," + }, + { + "line": 314, + "text": "tipChunkTooLarge: \"切片较大,可能影响检索精度\"," + }, + { + "line": 315, + "text": "tipOverlapSmall: \"建议重叠至少 $1 tokens\"," + }, + { + "line": 316, + "text": "tipMaxValues: \"使用最大值,处理速度可能较慢\"," + }, + { + "line": 317, + "text": "tipPreciseCost: \"精准模式会产生 API 费用,请确认预算\"," + }, + { + "line": 318, + "text": "selectEmbeddingFirst: \"请先选择嵌入模型\"," + }, + { + "line": 319, + "text": "confirmPreciseCost: \"精准模式会产生 API 费用,是否继续?\"," + }, + { + "line": 320, + "text": "startProcessing: \"开始处理\"," + }, + { + "line": 323, + "text": "notebooks: \"知识组\"," + }, + { + "line": 324, + "text": "notebooksDesc: \"管理您的文档和知识分组\"," + }, + { + "line": 325, + "text": "createNotebook: \"新建知识组\"," + }, + { + "line": 326, + "text": "chatWithNotebook: \"基于此知识组对话\"," + }, + { + "line": 327, + "text": "editNotebook: \"编辑知识组\"," + }, + { + "line": 328, + "text": "deleteNotebook: \"删除知识组 (包含文件)\"," + }, + { + "line": 329, + "text": "noDescription: \"无描述\"," + }, + { + "line": 330, + "text": "noNotebooks: \"暂无知识组,点击右上角创建\"," + }, + { + "line": 331, + "text": "createFailed: \"创建失败\"," + }, + { + "line": 332, + "text": "confirmDeleteNotebook: \"Confirm要删除知识组 \\\"$1\\\" 吗?\\n\\n注意:这将同时永久删除该知识组下的所有文件及其索引数据!\"," + }, + { + "line": 336, + "text": "personalNotebookDesc: \"记录您的个人笔记与灵感\"," + }, + { + "line": 337, + "text": "noNotes: \"暂无个人笔记\"," + }, + { + "line": 338, + "text": "createNote: \"新建笔记\"," + }, + { + "line": 341, + "text": "createNotebookTitle: \"新建知识组\"," + }, + { + "line": 342, + "text": "editNotebookTitle: \"编辑知识组\"," + }, + { + "line": 343, + "text": "createFailedRetry: \"创建失败,请重试\"," + }, + { + "line": 344, + "text": "updateFailedRetry: \"更新失败,请重试\"," + }, + { + "line": 345, + "text": "name: \"名称\"," + }, + { + "line": 346, + "text": "nameHelp: \"一个清晰的名称能帮你快速找到它。\"," + }, + { + "line": 347, + "text": "namePlaceholder: \"例如:量子物理研究...\"," + }, + { + "line": 348, + "text": "shortDescription: \"简短描述\"," + }, + { + "line": 349, + "text": "descPlaceholder: \"一句话描述这个知识组的用途\"," + }, + { + "line": 350, + "text": "creating: \"正在创建...\"," + }, + { + "line": 351, + "text": "createNow: \"立即创建\"," + }, + { + "line": 352, + "text": "saving: \"正在保存...\"," + }, + { + "line": 353, + "text": "save: \"保存\"," + }, + { + "line": 356, + "text": "chatTitle: \"知识库问答\"," + }, + { + "line": 357, + "text": "chatDesc: \"与您的知识库进行智能对话\"," + }, + { + "line": 358, + "text": "viewHistory: \"查看对话历史\"," + }, + { + "line": 359, + "text": "saveSettingsFailed: \"保存设置失败\"," + }, + { + "line": 360, + "text": "loginToUpload: \"请先登录再进行上传\"," + }, + { + "line": 361, + "text": "fileSizeLimitExceeded: \"$1 ($2 - 超过 $3MB 限制)\"," + }, + { + "line": 362, + "text": "unsupportedFileType: \"$1 - 不支持的文件类型 ($2)\"," + }, + { + "line": 363, + "text": "readFailed: \"$1 - 读取失败\"," + }, + { + "line": 364, + "text": "loadHistoryFailed: \"加载对话历史失败\"," + }, + { + "line": 365, + "text": "loadingUserData: \"正在加载用户数据...\"," + }, + { + "line": 366, + "text": "errorMessage: \"错误: $1\"," + }, + { + "line": 367, + "text": "welcomeMessage: \"你好!我是您的智能知识库助手。请选择知识库然后进行提问。\"," + }, + { + "line": 368, + "text": "selectKnowledgeGroup: \"选择知识库分组\"," + }, + { + "line": 369, + "text": "allKnowledgeGroups: \"全部知识库\"," + }, + { + "line": 370, + "text": "unknownGroup: \"未知分组\"," + }, + { + "line": 374, + "text": "generalSettings: \"一般配置\"," + }, + { + "line": 375, + "text": "modelManagement: \"模型管理\"," + }, + { + "line": 376, + "text": "languageSettings: \"语言设置\"," + }, + { + "line": 377, + "text": "passwordChangeSuccess: \"密码修改成功\"," + }, + { + "line": 378, + "text": "passwordChangeFailed: \"密码修改失败\"," + }, + { + "line": 379, + "text": "create: \"创建\"," + }, + { + "line": 383, + "text": "navChat: \"对话\"," + }, + { + "line": 384, + "text": "navCoach: \"教练\"," + }, + { + "line": 385, + "text": "navKnowledge: \"知识库\"," + }, + { + "line": 386, + "text": "navKnowledgeGroups: \"知识组\"," + }, + { + "line": 387, + "text": "navNotebook: \"笔记本\"," + }, + { + "line": 388, + "text": "navAgent: \"智能体\"," + }, + { + "line": 389, + "text": "navPlugin: \"插件\"," + }, + { + "line": 390, + "text": "notebookDesc: \"记录您的个人想法和研究笔记。\"," + }, + { + "line": 391, + "text": "newNote: \"新建笔记\"," + }, + { + "line": 392, + "text": "editNote: \"编辑笔记\"," + }, + { + "line": 393, + "text": "noNotesFound: \"未找到笔记\"," + }, + { + "line": 394, + "text": "startByCreatingNote: \"开始创建您的第一条个人笔记。\"," + }, + { + "line": 395, + "text": "navCrawler: \"资源获取\"," + }, + { + "line": 396, + "text": "expandMenu: \"展开菜单\"," + }, + { + "line": 397, + "text": "switchLanguage: \"切换语言\"," + }, + { + "line": 398, + "text": "navGlobal: \"全局\"," + }, + { + "line": 399, + "text": "navTenants: \"租户管理\"," + }, + { + "line": 400, + "text": "navSystemModels: \"系统模型\"," + }, + { + "line": 401, + "text": "navTenantManagement: \"租户管理\"," + }, + { + "line": 402, + "text": "navUsersTeam: \"用户与团队\"," + }, + { + "line": 403, + "text": "navTenantSettings: \"租户设置\"," + }, + { + "line": 404, + "text": "adminConsole: \"管理控制台\"," + }, + { + "line": 405, + "text": "globalDashboard: \"全局仪表盘\"," + }, + { + "line": 408, + "text": "selectKnowledgeGroups: \"选择知识库分组\"," + }, + { + "line": 410, + "text": "done: \"完成\"," + }, + { + "line": 411, + "text": "all: \"全部\"," + }, + { + "line": 416, + "text": "autoRefresh: \"自动刷新\"," + }, + { + "line": 417, + "text": "refreshInterval: \"刷新间隔\"," + }, + { + "line": 420, + "text": "errorRenderFlowchart: \"无法渲染流程图\"," + }, + { + "line": 421, + "text": "errorLoadData: \"加载数据失败\"," + }, + { + "line": 422, + "text": "confirmUnsupportedFile: \"文件类型 .$1 可能不受支持,是否继续?\"," + }, + { + "line": 423, + "text": "errorReadFile: \"文件读取失败: $1\"," + }, + { + "line": 424, + "text": "successUploadFile: \"文件上传并关联成功\"," + }, + { + "line": 425, + "text": "errorUploadFile: \"上传失败: $1\"," + }, + { + "line": 426, + "text": "errorProcessFile: \"文件处理失败\"," + }, + { + "line": 427, + "text": "errorTitleContentRequired: \"标题和内容不能为空\"," + }, + { + "line": 428, + "text": "successNoteUpdated: \"笔记已更新\"," + }, + { + "line": 429, + "text": "successNoteCreated: \"笔记已创建\"," + }, + { + "line": 430, + "text": "errorSaveFailed: \"保存失败: $1\"," + }, + { + "line": 431, + "text": "confirmDeleteNote: \"Confirm要删除这条笔记吗?\"," + }, + { + "line": 432, + "text": "successNoteDeleted: \"笔记已删除\"," + }, + { + "line": 433, + "text": "confirmRemoveFileFromGroup: \"Confirm要将文件 \\\"$1\\\" 从此知识组移除吗?(文件仍保留在知识库中)\"," + }, + { + "line": 434, + "text": "togglePreviewOpen: \"开启预览\"," + }, + { + "line": 435, + "text": "togglePreviewClose: \"关闭预览\"," + }, + { + "line": 436, + "text": "aiAssistant: \"AI 智能助手\"," + }, + { + "line": 437, + "text": "polishContent: \"润色内容\"," + }, + { + "line": 438, + "text": "expandContent: \"扩写\"," + }, + { + "line": 439, + "text": "summarizeContent: \"精简摘要\"," + }, + { + "line": 440, + "text": "translateToEnglish: \"翻译成英文\"," + }, + { + "line": 441, + "text": "fixGrammar: \"修复语法\"," + }, + { + "line": 442, + "text": "aiCommandInstructPolish: \"请帮我润色这段文字,使其表达更地道、更专业。\"," + }, + { + "line": 443, + "text": "aiCommandInstructExpand: \"请帮我扩写这段文字,增加更多细节,使其更充实和详细。\"," + }, + { + "line": 444, + "text": "aiCommandInstructSummarize: \"请帮我精简这段文字,提取核心观点,生成简洁的摘要。\"," + }, + { + "line": 445, + "text": "aiCommandInstructTranslateToEn: \"请帮我将这段文字翻译成英文。\"," + }, + { + "line": 446, + "text": "aiCommandInstructFixGrammar: \"请检查并修复这段文字中的语法和拼写错误。\"," + }, + { + "line": 447, + "text": "aiCommandsPreset: \"常用指令\"," + }, + { + "line": 448, + "text": "aiCommandsCustom: \"自定义需求\"," + }, + { + "line": 449, + "text": "aiCommandsCustomPlaceholder: \"例如:把这段话改写得更正式一点...\"," + }, + { + "line": 450, + "text": "aiCommandsReferenceContext: \"参考上下文 (前200字):\"," + }, + { + "line": 451, + "text": "aiCommandsStartGeneration: \"开始生成\"," + }, + { + "line": 452, + "text": "aiCommandsResult: \"AI 建议\"," + }, + { + "line": 453, + "text": "aiCommandsGenerating: \"生成中...\"," + }, + { + "line": 454, + "text": "aiCommandsApplyResult: \"替换选区\"," + }, + { + "line": 455, + "text": "aiCommandsGoBack: \"返回修改\"," + }, + { + "line": 456, + "text": "aiCommandsReset: \"清空重置\"," + }, + { + "line": 457, + "text": "aiCommandsModalPreset: \"选择预设指令\"," + }, + { + "line": 458, + "text": "aiCommandsModalCustom: \"或输入自定义指令\"," + }, + { + "line": 459, + "text": "aiCommandsModalCustomPlaceholder: \"告诉 AI 你想做什么...\"," + }, + { + "line": 460, + "text": "aiCommandsModalBasedOnSelection: \"将基于以下选Chinese本处理:\"," + }, + { + "line": 461, + "text": "aiCommandsModalResult: \"生成结果\"," + }, + { + "line": 462, + "text": "aiCommandsModalApply: \"采用此结果\"," + }, + { + "line": 463, + "text": "noteTitlePlaceholder: \"笔记标题\"," + }, + { + "line": 464, + "text": "noteContentPlaceholder: \"开始写作 (支持 Markdown)...\"," + }, + { + "line": 465, + "text": "markdownPreviewArea: \"Markdown 预览区域\"," + }, + { + "line": 466, + "text": "back: \"返回\"," + }, + { + "line": 467, + "text": "chatWithGroup: \"基于此知识组进行对话\"," + }, + { + "line": 468, + "text": "chatWithFile: \"基于此文件进行对话\"," + }, + { + "line": 469, + "text": "filesCountLabel: \"文件 ($1)\"," + }, + { + "line": 470, + "text": "notesCountLabel: \"笔记 ($1)\"," + }, + { + "line": 471, + "text": "indexIntoKB: \"索引到知识库\"," + }, + { + "line": 472, + "text": "noFilesOrNotes: \"暂无$1\"," + }, + { + "line": 473, + "text": "importFolder: \"导入文件夹\"," + }, + { + "line": 476, + "text": "createPDFNote: \"创建PDF笔记\"," + }, + { + "line": 477, + "text": "screenshotPreview: \"截图预览\"," + }, + { + "line": 478, + "text": "associateKnowledgeGroup: \"关联知识组\"," + }, + { + "line": 479, + "text": "globalNoSpecificGroup: \"全局 (无特定知识组)\"," + }, + { + "line": 480, + "text": "title: \"标题\"," + }, + { + "line": 481, + "text": "enterNoteTitle: \"输入笔记标题\"," + }, + { + "line": 482, + "text": "contentOCR: \"内容 (OCR提取的文本)\"," + }, + { + "line": 483, + "text": "extractingText: \"正在提取文本...\"," + }, + { + "line": 484, + "text": "analyzingImage: \"正在分析图片并提取文字...\"," + }, + { + "line": 485, + "text": "noTextExtracted: \"未提取到文本\"," + }, + { + "line": 486, + "text": "saveNote: \"保存笔记\"," + }, + { + "line": 489, + "text": "page: \"第\"," + }, + { + "line": 490, + "text": "placeholderText: \"OCR提取的文本将显示在这里,您可以编辑...\"," + }, + { + "line": 493, + "text": "createNewNotebook: \"新建知识组\"," + }, + { + "line": 494, + "text": "nameField: \"名称\"," + }, + { + "line": 496, + "text": "exampleResearch: \"例如:量子物理研究...\"," + }, + { + "line": 497, + "text": "shortDescriptionField: \"简短描述\"," + }, + { + "line": 498, + "text": "describePurpose: \"一句话描述这个知识组的用途\"," + }, + { + "line": 499, + "text": "creationFailed: \"创建失败,请重试\"," + }, + { + "line": 502, + "text": "preparingPDFConversion: \"准备转换PDF...\"," + }, + { + "line": 503, + "text": "pleaseWait: \"请稍候,这可能需要几分钟时间\"," + }, + { + "line": 504, + "text": "convertingPDF: \"正在转换PDF...\"," + }, + { + "line": 505, + "text": "pdfConversionFailed: \"PDF转换失败\"," + }, + { + "line": 506, + "text": "pdfConversionError: \"无法转换此文件为PDF格式,请检查文件是否损坏或格式不支持\"," + }, + { + "line": 507, + "text": "pdfLoadFailed: \"PDF加载失败\"," + }, + { + "line": 508, + "text": "pdfLoadError: \"无法在浏览器中显示PDF,请尝试下载或在新窗口中打开\"," + }, + { + "line": 509, + "text": "downloadingPDF: \"下载PDF中...\"," + }, + { + "line": 510, + "text": "loadingPDF: \"加载PDF中...\"," + }, + { + "line": 511, + "text": "zoomOut: \"缩小\"," + }, + { + "line": 512, + "text": "zoomIn: \"放大\"," + }, + { + "line": 513, + "text": "resetZoom: \"重置缩放\"," + }, + { + "line": 514, + "text": "selectPageNumber: \"选择页码:\"," + }, + { + "line": 515, + "text": "enterPageNumber: \"输入想要选取的页码\"," + }, + { + "line": 516, + "text": "exitSelectionMode: \"退出选择模式\"," + }, + { + "line": 517, + "text": "clickToSelectAndNote: \"点击框选区域并记笔记\"," + }, + { + "line": 518, + "text": "regeneratePDF: \"重新生成 PDF\"," + }, + { + "line": 519, + "text": "downloadPDF: \"下载 PDF\"," + }, + { + "line": 520, + "text": "openInNewWindow: \"在新窗口中打开\"," + }, + { + "line": 521, + "text": "exitFullscreen: \"退出全屏\"," + }, + { + "line": 522, + "text": "fullscreenDisplay: \"全屏显示\"," + }, + { + "line": 523, + "text": "pdfPreview: \"PDF预览\"," + }, + { + "line": 524, + "text": "converting: \"转换中...\"," + }, + { + "line": 525, + "text": "generatePDFPreview: \"生成PDF预览\"," + }, + { + "line": 526, + "text": "previewNotSupported: \"该格式不支持预览\"," + }, + { + "line": 529, + "text": "confirmRegeneratePDF: \"Confirm要重新生成 PDF 吗?这将覆盖当前的预览文件。\"," + }, + { + "line": 532, + "text": "pdfPreviewReady: \"PDF预览\"," + }, + { + "line": 533, + "text": "convertingInProgress: \"转换中...\"," + }, + { + "line": 534, + "text": "conversionFailed: \"转换失败\"," + }, + { + "line": 535, + "text": "generatePDFPreviewButton: \"生成PDF预览\"," + }, + { + "line": 539, + "text": "requestRegenerationFailed: \"请求重新生成失败\"," + }, + { + "line": 540, + "text": "downloadPDFFailed: \"PDF 下载失败\"," + }, + { + "line": 541, + "text": "openPDFInNewTabFailed: \"在新标签页打开 PDF 失败\"," + }, + { + "line": 544, + "text": "invalidFile: \"无效的文件\"," + }, + { + "line": 545, + "text": "incompleteFileInfo: \"文件信息不完整,将使用快速模式\"," + }, + { + "line": 546, + "text": "unsupportedFileFormat: \"不支持的文件格式: .$1\"," + }, + { + "line": 547, + "text": "willUseFastMode: \"将使用快速模式 (仅文本提取)\"," + }, + { + "line": 548, + "text": "formatNoPrecise: \"格式 .$1 不支持精准模式\"," + }, + { + "line": 549, + "text": "smallFileFastOk: \"文件较小,快速模式即可满足需求\"," + }, + { + "line": 550, + "text": "mixedContentPreciseRecommended: \"文件包含图文混合内容,建议使用精准模式\"," + }, + { + "line": 551, + "text": "willIncurApiCost: \"会产生 API 费用\"," + }, + { + "line": 552, + "text": "largeFilePreciseRecommended: \"文件较大,精准模式可保留完整信息\"," + }, + { + "line": 553, + "text": "longProcessingTime: \"处理时间可能较长\"," + }, + { + "line": 554, + "text": "highApiCost: \"会产生较高 API 费用\"," + }, + { + "line": 555, + "text": "considerFileSplitting: \"建议考虑文件拆分\"," + }, + { + "line": 558, + "text": "dragDropUploadTitle: \"拖拽文件到这里上传\"," + }, + { + "line": 559, + "text": "dragDropUploadDesc: \"或点击下方按钮选择文件\"," + }, + { + "line": 560, + "text": "supportedFormats: \"支持格式\"," + }, + { + "line": 561, + "text": "browseFiles: \"浏览文件\"," + }, + { + "line": 564, + "text": "recommendationMsg: \"推荐使用$1模式: $2\"," + }, + { + "line": 565, + "text": "autoAdjustChunk: \"切片大小自动调整为上限 $1\"," + }, + { + "line": 566, + "text": "autoAdjustOverlap: \"重叠大小自动调整为上限 $1\"," + }, + { + "line": 567, + "text": "autoAdjustOverlapMin: \"重叠大小自动调整为最小值 $1\"," + }, + { + "line": 568, + "text": "loadLimitsFailed: \"无法加载模型限制,将使用默认配置\"," + }, + { + "line": 569, + "text": "maxValueMsg: \"最大值为 $1\"," + }, + { + "line": 570, + "text": "overlapRatioLimit: \"不能超过切片大小的50% ($1)\"," + }, + { + "line": 571, + "text": "onlyAdminCanModify: \"只有管理员可以修改系统设置\"," + }, + { + "line": 572, + "text": "dragToSelect: \"拖动鼠标选择范围 • 按 ESC Cancel\"," + }, + { + "line": 575, + "text": "fillTargetName: \"请填写目标知识组名称\"," + }, + { + "line": 576, + "text": "submitFailed: \"提交失败: $1\"," + }, + { + "line": 577, + "text": "importFolderTitle: \"导入本地文件夹\"," + }, + { + "line": 578, + "text": "importFolderTip: \"提示: 请选择一个本地文件夹。系统将读取并上传文件夹内所有支持的文档。\"," + }, + { + "line": 579, + "text": "lblTargetGroup: \"目标知识组名称\"," + }, + { + "line": 580, + "text": "placeholderNewGroup: \"新分组名称\"," + }, + { + "line": 581, + "text": "importToCurrentGroup: \"将导入到当前所在的分组\"," + }, + { + "line": 582, + "text": "nextStep: \"下一步\"," + }, + { + "line": 583, + "text": "selectedFilesCount: \"已选择 $1 files\"," + }, + { + "line": 584, + "text": "clickToSelectFolder: \"点击选择本地文件夹\"," + }, + { + "line": 585, + "text": "selectFolderTip: \"将读取文件夹内所有支持的文件\"," + }, + { + "line": 586, + "text": "importComplete: \"导入完成\"," + }, + { + "line": 587, + "text": "importedFromLocalFolder: \"从本地文件夹导入: $1\"," + }, + { + "line": 590, + "text": "historyTitle: \"对话历史\"," + }, + { + "line": 591, + "text": "confirmDeleteHistory: \"Confirm要删除这条对话历史吗?\"," + }, + { + "line": 592, + "text": "deleteHistorySuccess: \"对话历史删除成功\"," + }, + { + "line": 593, + "text": "deleteHistoryFailed: \"删除对话历史失败\"," + }, + { + "line": 594, + "text": "yesterday: \"昨天\"," + }, + { + "line": 595, + "text": "daysAgo: \"$1天前\"," + }, + { + "line": 596, + "text": "historyMessages: \"$1 条消息\"," + }, + { + "line": 597, + "text": "noHistory: \"暂无对话历史\"," + }, + { + "line": 598, + "text": "noHistoryDesc: \"开始一次对话来创建历史记录\"," + }, + { + "line": 599, + "text": "loadMore: \"加载更多\"," + }, + { + "line": 600, + "text": "loadingHistoriesFailed: \"加载搜索历史失败\"," + }, + { + "line": 601, + "text": "generalSettingsSubtitle: \"管理您的应用程序首选项。\"," + }, + { + "line": 602, + "text": "userManagementSubtitle: \"管理访问权限和帐户。\"," + }, + { + "line": 603, + "text": "modelManagementSubtitle: \"配置全局 AI 模型。\"," + }, + { + "line": 604, + "text": "kbSettingsSubtitle: \"索引和聊天参数的技术配置。\"," + }, + { + "line": 605, + "text": "tenantsSubtitle: \"全局系统概览。\"," + }, + { + "line": 607, + "text": "allNotes: \"所有笔记\"," + }, + { + "line": 608, + "text": "filterNotesPlaceholder: \"筛选笔记...\"," + }, + { + "line": 609, + "text": "startWritingPlaceholder: \"开始写作...\"," + }, + { + "line": 610, + "text": "previewHeader: \"预览\"," + }, + { + "line": 611, + "text": "noContentToPreview: \"没有可预览的内容\"," + }, + { + "line": 612, + "text": "hidePreview: \"隐藏预览\"," + }, + { + "line": 613, + "text": "showPreview: \"显示预览\"," + }, + { + "line": 614, + "text": "directoryLabel: \"目录\"," + }, + { + "line": 615, + "text": "uncategorized: \"未分类\"," + }, + { + "line": 616, + "text": "enterNamePlaceholder: \"输入名称...\"," + }, + { + "line": 617, + "text": "subFolderPlaceholder: \"子文件夹...\"," + }, + { + "line": 618, + "text": "categoryCreated: \"分类已创建\"," + }, + { + "line": 619, + "text": "failedToCreateCategory: \"创建分类失败\"," + }, + { + "line": 620, + "text": "failedToDeleteCategory: \"删除分类失败\"," + }, + { + "line": 621, + "text": "confirmDeleteCategory: \"您Confirm要删除此分类吗?\"," + }, + { + "line": 622, + "text": "kbSettingsSaved: \"检索与对话配置已保存\"," + }, + { + "line": 623, + "text": "failedToSaveSettings: \"保存设置失败\"," + }, + { + "line": 624, + "text": "actionFailed: \"操作失败\"," + }, + { + "line": 625, + "text": "userAddedToOrganization: \"用户已添加到组织\"," + }, + { + "line": 626, + "text": "featureUpdated: \"功能已更新\"," + }, + { + "line": 627, + "text": "roleTenantAdmin: \"租户管理员\"," + }, + { + "line": 628, + "text": "roleRegularUser: \"普通用户\"," + }, + { + "line": 629, + "text": "creatingRegularUser: \"正在创建普通用户\"," + }, + { + "line": 630, + "text": "editUserRole: \"修改用户角色\"," + }, + { + "line": 631, + "text": "targetRole: \"目标角色\"," + }, + { + "line": 632, + "text": "editCategory: \"编辑分类\"," + }, + { + "line": 633, + "text": "totalTenants: \"总租户数\"," + }, + { + "line": 634, + "text": "systemUsers: \"系统用户\"," + }, + { + "line": 635, + "text": "systemHealth: \"系统健康\"," + }, + { + "line": 636, + "text": "operational: \"运行正常\"," + }, + { + "line": 637, + "text": "orgManagement: \"组织管理\"," + }, + { + "line": 638, + "text": "globalTenantControl: \"全局租户控制\"," + }, + { + "line": 639, + "text": "newTenant: \"新租户\"," + }, + { + "line": 640, + "text": "domainOptional: \"域名 (可选)\"," + }, + { + "line": 641, + "text": "saveChanges: \"保存修改\"," + }, + { + "line": 642, + "text": "modelConfiguration: \"模型配置\"," + }, + { + "line": 643, + "text": "defaultLLMModel: \"默认推理模型\"," + }, + { + "line": 644, + "text": "selectLLM: \"选择 LLM\"," + }, + { + "line": 645, + "text": "selectEmbedding: \"选择 Embedding\"," + }, + { + "line": 646, + "text": "rerankModel: \"Rerank 模型\"," + }, + { + "line": 647, + "text": "none: \"无\"," + }, + { + "line": 648, + "text": "indexingChunkingConfig: \"索引与切片配置\"," + }, + { + "line": 649, + "text": "chatHyperparameters: \"聊天超参数\"," + }, + { + "line": 650, + "text": "temperature: \"随机性 (Temperature)\"," + }, + { + "line": 651, + "text": "precise: \"精确\"," + }, + { + "line": 652, + "text": "creative: \"创意\"," + }, + { + "line": 653, + "text": "maxResponseTokens: \"最大响应标识 (Max Tokens)\"," + }, + { + "line": 654, + "text": "retrievalSearchSettings: \"检索与搜索设置\"," + }, + { + "line": 655, + "text": "topK: \"召回数量 (Top K)\"," + }, + { + "line": 656, + "text": "similarityThreshold: \"相似度阈值\"," + }, + { + "line": 657, + "text": "enableHybridSearch: \"启用混合检索\"," + }, + { + "line": 658, + "text": "hybridSearchDesc: \"同时使用向量和全文检索以提高召回率\"," + }, + { + "line": 659, + "text": "hybridWeight: \"混合权重 (0.0=全文, 1.0=向量)\"," + }, + { + "line": 660, + "text": "pureText: \"纯文本\"," + }, + { + "line": 661, + "text": "pureVector: \"纯向量\"," + }, + { + "line": 662, + "text": "enableQueryExpansion: \"启用查询扩展\"," + }, + { + "line": 663, + "text": "queryExpansionDesc: \"生成多个查询变体以提高覆盖率\"," + }, + { + "line": 664, + "text": "enableHyDE: \"启用 HyDE\"," + }, + { + "line": 665, + "text": "hydeDesc: \"生成假设回答以改善语义搜索\"," + }, + { + "line": 666, + "text": "enableReranking: \"启用重排序 (Rerank)\"," + }, + { + "line": 667, + "text": "rerankingDesc: \"使用 Rerank 模型对结果进行二次排序\"," + }, + { + "line": 668, + "text": "broad: \"宽泛\"," + }, + { + "line": 669, + "text": "strict: \"严格\"," + }, + { + "line": 670, + "text": "maxInput: \"最大输入\"," + }, + { + "line": 671, + "text": "dimensions: \"维度\"," + }, + { + "line": 672, + "text": "defaultBadge: \"默认\"," + }, + { + "line": 673, + "text": "dims: \"维度: $1\"," + }, + { + "line": 674, + "text": "ctx: \"上下文: $1\"," + }, + { + "line": 676, + "text": "configured: \"已配置\"," + }, + { + "line": 677, + "text": "groupUpdated: \"分组已更新\"," + }, + { + "line": 678, + "text": "groupDeleted: \"分组已删除\"," + }, + { + "line": 679, + "text": "groupCreated: \"分组已创建\"," + }, + { + "line": 680, + "text": "navCatalog: \"目录\"," + }, + { + "line": 681, + "text": "allDocuments: \"所有文档\"," + }, + { + "line": 682, + "text": "categories: \"分类\"," + }, + { + "line": 683, + "text": "uncategorizedFiles: \"未分类文件\"," + }, + { + "line": 684, + "text": "category: \"分类\"," + }, + { + "line": 685, + "text": "statusReadyDesc: \"已索引可查询\"," + }, + { + "line": 686, + "text": "statusIndexingDesc: \"正在建立词向量索引\"," + }, + { + "line": 687, + "text": "selectCategory: \"选择分类\"," + }, + { + "line": 688, + "text": "noneUncategorized: \"无未分类文件\"," + }, + { + "line": 689, + "text": "previous: \"上一页\"," + }, + { + "line": 690, + "text": "next: \"下一页\"," + }, + { + "line": 691, + "text": "createCategory: \"创建分类\"," + }, + { + "line": 692, + "text": "categoryDesc: \"描述您的知识分类\"," + }, + { + "line": 693, + "text": "categoryName: \"分类名称\"," + }, + { + "line": 694, + "text": "createCategoryBtn: \"立即创建\"," + }, + { + "line": 695, + "text": "newGroup: \"新建分组\"," + }, + { + "line": 696, + "text": "noKnowledgeGroups: \"暂无知识库分组\"," + }, + { + "line": 697, + "text": "createGroupDesc: \"开始创建您的第一个知识库分组并上传相关文档。\"," + }, + { + "line": 698, + "text": "noDescriptionProvided: \"未提供描述\"," + }, + { + "line": 699, + "text": "browseManageFiles: \"浏览并管理该分组下的文件和笔记。\"," + }, + { + "line": 700, + "text": "filterGroupFiles: \"根据名称搜索分组内文件...\"," + }, + { + "line": 704, + "text": "agentTitle: \"智能体中心\"," + }, + { + "line": 705, + "text": "agentDesc: \"管理和运行您的 AI 助手,协助完成复杂任务。\"," + }, + { + "line": 706, + "text": "createAgent: \"创建智能体\"," + }, + { + "line": 707, + "text": "searchAgent: \"搜索智能体...\"," + }, + { + "line": 708, + "text": "statusRunning: \"运行中\"," + }, + { + "line": 709, + "text": "statusStopped: \"已停止\"," + }, + { + "line": 710, + "text": "updatedAtPrefix: \"最后更新于 \"," + }, + { + "line": 711, + "text": "btnChat: \"开始对话\"," + }, + { + "line": 714, + "text": "agent1Name: \"数据分析专家\"," + }, + { + "line": 715, + "text": "agent1Desc: \"精通 SQL 和数据可视化,能够从复杂数据中提取洞察。\"," + }, + { + "line": 716, + "text": "agent2Name: \"代码审查助手\"," + }, + { + "line": 717, + "text": "agent2Desc: \"自动检查代码质量,提供重构建议和性能优化方案。\"," + }, + { + "line": 718, + "text": "agent3Name: \"学术论文润色\"," + }, + { + "line": 719, + "text": "agent3Desc: \"专业的学术写作助手,帮助优化论文结构和语言表达。\"," + }, + { + "line": 720, + "text": "agent4Name: \"法律顾问\"," + }, + { + "line": 721, + "text": "agent4Desc: \"提供法律条文查询和基础法律建议,协助起草合同。\"," + }, + { + "line": 722, + "text": "agent5Name: \"市场研究员\"," + }, + { + "line": 723, + "text": "agent5Desc: \"分析行业趋势,生成竞争对手调研报告。\"," + }, + { + "line": 724, + "text": "agent6Name: \"系统运维专家\"," + }, + { + "line": 725, + "text": "agent6Desc: \"监控系统健康,自动处理常见告警和排障。\"," + }, + { + "line": 726, + "text": "agent7Name: \"财务审计师\"," + }, + { + "line": 727, + "text": "agent7Desc: \"自动化报表审计,识别财务风险和异常交易。\"," + }, + { + "line": 728, + "text": "agent1Time: \"2 小时前\"," + }, + { + "line": 729, + "text": "agent2Time: \"5 小时前\"," + }, + { + "line": 730, + "text": "agent3Time: \"昨天\"," + }, + { + "line": 731, + "text": "agent4Time: \"2 天前\"," + }, + { + "line": 732, + "text": "agent5Time: \"3 天前\"," + }, + { + "line": 733, + "text": "agent6Time: \"5 天前\"," + }, + { + "line": 734, + "text": "agent7Time: \"1 周前\"," + }, + { + "line": 737, + "text": "pluginTitle: \"插件中心\"," + }, + { + "line": 738, + "text": "pluginDesc: \"扩展知识库的功能,集成外部工具和服务。\"," + }, + { + "line": 739, + "text": "searchPlugin: \"搜索插件...\"," + }, + { + "line": 740, + "text": "installPlugin: \"安装插件\"," + }, + { + "line": 741, + "text": "installedPlugin: \"已安装\"," + }, + { + "line": 742, + "text": "updatePlugin: \"有更新\"," + }, + { + "line": 743, + "text": "pluginOfficial: \"官方\"," + }, + { + "line": 744, + "text": "pluginCommunity: \"社区\"," + }, + { + "line": 745, + "text": "pluginBy: \"由 \"," + }, + { + "line": 746, + "text": "pluginConfig: \"插件配置\"," + }, + { + "line": 749, + "text": "plugin1Name: \"Web 搜索\"," + }, + { + "line": 750, + "text": "plugin1Desc: \"赋予 AI 实时访问互联网的能力,获取最新信息。\"," + }, + { + "line": 751, + "text": "plugin2Name: \"PDF 文档解析\"," + }, + { + "line": 752, + "text": "plugin2Desc: \"深度解析复杂 PDF 布局,提取表格和数学公式。\"," + }, + { + "line": 753, + "text": "plugin3Name: \"GitHub 集成\"," + }, + { + "line": 754, + "text": "plugin3Desc: \"直接访问 GitHub 仓库,进行代码提交和 issue 管理。\"," + }, + { + "line": 755, + "text": "plugin4Name: \"Google 日历\"," + }, + { + "line": 756, + "text": "plugin4Desc: \"同步您的日程安排,自动创建会议提醒。\"," + }, + { + "line": 757, + "text": "plugin5Name: \"SQL 数据库连接\"," + }, + { + "line": 758, + "text": "plugin5Desc: \"安全地连接到您的数据库,执行自然语言查询。\"," + }, + { + "line": 759, + "text": "plugin6Name: \"Slack 通知\"," + }, + { + "line": 760, + "text": "plugin6Desc: \"将 AI 生成的报告直接发送到指定的 Slack 频道。\"," + }, + { + "line": 763, + "text": "addSubcategory: \"添加子分类\"," + }, + { + "line": 764, + "text": "parentCategory: \"父分类 (可选)\"," + }, + { + "line": 765, + "text": "noParentTopLevel: \"无父分类(顶级)\"," + }, + { + "line": 766, + "text": "useHierarchyImport: \"按文件夹层级创建分类\"," + }, + { + "line": 767, + "text": "useHierarchyImportDesc: \"启用后将为每个子文件夹创建对应的子分类,并将文件导入到匹配的分类中。\"," + }, + { + "line": 770, + "text": "importImmediate: \"立即导入\"," + }, + { + "line": 771, + "text": "importScheduled: \"定时导入\"," + }, + { + "line": 772, + "text": "lblServerPath: \"服务器文件夹路径\"," + }, + { + "line": 773, + "text": "placeholderServerPath: \"例如: /data/documents\"," + }, + { + "line": 774, + "text": "scheduledImportTip: \"服务器端定时导入:服务器将在指定时间读取该路径下的文件并自动导入。请确保服务器有访问该路径的权限。\"," + }, + { + "line": 775, + "text": "lblScheduledTime: \"执行时间\"," + }, + { + "line": 776, + "text": "scheduledTimeHint: \"到达指定时间后,服务器将自动执行导入任务。\"," + }, + { + "line": 777, + "text": "scheduleImport: \"创建定时任务\"," + }, + { + "line": 778, + "text": "scheduleTaskCreated: \"定时导入任务已创建\"," + }, + { + "line": 779, + "text": "fillServerPath: \"请输入服务器文件夹路径\"," + }, + { + "line": 780, + "text": "invalidDateTime: \"请输入有效的日期时间\"," + }, + { + "line": 783, + "text": "importTasksTitle: \"定时计划\"," + }, + { + "line": 784, + "text": "noTasksFound: \"暂无任务\"," + }, + { + "line": 785, + "text": "sourcePath: \"源路径\"," + }, + { + "line": 786, + "text": "targetGroup: \"目标分组\"," + }, + { + "line": 787, + "text": "scheduledAt: \"计划执行时间\"," + }, + { + "line": 788, + "text": "confirmDeleteTask: \"Confirm要删除此导入任务记录吗?\"," + }, + { + "line": 789, + "text": "deleteTaskFailed: \"删除任务记录失败\"," + }, + { + "line": 1591, + "text": "aiCommandsError: \"エラーが発生しました\"," + }, + { + "line": 1592, + "text": "appTitle: \"Gemini ナレッジベース\"," + }, + { + "line": 1593, + "text": "loginTitle: \"ログイン\"," + }, + { + "line": 1594, + "text": "loginDesc: \"システムに入るためのキーを入力してください\"," + }, + { + "line": 1595, + "text": "loginButton: \"ログイン\"," + }, + { + "line": 1596, + "text": "loginError: \"キーは必須です\"," + }, + { + "line": 1597, + "text": "unknown: \"不明\"," + }, + { + "line": 1598, + "text": "unknownError: \"未知のエラー\"," + }, + { + "line": 1599, + "text": "usernamePlaceholder: \"ユーザー名\"," + }, + { + "line": 1600, + "text": "passwordPlaceholder: \"パスワード\"," + }, + { + "line": 1601, + "text": "registerButton: \"登録\"," + }, + { + "line": 1602, + "text": "langZh: \"言語: 中国語\"," + }, + { + "line": 1603, + "text": "langEn: \"言語: 英語\"," + }, + { + "line": 1604, + "text": "langJa: \"言語: Japanese\"," + }, + { + "line": 1605, + "text": "confirm: \"確認\"," + }, + { + "line": 1606, + "text": "cancel: \"キャンセル\"," + }, + { + "line": 1607, + "text": "confirmTitle: \"操作の確認\"," + }, + { + "line": 1608, + "text": "confirmDeleteGroup: \"グループ \\\"$1\\\" を削除してもよろしいですか?\"," + }, + { + "line": 1610, + "text": "sidebarTitle: \"索引とチャットの設定\"," + }, + { + "line": 1611, + "text": "backToWorkspace: \"ワークスペースに戻る\"," + }, + { + "line": 1612, + "text": "goToAdmin: \"管理画面へ\"," + }, + { + "line": 1613, + "text": "sidebarDesc: \"ドキュメントとモデル管理\"," + }, + { + "line": 1614, + "text": "tabFiles: \"ドキュメント\"," + }, + { + "line": 1615, + "text": "files: \"ファイル\"," + }, + { + "line": 1616, + "text": "notes: \"メモ\"," + }, + { + "line": 1617, + "text": "tabSettings: \"設定\"," + }, + { + "line": 1618, + "text": "systemConfiguration: \"システム構成\"," + }, + { + "line": 1619, + "text": "noFiles: \"ファイルなし\"," + }, + { + "line": 1620, + "text": "noFilesDesc: \"PDF、Office文書、テキスト、コード、画像などをサポート\"," + }, + { + "line": 1621, + "text": "addFile: \"ファイルAdded\"," + }, + { + "line": 1622, + "text": "clearAll: \"全削除\"," + }, + { + "line": 1623, + "text": "uploading: \"処理中\"," + }, + { + "line": 1624, + "text": "statusIndexing: \"ベクトル化中...\"," + }, + { + "line": 1625, + "text": "statusReady: \"完了\"," + }, + { + "line": 1628, + "text": "ragSettings: \"RAG 設定\"," + }, + { + "line": 1629, + "text": "enableRerank: \"リランクを有効にする\"," + }, + { + "line": 1630, + "text": "enableRerankDesc: \"リランクモデルを使用してSearch resultsを再ランク付けし、精度を向上させます\"," + }, + { + "line": 1631, + "text": "selectRerankModel: \"リランクモデルの選択\"," + }, + { + "line": 1632, + "text": "selectModelPlaceholder: \"モデルを選択...\"," + }, + { + "line": 1634, + "text": "headerModelSelection: \"モデル選択\"," + }, + { + "line": 1635, + "text": "headerHyperparams: \"推論パラメータ\"," + }, + { + "line": 1636, + "text": "headerIndexing: \"インデックスと分割\"," + }, + { + "line": 1637, + "text": "headerRetrieval: \"検索とランク付け\"," + }, + { + "line": 1638, + "text": "btnManageModels: \"プロバイダー管理\"," + }, + { + "line": 1640, + "text": "lblLLM: \"推論モデル (LLM)\"," + }, + { + "line": 1641, + "text": "lblEmbedding: \"埋め込みモデル\"," + }, + { + "line": 1642, + "text": "lblRerankRef: \"リランクモデル\"," + }, + { + "line": 1643, + "text": "lblTemperature: \"温度 (Temperature)\"," + }, + { + "line": 1644, + "text": "lblMaxTokens: \"最大トークン数\"," + }, + { + "line": 1646, + "text": "lblChunkOverlap: \"オーバーラップ\"," + }, + { + "line": 1647, + "text": "lblTopK: \"検索数 (Top K)\"," + }, + { + "line": 1648, + "text": "lblRerank: \"リランク有効化\"," + }, + { + "line": 1650, + "text": "idxModalTitle: \"インデックス設定\"," + }, + { + "line": 1651, + "text": "idxDesc: \"取り込みの前に分割ルールと埋め込みモデルを設定してください。\"," + }, + { + "line": 1652, + "text": "idxFiles: \"対象ファイル\"," + }, + { + "line": 1653, + "text": "idxMethod: \"分割設定\"," + }, + { + "line": 1654, + "text": "idxEmbeddingModel: \"埋め込みモデル\"," + }, + { + "line": 1655, + "text": "idxStart: \"インデックス開始\"," + }, + { + "line": 1656, + "text": "idxCancel: \"キャンセル\"," + }, + { + "line": 1657, + "text": "idxAuto: \"自動\"," + }, + { + "line": 1658, + "text": "idxCustom: \"カスタム\"," + }, + { + "line": 1660, + "text": "mmTitle: \"モデルプロバイダー管理\"," + }, + { + "line": 1661, + "text": "mmAddBtn: \"モデルAdded\"," + }, + { + "line": 1662, + "text": "mmEdit: \"編集\"," + }, + { + "line": 1663, + "text": "mmDelete: \"削除\"," + }, + { + "line": 1664, + "text": "mmEmpty: \"設定されたモデルはありません\"," + }, + { + "line": 1665, + "text": "mmFormName: \"表示名\"," + }, + { + "line": 1666, + "text": "mmFormProvider: \"プロバイダー\"," + }, + { + "line": 1667, + "text": "mmFormModelId: \"モデルID (例: gpt-4o)\"," + }, + { + "line": 1669, + "text": "mmFormType: \"機能タイプ\"," + }, + { + "line": 1670, + "text": "mmFormVision: \"画像認識対応\"," + }, + { + "line": 1671, + "text": "mmFormDimensions: \"ベクトル次元\"," + }, + { + "line": 1672, + "text": "mmFormDimensionsHelp: \"埋め込みベクトルの次元数、一般的な値:1536、3072\"," + }, + { + "line": 1673, + "text": "mmSave: \"保存\"," + }, + { + "line": 1674, + "text": "mmCancel: \"キャンセル\"," + }, + { + "line": 1675, + "text": "mmErrorNotAuthenticated: \"認証されていません、操作できません\"," + }, + { + "line": 1676, + "text": "mmErrorTitle: \"操作失敗\"," + }, + { + "line": 1677, + "text": "modelEnabled: \"モデル有効\"," + }, + { + "line": 1678, + "text": "modelDisabled: \"モデル無効\"," + }, + { + "line": 1679, + "text": "confirmChangeEmbeddingModel: \"警告:埋め込みモデルを変更すると、既存のインデックスが検索できなくなる可能性があります。\\n変更してよろしいですか?\"," + }, + { + "line": 1680, + "text": "embeddingModelWarning: \"この設定を変更すると、ナレッジベースのクリアと再インポートが必要になる場合があります。\"," + }, + { + "line": 1681, + "text": "sourcePreview: \"引用元プレビュー\"," + }, + { + "line": 1682, + "text": "matchScore: \"一致度\"," + }, + { + "line": 1683, + "text": "copyContent: \"内容をコピー\"," + }, + { + "line": 1684, + "text": "copySuccess: \"コピーしました\"," + }, + { + "line": 1686, + "text": "// ConfigPanel 缺失の翻訳" + }, + { + "line": 1687, + "text": "selectLLMModel: \"LLMモデルを選択してください\"," + }, + { + "line": 1688, + "text": "selectEmbeddingModel: \"Embeddingモデルを選択してください\"," + }, + { + "line": 1689, + "text": "defaultForUploads: \"新しいアップロードとクエリのデフォルト\"," + }, + { + "line": 1690, + "text": "noRerankModel: \"リランクモデルなし\"," + }, + { + "line": 1691, + "text": "vectorSimilarityThreshold: \"ベクトル検索しきい値\"," + }, + { + "line": 1692, + "text": "rerankSimilarityThreshold: \"リランクしきい値\"," + }, + { + "line": 1693, + "text": "filterLowResults: \"この値を下回る結果はフィルタリングされます\"," + }, + { + "line": 1694, + "text": "noteCreatedSuccess: \"Create noteしました\"," + }, + { + "line": 1695, + "text": "noteCreatedFailed: \"ノートの作成に失敗しました\"," + }, + { + "line": 1696, + "text": "fullTextSearch: \"全文検索\"," + }, + { + "line": 1697, + "text": "hybridVectorWeight: \"ハイブリッド検索ベクトル重み\"," + }, + { + "line": 1698, + "text": "hybridVectorWeightDesc: \"重み: 1.0 = ベクトルのみ, 0.0 = キーワードのみ\"," + }, + { + "line": 1699, + "text": "lblQueryExpansion: \"クエリ拡張 (Multi-Query)\"," + }, + { + "line": 1700, + "text": "lblHyDE: \"HyDE (仮想ドキュメント埋め込み)\"," + }, + { + "line": 1701, + "text": "lblQueryExpansionDesc: \"検索カバレッジ向上のために複数のクエリを生成\"," + }, + { + "line": 1702, + "text": "lblHyDEDesc: \"セマンティック検索改善のために仮想回答を生成\"," + }, + { + "line": 1704, + "text": "apiKeyValidationFailed: \"API Key検証に失敗しました\"," + }, + { + "line": 1705, + "text": "keepOriginalKey: \"空のままにすると元のAPI Keyを保持、新しい値を入力すると置換\"," + }, + { + "line": 1706, + "text": "leaveEmptyNoChange: \"空のままで変更なし\"," + }, + { + "line": 1708, + "text": "mmFormApiKeyPlaceholder: \"API Key を入力してください\"," + }, + { + "line": 1710, + "text": "// さらに缺失している翻訳" + }, + { + "line": 1711, + "text": "reconfigureFile: \"ファイルの再設定\"," + }, + { + "line": 1712, + "text": "modifySettings: \"ファイルの分割とベクトル化設定を変更\"," + }, + { + "line": 1713, + "text": "filesCount: \"ファイル\"," + }, + { + "line": 1714, + "text": "allFilesIndexed: \"以下の設定ですべてのファイルがインデックス化されます。\"," + }, + { + "line": 1715, + "text": "noEmbeddingModels: \"埋め込みモデルが設定されていません\"," + }, + { + "line": 1716, + "text": "reconfigure: \"再設定\"," + }, + { + "line": 1717, + "text": "refresh: \"更新\"," + }, + { + "line": 1718, + "text": "settings: \"設定\"," + }, + { + "line": 1719, + "text": "needLogin: \"チャット機能を使用するにはログインが必要です\"," + }, + { + "line": 1720, + "text": "citationSources: \"引用元\"," + }, + { + "line": 1721, + "text": "chunkNumber: \"フラグメント\"," + }, + { + "line": 1722, + "text": "getUserListFailed: \"ユーザー一覧の取得に失敗しました\"," + }, + { + "line": 1723, + "text": "usernamePasswordRequired: \"ユーザー名とパスワードは必須です\"," + }, + { + "line": 1724, + "text": "passwordMinLength: \"パスワードは6文字以上で入力してください\"," + }, + { + "line": 1725, + "text": "userCreatedSuccess: \"ユーザーが作成されました\"," + }, + { + "line": 1726, + "text": "createUserFailed: \"ユーザー作成に失敗しました\"," + }, + { + "line": 1727, + "text": "userPromotedToAdmin: \"ユーザーを管理者に昇格しました\"," + }, + { + "line": 1728, + "text": "userDemotedFromAdmin: \"ユーザーを一般ユーザーに降格しました\"," + }, + { + "line": 1729, + "text": "updateUserFailed: \"ユーザー情報の更新に失敗しました\"," + }, + { + "line": 1730, + "text": "confirmDeleteUser: \"このユーザーを削除してもよろしいですか?\"," + }, + { + "line": 1731, + "text": "deleteUser: \"ユーザー削除\"," + }, + { + "line": 1732, + "text": "deleteUserFailed: \"ユーザーの削除に失敗しました\"," + }, + { + "line": 1733, + "text": "userDeletedSuccessfully: \"ユーザーを削除しました\"," + }, + { + "line": 1734, + "text": "makeUserAdmin: \"管理者にする\"," + }, + { + "line": 1735, + "text": "makeUserRegular: \"一般ユーザーにする\"," + }, + { + "line": 1736, + "text": "loading: \"読み込み中...\"," + }, + { + "line": 1737, + "text": "noUsers: \"ユーザーなし\"," + }, + { + "line": 1740, + "text": "aiAssistant: \"AI アシスタント\"," + }, + { + "line": 1741, + "text": "polishContent: \"内容を洗練\"," + }, + { + "line": 1742, + "text": "expandContent: \"展開\"," + }, + { + "line": 1743, + "text": "summarizeContent: \"要約\"," + }, + { + "line": 1744, + "text": "translateToEnglish: \"英語に翻訳\"," + }, + { + "line": 1745, + "text": "fixGrammar: \"文法修正\"," + }, + { + "line": 1746, + "text": "aiCommandInstructPolish: \"このテキストをよりプロフェッショナルで自然な表現に推敲してください。\"," + }, + { + "line": 1747, + "text": "aiCommandInstructExpand: \"このテキストに詳細をAddedして内容を充実させ、詳しく書き広げてください。\"," + }, + { + "line": 1748, + "text": "aiCommandInstructSummarize: \"このテキストの要点を抽出し、簡潔な要約を作成してください。\"," + }, + { + "line": 1749, + "text": "aiCommandInstructTranslateToEn: \"このテキストを英語に翻訳してください。\"," + }, + { + "line": 1750, + "text": "aiCommandInstructFixGrammar: \"このテキストの文法やスペルの誤りをチェックし、修正してください。\"," + }, + { + "line": 1751, + "text": "aiCommandsPreset: \"よく使うコマンド\"," + }, + { + "line": 1752, + "text": "aiCommandsCustom: \"カスタムリクエスト\"," + }, + { + "line": 1753, + "text": "aiCommandsCustomPlaceholder: \"例:この文章をより正式なものに書き直してください...\"," + }, + { + "line": 1754, + "text": "aiCommandsReferenceContext: \"参照コンテキスト (最初の200文字):\"," + }, + { + "line": 1755, + "text": "aiCommandsStartGeneration: \"生成開始\"," + }, + { + "line": 1756, + "text": "aiCommandsResult: \"AIの提案\"," + }, + { + "line": 1757, + "text": "aiCommandsGenerating: \"生成中...\"," + }, + { + "line": 1758, + "text": "aiCommandsApplyResult: \"選択範囲を置換\"," + }, + { + "line": 1759, + "text": "aiCommandsGoBack: \"戻る\"," + }, + { + "line": 1760, + "text": "aiCommandsReset: \"リセット\"," + }, + { + "line": 1761, + "text": "aiCommandsModalPreset: \"プリセットコマンドを選択\"," + }, + { + "line": 1762, + "text": "aiCommandsModalCustom: \"またはカスタムコマンドを入力\"," + }, + { + "line": 1763, + "text": "aiCommandsModalCustomPlaceholder: \"AIに何をしたいか伝えてください...\"," + }, + { + "line": 1764, + "text": "aiCommandsModalBasedOnSelection: \"選択したテキストに基づいて:\"," + }, + { + "line": 1765, + "text": "aiCommandsModalResult: \"生成結果\"," + }, + { + "line": 1766, + "text": "aiCommandsModalApply: \"結果を適用\"," + }, + { + "line": 1768, + "text": "// ChangePasswordModal と SearchResultsPanel の缺失翻訳" + }, + { + "line": 1769, + "text": "fillAllFields: \"すべてのフィールドを入力してください\"," + }, + { + "line": 1770, + "text": "passwordMismatch: \"新しいパスワードと確認パスワードが一致しません\"," + }, + { + "line": 1771, + "text": "newPasswordMinLength: \"新しいパスワードは6文字以上で入力してください\"," + }, + { + "line": 1772, + "text": "changePasswordFailed: \"パスワードの変更に失敗しました\"," + }, + { + "line": 1773, + "text": "changePasswordTitle: \"パスワード変更\"," + }, + { + "line": 1774, + "text": "changing: \"変更中...\"," + }, + { + "line": 1775, + "text": "searchResults: \"関連コンテンツが見つかりました\"," + }, + { + "line": 1777, + "text": "// VisionModelSelector の缺失翻訳" + }, + { + "line": 1778, + "text": "visionModelSettings: \"ビジョンモデル設定\"," + }, + { + "line": 1779, + "text": "defaultVisionModel: \"デフォルトビジョンモデル\"," + }, + { + "line": 1780, + "text": "loadVisionModelFailed: \"ビジョンモデルの読み込みに失敗しました\"," + }, + { + "line": 1781, + "text": "loadFailed: \"読み込みに失敗しました、ネットワーク接続を確認してください\"," + }, + { + "line": 1782, + "text": "saveVisionModelFailed: \"ビジョンモデルの保存に失敗しました\"," + }, + { + "line": 1783, + "text": "noVisionModels: \"利用可能なビジョンモデルがありません\"," + }, + { + "line": 1784, + "text": "selectVisionModel: \"ビジョンモデルを選択してください\"," + }, + { + "line": 1785, + "text": "visionModelHelp: \"画像ファイルを処理するためのビジョンモデル。利用可能なモデルがない場合は、モデル管理でAddedし、「ビジョン対応」オプションをチェックしてください。\"," + }, + { + "line": 1786, + "text": "mmErrorNameRequired: \"Model nameは必須要素です\"," + }, + { + "line": 1787, + "text": "mmErrorModelIdRequired: \"モデルIDは必須です。\"," + }, + { + "line": 1788, + "text": "mmErrorBaseUrlRequired: \"選択されたプロバイダーにはBase URLが必要です。\"," + }, + { + "line": 1791, + "text": "typeLLM: \"推論 (LLM)\"," + }, + { + "line": 1792, + "text": "typeEmbedding: \"ベクトル化 (Embedding)\"," + }, + { + "line": 1793, + "text": "typeRerank: \"リランク (Rerank)\"," + }, + { + "line": 1794, + "text": "typeVision: \"画像認識 (Vision)\"," + }, + { + "line": 1796, + "text": "welcome: \"こんにちは!設定でモデルを選択し、ドキュメントをアップロードして質問を開始してください。\"," + }, + { + "line": 1797, + "text": "placeholderWithFiles: \"ナレッジベースについて質問...\"," + }, + { + "line": 1798, + "text": "placeholderEmpty: \"開始するにはファイルをアップロード...\"," + }, + { + "line": 1799, + "text": "analyzing: \"検索して生成中...\"," + }, + { + "line": 1800, + "text": "errorGeneric: \"エラーが発生しました。\"," + }, + { + "line": 1801, + "text": "errorLabel: \"エラー\"," + }, + { + "line": 1802, + "text": "errorNoModel: \"モデルが選択されていないか、設定が無効です。\"," + }, + { + "line": 1803, + "text": "aiDisclaimer: \"AIは間違いを犯す可能性があります。\"," + }, + { + "line": 1804, + "text": "confirmClear: \"すべてのファイルを削除しますか?\"," + }, + { + "line": 1805, + "text": "removeFile: \"ファイルを削除\"," + }, + { + "line": 1806, + "text": "apiError: \"設定が不足しているか、APIキーが有効ではありません。\"," + }, + { + "line": 1808, + "text": "processedButNoText: \"応答を生成できませんでした。\"," + }, + { + "line": 1809, + "text": "unitByte: \"バイト\"," + }, + { + "line": 1810, + "text": "readingFailed: \"読み込み失敗\"," + }, + { + "line": 1812, + "text": "copy: \"コピー\"," + }, + { + "line": 1813, + "text": "copied: \"コピーしました\"," + }, + { + "line": 1816, + "text": "logout: \"ログアウト\"," + }, + { + "line": 1817, + "text": "changePassword: \"パスワード変更\"," + }, + { + "line": 1818, + "text": "userManagement: \"ユーザー管理\"," + }, + { + "line": 1819, + "text": "userList: \"ユーザー一覧\"," + }, + { + "line": 1820, + "text": "addUser: \"ユーザーAdded\"," + }, + { + "line": 1821, + "text": "username: \"ユーザー名\"," + }, + { + "line": 1822, + "text": "password: \"パスワード\"," + }, + { + "line": 1823, + "text": "confirmPassword: \"パスワード確認\"," + }, + { + "line": 1824, + "text": "currentPassword: \"現在のパスワード\"," + }, + { + "line": 1825, + "text": "newPassword: \"新しいパスワード\"," + }, + { + "line": 1826, + "text": "createUser: \"ユーザー作成\"," + }, + { + "line": 1827, + "text": "admin: \"管理者\"," + }, + { + "line": 1828, + "text": "user: \"ユーザー\"," + }, + { + "line": 1829, + "text": "adminUser: \"管理者として設定\"," + }, + { + "line": 1830, + "text": "confirmChange: \"変更を確定\"," + }, + { + "line": 1831, + "text": "changeUserPassword: \"ユーザーのパスワードを変更\"," + }, + { + "line": 1832, + "text": "enterNewPassword: \"新しいパスワードを入力してください\"," + }, + { + "line": 1833, + "text": "createdAt: \"作成日時\"," + }, + { + "line": 1834, + "text": "newChat: \"新しい会話\"," + }, + { + "line": 1837, + "text": "kbManagement: \"ナレッジベース管理\"," + }, + { + "line": 1838, + "text": "kbManagementDesc: \"ドキュメントとナレッジグループの管理\"," + }, + { + "line": 1839, + "text": "searchPlaceholder: \"ファイル名を検索...\"," + }, + { + "line": 1840, + "text": "allGroups: \"すべてのグループ\"," + }, + { + "line": 1841, + "text": "allStatus: \"すべてのステータス\"," + }, + { + "line": 1842, + "text": "statusReadyFragment: \"完了\"," + }, + { + "line": 1843, + "text": "statusFailedFragment: \"失敗\"," + }, + { + "line": 1844, + "text": "statusIndexingFragment: \"インデックス中\"," + }, + { + "line": 1845, + "text": "uploadFile: \"ファイルをアップロード\"," + }, + { + "line": 1846, + "text": "fileName: \"ファイル名\"," + }, + { + "line": 1847, + "text": "size: \"サイズ\"," + }, + { + "line": 1848, + "text": "status: \"ステータス\"," + }, + { + "line": 1849, + "text": "groups: \"グループ\"," + }, + { + "line": 1850, + "text": "actions: \"アクション\"," + }, + { + "line": 1851, + "text": "groupsActions: \"グループ / アクション\"," + }, + { + "line": 1852, + "text": "noFilesFound: \"ファイルが見つかりません\"," + }, + { + "line": 1853, + "text": "showingRange: \"$3 件中 $1 - $2 を表示\"," + }, + { + "line": 1854, + "text": "confirmDeleteFile: \"このファイルを削除してもよろしいですか?\"," + }, + { + "line": 1855, + "text": "fileDeleted: \"ファイルを削除しました\"," + }, + { + "line": 1856, + "text": "deleteFailed: \"削除に失敗しました\"," + }, + { + "line": 1857, + "text": "fileAddedToGroup: \"ファイルがグループにAddedされました\"," + }, + { + "line": 1858, + "text": "failedToAddToGroup: \"グループへのAddedに失敗しました\"," + }, + { + "line": 1859, + "text": "fileRemovedFromGroup: \"ファイルがグループから削除されました\"," + }, + { + "line": 1860, + "text": "failedToRemoveFromGroup: \"グループからの削除に失敗しました\"," + }, + { + "line": 1861, + "text": "confirmClearKB: \"警告:これによりすべてのファイルとインデックスが完全に削除されます。\\n\\n本当にナレッジベースをクリアしますか?\"," + }, + { + "line": 1862, + "text": "kbCleared: \"ナレッジベースをクリアしました\"," + }, + { + "line": 1863, + "text": "clearFailed: \"クリアに失敗しました\"," + }, + { + "line": 1864, + "text": "loginRequired: \"先にログインしてください\"," + }, + { + "line": 1865, + "text": "uploadErrors: \"以下のファイルはアップロードできませんでした\"," + }, + { + "line": 1866, + "text": "uploadWarning: \"$1 つのファイルがアップロード準備完了、$2 つがフィルタリングされました\"," + }, + { + "line": 1867, + "text": "uploadFailed: \"アップロードに失敗しました\"," + }, + { + "line": 1868, + "text": "preview: \"プレビュー\"," + }, + { + "line": 1869, + "text": "addGroup: \"グループAdded\"," + }, + { + "line": 1870, + "text": "delete: \"削除\"," + }, + { + "line": 1871, + "text": "retry: \"再試行\"," + }, + { + "line": 1872, + "text": "retrying: \"再試行中...\"," + }, + { + "line": 1873, + "text": "retrySuccess: \"再試行成功\"," + }, + { + "line": 1874, + "text": "retryFailed: \"再試行失敗\"," + }, + { + "line": 1875, + "text": "chunkInfo: \"チャンク情報\"," + }, + { + "line": 1876, + "text": "totalChunks: \"総チャンク数\"," + }, + { + "line": 1877, + "text": "chunkIndex: \"チャンク\"," + }, + { + "line": 1878, + "text": "contentLength: \"文字\"," + }, + { + "line": 1879, + "text": "position: \"位置\"," + }, + { + "line": 1882, + "text": "reconfigureTitle: \"ファイルの再設定\"," + }, + { + "line": 1883, + "text": "reconfigureDesc: \"ファイル処理設定を変更\"," + }, + { + "line": 1884, + "text": "indexingConfigTitle: \"ドキュメントインデックス設定\"," + }, + { + "line": 1885, + "text": "indexingConfigDesc: \"ドキュメント処理オプションとモードを設定\"," + }, + { + "line": 1886, + "text": "pendingFiles: \"待機中のファイル\"," + }, + { + "line": 1887, + "text": "processingMode: \"処理モード\"," + }, + { + "line": 1889, + "text": "recommendationReason: \"理由\"," + }, + { + "line": 1891, + "text": "fastModeDesc: \"単純なテキスト抽出、Fast、No additional cost、純粋なテキストに適しています\"," + }, + { + "line": 1893, + "text": "preciseModeDesc: \"精密なレイアウト分析、表/画像を保持、APIコストがかかります\"," + }, + { + "line": 1894, + "text": "fastModeFeatures: \"Fast Modeの特徴:\"," + }, + { + "line": 1895, + "text": "fastFeature1: \"単純なテキスト抽出\"," + }, + { + "line": 1896, + "text": "fastFeature2: \"Fastな処理速度\"," + }, + { + "line": 1898, + "text": "fastFeature4: \"テキストのみ処理\"," + }, + { + "line": 1899, + "text": "fastFeature5: \"プレーンテキストに適しています\"," + }, + { + "line": 1900, + "text": "preciseModeFeatures: \"Precise Modeの特徴:\"," + }, + { + "line": 1901, + "text": "preciseFeature1: \"精密な構造認識\"," + }, + { + "line": 1902, + "text": "preciseFeature2: \"画像/表/チャートを認識\"," + }, + { + "line": 1903, + "text": "preciseFeature3: \"混合コンテンツを保持\"," + }, + { + "line": 1905, + "text": "preciseFeature5: \"APIコストが必要\"," + }, + { + "line": 1906, + "text": "preciseFeature6: \"処理時間が長くなります\"," + }, + { + "line": 1907, + "text": "embeddingModel: \"埋め込みモデル\"," + }, + { + "line": 1908, + "text": "pleaseSelect: \"選択してください...\"," + }, + { + "line": 1909, + "text": "pleaseSelectKnowledgeGroupFirst: \"保存する前に知識グループを選択してください\"," + }, + { + "line": 1910, + "text": "selectUnassignGroupWarning: \"ナレッジグループの割り当てを解除する場合は、この操作を確認してください\"," + }, + { + "line": 1912, + "text": "chunkSize: \"Chunk size (トークン)\"," + }, + { + "line": 1913, + "text": "min: \"最小\"," + }, + { + "line": 1914, + "text": "max: \"最大\"," + }, + { + "line": 1915, + "text": "chunkOverlap: \"オーバーラップ (トークン)\"," + }, + { + "line": 1916, + "text": "modelLimitsInfo: \"モデル制限情報\"," + }, + { + "line": 1917, + "text": "model: \"モデル\"," + }, + { + "line": 1918, + "text": "maxChunkSize: \"最大チャンク\"," + }, + { + "line": 1919, + "text": "maxOverlapSize: \"最大オーバーラップ\"," + }, + { + "line": 1920, + "text": "maxBatchSize: \"最大バッチ\"," + }, + { + "line": 1921, + "text": "envLimitWeaker: \"環境制限の方が厳しいです\"," + }, + { + "line": 1922, + "text": "optimizationTips: \"最適化のヒント\"," + }, + { + "line": 1923, + "text": "tipChunkTooLarge: \"Chunk sizeが大きいと検索精度に影響する可能性があります\"," + }, + { + "line": 1924, + "text": "tipOverlapSmall: \"オーバーラップは少なくとも $1 トークンを推奨します\"," + }, + { + "line": 1925, + "text": "tipMaxValues: \"最大値を使用すると処理が遅くなる可能性があります\"," + }, + { + "line": 1926, + "text": "tipPreciseCost: \"Precise ModeはAPIコストが発生します。予算を確認してください\"," + }, + { + "line": 1927, + "text": "selectEmbeddingFirst: \"先に埋め込みモデルを選択してください\"," + }, + { + "line": 1928, + "text": "confirmPreciseCost: \"Precise ModeはAPIコストが発生します。続けますか?\"," + }, + { + "line": 1929, + "text": "startProcessing: \"処理開始\"," + }, + { + "line": 1932, + "text": "notebooks: \"ナレッジグループ\"," + }, + { + "line": 1933, + "text": "notebooksDesc: \"研究プロジェクトやナレッジコレクションを管理\"," + }, + { + "line": 1934, + "text": "createNotebook: \"新しいナレッジグループ\"," + }, + { + "line": 1935, + "text": "chatWithNotebook: \"このグループとチャット\"," + }, + { + "line": 1936, + "text": "editNotebook: \"グループを編集\"," + }, + { + "line": 1937, + "text": "deleteNotebook: \"Delete group (ファイルを含む)\"," + }, + { + "line": 1938, + "text": "noDescription: \"説明なし\"," + }, + { + "line": 1939, + "text": "hasIntro: \"紹介あり\"," + }, + { + "line": 1940, + "text": "noIntro: \"紹介なし\"," + }, + { + "line": 1941, + "text": "noNotebooks: \"ナレッジグループはまだありません。右上の作成ボタンをクリックしてください\"," + }, + { + "line": 1942, + "text": "createFailed: \"作成に失敗しました\"," + }, + { + "line": 1943, + "text": "confirmDeleteNotebook: \"知識グループ \\\"$1\\\" を削除してもよろしいですか?\\n\\n注意:これにより、この知識グループ内のすべてのファイルとそのインデックスデータも完全に削除されます!\"," + }, + { + "line": 1946, + "text": "errorFileTooLarge: \"ファイルサイズが大きすぎます (20MB以下)\"," + }, + { + "line": 1947, + "text": "noFilesYet: \"ファイルがありません\"," + }, + { + "line": 1950, + "text": "createNotebookTitle: \"新しいナレッジグループ\"," + }, + { + "line": 1951, + "text": "editNotebookTitle: \"ナレッジグループを編集\"," + }, + { + "line": 1952, + "text": "createFailedRetry: \"作成に失敗しました。再試行してください\"," + }, + { + "line": 1953, + "text": "updateFailedRetry: \"更新に失敗しました。再試行してください\"," + }, + { + "line": 1954, + "text": "name: \"名前\"," + }, + { + "line": 1955, + "text": "nameHelp: \"明確な名前を付けると見つけやすくなります。\"," + }, + { + "line": 1956, + "text": "namePlaceholder: \"例: 量子物理学研究...\"," + }, + { + "line": 1957, + "text": "shortDescription: \"短い説明\"," + }, + { + "line": 1958, + "text": "descPlaceholder: \"このグループの目的を一文で説明\"," + }, + { + "line": 1959, + "text": "detailedIntro: \"詳細な紹介\"," + }, + { + "line": 1960, + "text": "introPlaceholder: \"ここの段落は、Q&Aのコンテキストに含まれる可能性があります。このグループの主要なトピック、背景知識、または目標をできるだけ詳しく説明してください。\"," + }, + { + "line": 1961, + "text": "introHelp: \"この紹介は、会話のAddedコンテキストとして使用されます。\"," + }, + { + "line": 1962, + "text": "creating: \"作成中...\"," + }, + { + "line": 1963, + "text": "createNow: \"今すぐ作成\"," + }, + { + "line": 1964, + "text": "saving: \"保存中...\"," + }, + { + "line": 1965, + "text": "save: \"保存\"," + }, + { + "line": 1968, + "text": "chatTitle: \"ナレッジベースチャット\"," + }, + { + "line": 1969, + "text": "chatDesc: \"ナレッジベースとのスマートな会話\"," + }, + { + "line": 1970, + "text": "viewHistory: \"チャット履歴を表示\"," + }, + { + "line": 1971, + "text": "saveSettingsFailed: \"設定の保存に失敗しました\"," + }, + { + "line": 1972, + "text": "loginToUpload: \"アップロードするにはログインしてください\"," + }, + { + "line": 1973, + "text": "fileSizeLimitExceeded: \"$1 ($2 - $3MB の制限)\"," + }, + { + "line": 1974, + "text": "unsupportedFileType: \"$1 - サポートされていないファイルタイプ ($2)\"," + }, + { + "line": 1975, + "text": "readFailed: \"$1 - 読み込みに失敗しました\"," + }, + { + "line": 1976, + "text": "loadHistoryFailed: \"履歴の読み込みに失敗しました\"," + }, + { + "line": 1977, + "text": "loadingUserData: \"ユーザーデータを読み込み中...\"," + }, + { + "line": 1978, + "text": "errorMessage: \"エラー: $1\"," + }, + { + "line": 1979, + "text": "welcomeMessage: \"こんにちは!私はあなたのAIナレッジベースアシスタントです。チャットを開始するにはナレッジグループを選択してください。\"," + }, + { + "line": 1980, + "text": "selectKnowledgeGroup: \"ナレッジグループを選択\"," + }, + { + "line": 1981, + "text": "allKnowledgeGroups: \"すべてのナレッジグループ\"," + }, + { + "line": 1982, + "text": "unknownGroup: \"不明なグループ\"," + }, + { + "line": 1983, + "text": "selectedGroupsCount: \"$1 グループ選択済み\"," + }, + { + "line": 1986, + "text": "generalSettings: \"一般設定\"," + }, + { + "line": 1987, + "text": "modelManagement: \"モデル管理\"," + }, + { + "line": 1988, + "text": "languageSettings: \"言語設定\"," + }, + { + "line": 1989, + "text": "passwordChangeSuccess: \"パスワードを変更しました\"," + }, + { + "line": 1990, + "text": "passwordChangeFailed: \"パスワードの変更に失敗しました\"," + }, + { + "line": 1991, + "text": "create: \"作成\"," + }, + { + "line": 1995, + "text": "navChat: \"チャット\"," + }, + { + "line": 1996, + "text": "navCoach: \"コーチ\"," + }, + { + "line": 1997, + "text": "navKnowledge: \"ナレッジベース\"," + }, + { + "line": 1998, + "text": "navKnowledgeGroups: \"ナレッジグループ\"," + }, + { + "line": 1999, + "text": "navNotebook: \"ノートブック\"," + }, + { + "line": 2000, + "text": "navAgent: \"エージェント\"," + }, + { + "line": 2001, + "text": "navPlugin: \"プラグイン\"," + }, + { + "line": 2002, + "text": "navCrawler: \"リソース取得\"," + }, + { + "line": 2003, + "text": "expandMenu: \"メニューを展開\"," + }, + { + "line": 2004, + "text": "switchLanguage: \"言語を切り替える\"," + }, + { + "line": 2007, + "text": "selectKnowledgeGroups: \"ナレッジグループを選択\"," + }, + { + "line": 2008, + "text": "searchGroupsPlaceholder: \"グループを検索...\"," + }, + { + "line": 2009, + "text": "done: \"完了\"," + }, + { + "line": 2010, + "text": "all: \"すべて\"," + }, + { + "line": 2011, + "text": "noGroupsFound: \"関連するグループが見つかりません\"," + }, + { + "line": 2012, + "text": "noGroups: \"グループなし\"," + }, + { + "line": 2015, + "text": "autoRefresh: \"自動更新\"," + }, + { + "line": 2016, + "text": "refreshInterval: \"更新間隔\"," + }, + { + "line": 2019, + "text": "errorRenderFlowchart: \"フローチャートを生成できません\"," + }, + { + "line": 2020, + "text": "errorLoadData: \"データの読み込みに失敗しました\"," + }, + { + "line": 2021, + "text": "confirmUnsupportedFile: \"拡張子 .$1 はサポートされていない可能性があります。続行しますか?\"," + }, + { + "line": 2022, + "text": "errorReadFile: \"ファイルの読み込みに失敗しました: $1\"," + }, + { + "line": 2023, + "text": "successUploadFile: \"ファイルのアップロードと関連付けに成功しました\"," + }, + { + "line": 2024, + "text": "errorUploadFile: \"アップロードに失敗しました: $1\"," + }, + { + "line": 2025, + "text": "errorProcessFile: \"ファイルの処理に失敗しました\"," + }, + { + "line": 2026, + "text": "errorTitleContentRequired: \"タイトルと内容は必須です\"," + }, + { + "line": 2027, + "text": "successNoteUpdated: \"メモを更新しました\"," + }, + { + "line": 2028, + "text": "successNoteCreated: \"メモを作成しました\"," + }, + { + "line": 2029, + "text": "errorSaveFailed: \"保存に失敗しました: $1\"," + }, + { + "line": 2030, + "text": "confirmDeleteNote: \"このメモを削除してもよろしいですか?\"," + }, + { + "line": 2031, + "text": "successNoteDeleted: \"メモを削除しました\"," + }, + { + "line": 2032, + "text": "confirmRemoveFileFromGroup: \"ファイル「$1」をこのグループから削除しますか?(ナレッジベースには残ります)\"," + }, + { + "line": 2033, + "text": "editNote: \"メモを編集\"," + }, + { + "line": 2034, + "text": "newNote: \"新規メモ\"," + }, + { + "line": 2035, + "text": "togglePreviewOpen: \"プレビューを表示\"," + }, + { + "line": 2036, + "text": "togglePreviewClose: \"プレビューを閉じる\"," + }, + { + "line": 2037, + "text": "noteTitlePlaceholder: \"メモのタイトル\"," + }, + { + "line": 2038, + "text": "noteContentPlaceholder: \"書き始める (Markdown 対応)...\"," + }, + { + "line": 2039, + "text": "markdownPreviewArea: \"Markdown プレビューエリア\"," + }, + { + "line": 2040, + "text": "back: \"戻る\"," + }, + { + "line": 2041, + "text": "chatWithGroup: \"このグループとチャット\"," + }, + { + "line": 2042, + "text": "chatWithFile: \"このファイルとチャット\"," + }, + { + "line": 2043, + "text": "filesCountLabel: \"ファイル ($1)\"," + }, + { + "line": 2044, + "text": "notesCountLabel: \"メモ ($1)\"," + }, + { + "line": 2045, + "text": "indexIntoKB: \"インデックスに登録\"," + }, + { + "line": 2046, + "text": "noFilesOrNotes: \"$1がありません\"," + }, + { + "line": 2047, + "text": "importFolder: \"フォルダをインポート\"," + }, + { + "line": 2051, + "text": "screenshotPreview: \"スクリーンショットプレビュー\"," + }, + { + "line": 2052, + "text": "associateKnowledgeGroup: \"ナレッジグループに関連付ける\"," + }, + { + "line": 2053, + "text": "globalNoSpecificGroup: \"全体 (特定のグループなし)\"," + }, + { + "line": 2054, + "text": "title: \"タイトル\"," + }, + { + "line": 2055, + "text": "enterNoteTitle: \"ノートのタイトルを入力\"," + }, + { + "line": 2056, + "text": "contentOCR: \"内容 (OCR抽出されたテキスト)\"," + }, + { + "line": 2057, + "text": "extractingText: \"テキストを抽出中...\"," + }, + { + "line": 2058, + "text": "analyzingImage: \"画像を分析してテキストを抽出中...\"," + }, + { + "line": 2059, + "text": "noTextExtracted: \"テキストが抽出されませんでした\"," + }, + { + "line": 2060, + "text": "saveNote: \"ノートを保存\"," + }, + { + "line": 2063, + "text": "page: \"ページ\"," + }, + { + "line": 2064, + "text": "placeholderText: \"OCR抽出されたテキストがここに表示されます。編集できます...\"," + }, + { + "line": 2067, + "text": "createNewNotebook: \"新しいナレッジグループ\"," + }, + { + "line": 2068, + "text": "nameField: \"名前\"," + }, + { + "line": 2070, + "text": "exampleResearch: \"例: 量子物理学研究...\"," + }, + { + "line": 2071, + "text": "shortDescriptionField: \"簡単な説明\"," + }, + { + "line": 2072, + "text": "describePurpose: \"このグループの目的を一文で説明してください\"," + }, + { + "line": 2073, + "text": "detailedIntroField: \"詳細な紹介\"," + }, + { + "line": 2074, + "text": "provideBackgroundInfo: \"詳細な背景、目標、またはコンテキスト情報を提供してください...\"," + }, + { + "line": 2075, + "text": "creationFailed: \"作成に失敗しました。もう一度お試しください\"," + }, + { + "line": 2078, + "text": "preparingPDFConversion: \"PDF変換を準備中...\"," + }, + { + "line": 2079, + "text": "pleaseWait: \"しばらくお待ちください。これには数分かかる場合があります\"," + }, + { + "line": 2080, + "text": "convertingPDF: \"PDFを変換中...\"," + }, + { + "line": 2081, + "text": "pdfConversionFailed: \"PDF変換に失敗しました\"," + }, + { + "line": 2082, + "text": "pdfConversionError: \"このファイルをPDF形式に変換できません。ファイルが破損していないか、サポートされていない形式でないか確認してください\"," + }, + { + "line": 2083, + "text": "pdfLoadFailed: \"PDF読み込みに失敗しました\"," + }, + { + "line": 2084, + "text": "pdfLoadError: \"ブラウザでPDFを表示できません。ダウンロードするか、新しいウィンドウで開いてみてください\"," + }, + { + "line": 2085, + "text": "downloadingPDF: \"PDFをダウンロード中...\"," + }, + { + "line": 2086, + "text": "loadingPDF: \"PDFを読み込み中...\"," + }, + { + "line": 2087, + "text": "zoomOut: \"ズームアウト\"," + }, + { + "line": 2088, + "text": "zoomIn: \"ズームイン\"," + }, + { + "line": 2089, + "text": "resetZoom: \"ズームをリセット\"," + }, + { + "line": 2090, + "text": "selectPageNumber: \"Page numberを選択:\"," + }, + { + "line": 2091, + "text": "enterPageNumber: \"選択したいPage numberを入力してください\"," + }, + { + "line": 2092, + "text": "exitSelectionMode: \"選択モードを終了\"," + }, + { + "line": 2093, + "text": "clickToSelectAndNote: \"クリックして領域を選択し、メモを取る\"," + }, + { + "line": 2094, + "text": "regeneratePDF: \"PDFを再生成\"," + }, + { + "line": 2095, + "text": "downloadPDF: \"PDFをダウンロード\"," + }, + { + "line": 2096, + "text": "openInNewWindow: \"新しいウィンドウで開く\"," + }, + { + "line": 2097, + "text": "exitFullscreen: \"全画面表示を終了\"," + }, + { + "line": 2098, + "text": "fullscreenDisplay: \"全画面表示\"," + }, + { + "line": 2099, + "text": "pdfPreview: \"PDFプレビュー\"," + }, + { + "line": 2100, + "text": "converting: \"変換中...\"," + }, + { + "line": 2101, + "text": "generatePDFPreview: \"PDFプレビューを生成\"," + }, + { + "line": 2102, + "text": "previewNotSupported: \"この形式はプレビューをサポートしていません\"," + }, + { + "line": 2105, + "text": "confirmRegeneratePDF: \"PDFを再生成してもよろしいですか?これにより現在のプレビューファイルが上書きされます。\"," + }, + { + "line": 2108, + "text": "pdfPreviewReady: \"PDFプレビュー\"," + }, + { + "line": 2109, + "text": "convertingInProgress: \"変換中...\"," + }, + { + "line": 2110, + "text": "conversionFailed: \"変換失敗\"," + }, + { + "line": 2111, + "text": "generatePDFPreviewButton: \"PDFプレビューを生成\"," + }, + { + "line": 2114, + "text": "checkPDFStatusFailed: \"PDFステータスの確認に失敗しました\"," + }, + { + "line": 2115, + "text": "requestRegenerationFailed: \"再生成要求に失敗しました\"," + }, + { + "line": 2116, + "text": "downloadPDFFailed: \"PDFのダウンロードに失敗しました\"," + }, + { + "line": 2117, + "text": "openPDFInNewTabFailed: \"新しいウィンドウでのPDFオープンに失敗しました\"," + }, + { + "line": 2120, + "text": "invalidFile: \"無効なファイル\"," + }, + { + "line": 2121, + "text": "incompleteFileInfo: \"ファイル情報が不完全です。Fast Modeを使用します\"," + }, + { + "line": 2122, + "text": "unsupportedFileFormat: \"サポートされていない形式: .$1\"," + }, + { + "line": 2123, + "text": "willUseFastMode: \"Fast Mode(テキスト抽出のみ)を使用します\"," + }, + { + "line": 2124, + "text": "formatNoPrecise: \"形式 .$1 はPrecise Modeをサポートしていません\"," + }, + { + "line": 2125, + "text": "smallFileFastOk: \"ファイルサイズが小さいため、Fast Modeで十分です\"," + }, + { + "line": 2126, + "text": "mixedContentPreciseRecommended: \"図表などが含まれるため、Precise Modeを推奨します\"," + }, + { + "line": 2127, + "text": "willIncurApiCost: \"APIコストが発生します\"," + }, + { + "line": 2128, + "text": "largeFilePreciseRecommended: \"大きなファイルです。構造保持のためPrecise Modeを推奨します\"," + }, + { + "line": 2129, + "text": "longProcessingTime: \"処理に時間がかかる可能性があります\"," + }, + { + "line": 2130, + "text": "highApiCost: \"高いAPIコストが発生します\"," + }, + { + "line": 2131, + "text": "considerFileSplitting: \"ファイルの分割を検討してください\"," + }, + { + "line": 2134, + "text": "dragDropUploadTitle: \"File to uploadをドラッグ&ドロップ\"," + }, + { + "line": 2135, + "text": "dragDropUploadDesc: \"または下のボタンをクリックしてファイルを選択\"," + }, + { + "line": 2136, + "text": "supportedFormats: \"対応フォーマット\"," + }, + { + "line": 2137, + "text": "browseFiles: \"ファイルを参照\"," + }, + { + "line": 2140, + "text": "recommendationMsg: \"$1モードを推奨します: $2\"," + }, + { + "line": 2141, + "text": "autoAdjustChunk: \"Chunk sizeを上限の $1 に調整しました\"," + }, + { + "line": 2142, + "text": "autoAdjustOverlap: \"重なりサイズを上限の $1 に調整しました\"," + }, + { + "line": 2143, + "text": "autoAdjustOverlapMin: \"重なりサイズを最小値の $1 に調整しました\"," + }, + { + "line": 2144, + "text": "loadLimitsFailed: \"モデル制限の読み込みに失敗しました。デフォルト設定を使用します\"," + }, + { + "line": 2145, + "text": "maxValueMsg: \"最大値は $1 です\"," + }, + { + "line": 2146, + "text": "overlapRatioLimit: \"切片サイズの50% ($1) を超えることはできません\"," + }, + { + "line": 2147, + "text": "onlyAdminCanModify: \"システム設定は管理者のみ変更可能です\"," + }, + { + "line": 2148, + "text": "dragToSelect: \"マウスをドラッグして範囲を選択 • ESCでキャンセル\"," + }, + { + "line": 2151, + "text": "fillTargetName: \"対象のナレッジグループ名を入力してください\"," + }, + { + "line": 2152, + "text": "submitFailed: \"送信に失敗しました: $1\"," + }, + { + "line": 2153, + "text": "importFolderTitle: \"ローカルフォルダをインポート\"," + }, + { + "line": 2154, + "text": "importFolderTip: \"ヒント: ローカルフォルダを選択してください。フォルダ内のすべてのサポートされているドキュメントが読み込まれ、アップロードされます。\"," + }, + { + "line": 2155, + "text": "lblTargetGroup: \"対象のナレッジグループ名\"," + }, + { + "line": 2156, + "text": "placeholderNewGroup: \"新規グループ名\"," + }, + { + "line": 2157, + "text": "importToCurrentGroup: \"現在のグループにインポートされます\"," + }, + { + "line": 2158, + "text": "nextStep: \"次へ\"," + }, + { + "line": 2159, + "text": "lblImportSource: \"インポート元\"," + }, + { + "line": 2160, + "text": "serverPath: \"サーバーのパス\"," + }, + { + "line": 2161, + "text": "localFolder: \"ローカルフォルダ\"," + }, + { + "line": 2162, + "text": "selectedFilesCount: \"$1 個のファイルが選択されました\"," + }, + { + "line": 2163, + "text": "clickToSelectFolder: \"クリックしてローカルフォルダを選択\"," + }, + { + "line": 2164, + "text": "selectFolderTip: \"フォルダ内のすべてのサポートされているファイルを読み込みます\"," + }, + { + "line": 2165, + "text": "importComplete: \"インポート完了\"," + }, + { + "line": 2166, + "text": "importedFromLocalFolder: \"ローカルフォルダからインポート: $1\"," + }, + { + "line": 2169, + "text": "historyTitle: \"会話履歴\"," + }, + { + "line": 2170, + "text": "confirmDeleteHistory: \"この会話履歴を削除してもよろしいですか?\"," + }, + { + "line": 2171, + "text": "deleteHistorySuccess: \"会話履歴を削除しました\"," + }, + { + "line": 2172, + "text": "deleteHistoryFailed: \"会話履歴の削除に失敗しました\"," + }, + { + "line": 2173, + "text": "yesterday: \"昨日\"," + }, + { + "line": 2174, + "text": "daysAgo: \"$1日前\"," + }, + { + "line": 2175, + "text": "historyMessages: \"$1 件のメッセージ\"," + }, + { + "line": 2176, + "text": "noHistory: \"会話履歴はありません\"," + }, + { + "line": 2177, + "text": "noHistoryDesc: \"会話を開始して履歴を作成してください\"," + }, + { + "line": 2178, + "text": "loadMore: \"もっと読み込む\"," + }, + { + "line": 2179, + "text": "loadingHistoriesFailed: \"履歴の読み込みに失敗しました\"," + }, + { + "line": 2180, + "text": "supportedFormatsInfo: \"ドキュメント、画像、ソースコードをサポート\"," + }, + { + "line": 2181, + "text": "kbSettingsSaved: \"設定を保存しました\"," + }, + { + "line": 2182, + "text": "failedToSaveSettings: \"設定の保存に失敗しました\"," + }, + { + "line": 2183, + "text": "actionFailed: \"操作に失敗しました\"," + }, + { + "line": 2184, + "text": "userAddedToOrganization: \"ユーザーが組織にAddedされました\"," + }, + { + "line": 2185, + "text": "featureUpdated: \"機能が更新されました\"," + }, + { + "line": 2186, + "text": "roleTenantAdmin: \"テナント管理者\"," + }, + { + "line": 2187, + "text": "roleRegularUser: \"一般ユーザー\"," + }, + { + "line": 2188, + "text": "creatingRegularUser: \"一般ユーザーを作成中\"," + }, + { + "line": 2189, + "text": "editUserRole: \"ユーザーロールを編集\"," + }, + { + "line": 2190, + "text": "targetRole: \"対象のロール\"," + }, + { + "line": 2191, + "text": "editCategory: \"カテゴリを編集\"," + }, + { + "line": 2192, + "text": "totalTenants: \"総テナント数\"," + }, + { + "line": 2193, + "text": "systemUsers: \"システムユーザー\"," + }, + { + "line": 2194, + "text": "systemHealth: \"システムヘルス\"," + }, + { + "line": 2195, + "text": "operational: \"正常稼働中\"," + }, + { + "line": 2196, + "text": "orgManagement: \"組織管理\"," + }, + { + "line": 2197, + "text": "globalTenantControl: \"グローバルテナントコントロール\"," + }, + { + "line": 2198, + "text": "newTenant: \"新規テナント\"," + }, + { + "line": 2199, + "text": "domainOptional: \"ドメイン (任意)\"," + }, + { + "line": 2200, + "text": "saveChanges: \"変更を保存\"," + }, + { + "line": 2201, + "text": "modelConfiguration: \"モデル設定\"," + }, + { + "line": 2202, + "text": "defaultLLMModel: \"デフォルト推論モデル\"," + }, + { + "line": 2203, + "text": "selectLLM: \"LLMを選択\"," + }, + { + "line": 2204, + "text": "selectEmbedding: \"埋め込みを選択\"," + }, + { + "line": 2205, + "text": "rerankModel: \"リランクモデル\"," + }, + { + "line": 2206, + "text": "none: \"なし\"," + }, + { + "line": 2207, + "text": "indexingChunkingConfig: \"インデックスとChunk configuration\"," + }, + { + "line": 2208, + "text": "chatHyperparameters: \"チャットハイパーパラメータ\"," + }, + { + "line": 2209, + "text": "temperature: \"温度\"," + }, + { + "line": 2210, + "text": "precise: \"精密\"," + }, + { + "line": 2211, + "text": "creative: \"クリエイティブ\"," + }, + { + "line": 2212, + "text": "maxResponseTokens: \"最大応答トークン数\"," + }, + { + "line": 2213, + "text": "retrievalSearchSettings: \"検索設定\"," + }, + { + "line": 2215, + "text": "similarityThreshold: \"類似度しきい値\"," + }, + { + "line": 2216, + "text": "enableHybridSearch: \"ハイブリッド検索を有効にする\"," + }, + { + "line": 2217, + "text": "hybridSearchDesc: \"ベクトル検索と全文検索を併用して検索精度を向上させます\"," + }, + { + "line": 2218, + "text": "hybridWeight: \"ハイブリッド重み (0.0=全文, 1.0=ベクトル)\"," + }, + { + "line": 2219, + "text": "pureText: \"純粋なテキスト\"," + }, + { + "line": 2220, + "text": "pureVector: \"純粋なベクトル\"," + }, + { + "line": 2221, + "text": "enableQueryExpansion: \"クエリ拡張を有効にする\"," + }, + { + "line": 2222, + "text": "queryExpansionDesc: \"複数のクエリバリアントを生成してカバレッジを向上させます\"," + }, + { + "line": 2223, + "text": "enableHyDE: \"HyDEを有効にする\"," + }, + { + "line": 2224, + "text": "hydeDesc: \"仮想的な回答を生成してセマンティック検索を改善します\"," + }, + { + "line": 2225, + "text": "enableReranking: \"リランクを有効にする\"," + }, + { + "line": 2226, + "text": "rerankingDesc: \"リランクモデルを使用して結果を再ソートします\"," + }, + { + "line": 2227, + "text": "broad: \"広範\"," + }, + { + "line": 2228, + "text": "strict: \"厳格\"," + }, + { + "line": 2229, + "text": "maxInput: \"最大入力\"," + }, + { + "line": 2230, + "text": "dimensions: \"次元\"," + }, + { + "line": 2231, + "text": "defaultBadge: \"デフォルト\"," + }, + { + "line": 2232, + "text": "dims: \"次元: $1\"," + }, + { + "line": 2233, + "text": "ctx: \"コンテキスト: $1\"," + }, + { + "line": 2235, + "text": "configured: \"設定済み\"," + }, + { + "line": 2236, + "text": "groupUpdated: \"グループが更新されました\"," + }, + { + "line": 2237, + "text": "groupDeleted: \"グループが削除されました\"," + }, + { + "line": 2238, + "text": "groupCreated: \"グループが作成されました\"," + }, + { + "line": 2239, + "text": "navCatalog: \"カタログ\"," + }, + { + "line": 2240, + "text": "allDocuments: \"すべてのドキュメント\"," + }, + { + "line": 2241, + "text": "categories: \"カテゴリ\"," + }, + { + "line": 2242, + "text": "uncategorizedFiles: \"未分類ファイル\"," + }, + { + "line": 2243, + "text": "category: \"カテゴリ\"," + }, + { + "line": 2244, + "text": "statusReadyDesc: \"インデックス済みで検索可能\"," + }, + { + "line": 2245, + "text": "statusIndexingDesc: \"ベクトルインデックスを作成中\"," + }, + { + "line": 2246, + "text": "selectCategory: \"カテゴリを選択\"," + }, + { + "line": 2247, + "text": "noneUncategorized: \"未分類ファイルなし\"," + }, + { + "line": 2248, + "text": "previous: \"前へ\"," + }, + { + "line": 2249, + "text": "next: \"次へ\"," + }, + { + "line": 2250, + "text": "createCategory: \"カテゴリを作成\"," + }, + { + "line": 2251, + "text": "categoryDesc: \"ナレッジカテゴリを説明します\"," + }, + { + "line": 2252, + "text": "categoryName: \"カテゴリ名\"," + }, + { + "line": 2253, + "text": "createCategoryBtn: \"今すぐ作成\"," + }, + { + "line": 2254, + "text": "newGroup: \"新規グループ\"," + }, + { + "line": 2255, + "text": "noKnowledgeGroups: \"ナレッジグループがまだありません\"," + }, + { + "line": 2256, + "text": "createGroupDesc: \"最初のナレッジCreate groupしてドキュメントをアップロードしてください。\"," + }, + { + "line": 2257, + "text": "noDescriptionProvided: \"説明なし\"," + }, + { + "line": 2258, + "text": "browseManageFiles: \"このグループ内のファイルとメモを閲覧・管理します。\"," + }, + { + "line": 2259, + "text": "filterGroupFiles: \"名前でグループ内のファイルを検索...\"," + }, + { + "line": 2260, + "text": "generalSettingsSubtitle: \"アプリケーションの設定を管理します。\"," + }, + { + "line": 2261, + "text": "userManagementSubtitle: \"アクセス権限とアカウントを管理します。\"," + }, + { + "line": 2262, + "text": "modelManagementSubtitle: \"グローバルなAIモデルを設定します。\"," + }, + { + "line": 2263, + "text": "kbSettingsSubtitle: \"インデックス作成とチャットパラメータの技術設定。\"," + }, + { + "line": 2264, + "text": "tenantsSubtitle: \"グローバルシステムの概要。\"," + }, + { + "line": 2265, + "text": "allNotes: \"すべてのノート\"," + }, + { + "line": 2266, + "text": "filterNotesPlaceholder: \"ノートをフィルタリング...\"," + }, + { + "line": 2267, + "text": "startWritingPlaceholder: \"書き始める...\"," + }, + { + "line": 2268, + "text": "previewHeader: \"プレビュー\"," + }, + { + "line": 2269, + "text": "noContentToPreview: \"プレビューするコンテンツがありません\"," + }, + { + "line": 2270, + "text": "hidePreview: \"プレビューを非表示\"," + }, + { + "line": 2271, + "text": "showPreview: \"プレビューを表示\"," + }, + { + "line": 2272, + "text": "directoryLabel: \"ディレクトリ\"," + }, + { + "line": 2273, + "text": "uncategorized: \"未分類\"," + }, + { + "line": 2274, + "text": "enterNamePlaceholder: \"名前を入力...\"," + }, + { + "line": 2275, + "text": "subFolderPlaceholder: \"サブフォルダ...\"," + }, + { + "line": 2276, + "text": "categoryCreated: \"カテゴリが作成されました\"," + }, + { + "line": 2277, + "text": "failedToCreateCategory: \"カテゴリの作成に失敗しました\"," + }, + { + "line": 2278, + "text": "failedToDeleteCategory: \"カテゴリの削除に失敗しました\"," + }, + { + "line": 2279, + "text": "confirmDeleteCategory: \"このカテゴリを削除してもよろしいですか?\"," + }, + { + "line": 2283, + "text": "agentTitle: \"エージェントセンター\"," + }, + { + "line": 2284, + "text": "agentDesc: \"複雑なタスクを支援する AI アシスタントを管理および実行します。\"," + }, + { + "line": 2285, + "text": "createAgent: \"エージェント作成\"," + }, + { + "line": 2286, + "text": "searchAgent: \"エージェントを検索...\"," + }, + { + "line": 2287, + "text": "statusRunning: \"実行中\"," + }, + { + "line": 2288, + "text": "statusStopped: \"停止中\"," + }, + { + "line": 2289, + "text": "updatedAtPrefix: \"最終更新日: \"," + }, + { + "line": 2290, + "text": "btnChat: \"会話を開始\"," + }, + { + "line": 2293, + "text": "agent1Name: \"データ分析エキスパート\"," + }, + { + "line": 2294, + "text": "agent1Desc: \"SQL とデータ視覚化に精通し、複雑なデータから洞察を抽出できます。\"," + }, + { + "line": 2295, + "text": "agent2Name: \"コードレビュー助手\"," + }, + { + "line": 2296, + "text": "agent2Desc: \"コードの品質を自動的にチェックし、リファクタリングの提案やパフォーマンス最適化案を提供します。\"," + }, + { + "line": 2297, + "text": "agent3Name: \"学術論文校閲\"," + }, + { + "line": 2298, + "text": "agent3Desc: \"専門的な学術ライティングアシスタント。論文の構成と表現の最適化を支援します。\"," + }, + { + "line": 2299, + "text": "agent4Name: \"法律顧問\"," + }, + { + "line": 2300, + "text": "agent4Desc: \"法律条文の検索や基本的な法的アドバイスを提供し、契約書の作成を支援します。\"," + }, + { + "line": 2301, + "text": "agent5Name: \"市場調査員\"," + }, + { + "line": 2302, + "text": "agent5Desc: \"業界のトレンドを分析し、競合他社の調査レポートを生成します。\"," + }, + { + "line": 2303, + "text": "agent6Name: \"システム運用保守エキスパート\"," + }, + { + "line": 2304, + "text": "agent6Desc: \"システムの健康状態を監視し、一般的なアラートへの対応やトラブルシューティングを自動化します。\"," + }, + { + "line": 2305, + "text": "agent7Name: \"財務監査人\"," + }, + { + "line": 2306, + "text": "agent7Desc: \"レポート監査を自動化し、財務リスクや異常な取引を特定します。\"," + }, + { + "line": 2307, + "text": "agent1Time: \"2 時間前\"," + }, + { + "line": 2308, + "text": "agent2Time: \"5 時間前\"," + }, + { + "line": 2309, + "text": "agent3Time: \"昨日\"," + }, + { + "line": 2310, + "text": "agent4Time: \"2 日前\"," + }, + { + "line": 2311, + "text": "agent5Time: \"3 日前\"," + }, + { + "line": 2312, + "text": "agent6Time: \"5 日前\"," + }, + { + "line": 2313, + "text": "agent7Time: \"1 週間前\"," + }, + { + "line": 2316, + "text": "pluginTitle: \"プラグインストア\"," + }, + { + "line": 2317, + "text": "pluginDesc: \"外部ツールやサービスを統合して、ナレッジベースの機能を拡張します。\"," + }, + { + "line": 2318, + "text": "searchPlugin: \"プラグインを検索...\"," + }, + { + "line": 2319, + "text": "installPlugin: \"インストール\"," + }, + { + "line": 2320, + "text": "installedPlugin: \"インストール済み\"," + }, + { + "line": 2321, + "text": "updatePlugin: \"アップデートあり\"," + }, + { + "line": 2322, + "text": "pluginOfficial: \"公式\"," + }, + { + "line": 2323, + "text": "pluginCommunity: \"コミュニティ\"," + }, + { + "line": 2324, + "text": "pluginBy: \"開発者: \"," + }, + { + "line": 2325, + "text": "pluginConfig: \"設定\"," + }, + { + "line": 2328, + "text": "plugin1Name: \"Web 検索\"," + }, + { + "line": 2329, + "text": "plugin1Desc: \"最新情報を取得するために、AI にインターネットへのリアルタイムアクセスを提供します。\"," + }, + { + "line": 2330, + "text": "plugin2Name: \"PDF ドキュメント解析\"," + }, + { + "line": 2331, + "text": "plugin2Desc: \"複雑な PDF レイアウトを詳細に解析し、表や数式を抽出します。\"," + }, + { + "line": 2332, + "text": "plugin3Name: \"GitHub 連携\"," + }, + { + "line": 2333, + "text": "plugin3Desc: \"GitHub リポジトリに直接アクセスし、コードのコミットやイシュー管理を行います。\"," + }, + { + "line": 2334, + "text": "plugin4Name: \"Google カレンダー\"," + }, + { + "line": 2335, + "text": "plugin4Desc: \"スケジュールを同期し、会議のリマインダーを自動的に作成します。\"," + }, + { + "line": 2336, + "text": "plugin5Name: \"SQL データベース接続\"," + }, + { + "line": 2337, + "text": "plugin5Desc: \"データベースに安全に接続し、自然語言でクエリを実行します。\"," + }, + { + "line": 2338, + "text": "plugin6Name: \"Slack 通知\"," + }, + { + "line": 2339, + "text": "plugin6Desc: \"AI が生成したレポートを指定された Slack チャンネルに直接送信します。\"," + }, + { + "line": 2341, + "text": "navTenants: \"テナント管理\"," + }, + { + "line": 2342, + "text": "noNotesFound: \"ノートが見つかりません\"," + }, + { + "line": 2343, + "text": "notebookDesc: \"ノートブックは知識の整理と要約に役立ちます。\"," + }, + { + "line": 2344, + "text": "personalNotebook: \"個人用ノートブック\"," + }, + { + "line": 2345, + "text": "warning: \"警告\"," + }, + { + "line": 2346, + "text": "\"x-api-key\": \"APIキー\"," + }, + { + "line": 2347, + "text": "\"x-tenant-id\": \"テナントID\"," + }, + { + "line": 2348, + "text": "\"x-user-language\": \"ユーザー言語\"," + }, + { + "line": 2351, + "text": "addSubcategory: \"サブカテゴリをAdded\"," + }, + { + "line": 2352, + "text": "parentCategory: \"親カテゴリ(任意)\"," + }, + { + "line": 2353, + "text": "noParentTopLevel: \"なし(トップレベル)\"," + }, + { + "line": 2354, + "text": "useHierarchyImport: \"フォルダ階層でカテゴリを作成\"," + }, + { + "line": 2355, + "text": "useHierarchyImportDesc: \"有効にすると、各サブフォルダにサブカテゴリが作成され、ファイルが対応するカテゴリにインポートされます。\"," + }, + { + "line": 2358, + "text": "importImmediate: \"今すぐインポート\"," + }, + { + "line": 2359, + "text": "importScheduled: \"スケジュールインポート\"," + }, + { + "line": 2360, + "text": "lblServerPath: \"サーバーフォルダパス\"," + }, + { + "line": 2361, + "text": "placeholderServerPath: \"例: /data/documents\"," + }, + { + "line": 2362, + "text": "scheduledImportTip: \"サーバー側のスケジュールインポート:指定した時刻にサーバーがパスのファイルを読み込んで自動インポートします。サーバーがそのパスにアクセスできることを確認してください。\"," + }, + { + "line": 2363, + "text": "lblScheduledTime: \"実行日時\"," + }, + { + "line": 2364, + "text": "scheduledTimeHint: \"指定した時刻に、サーバーが自動的にインポートタスクを実行します。\"," + }, + { + "line": 2365, + "text": "scheduleImport: \"スケジュールタスクを作成\"," + }, + { + "line": 2366, + "text": "scheduleTaskCreated: \"スケジュールインポートタスクが作成されました\"," + }, + { + "line": 2367, + "text": "fillServerPath: \"サーバーフォルダパスを入力してください\"," + }, + { + "line": 2368, + "text": "invalidDateTime: \"有効な日付と時刻を入力してください\"," + }, + { + "line": 2371, + "text": "importTasksTitle: \"定期計画\"," + }, + { + "line": 2372, + "text": "noTasksFound: \"タスクは見つかりませんでした\"," + }, + { + "line": 2373, + "text": "sourcePath: \"ソースパス\"," + }, + { + "line": 2374, + "text": "targetGroup: \"ターゲットグループ\"," + }, + { + "line": 2375, + "text": "scheduledAt: \"実行予定日時\"," + }, + { + "line": 2376, + "text": "confirmDeleteTask: \"このインポートタスクレコードを削除してもよろしいですか?\"," + }, + { + "line": 2377, + "text": "deleteTaskFailed: \"タスクレコードの削除に失敗しました\"," + } + ], + "d:\\workspace\\AuraK\\server\\src\\chat\\chat.controller.ts": [ + { + "line": 94, + "text": "console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无');" + } + ], + "d:\\workspace\\AuraK\\server\\src\\i18n\\i18n.service.ts": [ + { + "line": 7, + "text": "private readonly defaultLanguage = 'ja'; // プロジェクト要件に従い、Japaneseをデフォルトとして使用" + }, + { + "line": 30, + "text": "// 汎用メッセージ取得メソッド、順次検索" + }, + { + "line": 33, + "text": "// ステータスメッセージ、エラーメッセージ、ログメッセージの順に検索" + }, + { + "line": 43, + "text": "// メッセージの取得とフォーマット" + }, + { + "line": 52, + "text": "// サポートされている言語リストを取得" + }, + { + "line": 57, + "text": "// 言語がサポートされているか確認" + }, + { + "line": 62, + "text": "// システムプロンプトを取得" + }, + { + "line": 69, + "text": "基于以下知识库内容回答用户问题。" + }, + { + "line": 71, + "text": "**重要提示**: 用户已选择特定知识组,请严格基于以下知识库内容回答。如果知识库中没有相关信息,请明确告知用户:\"${noMatchMsg}\",然后再提供答案。" + }, + { + "line": 73, + "text": "知识库内容:" + }, + { + "line": 76, + "text": "历史对话:" + }, + { + "line": 79, + "text": "用户问题:{question}" + }, + { + "line": 81, + "text": "请用Chinese回答,并严格遵循以下 Markdown 格式要求:" + }, + { + "line": 83, + "text": "1. **段落与结构**:" + }, + { + "line": 84, + "text": "- 使用清晰的段落分隔,每个要点之间空一行" + }, + { + "line": 85, + "text": "- 使用标题(## 或 ###)组织长回答" + }, + { + "line": 87, + "text": "2. **文本格式**:" + }, + { + "line": 88, + "text": "- 使用 **粗体** 强调重要概念和关键词" + }, + { + "line": 89, + "text": "- 使用列表(- 或 1.)组织多个要点" + }, + { + "line": 90, + "text": "- 使用 \\`代码\\` 标记技术术语、命令、文件名" + }, + { + "line": 92, + "text": "3. **代码展示**:" + }, + { + "line": 93, + "text": "- 使用代码块展示代码,并指定语言:" + }, + { + "line": 96, + "text": "return \"示例\"" + }, + { + "line": 98, + "text": "- 支持语言:python, javascript, typescript, java, bash, sql 等" + }, + { + "line": 100, + "text": "4. **图表与可视化**:" + }, + { + "line": 101, + "text": "- 使用 Mermaid 语法绘制流程图、序列图等:" + }, + { + "line": 104, + "text": "A[开始] --> B[处理]" + }, + { + "line": 105, + "text": "B --> C[结束]" + }, + { + "line": 107, + "text": "- 适用场景:流程、架构、状态机、时序图" + }, + { + "line": 109, + "text": "5. **其他要求**:" + }, + { + "line": 110, + "text": "- 回答精炼准确" + }, + { + "line": 111, + "text": "- 多步骤操作使用有序列表" + }, + { + "line": 112, + "text": "- 对比类信息建议用表格展示(如果适用)" + }, + { + "line": 114, + "text": "作为智能助手,请回答用户的问题。" + }, + { + "line": 116, + "text": "历史对话:" + }, + { + "line": 119, + "text": "用户问题:{question}" + }, + { + "line": 121, + "text": "请用Chinese回答。" + }, + { + "line": 179, + "text": "} else { // 默认为日语,符合项目要求" + }, + { + "line": 181, + "text": "以下のナレッジベースの内容に基づいてユーザーの質問に答えてください。" + }, + { + "line": 183, + "text": "**重要**: ユーザーが特定の知識グループを選択しました。以下のナレッジベースの内容に厳密に基づいて回答してください。ナレッジベースに関連情報がない場合は、「${noMatchMsg}」とユーザーに明示的に伝えてから、回答を提供してください。" + }, + { + "line": 185, + "text": "ナレッジベースの内容:" + }, + { + "line": 188, + "text": "会話履歴:" + }, + { + "line": 191, + "text": "ユーザーの質問:{question}" + }, + { + "line": 193, + "text": "Japaneseで回答してください。以下の Markdown 書式要件に厳密に従ってください:" + }, + { + "line": 195, + "text": "1. **段落と構造**:" + }, + { + "line": 196, + "text": "- 明確な段落分けを使用し、要点間に空行を入れる" + }, + { + "line": 197, + "text": "- 長い回答には見出し(## または ###)を使用" + }, + { + "line": 199, + "text": "2. **テキスト書式**:" + }, + { + "line": 200, + "text": "- 重要な概念やキーワードを強調するために **太字** を使用" + }, + { + "line": 201, + "text": "- 複数のポイントを整理するためにリスト(- または 1.)を使用" + }, + { + "line": 202, + "text": "- 技術用語、コマンド、ファイル名をマークするために \\`コード\\` を使用" + }, + { + "line": 204, + "text": "3. **コード表示**:" + }, + { + "line": 205, + "text": "- 言語を指定してコードブロックを使用:" + }, + { + "line": 208, + "text": "return \"例\"" + }, + { + "line": 210, + "text": "- 対応言語:python, javascript, typescript, java, bash, sql など" + }, + { + "line": 212, + "text": "4. **図表とチャート**:" + }, + { + "line": 213, + "text": "- フローチャート、シーケンス図などに Mermaid 構文を使用:" + }, + { + "line": 216, + "text": "A[開始] --> B[処理]" + }, + { + "line": 217, + "text": "B --> C[終了]" + }, + { + "line": 219, + "text": "- 使用例:プロセスフロー、アーキテクチャ図、状態図、シーケンス図" + }, + { + "line": 221, + "text": "5. **その他の要件**:" + }, + { + "line": 222, + "text": "- 簡潔で明確な回答を心がける" + }, + { + "line": 223, + "text": "- 複数のステップがある場合は番号付きリストを使用" + }, + { + "line": 224, + "text": "- 比較情報には表を使用(該当する場合)" + }, + { + "line": 226, + "text": "インテリジェントアシスタントとして、ユーザーの質問に答えてください。" + }, + { + "line": 228, + "text": "会話履歴:" + }, + { + "line": 231, + "text": "ユーザーの質問:{question}" + }, + { + "line": 232, + "text": "Japaneseで回答してください。" + }, + { + "line": 237, + "text": "// タイトル生成用のプロンプトを取得" + }, + { + "line": 241, + "text": "return `你是一个文档分析师。请阅读以下文本(文档开Header分),并生成一个简炼、专业的标题(不超过50个字符)。" + }, + { + "line": 242, + "text": "只返回标题文本。不要包含任何解释性文字或前导词(如“标题是:”)。" + }, + { + "line": 243, + "text": "语言:Chinese" + }, + { + "line": 244, + "text": "文本内容:" + }, + { + "line": 253, + "text": "return `あなたはドキュメントアナライザーです。以下のテキスト(ドキュメントの冒頭部分)を読み、簡潔でプロフェッショナルなタイトル(最大50文字)を生成してください。" + }, + { + "line": 254, + "text": "タイトルテキストのみを返してください。説明文や前置き(例:「タイトルは:」)は含めないでください。" + }, + { + "line": 255, + "text": "言語:Japanese" + }, + { + "line": 256, + "text": "テキスト:" + }, + { + "line": 264, + "text": "return `根据以下对话片段,生成一个简短、描述性的标题(不超过50个字符),总结讨论的主题。" + }, + { + "line": 265, + "text": "只返回标题文本。不要包含任何前导词。" + }, + { + "line": 266, + "text": "语言:Chinese" + }, + { + "line": 267, + "text": "片段:" + }, + { + "line": 268, + "text": "用户: ${userMessage}" + }, + { + "line": 269, + "text": "助手: ${aiResponse}`;" + }, + { + "line": 278, + "text": "return `以下の会話スニペットに基づいて、トピックを要約する短く説明的なタイトル(最大50文字)を生成してください。" + }, + { + "line": 279, + "text": "タイトルのみを返してください。前置きは不要です。" + }, + { + "line": 280, + "text": "言語:Japanese" + }, + { + "line": 281, + "text": "スニペット:" + }, + { + "line": 282, + "text": "ユーザー: ${userMessage}" + }, + { + "line": 283, + "text": "アシスタント: ${aiResponse}`;" + } + ], + "d:\\workspace\\AuraK\\server\\src\\i18n\\messages.ts": [ + { + "line": 3, + "text": "noEmbeddingModel: '请先在系统设置中配置嵌入模型'," + }, + { + "line": 4, + "text": "searchFailed: '搜索知识库失败,将基于一般知识回答...'," + }, + { + "line": 5, + "text": "invalidApiKey: 'API密钥无效'," + }, + { + "line": 6, + "text": "fileNotFound: '未找到文件'," + }, + { + "line": 7, + "text": "insufficientQuota: '配额不足'," + }, + { + "line": 8, + "text": "modelNotConfigured: '未配置模型'," + }, + { + "line": 9, + "text": "visionModelNotConfigured: '未配置视觉模型'," + }, + { + "line": 10, + "text": "embeddingDimensionMismatch: '嵌入维度不匹配'," + }, + { + "line": 11, + "text": "uploadNoFile: '未上传文件'," + }, + { + "line": 12, + "text": "uploadSizeExceeded: '文件大小超过限制: {size}, 最大允许: {max}'," + }, + { + "line": 13, + "text": "uploadModelRequired: '必须选择嵌入模型'," + }, + { + "line": 14, + "text": "uploadTypeUnsupported: '不支持的文件格式: {type}'," + }, + { + "line": 15, + "text": "chunkOverflow: '切片大小 {size} 超过上限 {max} ({reason})。已自动调整'," + }, + { + "line": 16, + "text": "chunkUnderflow: '切片大小 {size} 小于最小值 {min}。已自动调整'," + }, + { + "line": 17, + "text": "overlapOverflow: '重叠大小 {size} 超过上限 {max}。已自动调整'," + }, + { + "line": 18, + "text": "overlapUnderflow: '重叠大小 {size} 小于最小值 {min}。已自动调整'," + }, + { + "line": 19, + "text": "overlapRatioExceeded: '重叠大小 {size} 超过切片大小的50% ({max})。已自动调整'," + }, + { + "line": 20, + "text": "batchOverflowWarning: '建议切片大小不超过 {safeSize} 以避免批量处理溢出 (当前: {size}, 模型限制的 {percent}%)'," + }, + { + "line": 21, + "text": "estimatedChunkCountExcessive: '预计切片数量过多 ({count}),处理可能较慢'," + }, + { + "line": 22, + "text": "contentAndTitleRequired: '内容和标题为必填项'," + }, + { + "line": 23, + "text": "embeddingModelNotFound: '找不到嵌入模型 {id} 或类型不是 embedding'," + }, + { + "line": 24, + "text": "ocrFailed: '提取文本失败: {message}'," + }, + { + "line": 25, + "text": "noImageUploaded: '未上传图片'," + }, + { + "line": 26, + "text": "adminOnlyViewList: '只有管理员可以查看用户列表'," + }, + { + "line": 27, + "text": "passwordsRequired: '当前密码和新密码不能为空'," + }, + { + "line": 28, + "text": "newPasswordMinLength: '新密码长度不能少于6位'," + }, + { + "line": 29, + "text": "adminOnlyCreateUser: '只有管理员可以创建用户'," + }, + { + "line": 30, + "text": "usernamePasswordRequired: '用户名和密码不能为空'," + }, + { + "line": 31, + "text": "passwordMinLength: '密码长度不能少于6位'," + }, + { + "line": 32, + "text": "adminOnlyUpdateUser: '只有管理员可以更新用户信息'," + }, + { + "line": 33, + "text": "userNotFound: '用户不存在'," + }, + { + "line": 34, + "text": "cannotModifyBuiltinAdmin: '无法修改内置管理员账户'," + }, + { + "line": 35, + "text": "adminOnlyDeleteUser: '只有管理员可以删除用户'," + }, + { + "line": 36, + "text": "cannotDeleteSelf: '不能删除自己的账户'," + }, + { + "line": 37, + "text": "cannotDeleteBuiltinAdmin: '无法删除内置管理员账户'," + }, + { + "line": 38, + "text": "incorrectCredentials: '用户名或密码不正确'," + }, + { + "line": 39, + "text": "incorrectCurrentPassword: '当前密码错误'," + }, + { + "line": 40, + "text": "usernameExists: '用户名已存在'," + }, + { + "line": 41, + "text": "noteNotFound: '找不到笔记: {id}'," + }, + { + "line": 42, + "text": "knowledgeGroupNotFound: '找不到知识组: {id}'," + }, + { + "line": 43, + "text": "accessDeniedNoToken: '访问被拒绝:缺少令牌'," + }, + { + "line": 44, + "text": "invalidToken: '无效的令牌'," + }, + { + "line": 45, + "text": "pdfFileNotFound: '找不到 PDF 文件'," + }, + { + "line": 46, + "text": "pdfFileEmpty: 'PDF 文件为空,转换可能失败'," + }, + { + "line": 47, + "text": "pdfConversionFailed: 'PDF 文件不存在或转换失败'," + }, + { + "line": 48, + "text": "pdfConversionFailedDetail: 'PDF 转换失败(文件 ID: {id}),请稍后重试'," + }, + { + "line": 49, + "text": "pdfPreviewNotSupported: '该文件格式不支持预览'," + }, + { + "line": 50, + "text": "pdfServiceUnavailable: 'PDF 服务不可用: {message}'," + }, + { + "line": 51, + "text": "pageImageNotFound: '找不到页面图像'," + }, + { + "line": 52, + "text": "pdfPageImageFailed: '无法获取 PDF 页面图像'," + }, + { + "line": 53, + "text": "someGroupsNotFound: '部分组不存在'," + }, + { + "line": 54, + "text": "promptRequired: '提示词是必填项'," + }, + { + "line": 55, + "text": "addLLMConfig: '请在系统设置中添加 LLM 模型'," + }, + { + "line": 56, + "text": "visionAnalysisFailed: '视觉分析失败: {message}'," + }, + { + "line": 57, + "text": "retryMechanismError: '重试机制异常'," + }, + { + "line": 58, + "text": "imageLoadError: '无法读取图像: {message}'," + }, + { + "line": 59, + "text": "groupNotFound: '分组不存在'," + }, + { + "line": 62, + "text": "noEmbeddingModel: '先にシステム設定で埋め込みモデルを設定してください'," + }, + { + "line": 63, + "text": "searchFailed: 'ナレッジベース検索に失敗しました。一般的な知識に基づいて回答します...'," + }, + { + "line": 64, + "text": "invalidApiKey: 'APIキーが無効です'," + }, + { + "line": 65, + "text": "fileNotFound: 'ファイルが見つかりません'," + }, + { + "line": 66, + "text": "insufficientQuota: '利用枠が不足しています'," + }, + { + "line": 67, + "text": "modelNotConfigured: 'モデルが設定されていません'," + }, + { + "line": 68, + "text": "visionModelNotConfigured: 'ビジョンモデルが設定されていません'," + }, + { + "line": 69, + "text": "embeddingDimensionMismatch: '埋め込み次元数が一致しません'," + }, + { + "line": 70, + "text": "uploadNoFile: 'ファイルがアップロードされていません'," + }, + { + "line": 71, + "text": "uploadSizeExceeded: 'ファイルサイズが制限: {size}, 最大許容: {max}'," + }, + { + "line": 72, + "text": "uploadModelRequired: '埋め込みモデルを選択する必要があります'," + }, + { + "line": 73, + "text": "uploadTypeUnsupported: 'サポートされていないファイル形式です: {type}'," + }, + { + "line": 74, + "text": "chunkOverflow: 'Chunk size {size} exceeds limit {max} ({reason}) 。自動調整されました'," + }, + { + "line": 75, + "text": "chunkUnderflow: 'Chunk size {size} is below minimum {min} 。自動調整されました'," + }, + { + "line": 76, + "text": "overlapOverflow: '重なりサイズ {size} exceeds limit {max} 。自動調整されました'," + }, + { + "line": 77, + "text": "overlapUnderflow: '重なりサイズ {size} is below minimum {min} 。自動調整されました'," + }, + { + "line": 78, + "text": "overlapRatioExceeded: '重なりサイズ {size} がChunk sizeの50% ({max}) 。自動調整されました'," + }, + { + "line": 79, + "text": "batchOverflowWarning: 'バッチ処理のオーバーフローを避けるため、Chunk sizeを {safeSize} 以下にすることをお勧めします (現在: {size}, モデル制限の {percent}%)'," + }, + { + "line": 80, + "text": "estimatedChunkCountExcessive: '推定チャンク数が多すぎます ({count})。処理に時間がかかる可能性があります'," + }, + { + "line": 81, + "text": "contentAndTitleRequired: '内容とタイトルは必須です'," + }, + { + "line": 82, + "text": "embeddingModelNotFound: '埋め込みモデル {id} が見つかりません、またはタイプが embedding ではありません'," + }, + { + "line": 83, + "text": "ocrFailed: 'テキストの抽出に失敗しました: {message}'," + }, + { + "line": 84, + "text": "noImageUploaded: '画像がアップロードされていません'," + }, + { + "line": 85, + "text": "adminOnlyViewList: '管理者のみがユーザーリストを表示できます'," + }, + { + "line": 86, + "text": "passwordsRequired: '現在のパスワードと新しいパスワードは必須です'," + }, + { + "line": 87, + "text": "newPasswordMinLength: '新しいパスワードは少なくとも6文字以上である必要があります'," + }, + { + "line": 88, + "text": "adminOnlyCreateUser: '管理者のみがユーザーを作成できます'," + }, + { + "line": 89, + "text": "usernamePasswordRequired: 'ユーザー名とパスワードは必須です'," + }, + { + "line": 90, + "text": "passwordMinLength: 'パスワードは少なくとも6文字以上である必要があります'," + }, + { + "line": 91, + "text": "adminOnlyUpdateUser: '管理者のみがユーザー情報を更新できます'," + }, + { + "line": 92, + "text": "userNotFound: 'ユーザーが見つかりません'," + }, + { + "line": 93, + "text": "cannotModifyBuiltinAdmin: 'ビルトイン管理者アカウントを変更できません'," + }, + { + "line": 94, + "text": "adminOnlyDeleteUser: '管理者のみがユーザーを削除できます'," + }, + { + "line": 95, + "text": "cannotDeleteSelf: '自分自身のアカウントを削除できません'," + }, + { + "line": 96, + "text": "cannotDeleteBuiltinAdmin: 'ビルトイン管理者アカウントを削除できません'," + }, + { + "line": 97, + "text": "incorrectCredentials: 'ユーザー名またはパスワードが間違っています'," + }, + { + "line": 98, + "text": "incorrectCurrentPassword: '現在のパスワードが間違っています'," + }, + { + "line": 99, + "text": "usernameExists: 'ユーザー名が既に存在します'," + }, + { + "line": 100, + "text": "noteNotFound: 'ノートが見つかりません: {id}'," + }, + { + "line": 101, + "text": "knowledgeGroupNotFound: 'ナレッジグループが見つかりません: {id}'," + }, + { + "line": 102, + "text": "accessDeniedNoToken: 'アクセス不許可:トークンがありません'," + }, + { + "line": 103, + "text": "invalidToken: '無効なトークンです'," + }, + { + "line": 104, + "text": "pdfFileNotFound: 'PDF ファイルが見つかりません'," + }, + { + "line": 105, + "text": "pdfFileEmpty: 'PDF ファイルが空です。変換に失敗した可能性があります'," + }, + { + "line": 106, + "text": "pdfConversionFailed: 'PDF ファイルが存在しないか、変換に失敗しました'," + }, + { + "line": 107, + "text": "pdfConversionFailedDetail: 'PDF 変換に失敗しました(ファイル ID: {id})。後でもう一度お試しください'," + }, + { + "line": 108, + "text": "pdfPreviewNotSupported: 'このファイル形式はプレビューをサポートしていません'," + }, + { + "line": 109, + "text": "pdfServiceUnavailable: 'PDF サービスを利用できません: {message}'," + }, + { + "line": 110, + "text": "pageImageNotFound: 'ページ画像が見つかりません'," + }, + { + "line": 111, + "text": "pdfPageImageFailed: 'PDF ページの画像を取得できませんでした'," + }, + { + "line": 112, + "text": "someGroupsNotFound: '一部のグループが存在しません'," + }, + { + "line": 113, + "text": "promptRequired: 'プロンプトは必須です'," + }, + { + "line": 114, + "text": "addLLMConfig: 'システム設定で LLM モデルをAddedしてください'," + }, + { + "line": 115, + "text": "visionAnalysisFailed: 'ビジョン分析に失敗しました: {message}'," + }, + { + "line": 116, + "text": "retryMechanismError: '再試行メカニズムの異常'," + }, + { + "line": 117, + "text": "imageLoadError: '画像を読み込めません: {message}'," + }, + { + "line": 118, + "text": "groupNotFound: 'グループが存在しません'," + }, + { + "line": 184, + "text": "processingFile: '处理文件: {name} ({size})'," + }, + { + "line": 185, + "text": "indexingComplete: '索引完成: {id}'," + }, + { + "line": 186, + "text": "vectorizingFile: '向量化文件: '," + }, + { + "line": 187, + "text": "searchQuery: '搜索查询: '," + }, + { + "line": 188, + "text": "modelCall: '[模型调用] 类型: {type}, 模型: {model}, 用户: {user}'," + }, + { + "line": 189, + "text": "memoryStatus: '内存状态: '," + }, + { + "line": 190, + "text": "uploadSuccess: '文件上传成功。正在后台索引'," + }, + { + "line": 191, + "text": "overlapAdjusted: '重叠大小超过切片大小的50%。已自动调整为 {newSize}'," + }, + { + "line": 192, + "text": "environmentLimit: '环境变量限制'," + }, + { + "line": 193, + "text": "modelLimit: '模型限制'," + }, + { + "line": 194, + "text": "configLoaded: '数据库模型配置加载: {name} ({id})'," + }, + { + "line": 195, + "text": "batchSizeAdjusted: '批量大小从 {old} 调整为 {new} (模型限制: {limit})'," + }, + { + "line": 196, + "text": "dimensionMismatch: '模型 {id} 维度不匹配: 预期 {expected}, 实际 {actual}'," + }, + { + "line": 197, + "text": "searchMetadataFailed: '为用户 {userId} 搜索知识库失败'," + }, + { + "line": 198, + "text": "extractedTextTooLarge: '抽出されたテキストが大きいです: {size}MB'," + }, + { + "line": 199, + "text": "preciseModeUnsupported: '格式 {ext} 不支持精密模式,回退到快速模式'," + }, + { + "line": 200, + "text": "visionModelNotConfiguredFallback: '未配置视觉模型,回退到快速模式'," + }, + { + "line": 201, + "text": "visionModelInvalidFallback: '视觉模型配置无效,回退到快速模式'," + }, + { + "line": 202, + "text": "visionPipelineFailed: '视觉流水线失败,回退到快速模式'," + }, + { + "line": 203, + "text": "preciseModeComplete: '精密模式提取完成: {pages}页, 费用: ${cost}'," + }, + { + "line": 204, + "text": "skippingEmptyVectorPage: '跳过第 {page} 页(空向量)'," + }, + { + "line": 205, + "text": "pdfPageImageError: '获取 PDF 页面图像失败: {message}'," + }, + { + "line": 206, + "text": "internalServerError: '服务器内部错误'," + }, + { + "line": 209, + "text": "processingFile: 'ファイル処理中: {name} ({size})'," + }, + { + "line": 210, + "text": "indexingComplete: 'インデックス完了: {id}'," + }, + { + "line": 211, + "text": "vectorizingFile: 'ファイルベクトル化中: '," + }, + { + "line": 212, + "text": "searchQuery: '検索クエリ: '," + }, + { + "line": 213, + "text": "modelCall: '[モデル呼び出し] タイプ: {type}, Model: {model}, ユーザー: {user}'," + }, + { + "line": 214, + "text": "memoryStatus: 'メモリ状態: '," + }, + { + "line": 215, + "text": "uploadSuccess: 'ファイルが正常にアップロードされました。バックグラウンドでインデックス処理を実行中です'," + }, + { + "line": 216, + "text": "overlapAdjusted: 'オーバーラップサイズがChunk sizeの50%。自動的に {newSize} に調整されました'," + }, + { + "line": 217, + "text": "environmentLimit: '環境変数の制限'," + }, + { + "line": 218, + "text": "modelLimit: 'モデルの制限'," + }, + { + "line": 219, + "text": "configLoaded: 'データベースからモデル設定を読み込みました: {name} ({id})'," + }, + { + "line": 220, + "text": "batchSizeAdjusted: 'バッチサイズを {old} から {new} に調整しました (モデル制限: {limit})'," + }, + { + "line": 221, + "text": "dimensionMismatch: 'モデル {id} の次元が一致しません: 期待値 {expected}, 実際 {actual}'," + }, + { + "line": 222, + "text": "searchMetadataFailed: 'ユーザー {userId} のナレッジベース検索に失敗しました'," + }, + { + "line": 223, + "text": "extractedTextTooLarge: '抽出されたテキストが大きいです: {size}MB'," + }, + { + "line": 224, + "text": "preciseModeUnsupported: 'ファイル形式 {ext} はPrecise Modeをサポートしていません。Fast Modeにフォールバックします'," + }, + { + "line": 225, + "text": "visionModelNotConfiguredFallback: 'ビジョンモデルが設定されていません。Fast Modeにフォールバックします'," + }, + { + "line": 226, + "text": "visionModelInvalidFallback: 'ビジョンモデルの設定が無効です。Fast Modeにフォールバックします'," + }, + { + "line": 227, + "text": "visionPipelineFailed: 'ビジョンパイプラインが失敗しました。Fast Modeにフォールバックします'," + }, + { + "line": 228, + "text": "preciseModeComplete: 'Precise Mode内容抽出完了: {pages}ページ, コスト: ${cost}'," + }, + { + "line": 229, + "text": "skippingEmptyVectorPage: '第 {page} ページの空ベクトルをスキップします'," + }, + { + "line": 230, + "text": "pdfPageImageError: 'PDF ページの画像取得に失敗しました: {message}'," + }, + { + "line": 231, + "text": "internalServerError: 'サーバー内部エラー'," + }, + { + "line": 262, + "text": "searching: '正在搜索知识库...'," + }, + { + "line": 263, + "text": "noResults: '未找到相关知识,将基于一般知识回答...'," + }, + { + "line": 264, + "text": "searchFailed: '知识库搜索失败,将基于一般知识回答...'," + }, + { + "line": 265, + "text": "generatingResponse: '正在生成回答'," + }, + { + "line": 267, + "text": "notebooks: '个笔记本'," + }, + { + "line": 268, + "text": "all: '全部'," + }, + { + "line": 269, + "text": "items: '个'," + }, + { + "line": 270, + "text": "searchResults: '搜索结果'," + }, + { + "line": 271, + "text": "relevantInfoFound: '条相关信息找到'," + }, + { + "line": 272, + "text": "searchHits: '搜索命中'," + }, + { + "line": 273, + "text": "relevance: '相关度'," + }, + { + "line": 274, + "text": "sourceFiles: '源文件'," + }, + { + "line": 275, + "text": "searchScope: '搜索范围'," + }, + { + "line": 276, + "text": "error: '错误'," + }, + { + "line": 277, + "text": "creatingHistory: '创建新对话历史: '," + }, + { + "line": 278, + "text": "searchingModelById: '根据ID搜索模型: '," + }, + { + "line": 279, + "text": "searchModelFallback: '未找到指定的嵌入模型。使用第一个可用模型。'," + }, + { + "line": 280, + "text": "noEmbeddingModelFound: '找不到嵌入模型设置'," + }, + { + "line": 281, + "text": "usingEmbeddingModel: '使用的嵌入模型: '," + }, + { + "line": 282, + "text": "startingSearch: '开始搜索知识库...'," + }, + { + "line": 283, + "text": "searchResultsCount: '搜索结果数: '," + }, + { + "line": 284, + "text": "searchFailedLog: '搜索失败'," + }, + { + "line": 285, + "text": "modelCall: '[模型调用]'," + }, + { + "line": 286, + "text": "chatStreamError: '聊天流错误'," + }, + { + "line": 287, + "text": "assistStreamError: '辅助流错误'," + }, + { + "line": 288, + "text": "file: '文件'," + }, + { + "line": 289, + "text": "content: '内容'," + }, + { + "line": 290, + "text": "userLabel: '用户'," + }, + { + "line": 291, + "text": "assistantLabel: '助手'," + }, + { + "line": 292, + "text": "intelligentAssistant: '您是智能写作助手。'," + }, + { + "line": 293, + "text": "searchString: '搜索字符串: '," + }, + { + "line": 294, + "text": "embeddingModelIdNotProvided: '未提供嵌入模型ID'," + }, + { + "line": 295, + "text": "generatingEmbeddings: '生成嵌入向量...'," + }, + { + "line": 296, + "text": "embeddingsGenerated: '嵌入向量生成完成'," + }, + { + "line": 297, + "text": "dimensions: '维度'," + }, + { + "line": 298, + "text": "performingHybridSearch: '执行混合搜索...'," + }, + { + "line": 299, + "text": "esSearchCompleted: 'ES搜索完成'," + }, + { + "line": 300, + "text": "resultsCount: '结果数'," + }, + { + "line": 301, + "text": "hybridSearchFailed: '混合搜索失败'," + }, + { + "line": 302, + "text": "getContextForTopicFailed: '获取主题上下文失败'," + }, + { + "line": 303, + "text": "noLLMConfigured: '用户未配置LLM模型'," + }, + { + "line": 304, + "text": "simpleChatGenerationError: '简单聊天生成错误'," + }, + { + "line": 305, + "text": "noMatchInKnowledgeGroup: '所选知识组中未找到相关内容,以下是基于模型的一般性回答:'," + }, + { + "line": 306, + "text": "uploadTextSuccess: '笔记内容已接收。正在后台索引'," + }, + { + "line": 307, + "text": "passwordChanged: '密码已成功修改'," + }, + { + "line": 308, + "text": "userCreated: '用户已成功创建'," + }, + { + "line": 309, + "text": "userInfoUpdated: '用户信息已更新'," + }, + { + "line": 310, + "text": "userDeleted: '用户已删除'," + }, + { + "line": 311, + "text": "pdfNoteTitle: 'PDF 笔记 - {date}'," + }, + { + "line": 312, + "text": "noTextExtracted: '未提取到文本'," + }, + { + "line": 313, + "text": "kbCleared: '知识库已清空'," + }, + { + "line": 314, + "text": "fileDeleted: '文件已删除'," + }, + { + "line": 315, + "text": "pageImageNotFoundDetail: '无法获取 PDF 第 {page} 页’的图像'," + }, + { + "line": 316, + "text": "groupSyncSuccess: '文件分组已更新'," + }, + { + "line": 317, + "text": "fileDeletedFromGroup: '文件已从分组中删除'," + }, + { + "line": 318, + "text": "chunkConfigCorrection: '切片配置已修正: {warnings}'," + }, + { + "line": 319, + "text": "noChunksGenerated: '文件 {id} 未生成任何切片'," + }, + { + "line": 320, + "text": "chunkCountAnomaly: '实际切片数 {actual} 大幅超过预计值 {estimated},可能存在异常'," + }, + { + "line": 321, + "text": "batchSizeExceeded: '批次 {index} 的大小 {actual} 超过推荐值 {limit},将拆分处理'," + }, + { + "line": 322, + "text": "skippingEmptyVectorChunk: '跳过文本块 {index} (空向量)'," + }, + { + "line": 323, + "text": "contextLengthErrorFallback: '批次处理发生上下文长度错误,降级到逐条处理模式'," + }, + { + "line": 324, + "text": "chunkLimitExceededForceBatch: '切片数 {actual} 超过模型批次限制 {limit},强制进行批次处理'," + }, + { + "line": 325, + "text": "noteContentRequired: '笔记内容是必填项'," + }, + { + "line": 326, + "text": "imageAnalysisStarted: '正在使用模型 {id} 分析图像...'," + }, + { + "line": 327, + "text": "batchAnalysisStarted: '正在分析 {count} 张图像...'," + }, + { + "line": 328, + "text": "pageAnalysisFailed: '第 {page} 页分析失败'," + }, + { + "line": 329, + "text": "visionSystemPrompt: '您是专业的文档分析助手。请分析此文档图像,并按以下要求以 JSON 格式返回:\\n\\n1. 提取所有可读文本(按阅读顺序,保持段落和格式)\\n2. 识别图像/图表/表格(描述内容、含义和作用)\\n3. 分析页面布局(仅文本/文本和图像混合/表格/图表等)\\n4. 评估分析质量 (0-1)\\n\\n响应格式:\\n{\\n \"text\": \"完整的文本内容\",\\n \"images\": [\\n {\"type\": \"图表类型\", \"description\": \"详细描述\", \"position\": 1}\\n ],\\n \"layout\": \"布局说明\",\\n \"confidence\": 0.95\\n}'," + }, + { + "line": 330, + "text": "visionModelCall: '[模型调用] 类型: Vision, 模型: {model}, 页面: {page}'," + }, + { + "line": 331, + "text": "visionAnalysisSuccess: '✅ 视觉分析完成: {path}{page}, 文本长度: {textLen}, 图像数: {imgCount}, 布局: {layout}, 置信度: {confidence}%'," + }, + { + "line": 332, + "text": "conversationHistoryNotFound: '对话历史不存在'," + }, + { + "line": 333, + "text": "batchContextLengthErrorFallback: '小文件批次处理发生上下文长度错误,降级到逐条处理模式'," + }, + { + "line": 334, + "text": "chunkProcessingFailed: '处理文本块 {index} 失败,已跳过: {message}'," + }, + { + "line": 335, + "text": "singleTextProcessingComplete: '逐条文本处理完成: {count} 个切片'," + }, + { + "line": 336, + "text": "fileVectorizationComplete: '文件 {id} 向量化完成。共处理 {count} 个文本块。最终内存: {memory}MB'," + }, + { + "line": 337, + "text": "fileVectorizationFailed: '文件 {id} 向量化失败'," + }, + { + "line": 338, + "text": "batchProcessingStarted: '开始批次处理: {count} 个项目'," + }, + { + "line": 339, + "text": "batchProcessingProgress: '正在处理批次 {index}/{total}: {count} 个项目'," + }, + { + "line": 340, + "text": "batchProcessingComplete: '批次处理完成: {count} 个项目,耗时 {duration}s'," + }, + { + "line": 341, + "text": "onlyFailedFilesRetryable: '仅允许重试失败的文件 (当前状态: {status})'," + }, + { + "line": 342, + "text": "emptyFileRetryFailed: '文件内容为空,无法重试。请重新上传文件。'," + }, + { + "line": 343, + "text": "ragSystemPrompt: '您是专业的知识库助手。请根据以下提供的文档内容回答用户的问题。'," + }, + { + "line": 344, + "text": "ragRules: '## 规则:\\n1. 仅根据提供的文档内容进行回答,请勿编造信息。\\n2. 如果文档中没有相关信息,请告知用户。\\n3. 请在回答中注明信息来源。格式:[文件名.扩展子]\\n4. 如果多个文档中的信息存在矛盾,请进行综合分析或解释不同的观点。\\n5. 请使用{lang}进行回答。'," + }, + { + "line": 345, + "text": "ragDocumentContent: '## 文档内容:'," + }, + { + "line": 346, + "text": "ragUserQuestion: '## 用户问题:'," + }, + { + "line": 347, + "text": "ragAnswer: '## 回答:'," + }, + { + "line": 348, + "text": "ragSource: '### 来源:{fileName}'," + }, + { + "line": 349, + "text": "ragSegment: '片段 {index} (相似度: {score}):'," + }, + { + "line": 350, + "text": "ragNoDocumentFound: '未找到相关文档。'," + }, + { + "line": 351, + "text": "queryExpansionPrompt: '您是一个搜索助手。请为以下用户查询生成3个不同的演变版本,以帮助在向量搜索中获得更好的结果。每个版本应包含不同的关键词或表达方式,但保持原始意思。直接输出3行查询,不要有数字或编号:\\n\\n查询:{query}'," + }, + { + "line": 352, + "text": "hydePrompt: '请为以下用户问题写一段简短、事实性的假设回答(约100字)。不要包含任何引导性文字(如“基于我的分析...”),直接输出答案内容。\\n\\n问题:{query}'," + }, + { + "line": 355, + "text": "searching: 'ナレッジベースを検索中...'," + }, + { + "line": 356, + "text": "noResults: '関連する知識が見つかりませんでした。一般的な知識に基づいて回答します...'," + }, + { + "line": 357, + "text": "searchFailed: 'ナレッジベース検索に失敗しました。一般的な知識に基づいて回答します...'," + }, + { + "line": 358, + "text": "generatingResponse: '回答を生成中'," + }, + { + "line": 359, + "text": "files: '個のファイル'," + }, + { + "line": 360, + "text": "notebooks: '個のノートブック'," + }, + { + "line": 361, + "text": "all: 'すべて'," + }, + { + "line": 362, + "text": "items: '件'," + }, + { + "line": 364, + "text": "relevantInfoFound: '件の関連情報が見つかりました'," + }, + { + "line": 365, + "text": "searchHits: '検索ヒット'," + }, + { + "line": 366, + "text": "relevance: '関連度'," + }, + { + "line": 367, + "text": "sourceFiles: '元ファイル'," + }, + { + "line": 368, + "text": "searchScope: '検索範囲'," + }, + { + "line": 369, + "text": "error: 'エラー'," + }, + { + "line": 370, + "text": "creatingHistory: '新規対話履歴を作成: '," + }, + { + "line": 371, + "text": "searchingModelById: 'selectedEmbeddingId に基づいてモデルを検索: '," + }, + { + "line": 372, + "text": "searchModelFallback: '指定された埋め込みモデルが見つかりません。最初に使用可能なモデルを使用します。'," + }, + { + "line": 373, + "text": "noEmbeddingModelFound: '埋め込みモデルの設定が見つかりません'," + }, + { + "line": 374, + "text": "usingEmbeddingModel: '使用する埋め込みModel: '," + }, + { + "line": 375, + "text": "startingSearch: 'ナレッジベースの検索を開始...'," + }, + { + "line": 376, + "text": "searchResultsCount: 'Search results数: '," + }, + { + "line": 377, + "text": "searchFailedLog: '検索失敗'," + }, + { + "line": 378, + "text": "chatStreamError: 'チャットストリームエラー'," + }, + { + "line": 379, + "text": "assistStreamError: 'アシストストリームエラー'," + }, + { + "line": 380, + "text": "file: 'ファイル'," + }, + { + "line": 381, + "text": "content: '内容'," + }, + { + "line": 382, + "text": "userLabel: 'ユーザー'," + }, + { + "line": 383, + "text": "assistantLabel: 'アシスタント'," + }, + { + "line": 384, + "text": "intelligentAssistant: 'あなたはインテリジェントな執筆アシスタントです。'," + }, + { + "line": 385, + "text": "searchString: '検索文字列: '," + }, + { + "line": 386, + "text": "embeddingModelIdNotProvided: 'Embedding model IDが提供されていません'," + }, + { + "line": 387, + "text": "generatingEmbeddings: '埋め込みベクトルを生成中...'," + }, + { + "line": 388, + "text": "embeddingsGenerated: '埋め込みベクトルの生成が完了しました'," + }, + { + "line": 389, + "text": "dimensions: '次元数'," + }, + { + "line": 390, + "text": "performingHybridSearch: 'ES 混合検索を実行中...'," + }, + { + "line": 391, + "text": "esSearchCompleted: 'ES 検索が完了しました'," + }, + { + "line": 392, + "text": "resultsCount: '結果数'," + }, + { + "line": 393, + "text": "hybridSearchFailed: '混合検索に失敗しました'," + }, + { + "line": 394, + "text": "getContextForTopicFailed: 'トピックのコンテキスト取得に失敗しました'," + }, + { + "line": 395, + "text": "noLLMConfigured: 'ユーザーにLLMモデルが設定されていません'," + }, + { + "line": 396, + "text": "simpleChatGenerationError: '簡易チャット生成エラー'," + }, + { + "line": 397, + "text": "noMatchInKnowledgeGroup: '選択された知識グループに関連する内容が見つかりませんでした。以下はモデルに基づく一般的な回答です:'," + }, + { + "line": 398, + "text": "uploadTextSuccess: 'ノート内容を受け取りました。バックグラウンドでインデックス処理を実行中です'," + }, + { + "line": 399, + "text": "passwordChanged: 'パスワードが正常に変更されました'," + }, + { + "line": 400, + "text": "userCreated: 'ユーザーが正常に作成されました'," + }, + { + "line": 401, + "text": "userInfoUpdated: 'ユーザー情報が更新されました'," + }, + { + "line": 402, + "text": "userDeleted: 'ユーザーが削除されました'," + }, + { + "line": 403, + "text": "pdfNoteTitle: 'PDF ノート - {date}'," + }, + { + "line": 404, + "text": "noTextExtracted: 'テキストが抽出されませんでした'," + }, + { + "line": 405, + "text": "kbCleared: 'ナレッジベースが空になりました'," + }, + { + "line": 406, + "text": "fileDeleted: 'ファイルが削除されました'," + }, + { + "line": 407, + "text": "pageImageNotFoundDetail: 'PDF の第 {page} ページの画像を取得できません'," + }, + { + "line": 408, + "text": "groupSyncSuccess: 'ファイルグループが更新されました'," + }, + { + "line": 409, + "text": "fileDeletedFromGroup: 'ファイルがグループから削除されました'," + }, + { + "line": 410, + "text": "chunkConfigCorrection: 'Chunk configurationの修正: {warnings}'," + }, + { + "line": 411, + "text": "noChunksGenerated: 'ファイル {id} からテキストチャンクが生成されませんでした'," + }, + { + "line": 412, + "text": "chunkCountAnomaly: '実際のチャンク数 {actual} が推定値 {estimated} を大幅に超えています。異常がある可能性があります'," + }, + { + "line": 413, + "text": "batchSizeExceeded: 'バッチ {index} のサイズ {actual} が推奨値 {limit} 。分割して処理します'," + }, + { + "line": 414, + "text": "skippingEmptyVectorChunk: '空ベクトルのテキストブロック {index} をスキップします'," + }, + { + "line": 415, + "text": "contextLengthErrorFallback: 'バッチ処理でコンテキスト長エラーが発生しました。単一テキスト処理モードにダウングレードします'," + }, + { + "line": 416, + "text": "chunkLimitExceededForceBatch: 'チャンク数 {actual} がモデルのバッチ制限 {limit} 。強制的にバッチ処理を行います'," + }, + { + "line": 417, + "text": "noteContentRequired: 'ノート内容は必須です'," + }, + { + "line": 418, + "text": "imageAnalysisStarted: 'モデル {id} で画像をAnalyzing...'," + }, + { + "line": 419, + "text": "batchAnalysisStarted: '{count} 枚の画像をAnalyzing...'," + }, + { + "line": 420, + "text": "pageAnalysisFailed: '第 {page} ページの分析に失敗しました'," + }, + { + "line": 421, + "text": "visionSystemPrompt: 'あなたは専門的なドキュメント分析アシスタントです。このドキュメント画像を分析し、以下の要求に従って JSON 形式で返してください:\\n\\n1. すべての読み取り可能なテキストを抽出(読み取り順序に従い、段落と形式を保持)\\n2. 画像/グラフ/表の識別(内容、意味、役割を記述)\\n3. ページレイアウトの分析(テキストのみ/テキストと画像の混合/表/グラフなど)\\n4. 分析品質の評価(0-1)\\n\\nレスポンス形式:\\n{\\n \"text\": \"完全なテキスト内容\",\\n \"images\": [\\n {\"type\": \"グラフの種類\", \"description\": \"詳細な記述\", \"position\": 1}\\n ],\\n \"layout\": \"レイアウトの説明\",\\n \"confidence\": 0.95\\n}'," + }, + { + "line": 422, + "text": "visionModelCall: '[モデル呼び出し] タイプ: Vision, Model: {model}, ページ: {page}'," + }, + { + "line": 423, + "text": "visionAnalysisSuccess: '✅ Vision 分析完了: {path}{page}, テキスト長: {textLen}文字, 画像数: {imgCount}, レイアウト: {layout}, 信頼度: {confidence}%'," + }, + { + "line": 424, + "text": "conversationHistoryNotFound: '会話履歴が存在しません'," + }, + { + "line": 425, + "text": "batchContextLengthErrorFallback: '小ファイルバッチ処理でコンテキスト長エラーが発生しました。単一テキスト処理モードにダウングレードします'," + }, + { + "line": 426, + "text": "chunkProcessingFailed: 'テキストブロック {index} の処理に失敗しました。スキップします: {message}'," + }, + { + "line": 427, + "text": "singleTextProcessingComplete: '単一テキスト処理完了: {count} チャンク'," + }, + { + "line": 428, + "text": "fileVectorizationComplete: 'ファイル {id} ベクトル化完了。{count} 個のテキストブロックを処理しました。最終メモリ: {memory}MB'," + }, + { + "line": 429, + "text": "fileVectorizationFailed: 'ファイル {id} ベクトル化失敗'," + }, + { + "line": 430, + "text": "batchProcessingStarted: 'バッチ処理を開始します: {count} アイテム'," + }, + { + "line": 431, + "text": "batchProcessingProgress: 'バッチ {index}/{total} を処理中: {count} 個のアイテム'," + }, + { + "line": 432, + "text": "batchProcessingComplete: 'バッチ処理完了: {count} アイテム, 所要時間 {duration}s'," + }, + { + "line": 433, + "text": "onlyFailedFilesRetryable: '失敗したファイルのみ再試行可能です (現在のステータス: {status})'," + }, + { + "line": 434, + "text": "emptyFileRetryFailed: 'ファイル内容が空です。再試行できません。ファイルを再アップロードしてください。'," + }, + { + "line": 435, + "text": "ragSystemPrompt: 'あなたは専門的なナレッジベースアシスタントです。以下の提供されたドキュメントの内容に基づいて、ユーザーの質問に答えてください。'," + }, + { + "line": 436, + "text": "ragRules: '## ルール:\\n1. 提供されたドキュメントの内容のみに基づいて回答し、情報を捏造しないでください。\\n2. ドキュメントに関連情報がない場合は、その旨をユーザーに伝えてください。\\n3. 回答には情報源を明記してください。形式:[ファイル名.拡張子]\\n4. 複数のドキュメントで情報が矛盾している場合は、総合的に分析するか、異なる視点を説明してください。\\n5. {lang}で回答してください。'," + }, + { + "line": 437, + "text": "ragDocumentContent: '## ドキュメント内容:'," + }, + { + "line": 438, + "text": "ragUserQuestion: '## ユーザーの質問:'," + }, + { + "line": 439, + "text": "ragAnswer: '## 回答:'," + }, + { + "line": 440, + "text": "ragSource: '### ソース:{fileName}'," + }, + { + "line": 441, + "text": "ragSegment: 'セグメント {index} (類似度: {score}):'," + }, + { + "line": 442, + "text": "ragNoDocumentFound: '関連するドキュメントが見つかりませんでした。'," + }, + { + "line": 443, + "text": "queryExpansionPrompt: 'あなたは検索アシスタントです。以下のユーザーのクエリに対して、ベクトル検索でより良い結果を得るために、3つの異なるバリエーションを生成してください。各バリエーションは異なるキーワードや表現を使用しつつ、元の意味を維持する必要があります。数字やプレフィックスなしで、3行のクエリを直接出力してください:\\n\\nクエリ:{query}'," + }, + { + "line": 444, + "text": "hydePrompt: '以下のユーザーの質問に対して、簡潔で事実に基づいた仮説的な回答(約200文字)を書いてください。「私の分析によると...」などの導入文は含めず、回答内容のみを直接出力してください。\\n\\n質問:{query}'," + } + ], + "d:\\workspace\\AuraK\\server\\src\\knowledge-base\\chunk-config.service.ts": [ + { + "line": 76, + "text": "const providerName = modelConfig.providerName || '不明';" + }, + { + "line": 81, + "text": "` - プロバイダー: ${providerName}\\n` +" + }, + { + "line": 82, + "text": "` - Token制限: ${maxInputTokens}\\n` +" + }, + { + "line": 85, + "text": "` - ベクトルモデルか: ${isVectorModel}`," + }, + { + "line": 294, + "text": "`Chunk size: ${chunkSize} tokens (制限: ${limits.maxInputTokens})`," + }, + { + "line": 295, + "text": "`重なりサイズ: ${chunkOverlap} tokens`," + }, + { + "line": 296, + "text": "`バッチサイズ: ${limits.maxBatchSize}`," + } + ] +} \ No newline at end of file diff --git a/cjk_files.txt b/cjk_files.txt new file mode 100644 index 0000000..0a738ef --- /dev/null +++ b/cjk_files.txt @@ -0,0 +1,50 @@ +d:\workspace\AuraK\web\components\GroupSelector.tsx +d:\workspace\AuraK\web\services\chunkConfigService.ts +d:\workspace\AuraK\web\services\geminiService.ts +d:\workspace\AuraK\web\services\knowledgeGroupService.ts +d:\workspace\AuraK\web\services\pdfPreviewService.ts +d:\workspace\AuraK\web\services\ragService.ts +d:\workspace\AuraK\web\services\searchHistoryService.ts +d:\workspace\AuraK\web\services\uploadService.ts +d:\workspace\AuraK\web\src\utils\toast.ts +d:\workspace\AuraK\web\types.ts +d:\workspace\AuraK\server\src\ai\embedding.service.ts +d:\workspace\AuraK\server\src\api\api.controller.ts +d:\workspace\AuraK\server\src\api\api.service.ts +d:\workspace\AuraK\server\src\chat\chat.controller.ts +d:\workspace\AuraK\server\src\chat\chat.service.ts +d:\workspace\AuraK\server\src\common\constants.ts +d:\workspace\AuraK\server\src\elasticsearch\elasticsearch.service.ts +d:\workspace\AuraK\server\src\i18n\i18n.service.ts +d:\workspace\AuraK\server\src\i18n\messages.ts +d:\workspace\AuraK\server\src\knowledge-base\chunk-config.service.ts +d:\workspace\AuraK\server\src\knowledge-base\embedding.service.ts +d:\workspace\AuraK\server\src\knowledge-base\knowledge-base.controller.ts +d:\workspace\AuraK\server\src\knowledge-base\knowledge-base.entity.ts +d:\workspace\AuraK\server\src\knowledge-base\knowledge-base.service.ts +d:\workspace\AuraK\server\src\knowledge-base\memory-monitor.service.ts +d:\workspace\AuraK\server\src\knowledge-base\text-chunker.service.ts +d:\workspace\AuraK\server\src\libreoffice\libreoffice.interface.ts +d:\workspace\AuraK\server\src\libreoffice\libreoffice.service.ts +d:\workspace\AuraK\server\src\migrations\1737800000000-AddKnowledgeBaseEnhancements.ts +d:\workspace\AuraK\server\src\model-config\dto\create-model-config.dto.ts +d:\workspace\AuraK\server\src\model-config\model-config.entity.ts +d:\workspace\AuraK\server\src\model-config\model-config.service.ts +d:\workspace\AuraK\server\src\pdf2image\pdf2image.interface.ts +d:\workspace\AuraK\server\src\pdf2image\pdf2image.service.ts +d:\workspace\AuraK\server\src\rag\rag.service.ts +d:\workspace\AuraK\server\src\rag\rerank.service.ts +d:\workspace\AuraK\server\src\search-history\search-history.controller.ts +d:\workspace\AuraK\server\src\search-history\search-history.service.ts +d:\workspace\AuraK\server\src\upload\upload.controller.ts +d:\workspace\AuraK\server\src\upload\upload.module.ts +d:\workspace\AuraK\server\src\user\user.controller.ts +d:\workspace\AuraK\server\src\user\user.entity.ts +d:\workspace\AuraK\server\src\user\user.service.ts +d:\workspace\AuraK\server\src\user-setting\user-setting.entity.ts +d:\workspace\AuraK\server\src\user-setting\user-setting.service.ts +d:\workspace\AuraK\server\src\vision\vision.interface.ts +d:\workspace\AuraK\server\src\vision\vision.service.ts +d:\workspace\AuraK\server\src\vision-pipeline\cost-control.service.ts +d:\workspace\AuraK\server\src\vision-pipeline\vision-pipeline-cost-aware.service.ts +d:\workspace\AuraK\server\src\vision-pipeline\vision-pipeline.interface.ts \ No newline at end of file diff --git a/clean_translations.js b/clean_translations.js new file mode 100644 index 0000000..0ef4140 --- /dev/null +++ b/clean_translations.js @@ -0,0 +1,184 @@ + +const fs = require('fs'); +const path = require('path'); + +const filePath = process.argv[2]; + +if (!filePath) { + console.error('Please provide a file path'); + process.exit(1); +} + +const content = fs.readFileSync(filePath, 'utf8'); + +// These are missing keys that we want to ensure exist in each language block +const missingKeysData = { + kbSettingsSaved: { zh: "检索与对话配置已保存", en: "Knowledge base settings saved", ja: "設定を保存しました" }, + failedToSaveSettings: { zh: "保存设置失败", en: "Failed to save settings", ja: "設定の保存に失敗しました" }, + actionFailed: { zh: "操作失败", en: "Action failed", ja: "操作に失敗しました" }, + userAddedToOrganization: { zh: "用户已添加到组织", en: "User added to organization", ja: "ユーザーが組織に追加されました" }, + featureUpdated: { zh: "功能已更新", en: "Feature updated", ja: "機能が更新されました" }, + roleTenantAdmin: { zh: "租户管理员", en: "Tenant Administrator", ja: "テナント管理者" }, + roleRegularUser: { zh: "普通用户", en: "Regular User", ja: "一般ユーザー" }, + creatingRegularUser: { zh: "正在创建普通用户", en: "Creating regular user", ja: "一般ユーザーを作成中" }, + editUserRole: { zh: "修改用户角色", en: "Edit user role", ja: "ユーザーロールを編集" }, + targetRole: { zh: "目标角色", en: "Target Role", ja: "対象のロール" }, + editCategory: { zh: "编辑分类", en: "Edit category", ja: "カテゴリを編集" }, + totalTenants: { zh: "总租户数", en: "Total Tenants", ja: "総テナント数" }, + systemUsers: { zh: "系统用户", en: "System Users", ja: "システムユーザー" }, + systemHealth: { zh: "系统健康", en: "System Health", ja: "システムヘルス" }, + operational: { zh: "运行正常", en: "Operational", ja: "正常稼働中" }, + orgManagement: { zh: "组织管理", en: "Organization Management", ja: "組織管理" }, + globalTenantControl: { zh: "全局租户控制", en: "Global Tenant Control", ja: "グローバルテナントコントロール" }, + newTenant: { zh: "新租户", en: "New Tenant", ja: "新規テナント" }, + domainOptional: { zh: "域名 (可选)", en: "Domain (Optional)", ja: "ドメイン (任意)" }, + saveChanges: { zh: "保存修改", en: "Save changes", ja: "変更を保存" }, + modelConfiguration: { zh: "模型配置", en: "Model Configuration", ja: "モデル設定" }, + defaultLLMModel: { zh: "默认推理模型", en: "Default LLM Model", ja: "デフォルト推論モデル" }, + selectLLM: { zh: "选择 LLM", en: "Select LLM", ja: "LLMを選択" }, + selectEmbedding: { zh: "选择 Embedding", en: "Select Embedding", ja: "埋め込みを選択" }, + rerankModel: { zh: "Rerank 模型", en: "Rerank Model", ja: "リランクモデル" }, + none: { zh: "无", en: "None", ja: "なし" }, + indexingChunkingConfig: { zh: "索引与切片配置", en: "Indexing & Chunking Config", ja: "インデックスとチャンク設定" }, + chatHyperparameters: { zh: "聊天超参数", en: "Chat Hyperparameters", ja: "チャットハイパーパラメータ" }, + temperature: { zh: "随机性 (Temperature)", en: "Temperature", ja: "温度" }, + precise: { zh: "精确", en: "Precise", ja: "精密" }, + creative: { zh: "创意", en: "Creative", ja: "クリエイティブ" }, + maxResponseTokens: { zh: "最大响应标识 (Max Tokens)", en: "Max Response Tokens", ja: "最大応答トークン数" }, + retrievalSearchSettings: { zh: "检索与搜索设置", en: "Retrieval & Search Settings", ja: "検索設定" }, + topK: { zh: "召回数量 (Top K)", en: "Top K", ja: "Top K" }, + similarityThreshold: { zh: "相似度阈值", en: "Similarity Threshold", ja: "類似度しきい値" }, + enableHybridSearch: { zh: "启用混合检索", en: "Enable Hybrid Search", ja: "ハイブリッド検索を有効にする" }, + hybridSearchDesc: { zh: "同时使用向量和全文检索以提高召回率", en: "Use both vector and full-text search to improve recall", ja: "ベクトル検索と全文検索を併用して検索精度を向上させます" }, + hybridWeight: { zh: "混合权重 (0.0=全文, 1.0=向量)", en: "Hybrid Weight (0.0=Fulltext, 1.0=Vector)", ja: "ハイブリッド重み (0.0=全文, 1.0=ベクトル)" }, + pureText: { zh: "纯文本", en: "Pure Text", ja: "純粋なテキスト" }, + pureVector: { zh: "纯向量", en: "Pure Vector", ja: "純粋なベクトル" }, + enableQueryExpansion: { zh: "启用查询扩展", en: "Enable Query Expansion", ja: "クエリ拡張を有効にする" }, + queryExpansionDesc: { zh: "生成多个查询变体以提高覆盖率", en: "Generate multiple query variations for better coverage", ja: "複数のクエリバリアントを生成してカバレッジを向上させます" }, + enableHyDE: { zh: "启用 HyDE", en: "Enable HyDE", ja: "HyDEを有効にする" }, + hydeDesc: { zh: "生成假设回答以改善语义搜索", en: "Generate hypothetical answers to improve semantic search", ja: "仮想的な回答を生成してセマンティック検索を改善します" }, + enableReranking: { zh: "启用重排序 (Rerank)", en: "Enable Reranking", ja: "リランクを有効にする" }, + rerankingDesc: { zh: "使用 Rerank 模型对结果进行二次排序", en: "Use Rerank model to re-sort results", ja: "リランクモデルを使用して結果を再ソートします" }, + broad: { zh: "宽泛", en: "Broad", ja: "広範" }, + strict: { zh: "严格", en: "Strict", ja: "厳格" }, + maxInput: { zh: "最大输入", en: "Max Input", ja: "最大入力" }, + dimensions: { zh: "维度", en: "Dimensions", ja: "次元" }, + defaultBadge: { zh: "默认", en: "Default", ja: "デフォルト" }, + dims: { zh: "维度: $1", en: "Dims: $1", ja: "次元: $1" }, + ctx: { zh: "上下文: $1", en: "Ctx: $1", ja: "コンテキスト: $1" }, + baseApi: { zh: "Base API: $1", en: "Base API: $1", ja: "Base API: $1" }, + configured: { zh: "已配置", en: "Configured", ja: "設定済み" }, + groupUpdated: { zh: "分组已更新", en: "Group updated", ja: "グループが更新されました" }, + groupDeleted: { zh: "分组已删除", en: "Group deleted", ja: "グループが削除されました" }, + groupCreated: { zh: "分组已创建", en: "Group created", ja: "グループが作成されました" }, + navCatalog: { zh: "目录", en: "Catalog", ja: "カタログ" }, + allDocuments: { zh: "所有文档", en: "All Documents", ja: "すべてのドキュメント" }, + categories: { zh: "分类", en: "Categories", ja: "カテゴリ" }, + uncategorizedFiles: { zh: "未分类文件", en: "Uncategorized Files", ja: "未分類ファイル" }, + category: { zh: "分类", en: "Category", ja: "カテゴリ" }, + statusReadyDesc: { zh: "已索引可查询", en: "Indexed and searchable", ja: "インデックス済みで検索可能" }, + statusIndexingDesc: { zh: "正在建立词向量索引", en: "Building vector index", ja: "ベクトルインデックスを作成中" }, + selectCategory: { zh: "选择分类", en: "Select Category", ja: "カテゴリを選択" }, + noneUncategorized: { zh: "无未分类文件", en: "No uncategorized files", ja: "未分類ファイルなし" }, + previous: { zh: "上一页", en: "Previous", ja: "前へ" }, + next: { zh: "下一页", en: "Next", ja: "次へ" }, + createCategory: { zh: "创建分类", en: "Create Category", ja: "カテゴリを作成" }, + categoryDesc: { zh: "描述您的知识分类", en: "Describe your knowledge category", ja: "ナレッジカテゴリを説明します" }, + categoryName: { zh: "分类名称", en: "Category Name", ja: "カテゴリ名" }, + createCategoryBtn: { zh: "立即创建", en: "Create Now", ja: "今すぐ作成" }, + newGroup: { zh: "新建分组", en: "New Group", ja: "新規グループ" }, + noKnowledgeGroups: { zh: "暂无知识库分组", en: "No knowledge groups yet", ja: "ナレッジグループがまだありません" }, + createGroupDesc: { zh: "开始创建您的第一个知识库分组并上传相关文档。", en: "Start by creating your first knowledge group and uploading documents.", ja: "最初のナレッジグループを作成してドキュメントをアップロードしてください。" }, + noDescriptionProvided: { zh: "未提供描述", en: "No description provided", ja: "説明なし" }, + browseManageFiles: { zh: "浏览并管理该分组下的文件和笔记。", en: "Browse and manage files and notes in this group.", ja: "このグループ内のファイルとメモを閲覧・管理します。" }, + filterGroupFiles: { zh: "根据名称搜索分组内文件...", en: "Search files in group by name...", ja: "名前でグループ内のファイルを検索..." }, + generalSettingsSubtitle: { zh: "管理您的应用程序首选项。", en: "Manage your application preferences.", ja: "アプリケーションの設定を管理します。" }, + userManagementSubtitle: { zh: "管理访问权限和帐户。", en: "Manage access and accounts.", ja: "アクセス権限とアカウントを管理します。" }, + modelManagementSubtitle: { zh: "配置全局 AI 模型。", en: "Configure global AI models.", ja: "グローバルなAIモデルを設定します。" }, + kbSettingsSubtitle: { zh: "索引和聊天参数的技术配置。", en: "Technical configuration for indexing and chat parameters.", ja: "インデックス作成とチャットパラメータの技術設定。" }, + tenantsSubtitle: { zh: "全局系统概览。", en: "Global system overview.", ja: "グローバルシステムの概要。" }, + allNotes: { zh: "所有笔记", en: "All Notes", ja: "すべてのノート" }, + filterNotesPlaceholder: { zh: "筛选笔记...", en: "Filter notes...", ja: "ノートをフィルタリング..." }, + noteTitlePlaceholder: { zh: "标题...", en: "Title...", ja: "タイトル..." }, + startWritingPlaceholder: { zh: "开始写作...", en: "Start writing...", ja: "書き始める..." }, + previewHeader: { zh: "预览", en: "Preview", ja: "プレビュー" }, + noContentToPreview: { zh: "没有可预览的内容", en: "No content to preview", ja: "プレビューするコンテンツがありません" }, + hidePreview: { zh: "隐藏预览", en: "Hide Preview", ja: "プレビューを非表示" }, + showPreview: { zh: "显示预览", en: "Show Preview", ja: "プレビューを表示" }, + directoryLabel: { zh: "目录", en: "Directory", ja: "ディレクトリ" }, + uncategorized: { zh: "未分类", en: "Uncategorized", ja: "未分類" }, + enterNamePlaceholder: { zh: "输入名称...", en: "Enter name...", ja: "名前を入力..." }, + subFolderPlaceholder: { zh: "子文件夹...", en: "Sub-folder...", ja: "サブフォルダ..." }, + categoryCreated: { zh: "分类已创建", en: "Category created", ja: "カテゴリが作成されました" }, + failedToCreateCategory: { zh: "创建分类失败", en: "Failed to create category", ja: "カテゴリの作成に失敗しました" }, + failedToDeleteCategory: { zh: "删除分类失败", en: "Failed to delete category", ja: "カテゴリの削除に失敗しました" }, + confirmDeleteCategory: { zh: "您确定要删除此分类吗?", en: "Are you sure you want to delete this category?", ja: "このカテゴリを削除してもよろしいですか?" } +}; + +const lines = content.split('\n'); +let currentLang = null; +let resultLines = []; +let keysSeen = new Set(); + +const langStartRegex = /^\s+(\w+): \{/; +const keyRegex = /^\s+([a-zA-Z0-9_-]+):/; + +for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + + const langMatch = line.match(langStartRegex); + if (langMatch) { + // If we were in a language block, append missing keys before finishing it + if (currentLang) { + addMissingKeys(currentLang, resultLines, keysSeen); + } + currentLang = langMatch[1]; + keysSeen = new Set(); + resultLines.push(line); + continue; + } + + if (currentLang) { + const keyMatch = line.match(keyRegex); + if (keyMatch) { + const key = keyMatch[1]; + if (keysSeen.has(key)) { + // Duplicate key, skip it + continue; + } + keysSeen.add(key); + } + + // If the line ends the block + if (line.trim() === '},') { + addMissingKeys(currentLang, resultLines, keysSeen); + currentLang = null; + resultLines.push(line); + continue; + } + + // Also handle the very last block which might not have a comma + if (line.trim() === '}' && i > lines.length - 5) { + addMissingKeys(currentLang, resultLines, keysSeen); + currentLang = null; + resultLines.push(line); + continue; + } + } + + resultLines.push(line); +} + +function addMissingKeys(lang, targetLines, seen) { + for (const [key, translations] of Object.entries(missingKeysData)) { + if (!seen.has(key)) { + const val = translations[lang] || translations['en'] || key; + const escapedVal = JSON.stringify(val); + targetLines.push(` ${key}: ${escapedVal},`); + seen.add(key); + } + } +} + +fs.writeFileSync(filePath, resultLines.join('\n'), 'utf8'); +console.log('Translations file cleaned and updated successfully!'); diff --git a/clean_translations.py b/clean_translations.py new file mode 100644 index 0000000..cc9b9c7 --- /dev/null +++ b/clean_translations.py @@ -0,0 +1,87 @@ + +import sys +import re + +def clean_translations(file_path): + with open(file_path, 'r', encoding='utf-8') as f: + content = f.read() + + # Split into blocks + blocks = re.split(r'(\s+\w+: \{)', content) + # Header is blocks[0] + # Then blocks[1] is " zh: {", blocks[2] is content of zh + # blocks[3] is " en: {", blocks[4] is content of en + # blocks[5] is " ja: {", blocks[6] is content of ja + + header = blocks[0] + processed_blocks = [] + + # Missing keys to ensure (with basic English values) + missing_keys = [ + "kbSettingsSaved", "failedToSaveSettings", "actionFailed", "userAddedToOrganization", + "featureUpdated", "roleTenantAdmin", "roleRegularUser", "creatingRegularUser", + "editUserRole", "targetRole", "editCategory", "totalTenants", "systemUsers", + "systemHealth", "operational", "orgManagement", "globalTenantControl", + "newTenant", "domainOptional", "saveChanges", "modelConfiguration", + "defaultLLMModel", "selectLLM", "selectEmbedding", "rerankModel", "none", + "indexingChunkingConfig", "chatHyperparameters", "temperature", "precise", + "creative", "maxResponseTokens", "retrievalSearchSettings", "topK", + "similarityThreshold", "enableHybridSearch", "hybridSearchDesc", "hybridWeight", + "pureText", "pureVector", "enableQueryExpansion", "queryExpansionDesc", + "enableHyDE", "hydeDesc", "enableReranking", "rerankingDesc", "broad", + "strict", "maxInput", "dimensions", "defaultBadge", "dims", "ctx", + "baseApi", "configured", "groupUpdated", "groupDeleted", "groupCreated", + "navCatalog", "allDocuments", "categories", "uncategorizedFiles", "category", + "statusReadyDesc", "statusIndexingDesc", "selectCategory", "noneUncategorized", + "previous", "next", "createCategory", "categoryDesc", "categoryName", + "createCategoryBtn", "newGroup", "noKnowledgeGroups", "createGroupDesc", + "noDescriptionProvided", "browseManageFiles", "filterGroupFiles" + ] + + for i in range(1, len(blocks), 2): + block_header = blocks[i] + block_content = blocks[i+1] + + # Parse keys and values + lines = block_content.split('\n') + keys_seen = set() + new_lines = [] + + # Regex to match "key: value," or "key: `value`," + # Support multiline strings too? Let's be careful. + # Most are single line: " key: \"value\"," + + for line in lines: + match = re.search(r'^\s+([a-zA-Z0-9_-]+):', line) + if match: + key = match.group(1) + if key in keys_seen: + continue # Skip duplicate + keys_seen.add(key) + new_lines.append(line) + + # Add missing keys if they are not in keys_seen + # Remove trailing " }," or "}," to append + if new_lines and re.search(r'^\s+},?$', new_lines[-1]): + last_line = new_lines.pop() + elif new_lines and re.search(r'^\s+},?$', new_lines[-2]): # Check if last is empty + last_line = new_lines.pop(-2) + else: + last_line = " }," + + for key in missing_keys: + if key not in keys_seen: + # Add a descriptive placeholder or common translation + val = f'"{key}"' # Default to key name + new_lines.append(f' {key}: {val},') + + new_lines.append(last_line) + processed_blocks.append(block_header + '\n'.join(new_lines)) + + new_content = header + ''.join(processed_blocks) + + with open(file_path, 'w', encoding='utf-8') as f: + f.write(new_content) + +if __name__ == "__main__": + clean_translations(sys.argv[1]) diff --git a/deploy.sh b/deploy.sh new file mode 100644 index 0000000..255a453 --- /dev/null +++ b/deploy.sh @@ -0,0 +1,43 @@ +#!/bin/bash +set -e + +# 进入脚本所在目录(确保和 docker-compose.yml 在同一目录) +cd "$(dirname "$0")" + +echo "=======================================================" +echo "开始在服务器上拉取镜像并一键部署" +echo "=======================================================" + +echo ">> 正在从阿里云镜像库拉取最新的 server 和 web 镜像..." +# 如果拉取需要密码,请确保服务器上已经执行过 docker login +if ! docker pull registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest; then + echo "拉取 server 镜像失败!请确保服务器已登录 registry.cn-qingdao.aliyuncs.com" + exit 1 +fi + +if ! docker pull registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest; then + echo "拉取 web 镜像失败!请确保服务器已登录 registry.cn-qingdao.aliyuncs.com" + exit 1 +fi + +echo ">> 为了让 docker-compose 能直接使用拉取的镜像,重新标记(Tag)镜像..." +docker tag registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest aurak-server:latest 2>/dev/null || true +docker tag registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest aurak-web:latest 2>/dev/null || true + +# 因为 docker-compose 没有指定 image,会默认通过文件夹名字或我们指定的标签运行 +# 如果 docker-compose 仍然会去找默认名字,我们需要让环境变量里的 image 为我们拉取的, +# 不过最简单的方式是,通过环境变量临时覆盖,或者使用 docker compose up 的特性 +# 但既然不能改 docker-compose.yml,我们可以通过 IMAGE_NAME 环境变量来覆盖吗?没有设定的话不行。 +# 所以我们可以通过 docker tag 来把阿里云的镜像打成 docker-compose.yml 默认预期的服务名字 +# 如果目录叫 AuraK,docker-compose 默认生成的镜像名叫 aurak-server 和 aurak-web +docker tag registry.cn-qingdao.aliyuncs.com/fzxs/aurak-server:latest aurak-server 2>/dev/null || true +docker tag registry.cn-qingdao.aliyuncs.com/fzxs/aurak-web:latest aurak-web 2>/dev/null || true + +echo ">> 正在重新创建并启动容器..." +# --no-build 确保在服务器上不会意外使用本地代码触发构建 +docker compose up -d --no-build server web + +echo "=======================================================" +echo "部署完成!当前服务运行状态:" +docker compose ps +echo "=======================================================" diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..549e3c1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,118 @@ +services: + es: + image: elasticsearch:9.2.1 + container_name: aurak-es + environment: + - discovery.type=single-node + - xpack.security.enabled=false + - "ES_JAVA_OPTS=-Xms512m -Xmx512m" + ports: + - "9200:9200" + volumes: + - es-data:/usr/share/elasticsearch/data + networks: + - aurak-network + # restart: unless-stopped + + tika: + image: apache/tika:latest + container_name: aurak-tika + ports: + - "9998:9998" + networks: + - aurak-network + restart: unless-stopped + + libreoffice: + build: + context: ./libreoffice-server + dockerfile: Dockerfile + container_name: aurak-libreoffice + ports: + - "8100:8100" + volumes: + - ./uploads:/app/uploads + - ./temp:/temp + networks: + - aurak-network + restart: unless-stopped + # ollama: + # image: ollama/ollama:latest + # container_name: aurak-ollama + # ports: + # - "11434:11434" + # environment: + # - OLLAMA_CPU_ONLY=1 + # volumes: + # - ollama-data:/root/.ollama + # networks: + # - aurak-network + # restart: unless-stopped + # entrypoint: ["/bin/sh", "-c"] + # command: > + # "ollama serve & + # sleep 10 && + # ollama pull qwen2.5:3b && + # ollama pull nomic-embed-text:latest && + # ollama pull llava-phi3:3.8b && + # echo 'All models pulled successfully!' && + # wait" + + server: + build: + context: ./server + dockerfile: Dockerfile + container_name: aurak-server + environment: + - NODE_ENV=production + - NODE_OPTIONS=--max-old-space-size=8192 + - PORT=3001 + - DATABASE_PATH=/app/data/metadata.db + - ELASTICSEARCH_HOST=http://es:9200 + - TIKA_HOST=http://tika:9998 + - LIBREOFFICE_URL=http://libreoffice:8100 + - JWT_SECRET=13405a7d-742a-41f5-8b34-012735acffea + - UPLOAD_FILE_PATH=/app/uploads + - DEFAULT_VECTOR_DIMENSIONS=2048 + - TEMP_DIR=/app/temp + - CHUNK_BATCH_SIZE=50 + volumes: + - ./data:/app/data + - ./uploads:/app/uploads + - ./temp:/app/temp + depends_on: + - es + - tika + - libreoffice + # restart: unless-stopped + networks: + - aurak-network + + web: + build: + context: . + dockerfile: ./web/Dockerfile + args: + - VITE_API_BASE_URL=/api + container_name: aurak-web + depends_on: + - server + ports: + - "80:80" + - "443:443" + volumes: + - ./nginx/conf.d:/etc/nginx/conf.d + networks: + - aurak-network + +networks: + aurak-network: + driver: bridge + +volumes: + es-data: + driver: local + ollama-data: + driver: local + aurak-data: + driver: local diff --git a/docs/1.0/API.md b/docs/1.0/API.md new file mode 100644 index 0000000..2fd758e --- /dev/null +++ b/docs/1.0/API.md @@ -0,0 +1,444 @@ +# API リファレンス + +## 基本情報 + +- **ベース URL**: `http://localhost:3000` +- **認証方式**: JWT Bearer トークン +- **Content-Type**: `application/json` + +## 認証 API + +### ユーザー登録 + +```http +POST /auth/register +Content-Type: application/json + +{ + "username": "string", + "password": "string" +} +``` + +**レスポンス**: + +```json +{ + "message": "ユーザーが正常に作成されました", + "user": { + "id": "string", + "username": "string", + "isAdmin": false + } +} +``` + +### ユーザーログイン + +```http +POST /auth/login +Content-Type: application/json + +{ + "username": "string", + "password": "string" +} +``` + +**レスポンス**: + +```json +{ + "access_token": "jwt_token_string", + "user": { + "id": "string", + "username": "string", + "isAdmin": false + } +} +``` + +### パスワード変更 + +```http +POST /auth/change-password +Authorization: Bearer +Content-Type: application/json + +{ + "currentPassword": "string", + "newPassword": "string" +} +``` + +## モデル設定 API + +### モデル一覧の取得 + +```http +GET /model-configs +Authorization: Bearer +``` + +**レスポンス**: + +```json +[ + { + "id": "string", + "name": "string", + "provider": "openai|gemini", + "modelId": "string", + "baseUrl": "string", + "type": "llm|embedding|rerank", + "supportsVision": boolean + } +] +``` + +### モデル設定の作成 + +```http +POST /model-configs +Authorization: Bearer +Content-Type: application/json + +{ + "name": "string", + "provider": "openai|gemini", + "modelId": "string", + "baseUrl": "string", + "apiKey": "string", + "type": "llm|embedding|rerank", + "supportsVision": boolean +} +``` + +### モデル設定の更新 + +```http +PUT /model-configs/:id +Authorization: Bearer +Content-Type: application/json + +{ + "name": "string", + "apiKey": "string", + // ... その他のフィールド +} +``` + +### モデル設定の削除 + +```http +DELETE /model-configs/:id +Authorization: Bearer +``` + +## ナレッジベース API + +### ファイルのアップロード + +```http +POST /upload +Authorization: Bearer +Content-Type: multipart/form-data + +{ + "file": File, + "chunkSize": number, + "chunkOverlap": number, + "embeddingModelId": "string", + "mode": "fast|precise" // 処理モード +} +``` + +**レスポンス**: + +```json +{ + "id": "string", + "name": "string", + "originalName": "string", + "size": number, + "mimetype": "string", + "status": "pending|indexing|completed|failed" +} +``` + +### ファイル一覧の取得 + +```http +GET /knowledge-bases +Authorization: Bearer +``` + +**レスポンス**: + +```json +[ + { + "id": "string", + "name": "string", + "originalName": "string", + "size": number, + "mimetype": "string", + "status": "pending|indexing|completed|failed", + "createdAt": "datetime" + } +] +``` + +### ファイルの削除 + +```http +DELETE /knowledge-bases/:id +Authorization: Bearer +``` + +### ナレッジベースの全消去 + +```http +DELETE /knowledge-bases/clear +Authorization: Bearer +``` + +## チャット API + +### ストリーミングチャット + +```http +POST /chat/stream +Authorization: Bearer +Content-Type: application/json + +{ + "message": "string", + "history": [ + { + "role": "user|assistant", + "content": "string" + } + ], + "userLanguage": "zh|en|ja" +} +``` + +**レスポンス**: Server-Sent Events (SSE) + +``` +data: {"type": "content", "data": "ナレッジベースを検索中..."} + +data: {"type": "content", "data": "関連情報が見つかりました..."} + +data: {"type": "content", "data": "回答内容の断片"} + +data: {"type": "sources", "data": [ + { + "fileName": "string", + "content": "string", + "score": number, + "chunkIndex": number + } +]} + +data: [DONE] +``` + +## ユーザー設定 API + +### ユーザー設定の取得 + +```http +GET /user-settings +Authorization: Bearer +``` + +**レスポンス**: + +```json +{ + "selectedLLMId": "string", + "selectedEmbeddingId": "string", + "selectedRerankId": "string", + "temperature": number, + "maxTokens": number, + "topK": number, + "enableRerank": boolean, + "similarityThreshold": number, + "enableFullTextSearch": boolean, + "language": "zh|en|ja" +} +``` + +### ユーザー設定の更新 + +```http +PUT /user-settings +Authorization: Bearer +Content-Type: application/json + +{ + "selectedLLMId": "string", + "temperature": number, + "maxTokens": number, + // ... その他の設定フィールド +} +``` + +## Vision Pipeline API + +### 推奨モードの取得 + +```http +GET /api/vision/recommend-mode?file=xxx&size=xxx +Authorization: Bearer +``` + +**レスポンス**: + +```json +{ + "recommendedMode": "precise", + "reason": "ファイルサイズが大きいため、高精度モードを推奨します", + "estimatedCost": 0.5, + "estimatedTime": 60, + "warnings": ["処理時間が長くなる可能性があります", "API 利用料が発生します"] +} +``` + +### LibreOffice 変換サービス + +```http +POST /libreoffice/convert +Content-Type: multipart/form-data + +{ + "file": File +} +``` + +**レスポンス**: + +```json +{ + "pdf_path": "/uploads/document.pdf", + "converted": true, + "original": "document.docx", + "file_size": 102400 +} +``` + +### ヘルスチェック + +```http +GET /libreoffice/health +``` + +**レスポンス**: + +```json +{ + "status": "healthy", + "service": "libreoffice-converter", + "version": "1.0.0", + "uptime": 3600.5 +} +``` + +## ユーザー管理 API (管理者用) + +### ユーザー一覧の取得 + +```http +GET /users +Authorization: Bearer +``` + +### ユーザーの作成 + +```http +POST /users +Authorization: Bearer +Content-Type: application/json + +{ + "username": "string", + "password": "string", + "isAdmin": boolean +} +``` + +### ユーザーの削除 + +```http +DELETE /users/:id +Authorization: Bearer +``` + +## エラーレスポンス形式 + +```json +{ + "statusCode": number, + "message": "string", + "error": "string" +} +``` + +## ステータスコードの説明 + +- `200` - 成功 +- `201` - 作成成功 +- `400` - リクエストパラメータの不正 +- `401` - 認証エラー / トークン無効 +- `403` - 権限不足 +- `404` - リソースが見つかりません +- `409` - リソースの競合 +- `500` - サーバー内部エラー + +## 実装例 + +### JavaScript/TypeScript + +```javascript +// ログイン +const loginResponse = await fetch('/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + username: 'user', + password: 'password' + }) +}); + +const { access_token } = await loginResponse.json(); + +// ファイル一覧の取得 +const filesResponse = await fetch('/knowledge-bases', { + headers: { + 'Authorization': `Bearer ${access_token}` + } +}); + +const files = await filesResponse.json(); + +// ストリーミングチャット +const chatResponse = await fetch('/chat/stream', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${access_token}`, + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + message: 'こんにちは', + history: [], + userLanguage: 'ja' + }) +}); + +const reader = chatResponse.body.getReader(); +// SSE ストリームの処理... +``` diff --git a/docs/1.0/CHUNK_SIZE_LIMITS.md b/docs/1.0/CHUNK_SIZE_LIMITS.md new file mode 100644 index 0000000..d5e3eeb --- /dev/null +++ b/docs/1.0/CHUNK_SIZE_LIMITS.md @@ -0,0 +1,361 @@ +# チャンクサイズの制限に関する完全スキーム + +## 🎯 設計目標 + +**主要な問題の解決:** + +1. ✅ チャンクサイズがモデルの入力制限を超えないようにする +2. ✅ 環境変数でグローバルな上限を設定可能にする +3. ✅ フロントエンドのスライダーで動的に制限し、上限を超えられないようにする +4. ✅ バックエンドで自動検証と調整を行う + +--- + +## 📋 設定階層構造 + +``` +┌─────────────────────────────────────────┐ +│ 環境変数の設定 (server/.env) │ +│ MAX_CHUNK_SIZE=8191 │ +│ MAX_OVERLAP_SIZE=200 │ +└─────────────────────────────────────────┘ + ↓ 優先度1(最も厳格) +┌─────────────────────────────────────────┐ +│ モデル制限設定 (ChunkConfigService) │ +│ OpenAI: 8191 tokens │ +│ Gemini: 2048 tokens │ +└─────────────────────────────────────────┘ + ↓ 優先度2 +┌─────────────────────────────────────────┐ +│ ユーザー設定 (フロントエンドスライダー)│ +│ chunkSize: 200 tokens │ +│ chunkOverlap: 40 tokens │ +└─────────────────────────────────────────┘ + ↓ 最終検証 +┌─────────────────────────────────────────┐ +│ 実際に適用される値 (自動調整) │ +└─────────────────────────────────────────┘ +``` + +--- + +## 🔧 環境変数の設定 + +### server/.env + +```env +# チャンクサイズの上限 (tokens) +# 使用する埋め込みモデルに合わせて設定 +# OpenAI text-embedding-3-large: 8191 +# OpenAI text-embedding-3-small: 8191 +# Google Gemini embedding-001: 2048 +MAX_CHUNK_SIZE=8191 + +# チャンクオーバーラップの上限 (tokens) +# チャンクサイズの 10-20% を推奨 +MAX_OVERLAP_SIZE=200 +``` + +--- + +## 🏗️ アーキテクチャの実装 + +### 1. ChunkConfigService (バックエンドコア) + +```typescript +// 環境変数から上限を読み込む +private readonly envMaxChunkSize: number; +private readonly envMaxOverlapSize: number; + +// 主要なモデルの制限 +private readonly MODEL_LIMITS = { + 'text-embedding-3-large': { + maxInputTokens: 8191, + maxBatchSize: 2048, + expectedDimensions: 3072, + }, + 'embedding-001': { + maxInputTokens: 2048, + maxBatchSize: 100, + expectedDimensions: 768, + }, +}; + +// 最終的な上限を計算 +const effectiveMaxChunkSize = Math.min( + this.envMaxChunkSize, // 環境変数 + limits.maxInputTokens // モデルの制限 +); +``` + +### 2. 検証ロジック + +```typescript +async validateChunkConfig(chunkSize, chunkOverlap, modelId, userId) { + const warnings = []; + + // 1. 最終的な上限を計算 + const effectiveMaxChunkSize = Math.min( + this.envMaxChunkSize, + limits.maxInputTokens + ); + + // 2. チャンクサイズの検証 + if (chunkSize > effectiveMaxChunkSize) { + warnings.push(`上限 ${effectiveMaxChunkSize} を超えています`); + chunkSize = effectiveMaxChunkSize; + } + + // 3. オーバーラップサイズの検証 + const maxOverlap = Math.min( + this.envMaxOverlapSize, + Math.floor(chunkSize * 0.5) + ); + if (chunkOverlap > maxOverlap) { + warnings.push(`オーバーラップが上限 ${maxOverlap} を超えています`); + chunkOverlap = maxOverlap; + } + + return { + chunkSize, + chunkOverlap, + warnings, + effectiveMaxChunkSize, + effectiveMaxOverlapSize, + }; +} +``` + +### 3. API エンドポイント + +```typescript +// GET /api/knowledge-bases/chunk-config/limits?embeddingModelId=xxx +{ + "maxChunkSize": 8191, + "maxOverlapSize": 200, + "defaultChunkSize": 200, + "defaultOverlapSize": 40, + "modelInfo": { + "name": "text-embedding-3-large", + "maxInputTokens": 8191, + "maxBatchSize": 2048, + "expectedDimensions": 3072 + } +} +``` + +--- + +## 🎨 フロントエンドの実装 + +### IndexingModal.tsx + +```typescript +// 状態管理 +const [limits, setLimits] = useState(null); +const [chunkSize, setChunkSize] = useState(200); +const [chunkOverlap, setChunkOverlap] = useState(40); + +// モデル選択時に制限をロード +useEffect(() => { + if (selectedEmbedding) { + const limitData = await chunkConfigService.getLimits(selectedEmbedding, token); + setLimits(limitData); + + // 現在の値を自動調整 + if (chunkSize > limitData.maxChunkSize) { + setChunkSize(limitData.maxChunkSize); + } + } +}, [selectedEmbedding]); + +// スライダー変更時の処理 +const handleChunkSizeChange = (value) => { + if (limits && value > limits.maxChunkSize) { + showWarning(`最大値は ${limits.maxChunkSize} です`); + setChunkSize(limits.maxChunkSize); + return; + } + setChunkSize(value); + + // オーバーラップの自動調整 + if (chunkOverlap > value * 0.5) { + setChunkOverlap(Math.floor(value * 0.5)); + } +}; +``` + +### UI 機能 + +1. **動的なスライダー範囲** + + ```jsx + + ``` + +2. **制限のリアルタイム表示** + + ``` + チャンクサイズ: 200 tokens (上限: 8191) + ``` + +3. **モデル情報の表示** + + ``` + モデル: text-embedding-3-large + チャンク上限: 8191 tokens + オーバーラップ上限: 200 tokens + バッチ制限: 2048 + ``` + +4. **最適化アドバイス** + + ``` + 💡 最適化アドバイス + • チャンクが大きすぎます (800)。検索精度に影響する可能性があります。 + • 少なくとも 80 tokens のオーバーラップを推奨します。 + • 最大値を使用すると、処理速度が低下する可能性があります。 + ``` + +--- + +## 📊 ユースケース例 + +### シナリオ1: OpenAI + 環境変数による制限 + +**設定:** + +```env +MAX_CHUNK_SIZE=4000 # モデルより厳格なカスタム制限 +``` + +**ユーザー操作:** + +``` +1. モデル選択: text-embedding-3-large +2. スライダー上限: 4000 (環境変数による制限) +3. ユーザー設定: 3000 tokens +4. バックエンド検証: ✅ 合格 +5. 実適用値: 3000 tokens +``` + +### シナリオ2: Gemini + モデルによる制限 + +**設定:** + +```env +MAX_CHUNK_SIZE=8191 # 環境変数は緩和 +``` + +**ユーザー操作:** + +``` +1. モデル選択: embedding-001 +2. スライダー上限: 2048 (モデル制限の方が厳格) +3. ユーザー設定: 1500 tokens +4. バックエンド検証: ✅ 合格 +5. 実適用値: 1500 tokens +``` + +### シナリオ3: 制限超過時の自動調整 + +**ユーザー操作:** + +``` +1. モデル選択: embedding-001 (制限 2048) +2. ユーザー入力: 3000 tokens +3. フロントエンド表示: "最大値は 2048 です" +4. スライダーを自動的に 2048 に調整 +5. バックエンド記録: ⚠️ 設定修正ログ +``` + +--- + +## 🔍 優先順位ルール + +### 上限計算ロジック + +```typescript +最終的な上限 = min(環境変数, モデル制限) + +例: +- 環境変数: 8191 +- モデル制限: 2048 (Gemini) +- 最終上限: 2048 ✅ + +- 環境変数: 4000 +- モデル制限: 8191 (OpenAI) +- 最終上限: 4000 ✅ +``` + +### 検証順序 + +```typescript +1. チャンクサイズ ≤ 最終上限 かを確認 +2. チャンクサイズ ≥ 最小値 (50) かを確認 +3. オーバーラップサイズ ≤ 環境変数の上限 かを確認 +4. オーバーラップサイズ ≤ チャンクサイズの 50% かを確認 +5. オーバーラップサイズ ≥ 0 かを確認 +``` + +--- + +## 📝 デプロイ時の推奨設定 + +### 開発環境 + +```env +# テストに適した設定 +MAX_CHUNK_SIZE=8191 +MAX_OVERLAP_SIZE=200 +``` + +### 本番環境 (OpenAI) + +```env +# 大容量ファイルへの対策を考慮した保守的な設定 +MAX_CHUNK_SIZE=4000 +MAX_OVERLAP_SIZE=500 +``` + +### 本番環境 (Gemini) + +```env +# モデルの制限に合わせた設定 +MAX_CHUNK_SIZE=2048 +MAX_OVERLAP_SIZE=300 +``` + +--- + +## ✅ メリットのまとめ + +| 特徴 | 実装方法 | 効果 | +|------|----------|------| +| **安全性** | 環境変数 + モデル制限の二重保護 | API の制限を超えない | +| **柔軟性** | 環境変数で調整可能 | 異なるデプロイ要件に対応 | +| **ユーザー体験** | フロントエンドでの動的制限 | 無効な値を選択できない | +| **透明性** | 制限情報をリアルタイム表示 | 設定理由が明確 | +| **自動調整** | バックエンドでの検証・修正 | 実行時のエラーを回避 | +| **ログ管理** | 詳細な警告情報 | 問題の切り分けがスムーズ | + +--- + +## 🎯 結論 + +このスキームにより、以下が実現されました: + +1. ✅ **環境変数の設定** - グローバルに制御可能な上限 +2. ✅ **モデル制限の認識** - 異なるモデルの自動識別 +3. ✅ **フロントエンドでの制限** - 無効な値を選択不可に +4. ✅ **バックエンド検証** - 二重の保険 +5. ✅ **自動調整** - 制限超過時の自動修正 +6. ✅ **透明なフィードバック** - 制限理由の表示 + +**これで、ユーザーがモデルの制限を超える値を選択することはなくなり、システムが自動的に保護されます!** diff --git a/docs/1.0/CURRENT_IMPLEMENTATION.md b/docs/1.0/CURRENT_IMPLEMENTATION.md new file mode 100644 index 0000000..6bd3fce --- /dev/null +++ b/docs/1.0/CURRENT_IMPLEMENTATION.md @@ -0,0 +1,165 @@ +# 現在の実装状況ドキュメント + +## システムアーキテクチャ + +### 技術スタック + +- **フロントエンド**: React + TypeScript + Vite + Tailwind CSS +- **バックエンド**: NestJS + LangChain + Elasticsearch + TypeORM +- **データベース**: SQLite (ユーザー、モデル設定、ナレッジベース、ユーザー設定) +- **ベクトルストレージ**: Elasticsearch +- **ファイル処理**: Apache Tika (高速モード) + Vision Pipeline (高精度モード) +- **認証**: JWT +- **ドキュメント変換**: LibreOffice + ImageMagick + +### コアモジュール + +#### 1. ユーザー認証システム (Auth) + +- JWT 認証システム +- ユーザー登録/ログイン/パスワード変更 +- ユーザー管理画面 +- ルート保護と権限制御 + +#### 2. モデル設定管理 (ModelConfig) + +- 多様なモデルプロバイダーをサポート: + - **OpenAI 互換**: OpenAI API および互換インターフェース(DeepSeek, Claude など)に対応 + - **Google Gemini**: ネイティブ SDK によるサポート +- モデルタイプ: + - **LLM**: 対話生成モデル + - **Embedding**: ベクトル化モデル + - **Rerank**: 再ランキングモデル +- ユーザー独自の API キーとモデルパラメータの設定が可能 +- ビジョン機能のフラグ管理をサポート + +#### 3. ナレッジベース管理 (KnowledgeBase) + +- ファイルのアップロードと保存(日本語ファイル名に対応) +- **デュアルモード処理**: + - **高速モード**: Apache Tika によるテキスト抽出 + - **高精度モード**: Vision Pipeline による画像・テキスト混合処理 +- インテリジェントなドキュメントのチャンク分割とベクトル化 +- Elasticsearch インデックスとハイブリッド検索 +- ファイルステータス管理(待機中、インデックス中、完了、失敗) +- 数百種類のファイル形式をサポート: PDF, Word, PPT, Excel, Markdown, コードファイル, 画像など + +#### 4. RAG 質問応答システム (Chat) + +- **ストリーミング出力**: Server-Sent Events (SSE) を利用 +- **インテリジェント検索**: LangChain キーワード抽出 + ES ハイブリッド検索 +- **類似度フィルタリング**: 関連性の低いコンテンツをフィルタリングするしきい値を設定可能 +- **引用表示**: ソースの断片、ファイル名、類似度スコアを表示 +- **多言語サポート**: ユーザーの言語設定に合わせて AI の回答言語を調整 + +#### 5. 統合設定管理 (Unified Settings) + +- **統合設定モーダル**: 各種管理機能を一つのタブ形式インターフェースに集約 + - **一般設定 (General)**: 言語切り替え、パスワード変更 + - **ユーザー管理 (User)**: ユーザー一覧、ユーザー追加(管理者機能) + - **モデル管理 (Model)**: LLM, Embedding, Rerank モデルの設定と管理 +- **クイックアクセス**: サイドバー下部の「設定」ボタンからワンクリックでアクセス可能 +- **一貫した体験**: 統一されたフォーム操作とステータスフィードバック + +## チャットフロー + +``` +ユーザーの質問 → キーワード抽出 → ESハイブリッド検索 → 類似度フィルタリング → コンテキスト構築 → LLMストリーミング生成 → 引用元の表示 +``` + +### 詳細ステップ + +1. **キーワード抽出** + - LangChain を使用して、ユーザーの質問から 3-5 個のキーワードを抽出します。 + - 不要な言葉(「の」「は」「のぼり」など)を除去します。 + +2. **ハイブリッド検索** + - キーワードを組み合わせてベクトル検索を実行します。 + - 全文検索を併用して再現率を向上させます。 + - 類似度しきい値でフィルタリングします。 + - 最も関連性の高いセグメントを返します。 + +3. **ストリーミング生成** + - 処理の進捗を表示します(「ナレッジベースを検索中...」など)。 + - LLM が生成した回答内容をリアルタイムで出力します。 + - 取得したセグメントに基づき、引用付きの回答を生成します。 + - 多言語での回答をサポートします。 + +4. **引用元の表示** + - セグメント内容の要約(最大150文字)を表示します。 + - 出典元ファイル名を表示します。 + - 類似度のパーセンテージを表示します。 + - セグメント番号を表示します。 + +## 主要な API エンドポイント + +### 認証関連 + +- `POST /auth/login` - ログイン +- `POST /auth/register` - ユーザー登録 +- `POST /auth/change-password` - パスワード変更(設定モーダル内から呼び出し) + +### チャット API + +- `POST /chat/stream` - ストリーミングチャット + - ユーザーが設定した LLM モデルと API キーを自動取得 + - OpenAI 互換インターフェースと Gemini をサポート + - SSE ストリーミングレスポンスを返却 + - 多言語パラメータの受け渡しに対応 + +### モデル管理 + +- `GET /model-configs` - モデル設定の一覧取得 +- `POST /model-configs` - モデル設定の作成 +- `PUT /model-configs/:id` - モデル設定の更新 +- `DELETE /model-configs/:id` - モデル設定の削除 + +### ナレッジベース管理 + +- `POST /upload` - ファイルアップロード(チャンクパラメータの設定が可能) +- `GET /knowledge-bases` - ファイル一覧の取得 +- `DELETE /knowledge-bases/:id` - ファイルの削除 +- `DELETE /knowledge-bases/clear` - ナレッジベースの全消去 + +### ユーザー設定 + +- `GET /user-settings` - 設定の取得 +- `PUT /user-settings` - 設定の更新 +- **注**: フロントエンドは統一された `SettingsModal` コンポーネントを介してこれらのエンドポイントと通信します。 + +## 利用方法 + +1. **ユーザー登録/ログイン** +2. **基本構成の設定** + - サイドバー下部の「設定」ボタンをクリックします。 + - 「モデル管理」タブで OpenAI 互換の LLM と Embedding モデルを追加します。 + - API キーとモデルパラメータを設定します。 + - 「一般設定」タブで言語を切り替えたり、パスワードを変更したりできます。 +3. **ドキュメントのアップロード** + - PDF, テキスト, 画像などの形式をサポートします。 + - チャンクサイズと Embedding モデルを設定します。 + - 自動的にベクトル化とインデックス化が行われます。 +4. **詳細設定の調整** + - 使用するモデルを選択します。 + - 推論パラメータと検索パラメータを構成します。 + - UI 言語を設定します。 +5. **対話を開始** + - 質問を送信します。 + - ストリーミング処理の経過を観察します。 + - 引用付きのインテリジェントな回答を確認します。 + +## 特筆すべき機能 + +- ✅ **ユーザー分離**: 各ユーザーに独立したモデル設定とナレッジベースを提供 +- ✅ **ストリーミング体験**: 処理の進捗と生成内容をリアルタイム表示 +- ✅ **インテリジェント検索**: キーワード抽出 + ハイブリッド検索 + 類似度フィルタリング +- ✅ **引用追跡**: 回答の根拠となるソースと関連セグメントを明確に表示 +- ✅ **マルチモデル対応**: OpenAI 互換インターフェース + Gemini ネイティブサポート +- ✅ **柔軟な設定**: ユーザー独自の API キーと推論パラメータのカスタマイズ +- ✅ **多言語サポート**: UI と AI 回答の両方を完全国際化 +- ✅ **ビジョン機能**: 画像処理をサポートするマルチモーダルモデルに対応 +- ✅ **ユーザー管理**: 登録、ログイン、パスワード管理の完備 +- ✅ **デュアルモード処理**: 高速モード (テキストのみ) + 高精度モード (画像・テキスト混合) +- ✅ **メモリの最適化**: 大容量ファイルを分割処理し、メモリオーバーフローを防止 +- ✅ **統合管理**: モデル、ユーザー、一般設定を一つにまとめたモダンな UI +- ✅ **ミニマルなデザイン**: サイドバーとヘッダーの冗余を排除し、対話体験に集中 diff --git a/docs/1.0/DEPLOYMENT.md b/docs/1.0/DEPLOYMENT.md new file mode 100644 index 0000000..063c160 --- /dev/null +++ b/docs/1.0/DEPLOYMENT.md @@ -0,0 +1,444 @@ +# デプロイガイド + +## 開発環境のデプロイ + +### 前提条件 + +- Node.js 18+ +- Yarn +- Docker & Docker Compose + +### 1. プロジェクトのクローン + +```bash +git clone +cd simple-kb +``` + +### 2. 依存関係のインストール + +```bash +yarn install +``` + +### 3. 基本サービスの起動 + +```bash +# Elasticsearch と Tika を起動 +docker-compose up -d elasticsearch tika +``` + +### 4. 環境変数の設定 + +```bash +# 環境変数のテンプレートをコピー +cp server/.env.sample server/.env + +# 設定ファイルを編集 +vim server/.env +``` + +### 5. 開発サービスの起動 + +```bash +# フロントエンドとバックエンドを同時に起動 +yarn dev + +# または個別に起動 +yarn dev:web # フロントエンド (ポート 5173) +yarn dev:server # バックエンド (ポート 3000) +``` + +## 本番環境のデプロイ + +### Docker Compose を使用する場合 + +1. **環境変数の設定** + +```bash +cp .env.sample .env +# 本番環境の設定を編集 +``` + +1. **ビルドと起動** + +```bash +# すべてのサービスを一括起動 +docker-compose up -d +``` + +1. **サービスへのアクセス** + +- HTTPS: (推奨) +- HTTP: (HTTPS へ自動リダイレクト) +- バックエンド API: Nginx プロキシ経由でアクセス +- Elasticsearch: +- Tika: + +### サービス構成 + +- **nginx**: リバースプロキシ。HTTPS と CORS 処理を担当 +- **web**: フロントエンド静的ファイルサービス (React) +- **server**: バックエンド API サービス (NestJS) +- **libreoffice**: LibreOffice ドキュメント変換サービス (FastAPI, ポート 8100) +- **elasticsearch**: ベクトル検索エンジン (ポート 9200) +- **tika**: ドキュメント内容抽出サービス (ポート 9998) + +### アーキテクチャ図 + +``` +ユーザー → nginx → web (React) + ↓ + server (NestJS) → elasticsearch + ↓ ↓ + libreoffice tika + (FastAPI) (Java) +``` + +### SSL 証明書の設定 + +#### 自己署名証明書(開発環境用) + +```bash +# 自己署名証明書を生成 +./nginx/generate-ssl.sh +``` + +#### 本番環境用証明書 + +正式な SSL 証明書を以下の場所に配置してください: + +- 証明書ファイル: `nginx/ssl/cert.pem` +- 秘密鍵ファイル: `nginx/ssl/key.pem` + +### Docker 常用コマンド + +```bash +# すべてのサービスのログを表示 +docker-compose logs -f + +# 特定のサービスのログを表示 +docker-compose logs -f nginx +docker-compose logs -f server + +# サービスの再起動 +docker-compose restart + +# 特定のサービスの再起動 +docker-compose restart nginx + +# サービスの停止 +docker-compose down + +# 再ビルドして起動 +docker-compose up -d --build +``` + +### データの永続化 + +#### SQLite データベース + +- データベースファイルの場所: `./data/database.sqlite` +- コンテナ外部に自動マウントされるため、コンテナ再起動時もデータは失われません。 + +#### アップロードファイル + +- ファイルの保存場所: `./uploads/` +- アップロードされたすべてのドキュメントと画像はホストマシンに保存されます。 + +#### Elasticsearch データ + +- データボリューム: `elasticsearch-data` +- ベクトルインデックスデータが永続的に保存されます。 + +### 手動デプロイ + +1. **フロントエンドのビルド** + +```bash +cd web +yarn build +``` + +1. **バックエンドのビルド** + +```bash +cd server +yarn build +``` + +1. **Nginx の設定** + +```nginx +server { + listen 80; + server_name your-domain.com; + + # フロントエンド静的ファイル + location / { + root /path/to/web/dist; + try_files $uri $uri/ /index.html; + } + + # バックエンド API プロキシ + location /api { + proxy_pass http://localhost:3000; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } +} +``` + +## 環境変数の設定 + +### バックエンド環境変数 (server/.env) + +```bash +# データベース +DATABASE_PATH=./data/metadata.db + +# Elasticsearch +ELASTICSEARCH_HOST=http://localhost:9200 +ELASTICSEARCH_INDEX=knowledge_base_chunks + +# Tika サービス +TIKA_HOST=http://localhost:9998 + +# LibreOffice サービス +LIBREOFFICE_URL=http://localhost:8100 + +# Vision API +VISION_API_KEY=sk-xxx-your-key +VISION_API_BASE=https://api.openai.com/v1 +VISION_MODEL=gpt-4-vision-preview + +# ファイルアップロード +UPLOAD_FILE_PATH=./uploads +MAX_FILE_SIZE=50MB + +# 一時ディレクトリ +TEMP_DIR=./temp + +# JWT +JWT_SECRET=your-jwt-secret-key +JWT_EXPIRES_IN=7d + +# サービスポート +PORT=3000 +``` + +### フロントエンド環境変数 (web/.env) + +```bash +# API アドレス +VITE_API_BASE_URL=http://localhost:3000 + +# アプリケーション設定 +VITE_APP_TITLE=簡易ナレッジベース +VITE_MAX_FILE_SIZE=50 +``` + +## バックアップと復元 + +### SQLite データベースのバックアップ + +```bash +# バックアップ +cp server/data/metadata.db backup/metadata_$(date +%Y%m%d).db + +# 復元 +cp backup/metadata_20240101.db server/data/metadata.db +``` + +### Elasticsearch データのバックアップ + +```bash +# スナップショット用リポジトリの作成 +curl -X PUT "localhost:9200/_snapshot/backup_repo" -H 'Content-Type: application/json' -d' +{ + "type": "fs", + "settings": { + "location": "/backup/elasticsearch" + } +}' + +# スナップショットの作成 +curl -X PUT "localhost:9200/_snapshot/backup_repo/snapshot_1" +``` + +## 監視とログ + +### アプリケーションログ + +- フロントエンドログ: ブラウザのコンソール +- バックエンドログ: `server/logs/` +- Elasticsearch ログ: Docker コンテナログ + +### ヘルスチェック + +```bash +# バックエンドのヘルスチェック +curl http://localhost:3000/health + +# Elasticsearch のヘルスチェック +curl http://localhost:9200/_cluster/health +``` + +## トラブルシューティング + +### よくある質問 + +1. **Elasticsearch への接続に失敗する** + - Docker コンテナの状態を確認してください。 + - ポート 9200 がアクセス可能か確認してください。 + - ファイアウォールの設定を確認してください。 + +2. **ファイルのアップロードに失敗する** + - uploads ディレクトリの権限を確認してください。 + - Tika サービスが正常に動作しているか確認してください。 + - ファイルサイズの制限を確認してください。 + +3. **モデル API の呼び出しに失敗する** + - API キーの設定を確認してください。 + - ネットワーク接続を確認してください。 + - モデル ID が正しいか確認してください。 + +#### 1. Elasticsearch への接続失敗 + +**症状**: バックエンドログに "Connection refused" または "ECONNREFUSED" と表示される +**解決策**: + +- Docker コンテナの状態確認: `docker-compose ps` +- ポート 9200 のアクセス確認: `curl http://localhost:9200` +- ファイアウォール設定の確認 +- Elasticsearch の再起動: `docker-compose restart elasticsearch` + +#### 2. ファイルのアップロード失敗 + +**症状**: アップロード時に「アップロード失敗」または「処理失敗」と表示される +**解決策**: + +- uploads ディレクトリの権限確認: `ls -la server/uploads/` +- Tika サービスの状態確認: `curl http://localhost:9998/version` +- ファイルサイズ制限の確認(デフォルト 50MB) +- バックエンドログの詳細エラーを確認 + +#### 3. モデル API の呼び出し失敗 + +**症状**: チャット時に「API キーが無効」または「モデルの呼び出しに失敗」と表示される +**解決策**: + +- API キーの設定が正しいか確認 +- ネットワーク接続とファイアウォールの確認 +- モデル ID の確認(例: gpt-4, gpt-3.5-turbo) +- API の利用残高と権限の確認 +- Base URL の設定確認(OpenAI 互換インターフェースの場合) + +#### 4. ユーザー認証の問題 + +**症状**: ログイン失敗またはトークンの期限切れ +**解決策**: + +- ユーザー名とパスワードの確認 +- ブラウザのキャッシュと localStorage のクリア +- JWT_SECRET の設定確認 +- ユーザーアカウントの再登録 + +#### 5. ナレッジベースの検索結果が出ない + +**症状**: 質問後に「関連する知識が見つかりません」と表示される +**解決策**: + +- ファイルのインデックスが完了しているか確認(ステータスが「完了」) +- 類似度しきい値の設定を調整 +- Embedding モデルの設定確認 +- 別のキーワードで質問してみる + +#### 6. フロントエンドページにアクセスできない + +**症状**: ブラウザに「このサイトにアクセスできません」と表示される +**解決策**: + +- フロントエンドサービスがポート 5173 で動作しているか確認 +- ファイアウォールとプロキシの設定確認 +- ブラウザのキャッシュのクリア +- シークレットモードでのアクセスを試す + +### デバッグツール + +#### サービス状態の確認 + +```bash +# すべての Docker コンテナを確認 +docker-compose ps + +# ポートの使用状況を確認 +netstat -tulpn | grep :5173 +netstat -tulpn | grep :3000 +``` + +#### 詳細ログの表示 + +```bash +# バックエンドログ +docker-compose logs -f server + +# Elasticsearch ログ +docker-compose logs -f elasticsearch + +# フロントエンド開発ログ +cd web && yarn dev +``` + +#### ヘルスチェック + +```bash +# バックエンド API のヘルスチェック +curl http://localhost:3000/health + +# Elasticsearch のヘルスチェック +curl http://localhost:9200/_cluster/health + +# LibreOffice サービスのチェック +curl http://localhost:8100/health + +# LibreOffice API ドキュメントの表示 +open http://localhost:8100/docs +``` + +### パフォーマンスの最適化 + +#### 1. Elasticsearch のチューニング + +```bash +# JVM ヒープメモリの増量 +export ES_JAVA_OPTS="-Xms2g -Xmx2g" + +# インデックス状態の確認 +curl http://localhost:9200/_cat/indices?v +``` + +#### 2. ファイル処理の最適化 + +- 同時にアップロードするファイル数を制限する +- チャンクサイズを適切に調整する(推奨 512-1024 トークン) +- 不要なインデックスデータを定期的に整理する + +### データの復元 + +#### SQLite データベースの復元 + +```bash +# バックアップから復元 +cp backup/metadata_20240101.db server/data/metadata.db + +# データベースの整合性チェック +sqlite3 server/data/metadata.db "PRAGMA integrity_check;" +``` + +#### Elasticsearch データの復元 + +```bash +# スナップショットの復元 +curl -X POST "localhost:9200/_snapshot/backup_repo/snapshot_1/_restore" +``` diff --git a/docs/1.0/DESIGN.md b/docs/1.0/DESIGN.md new file mode 100644 index 0000000..e78bdd1 --- /dev/null +++ b/docs/1.0/DESIGN.md @@ -0,0 +1,217 @@ +# 簡易ナレッジベース (Simple Knowledge Base) - システム設計ドキュメント + +## 1. プロジェクト概要 + +本プロジェクトは、React + NestJS をベースに開発されたフルスタックのナレッジベースQ&Aシステム(RAG - Retrieval-Augmented Generation)です。 +ユーザーは多様な形式のドキュメントをアップロードし、チャンク分割やインデックス設定をカスタマイズした上で、大規模言語モデル(LLM)を利用してナレッジベースに基づいた質問応答を行うことができます。 + +--- + +## 2. コアアーキテクチャ設計 + +### 2.1 技術スタック + +- **フロントエンド**: React 19 + TypeScript + Vite + Tailwind CSS +- **バックエンド**: NestJS + LangChain + TypeORM +- **データベース**: SQLite (ユーザー、モデル設定、ナレッジベースのメタデータ) +- **ベクトルストレージ**: Elasticsearch +- **ファイル処理**: Apache Tika (高速モード) + Vision Pipeline (高精度モード) +- **認証**: JWT +- **ドキュメント変換**: LibreOffice + ImageMagick + +### 2.2 システムアーキテクチャ + +``` +ユーザー -> Reactフロントエンド -> NestJSバックエンド -> SQLite/Elasticsearch + | + v + LangChain Agent + | + v + 大言語モデル (LLM) + +高精度モードのプロセス: +PDF/Word/PPT -> LibreOffice -> PDF -> ImageMagick -> Vision Model -> 構造化コンテンツ +``` + +--- + +## 3. コア機能モジュール + +### 3.1 ユーザー認証システム + +- **JWT 認証**: ユーザー名/パスワードに基づくログインシステム +- **ユーザー管理**: ユーザー登録、パスワード変更をサポート +- **権限制御**: ユーザーデータの隔離。各ユーザーに独立したナレッジベースを提供 +- **管理画面**: 統合された設定モーダルによるユーザー管理(作成/リスト表示) + +### 3.2 モデル設定管理 + +- **マルチプロバイダー対応**: + - **OpenAI 互換**: OpenAI API および互換インターフェース(DeepSeek, Claude など)に対応 + - **Google Gemini**: ネイティブ SDK によるサポート +- **モデルタイプ**: + - **LLM**: 対話生成モデル + - **Embedding**: ベクトル化モデル + - **Rerank**: 再ランキングモデル +- **ユーザーカスタマイズ**: ユーザーが独自の API キーとモデルパラメータを設定可能 +- **ビジョンサポート**: モデルが画像処理に対応しているかどうかのフラグ管理 +- **統合管理**: 設定モーダルの「モデル管理」タブで一括管理 + +### 3.3 ナレッジベース管理 + +- **ファイルアップロード**: PDF、ドキュメント、画像など多様な形式に対応 +- **デュアルモード処理**: + - **高速モード**: Apache Tika を使用したテキスト抽出 + - **高精度モード**: Vision Pipeline を使用した画像・テキスト混合処理 +- **インテリジェント・チャンキング**: チャンクサイズとオーバーラップを調整可能 +- **ベクトルインデックス**: ユーザーが選択した Embedding モデルによるベクトル化 +- **ステータス管理**: ファイル処理状況の追跡(待機中、インデックス中、完了、失敗) + +### 3.4 RAG 質問応答システム + +- **インテリジェント検索**: + - キーワード抽出とクエリの最適化 + - ハイブリッド検索(ベクトル検索 + 全文検索) + - 類似度しきい値によるフィルタリング +- **ストリーミング生成**: + - Server-Sent Events (SSE) によるストリーミング出力 + - 処理の進捗をリアルタイムに表示 + - 生成コンテンツを1文字ずつ表示 +- **引用追跡**: + - 回答の出典ファイルを表示 + - 関連するドキュメントセグメントを表示 + - 類似度スコアの表示 + +### 3.5 多言語サポート + +- **インターフェースの国際化**: 日本語、中国語、英語に対応 +- **インテリジェント回答**: ユーザーの言語設定に基づいた AI による回答 +- **言語設定の永続化**: ユーザーの選択した言語を自動保存 + +--- + +## 4. データモデル設計 + +### 4.1 SQLite テーブル + +**ユーザー表 (users)** + +- id, username, password_hash, is_admin, created_at + +**モデル設定表 (model_configs)** + +- id, user_id, name, provider, model_id, base_url, api_key, type, supports_vision + +**ナレッジベースファイル表 (knowledge_bases)** + +- id, user_id, name, original_name, storage_path, size, mimetype, status, created_at + +**ユーザー設定表 (user_settings)** + +- user_id, selected_llm_id, selected_embedding_id, temperature, max_tokens, top_k, similarity_threshold, language + +### 4.2 Elasticsearch インデックス + +**ナレッジベース・チャンクインデックス (knowledge_base_chunks)** + +```json +{ + "chunk_id": "string", + "knowledge_base_id": "string", + "user_id": "string", + "file_name": "string", + "content": "text", + "embedding": "dense_vector[1536]", + "chunk_index": "integer", + "metadata": "object" +} +``` + +--- + +## 5. API エンドポイント設計 + +### 5.1 認証 + +- `POST /auth/login` - ログイン +- `POST /auth/register` - ユーザー登録 +- `POST /auth/change-password` - パスワード変更 + +### 5.2 モデル管理 + +- `GET /model-configs` - モデル設定の取得 +- `POST /model-configs` - モデル設定の作成 +- `PUT /model-configs/:id` - モデル設定の更新 +- `DELETE /model-configs/:id` - モデル設定の削除 + +### 5.3 ナレッジベース + +- `POST /upload` - ファイルアップロード +- `GET /knowledge-bases` - ファイル一覧の取得 +- `DELETE /knowledge-bases/:id` - ファイルの削除 +- `DELETE /knowledge-bases/clear` - ナレッジベースの全削除 + +### 5.4 チャット + +- `POST /chat/stream` - ストリーミングチャット(SSE) + +### 5.5 ユーザー設定 + +- `GET /user-settings` - 設定の取得 +- `PUT /user-settings` - 設定の更新 + +--- + +## 6. コアフロー + +### 6.1 ファイル処理フロー + +**高速モード**: + +``` +アップロード → メタデータ保存 → Tikaテキスト抽出 → チャンク分割 → ベクトル化 → ESインデックス → ステータス更新 +``` + +**高精度モード**: + +``` +アップロード → LibreOffice変換 → PDF画像化 → Vision分析 → 構造化コンテンツ → ベクトル化 → ESインデックス +``` + +### 6.2 RAG 質問応答フロー + +``` +ユーザーの質問 → キーワード抽出 → ハイブリッド検索 → 類似度フィルタリング → プロンプト構築 → LLM生成 → ストリーミング出力 → 引用表示 +``` + +--- + +## 7. デプロイ構成 + +### 7.1 開発環境 + +- フロントエンド: Vite 開発サーバー (ポート 5173) +- バックエンド: NestJS 開発サーバー (ポート 3000) +- Elasticsearch: Docker コンテナ (ポート 9200) +- Apache Tika: Docker コンテナ (ポート 9998) + +### 7.2 本番環境 + +- Docker Compose を使用したコンテナ化デプロイ +- Nginx によるリバースプロキシと負荷分散 +- SSL 証明書の設定 + +--- + +## 8. 特徴的な機能 + +- ✅ **ユーザー分離**: ユーザーごとに独立したモデル設定とナレッジベースを保持 +- ✅ **ストリーミング体験**: 処理状況と生成内容をリアルタイム表示 +- ✅ **インテリジェント検索**: キーワード抽出 + ハイブリッド検索 + 類似度フィルタリング +- ✅ **引用追跡**: 回答の根拠となるソースと関連セグメントを明確に表示 +- ✅ **マルチモデル対応**: OpenAI 互換インターフェース + Gemini ネイティブサポート +- ✅ **柔軟な設定**: ユーザー独自の API キーと推論パラメータのカスタマイズ +- ✅ **多言語対応**: UI と AI 回答の完全な国際化サポート +- ✅ **ビジョン機能**: 画像処理に対応したマルチモーダルモデルのサポート +- ✅ **デュアルモード処理**: 高速モード (テキストのみ) + 高精度モード (画像・テキスト混合) diff --git a/docs/1.0/DEVELOPMENT_STANDARDS.md b/docs/1.0/DEVELOPMENT_STANDARDS.md new file mode 100644 index 0000000..abe552b --- /dev/null +++ b/docs/1.0/DEVELOPMENT_STANDARDS.md @@ -0,0 +1,71 @@ +# 開発基準 + +## コードコメントの基準 + +### 1. コメントの言語 + +- **すべてのコードコメントは中国語を使用する必要があります** +- 以下を含みますが、これらに限定されません: + - 関数/メソッドのコメント + - 行内コメント + - コードブロックの説明 + - TODO/FIXME コメント + +### 2. ログ出力の基準 + +- **すべてのログ出力は中国語を使用する必要があります** +- 以下を含みますが、これらに限定されません: + - `logger.log()` 情報ログ + - `logger.warn()` 警告ログ + - `logger.error()` ラーログ + - `console.log()` デバッグ出力 + +### 3. エラーメッセージの基準 + +- **ユーザーに表示されるエラーメッセージは中国語を使用します** +- **開発デバッグ用のエラーメッセージは中国語を使用します** +- 例外スロー時のエラーメッセージには中国語を使用します + +## 例 + +### 正しいコメントとログ + +```typescript +// 正解:中国語のコメント +async getEmbeddings(texts: string[]): Promise { + this.logger.log(`正在为 ${texts.length} 个文本生成嵌入向量`); // 正解:中国語のログ + + try { + // APIを呼び出して埋め込みベクトルを取得 + const response = await this.callEmbeddingAPI(texts); + return response.data; + } catch (error) { + this.logger.error('获取嵌入向量失败', error); // 正解:中国語のログ + throw new Error('嵌入向量生成失败'); // 正解:中国語のエラーメッセージ + } +} +``` + +### 誤ったコメントとログ + +```typescript +// 誤り:英語のコメントとログ +async getEmbeddings(texts: string[]): Promise { + this.logger.log(`Getting embeddings for ${texts.length} texts`); + + try { + // Call API to get embeddings + const response = await this.callEmbeddingAPI(texts); + return response.data; + } catch (error) { + this.logger.error('Failed to get embeddings', error); + throw new Error('Embedding generation failed'); + } +} +``` + +## 履行基準 + +1. **コードレビュー時には、必ずコメントとログの言語をチェックしてください** +2. **新規コードは、中国語のコメントとログの基準に従う必要があります** +3. **既存のコードをリファクタリングする際は、同時にコメントとログも中国語に更新してください** diff --git a/docs/1.0/EMBEDDING_MODEL_ID_FIX.md b/docs/1.0/EMBEDDING_MODEL_ID_FIX.md new file mode 100644 index 0000000..6cb850b --- /dev/null +++ b/docs/1.0/EMBEDDING_MODEL_ID_FIX.md @@ -0,0 +1,219 @@ +# Embedding モデル ID 連携の修正 + +## 🐛 問題の記述 + +``` +混合検索失敗: NotFoundException: ModelConfig with ID "embedding-3" not found or not owned by user. +``` + +## 🔍 問題の分析 + +### 混同されやすい概念 + +システム内には2種類の異なる「ID」が存在します: + +1. **モデル設定テーブルの ID** (`ModelConfig.id`) + - データベースの主キー + - 例:`"embedding-3"`, `"default-embedding"` + - 用途:`ModelConfigService.findOne(id, userId)` + +2. **モデル識別子** (`ModelConfig.modelId`) + - AI ベンダー側でのモデル名 + - 例:`"text-embedding-3-large"`, `"text-embedding-ada-002"` + - 用途:AI API 呼び出し時のパラメータ + +### データフロー + +``` +ユーザー設定: user_setting.selectedEmbeddingId = "embedding-3" ✅ テーブルID + +フロントエンド: settings.selectedEmbeddingId + ↓ 転送 +バックエンド Controller: selectedEmbeddingId = "embedding-3" + ↓ 転送 +ChatService: embeddingModel.id = "embedding-3" ✅ 正常 + ↓ 転送 +hybridSearch: embeddingModelId = "embedding-3" + ↓ 転送 +EmbeddingService.getEmbeddings(embeddingModelId) + ↓ 呼び出し +ModelConfigService.findOne("embedding-3", userId) ✅ 正常 +``` + +### 以前の誤り + +**ChatService.ts (誤り):** + +```typescript +// 182行目付近 +searchResults = await this.hybridSearch( + [message], + userId, + embeddingModel.modelId, // ❌ 誤り! "text-embedding-3-large" を渡してしまっていた +); +``` + +**hybridSearch (受信側):** + +```typescript +private async hybridSearch( + keywords: string[], + userId: string, + embeddingModelId?: string, // "text-embedding-3-large" を受け取ってしまう +) +``` + +**EmbeddingService (期待値):** + +```typescript +async getEmbeddings( + texts: string[], + userId: string, + embeddingModelConfigId: string, // 本来は "embedding-3" を期待 +) { + const modelConfig = await this.modelConfigService.findOne( + embeddingModelConfigId, // ❌ "text-embedding-3-large" で検索しても見つからない! + userId, + ); +} +``` + +## ✅ 修正内容 + +### 修正箇所 + +**server/src/chat/chat.service.ts:** + +```typescript +// 182行目付近 +searchResults = await this.hybridSearch( + [message], + userId, + embeddingModel.id, // ✅ テーブルID "embedding-3" を使用するように変更 +); +``` + +### 修正後のフロー + +``` +1. ユーザーが埋め込みモデルを選択: text-embedding-3-large + ↓ +2. システムが user_setting テーブルに保存: + selectedEmbeddingId = "embedding-3" (ModelConfig テーブルの主キー) + ↓ +3. フロントエンドがチャットリクエストを送信: + { selectedEmbeddingId: "embedding-3" } + ↓ +4. バックエンド Controller が受信: + selectedEmbeddingId = "embedding-3" + ↓ +5. ChatService がモデルを検索: + embeddingModel = models.find(m => m.id === "embedding-3") + // 結果: { id: "embedding-3", modelId: "text-embedding-3-large", ... } + ↓ +6. ChatService が hybridSearch を呼び出し: + hybridSearch(..., embeddingModel.id) // "embedding-3" を渡す + ↓ +7. hybridSearch が EmbeddingService を呼び出し: + getEmbeddings(..., "embedding-3") + ↓ +8. EmbeddingService が設定を検索: + findOne("embedding-3", userId) // ✅ 設定が見つかる + ↓ +9. AI API を呼び出し: + model: "text-embedding-3-large" // modelId を用いて API を実行 +``` + +## 📊 ID の対応関係 + +| シーン | 使用するフィールド | 例 | 用途 | +|------|-----------|--------|------| +| ユーザー設定 | `user_setting.selectedEmbeddingId` | `"embedding-3"` | ユーザーの選択を保存 | +| 設定の検索 | `ModelConfig.id` | `"embedding-3"` | データベースクエリ | +| API 呼び出し | `ModelConfig.modelId` | `"text-embedding-3-large"` | AI ベンダーのインターフェース | + +## 🔑 重要な原則 + +### 1. データベース操作にはテーブル ID を使用する + +```typescript +// ✅ 正解 +const model = await modelConfigService.findOne(modelId, userId); // modelId = "embedding-3" + +// ❌ 誤り +const model = await modelConfigService.findOne(modelId, userId); // modelId = "text-embedding-3-large" +``` + +### 2. API 呼び出しにはモデル識別子を使用する + +```typescript +// ✅ 正解 +fetch(apiUrl, { + body: JSON.stringify({ + model: modelConfig.modelId, // "text-embedding-3-large" + }), +}); +``` + +### 3. 内部的な受け渡しにはテーブル ID を使用する + +```typescript +// ✅ 正解 +embeddingService.getEmbeddings(texts, userId, modelConfig.id); // "embedding-3" + +// ❌ 誤り +embeddingService.getEmbeddings(texts, userId, modelConfig.modelId); // "text-embedding-3-large" +``` + +## 🧪 検証 + +### テスト手順 + +1. **ユーザー設定の確認** + + ```sql + SELECT selectedEmbeddingId FROM user_setting WHERE userId = 'xxx'; + -- 期待値: "embedding-3" (テーブルID) + ``` + +2. **モデル設定の確認** + + ```sql + SELECT id, modelId, name FROM model_config WHERE userId = 'xxx'; + -- 期待値: embedding-3 | text-embedding-3-large | Text Embedding 3 Large + ``` + +3. **チャットメッセージの送信** + - バックエンドログを確認 + - 期待される出力: "使用嵌入模型: Text Embedding 3 Large text-embedding-3-large ID: embedding-3" + +4. **埋め込みベクトルの生成確認** + - ログに "从 Text Embedding 3 Large 获取到 X 个嵌入向量" と表示されること + +### 期待されるログ出力 + +``` +=== ChatService.streamChat === +User ID: user-123 +Selected Embedding ID: embedding-3 +ID に基づいてモデルを検索: embedding-3 +使用するモデル: Text Embedding 3 Large text-embedding-3-large ID: embedding-3 +埋め込みベクトルを生成中... +Text Embedding 3 Large から 1 個の埋め込みベクトルを取得しました。次元数: 2560 +``` + +## 📁 修正されたファイル + +- `server/src/chat/chat.service.ts` - 182行目。 `embeddingModel.modelId` ではなく `embeddingModel.id` を渡すように変更。 + +## 💡 学んだ教訓 + +1. **2種類の ID を区別すること**:テーブル主キー vs モデル識別子 +2. **パラメータ名を明確にすること**:`embeddingModelConfigId` vs `embeddingModelId` +3. **呼び出し先の期待値を確認すること**:`EmbeddingService` がどのタイプの ID を求めているか +4. **ログ出力の工夫**:デバッグを容易にするため、両方の ID を出力する + +```typescript +console.log('使用するモデル:', embeddingModel.name, embeddingModel.modelId, 'ID:', embeddingModel.id); +// 出力: 使用するモデル: Text Embedding 3 Large text-embedding-3-large ID: embedding-3 +``` diff --git a/docs/1.0/FEATURE_SUMMARY.md b/docs/1.0/FEATURE_SUMMARY.md new file mode 100644 index 0000000..8428aa5 --- /dev/null +++ b/docs/1.0/FEATURE_SUMMARY.md @@ -0,0 +1,29 @@ +# 功能说明 + +## 用户信息显示功能已完成 + +此更新为系统添加了以下功能: + +1. 在侧边栏顶部显示当前登录用户的信息,包括: + - 用户头像和用户名 + - 管理员标识(如果用户是管理员) + - 用户ID的部分显示 + +2. 主要文件变更: + - 创建了 `UserInfoDisplay.tsx` 组件 + - 更新了 `SidebarRail.tsx` 以集成用户信息显示 + - 更新了 `App.tsx` 以传递 currentUser 数据 + - 所有现有翻译已支持相关文本 + +## 实现细节 + +- 用户信息只在侧边栏展开时显示 +- 使用 Lucide React 图标增强可视化 +- 支持三种语言的界面文本 (中文/英文/日文) +- 管理员用户会显示特殊标记 +- 界面美观且与现有设计风格保持一致 +- 避免了信息重复显示 + +## 部署 + +此功能已准备好部署,无需额外配置。 \ No newline at end of file diff --git a/docs/1.0/INTERNAL_DEPLOYMENT_GUIDE.md b/docs/1.0/INTERNAL_DEPLOYMENT_GUIDE.md new file mode 100644 index 0000000..debd684 --- /dev/null +++ b/docs/1.0/INTERNAL_DEPLOYMENT_GUIDE.md @@ -0,0 +1,94 @@ +# 内网部署指南 - Simple-KB 知识库系统 + +## 概述 + +本文档介绍如何在内部网络环境中部署Simple-KB知识库系统,确保所有外部依赖都被移除或替换为内部资源。 + +## 主要修改内容 + +### 1. 外部CDN资源移除 + +已完成修改: +- 将 KaTeX CSS 文件从外部 CDN (https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css) 移至本地 +- `web/index.html` 已更新为引用本地 `/katex/katex.min.css` +- KaTeX CSS 文件已复制到 `web/public/katex/katex.min.css` + +### 2. AI模型API配置 + +系统本身支持内部模型API配置: +- 模型配置通过 `ModelConfig` 实体管理 +- 支持自定义 `baseUrl` 来指定内部模型服务 +- 用户可通过UI界面配置内部模型端点 + +## 内网部署配置步骤 + +### 步骤1: 部署内部AI模型服务 + +在启动Simple-KB之前,请确保已部署内部AI模型服务,如: +- 自托管的OpenAI兼容接口 (如 vLLM, Text Generation WebUI等) +- 内部大语言模型服务 +- 内部嵌入模型服务 + +### 步骤2: 配置模型端点 + +1. 启动Simple-KB系统 +2. 登录系统后,在模型配置页面添加内部模型配置: + - LLM模型: 配置内部LLM服务的URL和API密钥 + - 嵌入模型: 配置内部嵌入服务的URL和API密钥 + - 重排序模型: 配置内部重排序服务的URL和API密钥 + +### 步骤3: Docker配置(可选高级配置) + +如果需要修改Docker构建过程以使用内部注册表,请修改以下文件: + +#### 修改 server/Dockerfile: +```dockerfile +# 替换这行: +RUN yarn config set registry https://registry.npmmirror.com && \ +# 为: +RUN yarn config set registry http://your-internal-npm-registry && \ +``` + +#### 修改 web/Dockerfile: +```dockerfile +# 替换这行: +RUN yarn config set registry https://registry.npmmirror.com && \ +# 为: +RUN yarn config set registry http://your-internal-npm-registry && \ +``` + +#### 修改 libreoffice-server/Dockerfile: +```dockerfile +# 替换APK仓库源 +RUN echo "http://your-internal-mirror/alpine/v3.19/main" > /etc/apk/repositories && \ + echo "http://your-internal-mirror/alpine/v3.19/community" >> /etc/apk/repositories && \ + +# 替换pip源 +RUN pip install --no-cache-dir -r requirements.txt -i http://your-internal-pypi/ + +# 替换npm源 +RUN npm install --registry=http://your-internal-npm-registry +``` + +### 步骤4: Nginx配置 + +如果需要修改Nginx配置以适应内部环境: + +1. 更新 `nginx/conf.d/kb.conf` 中的SSL证书路径 +2. 根据需要修改服务器名称 +3. 确保代理路径正确指向内部服务 + +## 验证步骤 + +1. 确认前端界面正常加载且无外部资源错误 +2. 测试数学公式渲染功能是否正常(KaTeX功能) +3. 配置内部模型服务并测试问答功能 +4. 确认所有API调用都在内部网络中完成 + +## 注意事项 + +- 系统的所有核心功能现均可在内部网络中运行 +- 外部CDN依赖已被完全移除 +- AI模型服务需单独部署内部实例 +- 在完全离线环境中,构建过程可能需要预先下载所有依赖包 +- 如需完全离线部署,建议预构建镜像并部署到内部镜像仓库 \ No newline at end of file diff --git a/docs/1.0/INTERNAL_DEPLOYMENT_SUMMARY.md b/docs/1.0/INTERNAL_DEPLOYMENT_SUMMARY.md new file mode 100644 index 0000000..9e3bba8 --- /dev/null +++ b/docs/1.0/INTERNAL_DEPLOYMENT_SUMMARY.md @@ -0,0 +1,40 @@ +# 内网部署修改摘要 - Simple-KB 知识库系统 + +## 修改概述 + +已完成对Simple-KB知识库系统的修改,以支持内部网络环境部署,消除了外部依赖。 + +## 具体修改内容 + +### 1. 外部CDN资源移除 +- **文件**: `web/index.html` +- **修改**: 将 KaTeX CSS 从外部 CDN (https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css) 更改为本地资源 (/katex/katex.min.css) +- **文件**: `web/public/katex/katex.min.css` +- **操作**: 从 node_modules 复制 KaTeX CSS 文件到本地目录 + +### 2. 文档更新 +- **新增文件**: `INTERNAL_DEPLOYMENT_GUIDE.md` +- **内容**: 详细的内网部署指南,包括配置内部AI模型服务的方法 +- **更新文件**: `README.md` +- **内容**: 添加了内网部署章节,链接到部署指南 + +## 系统状态 + +✅ **已完成**: +- 消除前端外部CDN依赖 +- 提供内部网络部署文档 +- 保持所有原有功能完整性 + +✅ **系统已准备好在内部网络环境中部署**: +- 所有前端资源均为本地资源 +- AI模型服务可通过配置指向内部服务 +- 系统不再依赖外部CDN或API端点(除用户自行配置的AI模型外) + +## 部署说明 + +要在内部网络中部署此系统: + +1. 按照 `INTERNAL_DEPLOYMENT_GUIDE.md` 的说明进行配置 +2. 部署内部AI模型服务(如适用) +3. 配置模型端点以使用内部服务 +4. 启动系统并验证功能 \ No newline at end of file diff --git a/docs/1.0/KNOWLEDGE_BASE_ENHANCEMENTS.md b/docs/1.0/KNOWLEDGE_BASE_ENHANCEMENTS.md new file mode 100644 index 0000000..9634afd --- /dev/null +++ b/docs/1.0/KNOWLEDGE_BASE_ENHANCEMENTS.md @@ -0,0 +1,464 @@ +# ナレッジベースの強化機能設計 + +## 🎯 機能概要 + +今回の開発には、以下の3つのコア機能が含まれます: + +1. **ナレッジベースのグループ化** - グループを作成し、ドキュメントを複数のグループに所属させ、検索時にグループを指定可能にします。 +2. **検索履歴** - 対話プロセス全体を保存し、過去の会話の閲覧や再開を可能にします。 +3. **PDF プレビュー** - すべてのファイルを PDF 形式に変換し、オンラインでプレビューできるようにします。 + +## 🗄️ データベース設計 + +### 新規テーブル構造 + +```sql +-- ナレッジベースグループ管理テーブル +CREATE TABLE knowledge_groups ( + id TEXT PRIMARY KEY, + name TEXT NOT NULL, + description TEXT, + color TEXT DEFAULT '#3B82F6', -- グループの色分けID + user_id TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- ドキュメント・グループ関連付けテーブル (多対多) +CREATE TABLE knowledge_base_groups ( + knowledge_base_id TEXT NOT NULL, + group_id TEXT NOT NULL, + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (knowledge_base_id, group_id), + FOREIGN KEY (knowledge_base_id) REFERENCES knowledge_base(id) ON DELETE CASCADE, + FOREIGN KEY (group_id) REFERENCES knowledge_groups(id) ON DELETE CASCADE +); + +-- 検索履歴テーブル +CREATE TABLE search_history ( + id TEXT PRIMARY KEY, + user_id TEXT NOT NULL, + title TEXT NOT NULL, -- 対話タイトル (質問の先頭50文字) + selected_groups TEXT, -- JSON配列: ["group1", "group2"] または null(すべて) + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + updated_at DATETIME DEFAULT CURRENT_TIMESTAMP +); + +-- 対話メッセージテーブル +CREATE TABLE chat_messages ( + id TEXT PRIMARY KEY, + search_history_id TEXT NOT NULL, + role TEXT NOT NULL CHECK (role IN ('user', 'assistant')), + content TEXT NOT NULL, + sources TEXT, -- JSON配列: 引用ソース情報 + created_at DATETIME DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY (search_history_id) REFERENCES search_history(id) ON DELETE CASCADE +); +``` + +### 既存テーブルの修正 + +```sql +-- knowledge_base テーブルに PDF パスフィールドを追加 +ALTER TABLE knowledge_base ADD COLUMN pdf_path TEXT; +``` + +## 🔌 API エンドポイント設計 + +### ナレッジベースグループ API + +```typescript +// ユーザーの全グループを取得 +GET /api/knowledge-groups +Response: { + groups: Array<{ + id: string; + name: string; + description?: string; + color: string; + fileCount: number; // 含まれるファイル数 + createdAt: string; + }> +} + +// グループの作成 +POST /api/knowledge-groups +Body: { name: string; description?: string; color?: string } +Response: { id: string; name: string; description?: string; color: string } + +// グループの更新 +PUT /api/knowledge-groups/:id +Body: { name?: string; description?: string; color?: string } + +// グループの削除 +DELETE /api/knowledge-groups/:id + +// グループ内のファイルを取得 +GET /api/knowledge-groups/:id/files +Response: { files: KnowledgeBase[] } + +// ファイルをグループに追加 +POST /api/knowledge-bases/:fileId/groups +Body: { groupIds: string[] } + +// グループからファイルを削除 +DELETE /api/knowledge-bases/:fileId/groups/:groupId +``` + +### 検索履歴 API + +```typescript +// 検索履歴の取得 (ページネーション) +GET /api/search-history?page=1&limit=20 +Response: { + histories: Array<{ + id: string; + title: string; + selectedGroups: string[] | null; + messageCount: number; + lastMessageAt: string; + createdAt: string; + }>; + total: number; + page: number; + limit: number; +} + +// 対話詳細の取得 +GET /api/search-history/:id +Response: { + id: string; + title: string; + selectedGroups: string[] | null; + messages: Array<{ + id: string; + role: 'user' | 'assistant'; + content: string; + sources?: Array<{ + fileName: string; + content: string; + score: number; + chunkIndex: number; + }>; + createdAt: string; + }>; +} + +// 新しい対話の作成 +POST /api/search-history +Body: { + title: string; + selectedGroups?: string[]; + firstMessage: string; +} +Response: { id: string } + +// 対話の削除 +DELETE /api/search-history/:id + +// 対話の継続 (既存のチャットインターフェースを拡張し、historyId パラメータを追加) +POST /api/chat/stream +Body: { + message: string; + history: ChatMessage[]; + userLanguage?: string; + selectedGroups?: string[]; // 新規:選択されたグループ + historyId?: string; // 新規:対話履歴ID +} +``` + +### PDF プレビュー API + +```typescript +// ファイルの PDF プレビューを取得 +GET /api/knowledge-bases/:id/pdf +Response: PDF ファイルストリーム、または PDF URL へのリダイレクト + +// PDF ステータスの確認 +GET /api/knowledge-bases/:id/pdf-status +Response: { + status: 'pending' | 'converting' | 'ready' | 'failed'; + pdfPath?: string; + error?: string; +} +``` + +## 🎨 フロントエンドコンポーネント設計 + +### 1. ナレッジベースグループコンポーネント + +```typescript +// グループマネージャー +interface GroupManagerProps { + groups: KnowledgeGroup[]; + onCreateGroup: (group: CreateGroupData) => void; + onUpdateGroup: (id: string, data: UpdateGroupData) => void; + onDeleteGroup: (id: string) => void; +} + +// グループセレクター (検索時の選択用) +interface GroupSelectorProps { + groups: KnowledgeGroup[]; + selectedGroups: string[]; + onSelectionChange: (groupIds: string[]) => void; + showSelectAll?: boolean; +} + +// ファイルグループタグ +interface FileGroupTagsProps { + fileId: string; + groups: KnowledgeGroup[]; + assignedGroups: string[]; + onGroupsChange: (groupIds: string[]) => void; +} +``` + +### 2. 検索履歴コンポーネント + +```typescript +// 履歴リスト +interface SearchHistoryListProps { + histories: SearchHistoryItem[]; + onSelectHistory: (historyId: string) => void; + onDeleteHistory: (historyId: string) => void; + onLoadMore: () => void; + hasMore: boolean; +} + +// 履歴対話ビューアー +interface HistoryViewerProps { + historyId: string; + onContinueChat: (historyId: string) => void; + onClose: () => void; +} +``` + +### 3. PDF プレビューコンポーネント + +```typescript +// PDF プレビューアー +interface PDFPreviewProps { + fileId: string; + fileName: string; + onClose: () => void; +} + +// PDF プレビューボタン +interface PDFPreviewButtonProps { + fileId: string; + fileName: string; + status: 'pending' | 'converting' | 'ready' | 'failed'; +} +``` + +## 🔄 ビジネスフロー設計 + +### ナレッジベースグループ化フロー + +``` +1. ユーザーがグループを作成 → knowledge_groups テーブルに保存 +2. ファイルアップロード時 → グループを選択可能 → knowledge_base_groups テーブルに関連付けを保存 +3. 検索時 → グループを選択 → Elasticsearch のクエリ範囲をフィルタリング +4. ファイル管理 → ファイルの所属グループを編集可能 +``` + +### 検索履歴フロー + +``` +1. ユーザーがチャットを開始 → search_history データを生成 +2. 各メッセージ → chat_messages テーブルに保存 +3. 履歴の確認 → 履歴リストをページネーションでロード +4. 履歴をクリック → 対話内容全体をロード +5. 対話の継続 → 既存の履歴をベースに新しいメッセージを追加 +``` + +### PDF プレビューフロー + +``` +1. ファイルアップロード → PDF かどうかを確認 +2. PDF 以外の場合 → LibreOffice を呼び出して PDF に変換 +3. PDF パスを knowledge_base.pdf_path に保存 +4. フロントエンドからプレビューをリクエスト → PDF ファイルストリームを返却 +5. HTML の または