TTS Provider¶
Text-to-Speech через Edge-TTS с извлечением таймингов слов.
Возможности¶
- Бесплатный TTS от Microsoft Edge
- Множество голосов и языков
- Word-level тайминги для синхронизации
- SSML поддержка
- Контроль скорости и pitch
Использование¶
Базовый синтез¶
from kit.providers.tts import EdgeTTSProvider
tts = EdgeTTSProvider(voice="ru-RU-DmitryNeural")
result = await tts.synthesize(
text="Привет! Как дела?",
output_path="output.mp3"
)
print(f"Audio: {result.audio_path}")
print(f"Duration: {result.duration_ms}ms")
Тайминги слов¶
result = await tts.synthesize(
text="Это пример текста для синтеза речи",
output_path="output.mp3"
)
# Тайминг каждого слова
for timing in result.word_timings:
print(f"{timing.word}: {timing.start_ms}-{timing.end_ms}ms")
# Пример вывода:
# Это: 0-250ms
# пример: 250-520ms
# текста: 520-890ms
# для: 890-1050ms
# синтеза: 1050-1450ms
# речи: 1450-1720ms
Доступные голоса¶
# Русские голоса
voices = [
"ru-RU-DmitryNeural", # Мужской
"ru-RU-SvetlanaNeural", # Женский
]
# Казахские голоса
voices = [
"kk-KZ-AigulNeural", # Женский
"kk-KZ-DauletNeural", # Мужской
]
# Английские голоса
voices = [
"en-US-GuyNeural",
"en-US-JennyNeural",
"en-GB-RyanNeural",
]
# Получить все голоса
all_voices = await EdgeTTSProvider.list_voices()
Параметры синтеза¶
result = await tts.synthesize(
text="Текст для озвучки",
output_path="output.mp3",
rate="+10%", # Скорость: -50% до +100%
pitch="+5Hz", # Высота тона
volume="+0%" # Громкость
)
SSML поддержка¶
ssml = """
<speak>
<prosody rate="slow">Медленная речь.</prosody>
<break time="500ms"/>
<prosody pitch="high">Высокий голос!</prosody>
<emphasis level="strong">Важно!</emphasis>
</speak>
"""
result = await tts.synthesize_ssml(ssml, "output.mp3")
Batch синтез¶
texts = [
"Первое предложение",
"Второе предложение",
"Третье предложение"
]
results = await tts.synthesize_batch(
texts,
output_dir="./audio"
)
for result in results:
print(f"{result.audio_path}: {result.duration_ms}ms")
API Reference¶
EdgeTTSProvider¶
class EdgeTTSProvider:
def __init__(
self,
voice: str = "ru-RU-DmitryNeural",
rate: str = "+0%",
pitch: str = "+0Hz",
volume: str = "+0%"
)
async def synthesize(
self,
text: str,
output_path: str,
rate: str = None,
pitch: str = None,
volume: str = None
) -> TTSResult
async def synthesize_ssml(
self,
ssml: str,
output_path: str
) -> TTSResult
async def synthesize_batch(
self,
texts: List[str],
output_dir: str
) -> List[TTSResult]
@staticmethod
async def list_voices(language: str = None) -> List[Voice]
TTSResult¶
@dataclass
class TTSResult:
audio_path: str
duration_ms: int
word_timings: List[WordTiming]
voice: str
@dataclass
class WordTiming:
word: str
start_ms: int
end_ms: int
@property
def duration_ms(self) -> int:
return self.end_ms - self.start_ms
Примеры из production¶
Autoshorts — озвучка с субтитрами¶
class VoiceoverGenerator:
def __init__(self):
self.tts = EdgeTTSProvider(voice="ru-RU-DmitryNeural")
async def generate_with_subtitles(
self,
script: str,
output_dir: str
) -> dict:
"""Генерация озвучки и файла субтитров."""
result = await self.tts.synthesize(
text=script,
output_path=f"{output_dir}/voiceover.mp3"
)
# Генерация SRT субтитров
srt_content = self.create_srt(result.word_timings)
srt_path = f"{output_dir}/subtitles.srt"
with open(srt_path, "w", encoding="utf-8") as f:
f.write(srt_content)
return {
"audio": result.audio_path,
"subtitles": srt_path,
"duration": result.duration_ms
}
def create_srt(self, timings: List[WordTiming]) -> str:
"""Создание SRT файла из таймингов."""
srt_lines = []
# Группируем слова по 5-7 для субтитров
chunks = self.chunk_words(timings, max_words=6)
for i, chunk in enumerate(chunks, 1):
start = self.ms_to_srt_time(chunk[0].start_ms)
end = self.ms_to_srt_time(chunk[-1].end_ms)
text = " ".join(w.word for w in chunk)
srt_lines.append(f"{i}")
srt_lines.append(f"{start} --> {end}")
srt_lines.append(text)
srt_lines.append("")
return "\n".join(srt_lines)
def ms_to_srt_time(self, ms: int) -> str:
"""Конвертация миллисекунд в SRT формат."""
hours = ms // 3600000
minutes = (ms % 3600000) // 60000
seconds = (ms % 60000) // 1000
millis = ms % 1000
return f"{hours:02d}:{minutes:02d}:{seconds:02d},{millis:03d}"
Karaoke-style субтитры¶
class KaraokeGenerator:
def __init__(self):
self.tts = EdgeTTSProvider()
async def generate(self, text: str, output_path: str) -> dict:
result = await self.tts.synthesize(text, f"{output_path}/audio.mp3")
# ASS субтитры с karaoke эффектом
ass_content = self.create_karaoke_ass(result.word_timings)
with open(f"{output_path}/karaoke.ass", "w") as f:
f.write(ass_content)
return {
"audio": result.audio_path,
"subtitles": f"{output_path}/karaoke.ass"
}
def create_karaoke_ass(self, timings: List[WordTiming]) -> str:
# ASS формат с подсветкой текущего слова
...
DedMoroz.ai — персонализированная озвучка¶
class GreetingVoiceover:
def __init__(self):
self.tts = EdgeTTSProvider(
voice="ru-RU-DmitryNeural",
rate="-5%", # Чуть медленнее для торжественности
pitch="-2Hz" # Чуть ниже для "дедморозовости"
)
async def generate(self, greeting: str, name: str) -> str:
output_path = f"./greetings/{name}_{uuid4()}.mp3"
await self.tts.synthesize(
text=greeting,
output_path=output_path
)
return output_path