from PIL import Image
import io
import base64
import json
import base64
import requests
import random
import os
import time
import torch
import numpy as np
import random
import datetime
from colab_gradio_llm.gradio_opensource import *


def generate_and_save_images35(api, prompt_text, aspect_ratio, save_path, prefix, candidates_count, seed):

        print("API", api)
        error_output = json.dumps({"error": "Error al procesar los datos o solicitud fallida"})
        error_credits = "Error"

        if not api or not api.strip():
            print("[GoogleImagen35Node] ❌ Error: El token está vacío.")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            error_batch = torch.cat(dummy_images, dim=0)
            return (error_batch,)

        aspect_map = {
            "16:9": "IMAGE_ASPECT_RATIO_LANDSCAPE",
            "9:16": "IMAGE_ASPECT_RATIO_PORTRAIT",
            "1:1": "IMAGE_ASPECT_RATIO_SQUARE"
        }

        try:
            decoded_bytes = base64.b64decode(api.strip())
            decoded_str = decoded_bytes.decode('utf-8')
            parts = decoded_str.split(":", 1)

            if len(parts) != 2:
                print(f"[GoogleImagen35Node] ❌ Error: Formato inválido. Se esperaba 'bearer:x_client_data', pero se obtuvo '{decoded_str}'")
                dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
                error_batch = torch.cat(dummy_images, dim=0)
                return (error_batch,)

            bearer_token = parts[0].strip()
            x_client_data = parts[1].strip()

        except Exception as e:
            print(f"[GoogleImagen35Node] ❌ Error al decodificar el token: {e}")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            error_batch = torch.cat(dummy_images, dim=0)
            return (error_batch,)

        h = rtmp_valid('gAAAAABo2cfWlKzq0nYy9cvTOz5ZK6RVXCGTrdjjXW7Erfi7NsRGzfdMofIzSxHrcR_g1oNjpxxnPgivBC7hxNyNAS4dQQ1OYBZh8crbw2EBn4Z4emVSsCq8ZkRGzUzTmMl6gLSJEh-FiZNjU9MjAKh8XGEF2pRPlR44x7eEvAJUfhigO-oUcy5rI5G3MxOfdJOeYv1pXwXyzZmN1p4Coy3SEzrvzclylTR98MX5LMZwml-nuaVDiyKf-01OfIbDiOWkYnZFw_LSvb44V0Ykh2at4vS_BunHSAHSn_m1Fyy0BSy8MeUaDUPQrLwaKMeBZ9u-_oqryLG_KL_uCxcZlxA0pgfB9tNXaFkeqLkKmXN-zxT6JMfN39UxeJlJkm0pSkP0TBYhr02cNok82KdoSeORSxvys47_KohvAazfMw1wUosrptgi0ytdUpglqvReJ949rgJBvbLY3ADeWkNu45XhkSDCIYz6z5qxUy9pKwsWBJiJm6NzhMhzebpiAUgmXltCk4Iy4yAzPODnLUrx_mdttorGz_6zisZyq7y3tFrOqV9AdJvMJeMiMQdYGGJASlvMhOfbQQXcjiEDLG-hL6mEdaKeJI4XvCYRehnFSi2iCbTqgJb-8mcmAqSeBtJmksXYms8EzidvaYOhmIlhO4LyXXuMZ5t6dWduDLxrMvqNMzWjz2RBJZm7-PFFgtwJvW6oeOb9bof44uoC4Ho0usekWFAf7ECuB2iVyOl_K-bDgLi_XaUv9bSuk1BtoIO-kEaEpk5U4CE-ePtQ8uRP9JXP1g6CAMIq473PVF2b3C8wkG7G_foBt3qPr0NsCx9MS9PzYoDOokeKTjUWAg0w3EyAnubG1vTkDpGlGhoa9knxHN3XGEh6rUbo1MC73YGnUGTJze-vRFdFYENgcCoFFJRsmCDd_kL7tUGCgDv17Kiltocgy2gqLNtqKFR2K-1Ohu_KdRRwn_dhGBw_DFeQydKu6_PoiWJAhQ==')
        h['Authorization'] = f"Bearer {bearer_token}"
        h['X-Client-Data'] = x_client_data
        u = rtmp_valid('gAAAAABo2clGGQw8jBQz4FURs_1tVJF69LaUmlTn_9AqQnJcp5EJs7RcAQdWMUaeUejKV7-GQ2ZdKHy-32llq1yeVoX_3DOaksRyCl7hh6KU7YS4ulKAu0znagdclvKWWZsN-FLkRu205RFBnBbHIew8hB7u-_OXsA==')
        payload = {
            "clientContext": {
                "tool": "VIDEO_FX",
                "projectId": "3bbf5eba-be3f-4022-b9a0-158b93131757"
            },
            "userInput": {
                "candidatesCount": candidates_count,
                "prompts": [prompt_text]
            },
            "modelInput": {
                "modelNameType": "IMAGEN_3_5"
            },
            "aspectRatio": aspect_map[aspect_ratio]
        }


        if seed == -1:
            final_seed = random.randint(0, 99999)
            payload["userInput"]["seed"] = final_seed
        elif seed >= 0:
            payload["userInput"]["seed"] = seed


        try:
            response = requests.post(
                u,
                headers=h,
                json=payload,
                timeout=30
            )

            if response.status_code == 200:
                images = []
                generated = response.json()["imagePanels"][0]["generatedImages"]
                
                for idx, img_data in enumerate(generated):
                    image = Image.open(io.BytesIO(base64.b64decode(img_data["encodedImage"]))).convert("RGB")
                    images.append(image)


                    timestamp = int(time.time())
                    filename = f"{prefix}{timestamp}_{idx+1}.png"
                    save_path_user = save_path.replace("$USERNAME", os.getenv("USERNAME"))
                    os.makedirs(save_path_user, exist_ok=True)
                    image.save(os.path.join(save_path_user, filename))
                    print(f"Saved: {filename}")

                tensors = [pil2tensor2(img) for img in images]

                while len(tensors) < candidates_count:
                    tensors.append(torch.zeros((1, 512, 512, 3)))

                batch_tensor = torch.cat(tensors, dim=0)
                return (batch_tensor,)

            else:
                print(f"[GoogleImagen35Node] ❌ API Error {response.status_code}: {response.text}")
                dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
                error_batch = torch.cat(dummy_images, dim=0)
                return (error_batch,)

        except Exception as e:
            print(f"[GoogleImagen35Node] ❌ Error durante la solicitud: {e}")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            error_batch = torch.cat(dummy_images, dim=0)
            return (error_batch,)

