anhuiqiang 2 周之前
父節點
當前提交
558d96e5ec
共有 41 個文件被更改,包括 453 次插入284 次删除
  1. 9 0
      .antigravityrules
  2. 9 0
      .cursorrules
  3. 4 4
      CLAUDE.md
  4. 43 0
      apply_translations.js
  5. 8 9
      docs/1.0/DEVELOPMENT_STANDARDS.md
  6. 37 0
      extract_logs.js
  7. 29 0
      extract_strings.js
  8. 4 0
      files_to_translate.json
  9. 0 0
      server/database.sqlite
  10. 49 49
      server/scripts/test-error-handling.js
  11. 49 49
      server/scripts/test-error-handling.ts
  12. 24 24
      server/scripts/test-vision-pipeline.js
  13. 24 24
      server/scripts/test-vision-pipeline.ts
  14. 3 3
      server/src/chat/chat.controller.ts
  15. 10 10
      server/src/chat/chat.service.ts
  16. 9 9
      server/src/elasticsearch/elasticsearch.service.ts
  17. 1 1
      server/src/knowledge-base/chunk-config.service.ts
  18. 11 11
      server/src/knowledge-base/embedding.service.ts
  19. 1 1
      server/src/knowledge-base/knowledge-base.controller.ts
  20. 26 26
      server/src/knowledge-base/knowledge-base.service.ts
  21. 10 10
      server/src/knowledge-base/memory-monitor.service.ts
  22. 4 4
      server/src/ocr/ocr.controller.ts
  23. 7 7
      server/src/ocr/ocr.service.ts
  24. 5 5
      server/src/pdf2image/pdf2image.service.ts
  25. 1 1
      server/src/rag/rag.service.ts
  26. 4 4
      server/src/user-setting/user-setting.service.ts
  27. 2 2
      server/src/user/user.service.ts
  28. 4 4
      server/src/vision-pipeline/cost-control.service.ts
  29. 2 2
      server/src/vision-pipeline/vision-pipeline-cost-aware.service.ts
  30. 13 13
      server/src/vision/vision.service.ts
  31. 26 0
      server/test_db.py
  32. 4 0
      translation_map.json
  33. 3 0
      web/.env
  34. 3 0
      web/.env.example
  35. 1 1
      web/components/ImportFolderDrawer.tsx
  36. 1 1
      web/components/IndexingModal.tsx
  37. 2 2
      web/components/IndexingModalWithMode.tsx
  38. 1 1
      web/components/ModeSelector.tsx
  39. 4 2
      web/components/drawers/ImportTasksDrawer.tsx
  40. 2 1
      web/contexts/LanguageContext.tsx
  41. 4 4
      web/services/settingsService.ts

+ 9 - 0
.antigravityrules

@@ -0,0 +1,9 @@
+# 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.

+ 9 - 0
.cursorrules

@@ -0,0 +1,9 @@
+# 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.

+ 4 - 4
CLAUDE.md

@@ -113,8 +113,8 @@ simple-kb/
 ## Code Standards
 
 ### Language Requirements
