| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204 |
- import {
- Body,
- Controller,
- Post,
- Request,
- Res,
- UseGuards,
- } from '@nestjs/common';
- import { Response } from 'express';
- import { ChatMessage, ChatService } from './chat.service';
- import { CombinedAuthGuard } from '../auth/combined-auth.guard';
- import { ModelConfigService } from '../model-config/model-config.service';
- import { TenantService } from '../tenant/tenant.service';
- import { ModelType } from '../types';
- class StreamChatDto {
- message: string;
- history: ChatMessage[];
- userLanguage?: string;
- selectedEmbeddingId?: string;
- selectedLLMId?: string;
- selectedGroups?: string[];
- selectedFiles?: string[];
- historyId?: string;
- enableRerank?: boolean;
- selectedRerankId?: string;
- temperature?: number;
- maxTokens?: number;
- topK?: number;
- similarityThreshold?: number;
- rerankSimilarityThreshold?: number;
- enableQueryExpansion?: boolean;
- enableHyDE?: boolean;
- }
- @Controller('chat')
- @UseGuards(CombinedAuthGuard)
- export class ChatController {
- constructor(
- private chatService: ChatService,
- private modelConfigService: ModelConfigService,
- private tenantService: TenantService,
- ) { }
- @Post('stream')
- async streamChat(
- @Request() req,
- @Body() body: StreamChatDto,
- @Res() res: Response,
- ) {
- try {
- console.log('Full Request Body:', JSON.stringify(body, null, 2));
- 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('=== Chat Debug Info ===');
- console.log('User ID:', userId);
- console.log('Message:', message);
- console.log('User Language:', userLanguage);
- console.log('Selected Embedding ID:', selectedEmbeddingId);
- console.log('Selected LLM ID:', selectedLLMId);
- 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('Similarity Threshold:', similarityThreshold);
- console.log('Rerank Similarity Threshold:', rerankSimilarityThreshold);
- console.log('Query Expansion:', enableQueryExpansion);
- console.log('HyDE:', enableHyDE);
- const role = req.user.role;
- const tenantId = req.user.tenantId;
- let models = await this.modelConfigService.findAll(userId, tenantId);
- if (role !== 'SUPER_ADMIN') {
- const tenantSettings = await this.tenantService.getSettings(tenantId);
- const enabledIds = tenantSettings.enabledModelIds || [];
- // Only allow models that are enabled by the tenant admin
- models = models.filter(m => enabledIds.includes(m.id));
- }
- let llmModel;
- if (selectedLLMId) {
- // Find specifically selected model
- llmModel = await this.modelConfigService.findOne(selectedLLMId, userId, tenantId);
- 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('Final LLM model used (default):', llmModel ? llmModel.name : 'None');
- }
- res.setHeader('Content-Type', 'text/event-stream');
- res.setHeader('Cache-Control', 'no-cache');
- res.setHeader('Connection', 'keep-alive');
- res.setHeader('Access-Control-Allow-Origin', '*');
- if (!llmModel) {
- res.write(
- `data: ${JSON.stringify({ type: 'error', data: 'Please add LLM model and configure API key in model management' })}\n\n`,
- );
- res.write('data: [DONE]\n\n');
- res.end();
- return;
- }
- const stream = this.chatService.streamChat(
- message,
- history,
- userId,
- llmModel as any,
- userLanguage,
- selectedEmbeddingId,
- selectedGroups,
- selectedFiles,
- historyId,
- enableRerank,
- selectedRerankId,
- temperature,
- maxTokens,
- topK,
- similarityThreshold,
- rerankSimilarityThreshold,
- enableQueryExpansion,
- enableHyDE,
- req.user.tenantId // Pass tenant ID
- );
- for await (const chunk of stream) {
- res.write(`data: ${JSON.stringify(chunk)}\n\n`);
- }
- res.write('data: [DONE]\n\n');
- res.end();
- } catch (error) {
- console.error('Stream chat error:', error);
- try {
- res.write(
- `data: ${JSON.stringify({ type: 'error', data: error.message || 'Server Error' })}\n\n`,
- );
- res.write('data: [DONE]\n\n');
- res.end();
- } catch (writeError) {
- console.error('Failed to write error response:', writeError);
- }
- }
- }
- @Post('assist')
- async streamAssist(
- @Request() req,
- @Body() body: { instruction: string; context: string },
- @Res() res: Response,
- ) {
- try {
- const { instruction, context } = body;
- const userId = req.user.id; // Corrected to use req.user.id
- const tenantId = req.user.tenantId;
- const role = req.user.role;
- // Use organization's default LLM from Index Chat Config (strict)
- const llmModel = await this.modelConfigService.findDefaultByType(tenantId, ModelType.LLM);
- res.setHeader('Content-Type', 'text/event-stream');
- res.setHeader('Cache-Control', 'no-cache');
- res.setHeader('Connection', 'keep-alive');
- res.setHeader('Access-Control-Allow-Origin', '*');
- if (!llmModel) {
- res.write(
- `data: ${JSON.stringify({ type: 'error', data: 'LLM model configuration not found' })}\n\n`,
- );
- res.write('data: [DONE]\n\n');
- res.end();
- return;
- }
- const stream = this.chatService.streamAssist(
- instruction,
- context,
- llmModel as any,
- );
- for await (const chunk of stream) {
- res.write(`data: ${JSON.stringify(chunk)}\n\n`);
- }
- res.write('data: [DONE]\n\n');
- res.end();
- } catch (error) {
- console.error('Stream assist error:', error);
- res.write(
- `data: ${JSON.stringify({ type: 'error', data: error.message || 'Server Error' })}\n\n`,
- );
- res.write('data: [DONE]\n\n');
- res.end();
- }
- }
- }
|