voice
This commit is contained in:
parent
4b6e1aa69c
commit
add124970e
3 changed files with 42 additions and 5 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<string>('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<Buffer> {
|
||||
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<Buffer> {
|
||||
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,
|
||||
|
|
|
|||
Loading…
Reference in a new issue