Update main.py
Browse files
main.py
CHANGED
|
@@ -387,6 +387,72 @@ Se o contexto enviado pelo usuário não for verdadeiro ou estiver impreciso, ig
|
|
| 387 |
if cut_file and os.path.exists(cut_file.name): os.unlink(cut_file.name)
|
| 388 |
|
| 389 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 390 |
# ==========================================
|
| 391 |
# GROQ ENDPOINTS / SUBTITLES
|
| 392 |
# ==========================================
|
|
|
|
| 387 |
if cut_file and os.path.exists(cut_file.name): os.unlink(cut_file.name)
|
| 388 |
|
| 389 |
|
| 390 |
+
class VideoFilterRequest(BaseModel):
|
| 391 |
+
video_url: str
|
| 392 |
+
|
| 393 |
+
@app.post("/video-filter")
|
| 394 |
+
async def video_filter_endpoint(request: VideoFilterRequest):
|
| 395 |
+
if not client:
|
| 396 |
+
raise HTTPException(status_code=500, detail="Gemini client is not initialized")
|
| 397 |
+
temp_file = None
|
| 398 |
+
try:
|
| 399 |
+
if not request.video_url:
|
| 400 |
+
raise HTTPException(status_code=400, detail="URL do vídeo é obrigatória")
|
| 401 |
+
|
| 402 |
+
print(f"📥 Baixando vídeo para filtro: {request.video_url}")
|
| 403 |
+
response = download_file_with_retry(request.video_url, timeout=600)
|
| 404 |
+
ext = '.webm' if 'webm' in response.headers.get('content-type', '').lower() else '.mp4'
|
| 405 |
+
|
| 406 |
+
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=ext)
|
| 407 |
+
for chunk in response.iter_content(chunk_size=1024*1024):
|
| 408 |
+
if chunk: temp_file.write(chunk)
|
| 409 |
+
temp_file.close()
|
| 410 |
+
|
| 411 |
+
video_path_to_analyze = temp_file.name
|
| 412 |
+
|
| 413 |
+
prompt = """Analise o vídeo anexado e retorne um JSON, apenas o JSON, sem texto adicional, de um filtro sobre o vídeo.
|
| 414 |
+
|
| 415 |
+
Base do JSON: {
|
| 416 |
+
"viralization_probability": 88,
|
| 417 |
+
"sensitive_content": false,
|
| 418 |
+
"political_content": false,
|
| 419 |
+
"should_post": true
|
| 420 |
+
}
|
| 421 |
+
|
| 422 |
+
Estou criando uma página do Instagram e quero saber o que postar ou não postar.
|
| 423 |
+
|
| 424 |
+
viralization_probability
|
| 425 |
+
|
| 426 |
+
Probabilidade estimada (0–100) de o vídeo viralizar. A IA deve estimar isso analisando fatores modernos de performance no Instagram, como força do “hook” nos primeiros segundos, potencial de retenção, probabilidade de compartilhamento, identificação com o público da geração Z (14–30 anos), impacto emocional, alinhamento com tendências e potencial de replay.
|
| 427 |
+
|
| 428 |
+
sensitive_content
|
| 429 |
+
|
| 430 |
+
Valor booleano que indica se o vídeo contém conteúdo perturbador, trágico ou pesado. Isso inclui desastres, acidentes, violência ou tragédias. Como a página tem o lema de que o mundo não precisa ser focado em desastre ou tragédia, esse tipo de conteúdo deve ser marcado como true.
|
| 431 |
+
|
| 432 |
+
political_content
|
| 433 |
+
|
| 434 |
+
Valor booleano que indica se o vídeo menciona, mostra ou faz referência a qualquer político, evento político, discussão política ou símbolo político, independentemente de ser positivo, negativo ou neutro. Caso haja qualquer referência política, o valor deve ser true.
|
| 435 |
+
|
| 436 |
+
should_post
|
| 437 |
+
|
| 438 |
+
Decisão final da IA indicando se o vídeo deve ou não ser postado. Essa decisão deve considerar todos os fatores anteriores, como potencial de viralização, presença de conteúdo sensível, política, marca d’água e outros sinais relevantes."""
|
| 439 |
+
|
| 440 |
+
model_obj = get_gemini_model("flash")
|
| 441 |
+
print(f"🧠 Enviando para Gemini (flash) para filtro de vídeo...")
|
| 442 |
+
|
| 443 |
+
response_gemini = await client.generate_content(prompt, files=[video_path_to_analyze], model=model_obj)
|
| 444 |
+
|
| 445 |
+
filter_data = extract_json_from_text(response_gemini.text)
|
| 446 |
+
if filter_data is None:
|
| 447 |
+
return JSONResponse(content={"raw_content": response_gemini.text, "error": "Failed to parse JSON"}, status_code=200)
|
| 448 |
+
|
| 449 |
+
return filter_data
|
| 450 |
+
except Exception as e:
|
| 451 |
+
raise HTTPException(status_code=500, detail=f"Erro interno: {str(e)}")
|
| 452 |
+
finally:
|
| 453 |
+
if temp_file and os.path.exists(temp_file.name): os.unlink(temp_file.name)
|
| 454 |
+
|
| 455 |
+
|
| 456 |
# ==========================================
|
| 457 |
# GROQ ENDPOINTS / SUBTITLES
|
| 458 |
# ==========================================
|