-- **Code comments must be in Japanese** (updated from Chinese as per user requirement)
-- **Log messages must be in Japanese**
+- **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
@@ -198,6 +198,6 @@ docker-compose up -d  # Builds and starts all services
 - **docs/**: Comprehensive documentation (mostly Japanese/Chinese)
 - **DESIGN.md**: System architecture and design
 - **API.md**: API reference
-- **DEVELOPMENT_STANDARDS.md**: Mandates Japanese comments/logs
+- **DEVELOPMENT_STANDARDS.md**: Mandates English comments/logs and internationalized messages
 
-When modifying code, always add Japanese comments as required by development standards. The project has extensive existing documentation in Japanese/Chinese - refer to `docs/` directory for detailed technical information.
+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.

+ 43 - 0
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);

+ 8 - 9
docs/1.0/DEVELOPMENT_STANDARDS.md

@@ -4,7 +4,7 @@
 
 ### 1. コメントの言語
 
-- **すべてのコードコメントは中国語を使用する必要があります**
+- **すべてのコードコメントは語を使用する必要があります**
 - 以下を含みますが、これらに限定されません:
   - 関数/メソッドのコメント
   - 行内コメント
@@ -13,18 +13,17 @@
 
 ### 2. ログ出力の基準
 
-- **すべてのログ出力は中国語を使用する必要があります**
+- **すべてのログ出力は語を使用する必要があります**
 - 以下を含みますが、これらに限定されません:
   - `logger.log()` 情報ログ
   - `logger.warn()` 警告ログ
   - `logger.error()` ラーログ
   - `console.log()` デバッグ出力
 
-### 3. エラーメッセージの基準
+### 3. メッセージの基準
 
-- **ユーザーに表示されるエラーメッセージは中国語を使用します**
-- **開発デバッグ用のエラーメッセージは中国語を使用します**
-- 例外スロー時のエラーメッセージには中国語を使用します
+- **すべてのメッセージ(エラー、APIレスポンス、UIテキストなど)は国際化(i18n)を保証する必要があります**
+- ハードコードされた文字列を直接使用せず、必ず翻訳キーを使用してください
 
 ## 例
 
@@ -66,6 +65,6 @@ async getEmbeddings(texts: string[]): Promise<number[][]> {
 
 ## 履行基準
 
-1. **コードレビュー時には、必ずコメントとログの言語をチェックしてください**
-2. **新規コードは、中国語のコメントとログの基準に従う必要があります**
-3. **既存のコードをリファクタリングする際は、同時にコメントとログも中国語に更新してください**
+1. **コードレビュー時には、必ずコメントとログが英語であること、およびメッセージが国際化されているかをチェックしてください**
+2. **新規コードは、英語のコメントとログ、および国際化されたメッセージの基準に従う必要があります**
+3. **既存のコードをリファクタリングする際は、同時にコメントとログを英語に更新し、メッセージを国際化してください**

+ 37 - 0
extract_logs.js

@@ -0,0 +1,37 @@
+const fs = require('fs');
+const path = require('path');
+
+function walkDir(dir, callback) {
+    fs.readdirSync(dir).forEach(f => {
+        let dirPath = path.join(dir, f);
+        let isDirectory = fs.statSync(dirPath).isDirectory();
+        if (isDirectory) {
+            if (f !== 'node_modules' && f !== '.git' && f !== 'dist' && f !== '.next' && f !== 'build' && f !== 'coverage') {
+                walkDir(dirPath, callback);
+            }
+        } else {
+            if (dirPath.endsWith('.ts') || dirPath.endsWith('.tsx') || dirPath.endsWith('.js')) {
+                callback(path.join(dir, f));
+            }
+        }
+    });
+}
+
+const filesWithLogs = [];
+const logRegex = /(console|logger|Logger)\.(log|error|warn|info|debug|verbose)\(([^)]*[\u4e00-\u9fa5]+[^)]*)\)/g;
+
+walkDir('d:/workspace/AuraK/server', (filePath) => {
+    const content = fs.readFileSync(filePath, 'utf8');
+    if (logRegex.test(content)) {
+        filesWithLogs.push(filePath);
+    }
+});
+walkDir('d:/workspace/AuraK/web', (filePath) => {
+    const content = fs.readFileSync(filePath, 'utf8');
+    if (logRegex.test(content)) {
+        filesWithLogs.push(filePath);
+    }
+});
+
+console.log('Found ' + filesWithLogs.length + ' files');
+fs.writeFileSync('d:/workspace/AuraK/files_to_translate.json', JSON.stringify(filesWithLogs, null, 2));

+ 29 - 0
extract_strings.js

@@ -0,0 +1,29 @@
+const fs = require('fs');
+
+const files = require('./files_to_translate.json');
+const translationMap = {};
+
+const logRegex = /(?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*((?:[\'\"\`])(?:.*?)[\u4e00-\u9fa5]+(?:.*?)(?:[\'\"\`]))/g;
+// We also need to catch template literals that have variables, e.g. `User ${userId} created`
+const logRegexTemplate = /(?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*(\`(?:.*?)\`)/gs;
+
+files.forEach(file => {
+    const content = fs.readFileSync(file, 'utf8');
+    let match;
+    // Match single/double quotes with Chinese
+    const simpleStringRegex = /(?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*(['"])(.*?[\u4e00-\u9fa5]+.*?)\1/g;
+    while ((match = simpleStringRegex.exec(content)) !== null) {
+        translationMap[match[2]] = ""; // The inner string
+    }
+
+    // Match template literals with Chinese
+    const templateRegex = /(?:console|logger|Logger|this\.logger)\.(?:log|error|warn|info|debug|verbose)\(\s*\`([\s\S]*?)\`/g;
+    while ((match = templateRegex.exec(content)) !== null) {
+        if (/[\u4e00-\u9fa5]/.test(match[1])) {
+            translationMap[match[1]] = "";
+        }
+    }
+});
+
+fs.writeFileSync('translation_map.json', JSON.stringify(translationMap, null, 2));
+console.log('Extracted ' + Object.keys(translationMap).length + ' distinct strings.');

+ 4 - 0
files_to_translate.json

@@ -0,0 +1,4 @@
+[
+  "d:\\workspace\\AuraK\\server\\src\\knowledge-base\\embedding.service.ts",
+  "d:\\workspace\\AuraK\\server\\src\\vision\\vision.service.ts"
+]

+ 0 - 0
server/database.sqlite


+ 49 - 49
server/scripts/test-error-handling.js

@@ -43,12 +43,12 @@ const vision_pipeline_service_1 = require("./src/vision-pipeline/vision-pipeline
 const fs = __importStar(require("fs/promises"));
 const path = __importStar(require("path"));
 async function testErrorHandling() {
-    console.log('🧪 开始错误处理和降级机制测试\n');
+    console.log('🧪 Starting error handling and degradation mechanism tests\n');
     const app = await core_1.NestFactory.createApplicationContext(app_module_1.AppModule, {
         logger: ['error', 'warn', 'log'],
     });
     try {
-        console.log('=== 测试 1: LibreOffice 服务不可用 ===');
+        console.log('=== Test 1: LibreOffice service unavailable ===');
         const libreOffice = app.get(libreoffice_service_1.LibreOfficeService);
         try {
             const originalUrl = process.env.LIBREOFFICE_URL;
@@ -58,57 +58,57 @@ async function testErrorHandling() {
             if (await fs.access(testWord).then(() => true).catch(() => false)) {
                 try {
                     await libreOffice.convertToPDF(testWord);
-                    console.log('❌ 应该失败但成功了');
+                    console.log('❌ Should have failed but succeeded');
                 }
                 catch (error) {
-                    console.log(`✅ 正确捕获错误: ${error.message}`);
+                    console.log(`✅ Correctly caught error: ${error.message}`);
                 }
             }
             else {
-                console.log('⚠️  测试 Word 文件不存在,跳过此部分');
+                console.log('⚠️  Test Word file does not exist, skipping this part');
             }
             process.env.LIBREOFFICE_URL = originalUrl;
         }
         catch (error) {
-            console.log('✅ LibreOffice 错误处理测试完成');
+            console.log('✅ LibreOffice error handling test complete');
         }
-        console.log('\n=== 测试 2: PDF 转图片失败 ===');
+        console.log('\n=== Test 2: PDF to Image conversion failed ===');
         const pdf2Image = app.get(pdf2image_service_1.Pdf2ImageService);
         try {
             await pdf2Image.convertToImages('/nonexistent/file.pdf');
-            console.log('❌ 应该失败但成功了');
+            console.log('❌ Should have failed but succeeded');
         }
         catch (error) {
-            console.log(`✅ 正确捕获错误: ${error.message}`);
+            console.log(`✅ Correctly caught error: ${error.message}`);
         }
-        console.log('\n=== 测试 3: Vision Pipeline 降级机制 ===');
+        console.log('\n=== Test 3: Vision Pipeline degradation mechanism ===');
         const visionPipeline = app.get(vision_pipeline_service_1.VisionPipelineService);
         const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf';
         if (await fs.access(testPdf).then(() => true).catch(() => false)) {
-            console.log(`测试文件: ${path.basename(testPdf)}`);
+            console.log(`Test file: ${path.basename(testPdf)}`);
             const recommendation = await visionPipeline.recommendMode(testPdf);
-            console.log(`模式推荐: ${recommendation.recommendedMode}`);
-            console.log(`原因: ${recommendation.reason}`);
+            console.log(`Recommended mode: ${recommendation.recommendedMode}`);
+            console.log(`Reason: ${recommendation.reason}`);
             if (recommendation.recommendedMode === 'precise') {
-                console.log('\n⚠️  注意: 完整流程测试需要:');
-                console.log('  1. LibreOffice 服务运行');
-                console.log('  2. ImageMagick 安装');
-                console.log('  3. Vision 模型 API Key 配置');
-                console.log('\n如需完整测试,请手动配置以上环境');
+                console.log('\n⚠️  Note: Full pipeline testing requires:');
+                console.log('  1. LibreOffice service running');
+                console.log('  2. ImageMagick installed');
+                console.log('  3. Vision model API Key configured');
+                console.log('\nTo run full test, please manually configure the above environments');
             }
         }
         else {
-            console.log('⚠️  未找到测试文件');
+            console.log('⚠️  Test files not found');
         }
-        console.log('\n=== 测试 4: KnowledgeBase 降级逻辑 ===');
+        console.log('\n=== Test 4: KnowledgeBase degradation logic ===');
         const kbService = app.get(knowledge_base_service_1.KnowledgeBaseService);
-        console.log('降级逻辑检查:');
-        console.log('✅ 支持的格式: PDF, DOC, DOCX, PPT, PPTX');
-        console.log('✅ 检查 Vision 模型配置');
-        console.log('✅ 自动降级到快速模式');
-        console.log('✅ 错误日志记录');
-        console.log('✅ 临时文件清理');
-        console.log('\n=== 测试 5: 环境配置验证 ===');
+        console.log('Degradation logic check:');
+        console.log('✅ Supported formats: PDF, DOC, DOCX, PPT, PPTX');
+        console.log('✅ Check Vision model configuration');
+        console.log('✅ Auto-degrade to fast mode');
+        console.log('✅ Error logging');
+        console.log('✅ Temporary file cleanup');
+        console.log('\n=== Test 5: Environment configuration validation ===');
         const configService = app.get(require('@nestjs/config').ConfigService);
         const checks = [
             { name: 'LIBREOFFICE_URL', required: true },
@@ -122,52 +122,52 @@ async function testErrorHandling() {
             const value = configService.get(check.name);
             const passed = check.required ? !!value : true;
             const status = passed ? '✅' : '❌';
-            console.log(`${status} ${check.name}: ${value || '未配置'}`);
+            console.log(`${status} ${check.name}: ${value || 'Not configured'}`);
             if (!passed)
                 allPassed = false;
         }
         if (allPassed) {
-            console.log('\n🎉 所有配置检查通过!');
+            console.log('\n🎉 All configuration checks passed!');
         }
         else {
-            console.log('\n⚠️  请检查缺失的配置项');
+            console.log('\n⚠️  Please check missing configuration items');
         }
-        console.log('\n=== 测试 6: 临时文件清理机制 ===');
+        console.log('\n=== Test 6: Temporary file cleanup mechanism ===');
         try {
             const tempDir = configService.get('TEMP_DIR', './temp');
             const tempExists = await fs.access(tempDir).then(() => true).catch(() => false);
             if (tempExists) {
-                console.log(`✅ 临时目录存在: ${tempDir}`);
+                console.log(`✅ Temporary directory exists: ${tempDir}`);
                 const files = await fs.readdir(tempDir);
                 if (files.length > 0) {
-                    console.log(`⚠️  发现 ${files.length} 个临时文件,建议清理`);
+                    console.log(`⚠️  Found ${files.length} temporary files, cleanup recommended`);
                 }
                 else {
-                    console.log('✅ 临时目录为空');
+                    console.log('✅ Temporary directory is empty');
                 }
             }
             else {
-                console.log('⚠️  临时目录不存在,将在首次运行时创建');
+                console.log('⚠️  Temporary directory does not exist, will be created on first run');
             }
         }
         catch (error) {
-            console.log(`❌ 临时目录检查失败: ${error.message}`);
+            console.log(`❌ Temporary directory check failed: ${error.message}`);
         }
-        console.log('\n=== 错误处理测试总结 ===');
-        console.log('✅ LibreOffice 连接错误处理');
-        console.log('✅ PDF 转图片失败处理');
-        console.log('✅ Vision 模型错误处理');
-        console.log('✅ 自动降级到快速模式');
-        console.log('✅ 临时文件清理');
-        console.log('✅ 环境配置验证');
-        console.log('\n💡 建议:');
-        console.log('  1. 在生产环境中添加更多监控');
-        console.log('  2. 实现用户配额限制');
-        console.log('  3. 添加处理超时机制');
-        console.log('  4. 定期清理临时文件');
+        console.log('\n=== Error Handling Test Summary ===');
+        console.log('✅ LibreOffice connection error handling');
+        console.log('✅ PDF to Image conversion failure handling');
+        console.log('✅ Vision model error handling');
+        console.log('✅ Auto-degrade to fast mode');
+        console.log('✅ Temporary file cleanup');
+        console.log('✅ Environment configuration validation');
+        console.log('\n💡 Suggestions:');
+        console.log('  1. Add more monitoring in production environment');
+        console.log('  2. Implement user quota limits');
+        console.log('  3. Add processing timeout mechanism');
+        console.log('  4. Regularly clean up temporary files');
     }
     catch (error) {
-        console.error('❌ 测试失败:', error.message);
+        console.error('❌ Test failed:', error.message);
         console.error(error.stack);
     }
     finally {

+ 49 - 49
server/scripts/test-error-handling.ts

@@ -14,7 +14,7 @@ import * as fs from 'fs/promises';
 import * as path from 'path';
 
 async function testErrorHandling() {
-  console.log('🧪 开始错误处理和降级机制测试\n');
+  console.log('🧪 Starting error handling and degradation mechanism tests\n');
 
   const app = await NestFactory.createApplicationContext(AppModule, {
     logger: ['error', 'warn', 'log'],
@@ -22,7 +22,7 @@ async function testErrorHandling() {
 
   try {
     // 测试 1: LibreOffice 服务不可用
-    console.log('=== 测试 1: LibreOffice 服务不可用 ===');
+    console.log('=== Test 1: LibreOffice service unavailable ===');
     const libreOffice = app.get(LibreOfficeService);
 
     try {
@@ -37,71 +37,71 @@ async function testErrorHandling() {
       if (await fs.access(testWord).then(() => true).catch(() => false)) {
         try {
           await libreOffice.convertToPDF(testWord);
-          console.log('❌ 应该失败但成功了');
+          console.log('❌ Should have failed but succeeded');
         } catch (error) {
-          console.log(`✅ 正确捕获错误: ${error.message}`);
+          console.log(`✅ Correctly caught error: ${error.message}`);
         }
       } else {
-        console.log('⚠️  测试 Word 文件不存在,跳过此部分');
+        console.log('⚠️  Test Word file does not exist, skipping this part');
       }
 
       // 恢复配置
       process.env.LIBREOFFICE_URL = originalUrl;
     } catch (error) {
-      console.log('✅ LibreOffice 错误处理测试完成');
+      console.log('✅ LibreOffice error handling test complete');
     }
 
     // 测试 2: PDF 转图片失败
-    console.log('\n=== 测试 2: PDF 转图片失败 ===');
+    console.log('\n=== Test 2: PDF to Image conversion failed ===');
     const pdf2Image = app.get(Pdf2ImageService);
 
     try {
       // 测试不存在的 PDF
       await pdf2Image.convertToImages('/nonexistent/file.pdf');
-      console.log('❌ 应该失败但成功了');
+      console.log('❌ Should have failed but succeeded');
     } catch (error) {
-      console.log(`✅ 正确捕获错误: ${error.message}`);
+      console.log(`✅ Correctly caught error: ${error.message}`);
     }
 
     // 测试 3: Vision Pipeline 完整流程 - 降级测试
-    console.log('\n=== 测试 3: Vision Pipeline 降级机制 ===');
+    console.log('\n=== Test 3: Vision Pipeline degradation mechanism ===');
     const visionPipeline = app.get(VisionPipelineService);
 
     // 检查是否有测试文件
     const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf';
     if (await fs.access(testPdf).then(() => true).catch(() => false)) {
-      console.log(`测试文件: ${path.basename(testPdf)}`);
+      console.log(`Test file: ${path.basename(testPdf)}`);
 
       // 测试模式推荐
       const recommendation = await visionPipeline.recommendMode(testPdf);
-      console.log(`模式推荐: ${recommendation.recommendedMode}`);
-      console.log(`原因: ${recommendation.reason}`);
+      console.log(`Recommended mode: ${recommendation.recommendedMode}`);
+      console.log(`Reason: ${recommendation.reason}`);
 
       // 如果推荐精准模式,测试流程
       if (recommendation.recommendedMode === 'precise') {
-        console.log('\n⚠️  注意: 完整流程测试需要:');
-        console.log('  1. LibreOffice 服务运行');
-        console.log('  2. ImageMagick 安装');
-        console.log('  3. Vision 模型 API Key 配置');
-        console.log('\n如需完整测试,请手动配置以上环境');
+        console.log('\n⚠️  Note: Full pipeline testing requires:');
+        console.log('  1. LibreOffice service running');
+        console.log('  2. ImageMagick installed');
+        console.log('  3. Vision model API Key configured');
+        console.log('\nTo run full test, please manually configure the above environments');
       }
     } else {
-      console.log('⚠️  未找到测试文件');
+      console.log('⚠️  Test files not found');
     }
 
     // 测试 4: KnowledgeBase 降级逻辑
-    console.log('\n=== 测试 4: KnowledgeBase 降级逻辑 ===');
+    console.log('\n=== Test 4: KnowledgeBase degradation logic ===');
     const kbService = app.get(KnowledgeBaseService);
 
-    console.log('降级逻辑检查:');
-    console.log('✅ 支持的格式: PDF, DOC, DOCX, PPT, PPTX');
-    console.log('✅ 检查 Vision 模型配置');
-    console.log('✅ 自动降级到快速模式');
-    console.log('✅ 错误日志记录');
-    console.log('✅ 临时文件清理');
+    console.log('Degradation logic check:');
+    console.log('✅ Supported formats: PDF, DOC, DOCX, PPT, PPTX');
+    console.log('✅ Check Vision model configuration');
+    console.log('✅ Auto-degrade to fast mode');
+    console.log('✅ Error logging');
+    console.log('✅ Temporary file cleanup');
 
     // 测试 5: 环境配置验证
-    console.log('\n=== 测试 5: 环境配置验证 ===');
+    console.log('\n=== Test 5: Environment configuration validation ===');
     const configService = app.get(require('@nestjs/config').ConfigService);
 
     const checks = [
@@ -117,55 +117,55 @@ async function testErrorHandling() {
       const value = configService.get(check.name);
       const passed = check.required ? !!value : true;
       const status = passed ? '✅' : '❌';
-      console.log(`${status} ${check.name}: ${value || '未配置'}`);
+      console.log(`${status} ${check.name}: ${value || 'Not configured'}`);
       if (!passed) allPassed = false;
     }
 
     if (allPassed) {
-      console.log('\n🎉 所有配置检查通过!');
+      console.log('\n🎉 All configuration checks passed!');
     } else {
-      console.log('\n⚠️  请检查缺失的配置项');
+      console.log('\n⚠️  Please check missing configuration items');
     }
 
     // 测试 6: 临时文件清理机制
-    console.log('\n=== 测试 6: 临时文件清理机制 ===');
+    console.log('\n=== Test 6: Temporary file cleanup mechanism ===');
     try {
       // 检查临时目录
       const tempDir = configService.get('TEMP_DIR', './temp');
       const tempExists = await fs.access(tempDir).then(() => true).catch(() => false);
 
       if (tempExists) {
-        console.log(`✅ 临时目录存在: ${tempDir}`);
+        console.log(`✅ Temporary directory exists: ${tempDir}`);
 
         // 检查是否有遗留文件
         const files = await fs.readdir(tempDir);
         if (files.length > 0) {
-          console.log(`⚠️  发现 ${files.length} 个临时文件,建议清理`);
+          console.log(`⚠️  Found ${files.length} temporary files, cleanup recommended`);
         } else {
-          console.log('✅ 临时目录为空');
+          console.log('✅ Temporary directory is empty');
         }
       } else {
-        console.log('⚠️  临时目录不存在,将在首次运行时创建');
+        console.log('⚠️  Temporary directory does not exist, will be created on first run');
       }
     } catch (error) {
-      console.log(`❌ 临时目录检查失败: ${error.message}`);
+      console.log(`❌ Temporary directory check failed: ${error.message}`);
     }
 
-    console.log('\n=== 错误处理测试总结 ===');
-    console.log('✅ LibreOffice 连接错误处理');
-    console.log('✅ PDF 转图片失败处理');
-    console.log('✅ Vision 模型错误处理');
-    console.log('✅ 自动降级到快速模式');
-    console.log('✅ 临时文件清理');
-    console.log('✅ 环境配置验证');
-    console.log('\n💡 建议:');
-    console.log('  1. 在生产环境中添加更多监控');
-    console.log('  2. 实现用户配额限制');
-    console.log('  3. 添加处理超时机制');
-    console.log('  4. 定期清理临时文件');
+    console.log('\n=== Error Handling Test Summary ===');
+    console.log('✅ LibreOffice connection error handling');
+    console.log('✅ PDF to Image conversion failure handling');
+    console.log('✅ Vision model error handling');
+    console.log('✅ Auto-degrade to fast mode');
+    console.log('✅ Temporary file cleanup');
+    console.log('✅ Environment configuration validation');
+    console.log('\n💡 Suggestions:');
+    console.log('  1. Add more monitoring in production environment');
+    console.log('  2. Implement user quota limits');
+    console.log('  3. Add processing timeout mechanism');
+    console.log('  4. Regularly clean up temporary files');
 
   } catch (error) {
-    console.error('❌ 测试失败:', error.message);
+    console.error('❌ Test failed:', error.message);
     console.error(error.stack);
   } finally {
     await app.close();

+ 24 - 24
server/scripts/test-vision-pipeline.js

@@ -42,38 +42,38 @@ const pdf2image_service_1 = require("./src/pdf2image/pdf2image.service");
 const fs = __importStar(require("fs/promises"));
 const path = __importStar(require("path"));
 async function testVisionPipeline() {
-    console.log('🚀 开始 Vision Pipeline 端到端测试\n');
+    console.log('🚀 Starting Vision Pipeline end-to-end test\n');
     const app = await core_1.NestFactory.createApplicationContext(app_module_1.AppModule, {
         logger: ['error', 'warn', 'log'],
     });
     try {
-        console.log('=== 测试 1: LibreOffice 服务 ===');
+        console.log('=== Test 1: LibreOffice service ===');
         const libreOffice = app.get(libreoffice_service_1.LibreOfficeService);
         const isHealthy = await libreOffice.healthCheck();
-        console.log(`LibreOffice 健康检查: ${isHealthy ? '✅ 通过' : '❌ 失败'}`);
+        console.log(`LibreOffice health check: ${isHealthy ? '✅ Passed' : '❌ Failed'}`);
         if (!isHealthy) {
-            console.log('⚠️  LibreOffice 服务未运行,跳过后续测试');
+            console.log('⚠️  LibreOffice service not running, skipping subsequent tests');
             return;
         }
-        console.log('\n=== 测试 2: PDF 转图片服务 ===');
+        console.log('\n=== Test 2: PDF to Image service ===');
         const pdf2Image = app.get(pdf2image_service_1.Pdf2ImageService);
         const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf';
         if (await fs.access(testPdf).then(() => true).catch(() => false)) {
-            console.log(`测试 PDF: ${path.basename(testPdf)}`);
+            console.log(`Test PDF: ${path.basename(testPdf)}`);
             const result = await pdf2Image.convertToImages(testPdf, {
                 density: 150,
                 quality: 75,
                 format: 'jpeg',
             });
-            console.log(`✅ 转换成功: ${result.images.length}/${result.totalPages} 页`);
-            console.log(`   成功: ${result.successCount}, 失败: ${result.failedCount}`);
+            console.log(`✅ Conversion successful: ${result.images.length}/${result.totalPages} pages`);
+            console.log(`   Success: ${result.successCount}, Failed: ${result.failedCount}`);
             await pdf2Image.cleanupImages(result.images);
-            console.log('✅ 临时文件已清理');
+            console.log('✅ Temporary files cleaned up');
         }
         else {
-            console.log('⚠️  测试 PDF 文件不存在,跳过此测试');
+            console.log('⚠️  Test PDF file does not exist, skipping this test');
         }
-        console.log('\n=== 测试 3: Vision Pipeline 完整流程 ===');
+        console.log('\n=== Test 3: Vision Pipeline complete flow ===');
         const visionPipeline = app.get(vision_pipeline_service_1.VisionPipelineService);
         const testFiles = [
             '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf',
@@ -87,26 +87,26 @@ async function testVisionPipeline() {
             }
         }
         if (testFile) {
-            console.log(`测试文件: ${path.basename(testFile)}`);
+            console.log(`Test file: ${path.basename(testFile)}`);
             const recommendation = await visionPipeline.recommendMode(testFile);
-            console.log(`模式推荐: ${recommendation.recommendedMode}`);
-            console.log(`原因: ${recommendation.reason}`);
+            console.log(`Recommended mode: ${recommendation.recommendedMode}`);
+            console.log(`Reason: ${recommendation.reason}`);
             if (recommendation.estimatedCost) {
-                console.log(`预估成本: $${recommendation.estimatedCost.toFixed(2)}`);
+                console.log(`Estimated cost: $${recommendation.estimatedCost.toFixed(2)}`);
             }
             if (recommendation.estimatedTime) {
-                console.log(`预估时间: ${recommendation.estimatedTime.toFixed(1)}s`);
+                console.log(`Estimated time: ${recommendation.estimatedTime.toFixed(1)}s`);
             }
             if (recommendation.warnings && recommendation.warnings.length > 0) {
-                console.log(`警告: ${recommendation.warnings.join(', ')}`);
+                console.log(`Warnings: ${recommendation.warnings.join(', ')}`);
             }
-            console.log('\n✅ Vision Pipeline 模块已正确配置');
-            console.log('   注意: 完整流程测试需要配置有效的 Vision 模型 API Key');
+            console.log('\n✅ Vision Pipeline module correctly configured');
+            console.log('   Note: Full flow testing requires a valid Vision model API Key');
         }
         else {
-            console.log('⚠️  未找到测试文件,跳过完整流程测试');
+            console.log('⚠️  Test files not found, skipping complete flow test');
         }
-        console.log('\n=== 测试 4: 环境配置检查 ===');
+        console.log('\n=== Test 4: Environment configuration check ===');
         const configService = app.get(require('@nestjs/config').ConfigService);
         const requiredEnvVars = [
             'LIBREOFFICE_URL',
@@ -120,13 +120,13 @@ async function testVisionPipeline() {
                 console.log(`✅ ${envVar}: ${value}`);
             }
             else {
-                console.log(`❌ ${envVar}: 未配置`);
+                console.log(`❌ ${envVar}: Not configured`);
             }
         }
-        console.log('\n🎉 所有基础测试完成!');
+        console.log('\n🎉 All basic tests completed!');
     }
     catch (error) {
-        console.error('❌ 测试失败:', error.message);
+        console.error('❌ Test failed:', error.message);
         console.error(error.stack);
     }
     finally {

+ 24 - 24
server/scripts/test-vision-pipeline.ts

@@ -18,7 +18,7 @@ import * as fs from 'fs/promises';
 import * as path from 'path';
 
 async function testVisionPipeline() {
-  console.log('🚀 开始 Vision Pipeline 端到端测试\n');
+  console.log('🚀 Starting Vision Pipeline end-to-end test\n');
 
   // 初始化 Nest 应用
   const app = await NestFactory.createApplicationContext(AppModule, {
@@ -27,25 +27,25 @@ async function testVisionPipeline() {
 
   try {
     // 1. 测试 LibreOffice 服务
-    console.log('=== 测试 1: LibreOffice 服务 ===');
+    console.log('=== Test 1: LibreOffice service ===');
     const libreOffice = app.get(LibreOfficeService);
 
     // 检查健康状态
     const isHealthy = await libreOffice.healthCheck();
-    console.log(`LibreOffice 健康检查: ${isHealthy ? '✅ 通过' : '❌ 失败'}`);
+    console.log(`LibreOffice health check: ${isHealthy ? '✅ Passed' : '❌ Failed'}`);
 
     if (!isHealthy) {
-      console.log('⚠️  LibreOffice 服务未运行,跳过后续测试');
+      console.log('⚠️  LibreOffice service not running, skipping subsequent tests');
       return;
     }
 
     // 2. 测试 PDF 转图片服务
-    console.log('\n=== 测试 2: PDF 转图片服务 ===');
+    console.log('\n=== Test 2: PDF to Image service ===');
     const pdf2Image = app.get(Pdf2ImageService);
 
     const testPdf = '/home/fzxs/workspaces/demo/simple-kb/uploads/file-1766236004300-577549403.pdf';
     if (await fs.access(testPdf).then(() => true).catch(() => false)) {
-      console.log(`测试 PDF: ${path.basename(testPdf)}`);
+      console.log(`Test PDF: ${path.basename(testPdf)}`);
 
       const result = await pdf2Image.convertToImages(testPdf, {
         density: 150,  // 降低密度以加快测试
@@ -53,18 +53,18 @@ async function testVisionPipeline() {
         format: 'jpeg',
       });
 
-      console.log(`✅ 转换成功: ${result.images.length}/${result.totalPages} 页`);
-      console.log(`   成功: ${result.successCount}, 失败: ${result.failedCount}`);
+      console.log(`✅ Conversion successful: ${result.images.length}/${result.totalPages} pages`);
+      console.log(`   Success: ${result.successCount}, Failed: ${result.failedCount}`);
 
       // 清理测试文件
       await pdf2Image.cleanupImages(result.images);
-      console.log('✅ 临时文件已清理');
+      console.log('✅ Temporary files cleaned up');
     } else {
-      console.log('⚠️  测试 PDF 文件不存在,跳过此测试');
+      console.log('⚠️  Test PDF file does not exist, skipping this test');
     }
 
     // 3. 测试 Vision Pipeline 完整流程
-    console.log('\n=== 测试 3: Vision Pipeline 完整流程 ===');
+    console.log('\n=== Test 3: Vision Pipeline complete flow ===');
     const visionPipeline = app.get(VisionPipelineService);
 
     // 检查是否有支持的测试文件
@@ -82,33 +82,33 @@ async function testVisionPipeline() {
     }
 
     if (testFile) {
-      console.log(`测试文件: ${path.basename(testFile)}`);
+      console.log(`Test file: ${path.basename(testFile)}`);
 
       // 模式推荐测试
       const recommendation = await visionPipeline.recommendMode(testFile);
-      console.log(`模式推荐: ${recommendation.recommendedMode}`);
-      console.log(`原因: ${recommendation.reason}`);
+      console.log(`Recommended mode: ${recommendation.recommendedMode}`);
+      console.log(`Reason: ${recommendation.reason}`);
       if (recommendation.estimatedCost) {
-        console.log(`预估成本: $${recommendation.estimatedCost.toFixed(2)}`);
+        console.log(`Estimated cost: $${recommendation.estimatedCost.toFixed(2)}`);
       }
       if (recommendation.estimatedTime) {
-        console.log(`预估时间: ${recommendation.estimatedTime.toFixed(1)}s`);
+        console.log(`Estimated time: ${recommendation.estimatedTime.toFixed(1)}s`);
       }
       if (recommendation.warnings && recommendation.warnings.length > 0) {
-        console.log(`警告: ${recommendation.warnings.join(', ')}`);
+        console.log(`Warnings: ${recommendation.warnings.join(', ')}`);
       }
 
       // 注意:完整流程测试需要配置 Vision 模型 API Key
       // 这里只测试流程结构
-      console.log('\n✅ Vision Pipeline 模块已正确配置');
-      console.log('   注意: 完整流程测试需要配置有效的 Vision 模型 API Key');
+      console.log('\n✅ Vision Pipeline module correctly configured');
+      console.log('   Note: Full flow testing requires a valid Vision model API Key');
 
     } else {
-      console.log('⚠️  未找到测试文件,跳过完整流程测试');
+      console.log('⚠️  Test files not found, skipping complete flow test');
     }
 
     // 4. 检查环境配置
-    console.log('\n=== 测试 4: 环境配置检查 ===');
+    console.log('\n=== Test 4: Environment configuration check ===');
     const configService = app.get(require('@nestjs/config').ConfigService);
 
     const requiredEnvVars = [
@@ -123,14 +123,14 @@ async function testVisionPipeline() {
       if (value) {
         console.log(`✅ ${envVar}: ${value}`);
       } else {
-        console.log(`❌ ${envVar}: 未配置`);
+        console.log(`❌ ${envVar}: Not configured`);
       }
     }
 
-    console.log('\n🎉 所有基础测试完成!');
+    console.log('\n🎉 All basic tests completed!');
 
   } catch (error) {
-    console.error('❌ 测试失败:', error.message);
+    console.error('❌ Test failed:', error.message);
     console.error(error.stack);
   } finally {
     await app.close();

+ 3 - 3
server/src/chat/chat.controller.ts

@@ -53,7 +53,7 @@ export class ChatController {
       const { message, history = [], userLanguage = 'zh', selectedEmbeddingId, selectedLLMId, selectedGroups, selectedFiles, historyId, enableRerank, selectedRerankId, temperature, maxTokens, topK, similarityThreshold, rerankSimilarityThreshold, enableQueryExpansion, enableHyDE } = body;
       const userId = req.user.id;
 
-      console.log('=== 聊天调试信息 ===');
+      console.log('=== Chat Debug Info ===');
       console.log('User ID:', userId);
       console.log('Message:', message);
       console.log('User Language:', userLanguage);
@@ -87,11 +87,11 @@ export class ChatController {
       if (selectedLLMId) {
         // Find specifically selected model
         llmModel = await this.modelConfigService.findOne(selectedLLMId, userId, tenantId);
-        console.log('使用选中的LLM模型:', llmModel.name);
+        console.log('Using selected LLM model:', llmModel.name);
       } else {
         // Use organization's default LLM from Index Chat Config (strict)
         llmModel = await this.modelConfigService.findDefaultByType(tenantId, ModelType.LLM);
-        console.log('最终使用的LLM模型 (默认):', llmModel ? llmModel.name : '无');
+        console.log('Final LLM model used (default):', llmModel ? llmModel.name : '无');
       }
 
       // 设置 SSE 响应头

+ 10 - 10
server/src/chat/chat.service.ts

@@ -65,25 +65,25 @@ export class ChatService {
   ): AsyncGenerator<{ type: 'content' | 'sources' | 'historyId'; data: any }> {
     console.log('=== ChatService.streamChat ===');
     console.log('ユーザーID:', userId);
-    console.log('ユーザー言語:', userLanguage);
-    console.log('選択された埋め込みモデルID:', selectedEmbeddingId);
-    console.log('選択されたグループ:', selectedGroups);
-    console.log('選択されたファイル:', selectedFiles);
-    console.log('履歴ID:', historyId);
+    console.log('User language:', userLanguage);
+    console.log('Selected embedding model ID:', selectedEmbeddingId);
+    console.log('Selected group:', selectedGroups);
+    console.log('Selected files:', selectedFiles);
+    console.log('History ID:', historyId);
     console.log('Temperature:', temperature);
     console.log('Max Tokens:', maxTokens);
     console.log('Top K:', topK);
-    console.log('類似度しきい値:', similarityThreshold);
-    console.log('Rerankしきい値:', rerankSimilarityThreshold);
-    console.log('Query拡張:', enableQueryExpansion);
+    console.log('Similarity threshold:', similarityThreshold);
+    console.log('Rerank threshold:', rerankSimilarityThreshold);
+    console.log('Query expansion:', enableQueryExpansion);
     console.log('HyDE:', enableHyDE);
-    console.log('モデル設定:', {
+    console.log('Model configuration:', {
       name: modelConfig.name,
       modelId: modelConfig.modelId,
       baseUrl: modelConfig.baseUrl,
     });
     console.log('API Key プレフィックス:', modelConfig.apiKey?.substring(0, 10) + '...');
-    console.log('API Key 長さ:', modelConfig.apiKey?.length);
+    console.log('API Key length:', modelConfig.apiKey?.length);
 
     // 現在の言語設定を取得 (下位互換性のためにLANGUAGE_CONFIGを保持しますが、現在はi18nサービスを使>用)
     // ユーザー設定に基づいて実際の言語を使用

+ 9 - 9
server/src/elasticsearch/elasticsearch.service.ts

@@ -44,7 +44,7 @@ export class ElasticsearchService implements OnModuleInit {
 
     if (!indexExists) {
       this.logger.log(
-        `インデックス ${this.indexName} を作成します。ベクトル次元数: ${vectorDimensions}`,
+        `Creating index ${this.indexName}. Vector dimensions: ${vectorDimensions}`,
       );
       await this.createIndex(vectorDimensions);
     } else {
@@ -59,19 +59,19 @@ export class ElasticsearchService implements OnModuleInit {
 
       if (existingDims && existingDims !== vectorDimensions) {
         this.logger.warn(
-          `インデックス ${this.indexName} のベクトル次元数 ${existingDims} が現在のモデル次元数 ${vectorDimensions} と一致しません。`,
+          `Vector dimensions ${existingDims} of index ${this.indexName} do not match the current model dimensions ${vectorDimensions}.`,
         );
-        this.logger.warn(`原因: 異なる次元数の埋め込みモデルに変更された可能性があります。システムは自動的にインデックスを再作成します。`);
+        this.logger.warn(`Reason: The embedding model might have been changed to one with different dimensions. The system will automatically recreate the index.`);
 
         // 既存インデックスを削除して再作成
         await this.client.indices.delete({ index: this.indexName });
-        this.logger.log(`旧インデックスを正常に削除しました: ${this.indexName}`);
+        this.logger.log(`Successfully deleted old index: ${this.indexName}`);
 
         await this.createIndex(vectorDimensions);
-        this.logger.log(`インデックスを再作成しました: ${this.indexName} (次元数: ${vectorDimensions})`);
+        this.logger.log(`Recreated index: ${this.indexName} (Dimensions: ${vectorDimensions})`);
       } else {
         this.logger.log(
-          `インデックス ${this.indexName} は既に存在します。ベクトル次元数: ${existingDims || '未知'}`,
+          `Index ${this.indexName} already exists. Vector dimensions: ${existingDims || 'Unknown'}`,
         );
       }
     }
@@ -295,12 +295,12 @@ export class ElasticsearchService implements OnModuleInit {
     const fileIds = explicitFileIds;
 
     if (fileIds && fileIds.length === 0) {
-      this.logger.log('検索対象ファイルが0件のため、検索をスキップします');
+      this.logger.log('Skipping search because there are 0 target files');
       return [];
     }
 
     if (fileIds) {
-      this.logger.log(`最終検索対象ファイル範囲: ${fileIds.length} 個のファイル`);
+      this.logger.log(`Final search target scope: ${fileIds.length} files`);
     }
 
     // ハイブリッド検索:ベクトル検索 + 全文検索
@@ -414,7 +414,7 @@ export class ElasticsearchService implements OnModuleInit {
     });
 
     this.logger.log(
-      `インデックス ${this.indexName} を正常に作成しました。ベクトル次元数: ${vectorDimensions}`,
+      `Successfully created index ${this.indexName}. Vector dimensions: ${vectorDimensions}`,
     );
   }
 

+ 1 - 1
server/src/knowledge-base/chunk-config.service.ts

@@ -59,7 +59,7 @@ export class ChunkConfigService {
     );
 
     this.logger.log(
-      `環境変数設定の上限: MAX_CHUNK_SIZE=${this.envMaxChunkSize}, MAX_OVERLAP_SIZE=${this.envMaxOverlapSize}`
+      `Environment variable limits: MAX_CHUNK_SIZE=${this.envMaxChunkSize}, MAX_OVERLAP_SIZE=${this.envMaxOverlapSize}`
     );
   }
 

+ 11 - 11
server/src/knowledge-base/embedding.service.ts

@@ -26,7 +26,7 @@ export class EmbeddingService {
     this.defaultDimensions = parseInt(
       this.configService.get<string>('DEFAULT_VECTOR_DIMENSIONS', '2560'),
     );
-    this.logger.log(`デフォルトのベクトル次元が ${this.defaultDimensions} に設定されました`);
+    this.logger.log(`Default vector dimensions set to ${this.defaultDimensions}`);
   }
 
   async getEmbeddings(
@@ -35,7 +35,7 @@ export class EmbeddingService {
     embeddingModelConfigId: string,
     tenantId?: string,
   ): Promise<number[][]> {
-    this.logger.log(`${texts.length} 個のテキストに対して埋め込みベクトルを生成しています`);
+    this.logger.log(`Generating embedding vectors for ${texts.length} texts`);
 
     const modelConfig = await this.modelConfigService.findOne(
       embeddingModelConfigId,
@@ -62,7 +62,7 @@ export class EmbeddingService {
     // バッチサイズが制限を超える場合は分割して処理
     if (texts.length > maxBatchSize) {
       this.logger.log(
-        `テキスト数 ${texts.length} がモデルのバッチ制限 ${maxBatchSize} を超えているため、分割処理します`
+        `Text count ${texts.length} exceeds model batch limit ${maxBatchSize}, splitting into batches`
       );
 
       const allEmbeddings: number[][] = [];
@@ -136,8 +136,8 @@ export class EmbeddingService {
           this.logger.error(`Embedding API timeout after 60s: ${apiUrl}`);
         }, 60000); // 60s timeout
 
-        this.logger.log(`[モデル呼び出し] タイプ: Embedding, モデル: ${modelConfig.name} (${modelConfig.modelId}), ユーザー: ${userId}, テキスト数: ${texts.length}`);
-        this.logger.log(`埋め込み API を呼び出し中 (試行 ${attempt}/${MAX_RETRIES}): ${apiUrl}`);
+        this.logger.log(`[Model Call] Type: Embedding, Model: ${modelConfig.name} (${modelConfig.modelId}), User: ${userId}, Text Count: ${texts.length}`);
+        this.logger.log(`Calling Embedding API (Attempt ${attempt}/${MAX_RETRIES}): ${apiUrl}`);
 
         let response;
         try {
@@ -165,7 +165,7 @@ export class EmbeddingService {
           if (errorText.includes('batch size is invalid') || errorText.includes('batch_size') ||
             errorText.includes('invalid') || errorText.includes('larger than')) {
             this.logger.warn(
-              `バッチサイズ制限エラーが検出されました。バッチサイズを半分に分割して再試行します: ${maxBatchSize} -> ${Math.floor(maxBatchSize / 2)}`
+              `Batch size limit error detected. Halving batch size and retrying: ${maxBatchSize} -> ${Math.floor(maxBatchSize / 2)}`
             );
 
             // バッチをさらに小さな単位に分割して再試行
@@ -186,7 +186,7 @@ export class EmbeddingService {
             const avgLength = texts.reduce((s, t) => s + t.length, 0) / texts.length;
             const totalLength = texts.reduce((s, t) => s + t.length, 0);
             this.logger.error(
-              `テキスト長が制限を超過しました: 入力 ${texts.length} 個のテキスト、` +
+              `Text length exceeded limit: Input ${texts.length} texts,` +
               `総計 ${totalLength} 文字、平均 ${Math.round(avgLength)} 文字、` +
               `モデル制限: ${modelConfig.maxInputTokens || 8192} tokens`
             );
@@ -200,11 +200,11 @@ export class EmbeddingService {
 
           // 429 (Too Many Requests) または 5xx (Server Error) の場合は再試行
           if (response.status === 429 || response.status >= 500) {
-            this.logger.warn(`埋め込み API で一時的なエラーが発生しました (${response.status}): ${errorText}`);
+            this.logger.warn(`Temporary error occurred in Embedding API (${response.status}): ${errorText}`);
             throw new Error(`API Error ${response.status}: ${errorText}`);
           }
 
-          this.logger.error(`埋め込み API エラーの詳細: ${errorText}`);
+          this.logger.error(`Embedding API Error Details: ${errorText}`);
           this.logger.error(`リクエストパラメータ: model=${modelConfig.modelId}, inputLength=${texts[0]?.length}`);
           throw new Error(`埋め込み API の呼び出しに失敗しました: ${response.statusText} - ${errorText}`);
         }
@@ -215,7 +215,7 @@ export class EmbeddingService {
         // 実際のレスポンスから次元を取得
         const actualDimensions = embeddings[0]?.length || this.defaultDimensions;
         this.logger.log(
-          `${modelConfig.name} から ${embeddings.length} 個の埋め込みベクトルを取得しました。次元: ${actualDimensions}`,
+          `Retrieved ${embeddings.length} embeddings from ${modelConfig.name}. Dimensions: ${actualDimensions}`,
         );
 
         return embeddings;
@@ -225,7 +225,7 @@ export class EmbeddingService {
         // 最後のアテンプトでなく、エラーが一時的と思われる場合(または堅牢性のために全て)は、待機後に再試行
         if (attempt < MAX_RETRIES) {
           const delay = Math.pow(2, attempt - 1) * 1000; // 1s, 2s, 4s
-          this.logger.warn(`埋め込みリクエストが失敗しました。${delay}ms 後に再試行します: ${error.message}`);
+          this.logger.warn(`Embedding request failed. Retrying in ${delay}ms: ${error.message}`);
           await new Promise(resolve => setTimeout(resolve, delay));
           continue;
         }

+ 1 - 1
server/src/knowledge-base/knowledge-base.controller.ts

@@ -330,7 +330,7 @@ export class KnowledgeBaseController {
 
       res.sendFile(path.resolve(imagePath));
     } catch (error) {
-      this.logger.error(`PDF ページの画像取得に失敗しました: ${error.message}`);
+      this.logger.error(`Failed to get PDF page image: ${error.message}`);
       throw new NotFoundException(this.i18nService.getMessage('pdfPageImageFailed'));
     }
   }

+ 26 - 26
server/src/knowledge-base/knowledge-base.service.ts

@@ -431,7 +431,7 @@ export class KnowledgeBaseService {
 
       // メモリ監視 - 処理前チェック
       const memBefore = this.memoryMonitor.getMemoryUsage();
-      this.logger.log(`メモリ状態 - 処理前: ${memBefore.heapUsed}/${memBefore.heapTotal}MB`);
+      this.logger.log(`Memory state - Before processing: ${memBefore.heapUsed}/${memBefore.heapTotal}MB`);
 
       // モードに基づいて処理フローを選択
       const mode = config?.mode || 'fast';
@@ -670,14 +670,14 @@ export class KnowledgeBaseService {
           );
         }
 
-        this.logger.log(`バッチ ${Math.floor(i / batchSize) + 1} 完了: ${batch.length} ページ`);
+        this.logger.log(`Batch ${Math.floor(i / batchSize) + 1} complete: ${batch.length} pages`);
       } catch (error) {
-        this.logger.error(`バッチ ${Math.floor(i / batchSize) + 1} の処理に失敗しました`, error);
+        this.logger.error(`Processing of batch ${Math.floor(i / batchSize) + 1} failed`, error);
       }
     }
 
     await this.updateStatus(kb.id, FileStatus.VECTORIZED);
-    this.logger.log(`精密モードのインデックス完了: ${results.length} ページ`);
+    this.logger.log(`Precise mode indexing complete: ${results.length} pages`);
   }
 
   /**
@@ -716,7 +716,7 @@ export class KnowledgeBaseService {
       // メモリ監視 - ベクトル化前チェック
       const memBeforeChunk = this.memoryMonitor.getMemoryUsage();
       this.logger.log(
-        `ベクトル化前メモリ: ${memBeforeChunk.heapUsed}/${memBeforeChunk.heapTotal}MB`,
+        `Memory before vectorization: ${memBeforeChunk.heapUsed}/${memBeforeChunk.heapTotal}MB`,
       );
 
       this.logger.debug(`File ${kbId}: Validating chunk config...`);
@@ -753,8 +753,8 @@ export class KnowledgeBaseService {
         kb.embeddingModelId,
         userId,
       );
-      this.logger.log(`チャンク設定: ${configSummary}`);
-      this.logger.log(`設定上限: チャンク=${validatedConfig.effectiveMaxChunkSize}, 重複=${validatedConfig.effectiveMaxOverlapSize}`);
+      this.logger.log(`Chunk configuration: ${configSummary}`);
+      this.logger.log(`Configuration limits: Chunk=${validatedConfig.effectiveMaxChunkSize}, Overlap=${validatedConfig.effectiveMaxOverlapSize}`);
 
       // 2. 検証済みの設定を使用してチャンク分割
       const chunks = this.textChunkerService.chunkText(
@@ -762,7 +762,7 @@ export class KnowledgeBaseService {
         validatedConfig.chunkSize,
         validatedConfig.chunkOverlap,
       );
-      this.logger.log(`ファイル ${kbId} から ${chunks.length} 個のテキストブロックを分割しました`);
+      this.logger.log(`Split ${chunks.length} text blocks from file ${kbId}`);
 
       if (chunks.length === 0) {
         this.logger.warn(this.i18nService.formatMessage('noChunksGenerated', { id: kbId }));
@@ -796,7 +796,7 @@ export class KnowledgeBaseService {
         avgChunkSize,
         parseInt(process.env.DEFAULT_VECTOR_DIMENSIONS || '2560'),
       );
-      this.logger.log(`推定メモリ使用量: ${estimatedMemory}MB (バッチサイズ: ${recommendedBatchSize})`);
+      this.logger.log(`Estimated memory usage: ${estimatedMemory}MB (Batch Size: ${recommendedBatchSize})`);
 
       // 6. 実際のモデル次元数を取得し、インデックスの存在を確認
       const actualDimensions = await this.getActualModelDimensions(kb.embeddingModelId, userId, tenantId);
@@ -831,7 +831,7 @@ export class KnowledgeBaseService {
               // 次元の整合性を検証
               if (embeddings.length > 0 && embeddings[0].length !== actualDimensions) {
                 this.logger.warn(
-                  `ベクトル次元が不一致です: 期待値 ${actualDimensions}, 実際 ${embeddings[0].length}`
+                  `Vector dimension mismatch: Expected ${actualDimensions}, Actual ${embeddings[0].length}`
                 );
               }
 
@@ -861,14 +861,14 @@ export class KnowledgeBaseService {
                 );
               }
 
-              this.logger.log(`バッチ ${batchIndex} 完了: ${batch.length} チャンク`);
+              this.logger.log(`Batch ${batchIndex} complete: ${batch.length} chunks`);
             },
             {
               batchSize: recommendedBatchSize,
               onBatchComplete: (batchIndex, totalBatches) => {
                 const mem = this.memoryMonitor.getMemoryUsage();
                 this.logger.log(
-                  `バッチ ${batchIndex}/${totalBatches} 完了, メモリ: ${mem.heapUsed}MB`,
+                  `Batch ${batchIndex}/${totalBatches} complete, Memory: ${mem.heapUsed}MB`,
                 );
               },
             },
@@ -911,17 +911,17 @@ export class KnowledgeBaseService {
                 );
 
                 if ((i + 1) % 10 === 0) {
-                  this.logger.log(`単一処理進捗: ${i + 1}/${chunks.length}`);
+                  this.logger.log(`Single processing progress: ${i + 1}/${chunks.length}`);
                 }
               } catch (chunkError) {
                 this.logger.error(
-                  `テキストブロック ${chunk.index} の処理に失敗しました。スキップします: ${chunkError.message}`
+                  `Failed to process text block ${chunk.index}. Skipping: ${chunkError.message}`
                 );
                 continue;
               }
             }
 
-            this.logger.log(`単一テキスト処理完了: ${chunks.length} チャンク`);
+            this.logger.log(`Single text processing complete: ${chunks.length} chunks`);
           } else {
             // その他のエラーは直接スロー
             throw error;
@@ -952,7 +952,7 @@ export class KnowledgeBaseService {
                   const embedding = embeddings[i];
 
                   if (!embedding || embedding.length === 0) {
-                    this.logger.warn(`空ベクトルのテキストブロック ${chunk.index} をスキップします`);
+                    this.logger.warn(`Skipping text block ${chunk.index} with empty vector`);
                     continue;
                   }
 
@@ -1012,7 +1012,7 @@ export class KnowledgeBaseService {
                   );
 
                   if ((i + 1) % 10 === 0) {
-                    this.logger.log(`単一処理進捗: ${i + 1}/${chunks.length}`);
+                    this.logger.log(`Single processing progress: ${i + 1}/${chunks.length}`);
                   }
                 } catch (chunkError) {
                   this.logger.error(
@@ -1079,7 +1079,7 @@ export class KnowledgeBaseService {
                   );
 
                   if (!embeddings[0] || embeddings[0].length === 0) {
-                    this.logger.warn(`空ベクトルのテキストブロック ${chunk.index} をスキップします`);
+                    this.logger.warn(`Skipping text block ${chunk.index} with empty vector`);
                     continue;
                   }
 
@@ -1100,11 +1100,11 @@ export class KnowledgeBaseService {
                   );
 
                   if ((i + 1) % 10 === 0) {
-                    this.logger.log(`単一処理進捗: ${i + 1}/${chunks.length}`);
+                    this.logger.log(`Single processing progress: ${i + 1}/${chunks.length}`);
                   }
                 } catch (chunkError) {
                   this.logger.error(
-                    `テキストブロック ${chunk.index} の処理に失敗しました。スキップします: ${chunkError.message}`
+                    `Failed to process text block ${chunk.index}. Skipping: ${chunkError.message}`
                   );
                   continue;
                 }
@@ -1450,12 +1450,12 @@ export class KnowledgeBaseService {
       );
 
       if (modelConfig && modelConfig.dimensions) {
-        this.logger.log(`設定から ${modelConfig.name} の次元数を取得しました: ${modelConfig.dimensions}`);
+        this.logger.log(`Retrieved dimensions for ${modelConfig.name} from config: ${modelConfig.dimensions}`);
         return modelConfig.dimensions;
       }
 
       // 2. それ以外の場合はプローブにより取得
-      this.logger.log(`モデル次元数をプローブ中: ${embeddingModelId}`);
+      this.logger.log(`Probing model dimensions: ${embeddingModelId}`);
       const probeEmbeddings = await this.embeddingService.getEmbeddings(
         ['probe'],
         userId,
@@ -1464,7 +1464,7 @@ export class KnowledgeBaseService {
 
       if (probeEmbeddings.length > 0) {
         const actualDimensions = probeEmbeddings[0].length;
-        this.logger.log(`モデルの実際の次元数を検出しました: ${actualDimensions}`);
+        this.logger.log(`Detected actual model dimensions: ${actualDimensions}`);
 
         // 次回利用のためにモデル設定を更新
         if (modelConfig) {
@@ -1472,9 +1472,9 @@ export class KnowledgeBaseService {
             await this.modelConfigService.update(userId, tenantId, modelConfig.id, {
               dimensions: actualDimensions,
             });
-            this.logger.log(`モデル ${modelConfig.name} の次元数設定を ${actualDimensions} に更新しました`);
+            this.logger.log(`Updated dimension config for model ${modelConfig.name} to ${actualDimensions}`);
           } catch (updateErr) {
-            this.logger.warn(`モデル次元数設定の更新に失敗しました: ${updateErr.message}`);
+            this.logger.warn(`Failed to update model dimension setting: ${updateErr.message}`);
           }
         }
 
@@ -1482,7 +1482,7 @@ export class KnowledgeBaseService {
       }
     } catch (err) {
       this.logger.warn(
-        `次元数の取得に失敗しました。デフォルト次元数を使用します: ${defaultDimensions}`,
+        `Failed to get dimensions. Using default dimensions: ${defaultDimensions}`,
         err.message,
       );
     }

+ 10 - 10
server/src/knowledge-base/memory-monitor.service.ts

@@ -21,7 +21,7 @@ export class MemoryMonitorService {
     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をトリガー
 
-    this.logger.log(`メモリ監視を初期化しました: 上限=${this.MAX_MEMORY_MB}MB, バッチサイズ=${this.BATCH_SIZE}, GC閾値=${this.GC_THRESHOLD_MB}MB`);
+    this.logger.log(`Initialized memory monitoring: Limit=${this.MAX_MEMORY_MB}MB, Batch Size=${this.BATCH_SIZE}, GC Threshold=${this.GC_THRESHOLD_MB}MB`);
   }
 
   /**
@@ -58,12 +58,12 @@ export class MemoryMonitorService {
       }
 
       this.logger.warn(
-        `メモリ使用量が高すぎます。解放を待機中... ${this.getMemoryUsage().heapUsed}/${this.MAX_MEMORY_MB}MB`,
+        `Memory usage is too high. Waiting for release... ${this.getMemoryUsage().heapUsed}/${this.MAX_MEMORY_MB}MB`,
       );
 
       // ガベージコレクションを強制実行(可能な場合)
       if (global.gc) {
-        this.logger.log('強制ガベージコレクションを実行中...');
+        this.logger.log('Running forced garbage collection...');
         global.gc();
       }
 
@@ -80,7 +80,7 @@ export class MemoryMonitorService {
       global.gc();
       const after = this.getMemoryUsage();
       this.logger.log(
-        `GC完了: ${before.heapUsed}MB → ${after.heapUsed}MB (${before.heapUsed - after.heapUsed}MB 解放)`,
+        `GC Complete: ${before.heapUsed}MB → ${after.heapUsed}MB (${before.heapUsed - after.heapUsed}MB released)`,
       );
     }
   }
@@ -95,7 +95,7 @@ export class MemoryMonitorService {
       // メモリ逼迫、バッチサイズを削減
       const reduced = Math.max(10, Math.floor(baseBatchSize * 0.5));
       this.logger.warn(
-        `メモリ逼迫 (${currentMemoryMB}MB)、バッチサイズを動的に調整: ${baseBatchSize} → ${reduced}`,
+        `Memory constrained (${currentMemoryMB}MB), dynamically adjusting batch size: ${baseBatchSize} → ${reduced}`,
       );
       return reduced;
     } else if (currentMemoryMB < this.MAX_MEMORY_MB * 0.4) {
@@ -103,7 +103,7 @@ export class MemoryMonitorService {
       const increased = Math.min(200, Math.floor(baseBatchSize * 1.2));
       if (increased > baseBatchSize) {
         this.logger.log(
-          `メモリに余裕あり (${currentMemoryMB}MB)、バッチサイズを動的に調整: ${baseBatchSize} → ${increased}`,
+          `Memory available (${currentMemoryMB}MB), dynamically adjusting batch size: ${baseBatchSize} → ${increased}`,
         );
       }
       return increased;
@@ -127,7 +127,7 @@ export class MemoryMonitorService {
     if (totalItems === 0) return [];
 
     const startTime = Date.now();
-    this.logger.log(`バッチ処理を開始します: ${totalItems} 項目`);
+    this.logger.log(`Starting batch processing: ${totalItems} items`);
 
     const allResults: R[] = [];
     let processedCount = 0;
@@ -146,7 +146,7 @@ export class MemoryMonitorService {
       const totalBatches = Math.ceil(totalItems / batchSize);
 
       this.logger.log(
-        `バッチを処理中 ${batchIndex}/${totalBatches}: ${batch.length} 項目 (累計 ${processedCount}/${totalItems})`,
+        `Processing batch ${batchIndex}/${totalBatches}: ${batch.length} items (Total ${processedCount}/${totalItems})`,
       );
 
       // バッチを処理
@@ -173,7 +173,7 @@ export class MemoryMonitorService {
     const duration = ((Date.now() - startTime) / 1000).toFixed(2);
     const finalMem = this.getMemoryUsage();
     this.logger.log(
-      `バッチ処理が完了しました: ${totalItems} 項目, 所要時間 ${duration}s, 最終メモリ ${finalMem.heapUsed}MB`,
+      `Batch processing complete: ${totalItems} items, Duration ${duration}s, Final memory ${finalMem.heapUsed}MB`,
     );
 
     return allResults;
@@ -206,7 +206,7 @@ export class MemoryMonitorService {
 
     if (estimatedMB > threshold) {
       this.logger.warn(
-        `推定メモリ ${estimatedMB}MB が閾値 ${threshold}MB を超えているため、バッチ処理を使用します`,
+        `Estimated memory ${estimatedMB}MB exceeds threshold ${threshold}MB, using batch processing`,
       );
       return true;
     }

+ 4 - 4
server/src/ocr/ocr.controller.ts

@@ -22,14 +22,14 @@ export class OcrController {
     @Post('recognize')
     @UseInterceptors(FileInterceptor('image'))
     async recognizeText(@UploadedFile() image: Express.Multer.File) {
-        console.log('OCR認識エンドポイントが呼び出されました');
+        console.log('OCR recognition endpoint called');
         if (!image) {
-            console.error('画像がアップロードされていません');
+            console.error('No image uploaded');
             throw new Error(this.i18n.getMessage('noImageUploaded'));
         }
-        console.log(`画像を受信しました。サイズ: ${image.size} bytes`);
+        console.log(`Received image. Size: ${image.size} bytes`);
         const text = await this.ocrService.extractTextFromImage(image.buffer);
-        console.log(`OCR抽出が完了しました。テキスト長: ${text.length}`);
+        console.log(`OCR extraction complete. Text length: ${text.length}`);
         return { text };
     }
 }

+ 7 - 7
server/src/ocr/ocr.service.ts

@@ -9,7 +9,7 @@ export class OcrService {
     constructor(private readonly i18n: I18nService) { }
 
     async extractTextFromImage(imageBuffer: Buffer): Promise<string> {
-        this.logger.log(`画像のOCR抽出を開始します (${imageBuffer.length} bytes)...`);
+        this.logger.log(`Starting image OCR extraction (${imageBuffer.length} bytes)...`);
 
         // Create worker for this request to ensure stability
         let worker: any = null;
@@ -17,16 +17,16 @@ export class OcrService {
             worker = await createWorker('chi_sim+eng+jpn');
 
             const { data: { text } } = await worker.recognize(imageBuffer);
-            this.logger.log(`OCR抽出が完了しました。 ${text.length} 文字抽出されました。`);
+            this.logger.log(`OCR extraction complete. ${text.length} characters extracted.`);
 
             if (text.length === 0) {
-                this.logger.warn('OCRが空のテキストを返しました。');
+                this.logger.warn('OCR returned empty text.');
             }
 
             await worker.terminate();
             return text.trim();
         } catch (error) {
-            this.logger.error(`OCRテキスト抽出に失敗しました: ${error.message}`);
+            this.logger.error(`Failed to extract OCR text: ${error.message}`);
             if (worker) {
                 try { await worker.terminate(); } catch (e) { }
             }
@@ -38,13 +38,13 @@ export class OcrService {
         text: string;
         confidence: number;
     }> {
-        this.logger.log(`信頼度付き画像のOCR抽出を開始します (${imageBuffer.length} bytes)...`);
+        this.logger.log(`Starting image OCR extraction with confidence (${imageBuffer.length} bytes)...`);
 
         let worker: any = null;
         try {
             worker = await createWorker('chi_sim+eng+jpn');
             const { data } = await worker.recognize(imageBuffer);
-            this.logger.log(`OCR抽出が完了しました。信頼度: ${data.confidence}%`);
+            this.logger.log(`OCR extraction complete. Confidence: ${data.confidence}%`);
 
             await worker.terminate();
             return {
@@ -52,7 +52,7 @@ export class OcrService {
                 confidence: data.confidence,
             };
         } catch (error) {
-            this.logger.error(`OCRテキスト抽出に失敗しました: ${error.message}`);
+            this.logger.error(`Failed to extract OCR text: ${error.message}`);
             if (worker) {
                 try { await worker.terminate(); } catch (e) { }
             }

+ 5 - 5
server/src/pdf2image/pdf2image.service.ts

@@ -58,16 +58,16 @@ export class Pdf2ImageService {
         throw new Error('PDF のページ数を取得できません');
       }
 
-      this.logger.log(`📄 PDF 変換開始: ${path.basename(pdfPath)} (全 ${totalPages} ページ)`);
-      this.logger.log(`📁 出力ディレクトリ: ${outputDir}`);
-      this.logger.log(`⚙️  変換パラメータ: 密度=${density}dpi, 品質=${quality}%, 形式=${format}`);
+      this.logger.log(`📄 PDF conversion started: ${path.basename(pdfPath)} (Total ${totalPages} pages)`);
+      this.logger.log(`📁 Output directory: ${outputDir}`);
+      this.logger.log(`⚙️  Conversion parameters: Density=${density}dpi, Quality=${quality}%, Format=${format}`);
 
       // Python スクリプトを使用して変換
       const zoom = (density / 72).toFixed(2);
       const pythonScript = path.join(process.cwd(), 'pdf_to_images.py');
       const cmd = `python "${pythonScript}" "${pdfPath}" "${outputDir}" ${zoom} ${quality}`;
 
-      this.logger.log(`変換コマンドを実行中: ${cmd}`);
+      this.logger.log(`Running conversion command: ${cmd}`);
       const { stdout } = await execAsync(cmd);
       const result = JSON.parse(stdout);
 
@@ -80,7 +80,7 @@ export class Pdf2ImageService {
       const failedCount = totalPages - successCount;
 
       this.logger.log(
-        `🎉 PDF 変換完了! ✅ 成功: ${successCount} ページ, ❌ 失敗: ${failedCount} ページ, 📊 総ページ数: ${totalPages}`
+        `🎉 PDF conversion complete! ✅ Success: ${successCount} pages, ❌ Failed: ${failedCount} pages, 📊 Total pages: ${totalPages}`
       );
 
       return {

+ 1 - 1
server/src/rag/rag.service.ts

@@ -39,7 +39,7 @@ export class RagService {
     this.defaultDimensions = parseInt(
       this.configService.get<string>('DEFAULT_VECTOR_DIMENSIONS', '2560'),
     );
-    this.logger.log(`RAG サービスのデフォルトベクトル次元数: ${this.defaultDimensions}`);
+    this.logger.log(`Default vector dimensions for RAG service: ${this.defaultDimensions}`);
   }
 
   async searchKnowledge(

+ 4 - 4
server/src/user-setting/user-setting.service.ts

@@ -113,12 +113,12 @@ export class UserSettingService implements OnModuleInit {
   async updateLanguage(userId: string, language: string): Promise<UserSetting> {
     console.log('=== updateLanguage デバッグ ===');
     console.log('userId:', userId);
-    console.log('新しい言語:', language);
+    console.log('New language:', language);
     const settings = await this.findOrCreate(userId);
-    console.log('更新前 settings:', settings);
+    console.log('Settings before update:', settings);
     settings.language = language;
     const result = await this.userSettingRepository.save(settings);
-    console.log('更新後 result:', result);
+    console.log('Result after update:', result);
     console.log('===============================');
     return result;
   }
@@ -131,7 +131,7 @@ export class UserSettingService implements OnModuleInit {
     console.log('userId:', userId);
     console.log('settings:', settings);
     console.log('settings.language:', settings?.language);
-    console.log('返す言語:', settings?.language || 'zh');
+    console.log('Returned language:', settings?.language || 'zh');
     console.log('============================');
     return settings?.language || 'zh';
   }

+ 2 - 2
server/src/user/user.service.ts

@@ -301,8 +301,8 @@ export class UserService implements OnModuleInit {
         role: UserRole.SUPER_ADMIN,
       });
 
-      console.log('\n=== 管理者アカウントが作成されました ===');
-      console.log('ユーザー名: admin');
+      console.log('\n=== Administrator Account Created ===');
+      console.log('Username: admin');
       console.log('パスワード:', randomPassword);
       console.log('========================================\n');
     }

+ 4 - 4
server/src/vision-pipeline/cost-control.service.ts

@@ -79,7 +79,7 @@ export class CostControlService {
 
     if (quota.remaining < estimatedCost) {
       this.logger.warn(
-        `ユーザー ${userId} のクォータが不足しています: 残り $${quota.remaining.toFixed(2)}, 必要 $${estimatedCost.toFixed(2)}`,
+        `Insufficient quota for user ${userId}: Remaining $${quota.remaining.toFixed(2)}, Required $${estimatedCost.toFixed(2)}`,
       );
       return {
         allowed: false,
@@ -107,7 +107,7 @@ export class CostControlService {
     });
 
     this.logger.log(
-      `ユーザー ${userId} のクォータから $${actualCost.toFixed(2)} を差し引きました。残り $${quota.remaining.toFixed(2)}`,
+      `Deducted $${actualCost.toFixed(2)} from user ${userId}'s quota. Remaining $${quota.remaining.toFixed(2)}`,
     );
   }
 
@@ -147,7 +147,7 @@ export class CostControlService {
       now.getMonth() !== lastReset.getMonth() ||
       now.getFullYear() !== lastReset.getFullYear()
     ) {
-      this.logger.log(`ユーザー ${quota.userId} の月間クォータをリセットしました`);
+      this.logger.log(`Reset monthly quota for user ${quota.userId}`);
 
       // クォータをリセット
       quota.monthlyCost = 0;
@@ -167,7 +167,7 @@ export class CostControlService {
    */
   async setQuotaLimit(userId: string, maxCost: number): Promise<void> {
     await this.userRepository.update(userId, { maxCost });
-    this.logger.log(`ユーザー ${userId} のクォータ制限を $${maxCost} に設定しました`);
+    this.logger.log(`Set quota limit for user ${userId} to $${maxCost}`);
   }
 
   /**

+ 2 - 2
server/src/vision-pipeline/vision-pipeline-cost-aware.service.ts

@@ -77,7 +77,7 @@ export class VisionPipelineCostAwareService {
       this.updateStatus('checking', 40, 'クォータを確認し、コストを見積もり中...');
       const costEstimate = this.costControl.estimateCost(pageCount);
       this.logger.log(
-        `推定コスト: $${costEstimate.estimatedCost.toFixed(2)}, 推定時間: ${this.costControl.formatTime(costEstimate.estimatedTime)}`
+        `Estimated cost: $${costEstimate.estimatedCost.toFixed(2)}, Estimated time: ${this.costControl.formatTime(costEstimate.estimatedTime)}`
       );
 
       // クォータチェック
@@ -118,7 +118,7 @@ export class VisionPipelineCostAwareService {
       // ステップ 6: 実際のコストを差し引く
       if (totalCost > 0) {
         await this.costControl.deductQuota(options.userId, totalCost);
-        this.logger.log(`実際に差し引かれたコスト: $${totalCost.toFixed(2)}`);
+        this.logger.log(`Actual deducted cost: $${totalCost.toFixed(2)}`);
       }
 
       // ステップ 7: 一時ファイルのクリーンアップ

+ 13 - 13
server/src/vision/vision.service.ts

@@ -38,7 +38,7 @@ export class VisionService {
 
         const delay = baseDelay + Math.random() * 2000; // 3-5秒のランダムな遅延
         this.logger.warn(
-          `⚠️ 第 ${pageIndex || '?'} ページの分析に失敗しました (${attempt}/${maxRetries}), ${delay.toFixed(0)}ms後に再試行します: ${error.message}`
+          `⚠️ Failed to analyze page ${pageIndex || '?'} (${attempt}/${maxRetries}), retrying in ${delay.toFixed(0)}ms: ${error.message}`
         );
 
         await this.sleep(delay);
@@ -189,14 +189,14 @@ export class VisionService {
     let failedCount = 0;
 
     this.logger.log(this.i18nService.formatMessage('batchAnalysisStarted', { count: imagePaths.length }));
-    this.logger.log(`🔧 モデル設定: ${modelConfig.modelId} (${modelConfig.baseUrl || 'OpenAI'})`);
+    this.logger.log(`🔧 Model configuration: ${modelConfig.modelId} (${modelConfig.baseUrl || 'OpenAI'})`);
 
     for (let i = 0; i < imagePaths.length; i++) {
       const imagePath = imagePaths[i];
       const pageIndex = startIndex + i;
       const progress = Math.round(((i + 1) / imagePaths.length) * 100);
 
-      this.logger.log(`🖼️  第 ${pageIndex} ページを分析中 (${i + 1}/${imagePaths.length}, ${progress}%)`);
+      this.logger.log(`🖼️  Analyzing page ${pageIndex} (${i + 1}/${imagePaths.length}, ${progress}%)`);
 
       // 進捗コールバックを呼び出し
       if (onProgress) {
@@ -207,16 +207,16 @@ export class VisionService {
       if (!skipQualityCheck) {
         const quality = await this.checkImageQuality(imagePath);
         if (!quality.isGood) {
-          this.logger.warn(`⚠️  第 ${pageIndex} ページをスキップ(品質不良): ${quality.reason}`);
+          this.logger.warn(`⚠️  Skipping page ${pageIndex} (Poor quality): ${quality.reason}`);
           failedCount++;
           continue;
         } else {
-          this.logger.log(`✅ 第 ${pageIndex} ページの品質チェック合格 (スコア: ${(quality.score || 0).toFixed(2)})`);
+          this.logger.log(`✅ Page ${pageIndex} passed quality check (Score: ${(quality.score || 0).toFixed(2)})`);
         }
       }
 
       try {
-        this.logger.log(`🔍 Vision モデルで第 ${pageIndex} ページを分析中...`);
+        this.logger.log(`🔍 Analyzing page ${pageIndex} with Vision model...`);
         const startTime = Date.now();
         const result = await this.analyzeImage(imagePath, modelConfig, pageIndex);
         const duration = ((Date.now() - startTime) / 1000).toFixed(1);
@@ -225,10 +225,10 @@ export class VisionService {
         successCount++;
 
         this.logger.log(
-          `✅ 第 ${pageIndex} ページ分析完了 (所要時間: ${duration}s, ` +
-          `テキスト: ${result.text.length}文字, ` +
-          `画像数: ${result.images.length}個, ` +
-          `信頼度: ${(result.confidence * 100).toFixed(1)}%)`
+          `✅ Analysis for page ${pageIndex} complete (Time taken: ${duration}s, ` +
+          `Text: ${result.text.length} chars, ` +
+          `Images: ${result.images.length}, ` +
+          `Confidence: ${(result.confidence * 100).toFixed(1)}%)`
         );
 
         // 結果付きで進捗コールバックを呼び出し
@@ -245,9 +245,9 @@ export class VisionService {
     const estimatedCost = successCount * 0.01;
 
     this.logger.log(
-      `🎉 Vision 一括分析完了! ` +
-      `✅ 成功: ${successCount} ページ, ❌ 失敗: ${failedCount} ページ, ` +
-      `💰 推定コスト: $${estimatedCost.toFixed(2)}`
+      `🎉 Vision batch analysis complete! ` +
+      `✅ Success: ${successCount} pages, ❌ Failed: ${failedCount} pages, ` +
+      `💰 Estimated cost: $${estimatedCost.toFixed(2)}`
     );
 
     return {

+ 26 - 0
server/test_db.py

@@ -0,0 +1,26 @@
+import sqlite3
+import os
+
+db_path = 'd:/workspace/AuraK/server/database.sqlite'
+if not os.path.exists(db_path):
+    print("DB not found")
+    exit(1)
+
+conn = sqlite3.connect(db_path)
+c = conn.cursor()
+
+print("--- knowledge_group ---")
+try:
+    for row in c.execute('SELECT id, name, tenantId from knowledge_group'):
+        print(row)
+except Exception as e:
+    print(e)
+    
+print("\n--- import_task ---")
+try:
+    for row in c.execute('SELECT id, targetGroupId, targetGroupName, status from import_task'):
+        print(row)
+except Exception as e:
+    print(e)
+
+conn.close()

+ 4 - 0
translation_map.json

@@ -0,0 +1,4 @@
+{
+  "      `💰 推定コスト: $${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`);"
+}

+ 3 - 0
web/.env

@@ -7,3 +7,6 @@ VITE_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
 VITE_PORT=13001
 VITE_HOST=0.0.0.0
 VITE_BACKEND_URL=http://localhost:3001
+
+# ĬÈÏϵͳÓïÑÔ£¨zh, en, ja£©
+VITE_DEFAULT_LANGUAGE=en

+ 3 - 0
web/.env.example

@@ -9,3 +9,6 @@ VITE_ALLOWED_HOSTS=localhost,127.0.0.1,0.0.0.0
 VITE_PORT=13001
 VITE_HOST=0.0.0.0
 VITE_BACKEND_URL=http://localhost:3001
+
+# ĬÈÏϵͳÓïÑÔ£¨zh, en, ja£©
+VITE_DEFAULT_LANGUAGE=en

+ 1 - 1
web/components/ImportFolderDrawer.tsx

@@ -280,7 +280,7 @@ export const ImportFolderDrawer: React.FC<ImportFolderDrawerProps> = ({
             await apiClient.post('/import-tasks', {
                 sourcePath: serverPath.trim(),
                 targetGroupId: finalGroupId,
-                targetGroupName: undefined,
+                targetGroupName: schedTargetName.trim() || initialGroupName || undefined,
                 embeddingModelId: defaultModel?.id,
                 scheduledAt: scheduledAt.toISOString(),
                 chunkSize: 500,

+ 1 - 1
web/components/IndexingModal.tsx

@@ -82,7 +82,7 @@ const IndexingModal: React.FC<IndexingModalProps> = ({
         }
 
       } catch (error) {
-        console.error('設定制限の読み込みに失敗しました:', error);
+        console.error('Failed to read configuration limits:', error);
         showWarning(t('loadLimitsFailed'));
       } finally {
         setIsLoadingLimits(false);

+ 2 - 2
web/components/IndexingModalWithMode.tsx

@@ -89,7 +89,7 @@ const IndexingModalWithMode: React.FC<IndexingModalWithModeProps> = ({
           showInfo(t('recommendationMsg', rec.recommendedMode === 'precise' ? t('preciseMode') : t('fastMode'), t(rec.reason, ...(rec.reasonArgs || []))));
         }
       } catch (error) {
-        console.error('モード推奨の取得に失敗しました:', error);
+        console.error('Failed to get mode recommendation:', error);
       } finally {
         setIsLoadingRecommendation(false);
       }
@@ -132,7 +132,7 @@ const IndexingModalWithMode: React.FC<IndexingModalWithModeProps> = ({
         }
 
       } catch (error) {
-        console.error('設定制限の読み込みに失敗しました:', error);
+        console.error('Failed to read configuration limits:', error);
         showWarning(t('loadLimitsFailed'));
       } finally {
         setIsLoadingLimits(false);

+ 1 - 1
web/components/ModeSelector.tsx

@@ -42,7 +42,7 @@ export const ModeSelector: React.FC<ModeSelectorProps> = ({
       setSelectedMode(rec.recommendedMode);
       onModeChange(rec.recommendedMode);
     } catch (error) {
-      console.error('モード推奨の取得に失敗しました:', error);
+      console.error('Failed to get mode recommendation:', error);
     } finally {
       setLoading(false);
     }

+ 4 - 2
web/components/drawers/ImportTasksDrawer.tsx

@@ -4,6 +4,7 @@ import { importService, ImportTask } from '../../services/importService';
 import { useLanguage } from '../../contexts/LanguageContext';
 import { knowledgeGroupService } from '../../services/knowledgeGroupService';
 import { KnowledgeGroup } from '../../types';
+import { useToast } from '../../contexts/ToastContext';
 
 interface ImportTasksDrawerProps {
     isOpen: boolean;
@@ -17,6 +18,7 @@ export const ImportTasksDrawer: React.FC<ImportTasksDrawerProps> = ({
     authToken,
 }) => {
     const { t } = useLanguage();
+    const { showError } = useToast();
     const [importTasks, setImportTasks] = useState<ImportTask[]>([]);
     const [groups, setGroups] = useState<KnowledgeGroup[]>([]);
     const [isLoading, setIsLoading] = useState(false);
@@ -55,7 +57,7 @@ export const ImportTasksDrawer: React.FC<ImportTasksDrawerProps> = ({
             fetchData();
         } catch (error) {
             console.error('Failed to delete task:', error);
-            alert(t('deleteTaskFailed'));
+            showError(t('deleteTaskFailed'));
         }
     };
 
@@ -129,7 +131,7 @@ export const ImportTasksDrawer: React.FC<ImportTasksDrawerProps> = ({
                                                     {task.sourcePath}
                                                 </td>
                                                 <td className="px-6 py-4 text-slate-500">
-                                                    {groups.find((g: any) => g.id === task.targetGroupId)?.name || task.targetGroupName || task.targetGroupId || '-'}
+                                                    {groups.find((g: any) => g.id === task.targetGroupId)?.name || task.targetGroupName || task.sourcePath.split(/[\\/]/).pop() || task.targetGroupId || '-'}
                                                 </td>
                                                 <td className="px-6 py-4">
                                                     {(() => {

+ 2 - 1
web/contexts/LanguageContext.tsx

@@ -12,7 +12,8 @@ const LanguageContext = React.createContext<LanguageContextType | undefined>(und
 export const LanguageProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
   const [language, setLanguage] = React.useState<Language>(() => {
     const saved = localStorage.getItem('userLanguage');
-    return (saved as Language) || 'en';
+    const envDefault = (import.meta as any).env.VITE_DEFAULT_LANGUAGE as Language;
+    return (saved as Language) || envDefault || 'en';
   });
 
   const handleSetLanguage = (lang: Language) => {

+ 4 - 4
web/services/settingsService.ts

@@ -24,13 +24,13 @@ export const settingsService = {
   },
 
   async updateLanguage(language: string) {
-    console.log('=== API 调用 updateLanguage ===');
-    console.log('请求语言:', language);
-    console.log('请求URL:', '/settings/language');
+    console.log('=== API Call updateLanguage ===');
+    console.log('Requested language:', language);
+    console.log('Request URL:', '/settings/language');
     const response = await apiClient.put('/settings/language', {
       language,
     });
-    console.log('API 响应:', response);
+    console.log('API Response:', response);
     return response.data;
   },
 };