habulaj commited on
Commit
fb8320d
·
verified ·
1 Parent(s): 8a218aa

Update main.py

Browse files
Files changed (1) hide show
  1. main.py +464 -5
main.py CHANGED
@@ -210,6 +210,396 @@ async def chat_endpoint(request: ChatRequest):
210
  raise HTTPException(status_code=500, detail=str(e))
211
 
212
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  @app.api_route("/process/{account}", methods=["GET", "POST"])
214
  async def process_account_endpoint(account: str):
215
  if not client:
@@ -475,14 +865,83 @@ async def process_account_endpoint(account: str):
475
 
476
  if srt_raw and srt_raw.strip():
477
  # Tradução via Gemini (mesmo prompt do /subtitle)
478
- translate_prompt = f"""IDIOMA: A legenda traduzida DEVE ser inteiramente em PORTUGUÊS DO BRASIL (pt-BR).
479
 
480
  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.
481
  Você DEVE se basear estritamente na legenda original fornecida. NUNCA crie legendas novas e NUNCA adicione ou verifique diálogos no áudio que não estejam presentes na legenda original. Apenas traduza.
482
- Mande o SRT completo, sem textos adicionais na resposta, apenas o SRT traduzido.
483
- Não deve ser literal a tradução, deve se adaptar ao contexto e entonação. Se alguém estiver gritando, ESCREVA MAIÚSCULO!
484
- NUNCA legende músicas, apenas diálogos falados.
485
- PALAVRÕES: substitua com asteriscos (ex: "merda" → "merd*", "caralho" → "caral**").
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
486
 
487
  LEGENDA ORIGINAL:
488
  {srt_raw}"""
 
210
  raise HTTPException(status_code=500, detail=str(e))
211
 
212
 