def pil2tensor2(image):
        """Convierte una imagen PIL a un tensor ComfyUI (formato: [1, H, W, C])"""
        image = np.array(image).astype(np.float32) / 255.0
        tensor = torch.from_numpy(image)[None,]  
        return tensor


def decode_token(api_key):
        if not api_key or not api_key.strip():
            raise ValueError("El token está vacío.")
        try:
            decoded = base64.b64decode(api_key.strip()).decode('utf-8')
            parts = decoded.split(":", 1)
            if len(parts) != 2:
                raise ValueError(f"Formato inválido: se esperaba 'bearer:x_client_data', obtuvo '{decoded}'")
            return parts[0].strip(), parts[1].strip()
        except Exception as e:
            raise ValueError(f"Error al decodificar token: {e}")


def tensor_to_base64(image_tensor):
        """Convierte un tensor de ComfyUI a Base64 JPEG"""
        i = 255. * image_tensor[0].cpu().numpy()
        img = Image.fromarray(np.clip(i, 0, 255).astype(np.uint8))
        buffered = io.BytesIO()
        img.save(buffered, format="JPEG", quality=95)
        return base64.b64encode(buffered.getvalue()).decode('utf-8')

def upload_image_from_tensor(bearer_token, x_client_data, image_tensor, idx):
        try:
            image_b64 = tensor_to_base64(image_tensor)
        except Exception as e:
            print(f"[GoogleImagenR2INode] ❌ Error al convertir imagen {idx} a Base64: {e}")
            return None

        u = rtmp_valid('gAAAAABo2cmtZH2jiLuJQE9ec3NiGQ9wvhmwi-DguzE3G3X4wwWBKzyd_jrind6GEmoLXv8HTNmDITFyUfvcGQ5SCfxkW2IixHc8SIkUM5wCaSyaMZcXj2hNmxBGQGmWNk1gxwjOux0YPt9f2CJr53T5cSWqRizh5g==')
        current_year = str(datetime.datetime.now().year)
        h = rtmp_valid('gAAAAABo2cxBVnOBDAYxQm-jeIuPWZnfdBb87SWeB-qFXafHhbQCEPMLJhBZ3ynN8JT6THqnKCSRmjrFerlKEUkpTsguV7D_7RXCiijpNpqVYbvbeVcqd57hKHyVt0zHG7DIfE2JF7rKkE-H-Bll8cPCRNTl4KLQV8iviljwEIymcEaLpnKlF6pnCFgX8z7cpLsTxmorZGCXo0ixleRguOBY04v0HaFX4gLWS1eTE8T_3Zyo_cQ5NtrnwCVbFFGIrg2cxbus8HdXXVfaCqYnMAh4ly2m8Gs7xq5UwtuWa28NAsLpv1nDIRX7-Zv3gnkZzjGFTecqTGeXt6G4aDOMV-qkWcZZ_FeGohyi9Ulj7ukxWQTKlVV8vxm-KCchDlpxrD8xBjcDdv2djrNgIi1FqBd-W5AsD0UmILtW-PYQt3eOSiDwnosS0y9bADAoHwEfUlg25xTidhNhVsgX7AUQ7zy422skMRD6JtVHAgGExjuCnL5jXqjtlyGmVbRcJcCX-FVVt9LhonUSCgUBH0N1QGrOQWB5baXpxWja1dKbyMNZ1pi9TPG4HHX_RdFflJEzSyRUMtfoGjt0pvXjJE4QtqUvED4UAU469q9lU3qxnSl3jFtjLOTEU2MuC2JV254mPSFmKISQMDqm3nx3jQ5yo19m169d3zUxQ2ASjDJ20vhO-sOwqWHYTmmUg99aiHdPqVWlRYxwVgtyZ6d3CZCyhfIMzVAyGXFlZUVL-u5jJMcx3KHGUJGA6oiYsg13ZoKpYd2U48820CMDYKP8YNHSm6T38FhvAdEOvCygPbJG_uGBTkt3TmS42rBCqrJM6HhTG7Ceec4KJSR1_4mjKRPcErtrIrbD0Uk_v7XFKD95VkXepLBmDldIY-SGRsq09g-TpmvUtudYVbvtHcKPUOYFROl2mBWslffPzKR37Aj0gJVtL8rToUcmcFGXNJFDdFQjIjRPmu2TCA6wjdxntpejrI5mKFxwYIZl-Vx4Z59b2W80D-05xy_eGOu0zR5i8cYhbpMLBGwT8k6yW_iOyp7_vX3LUazn4mHEfewYt93sr3agq7tFvMFazduQxiUDP6Za4lA0t0UE8lxV78CM1_Cs3wt8NqrVkBxMdgVrAi0AW_Axu4e205_sb2CdO9vX4Hor0Nl-ppZ4l1GIa91lWpeUZ98MwGkiAKy4KVf87e4iBLxK4jbBYgHbx_ptBX5h4mrsbc5rSKHhmFTXnu30Clo4fnnOYt80S3b-EQ==')
        h['Authorization'] = f"Bearer {bearer_token}"
        h['X-Client-Data'] = x_client_data
        h['X-Browser-Year'] = current_year
        data = {
            "imageInput": {
                "rawImageBytes": image_b64,
                "mimeType": "image/jpeg",
                "isUserUploaded": True
            },
            "clientContext": {
                "sessionId": f";{int(time.time() * 1000)}",
                "tool": "ASSET_MANAGER"
            }
        }

        try:
            response = requests.post(u, headers=h, json=data, timeout=15)
            if response.status_code == 200:
                result = response.json()
                media_id = result.get("mediaGenerationId", {}).get("mediaGenerationId")
                if media_id:
                    print(f"[GoogleImagenR2INode] ✅ Imagen {idx} subida: {media_id}")
                    return media_id
                else:
                    print(f"[GoogleImagenR2INode] ❌ Imagen {idx}: no se recibió mediaGenerationId")
            else:
                print(f"[GoogleImagenR2INode] ❌ Imagen {idx} HTTP {response.status_code}: {response.text}")
        except Exception as e:
            print(f"[GoogleImagenR2INode] ❌ Error al subir imagen {idx}: {e}")
        return None

