anhuiqiang 1 tydzień temu
rodzic
commit
6e0a78a352
2 zmienionych plików z 45 dodań i 33 usunięć
  1. 36 33
      server/src/chat/chat.service.ts
  2. 9 0
      server/src/i18n/messages.ts

+ 36 - 33
server/src/chat/chat.service.ts

@@ -66,26 +66,26 @@ export class ChatService {
     tenantId?: string // New: tenant isolation
   ): 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 ID:', userId);
+    console.log('User language:', userLanguage);
+    console.log('Selected embedding model ID:', selectedEmbeddingId);
+    console.log('Selected groups:', 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 prefix:', modelConfig.apiKey?.substring(0, 10) + '...');
+    console.log('API Key length:', modelConfig.apiKey?.length);
 
     // Get current language setting (keeping LANGUAGE_CONFIG for backward compatibility, now uses i18n service)
     // Use actual language based on user settings
@@ -284,13 +284,14 @@ export class ChatService {
     instruction: string,
     context: string,
     modelConfig: ModelConfig,
+    userLanguage: string = DEFAULT_LANGUAGE,
   ): AsyncGenerator<{ type: 'content'; data: any }> {
     try {
       this.logger.log(this.i18nService.formatMessage('modelCall', {
         type: 'LLM (Assist)',
         model: `${modelConfig.name} (${modelConfig.modelId})`,
         user: 'N/A'
-      }, 'ja'));
+      }, userLanguage));
       const llm = new ChatOpenAI({
         apiKey: modelConfig.apiKey || 'ollama',
         streaming: true,
@@ -301,14 +302,13 @@ export class ChatService {
         },
       });
 
-      const systemPrompt = `${this.i18nService.getMessage('intelligentAssistant', 'ja')}
-提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善please。
-挨拶や結びの言葉(「わかりました、こちらが...」etc.)は含めず、修正後の内容のみを直接出力please。
+      const systemPrompt = `${this.i18nService.getMessage('intelligentAssistant', userLanguage)}
+${this.i18nService.getMessage('assistSystemPrompt', userLanguage)}
 
-コンテキスト(現在の内容):
+${this.i18nService.getMessage('contextLabel', userLanguage)}:
 ${context}
 
-ユーザーの指示:
+${this.i18nService.getMessage('userInstructionLabel', userLanguage)}:
 ${instruction}`;
 
       const stream = await llm.stream(systemPrompt);
@@ -319,8 +319,8 @@ ${instruction}`;
         }
       }
     } catch (error) {
-      this.logger.error(this.i18nService.getMessage('assistStreamError', 'ja'), error);
-      yield { type: 'content', data: `${this.i18nService.getMessage('error', 'ja')}: ${error.message}` };
+      this.logger.error(this.i18nService.getMessage('assistStreamError', userLanguage), error);
+      yield { type: 'content', data: `${this.i18nService.getMessage('error', userLanguage)}: ${error.message}` };
     }
   }
 
@@ -331,30 +331,31 @@ ${instruction}`;
     selectedGroups?: string[], // New parameter
     explicitFileIds?: string[], // New parameter
     tenantId?: string, // Added
+    userLanguage: string = DEFAULT_LANGUAGE,
   ): Promise<any[]> {
     try {
       // Join keywords into search string
       const combinedQuery = keywords.join(' ');
-      console.log(this.i18nService.getMessage('searchString', 'ja') + combinedQuery);
+      console.log(this.i18nService.getMessage('searchString', userLanguage) + combinedQuery);
 
       // Check if embedding model ID is provided
       if (!embeddingModelId) {
-        console.log(this.i18nService.getMessage('embeddingModelIdNotProvided', 'ja'));
+        console.log(this.i18nService.getMessage('embeddingModelIdNotProvided', userLanguage));
         return [];
       }
 
       // Use actual embedding vector
-      console.log(this.i18nService.getMessage('generatingEmbeddings', 'ja'));
+      console.log(this.i18nService.getMessage('generatingEmbeddings', userLanguage));
       const queryEmbedding = await this.embeddingService.getEmbeddings(
         [combinedQuery],
         userId,
         embeddingModelId,
       );
       const queryVector = queryEmbedding[0];
-      console.log(this.i18nService.getMessage('embeddingsGenerated', 'ja') + this.i18nService.getMessage('dimensions', 'ja') + ':', queryVector.length);
+      console.log(this.i18nService.getMessage('embeddingsGenerated', userLanguage) + this.i18nService.getMessage('dimensions', userLanguage) + ':', queryVector.length);
 
       // Hybrid search
-      console.log(this.i18nService.getMessage('performingHybridSearch', 'ja'));
+      console.log(this.i18nService.getMessage('performingHybridSearch', userLanguage));
       const results = await this.elasticsearchService.hybridSearch(
         queryVector,
         combinedQuery,
@@ -363,13 +364,13 @@ ${instruction}`;
         0.6,
         selectedGroups, // Pass selected groups
         explicitFileIds, // Pass explicit file IDs
