forked from mrq/tortoise-tts
164 lines
5.8 KiB
Python
Executable File
164 lines
5.8 KiB
Python
Executable File
import os
|
|
import argparse
|
|
import gradio as gr
|
|
import torch
|
|
import torchaudio
|
|
import time
|
|
|
|
from datetime import datetime
|
|
from tortoise.api import TextToSpeech
|
|
from tortoise.utils.audio import load_audio, load_voice, load_voices
|
|
|
|
def inference(text, emotion, prompt, voice, mic_audio, preset, seed, candidates, num_autoregressive_samples, diffusion_iterations, temperature, progress=gr.Progress()):
|
|
if voice != "microphone":
|
|
voices = [voice]
|
|
else:
|
|
voices = []
|
|
|
|
if emotion == "Custom" and prompt.strip() != "":
|
|
text = f"[{prompt},] {text}"
|
|
elif emotion != "None":
|
|
text = f"[I am really {emotion.lower()},] {text}"
|
|
|
|
if voice == "microphone":
|
|
if mic_audio is None:
|
|
raise gr.Error("Please provide audio from mic when choosing `microphone` as a voice input")
|
|
mic = load_audio(mic_audio, 22050)
|
|
voice_samples, conditioning_latents = [mic], None
|
|
else:
|
|
voice_samples, conditioning_latents = load_voice(voice)
|
|
|
|
if voice_samples is not None:
|
|
sample_voice = voice_samples[0]
|
|
conditioning_latents = tts.get_conditioning_latents(voice_samples)
|
|
torch.save(conditioning_latents, os.path.join(f'./tortoise/voices/{voice}/', f'latents.pth'))
|
|
voice_samples = None
|
|
else:
|
|
sample_voice = None
|
|
|
|
if seed == 0:
|
|
seed = None
|
|
|
|
start_time = time.time()
|
|
|
|
presets = {
|
|
'ultra_fast': {'num_autoregressive_samples': 16, 'diffusion_iterations': 30, 'cond_free': False},
|
|
'fast': {'num_autoregressive_samples': 96, 'diffusion_iterations': 80},
|
|
'standard': {'num_autoregressive_samples': 256, 'diffusion_iterations': 200},
|
|
'high_quality': {'num_autoregressive_samples': 256, 'diffusion_iterations': 400},
|
|
'none': {'num_autoregressive_samples': num_autoregressive_samples, 'diffusion_iterations': diffusion_iterations},
|
|
}
|
|
settings = {
|
|
'temperature': temperature, 'length_penalty': 1.0, 'repetition_penalty': 2.0,
|
|
'top_p': .8,
|
|
'cond_free_k': 2.0, 'diffusion_temperature': 1.0,
|
|
|
|
'voice_samples': voice_samples,
|
|
'conditioning_latents': conditioning_latents,
|
|
'use_deterministic_seed': seed,
|
|
'return_deterministic_state': True,
|
|
'k': candidates,
|
|
'progress': progress,
|
|
}
|
|
settings.update(presets[preset])
|
|
gen, additionals = tts.tts( text, **settings )
|
|
seed = additionals[0]
|
|
|
|
info = f"{datetime.now()} | Voice: {','.join(voices)} | Text: {text} | Quality: {preset} preset / {num_autoregressive_samples} samples / {diffusion_iterations} iterations | Temperature: {temperature} | Time Taken (s): {time.time()-start_time} | Seed: {seed}\n"
|
|
with open("results.log", "a") as f:
|
|
f.write(info)
|
|
|
|
timestamp = int(time.time())
|
|
outdir = f"./results/{voice}/{timestamp}/"
|
|
|
|
os.makedirs(outdir, exist_ok=True)
|
|
|
|
with open(os.path.join(outdir, f'input.txt'), 'w') as f:
|
|
f.write(f"{text}\n\n{info}")
|
|
|
|
if isinstance(gen, list):
|
|
for j, g in enumerate(gen):
|
|
torchaudio.save(os.path.join(outdir, f'result_{j}.wav'), g.squeeze(0).cpu(), 24000)
|
|
|
|
output_voice = gen[0]
|
|
else:
|
|
torchaudio.save(os.path.join(outdir, f'result.wav'), gen.squeeze(0).cpu(), 24000)
|
|
output_voice = gen
|
|
|
|
output_voice = (24000, output_voice.squeeze().cpu().numpy())
|
|
|
|
if sample_voice is not None:
|
|
sample_voice = (22050, sample_voice.squeeze().cpu().numpy())
|
|
|
|
return (
|
|
sample_voice,
|
|
output_voice,
|
|
seed
|
|
)
|
|
|
|
def main():
|
|
text = gr.Textbox(lines=4, label="Prompt")
|
|
emotion = gr.Radio(
|
|
["None", "Happy", "Sad", "Angry", "Disgusted", "Arrogant", "Custom"],
|
|
value="None",
|
|
label="Emotion",
|
|
type="value",
|
|
)
|
|
prompt = gr.Textbox(lines=1, label="Custom Emotion (if selected)")
|
|
preset = gr.Radio(
|
|
["ultra_fast", "fast", "standard", "high_quality", "none"],
|
|
value="none",
|
|
label="Preset",
|
|
type="value",
|
|
)
|
|
candidates = gr.Slider(value=1, minimum=1, maximum=6, label="Candidates")
|
|
num_autoregressive_samples = gr.Slider(value=128, minimum=0, maximum=512, step=1, label="Samples")
|
|
diffusion_iterations = gr.Slider(value=128, minimum=0, maximum=512, step=1, label="Iterations")
|
|
temperature = gr.Slider(value=0.2, minimum=0, maximum=1, step=0.1, label="Temperature")
|
|
|
|
voice = gr.Dropdown(
|
|
os.listdir(os.path.join("tortoise", "voices")) + ["random", "microphone", "disabled"],
|
|
label="Voice",
|
|
type="value",
|
|
)
|
|
mic_audio = gr.Audio(
|
|
label="Microphone Source",
|
|
source="microphone",
|
|
type="filepath",
|
|
)
|
|
seed = gr.Number(value=0, precision=0, label="Seed")
|
|
|
|
selected_voice = gr.Audio(label="Source Sample")
|
|
output_audio = gr.Audio(label="Output")
|
|
usedSeed = gr.Textbox(label="Seed", placeholder="0", interactive=False)
|
|
|
|
interface = gr.Interface(
|
|
fn=inference,
|
|
inputs=[
|
|
text,
|
|
emotion,
|
|
prompt,
|
|
voice,
|
|
mic_audio,
|
|
preset,
|
|
seed,
|
|
candidates,
|
|
num_autoregressive_samples,
|
|
diffusion_iterations,
|
|
temperature
|
|
],
|
|
outputs=[selected_voice, output_audio, usedSeed],
|
|
allow_flagging='never'
|
|
)
|
|
interface.queue().launch(share=args.share)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--share", action='store_true', help="Lets Gradio return a public URL to use anywhere")
|
|
parser.add_argument("--low-vram", action='store_true', help="Disables some optimizations that increases VRAM usage")
|
|
args = parser.parse_args()
|
|
|
|
tts = TextToSpeech(minor_optimizations=not args.low_vram)
|
|
|
|
main() |