|
|
@@ -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}`);
|