perplexity-hackathon-LawMitra / perplexity_hackathon / src / routes / ttsRoutes.ts
ttsRoutes.ts
Raw
import { Router, Request, Response } from 'express';
import { z } from 'zod';
import { ttsService } from '../services/ttsService';
import { languageService } from '../services/languageService';

const router = Router();

// Schema for TTS request
const ttsSchema = z.object({
  text: z.string().min(1).max(5000),
  voiceId: z.string().optional(),
});

router.post('/speak', async (req: Request, res: Response) => {
  try {
    const validatedData = ttsSchema.parse(req.body);

    // Detect language if not already set
    if (!req.language) {
      const detectedLanguage = await languageService.detectFromText(
        validatedData.text,
        req.sessionId || 'default'
      );
      req.language = detectedLanguage;
    }

    // Generate speech using detected/stored language
    const result = await ttsService.generateSpeech({
      ...validatedData,
      language: req.language.code,
    });

    // Set appropriate headers for audio file
    res.setHeader('Content-Type', 'audio/mpeg');
    res.setHeader('Content-Disposition', 'attachment; filename="speech.mp3"');
    res.setHeader('X-Detected-Language', req.language.code);

    // Send the file and clean up afterward
    res.sendFile(result.audioPath, async (err) => {
      if (err) {
        console.error('Error sending audio file:', err);
      }
      // Clean up the file after sending
      await ttsService.cleanup(result.audioPath);
    });
  } catch (error) {
    if (error instanceof z.ZodError) {
      return res.status(400).json({
        success: false,
        error: 'Validation error',
        details: error.errors,
      });
    }

    console.error('Error processing TTS request:', error);
    res.status(500).json({
      success: false,
      error: 'Failed to generate speech',
    });
  }
});

export default router;