ai-interview-caller / src /speech.py
ranjithkumar111's picture
Upload 8 files
b253d7e verified
Raw
History Blame Contribute Delete
2.36 kB
# File: src/speech.py
# Purpose: Speech-to-Text via Groq Whisper and Text-to-Speech via ElevenLabs
import tempfile
from pathlib import Path
import httpx
from groq import Groq
from config import (
GROQ_API_KEY, GROQ_STT_MODEL,
ELEVENLABS_API_KEY, ELEVENLABS_VOICE_ID, ELEVENLABS_MODEL_ID,
)
_groq = Groq(api_key=GROQ_API_KEY)
# ── Speech-to-Text (Groq Whisper) ─────────────────────────────────────────────
def transcribe_audio(audio_bytes: bytes, content_type: str = "audio/wav") -> str:
"""Transcribe audio bytes using Groq Whisper. Returns transcript string."""
suffix_map = {
"audio/wav": ".wav",
"audio/mpeg": ".mp3",
"audio/webm": ".webm",
"audio/ogg": ".ogg",
}
suffix = suffix_map.get(content_type, ".wav")
with tempfile.NamedTemporaryFile(suffix=suffix, delete=False) as tmp:
tmp.write(audio_bytes)
tmp_path = tmp.name
try:
with open(tmp_path, "rb") as f:
transcript = _groq.audio.transcriptions.create(
model=GROQ_STT_MODEL,
file=(Path(tmp_path).name, f, content_type),
language="en",
)
return transcript.text.strip()
finally:
Path(tmp_path).unlink(missing_ok=True)
# ── Text-to-Speech (ElevenLabs) ───────────────────────────────────────────────
ELEVENLABS_TTS_URL = f"https://api.elevenlabs.io/v1/text-to-speech/{ELEVENLABS_VOICE_ID}"
def synthesize_speech(text: str) -> bytes:
"""Convert text to speech using ElevenLabs. Returns raw MP3 bytes."""
headers = {
"xi-api-key": ELEVENLABS_API_KEY,
"Content-Type": "application/json",
"Accept": "audio/mpeg",
}
payload = {
"text": text,
"model_id": ELEVENLABS_MODEL_ID,
"voice_settings": {
"stability": 0.55,
"similarity_boost": 0.75,
"style": 0.0,
"use_speaker_boost": True,
},
}
response = httpx.post(ELEVENLABS_TTS_URL, headers=headers, json=payload, timeout=30)
response.raise_for_status()
return response.content