"""Sintesi delle battute con XTTS-v2 (gira nel Python di XTTS, lo lancia tools/voci.mjs): voci_xtts.py lavori.json lavori.json: [{"text": ..., "speaker": ..., "out": "/assoluto/x.wav"}, ...]; un lavoro già fatto si salta. In italiano XTTS legge i punti a fine frase («Buongiorno, punto») e inciampa sui caporali: ogni battuta si divide in frasi, senza punti finali né caporali, e le frasi si uniscono con una pausa breve. Il modello è sotto licenza Coqui Public Model License: solo uso non commerciale.""" import json import os import re import sys PAUSA = 0.22 # secondi fra una frase e l'altra os.environ["COQUI_TOS_AGREED"] = "1" def frasi(testo: str) -> list[str]: testo = re.sub(r"[«»\"“”]", "", testo) parti = re.split(r"(?<=[.!?…])\s+", testo.strip()) pulite = [re.sub(r"(\.\.\.|…|\.)+$", "", p).strip() for p in parti] return [p for p in pulite if re.search(r"\w", p)] lavori = [j for j in json.load(open(sys.argv[1])) if not os.path.exists(j["out"])] if lavori: import torch import torchaudio from TTS.api import TTS tts = TTS("tts_models/multilingual/multi-dataset/xtts_v2").to("cuda") sr = tts.synthesizer.output_sample_rate for i, j in enumerate(lavori, 1): pezzi = [] for f in frasi(j["text"]): if pezzi: pezzi.append(torch.zeros(int(sr * PAUSA))) pezzi.append(torch.tensor(tts.tts(f, language="it", speaker=j["speaker"], split_sentences=False), dtype=torch.float32)) torchaudio.save(j["out"] + ".tmp.wav", torch.cat(pezzi).unsqueeze(0), sr, format="wav") os.replace(j["out"] + ".tmp.wav", j["out"]) print(f"{i}/{len(lavori)}", flush=True) print(f"{len(lavori)} battute sintetizzate")