Update main.py
Browse files
main.py
CHANGED
|
@@ -743,8 +743,8 @@ async def process_account_endpoint(account: str):
|
|
| 743 |
t_start = time.time()
|
| 744 |
record = records[0]
|
| 745 |
record_id = record.get("id")
|
| 746 |
-
print(f"🚀 [0.0s] Inciando processamento da conta '{account}' para Record: {record_id}")
|
| 747 |
video_url = record.get("ig_post_url")
|
|
|
|
| 748 |
context = record.get("ig_caption", "")
|
| 749 |
comments = record.get("comments") # Se existir no banco, pode ser uma lista
|
| 750 |
contains_image = record.get("contains_image", False)
|
|
@@ -777,8 +777,8 @@ async def process_account_endpoint(account: str):
|
|
| 777 |
except Exception as _e:
|
| 778 |
print(f"⚠️ Erro ao enviar notificação de início para o Discord: {_e}")
|
| 779 |
|
| 780 |
-
print(f"📥 Baixando vídeo para processamento: {video_url}")
|
| 781 |
-
response = download_file_with_retry(video_url, timeout=600)
|
| 782 |
content_type = response.headers.get('content-type', '').lower()
|
| 783 |
if 'image' in content_type:
|
| 784 |
if 'png' in content_type: ext = '.png'
|
|
@@ -795,55 +795,78 @@ async def process_account_endpoint(account: str):
|
|
| 795 |
|
| 796 |
video_path_to_analyze = temp_file.name
|
| 797 |
files_to_send = [] # Ordem: [cropped, original]
|
|
|
|
| 798 |
|
| 799 |
-
|
| 800 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 801 |
try:
|
| 802 |
-
|
| 803 |
-
|
| 804 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 805 |
except Exception as e:
|
| 806 |
-
print(f"⚠️
|
| 807 |
else:
|
| 808 |
-
#
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
| 814 |
-
|
| 815 |
-
|
| 816 |
-
|
| 817 |
-
|
| 818 |
-
|
| 819 |
-
|
| 820 |
-
|
| 821 |
-
|
| 822 |
-
|
| 823 |
-
files_to_send.append(cropped_video_path)
|
| 824 |
-
print(f"✅ [{time.perf_counter()-t_start:.1f}s] Vídeo cortado com sucesso.")
|
| 825 |
|
| 826 |
-
|
| 827 |
-
|
| 828 |
-
|
| 829 |
-
|
| 830 |
-
"
|
| 831 |
-
|
| 832 |
-
|
| 833 |
-
|
| 834 |
-
|
| 835 |
-
|
| 836 |
-
|
| 837 |
-
|
| 838 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 839 |
cropped_video_path = None
|
| 840 |
-
print(f"⚠️
|
| 841 |
-
|
| 842 |
-
|
| 843 |
-
|
| 844 |
-
|
| 845 |
-
# Adiciona o vídeo original (sempre em segundo se houver crop)
|
| 846 |
-
files_to_send.append(video_path_to_analyze)
|
| 847 |
contexto_add = f"\n{context}" if context else ""
|
| 848 |
comentarios_add = ""
|
| 849 |
if comments:
|
|
@@ -1418,20 +1441,58 @@ async def run_filter_account(account: str):
|
|
| 1418 |
if chunk: temp_file.write(chunk)
|
| 1419 |
media_path_to_analyze = temp_file.name
|
| 1420 |
cropped_file_path = None
|
|
|
|
| 1421 |
|
| 1422 |
-
# .
|
| 1423 |
-
|
| 1424 |
-
# Se for imagem, faz o crop e prepara dois anexos
|
| 1425 |
if 'image' in content_type:
|
| 1426 |
print(f"✂️ Processando imagem: detectando e cortando...")
|
| 1427 |
try:
|
| 1428 |
-
cropped_file_path = detect_and_crop_image(
|
| 1429 |
except Exception as e:
|
| 1430 |
print(f"⚠️ Erro ao cortar imagem: {e}")
|
| 1431 |
-
|
| 1432 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1433 |
if cropped_file_path and os.path.exists(cropped_file_path):
|
| 1434 |
files_to_send.append(cropped_file_path)
|
|
|
|
| 1435 |
|
| 1436 |
contexto_add = f"\n\nContexto Adicional / Legenda Original:\n{context_text}" if context_text else ""
|
| 1437 |
|
|
@@ -1494,6 +1555,9 @@ async def run_filter_account(account: str):
|
|
| 1494 |
"image_needs_correction": filter_data.get("image_needs_correction", False),
|
| 1495 |
"contains_image": filter_data.get("contains_image", False)
|
| 1496 |
}
|
|
|
|
|
|
|
|
|
|
| 1497 |
res_patch = requests.patch(update_url, headers=headers, json=patch_payload, timeout=10)
|
| 1498 |
if not res_patch.ok:
|
| 1499 |
print(f"⚠️ Erro ao atualizar Supabase: {res_patch.text}")
|
|
|
|
| 743 |
t_start = time.time()
|
| 744 |
record = records[0]
|
| 745 |
record_id = record.get("id")
|
|
|
|
| 746 |
video_url = record.get("ig_post_url")
|
| 747 |
+
crop_url = record.get("crop_content_url")
|
| 748 |
context = record.get("ig_caption", "")
|
| 749 |
comments = record.get("comments") # Se existir no banco, pode ser uma lista
|
| 750 |
contains_image = record.get("contains_image", False)
|
|
|
|
| 777 |
except Exception as _e:
|
| 778 |
print(f"⚠️ Erro ao enviar notificação de início para o Discord: {_e}")
|
| 779 |
|
| 780 |
+
print(f"📥 Baixando vídeo para processamento: {crop_url if crop_url else video_url}")
|
| 781 |
+
response = download_file_with_retry(crop_url if crop_url else video_url, timeout=600)
|
| 782 |
content_type = response.headers.get('content-type', '').lower()
|
| 783 |
if 'image' in content_type:
|
| 784 |
if 'png' in content_type: ext = '.png'
|
|
|
|
| 795 |
|
| 796 |
video_path_to_analyze = temp_file.name
|
| 797 |
files_to_send = [] # Ordem: [cropped, original]
|
| 798 |
+
temp_file_original = None
|
| 799 |
|
| 800 |
+
# 3. Lógica de Crop (Pular se já baixamos a versão cortada)
|
| 801 |
+
if crop_url:
|
| 802 |
+
print(f"✨ [{time.time()-t_start:.1f}s] Usando vídeo já cortado (crop_content_url). Pulando processamento de crop.")
|
| 803 |
+
cropped_video_path = video_path_to_analyze
|
| 804 |
+
files_to_send.append(cropped_video_path)
|
| 805 |
+
|
| 806 |
+
# Adicionar o original como segundo anexo para contexto
|
| 807 |
+
print(f"📥 [{time.time()-t_start:.1f}s] Baixando vídeo original para contexto Gemini...")
|
| 808 |
try:
|
| 809 |
+
orig_resp = download_file_with_retry(video_url, timeout=300)
|
| 810 |
+
orig_temp = tempfile.NamedTemporaryFile(delete=False, suffix=ext)
|
| 811 |
+
for chunk in orig_resp.iter_content(chunk_size=1024*1024):
|
| 812 |
+
if chunk: orig_temp.write(chunk)
|
| 813 |
+
orig_temp.close()
|
| 814 |
+
files_to_send.append(orig_temp.name)
|
| 815 |
+
# Adicionar à lista de limpeza final
|
| 816 |
+
temp_file_original = orig_temp # Guardar para cleanup
|
| 817 |
except Exception as e:
|
| 818 |
+
print(f"⚠️ Não foi possível baixar o vídeo original para contexto: {e}")
|
| 819 |
else:
|
| 820 |
+
# Lógica tradicional de crop
|
| 821 |
+
if 'image' in content_type:
|
| 822 |
+
print(f"✂️ [{time.time()-t_start:.1f}s] Processando imagem: detectando e cortando...")
|
| 823 |
+
try:
|
| 824 |
+
cropped_file_path = detect_and_crop_image(video_path_to_analyze)
|
| 825 |
+
if cropped_file_path and os.path.exists(cropped_file_path):
|
| 826 |
+
files_to_send.append(cropped_file_path)
|
| 827 |
+
except Exception as e:
|
| 828 |
+
print(f"⚠️ Erro ao cortar imagem: {e}")
|
| 829 |
+
else:
|
| 830 |
+
# Vídeo: detectar e cortar bordas estáticas
|
| 831 |
+
print(f"✂️ [{time.time()-t_start:.1f}s] Processando vídeo: detectando e cortando bordas...")
|
| 832 |
+
try:
|
| 833 |
+
cropped_video_path = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4').name
|
| 834 |
+
crop_status = detect_and_crop_video(video_path_to_analyze, cropped_video_path)
|
|
|
|
|
|
|
| 835 |
|
| 836 |
+
if crop_status == "aborted_area_too_small":
|
| 837 |
+
print(f"🚫 [{time.time()-t_start:.1f}s] Crop abortado: área de texto no centro. Negando filtro.")
|
| 838 |
+
requests.patch(f"{supabase_url}/rest/v1/posts?id=eq.{record_id}", headers=headers, json={
|
| 839 |
+
"approved_filter": False,
|
| 840 |
+
"result": {"error": "Rejeitado: Região útil de texto insuficiente para crop seguro (texto centralizado)."}
|
| 841 |
+
})
|
| 842 |
+
return {"status": "rejected", "message": "Postagem rejeitada por crop insuficiente."}
|
| 843 |
+
|
| 844 |
+
if crop_status == "success" and os.path.exists(cropped_video_path):
|
| 845 |
+
files_to_send.append(cropped_video_path)
|
| 846 |
+
print(f"✅ [{time.perf_counter()-t_start:.1f}s] Vídeo cortado com sucesso.")
|
| 847 |
+
|
| 848 |
+
# Upload antecipado para recurve-save (Performance)
|
| 849 |
+
print(f"☁️ [{time.time()-t_start:.1f}s] Enviando vídeo cortado antecipadamente para recurve-save...")
|
| 850 |
+
with open(cropped_video_path, 'rb') as vf:
|
| 851 |
+
vid_upload_resp = requests.post(
|
| 852 |
+
"https://habulaj-recurve-save.hf.space/upload",
|
| 853 |
+
files={'files': ('cropped_video.mp4', vf, 'video/mp4')},
|
| 854 |
+
data={'long_duration': 'yes'},
|
| 855 |
+
timeout=120
|
| 856 |
+
)
|
| 857 |
+
vid_upload_resp.raise_for_status()
|
| 858 |
+
cropped_video_url = vid_upload_resp.json().get("url", "")
|
| 859 |
+
print(f"✅ [{time.time()-t_start:.1f}s] URL do vídeo cortado: {cropped_video_url}")
|
| 860 |
+
else:
|
| 861 |
+
cropped_video_path = None
|
| 862 |
+
print(f"⚠️ [{time.time()-t_start:.1f}s] Crop de vídeo não gerou resultado, seguindo com original apenas")
|
| 863 |
+
except Exception as e:
|
| 864 |
cropped_video_path = None
|
| 865 |
+
print(f"⚠️ Erro ao cortar vídeo: {e}")
|
| 866 |
+
|
| 867 |
+
# Adiciona o vídeo original (sempre em segundo se houver crop)
|
| 868 |
+
files_to_send.append(video_path_to_analyze)
|
| 869 |
+
|
|
|
|
|
|
|
| 870 |
contexto_add = f"\n{context}" if context else ""
|
| 871 |
comentarios_add = ""
|
| 872 |
if comments:
|
|
|
|
| 1441 |
if chunk: temp_file.write(chunk)
|
| 1442 |
media_path_to_analyze = temp_file.name
|
| 1443 |
cropped_file_path = None
|
| 1444 |
+
crop_content_url = None
|
| 1445 |
|
| 1446 |
+
# 3. Crop (Filtro Inteligente)
|
|
|
|
|
|
|
| 1447 |
if 'image' in content_type:
|
| 1448 |
print(f"✂️ Processando imagem: detectando e cortando...")
|
| 1449 |
try:
|
| 1450 |
+
cropped_file_path = detect_and_crop_image(media_path_to_analyze)
|
| 1451 |
except Exception as e:
|
| 1452 |
print(f"⚠️ Erro ao cortar imagem: {e}")
|
| 1453 |
+
else:
|
| 1454 |
+
print(f"✂️ Processando vídeo: detectando e cortando bordas...")
|
| 1455 |
+
try:
|
| 1456 |
+
# Criar arquivo temporário para o vídeo cortado
|
| 1457 |
+
cropped_video_tmp = tempfile.NamedTemporaryFile(delete=False, suffix='.mp4').name
|
| 1458 |
+
crop_status = detect_and_crop_video(media_path_to_analyze, cropped_video_tmp)
|
| 1459 |
+
|
| 1460 |
+
if crop_status == "aborted_area_too_small":
|
| 1461 |
+
print(f"🚫 Crop abortado: área de texto no centro. Reprovando filtro.")
|
| 1462 |
+
requests.patch(f"{supabase_url}/rest/v1/posts?id=eq.{record_id}", headers=headers, json={
|
| 1463 |
+
"approved_filter": False,
|
| 1464 |
+
"filter_message": "Rejeitado automaticamente: Região útil de texto insuficiente para crop seguro (texto centralizado no vídeo).",
|
| 1465 |
+
"contains_image": False
|
| 1466 |
+
})
|
| 1467 |
+
return # Para o processamento aqui
|
| 1468 |
+
|
| 1469 |
+
if crop_status == "success" and os.path.exists(cropped_video_tmp):
|
| 1470 |
+
cropped_file_path = cropped_video_tmp
|
| 1471 |
+
else:
|
| 1472 |
+
if os.path.exists(cropped_video_tmp): os.unlink(cropped_video_tmp)
|
| 1473 |
+
except Exception as e:
|
| 1474 |
+
print(f"⚠️ Erro ao cortar vídeo: {e}")
|
| 1475 |
+
|
| 1476 |
+
# 4. Upload do crop (Se houver) para reuso no Processamento
|
| 1477 |
+
if cropped_file_path and os.path.exists(cropped_file_path):
|
| 1478 |
+
try:
|
| 1479 |
+
print(f"☁️ Enviando mídia cortada para recurve-save (reuso posterior)...")
|
| 1480 |
+
is_vid = 'image' not in content_type
|
| 1481 |
+
with open(cropped_file_path, 'rb') as cf:
|
| 1482 |
+
files = {'files': (f"crop_{'vid' if is_vid else 'img'}{ext}", cf, content_type)}
|
| 1483 |
+
data = {'long_duration': 'yes'} if is_vid else {}
|
| 1484 |
+
up_resp = requests.post("https://habulaj-recurve-save.hf.space/upload", files=files, data=data, timeout=120)
|
| 1485 |
+
up_resp.raise_for_status()
|
| 1486 |
+
crop_content_url = up_resp.json().get("url", "")
|
| 1487 |
+
print(f"✅ Crop content URL: {crop_content_url}")
|
| 1488 |
+
except Exception as up_e:
|
| 1489 |
+
print(f"⚠️ Erro ao subir crop para recurve-save: {up_e}")
|
| 1490 |
+
|
| 1491 |
+
# Ordem de anexos para Gemini: [cortado, original]
|
| 1492 |
+
files_to_send = []
|
| 1493 |
if cropped_file_path and os.path.exists(cropped_file_path):
|
| 1494 |
files_to_send.append(cropped_file_path)
|
| 1495 |
+
files_to_send.append(media_path_to_analyze)
|
| 1496 |
|
| 1497 |
contexto_add = f"\n\nContexto Adicional / Legenda Original:\n{context_text}" if context_text else ""
|
| 1498 |
|
|
|
|
| 1555 |
"image_needs_correction": filter_data.get("image_needs_correction", False),
|
| 1556 |
"contains_image": filter_data.get("contains_image", False)
|
| 1557 |
}
|
| 1558 |
+
if crop_content_url:
|
| 1559 |
+
patch_payload["crop_content_url"] = crop_content_url
|
| 1560 |
+
|
| 1561 |
res_patch = requests.patch(update_url, headers=headers, json=patch_payload, timeout=10)
|
| 1562 |
if not res_patch.ok:
|
| 1563 |
print(f"⚠️ Erro ao atualizar Supabase: {res_patch.text}")
|