Update app.py
Browse files
app.py
CHANGED
|
@@ -850,8 +850,7 @@ async def generate_subtitle_groq(request: GroqRequest):
|
|
| 850 |
|
| 851 |
return JSONResponse(content={
|
| 852 |
"srt": srt_filtered,
|
| 853 |
-
"srt_word": srt_word
|
| 854 |
-
"processed_audio_url": processed_audio_url
|
| 855 |
})
|
| 856 |
|
| 857 |
except HTTPException:
|
|
@@ -861,6 +860,89 @@ async def generate_subtitle_groq(request: GroqRequest):
|
|
| 861 |
traceback.print_exc()
|
| 862 |
raise HTTPException(status_code=500, detail=f"Erro interno: {str(e)}")
|
| 863 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 864 |
@app.get("/subtitle")
|
| 865 |
async def generate_subtitle(
|
| 866 |
file: str,
|
|
|
|
| 850 |
|
| 851 |
return JSONResponse(content={
|
| 852 |
"srt": srt_filtered,
|
| 853 |
+
"srt_word": srt_word
|
|
|
|
| 854 |
})
|
| 855 |
|
| 856 |
except HTTPException:
|
|
|
|
| 860 |
traceback.print_exc()
|
| 861 |
raise HTTPException(status_code=500, detail=f"Erro interno: {str(e)}")
|
| 862 |
|
| 863 |
+
class GeminiSubtitleRequest(BaseModel):
|
| 864 |
+
url: str
|
| 865 |
+
has_bg_music: Optional[bool] = False
|
| 866 |
+
context: Optional[str] = "N/A"
|
| 867 |
+
model: Optional[str] = "flash" # 'flash' or 'thinking'
|
| 868 |
+
|
| 869 |
+
@app.post("/subtitle/gemini")
|
| 870 |
+
async def generate_subtitle_gemini(request: GeminiSubtitleRequest):
|
| 871 |
+
"""
|
| 872 |
+
Endpoint PRINCIPAL:
|
| 873 |
+
1. Baixa e Processa áudio (Demucs opcional + Filtros FFmpeg)
|
| 874 |
+
2. Gera SRT base via Groq (Whisper)
|
| 875 |
+
3. Envia Áudio Processado + SRT Base + Prompt para Gemini
|
| 876 |
+
4. Gemini analisa entonação/contexto e traduz/corrige.
|
| 877 |
+
"""
|
| 878 |
+
if not chatbots:
|
| 879 |
+
raise HTTPException(status_code=500, detail="Chatbot não inicializado")
|
| 880 |
+
|
| 881 |
+
try:
|
| 882 |
+
# 1. Obter SRT base + Caminho do áudio processado
|
| 883 |
+
print("🚀 Iniciando pipeline completo de legendagem Gemini...")
|
| 884 |
+
|
| 885 |
+
srt_filtered, srt_word, processed_audio_url = await get_groq_srt_base(
|
| 886 |
+
url=request.url,
|
| 887 |
+
language="en",
|
| 888 |
+
temperature=0.4,
|
| 889 |
+
has_bg_music=request.has_bg_music
|
| 890 |
+
)
|
| 891 |
+
|
| 892 |
+
# Converter URL /static/xyz.mp3 para path local
|
| 893 |
+
# processed_audio_url ex: "/static/audio_..."
|
| 894 |
+
filename = processed_audio_url.split("/")[-1]
|
| 895 |
+
processed_audio_path = os.path.join("static", filename)
|
| 896 |
+
|
| 897 |
+
if not os.path.exists(processed_audio_path):
|
| 898 |
+
raise HTTPException(status_code=500, detail=f"Arquivo de áudio processado não encontrado: {processed_audio_path}")
|
| 899 |
+
|
| 900 |
+
# 2. Selecionar Modelo Gemini
|
| 901 |
+
requested_model = request.model.lower()
|
| 902 |
+
chatbot_key = 'thinking' if 'thinking' in requested_model else 'flash'
|
| 903 |
+
chatbot = chatbots.get(chatbot_key, chatbots['default'])
|
| 904 |
+
|
| 905 |
+
print(f"🧠 [Gemini] Enviando SRT + Áudio para análise ({chatbot_key})...")
|
| 906 |
+
|
| 907 |
+
# 3. Montar Prompt
|
| 908 |
+
processed_context = request.context if request.context else "N/A"
|
| 909 |
+
|
| 910 |
+
prompt = f\"\"\"
|
| 911 |
+
Traduza essa legenda pro português do Brasil, corrija qualquer erro de formatação, pontuação e mantenha timestamps e os textos nos seus respectivos blocos de legenda.
|
| 912 |
+
|
| 913 |
+
Deve traduzir exatamente o texto da legenda observando o contexto, não é pra migrar, por exemplo, textos de um bloco de legenda pra outro. Deve traduzir exatamente o texto de cada bloco de legenda, manter sempre as palavras, nunca retirar.
|
| 914 |
+
|
| 915 |
+
Mande o SRT completo, sem textos adicionais na resposta, apenas o SRT traduzido. Também analise o áudio anexado pra ver se algo foi legendado incorretamente ou errado, ou se algo não for legendado. Se não for, inclua, sem mudar o timestamp já existente. A legenda acima é uma base gerada pelo Whisper que precisa ser analisada e traduzida, não o resultado final.
|
| 916 |
+
|
| 917 |
+
A legenda deve ser totalmente traduzida corretamente analisando o contexto e a entonação de falar. Se alguém estiver gritando, ESCREVA MAIÚSCULO! etc... Adapte gírias e qualquer coisa do tipo. Não deve ser literal a tradução, deve se adaptar.
|
| 918 |
+
|
| 919 |
+
INSTRUÇÕES/CONTEXTO DO USUÁRIO: {processed_context}
|
| 920 |
+
|
| 921 |
+
--- LEGENDA BASE (WHISPER) ---
|
| 922 |
+
{srt_filtered}
|
| 923 |
+
\"\"\"
|
| 924 |
+
|
| 925 |
+
# 4. Enviar para Gemini
|
| 926 |
+
response = await chatbot.ask(prompt, audio=processed_audio_path)
|
| 927 |
+
|
| 928 |
+
content = response.get("content", "")
|
| 929 |
+
if response.get("error"):
|
| 930 |
+
raise HTTPException(status_code=500, detail=f"Erro no Gemini: {content}")
|
| 931 |
+
|
| 932 |
+
# Limpar markdown do SRT se houver
|
| 933 |
+
cleaned_srt = clean_and_validate_srt(content)
|
| 934 |
+
|
| 935 |
+
return JSONResponse(content={
|
| 936 |
+
"srt": cleaned_srt,
|
| 937 |
+
"original_srt": srt_filtered,
|
| 938 |
+
"used_audio_processed": True
|
| 939 |
+
})
|
| 940 |
+
|
| 941 |
+
except Exception as e:
|
| 942 |
+
import traceback
|
| 943 |
+
traceback.print_exc()
|
| 944 |
+
raise HTTPException(status_code=500, detail=str(e))
|
| 945 |
+
|
| 946 |
@app.get("/subtitle")
|
| 947 |
async def generate_subtitle(
|
| 948 |
file: str,
|