-        tenantId, // Added: tenantId
+        tenantId, // Pass tenant ID
       );
-      console.log(this.i18nService.getMessage('esSearchCompleted', 'ja') + this.i18nService.getMessage('resultsCount', 'ja') + ':', results.length);
+      console.log(this.i18nService.getMessage('esSearchCompleted', userLanguage) + this.i18nService.getMessage('resultsCount', userLanguage) + ':', results.length);
 
       return results.slice(0, 10);
     } catch (error) {
-      console.error(this.i18nService.getMessage('hybridSearchFailed', 'ja') + ':', error);
+      console.error(this.i18nService.getMessage('hybridSearchFailed', userLanguage) + ':', error);
       return [];
     }
   }
@@ -398,7 +399,7 @@ ${instruction}`;
       )
       .join('\n');
   }
-  async getContextForTopic(topic: string, userId: string, tenantId?: string, groupId?: string, fileIds?: string[]): Promise<string> {
+  async getContextForTopic(topic: string, userId: string, tenantId?: string, groupId?: string, fileIds?: string[], userLanguage: string = DEFAULT_LANGUAGE): Promise<string> {
     try {
       // Use organization's default embedding from Index Chat Config (strict)
       const embeddingModel = await this.modelConfigService.findDefaultByType(tenantId || 'default', ModelType.EMBEDDING);
@@ -409,12 +410,13 @@ ${instruction}`;
         embeddingModel.id,
         groupId ? [groupId] : undefined,
         fileIds,
-        tenantId
+        tenantId,
+        userLanguage,
       );
 
       return this.buildContext(results);
     } catch (err) {
-      this.logger.error(`${this.i18nService.getMessage('getContextForTopicFailed', 'ja')}: ${err.message}`);
+      this.logger.error(`${this.i18nService.getMessage('getContextForTopicFailed', userLanguage)}: ${err.message}`);
       return '';
     }
   }
@@ -424,6 +426,7 @@ ${instruction}`;
     userId: string,
     tenantId?: string,
     modelConfig?: ModelConfig, // Optional, looks up if not provided
+    userLanguage: string = DEFAULT_LANGUAGE,
   ): Promise<string> {
     try {
       let config = modelConfig;
@@ -454,13 +457,13 @@ ${instruction}`;
 
       return String(response.content);
     } catch (error) {
-      this.logger.error(this.i18nService.getMessage('simpleChatGenerationError', 'ja'), error);
+      this.logger.error(this.i18nService.getMessage('simpleChatGenerationError', userLanguage), error);
       throw error;
     }
   }
 
   /**
-   * 対話内容に基づいてチャットのタイトルを自動生成する
+   * Automatically generate chat title based on conversation content
    */
   async generateChatTitle(historyId: string, userId: string, tenantId?: string): Promise<string | null> {
     this.logger.log(`Generating automatic title for chat session ${historyId}`);

+ 9 - 0
server/src/i18n/messages.ts

@@ -357,6 +357,9 @@ export const statusMessages = {
     userLabel: '用户',
     assistantLabel: '助手',
     intelligentAssistant: '您是智能写作助手。',
+    assistSystemPrompt: '请根据用户的指示修正或改进提供的文本内容。不要包含问候语或结束语(如"明白了,这是..."等),直接输出修正后的内容。',
+    contextLabel: '上下文(当前内容)',
+    userInstructionLabel: '用户指示',
     searchString: '搜索字符串: ',
     embeddingModelIdNotProvided: '未提供嵌入模型ID',
     generatingEmbeddings: '生成嵌入向量...',
@@ -449,6 +452,9 @@ export const statusMessages = {
     userLabel: 'ユーザー',
     assistantLabel: 'アシスタント',
     intelligentAssistant: 'あなたはインテリジェントな執筆アシスタントです。',
+    assistSystemPrompt: '提供されたテキスト内容を、ユーザーの指示に基づいて修正または改善してください。挨拶や結びの言葉(「わかりました、こちらが...」など)は含めず、修正後の内容のみを直接出力してください。',
+    contextLabel: 'コンテキスト(現在の内容)',
+    userInstructionLabel: 'ユーザーの指示',
     searchString: '検索文字列: ',
     embeddingModelIdNotProvided: '埋め込みモデルIDが提供されていません',
     generatingEmbeddings: '埋め込みベクトルを生成中...',
@@ -541,6 +547,9 @@ export const statusMessages = {
     userLabel: 'User',
     assistantLabel: 'Assistant',
     intelligentAssistant: 'You are an intelligent writing assistant.',
+    assistSystemPrompt: 'Please revise or improve the provided text content based on the user\'s instructions. Do not include greetings or closing phrases (such as "Understood, here is..." etc.), output only the revised content directly.',
+    contextLabel: 'Context (current content)',
+    userInstructionLabel: 'User instructions',
     searchString: 'Search string: ',
     embeddingModelIdNotProvided: 'Embedding model ID not provided',
     generatingEmbeddings: 'Generating embeddings...',