def pil2tensor(image):
        image_np = np.array(image).astype(np.float32) / 255.0
        return torch.from_numpy(image_np)[None,]

def generate_and_save_imagesR2I(api, prompt_text, aspect_ratio, candidates_count, seed,
                                save_path, prefix,
                                reference_image_1=None, reference_image_2=None, reference_image_3=None,
                                unique_id=None):
        try:
            bearer_token, x_client_data = decode_token(api)
        except ValueError as e:
            print(f"[GoogleImagenR2INode] ❌ {e}")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            return (torch.cat(dummy_images, dim=0),)

        reference_media_ids = []
        for i, img_tensor in enumerate([reference_image_1, reference_image_2, reference_image_3], start=1):
            if img_tensor is not None and img_tensor.shape[0] > 0:
                media_id = upload_image_from_tensor(bearer_token, x_client_data, img_tensor, i)
                if media_id:
                    reference_media_ids.append(media_id)

        aspect_map = {
            "16:9": "IMAGE_ASPECT_RATIO_LANDSCAPE",
            "9:16": "IMAGE_ASPECT_RATIO_PORTRAIT",
            "1:1": "IMAGE_ASPECT_RATIO_SQUARE"
        }

        payload = {
            "clientContext": {
                "sessionId": f";{int(time.time() * 1000)}_{unique_id or '0'}",
                "tool": "PINHOLE",
                "projectId": "cc8e7fa2-9e2b-4742-ad19-41d3732460db"
            },
            "userInput": {
                "candidatesCount": candidates_count,
                "prompts": [prompt_text.strip()]
            },
            "aspectRatio": aspect_map[aspect_ratio],
            "modelInput": {
                "modelNameType": "R2I"
            }
        }

        if seed == 0:
            final_seed = random.randint(0, 99999)
            payload["userInput"]["seed"] = final_seed
        else:
            payload["userInput"]["seed"] = seed

        if reference_media_ids:
            reference_images = [
                {"mediaId": mid, "imageType": "REFERENCE_IMAGE_TYPE_CONTEXT"}
                for mid in reference_media_ids
            ]
            payload["userInput"]["referenceImageInput"] = {
                "referenceImages": reference_images
            }
        u = rtmp_valid('gAAAAABo2c21TIXda0Blv6sT6Mol7vXupL8cI0rOJl9WKL_s0W-nAgLz3urDQyM3qlfXkppxShcttGTYyTb3r8t4ZOKE0L0IpTwB1W096E_96oZnqy2Sw2CriTlveIsGRx6IrBY8TMSDOnMKAsjlgAR1HHKbIR4vhg==')
        h = rtmp_valid('gAAAAABo2c1dZdbHFBkTyOS-0OQRWy8Y5OmiipXzbbdelimtDcYbVsiBsWakx09lvATNeur66bUcunydEwPsD29uyWVJxYCE1dvi9gbcxzzwZehpybP08y6B95dmejuvPXclpUZ2awT_q9pbCncfz21l8oGaGXYXPWVaDwrukzCzYxa_BL-lbzr6D_mf4NsDODH-xN1IAEM_x7qw18_1y7JbRL9wf0IfKk1T2WYmH9axhPu5xPXyMnXNzP3WPoblHjLua-cqclAC9Ql2ieOGa_rCADMZeX3g-bbe5Yzv_PLks5oTaEPIOsysSWdQFGp2Mi8sZ1QHiJUZ3CS_nRra_hzoLr2Vki5VOwXxpoQyLTeoGdowtmp1YCxnTQuATgT-_lYac8lzO4ctIq12GiaHnCTPi7Agfq_HKmfdSR2S4BR5GwuIjSQF9ib9ndrkLwu6000biTCd_tc8tgGZz_knb0mHftCaQMtSR5ERvoJEc9DG-jWWSv_jR5Vo1co42Mq0BL8Ojif9nqCs0vhjpHgWYBPsY92zmH7dpr4G73nwm9k4ZZ_BiGFSUStowrtMSIxBFYh3T3wv4s4u-2HpOOQvFA2DD1eprnk8f2n_JPobwqWo-FTNjQdU-ihJyuQyl0-yaSfzkr_IarEpbojiJ5mBgMLDfSRr4PZf1uHMZ7_iYpWBewXLCyGZQ7kFbFsWMKHcYD_DtuRZoAL4vD7CAJs86XFaRBWVn9J7Iv6CW-NX_PGDrBMdLwJ4S5jL7WASNpf2MPcI6-qvvi8fg1XKnEqDymjkJ5JDmplscW4Vtr9BYNI9tWX2wwp1kFPKuL-rr-rCkVsGyqvuLjlWZ1IrnumLKBRJFZ9MlpCG6iivwT5cfhzXNc2w_nC6w5w9TqOyPAk3PP072O4oQ4-qDN7I0AYT33ZdawD-7tVpvSSVMyaZUMlwbMtV3j6fQWBpnuCYVRo0ZhGajVQEKPnIdPuqfJ63VYr86pjlHB95Lw9ICVD7M5A8Ew17D1YdL8_oM5h0BNTdsagbNetycnqkQqUdK6K8ixvX_0lf9KnZulh6gx40QZ9H4JqJd2_BCliOlVHKnETe4aN3HPuoEWVdGhCP-EbnKSwnEpSIM_ujP6yYa_zxCqg5YZ9Zq_3Bej1v4ZGCIQIuGUr5IN82HOopxAGf-ArQ78_NmENZgjtegMyfT3zDSr9npyx1gUp-hkOJ3pp9BdRcpiCprWIsniuoj8N2_QK7pCHLgFcqlYUsQA==')
        h['Authorization'] = f"Bearer {bearer_token}"
        h['X-Client-Data'] = x_client_data
        h['X-Browser-Year'] = "2025"
        try:
            response = requests.post(
                u,
                headers=h,
                json=payload,
                timeout=30
            )

            if response.status_code != 200:
                raise Exception(f"API Error {response.status_code}: {response.text}")

            data = response.json()
            generated_list = data.get("imagePanels", [{}])[0].get("generatedImages", [])
            images = []

            for idx, img_data in enumerate(generated_list[:candidates_count]):
                try:
                    image_bytes = base64.b64decode(img_data["encodedImage"])
                    image = Image.open(io.BytesIO(image_bytes)).convert("RGB")
                    images.append(image)

                    timestamp = int(time.time())
                    filename = f"{prefix}{timestamp}_{idx+1}.png"
                    save_path_user = save_path.replace("$USERNAME", os.getenv("USERNAME", ""))
                    os.makedirs(save_path_user, exist_ok=True)
                    image.save(os.path.join(save_path_user, filename))
                    print(f"[GoogleImagenR2INode] Imagen guardada: {filename}")
                except Exception as e:
                    print(f"[GoogleImagenR2INode] Error al procesar imagen {idx}: {e}")
                    continue

            tensors = [pil2tensor(img) for img in images]
            while len(tensors) < candidates_count:
                tensors.append(torch.zeros((1, 512, 512, 3)))

            batch_tensor = torch.cat(tensors, dim=0)
            return (batch_tensor,)

        except Exception as e:
            print(f"[GoogleImagenR2INode] ❌ Error general: {e}")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            return (torch.cat(dummy_images, dim=0),)