213
+ class ProcessUrlRequest(BaseModel):
214
+ url: str
215
+ context: Optional[str] = ""
216
+ version: str # "recurvepop" or "girlsmoodaily"
217
+ raw_url: Optional[bool] = True
218
+
219
+ @app.post("/process-url")
220
+ async def process_url_endpoint(request: ProcessUrlRequest):
221
+ """
222
+ Processa um post do Instagram a partir de uma URL, sem cadastrar no Supabase.
223
+ Chama o agente 'process' da conta especificada em `version`.
224
+ """
225
+ if not client:
226
+ raise HTTPException(status_code=500, detail="Gemini client is not initialized")
227
+
228
+ temp_file = None
229
+ cropped_file_path = None
230
+ cropped_video_path = None
231
+ screenshot_path = None
232
+
233
+ try:
234
+ from agent_config import AGENTS
235
+ account = request.version
236
+ if account not in AGENTS:
237
+ raise HTTPException(status_code=400, detail=f"Conta '{account}' não configurada.")
238
+ agent_conf = AGENTS[account]["process"]
239
+ agent_name = agent_conf["name"]
240
+
241
+ # 1. Chamar a API externa para obter informações do post
242
+ print(f"🔗 Buscando dados do post via API externa: {request.url}")
243
+ api_headers = {
244
+ "accept": "*/*",
245
+ "accept-language": "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7",
246
+ "content-type": "application/json",
247
+ "origin": "http://localhost:5173",
248
+ "referer": "http://localhost:5173/",
249
+ "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36",
250
+ }
251
+ api_payload = {"url": request.url, "videoQuality": "best"}
252
+ api_resp = requests.post(
253
+ "https://proud-paper-3751.fly.dev/api/json",
254
+ headers=api_headers,
255
+ json=api_payload,
256
+ timeout=60,
257
+ )
258
+ if not api_resp.ok:
259
+ raise HTTPException(status_code=502, detail=f"Erro na API externa: {api_resp.text}")
260
+
261
+ api_data = api_resp.json()
262
+ video_url = api_data.get("url")
263
+ context = request.context or api_data.get("caption", "")
264
+ comments = api_data.get("comments", [])
265
+
266
+ if not video_url:
267
+ raise HTTPException(status_code=502, detail="API externa não retornou URL de mídia.")
268
+
269
+ print(f"✅ Mídia obtida: {video_url}")
270
+
271
+ # 2. Baixar mídia
272
+ print(f"📥 Baixando mídia: {video_url}")
273
+ response = download_file_with_retry(video_url, timeout=600)
274
+ content_type = response.headers.get("content-type", "").lower()
275
+ if "image" in content_type:
276
+ if "png" in content_type: ext = ".png"
277
+ elif "webp" in content_type: ext = ".webp"
278
+ else: ext = ".jpg"
279
+ else:
280
+ ext = ".webm" if "webm" in content_type else ".mp4"
281
+
282
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=ext)
283
+ for chunk in response.iter_content(chunk_size=1024 * 1024):
284
+ if chunk:
285
+ temp_file.write(chunk)
286
+ temp_file.close()
287
+
288
+ video_path_to_analyze = temp_file.name
289
+ files_to_send = [video_path_to_analyze]
290
+
291
+ # 3. Crop
292
+ if "image" in content_type:
293
+ print("✂️ Processando imagem: detectando e cortando...")
294
+ try:
295
+ cropped_file_path = detect_and_crop_image(video_path_to_analyze)
296
+ if cropped_file_path and os.path.exists(cropped_file_path):
297
+ files_to_send.append(cropped_file_path)
298
+ except Exception as e:
299
+ print(f"⚠️ Erro ao cortar imagem: {e}")
300
+ else:
301
+ print("✂️ Processando vídeo: detectando e cortando bordas...")
302
+ try:
303
+ cropped_video_path = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4").name
304
+ crop_success = detect_and_crop_video(video_path_to_analyze, cropped_video_path)
305
+ if crop_success and os.path.exists(cropped_video_path):
306
+ files_to_send.append(cropped_video_path)
307
+ print("✅ Vídeo cortado adicionado como segundo anexo")
308
+ else:
309
+ cropped_video_path = None
310
+ except Exception as e:
311
+ cropped_video_path = None
312
+ print(f"⚠️ Erro ao cortar vídeo: {e}")
313
+
314
+ # 4. Montar contextos
315
+ contexto_add = f"\n{context}" if context else ""
316
+ comentarios_add = ""
317
+ if comments:
318
+ comentarios_add = "\nCOMENTÁRIOS DO POST (Use como forte inspiração para criar títulos mais reais e humanizados):\n"
319
+ for c in comments:
320
+ if isinstance(c, dict) and (text := c.get("text", "").strip()):
321
+ comentarios_add += f"- {text} ({c.get('like_count', 0)} curtidas)\n"
322
+
323
+ if "image" in content_type:
324
+ tipo_conteudo_add = "\n\nCONTEXTO DO CONTEÚDO: Este post é uma IMAGEM. O título vai aparecer em cima da imagem."
325
+ else:
326
+ tipo_conteudo_add = ""
327
+
328
+ filter_message_add = ""
329
+
330
+ prompt = agent_conf["get_prompt"](
331
+ date_str=time.strftime("%d/%m/%Y"),
332
+ contexto_add=contexto_add,
333
+ comentarios_add=comentarios_add,
334
+ tipo_conteudo_add=tipo_conteudo_add,
335
+ filter_message_add=filter_message_add,
336
+ )
337
+
338
+ # 5. Gerar com Gemini
339
+ model_obj = get_gemini_model("flash")
340
+ print(f"🧠 Enviando para Gemini (flash) [{agent_name}]...")
341
+ response_gemini = await client.generate_content(prompt, files=files_to_send, model=model_obj)
342
+
343
+ titles_data = extract_json_from_text(response_gemini.text)
344
+ if not titles_data:
345
+ return JSONResponse(
346
+ content={"raw_content": response_gemini.text, "error": "Failed to parse JSON"},
347
+ status_code=200,
348
+ )
349
+
350
+ result_json = titles_data if isinstance(titles_data, list) else [titles_data]
351
+
352
+ # 6. Video export (mesma lógica do /process/{account})
353
+ final_content_url = None
354
+ srt_for_export = None
355
+ if result_json:
356
+ result_data = result_json[0] if isinstance(result_json[0], dict) else {}
357
+ title_text = result_data.get("title", "")
358
+
359
+ if "image" not in content_type and title_text:
360
+ title_text = title_text[0].upper() + title_text[1:] if title_text else title_text
361
+ try:
362
+ video_for_export = (
363
+ cropped_video_path
364
+ if cropped_video_path and os.path.exists(cropped_video_path)
365
+ else temp_file.name
366
+ )
367
+
368
+ screenshot_path = tempfile.NamedTemporaryFile(delete=False, suffix=".jpg").name
369
+ duration_probe = subprocess.run(
370
+ ["ffprobe", "-v", "quiet", "-show_entries", "format=duration", "-of", "csv=p=0", video_for_export],
371
+ capture_output=True, text=True,
372
+ )
373
+ video_duration = (
374
+ float(duration_probe.stdout.strip())
375
+ if duration_probe.returncode == 0 and duration_probe.stdout.strip()
376
+ else 10.0
377
+ )
378
+ middle_time = str(video_duration / 2)
379
+
380
+ ffmpeg_ss = subprocess.run(
381
+ ["ffmpeg", "-y", "-i", video_for_export, "-ss", middle_time, "-frames:v", "1", screenshot_path],
382
+ capture_output=True, text=True,
383
+ )
384
+ if ffmpeg_ss.returncode == 0:
385
+ print("📸 Enviando screenshot para recurve-save...")
386
+ with open(screenshot_path, "rb") as ss_f:
387
+ upload_resp = requests.post(
388
+ "https://habulaj-recurve-save.hf.space/upload",
389
+ files={"files": ("screenshot.jpg", ss_f, "image/jpeg")},
390
+ timeout=60,
391
+ )
392
+ upload_resp.raise_for_status()
393
+ screenshot_url = upload_resp.json().get("url", "")
394
+
395
+ if screenshot_url:
396
+ # Upload vídeo cortado
397
+ cropped_video_url = None
398
+ if video_for_export != temp_file.name:
399
+ print("☁️ Enviando vídeo cortado para recurve-save...")
400
+ with open(video_for_export, "rb") as vf:
401
+ vid_upload_resp = requests.post(
402
+ "https://habulaj-recurve-save.hf.space/upload",
403
+ files={"files": ("cropped_video.mp4", vf, "video/mp4")},
404
+ data={"long_duration": "yes"},
405
+ timeout=120,
406
+ )
407
+ vid_upload_resp.raise_for_status()
408
+ cropped_video_url = vid_upload_resp.json().get("url", "")
409
+
410
+ export_video_url = cropped_video_url if cropped_video_url else video_url
411
+
412
+ import cv2
413
+ cap = cv2.VideoCapture(video_for_export)
414
+ crop_w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) if cap.isOpened() else 1080
415
+ crop_h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) if cap.isOpened() else 1920
416
+ cap.release()
417
+
418
+ canvas_width = 1080
419
+ image_height = 616
420
+ video_dest_height = 1920 - image_height
421
+ video_template = "horizontal" if crop_w > crop_h else "vertical"
422
+
423
+ if video_template == "vertical":
424
+ scaled_h = int(crop_h * canvas_width / crop_w) if crop_w > 0 else crop_h
425
+ video_x, video_y = 0, max(0, (scaled_h - video_dest_height) // 2)
426
+ else:
427
+ video_x, video_y = 0, 0
428
+
429
+ # Legendas
430
+ needs_legenda = result_data.get("legenda", False)
431
+ if needs_legenda:
432
+ print("🎙️ Gerando legendas (Groq + Gemini)...")
433
+ try:
434
+ srt_raw, _, _, _ = await get_groq_srt_base(
435
+ export_video_url, language="en", temperature=0.4, has_bg_music=False
436
+ )
437
+ if srt_raw and srt_raw.strip():
438
+ translate_prompt = f"""IDIOMA: A legenda traduzida DEVE ser inteiramente em PORTUGUÊS DO BRASIL (pt-BR). Independente do idioma original do vídeo.
439
+
440
+ 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.
441
+ Você DEVE se basear estritamente na legenda original fornecida. NUNCA crie legendas novas e NUNCA adicione ou verifique diálogos no áudio que não estejam presentes na legenda original. Apenas traduza.
442
+ 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.
443
+ Mande o SRT completo, sem textos adicionais na resposta, apenas o SRT traduzido. A legenda acima é uma base gerada pelo Whisper que precisa ser limpa e traduzida, não o resultado final.
444
+ 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.
445
+
446
+ MÚSICA E LETRAS:
447
+ - NUNCA LEGENDE MÚSICAS OU CANÇÕES.
448
+ - Se houver música de fundo ou pessoas cantando uma música, IGNORE COMPLETAMENTE e não inclua na legenda.
449
+ - VOCÊ DEVE LEGENDAR APENAS DIÁLOGOS E FALAS REAIS.
450
+
451
+ PALAVRÕES E CENSURA:
452
+ - Você DEVE censurar palavras de baixo calão e palavrões pesados utilizando asteriscos.
453
+ - Substitua a maior parte da palavra censurada e mantenha apenas as primeiras letras.
454
+ - Exemplo: "filha da puta" se torna "filha da pu**", "caralho" se torna "caral**", "merda" se torna "merd*", "foda" se torna "fod*".
455
+
456
+ EXTREMAMENTE IMPORTANTE: NUNCA legende músicas (quando detectar que é uma música, não legende), apenas diálogos falados. Nunca altere o timing das legendas, deve ser exatamente igual ao original de referência. Nunca legende ações também, exemplo: [Música alta], [Música de encerramento], etc. Deve ser apenas, unicamente, diálogo humano.
457
+
458
+ EXEMPLO:
459
+
460
+ (Original): 1
461
+ 00:00:01,000 --> 00:00:04,000
462
+ hey what are you doing here i thought you left already
463
+
464
+ 2
465
+ 00:00:04,500 --> 00:00:07,200
466
+ yeah i was going to but then i realized i forgot my keys
467
+
468
+ 3
469
+ 00:00:07,900 --> 00:00:10,500
470
+ you always forget something man this is crazy
471
+
472
+ 4
473
+ 00:00:11,000 --> 00:00:14,000
474
+ relax it's not a big deal stop acting like that
475
+
476
+ 5
477
+ 00:00:14,500 --> 00:00:17,800
478
+ i am not acting you said you would be on time
479
+
480
+ 6
481
+ 00:00:18,000 --> 00:00:21,500
482
+ okay okay i'm sorry can we just go now
483
+
484
+ 7
485
+ 00:00:22,000 --> 00:00:25,000
486
+ fine but if we are late again you are a son of a bitch
487
+
488
+ (Traduzido, como você deveria traduzir): 1
489
+ 00:00:01,000 --> 00:00:04,000
490
+ Ué, o que você tá fazendo aqui? Não era pra você já ter ido embora?
491
+
492
+ 2
493
+ 00:00:04,500 --> 00:00:07,200
494
+ Eu ia, mas aí percebi que esqueci minhas chaves.
495
+
496
+ 3
497
+ 00:00:07,900 --> 00:00:10,500
498
+ Cara, você SEMPRE esquece alguma coisa, isso é surreal!
499
+
500
+ 4
501
+ 00:00:11,000 --> 00:00:14,000
502
+ Ah, relaxa! Não é o fim do mundo, para de drama.
503
+
504
+ 5
505
+ 00:00:14,500 --> 00:00:17,800
506
+ Não é drama! Você falou que ia chegar no horário!
507
+
508
+ 6
509
+ 00:00:18,000 --> 00:00:21,500
510
+ Tá, tá... foi mal. Bora logo?
511
+
512
+ 7
513
+ 00:00:22,000 --> 00:00:25,000
514
+ Tá bom, mas se a gente se atrasar de novo, você é um filha da pu**!
515
+
516
+ LEGENDA ORIGINAL:
517
+ {srt_raw}"""
518
+ translate_model = get_gemini_model("flash")
519
+ translate_resp = await client.generate_content(translate_prompt, model=translate_model)
520
+ translated_srt = translate_resp.text.strip()
521
+ if "```" in translated_srt:
522
+ parts = translated_srt.split("```")
523
+ for part in parts:
524
+ clean = part.strip()
525
+ if clean.startswith("srt"): clean = clean[3:].strip()
526
+ if re.match(r"\d+\s*\n\d{2}:", clean):
527
+ translated_srt = clean
528
+ break
529
+ if translated_srt:
530
+ srt_for_export = translated_srt
531
+ except Exception as sub_e:
532
+ print(f"⚠️ Erro ao gerar legendas: {sub_e}")
533
+
534
+ import urllib.parse
535
+ title_params = urllib.parse.urlencode({"text": title_text, "version": account})
536
+ title_url = f"https://habulaj-recurve-api-img.hf.space/cover/title?{title_params}&image_url={screenshot_url}"
537
+ result_json[0]["title_url"] = title_url
538
+
539
+ export_payload = {
540
+ "video_url": export_video_url,
541
+ "title_url": title_url,
542
+ "image_height": image_height,
543
+ "cut_start": 0,
544
+ "cut_end": video_duration,
545
+ "video_x": video_x,
546
+ "video_y": video_y,
547
+ "video_width": crop_w,
548
+ "video_height": crop_h,
549
+ "video_template": video_template,
550
+ }
551
+ if srt_for_export:
552
+ export_payload["subtitles"] = srt_for_export
553
+
554
+ print("🎬 Chamando video export API...")
555
+ export_resp = requests.post(
556
+ "https://habulaj-recurve-videos-export.hf.space/video/export",
557
+ json=export_payload,
558
+ timeout=600,
559
+ )
560
+ if not export_resp.ok:
561
+ raise Exception(f"API de video export falhou: {export_resp.status_code}: {export_resp.text}")
562
+ export_data = export_resp.json()
563
+ final_content_url = export_data.get("video_url")
564
+ print(f"✅ Vídeo exportado: {final_content_url}")
565
+ except Exception as ve:
566
+ print(f"⚠️ Erro no video export: {ve}")
567
+ raise Exception(f"Falha no video export: {ve}")
568
+
569
+ elif "image" in content_type and title_text and result_data.get("result_type") == "meme":
570
+ try:
571
+ img_for_meme = (
572
+ cropped_file_path
573
+ if cropped_file_path and os.path.exists(cropped_file_path)
574
+ else temp_file.name
575
+ )
576
+ import urllib.parse
577
+ meme_params = urllib.parse.urlencode({"text": title_text})
578
+ final_content_url = f"https://habulaj-recurve-api-img.hf.space/meme?{meme_params}"
579
+ result_json[0]["title_url"] = final_content_url
580
+ except Exception as e:
581
+ print(f"⚠️ Erro ao gerar URL do meme: {e}")
582
+
583
+ if result_json and srt_for_export and isinstance(result_json[0], dict):
584
+ result_json[0]["subtitle_srt"] = srt_for_export
585
+
586
+ if final_content_url and isinstance(result_json[0], dict):
587
+ result_json[0]["final_content_url"] = final_content_url
588
+
589
+ return result_json
590
+
591
+ except HTTPException:
592
+ raise
593
+ except Exception as e:
594
+ print(f"⚠️ Erro em /process-url: {e}")
595
+ raise HTTPException(status_code=500, detail=str(e))
596
+ finally:
597
+ if temp_file and os.path.exists(temp_file.name): os.unlink(temp_file.name)
598
+ if cropped_file_path and os.path.exists(cropped_file_path): os.unlink(cropped_file_path)
599
+ if cropped_video_path and os.path.exists(cropped_video_path): os.unlink(cropped_video_path)
600
+ if screenshot_path and os.path.exists(screenshot_path): os.unlink(screenshot_path)
601
+
602
+
603
  @app.api_route("/process/{account}", methods=["GET", "POST"])
604
  async def process_account_endpoint(account: str):
605
  if not client:
 
865
 
866
  if srt_raw and srt_raw.strip():
867
  # Tradução via Gemini (mesmo prompt do /subtitle)
868
+ translate_prompt = f"""IDIOMA: A legenda traduzida DEVE ser inteiramente em PORTUGUÊS DO BRASIL (pt-BR). Independente do idioma original do vídeo.
869
 
870
  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.
871
  Você DEVE se basear estritamente na legenda original fornecida. NUNCA crie legendas novas e NUNCA adicione ou verifique diálogos no áudio que não estejam presentes na legenda original. Apenas traduza.
872
+ 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.
873
+ Mande o SRT completo, sem textos adicionais na resposta, apenas o SRT traduzido. A legenda acima é uma base gerada pelo Whisper que precisa ser limpa e traduzida, não o resultado final.
874
+ 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.
875
+
876
+ MÚSICA E LETRAS:
877
+ - NUNCA LEGENDE MÚSICAS OU CANÇÕES.
878
+ - Se houver música de fundo ou pessoas cantando uma música, IGNORE COMPLETAMENTE e não inclua na legenda.
879
+ - VOCÊ DEVE LEGENDAR APENAS DIÁLOGOS E FALAS REAIS.
880
+
881
+ PALAVRÕES E CENSURA:
882
+ - Você DEVE censurar palavras de baixo calão e palavrões pesados utilizando asteriscos.
883
+ - Substitua a maior parte da palavra censurada e mantenha apenas as primeiras letras.
884
+ - Exemplo: "filha da puta" se torna "filha da pu**", "caralho" se torna "caral**", "merda" se torna "merd*", "foda" se torna "fod*".
885
+
886
+ EXTREMAMENTE IMPORTANTE: NUNCA legende músicas (quando detectar que é uma música, não legende), apenas diálogos falados. Nunca altere o timing das legendas, deve ser exatamente igual ao original de referência. Nunca legende ações também, exemplo: [Música alta], [Música de encerramento], etc. Deve ser apenas, unicamente, diálogo humano.
887
+
888
+ EXEMPLO:
889
+
890
+ (Original): 1
891
+ 00:00:01,000 --> 00:00:04,000
892
+ hey what are you doing here i thought you left already
893
+
894
+ 2
895
+ 00:00:04,500 --> 00:00:07,200
896
+ yeah i was going to but then i realized i forgot my keys
897
+
898
+ 3
899
+ 00:00:07,900 --> 00:00:10,500
900
+ you always forget something man this is crazy
901
+
902
+ 4
903
+ 00:00:11,000 --> 00:00:14,000
904
+ relax it's not a big deal stop acting like that
905
+
906
+ 5
907
+ 00:00:14,500 --> 00:00:17,800
908
+ i am not acting you said you would be on time
909
+
910
+ 6
911
+ 00:00:18,000 --> 00:00:21,500
912
+ okay okay i'm sorry can we just go now
913
+
914
+ 7
915
+ 00:00:22,000 --> 00:00:25,000
916
+ fine but if we are late again you are a son of a bitch
917
+
918
+ (Traduzido, como você deveria traduzir): 1
919
+ 00:00:01,000 --> 00:00:04,000
920
+ Ué, o que você tá fazendo aqui? Não era pra você já ter ido embora?
921
+
922
+ 2
923
+ 00:00:04,500 --> 00:00:07,200
924
+ Eu ia, mas aí percebi que esqueci minhas chaves.
925
+
926
+ 3
927
+ 00:00:07,900 --> 00:00:10,500
928
+ Cara, você SEMPRE esquece alguma coisa, isso é surreal!
929
+
930
+ 4
931
+ 00:00:11,000 --> 00:00:14,000
932
+ Ah, relaxa! Não é o fim do mundo, para de drama.
933
+
934
+ 5
935
+ 00:00:14,500 --> 00:00:17,800
936
+ Não é drama! Você falou que ia chegar no horário!
937
+
938
+ 6
939
+ 00:00:18,000 --> 00:00:21,500
940
+ Tá, tá... foi mal. Bora logo?
941
+
942
+ 7
943
+ 00:00:22,000 --> 00:00:25,000
944
+ Tá bom, mas se a gente se atrasar de novo, você é um filha da pu**!
945
 
946
  LEGENDA ORIGINAL:
947
  {srt_raw}"""