From add124970ef4bddb8eb371f976e94b4f4d7329a4 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Mon, 5 Jan 2026 03:57:10 +0300 Subject: [PATCH] voice --- backend/src/main.ts | 1 + backend/src/voice/voice.controller.ts | 15 ++++++++++++- backend/src/voice/voice.service.ts | 31 +++++++++++++++++++++++---- 3 files changed, 42 insertions(+), 5 deletions(-) diff --git a/backend/src/main.ts b/backend/src/main.ts index 97f5e11..ad60f27 100644 --- a/backend/src/main.ts +++ b/backend/src/main.ts @@ -32,6 +32,7 @@ log(` JWT_SECRET: ${process.env.JWT_SECRET ? 'SET (length: ' + process.env.JWT_ log(` PORT: ${process.env.PORT || 'NOT SET (default: 3000)'}`); log(` HOST: ${process.env.HOST || 'NOT SET (default: 0.0.0.0)'}`); log(` CORS_ORIGIN: ${process.env.CORS_ORIGIN || 'NOT SET (default: http://localhost:5173)'}`); +log(` VOICE_SERVICE_HOST: ${process.env.VOICE_SERVICE_HOST || 'NOT SET'}`); // Проверяем и исправляем формат DATABASE_URL if (process.env.DATABASE_URL) { diff --git a/backend/src/voice/voice.controller.ts b/backend/src/voice/voice.controller.ts index fd356cc..bf99c08 100644 --- a/backend/src/voice/voice.controller.ts +++ b/backend/src/voice/voice.controller.ts @@ -7,22 +7,30 @@ import { Res, HttpStatus, HttpException, + Logger, } from '@nestjs/common'; import type { Response } from 'express'; import { VoiceService } from './voice.service'; @Controller('voice') export class VoiceController { - constructor(private voiceService: VoiceService) {} + private readonly logger = new Logger(VoiceController.name); + + constructor(private voiceService: VoiceService) { + this.logger.log('VoiceController initialized'); + } @Post('tts') async generateTTS( @Body() body: { text: string; voice?: string }, @Res() res: Response, ) { + this.logger.log('POST /voice/tts - Request received'); const { text, voice = 'sarah' } = body; + this.logger.debug(`Request body: text="${text?.substring(0, 50)}...", voice=${voice}`); if (!text) { + this.logger.warn('POST /voice/tts - Text is missing'); return res.status(HttpStatus.BAD_REQUEST).json({ error: 'Text is required', }); @@ -31,6 +39,7 @@ export class VoiceController { try { const audioBuffer = await this.voiceService.generateTTS(text, voice); + this.logger.log(`POST /voice/tts - Success, sending ${audioBuffer.length} bytes`); res.setHeader('Content-Type', 'audio/mpeg'); res.setHeader('Content-Length', audioBuffer.length.toString()); res.send(audioBuffer); @@ -39,6 +48,7 @@ export class VoiceController { ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const message = error.message || 'Failed to generate speech'; + this.logger.error(`POST /voice/tts - Error: ${message} (status: ${status})`); return res.status(status).json({ error: message, }); @@ -50,9 +60,11 @@ export class VoiceController { @Param('effectType') effectType: string, @Res() res: Response, ) { + this.logger.log(`GET /voice/effects/${effectType} - Request received`); try { const audioBuffer = await this.voiceService.getEffect(effectType); + this.logger.log(`GET /voice/effects/${effectType} - Success, sending ${audioBuffer.length} bytes`); res.setHeader('Content-Type', 'audio/mpeg'); res.setHeader('Content-Length', audioBuffer.length.toString()); res.send(audioBuffer); @@ -61,6 +73,7 @@ export class VoiceController { ? error.getStatus() : HttpStatus.INTERNAL_SERVER_ERROR; const message = error.message || 'Failed to get sound effect'; + this.logger.error(`GET /voice/effects/${effectType} - Error: ${message} (status: ${status})`); return res.status(status).json({ error: message, }); diff --git a/backend/src/voice/voice.service.ts b/backend/src/voice/voice.service.ts index f92b190..b28f975 100644 --- a/backend/src/voice/voice.service.ts +++ b/backend/src/voice/voice.service.ts @@ -1,23 +1,30 @@ -import { Injectable, HttpException, HttpStatus } from '@nestjs/common'; +import { Injectable, HttpException, HttpStatus, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; @Injectable() export class VoiceService { + private readonly logger = new Logger(VoiceService.name); private readonly voiceServiceUrl: string; constructor(private configService: ConfigService) { + this.logger.log('Initializing VoiceService...'); const voiceServiceHost = this.configService.get('VOICE_SERVICE_HOST'); if (!voiceServiceHost) { - throw new Error('VOICE_SERVICE_HOST environment variable is not set'); + const error = 'VOICE_SERVICE_HOST environment variable is not set'; + this.logger.error(error); + throw new Error(error); } this.voiceServiceUrl = voiceServiceHost; + this.logger.log(`VoiceService initialized with URL: ${this.voiceServiceUrl}`); } async generateTTS(text: string, voice: string = 'sarah'): Promise { + this.logger.log(`Generating TTS for text: "${text.substring(0, 50)}..." with voice: ${voice}`); try { const url = `${this.voiceServiceUrl}/api/voice/tts`; + this.logger.debug(`Making request to: ${url}`); const response = await fetch(url, { method: 'POST', headers: { @@ -26,7 +33,10 @@ export class VoiceService { body: JSON.stringify({ text, voice }), }); + this.logger.debug(`Response status: ${response.status} ${response.statusText}`); + if (!response.ok) { + this.logger.error(`Voice service error: ${response.status} ${response.statusText}`); throw new HttpException( `Voice service error: ${response.statusText}`, response.status || HttpStatus.INTERNAL_SERVER_ERROR, @@ -34,11 +44,15 @@ export class VoiceService { } const arrayBuffer = await response.arrayBuffer(); - return Buffer.from(arrayBuffer); + const buffer = Buffer.from(arrayBuffer); + this.logger.log(`TTS generated successfully, size: ${buffer.length} bytes`); + return buffer; } catch (error) { if (error instanceof HttpException) { + this.logger.error(`HttpException in generateTTS: ${error.message}`); throw error; } + this.logger.error(`Error in generateTTS: ${error.message}`, error.stack); throw new HttpException( `Failed to generate speech: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR, @@ -47,13 +61,18 @@ export class VoiceService { } async getEffect(effectType: string): Promise { + this.logger.log(`Getting effect: ${effectType}`); try { const url = `${this.voiceServiceUrl}/api/voice/effects/${effectType}`; + this.logger.debug(`Making request to: ${url}`); const response = await fetch(url, { method: 'GET', }); + this.logger.debug(`Response status: ${response.status} ${response.statusText}`); + if (!response.ok) { + this.logger.error(`Voice service error: ${response.status} ${response.statusText}`); throw new HttpException( `Voice service error: ${response.statusText}`, response.status || HttpStatus.INTERNAL_SERVER_ERROR, @@ -61,11 +80,15 @@ export class VoiceService { } const arrayBuffer = await response.arrayBuffer(); - return Buffer.from(arrayBuffer); + const buffer = Buffer.from(arrayBuffer); + this.logger.log(`Effect retrieved successfully, size: ${buffer.length} bytes`); + return buffer; } catch (error) { if (error instanceof HttpException) { + this.logger.error(`HttpException in getEffect: ${error.message}`); throw error; } + this.logger.error(`Error in getEffect: ${error.message}`, error.stack); throw new HttpException( `Failed to get sound effect: ${error.message}`, HttpStatus.INTERNAL_SERVER_ERROR,