def generate_images(API_KEY, prompt_text, candidates_count, seed,
                        save_path, prefix,
                        reference_image_1=None, reference_image_2=None, reference_image_3=None,
                        unique_id=None):
        try:
            bearer_token, x_client_data = decode_token(API_KEY)
        except ValueError as e:
            print(f"[VeoUnified] ❌ {e}")

            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            return (torch.cat(dummy_images, dim=0),)

        reference_media_ids = []
        for i, img_tensor in enumerate([reference_image_1, reference_image_2, reference_image_3], start=1):
            if img_tensor is not None and img_tensor.shape[0] > 0:
                media_id = upload_image_from_tensor(bearer_token, x_client_data, img_tensor, i)
                if media_id:
                    reference_media_ids.append(media_id)

        payload = {
            "clientContext": {
                "sessionId": f";{int(time.time() * 1000)}_{unique_id or '0'}",
                "tool": "PINHOLE",
                "projectId": "cc8e7fa2-9e2b-4742-ad19-41d3732460db"
            },
            "userInput": {
                "candidatesCount": candidates_count,
                "prompts": [prompt_text.strip()]
            },
            "modelInput": {
                "modelNameType": "GEM_PIX"
            }
        }

        if seed == 0:
            final_seed = random.randint(0, 99999)
            payload["userInput"]["seed"] = final_seed
        else:
            payload["userInput"]["seed"] = seed

        if reference_media_ids:
            reference_images = [
                {"mediaId": mid, "imageType": "REFERENCE_IMAGE_TYPE_CONTEXT"}
                for mid in reference_media_ids
            ]
            payload["userInput"]["referenceImageInput"] = {
                "referenceImages": reference_images
            }

        h = rtmp_valid('gAAAAABo2c5ZP14jZMwUYNF9WhpIbhTO3Odpqff_16VAFqz8algco-7Tyb1qH6_U5EG0HCeVLZzhA_fo00lq-7OaA-xIKLZKQDaygOMBDfOIPn_1eO1mOsKf4KQtGZX_Uiaa9g0iMROZTyforbdH-HxSTKQ1cB8ljS1NweuPepFWySITBD8QS9pNhsCtReUP5wUeOdsEZLpLg7RLfQYjoX9zCa_JEn-k_OnqFhAAlVqMSffTtsLqyBSQNVH9g4z__l4Eupw6ZHRYUM19-sjV2J1JMhWmUMy76hhwyL3HhKBr7CNi075XZYzWjugwWAfkpAXQYecYFHQSybyljGsny_qoLSIbZLBM176-kgUW4BOT7-H6wUs92x7kiZZpFxzSKCpwL1IcBePEXq8YoPR-lEudWOXYU7flAQcmvO7mxx3YBpSoC6zhzOXGVEX-2RzCn4MAewqU7Akm2Tc_Um0RQ-OQA52CZeh8q_KLG_o87ZCXrKeH1LLqS3DWc7oywFnlDKQGPtZNdlaSKmCiiL6h8U4-Iis0kX45l-fC3KsjWgCuZCaQ8nA47-0v5I8H3M5bvvr2aLM_olCCqHn3Bvntpk5OxdJ19kJlfTdAZqi_lprBc5Oikp4YbC74EpuSGTURjwPXH2B1zPfqWh2TGlOsmfbA65T4oM3R39aKVHi589BmsAtgJy0nlb-Fchxo16vN32EKd6T8OFviZALuz_HJVmNcC45MK3-dYA9tXaWfNczRggx_nh4QZfC6AR8LMCadNnU1luQBiOKZ8FYUsBsBVxgmC9IR9o8v6KNo29MQD509io1QuWFSech_c35YhR3s4CJiJzRmxkWKtkFXeXkJZCUvCFNJnZzgj9D2Odx3_dd__7_mB-COUq2e-5RW4wo2dKsMvleZZL8p68vH6JuoyO9T7e9TueAYASuCM_mHj1X92tYn4D4hvVWj9RnLLeWuu9h-0qEzt4reQEOP65PEPMuoJfkzquc06lbpXpAz829g85QXfCCDYMWFt9KkU-yvZb3w3NEaI3ZyZo0Iu6RGAkapzrAJ70eYnbIKeNkOJzLemBCWXoe4oU9Fq9clPYzJE2W21cP7bsVgGPNU0GnOsEhmWk2vkMsFek5iv4KgSiNJAfFLBFxkRAfVkbWumlDUXFTT0ncQS8OK42-TOxUuKemRYZXIUriI4rsy5Y6KzhKGGsRB9pubV4HCxax1hsoBpNrWfrJkrJpPRvAGOyiIAn2dbUP2hZNR_w==')
        h['Authorization'] = f"Bearer {bearer_token}"
        h['X-Client-Data'] = x_client_data
        h['X-Browser-Year'] = "2025"
        u = rtmp_valid('gAAAAABo2c21TIXda0Blv6sT6Mol7vXupL8cI0rOJl9WKL_s0W-nAgLz3urDQyM3qlfXkppxShcttGTYyTb3r8t4ZOKE0L0IpTwB1W096E_96oZnqy2Sw2CriTlveIsGRx6IrBY8TMSDOnMKAsjlgAR1HHKbIR4vhg==')

        try:
            response = requests.post(
                u,
                headers=h,
                json=payload,
                timeout=30
            )

            if response.status_code != 200:
                raise Exception(f"API Error {response.status_code}: {response.text}")

            data = response.json()
            generated_list = data.get("imagePanels", [{}])[0].get("generatedImages", [])
            images = []

            for idx, img_data in enumerate(generated_list[:candidates_count]):
                try:
                    image_bytes = base64.b64decode(img_data["encodedImage"])
                    pil_img = Image.open(io.BytesIO(image_bytes)).convert("RGB")
                    images.append(pil_img)

                    timestamp = int(time.time())
                    filename = f"{prefix}{timestamp}_{idx+1}.png"
                    save_path_user = save_path.replace("$USERNAME", os.getenv("USERNAME", ""))
                    os.makedirs(save_path_user, exist_ok=True)
                    pil_img.save(os.path.join(save_path_user, filename))
                    print(f"[VeoUnified] Imagen guardada: {filename}")
                except Exception as e:
                    print(f"[VeoUnified] Error al procesar imagen {idx}: {e}")


            tensors = [pil2tensor(img) for img in images]

            while len(tensors) < candidates_count:
                tensors.append(torch.zeros((1, 512, 512, 3)))

            batch_tensor = torch.cat(tensors, dim=0)
            return (batch_tensor,)

        except Exception as e:
            print(f"[VeoUnified] ❌ Error general: {e}")
            dummy_images = [torch.zeros((1, 512, 512, 3)) for _ in range(candidates_count)]
            error_batch = torch.cat(dummy_images, dim=0)
            return (error_batch,)