Praieiro commited on
Commit
633046d
·
verified ·
1 Parent(s): 4f82bb6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +35 -57
app.py CHANGED
@@ -1,86 +1,64 @@
1
  import io
2
  import os
3
  import soundfile as sf
4
- import torch
5
- import numpy as np
6
  import gradio as gr
7
  import spaces
8
- from kokoro import KPipeline
9
  from pydantic import BaseModel
10
  from fastapi import HTTPException, Header, Response
 
11
 
12
  SHARED_SECRET = os.environ.get("PRAIEIRO_SECRET", "praieiro-voz-2026")
 
13
 
14
- print("Carregando Kokoro-82M para Português do Brasil...")
15
- pipeline = KPipeline(lang_code="p")
16
 
17
- VOICES = {
18
- "pm_alex (Masculina natural)": "pm_alex",
19
- "pm_santa (Masculina encorpada)": "pm_santa",
20
- "pf_dora (Feminina natural)": "pf_dora",
21
- }
22
-
23
- @spaces.GPU
24
- def generate_audio(text: str, voice_label: str = "pm_alex (Masculina natural)", speed: float = 1.0):
25
- text = (text or "").strip()
26
- if not text:
27
  return None
28
- voice_key = VOICES.get(voice_label, voice_label)
29
-
30
- generator = pipeline(text, voice=voice_key, speed=speed, split_pattern=r"\n+")
31
- audio_chunks = []
32
- for _, _, audio in generator:
33
- audio_chunks.append(audio)
34
 
35
- if not audio_chunks:
36
- return None
37
-
38
- full_audio = np.concatenate(audio_chunks)
39
- return (24000, full_audio)
 
 
 
40
 
41
- # Interface visual do Gradio (para você testar e ouvir na tela do celular)
42
- with gr.Blocks(title="Praieiro Voice · Kokoro") as demo:
43
- gr.Markdown("# 🌊 Praieiro Voice · Kokoro TTS (PT-BR)")
44
- gr.Markdown("Voz neural ultrarrápida para o agente do Praieiro rodando no Hugging Face ZeroGPU.")
45
 
46
  with gr.Row():
47
  text_input = gr.Textbox(
48
- label="Texto para o agente falar",
49
- placeholder="Digite algo...",
50
- value="Fala meu brother! Seu pedido na praia já tá sendo preparado e chega rapidinho na sua barraca.",
51
- lines=3,
52
  )
53
- with gr.Row():
54
- voice_input = gr.Dropdown(
55
- choices=list(VOICES.keys()),
56
- value="pm_alex (Masculina natural)",
57
- label="Escolha a Voz",
58
- )
59
- speed_input = gr.Slider(minimum=0.7, maximum=1.5, value=1.0, step=0.05, label="Velocidade")
60
-
61
- btn = gr.Button("🔊 Ouvir Voz do Agente", variant="primary")
62
- audio_output = gr.Audio(label="Áudio Gerado", autoplay=True)
63
 
64
  btn.click(
65
- fn=generate_audio,
66
- inputs=[text_input, voice_input, speed_input],
67
- outputs=[audio_output],
68
  )
69
 
70
- class SpeechRequest(BaseModel):
 
 
71
  input: str
72
- voice: str = "pm_alex"
73
- speed: float = 1.0
74
 
75
- # Endpoints de API para o Praieiro chamar via HTTP
76
- @demo.app.post("/v1/audio/speech")
77
- @demo.app.post("/tts")
78
- def api_speak(req: SpeechRequest, authorization: str = Header(None)):
79
- expected = f"Bearer {SHARED_SECRET}"
80
- if SHARED_SECRET and authorization != expected:
81
  raise HTTPException(status_code=401, detail="Não autorizado")
82
 
83
- res = generate_audio(req.input, req.voice, req.speed)
84
  if res is None:
85
  raise HTTPException(status_code=400, detail="Texto vazio ou inválido")
86
 
 
1
  import io
2
  import os
3
  import soundfile as sf
 
 
4
  import gradio as gr
5
  import spaces
 
6
  from pydantic import BaseModel
7
  from fastapi import HTTPException, Header, Response
8
+ from f5_tts.api import F5TTS
9
 
10
  SHARED_SECRET = os.environ.get("PRAIEIRO_SECRET", "praieiro-voz-2026")
11
+ REF_AUDIO_PATH = "PraieiroVox.wav"
12
 
13
+ print("Carregando modelo F5-TTS para clonagem de voz...")
14
+ f5tts = F5TTS(model_type="F5-TTS_PT")
15
 
16
+ @spaces.GPU(duration=30)
17
+ def clone_voice(text: str):
18
+ if not text or not text.strip():
 
 
 
 
 
 
 
19
  return None
 
 
 
 
 
 
20
 
21
+ # Gera a fala imitando exatamente o áudio PraieiroVox.wav
22
+ wav, sr, _ = f5tts.infer(
23
+ ref_file=REF_AUDIO_PATH,
24
+ ref_text="",
25
+ gen_text=text.strip(),
26
+ remove_silence=True
27
+ )
28
+ return sr, wav
29
 
30
+ with gr.Blocks(title="Praieiro Vox · Clonagem de Voz") as demo:
31
+ gr.Markdown("# 🌊 Praieiro Vox · Clonador de Voz do Agente")
32
+ gr.Markdown(f"Clonando a voz oficial a partir de **{REF_AUDIO_PATH}** em GPU.")
 
33
 
34
  with gr.Row():
35
  text_input = gr.Textbox(
36
+ label="Texto a ser falado",
37
+ value="Fala meu brother! Seu pedido na praia já tá sendo preparado e chega voando!",
38
+ lines=3
 
39
  )
40
+
41
+ btn = gr.Button("🎤 Gerar Fala com a Voz Clonada", variant="primary")
42
+ audio_output = gr.Audio(label="Áudio Gerado", type="numpy")
 
 
 
 
 
 
 
43
 
44
  btn.click(
45
+ fn=clone_voice,
46
+ inputs=[text_input],
47
+ outputs=[audio_output]
48
  )
49
 
50
+ app = demo.app
51
+
52
+ class TTSRequest(BaseModel):
53
  input: str
 
 
54
 
55
+ @app.post("/v1/audio/speech")
56
+ def generate_speech_endpoint(req: TTSRequest, authorization: str = Header(None)):
57
+ token = authorization.replace("Bearer ", "") if authorization else ""
58
+ if token != SHARED_SECRET:
 
 
59
  raise HTTPException(status_code=401, detail="Não autorizado")
60
 
61
+ res = clone_voice(req.input)
62
  if res is None:
63
  raise HTTPException(status_code=400, detail="Texto vazio ou inválido")
64