habulaj commited on
Commit
3ad4cfe
·
verified ·
1 Parent(s): d0cd421

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +255 -0
main.py CHANGED
@@ -739,6 +739,11 @@ LEGENDA ORIGINAL:
739
  except Exception as e:
740
  print(f"⚠️ Erro ao gerar URL do meme: {e}")
741
 
 
 
 
 
 
742
  # Atualizar no Supabase
743
  update_url = f"{supabase_url}/rest/v1/posts?id=eq.{record_id}"
744
  patch_payload = {
@@ -1033,6 +1038,256 @@ Reprovando (exemplo 2):
1033
  os.unlink(cropped_file_path)
1034
 
1035
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1036
  # ==========================================
1037
  # GROQ ENDPOINTS / SUBTITLES
1038
  # ==========================================
 
739
  except Exception as e:
740
  print(f"⚠️ Erro ao gerar URL do meme: {e}")
741
 
742
+ # Add generated subtitles to the result JSON for Supabase
743
+ if result_json and srt_for_export:
744
+ if isinstance(result_json[0], dict):
745
+ result_json[0]["subtitle_srt"] = srt_for_export
746
+
747
  # Atualizar no Supabase
748
  update_url = f"{supabase_url}/rest/v1/posts?id=eq.{record_id}"
749
  patch_payload = {
 
1038
  os.unlink(cropped_file_path)
1039
 
1040
 
1041
+ @app.api_route("/publish-girlsmoodaily", methods=["GET", "POST"])
1042
+ async def publish_girlsmoodaily_endpoint():
1043
+ if not client:
1044
+ raise HTTPException(status_code=500, detail="Gemini client is not initialized")
1045
+ temp_file = None
1046
+ try:
1047
+ supabase_url = os.getenv("SUPABASE_URL", "").rstrip("/")
1048
+ supabase_key = os.getenv("SUPABASE_KEY", "")
1049
+ if not supabase_url or not supabase_key:
1050
+ raise HTTPException(status_code=500, detail="Credenciais do Supabase não configuradas no ambiente.")
1051
+
1052
+ headers = {
1053
+ "apikey": supabase_key,
1054
+ "Authorization": f"Bearer {supabase_key}",
1055
+ "Content-Type": "application/json"
1056
+ }
1057
+
1058
+ # Buscar 1 post pronto para publicação: tem result, tem final_content_url, published=false, superior_needs_verification IS NULL
1059
+ select_url = f"{supabase_url}/rest/v1/posts?select=*&result=not.is.null&final_content_url=not.is.null&published=eq.false&superior_needs_verification=is.null&limit=1"
1060
+ res_get = requests.get(select_url, headers=headers, timeout=10)
1061
+ if not res_get.ok:
1062
+ raise HTTPException(status_code=500, detail=f"Erro ao ler posts: {res_get.text}")
1063
+
1064
+ records = res_get.json()
1065
+ if not records:
1066
+ return {"status": "ok", "message": "Nenhuma postagem pendente para publicação."}
1067
+
1068
+ record = records[0]
1069
+ record_id = record.get("id")
1070
+ final_content_url = record.get("final_content_url", "")
1071
+ result_data = record.get("result", [])
1072
+
1073
+ if not final_content_url:
1074
+ raise HTTPException(status_code=400, detail=f"Registro ID {record_id} falhou: final_content_url inválida.")
1075
+
1076
+ discord_id = 3
1077
+ agent_name = "Amanda"
1078
+
1079
+ # Notificação de início no Discord
1080
+ try:
1081
+ import urllib.parse
1082
+ sys_msg = f"📦 **{agent_name}** começou a revisar uma postagem para publicação...\n\n📎 **Conteúdo:** {final_content_url}"
1083
+ sys_target_url = "https://discordmsg.arthurmribeiro51.workers.dev/?" + urllib.parse.urlencode({
1084
+ "mensagem": sys_msg,
1085
+ "id": 0
1086
+ })
1087
+ requests.get(
1088
+ "https://proxy.onrecurve.com/",
1089
+ params={"quest": sys_target_url},
1090
+ timeout=5
1091
+ )
1092
+ except Exception as e:
1093
+ print(f"⚠️ Erro ao enviar mensagem de sistema para o Discord: {e}")
1094
+
1095
+ # Baixar o conteúdo final para enviar ao Gemini
1096
+ print(f"📥 Baixando conteúdo final para revisão: {final_content_url}")
1097
+ response = download_file_with_retry(final_content_url, timeout=600)
1098
+
1099
+ content_type = response.headers.get('content-type', '').lower()
1100
+ if 'image' in content_type:
1101
+ if 'png' in content_type: ext = '.png'
1102
+ elif 'webp' in content_type: ext = '.webp'
1103
+ else: ext = '.jpg'
1104
+ else:
1105
+ ext = '.webm' if 'webm' in content_type else '.mp4'
1106
+
1107
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=ext)
1108
+ for chunk in response.iter_content(chunk_size=1024*1024):
1109
+ if chunk: temp_file.write(chunk)
1110
+ temp_file.close()
1111
+
1112
+ # Montar contexto do que a Vicky produziu
1113
+ vicky_result = ""
1114
+ if result_data and isinstance(result_data, list) and len(result_data) > 0:
1115
+ r0 = result_data[0] if isinstance(result_data[0], dict) else {}
1116
+ vicky_result = f"""
1117
+ RESULTADO DA VICKY (o que foi produzido):
1118
+ - Título: {r0.get('title', 'N/A')}
1119
+ - Descrição: {r0.get('description', 'N/A')}
1120
+ - Legenda (subtítulos): {r0.get('legenda', False)}
1121
+ - Tipo: {r0.get('result_type', 'N/A')}
1122
+ """
1123
+
1124
+ is_video = 'image' not in content_type
1125
+
1126
+ prompt = f"""Você é AMANDA, a Gestora de Distribuição da @girlsmoodaily no Instagram.
1127
+
1128
+ QUEM VOCÊ É
1129
+
1130
+ Você é a Amanda, organizada, detalhista e com olho clínico para qualidade. Você é a última pessoa que vê o conteúdo antes de ele ir ao ar. Nada sai sem a sua aprovação. Você fala de forma profissional mas acessível, como uma gerente de redes sociais que leva o trabalho muito a sério mas não é robótica. Você se comunica exclusivamente em português brasileiro.
1131
+
1132
+ Sua personalidade: responsável, metódica e confiante. Você não deixa passar nada. Se algo está errado, você percebe. Se está tudo certo, você aprova com segurança. Você é firme mas não arrogante, e sempre explica suas decisões com clareza.
1133
+
1134
+
1135
+ SUA MISSÃO
1136
+
1137
+ Você é o último filtro antes da publicação. Você recebe o conteúdo FINAL (já editado, com título aplicado, exportado e pronto) e verifica se ele está apto para ser publicado na @girlsmoodaily.
1138
+
1139
+ Sua verificação é sobre o PRODUTO FINAL, não sobre o conteúdo bruto original. A Diana já filtrou o conteúdo e a Vicky já criou o post. Você está olhando para o resultado final que vai pro feed/reels.
1140
+
1141
+ {vicky_result}
1142
+
1143
+ O QUE VOCÊ DEVE VERIFICAR
1144
+
1145
+ 1. QUALIDADE VISUAL GERAL
1146
+ - O conteúdo final está visualmente limpo e profissional?
1147
+ - A resolução e qualidade são aceitáveis para publicação?
1148
+ - Se for vídeo: a imagem do título está bem posicionada? O vídeo está cortado corretamente?
1149
+ - Se for meme/imagem: o texto está legível? A composição visual está harmoniosa?
1150
+
1151
+ 2. MARCAS D'ÁGUA E TEXTOS INDESEJADOS
1152
+ - Há marcas d'água visíveis de outras plataformas (TikTok, Instagram de terceiros, etc.)?
1153
+ - Há textos em idiomas estrangeiros que não deveriam estar ali (exceto se forem parte natural do conteúdo, como um meme em inglês que foi traduzido no título)?
1154
+ - Há logos ou arrobas de outras páginas visíveis no conteúdo final?
1155
+
1156
+ 3. TÍTULO E TEXTO DA @GIRLSMOODAILY
1157
+ - O título aplicado pela Vicky está visível e legível?
1158
+ - O título faz sentido com o conteúdo visual?
1159
+ - Se for meme: o texto central está correto e bem formatado?
1160
+ - IMPORTANTE: Se houver texto no conteúdo que NÃO seja o título/texto central da @girlsmoodaily (como texto residual do post original que não foi removido), isso é um problema que merece atenção.
1161
+
1162
+ 4. LEGENDAS (SUBTÍTULOS) - SOMENTE PARA VÍDEOS
1163
+ - Se o vídeo tem legendas incorporadas, elas estão em português?
1164
+ - As legendas são legíveis e bem posicionadas?
1165
+ - Se o vídeo deveria ter legendas mas não tem, isso é um problema.
1166
+
1167
+ 5. ALINHAMENTO COM A IDENTIDADE DA PÁGINA
1168
+ - O produto final parece algo que a @girlsmoodaily publicaria?
1169
+ - A estética geral está alinhada com a vibe feminina, leve e alto-astral da página?
1170
+
1171
+ REGRAS DE DECISÃO
1172
+
1173
+ PUBLICAR (published: true, superior_needs_verification: false):
1174
+ - Tudo está perfeito. Conteúdo limpo, título legível, sem marcas d'água, qualidade boa, alinhado com a página. Pode ir ao ar.
1175
+
1176
+ PRECISA DE VERIFICAÇÃO SUPERIOR (published: false, superior_needs_verification: true):
1177
+ - O conteúdo provavelmente está ok, mas você tem alguma dúvida ou incerteza. Exemplos:
1178
+ - Há um texto residual no conteúdo que pode ou não ser problemático
1179
+ - A imagem do título parece levemente desalinhada ou cortada de forma estranha
1180
+ - Você não tem certeza se uma marca d'água sutil é realmente uma marca d'água
1181
+ - O conteúdo é bom mas algo te deixa com uma pulga atrás da orelha
1182
+ - Use isso quando você ACHA que deveria publicar mas não tem 100% de certeza
1183
+
1184
+ REJEITAR (published: false, superior_needs_verification: false):
1185
+ - O conteúdo tem problemas claros e óbvios que impedem a publicação. Exemplos:
1186
+ - Marca d'água enorme e visível
1187
+ - Texto completamente ilegível
1188
+ - Conteúdo claramente quebrado ou corrompido
1189
+ - Qualidade visual inaceitável
1190
+ - Problema grave que não tem como ser ignorado
1191
+
1192
+ FORMATO DE SAÍDA
1193
+
1194
+ Você deve retornar APENAS um objeto JSON puro, sem markdown, sem blocos de código, sem nenhum texto antes ou depois.
1195
+
1196
+ {{
1197
+ "publish_message": "<sua mensagem aqui>",
1198
+ "published": true ou false,
1199
+ "superior_needs_verification": true ou false
1200
+ }}
1201
+
1202
+ Regras para publish_message: escrita em português brasileiro, casual mas profissional, sem formatações, sem negrito, sem travessão, sem listas. Deve soar como uma gestora de redes sociais real falando. Explique sua decisão de forma clara e direta. Varie sempre a abertura. Nunca comece com "gente" ou "pessoal". Entre 2 e 4 frases.
1203
+
1204
+ EXEMPLOS DE TOM
1205
+
1206
+ Publicando:
1207
+ "Revisei o conteúdo final e tá tudo impecável. Título legível, sem marcas d'água, qualidade visual ótima e totalmente alinhado com a vibe da página. Pode ir ao ar sem nenhuma preocupação. ✅"
1208
+
1209
+ Pedindo verificação:
1210
+ "O conteúdo tá bom no geral, mas percebi um texto pequeno no canto inferior do vídeo que pode ser uma marca d'água ou pode ser parte do conteúdo original. Não consigo ter certeza, então prefiro que alguém dê uma segunda olhada antes de publicar. 🔍"
1211
+
1212
+ Rejeitando:
1213
+ "Infelizmente não posso aprovar essa aqui. Tem uma marca d'água do TikTok bem visível no meio do vídeo que compromete completamente a qualidade do post. Precisa ser reprocessado antes de publicar. ❌"
1214
+ """
1215
+
1216
+ model_obj = get_gemini_model("flash")
1217
+ print(f"🧠 Enviando para Gemini (flash) para revisão de publicação...")
1218
+
1219
+ response_gemini = await client.generate_content(prompt, files=[temp_file.name], model=model_obj)
1220
+
1221
+ publish_data = extract_json_from_text(response_gemini.text)
1222
+ if publish_data is None:
1223
+ return JSONResponse(content={"raw_content": response_gemini.text, "error": "Failed to parse JSON"}, status_code=200)
1224
+
1225
+ # Enviar mensagens no Discord
1226
+ try:
1227
+ import urllib.parse
1228
+ # 1) Mensagem da Amanda para o canal dela (ID 3)
1229
+ target_url = "https://discordmsg.arthurmribeiro51.workers.dev/?" + urllib.parse.urlencode({
1230
+ "mensagem": publish_data.get("publish_message", ""),
1231
+ "id": discord_id
1232
+ })
1233
+ requests.get(
1234
+ "https://proxy.onrecurve.com/",
1235
+ params={"quest": target_url},
1236
+ timeout=5
1237
+ )
1238
+
1239
+ # 2) Aviso final pro Painel de Sistema (ID 0)
1240
+ is_published = publish_data.get("published", False)
1241
+ needs_verification = publish_data.get("superior_needs_verification", False)
1242
+
1243
+ if is_published:
1244
+ status_emoji = "✅"
1245
+ status_text = "APROVOU a publicação"
1246
+ elif needs_verification:
1247
+ status_emoji = "🔍"
1248
+ status_text = "SOLICITOU verificação de um superior"
1249
+ else:
1250
+ status_emoji = "❌"
1251
+ status_text = "REJEITOU a publicação"
1252
+
1253
+ sys_end_msg = f"{status_emoji} **{agent_name}** {status_text} da postagem #{record_id}."
1254
+ if final_content_url:
1255
+ sys_end_msg += f"\n\n📎 {final_content_url}"
1256
+
1257
+ sys_end_url = "https://discordmsg.arthurmribeiro51.workers.dev/?" + urllib.parse.urlencode({
1258
+ "mensagem": sys_end_msg,
1259
+ "id": 0
1260
+ })
1261
+ requests.get(
1262
+ "https://proxy.onrecurve.com/",
1263
+ params={"quest": sys_end_url},
1264
+ timeout=5
1265
+ )
1266
+ except Exception as e:
1267
+ print(f"⚠️ Erro ao enviar log para o Discord: {e}")
1268
+
1269
+ # Atualizar no Supabase
1270
+ update_url = f"{supabase_url}/rest/v1/posts?id=eq.{record_id}"
1271
+ patch_payload = {
1272
+ "publish_message": publish_data.get("publish_message"),
1273
+ "published": publish_data.get("published", False),
1274
+ "superior_needs_verification": publish_data.get("superior_needs_verification", False)
1275
+ }
1276
+ res_patch = requests.patch(update_url, headers=headers, json=patch_payload, timeout=10)
1277
+ if not res_patch.ok:
1278
+ print(f"⚠️ Erro ao atualizar Supabase: {res_patch.text}")
1279
+
1280
+ return {
1281
+ "success": True,
1282
+ "record_id": record_id,
1283
+ "publish_data": publish_data
1284
+ }
1285
+ except Exception as e:
1286
+ raise HTTPException(status_code=500, detail=f"Erro interno: {str(e)}")
1287
+ finally:
1288
+ if temp_file and os.path.exists(temp_file.name): os.unlink(temp_file.name)
1289
+
1290
+
1291
  # ==========================================
1292
  # GROQ ENDPOINTS / SUBTITLES
1293
  # ==========================================