habulaj commited on
Commit
14e2605
·
verified ·
1 Parent(s): a2f635a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +174 -82
app.py CHANGED
@@ -7,6 +7,9 @@ from pathlib import Path
7
  import re
8
  import requests
9
  import time
 
 
 
10
 
11
  from gemini_client import AsyncChatbot, Model, load_cookies
12
 
@@ -559,6 +562,127 @@ TRADUZA TUDO DE IMPORTANTE NO {media_desc_final}, que tenha dialogo... Nunca dei
559
  pass
560
 
561
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
562
  @app.get("/upscale")
563
  async def upscale_image(
564
  file: str
@@ -566,11 +690,15 @@ async def upscale_image(
566
  """
567
  Endpoint para fazer upscale 4x de uma imagem usando o Nano Banana Pro.
568
 
 
 
 
 
569
  Parâmetros:
570
  - file: URL da imagem
571
 
572
  Retorna:
573
- - JSON com a URL da imagem gerada (upscaled)
574
  """
575
  if upscale_chatbot is None:
576
  raise HTTPException(status_code=500, detail="Upscale Chatbot não inicializado")
@@ -579,6 +707,8 @@ async def upscale_image(
579
  raise HTTPException(status_code=400, detail="Parâmetro 'file' é obrigatório")
580
 
581
  temp_file = None
 
 
582
  try:
583
  # Baixar arquivo da URL com retry
584
  response = download_file_with_retry(file, max_retries=3, timeout=300)
@@ -603,46 +733,7 @@ async def upscale_image(
603
 
604
  prompt = "Upscale this image by 4x. Keep everything exactly as it is, including text, colors, texture, aspect ratio, zoom and proportions. Just increase the quality and sharpness. Do not add any new elements or modify the composition"
605
 
606
- # Enviar para o Gemini (Nano Banana)
607
- print(f"🧠 Enviando imagem para upscale...")
608
- result = await upscale_chatbot.ask(prompt, image=temp_file.name)
609
-
610
- if result.get("error"):
611
- raise HTTPException(
612
- status_code=500,
613
- detail=f"Erro ao gerar upscale: {result.get('content', 'Erro desconhecido')}"
614
- )
615
-
616
- # Tentar extrair imagem gerada (geralmente formato 2 no core.py)
617
- upscaled_url = None
618
-
619
- # Debug do resultado
620
- # print("Resultado completo:", result)
621
-
622
- if result.get("images"):
623
- # Preferir imagens geradas
624
- for img in result["images"]:
625
- if "[Generated Image" in img.get("title", ""):
626
- upscaled_url = img["url"]
627
- break
628
-
629
- # Se não achou 'Generated Image', pega a última (comportamento padrão)
630
- if not upscaled_url and len(result["images"]) > 0:
631
- upscaled_url = result["images"][-1]["url"]
632
-
633
- if not upscaled_url:
634
- raise HTTPException(
635
- status_code=500,
636
- detail="Nenhuma imagem de upscale foi retornada pelo modelo."
637
- )
638
- # Primeiro, acessar a URL original para obter o redirect
639
- # A URL gg-dl redireciona para rd-gg-dl
640
- print(f"📥 Resolvendo redirect da URL...")
641
-
642
- import base64
643
-
644
- # Carregar cookies do arquivo para usar nas requisições autenticadas
645
- # Usa load_cookies que suporta JSON e Netscape
646
  cookies_dict = {}
647
  cookie_path = os.getenv("COOKIE_PATH", "cookies.json")
648
  try:
@@ -654,62 +745,58 @@ async def upscale_image(
654
  except Exception as cookie_err:
655
  print(f"⚠️ Aviso: Não foi possível carregar cookies: {cookie_err}")
656
 
657
- try:
658
- # Primeira requisição: seguir redirect para obter URL final COM cookies
659
- redirect_response = requests.get(upscaled_url, timeout=60, allow_redirects=True,
660
- cookies=cookies_dict,
661
- headers={
662
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
663
- 'Referer': 'https://gemini.google.com/',
664
- 'Accept': 'image/*,*/*'
665
- }
666
- )
667
-
668
- # A URL final após redirect
669
- final_url = redirect_response.url
670
- print(f"📍 URL após redirect: {final_url[:80]}...")
671
-
672
- # Remover parâmetros existentes e adicionar =s0-d-I para full resolution
673
- if "?" in final_url:
674
- final_url = final_url.split("?")[0]
675
- # Remover qualquer =sXXX existente
676
- if "=s" in final_url:
677
- final_url = final_url.rsplit("=s", 1)[0]
678
-
679
- download_url = final_url + "=s0-d-I"
680
- print(f"📥 Baixando imagem full res de: {download_url[:80]}...")
681
 
682
- # Segunda requisição: baixar a imagem em full resolution COM cookies
683
- img_response = requests.get(download_url, timeout=60,
684
- cookies=cookies_dict,
685
- headers={
686
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
687
- 'Referer': 'https://gemini.google.com/',
688
- 'Accept': 'image/*,*/*'
689
- }
690
- )
691
- img_response.raise_for_status()
692
 
693
- # Converter para base64
694
- img_base64 = base64.b64encode(img_response.content).decode('utf-8')
695
- content_type = img_response.headers.get('content-type', 'image/png')
696
 
697
- print(f"✅ Imagem baixada e convertida para base64 ({len(img_base64)} chars)")
 
 
 
 
698
 
 
 
 
 
 
 
699
  except Exception as download_error:
700
  print(f"❌ Erro ao baixar imagem: {download_error}")
701
  raise HTTPException(
702
  status_code=500,
703
  detail=f"Erro ao baixar imagem upscaled: {str(download_error)}"
704
  )
 
 
 
 
 
 
705
 
706
  return JSONResponse(
707
  content={
708
  "image_base64": img_base64,
709
- "content_type": content_type,
710
  "success": True,
711
  "original_url": file,
712
- "upscaled_url": download_url
 
713
  }
714
  )
715
 
@@ -720,9 +807,14 @@ async def upscale_image(
720
  traceback.print_exc()
721
  raise HTTPException(status_code=500, detail=f"Erro interno no upscale: {str(e)}")
722
  finally:
723
- # Limpar arquivo temporário
724
  if temp_file and os.path.exists(temp_file.name):
725
  try:
726
  os.unlink(temp_file.name)
 
 
 
 
 
727
  except:
728
  pass
 
7
  import re
8
  import requests
9
  import time
10
+ import base64
11
+ import io
12
+ from PIL import Image
13
 
14
  from gemini_client import AsyncChatbot, Model, load_cookies
15
 
 
562
  pass
563
 
564
 
565
+ def flip_image_both_axes(image_path: str) -> str:
566
+ """
567
+ Inverte uma imagem horizontalmente e verticalmente.
568
+ Retorna o caminho para um novo arquivo temporário com a imagem invertida.
569
+ """
570
+ with Image.open(image_path) as img:
571
+ # Inverter horizontalmente e verticalmente
572
+ flipped = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.FLIP_TOP_BOTTOM)
573
+
574
+ # Salvar em arquivo temporário
575
+ temp_flipped = tempfile.NamedTemporaryFile(delete=False, suffix=Path(image_path).suffix)
576
+ flipped.save(temp_flipped.name)
577
+ temp_flipped.close()
578
+
579
+ return temp_flipped.name
580
+
581
+
582
+ def flip_base64_image_both_axes(img_base64: str, content_type: str) -> str:
583
+ """
584
+ Inverte uma imagem base64 horizontalmente e verticalmente.
585
+ Retorna o base64 da imagem invertida.
586
+ """
587
+ # Decodificar base64 para bytes
588
+ img_bytes = base64.b64decode(img_base64)
589
+
590
+ # Abrir imagem dos bytes
591
+ with Image.open(io.BytesIO(img_bytes)) as img:
592
+ # Inverter horizontalmente e verticalmente
593
+ flipped = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.FLIP_TOP_BOTTOM)
594
+
595
+ # Salvar em buffer
596
+ buffer = io.BytesIO()
597
+ # Determinar formato baseado no content_type
598
+ img_format = 'PNG'
599
+ if 'jpeg' in content_type or 'jpg' in content_type:
600
+ img_format = 'JPEG'
601
+ elif 'webp' in content_type:
602
+ img_format = 'WEBP'
603
+
604
+ flipped.save(buffer, format=img_format)
605
+ buffer.seek(0)
606
+
607
+ # Converter de volta para base64
608
+ return base64.b64encode(buffer.read()).decode('utf-8')
609
+
610
+
611
+ async def _try_upscale(chatbot, image_path: str, prompt: str):
612
+ """
613
+ Tenta fazer upscale de uma imagem.
614
+ Retorna (result, upscaled_url) ou (None, None) em caso de erro.
615
+ """
616
+ result = await chatbot.ask(prompt, image=image_path)
617
+
618
+ if result.get("error"):
619
+ return None, None
620
+
621
+ upscaled_url = None
622
+ if result.get("images"):
623
+ # Preferir imagens geradas
624
+ for img in result["images"]:
625
+ if "[Generated Image" in img.get("title", ""):
626
+ upscaled_url = img["url"]
627
+ break
628
+
629
+ # Se não achou 'Generated Image', pega a última
630
+ if not upscaled_url and len(result["images"]) > 0:
631
+ upscaled_url = result["images"][-1]["url"]
632
+
633
+ return result, upscaled_url
634
+
635
+
636
+ async def _download_upscaled_image(upscaled_url: str, cookies_dict: dict) -> tuple:
637
+ """
638
+ Baixa a imagem upscaled e retorna (img_base64, content_type, download_url).
639
+ """
640
+ print(f"📥 Resolvendo redirect da URL...")
641
+
642
+ # Primeira requisição: seguir redirect para obter URL final COM cookies
643
+ redirect_response = requests.get(upscaled_url, timeout=60, allow_redirects=True,
644
+ cookies=cookies_dict,
645
+ headers={
646
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
647
+ 'Referer': 'https://gemini.google.com/',
648
+ 'Accept': 'image/*,*/*'
649
+ }
650
+ )
651
+
652
+ # A URL final após redirect
653
+ final_url = redirect_response.url
654
+ print(f"📍 URL após redirect: {final_url[:80]}...")
655
+
656
+ # Remover parâmetros existentes e adicionar =s0-d-I para full resolution
657
+ if "?" in final_url:
658
+ final_url = final_url.split("?")[0]
659
+ # Remover qualquer =sXXX existente
660
+ if "=s" in final_url:
661
+ final_url = final_url.rsplit("=s", 1)[0]
662
+
663
+ download_url = final_url + "=s0-d-I"
664
+ print(f"📥 Baixando imagem full res de: {download_url[:80]}...")
665
+
666
+ # Segunda requisição: baixar a imagem em full resolution COM cookies
667
+ img_response = requests.get(download_url, timeout=60,
668
+ cookies=cookies_dict,
669
+ headers={
670
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
671
+ 'Referer': 'https://gemini.google.com/',
672
+ 'Accept': 'image/*,*/*'
673
+ }
674
+ )
675
+ img_response.raise_for_status()
676
+
677
+ # Converter para base64
678
+ img_base64 = base64.b64encode(img_response.content).decode('utf-8')
679
+ content_type = img_response.headers.get('content-type', 'image/png')
680
+
681
+ print(f"✅ Imagem baixada e convertida para base64 ({len(img_base64)} chars)")
682
+
683
+ return img_base64, content_type, download_url
684
+
685
+
686
  @app.get("/upscale")
687
  async def upscale_image(
688
  file: str
 
690
  """
691
  Endpoint para fazer upscale 4x de uma imagem usando o Nano Banana Pro.
692
 
693
+ Se a primeira tentativa falhar (ex: erro de figuras públicas),
694
+ tenta novamente invertendo a imagem horizontalmente e verticalmente,
695
+ e depois inverte o resultado de volta.
696
+
697
  Parâmetros:
698
  - file: URL da imagem
699
 
700
  Retorna:
701
+ - JSON com a imagem gerada em base64 (upscaled)
702
  """
703
  if upscale_chatbot is None:
704
  raise HTTPException(status_code=500, detail="Upscale Chatbot não inicializado")
 
707
  raise HTTPException(status_code=400, detail="Parâmetro 'file' é obrigatório")
708
 
709
  temp_file = None
710
+ temp_flipped_file = None
711
+
712
  try:
713
  # Baixar arquivo da URL com retry
714
  response = download_file_with_retry(file, max_retries=3, timeout=300)
 
733
 
734
  prompt = "Upscale this image by 4x. Keep everything exactly as it is, including text, colors, texture, aspect ratio, zoom and proportions. Just increase the quality and sharpness. Do not add any new elements or modify the composition"
735
 
736
+ # Carregar cookies para download
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
737
  cookies_dict = {}
738
  cookie_path = os.getenv("COOKIE_PATH", "cookies.json")
739
  try:
 
745
  except Exception as cookie_err:
746
  print(f"⚠️ Aviso: Não foi possível carregar cookies: {cookie_err}")
747
 
748
+ # ========== PRIMEIRA TENTATIVA: Normal ==========
749
+ print(f"🧠 [Tentativa 1] Enviando imagem para upscale...")
750
+ result, upscaled_url = await _try_upscale(upscale_chatbot, temp_file.name, prompt)
751
+
752
+ used_flip_workaround = False
753
+
754
+ if result is None or upscaled_url is None:
755
+ # ========== SEGUNDA TENTATIVA: Inverter imagem ==========
756
+ print(f"⚠️ Primeira tentativa falhou. Tentando workaround de inversão...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
757
 
758
+ # Inverter a imagem horizontalmente e verticalmente
759
+ print(f"🔄 Invertendo imagem (horizontal + vertical)...")
760
+ temp_flipped_file = flip_image_both_axes(temp_file.name)
761
+ print(f"✅ Imagem invertida salva em: {temp_flipped_file}")
 
 
 
 
 
 
762
 
763
+ # Tentar novamente com a imagem invertida
764
+ print(f"🧠 [Tentativa 2] Enviando imagem INVERTIDA para upscale...")
765
+ result, upscaled_url = await _try_upscale(upscale_chatbot, temp_flipped_file, prompt)
766
 
767
+ if result is None or upscaled_url is None:
768
+ raise HTTPException(
769
+ status_code=500,
770
+ detail="Nenhuma imagem de upscale foi retornada pelo modelo após múltiplas tentativas."
771
+ )
772
 
773
+ used_flip_workaround = True
774
+ print(f"✅ Segunda tentativa (com inversão) funcionou!")
775
+
776
+ # Baixar imagem upscaled
777
+ try:
778
+ img_base64, img_content_type, download_url = await _download_upscaled_image(upscaled_url, cookies_dict)
779
  except Exception as download_error:
780
  print(f"❌ Erro ao baixar imagem: {download_error}")
781
  raise HTTPException(
782
  status_code=500,
783
  detail=f"Erro ao baixar imagem upscaled: {str(download_error)}"
784
  )
785
+
786
+ # Se usamos o workaround de inversão, precisamos inverter o resultado de volta
787
+ if used_flip_workaround:
788
+ print(f"🔄 Invertendo resultado de volta (restaurando orientação original)...")
789
+ img_base64 = flip_base64_image_both_axes(img_base64, img_content_type)
790
+ print(f"✅ Imagem restaurada para orientação original")
791
 
792
  return JSONResponse(
793
  content={
794
  "image_base64": img_base64,
795
+ "content_type": img_content_type,
796
  "success": True,
797
  "original_url": file,
798
+ "upscaled_url": download_url,
799
+ "used_flip_workaround": used_flip_workaround
800
  }
801
  )
802
 
 
807
  traceback.print_exc()
808
  raise HTTPException(status_code=500, detail=f"Erro interno no upscale: {str(e)}")
809
  finally:
810
+ # Limpar arquivos temporários
811
  if temp_file and os.path.exists(temp_file.name):
812
  try:
813
  os.unlink(temp_file.name)
814
+ except:
815
+ pass
816
+ if temp_flipped_file and os.path.exists(temp_flipped_file):
817
+ try:
818
+ os.unlink(temp_flipped_file)
819
  except:
820
  pass