| import ttsService from '../services/tts.service.js'; | |
| import ttsJobService from '../services/ttsJob.service.js'; | |
| import audioTranscodeService from '../services/audioTranscode.service.js'; | |
| class TtsController { | |
| handleServiceError(error, res, defaultMessage) { | |
| console.error('[TTS Bridge] Error:', error.message); | |
| if (error.response) { | |
| return res.status(error.response.status).json({ | |
| error: defaultMessage, | |
| details: error.response.data | |
| }); | |
| } | |
| return res.status(500).json({ | |
| error: defaultMessage, | |
| details: error.message | |
| }); | |
| } | |
| async health(req, res) { | |
| try { | |
| const data = await ttsService.health(); | |
| return res.json(data); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to reach TTS service'); | |
| } | |
| } | |
| async synthesize(req, res) { | |
| try { | |
| const { text, language, speaker_audio } = req.body; | |
| if (!text) { | |
| return res.status(400).json({ error: 'Text is required' }); | |
| } | |
| const data = await ttsService.synthesize({ | |
| text, | |
| language, | |
| speaker_audio | |
| }); | |
| if (!data?.audio_base64) { | |
| return res.status(502).json({ error: 'TTS service returned empty audio payload' }); | |
| } | |
| const wavBuffer = Buffer.from(data.audio_base64, 'base64'); | |
| const mp3Buffer = await audioTranscodeService.convertWavToMp3(wavBuffer); | |
| const responsePayload = { | |
| ...data, | |
| audio_base64: mp3Buffer.toString('base64'), | |
| format: 'mp3', | |
| mime_type: 'audio/mpeg', | |
| size_bytes: mp3Buffer.length | |
| }; | |
| return res.json(responsePayload); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to synthesize speech'); | |
| } | |
| } | |
| async createTask(req, res) { | |
| try { | |
| const { text, language, speaker_audio } = req.body; | |
| if (!text) { | |
| return res.status(400).json({ error: 'Text is required' }); | |
| } | |
| const data = await ttsService.createTask({ | |
| text, | |
| language, | |
| speaker_audio | |
| }); | |
| return res.status(202).json(data); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to dispatch TTS task'); | |
| } | |
| } | |
| async getTask(req, res) { | |
| try { | |
| const { taskId } = req.params; | |
| if (!taskId) { | |
| return res.status(400).json({ error: 'taskId is required' }); | |
| } | |
| const data = await ttsService.getTask(taskId); | |
| return res.json(data); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to fetch TTS task status'); | |
| } | |
| } | |
| async createStorageJob(req, res) { | |
| try { | |
| const { text, language, speaker_audio } = req.body; | |
| if (!text) { | |
| return res.status(400).json({ error: 'Text is required' }); | |
| } | |
| const data = ttsJobService.createJob({ | |
| text, | |
| language, | |
| speaker_audio | |
| }); | |
| return res.status(202).json(data); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to create TTS storage job'); | |
| } | |
| } | |
| async getStorageJob(req, res) { | |
| try { | |
| const { key } = req.params; | |
| if (!key) { | |
| return res.status(400).json({ error: 'key is required' }); | |
| } | |
| const data = ttsJobService.getJob(key); | |
| if (!data) { | |
| return res.status(404).json({ error: 'TTS job not found' }); | |
| } | |
| return res.json(data); | |
| } catch (error) { | |
| return this.handleServiceError(error, res, 'Failed to fetch TTS storage job'); | |
| } | |
| } | |
| } | |
| export default new TtsController(); | |