Spaces:
Sleeping
Sleeping
| import { | |
| Injectable, | |
| Logger, | |
| } from '@nestjs/common'; | |
| import { ConfigService } from '@nestjs/config'; | |
| interface AgentApiRequest { | |
| conversation_id: string; | |
| query: string; | |
| sender_id: string; | |
| } | |
| interface AgentApiResponse { | |
| reply?: string; | |
| message?: string; | |
| content?: string; | |
| response?: string; | |
| text?: string; | |
| answer?: string; | |
| } | |
| () | |
| export class AgentService { | |
| private readonly logger = new Logger(AgentService.name); | |
| constructor( | |
| private readonly configService: ConfigService, | |
| ) {} | |
| // ==================== Mention Bot Logic ==================== | |
| /** | |
| * Check if message contains a mention of the configured bot username | |
| */ | |
| containsMention(content: string): boolean { | |
| const botUsername = this.configService.get<string>('AGENT_BOT_USERNAME') || this.configService.get<string>('agent.botUsername') || 'studybot'; | |
| const pattern = new RegExp(`@${botUsername}\\b`, 'i'); | |
| return pattern.test(content); | |
| } | |
| /** | |
| * Extract the prompt from a message by removing the bot mention | |
| */ | |
| extractPrompt(content: string): string { | |
| const botUsername = this.configService.get<string>('AGENT_BOT_USERNAME') || this.configService.get<string>('agent.botUsername') || 'studybot'; | |
| const pattern = new RegExp(`@${botUsername}\\b`, 'gi'); | |
| return content.replace(pattern, '').trim(); | |
| } | |
| /** | |
| * Get bot user ID from config | |
| */ | |
| getBotUserId(): string | undefined { | |
| const botUserId = this.configService.get<string>('AGENT_BOT_USER_ID'); | |
| if (botUserId) return botUserId; | |
| return this.configService.get<string>('agent.botUserId') || undefined; | |
| } | |
| /** | |
| * Call the external agent API and return the reply text | |
| * Returns null if agent is not configured or returns empty | |
| */ | |
| async callAgent( | |
| roomId: string, | |
| userId: string, | |
| prompt: string, | |
| username?: string, | |
| ): Promise<string | null> { | |
| const baseUrl = this.configService.get<string>('AGENT_API_URL') || this.configService.get<string>('agent.apiUrl'); | |
| if (!baseUrl) { | |
| this.logger.warn('AGENT_API_URL not configured, skipping agent call'); | |
| return 'Xin lỗi, tôi đang gặp sự cố kết nối. Vui lòng thử lại sau!'; | |
| } | |
| if (!prompt) { | |
| this.logger.debug('Empty prompt, skipping agent call'); | |
| return null; | |
| } | |
| try { | |
| this.logger.log(`Calling agent API for room ${roomId}, user ${userId}`); | |
| const reply = await this.callAgentApi({ | |
| conversation_id: roomId, | |
| query: prompt, | |
| sender_id: username || userId, | |
| }); | |
| if (!reply || reply.trim().length === 0) { | |
| this.logger.warn('Agent returned empty reply'); | |
| return 'Xin lỗi, tôi không hiểu câu hỏi của bạn. Vui lòng thử lại!'; | |
| } | |
| this.logger.log(`Agent replied for room ${roomId}`); | |
| return reply; | |
| } catch (error) { | |
| this.logger.error(`Failed to call agent: ${error.message}`); | |
| return 'Xin lỗi, tôi đang gặp sự cố kỹ thuật. Vui lòng thử lại sau nhé!'; | |
| } | |
| } | |
| /** | |
| * Call the external agent API at POST /api/v1/chat | |
| */ | |
| private async callAgentApi(payload: AgentApiRequest): Promise<string> { | |
| const baseUrl = this.configService.get<string>('AGENT_API_URL') || this.configService.get<string>('agent.apiUrl'); | |
| const apiKey = this.configService.get<string>('AGENT_API_KEY') || this.configService.get<string>('agent.apiKey'); | |
| const url = `${baseUrl}/api/v1/chat`; | |
| this.logger.debug(`Agent API URL: ${url}`); | |
| this.logger.debug(`Agent API payload: ${JSON.stringify(payload)}`); | |
| const headers: Record<string, string> = { | |
| 'Content-Type': 'application/json', | |
| }; | |
| if (apiKey) { | |
| headers['Authorization'] = `Bearer ${apiKey}`; | |
| } | |
| const response = await fetch(url, { | |
| method: 'POST', | |
| headers, | |
| body: JSON.stringify(payload), | |
| }); | |
| if (!response.ok) { | |
| throw new Error(`Agent API returned ${response.status}: ${await response.text()}`); | |
| } | |
| const data = (await response.json()) as AgentApiResponse; | |
| // Support multiple response formats | |
| return ( | |
| data.reply || | |
| data.message || | |
| data.content || | |
| data.response || | |
| data.text || | |
| data.answer || | |
| '' | |
| ); | |
| } | |
| } | |