[{"data":1,"prerenderedAt":11078},["ShallowReactive",2],{"blog-/es/blog/seedance-2-api-tutorial-python":3},{"id":4,"title":5,"body":6,"description":11067,"extension":11068,"meta":11069,"navigation":57,"path":11074,"seo":11075,"stem":11076,"__hash__":11077},"content/es/blog/seedance-2-api-tutorial-python.md","Tutorial de API de Seedance 2.0: De Cero a Su Primer Video con IA (Python)",{"type":7,"value":8,"toc":11010},"minimark",[9,13,16,31,43,46,51,54,65,68,90,95,123,126,199,201,205,214,217,245,248,269,272,283,294,310,312,316,323,1547,1550,1640,1643,1655,1659,1666,1844,1847,1969,1983,1987,1993,2001,2004,2012,2020,2027,2029,2033,2040,2076,2079,2083,2089,2159,2163,2169,2175,2236,2247,2251,2254,2381,2395,2402,2412,2414,2418,2430,2436,2698,2701,2750,2754,2782,2785,2867,2870,3022,3028,3032,3086,3096,3104,3108,3111,3190,3197,3199,3203,3206,3426,3453,3457,3462,3466,3557,3566,3571,3666,3673,3678,3766,3771,3846,3863,3867,3870,3941,3954,3972,3974,3978,3981,3985,3988,4046,4069,4072,4077,4120,4127,4132,4186,4192,4197,4249,4259,4264,4316,4332,4337,4380,4386,4391,4445,4451,4456,4499,4502,4507,4550,4553,4558,4612,4618,4622,4832,4836,4839,4843,5587,5590,5622,5629,5633,5636,6216,6227,6229,6233,6240,6244,6250,6255,6413,6419,6423,6485,6489,6492,7649,7652,7675,7678,7706,7710,7719,7767,7770,7776,7781,7828,7843,7847,7850,8022,8026,8105,8112,8114,8118,8121,8126,8676,8679,8701,8703,8707,8710,8714,8754,8758,8781,8785,8788,8820,8830,8832,8836,8840,8846,8850,8856,8860,8866,8870,8881,8885,8899,8903,8913,8917,8932,8936,8943,8947,8963,8967,8975,8977,8981,8984,10984,10998,11006],[10,11,12],"p",{},"Seedance 2.0 es el modelo de video con IA más avanzado de ByteDance — referencias multimodales, audio nativo, control de cámara cinematográfico y generación de 4 a 15 segundos en hasta 1080p. Este tutorial le guía a través de todo el flujo de trabajo de la API en Python: desde obtener su clave API hasta descargar su primer video generado.",[10,14,15],{},"Al finalizar, tendrá código funcional para texto a video, imagen a video, polling asíncrono, manejo de webhooks y recuperación de errores. Cada ejemplo de código aquí fue probado contra una API en vivo.",[17,18,19],"blockquote",{},[10,20,21,25,26,30],{},[22,23,24],"strong",{},"Nota — Seedance 2.0 vs 1.5:"," Seedance 2.0 se está implementando progresivamente. Puede probar el flujo de trabajo completo ahora mismo usando ",[27,28,29],"code",{},"seedance-1.5-pro"," — cuando 2.0 esté completamente disponible, solo cambie el nombre del modelo. Todos los endpoints, parámetros y formatos de respuesta son idénticos. Las diferencias clave en 2.0: referencias multimodales (mezcle imágenes, videos y audio como entradas), generación de audio nativo, simulación de física mejorada y capacidades de edición de video. Todo en este tutorial funciona con ambas versiones.",[10,32,33],{},[22,34,35,42],{},[36,37,41],"a",{"href":38,"rel":39},"https://evolink.ai/early-access",[40],"nofollow","Obtenga su clave API gratuita"," para seguir el tutorial.",[44,45],"hr",{},[47,48,50],"h2",{"id":49},"qué-construirá-y-qué-necesita","Qué Construirá (y Qué Necesita)",[10,52,53],{},"Así se ve un video generado por Seedance — creado con una sola llamada a la API:",[55,56,59,60],"video",{"autoPlay":57,"loop":57,"muted":57,"playsInline":57,"style":58},true,"width:100%;border-radius:12px;margin:1.5em 0","\n  ",[61,62],"source",{"src":63,"type":64},"https://cdn.evolink.ai/seedance2api/%E5%B0%8F%E5%A5%B3%E5%AD%A9%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%A5%87%E9%81%87.mp4","video/mp4",[10,66,67],{},"En este tutorial, escribirá código Python que:",[69,70,71,75,78,81,84,87],"ol",{},[72,73,74],"li",{},"Envía un prompt de texto → recibe un video generado",[72,76,77],{},"Envía una imagen → la anima en un video",[72,79,80],{},"Realiza polling de resultados de forma asíncrona",[72,82,83],{},"Maneja errores y reintentos como código de producción",[72,85,86],{},"Recibe resultados vía webhook (sin necesidad de polling)",[72,88,89],{},"Cancela tareas en progreso cuando sea necesario",[91,92,94],"h3",{"id":93},"requisitos-previos","Requisitos Previos",[96,97,98,108,117],"ul",{},[72,99,100,103,104,107],{},[22,101,102],{},"Python 3.8+"," (verifique con ",[27,105,106],{},"python3 --version",")",[72,109,110,113,114,107],{},[22,111,112],{},"Biblioteca requests"," (",[27,115,116],{},"pip install requests",[72,118,119,122],{},[22,120,121],{},"Una clave API de EvoLink"," (registro gratuito — obtendremos esto en la siguiente sección)",[10,124,125],{},"Sin GPU, sin Docker, sin configuración compleja. Solo Python y una clave API.",[17,127,128,134],{},[10,129,130,133],{},[22,131,132],{},"Consejo Profesional:"," Si está construyendo una aplicación de producción, considere usar un entorno virtual para aislar dependencias:",[135,136,141],"pre",{"className":137,"code":138,"language":139,"meta":140,"style":140},"language-bash shiki shiki-themes github-dark","python3 -m venv seedance-env\nsource seedance-env/bin/activate  # macOS/Linux\nseedance-env\\Scripts\\activate     # Windows\npip install requests flask\n","bash","",[27,142,143,163,175,184],{"__ignoreMap":140},[144,145,148,152,156,160],"span",{"class":146,"line":147},"line",1,[144,149,151],{"class":150},"svObZ","python3",[144,153,155],{"class":154},"sDLfK"," -m",[144,157,159],{"class":158},"sU2Wk"," venv",[144,161,162],{"class":158}," seedance-env\n",[144,164,166,168,171],{"class":146,"line":165},2,[144,167,61],{"class":154},[144,169,170],{"class":158}," seedance-env/bin/activate",[144,172,174],{"class":173},"sAwPA","  # macOS/Linux\n",[144,176,178,181],{"class":146,"line":177},3,[144,179,180],{"class":150},"seedance-env\\Scripts\\activate",[144,182,183],{"class":173},"     # Windows\n",[144,185,187,190,193,196],{"class":146,"line":186},4,[144,188,189],{"class":150},"pip",[144,191,192],{"class":158}," install",[144,194,195],{"class":158}," requests",[144,197,198],{"class":158}," flask\n",[44,200],{},[47,202,204],{"id":203},"obtenga-su-clave-api","Obtenga Su Clave API",[10,206,207,208,213],{},"Seedance 2.0 está disponible a través de ",[36,209,212],{"href":210,"rel":211},"https://evolink.ai",[40],"EvoLink",", un gateway de API que proporciona acceso unificado a múltiples modelos de video con IA — incluyendo Seedance 2.0, Kling y otros — a través de una sola clave API.",[10,215,216],{},"Así es como comenzar:",[69,218,219,227,233,239],{},[72,220,221,222,226],{},"Vaya a ",[36,223,225],{"href":38,"rel":224},[40],"evolink.ai/early-access"," y cree una cuenta",[72,228,229,230],{},"Navegue a ",[22,231,232],{},"Dashboard → API Keys",[72,234,235,236],{},"Haga clic en ",[22,237,238],{},"Create New Key",[72,240,241,242],{},"Copie su clave — comienza con ",[27,243,244],{},"sk-",[10,246,247],{},"Almacene su clave de forma segura. No la suba al control de versiones. Usaremos una variable de entorno:",[135,249,251],{"className":137,"code":250,"language":139,"meta":140,"style":140},"export EVOLINK_API_KEY=\"sk-your-api-key-here\"\n",[27,252,253],{"__ignoreMap":140},[144,254,255,259,263,266],{"class":146,"line":147},[144,256,258],{"class":257},"snl16","export",[144,260,262],{"class":261},"s95oV"," EVOLINK_API_KEY",[144,264,265],{"class":257},"=",[144,267,268],{"class":158},"\"sk-your-api-key-here\"\n",[10,270,271],{},"En Windows (PowerShell):",[135,273,277],{"className":274,"code":275,"language":276,"meta":140,"style":140},"language-powershell shiki shiki-themes github-dark","$env:EVOLINK_API_KEY=\"sk-your-api-key-here\"\n","powershell",[27,278,279],{"__ignoreMap":140},[144,280,281],{"class":146,"line":147},[144,282,275],{},[10,284,285,286,289,290,293],{},"Para hacerlo permanente, agregue la línea a su ",[27,287,288],{},"~/.bashrc",", ",[27,291,292],{},"~/.zshrc"," o perfil de PowerShell.",[17,295,296],{},[10,297,298,301,302,305,306,309],{},[22,299,300],{},"Seguridad:"," Nunca incluya claves API directamente en su código fuente. Use variables de entorno, archivos ",[27,303,304],{},".env"," (con ",[27,307,308],{},"python-dotenv","), o servicios de gestión de secretos como AWS Secrets Manager o HashiCorp Vault para aplicaciones de producción.",[44,311],{},[47,313,315],{"id":314},"su-primer-video-texto-a-video","Su Primer Video: Texto a Video",[10,317,318,319,322],{},"Comencemos con el caso de uso más simple: enviar un prompt de texto y obtener un video. Cree un nuevo archivo llamado ",[27,320,321],{},"seedance_tutorial.py",":",[135,324,328],{"className":325,"code":326,"language":327,"meta":140,"style":140},"language-python shiki shiki-themes github-dark","import os\nimport time\nimport requests\n\n# Configuración de la API\nBASE_URL = \"https://api.seedance2api.app/v1\"\nAPI_KEY = os.environ.get(\"EVOLINK_API_KEY\")\n\nif not API_KEY:\n    raise ValueError(\"EVOLINK_API_KEY no está configurada. Ejecute: export EVOLINK_API_KEY='sk-...'\")\n\nHEADERS = {\n    \"Authorization\": f\"Bearer {API_KEY}\",\n    \"Content-Type\": \"application/json\"\n}\n\n\ndef wait_for_video(task_id, poll_interval=10):\n    \"\"\"Realiza polling de una tarea hasta que se complete o falle.\"\"\"\n    start_time = time.time()\n\n    while True:\n        response = requests.get(\n            f\"{BASE_URL}/tasks/{task_id}\",\n            headers=HEADERS\n        )\n        response.raise_for_status()\n        task = response.json()\n\n        status = task[\"status\"]\n        progress = task.get(\"progress\", 0)\n        elapsed = int(time.time() - start_time)\n\n        print(f\"  [{elapsed}s] Estado: {status} | Progreso: {progress}%\")\n\n        if status == \"completed\":\n            return task\n        elif status == \"failed\":\n            error_msg = task.get(\"error\", {}).get(\"message\", \"Error desconocido\")\n            raise Exception(f\"La tarea falló: {error_msg}\")\n\n        time.sleep(poll_interval)\n\n\ndef download_video(url, filename):\n    \"\"\"Descarga un video desde una URL a un archivo local.\"\"\"\n    print(f\"Descargando video a {filename}...\")\n    response = requests.get(url, stream=True)\n    response.raise_for_status()\n\n    with open(filename, \"wb\") as f:\n        for chunk in response.iter_content(chunk_size=8192):\n            f.write(chunk)\n\n    size_kb = os.path.getsize(filename) / 1024\n    print(f\"Guardado: {filename} ({size_kb:.0f} KB)\")\n\n\ndef text_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",          # El modelo de IA a usar\n        \"prompt\": (\n            \"Un cachorro golden retriever persigue una mariposa a través \"\n            \"de un prado iluminado por el sol. La cámara sigue al cachorro con un \"\n            \"plano de seguimiento suave mientras las flores silvestres se mecen con la brisa.\"\n        ),\n        \"duration\": 5,                     # Duración del video: 4-15 segundos\n        \"quality\": \"720p\",                 # Resolución: 480p, 720p, 1080p\n        \"aspect_ratio\": \"16:9\",            # Pantalla ancha estándar\n        \"generate_audio\": True             # La IA genera audio coincidente\n    }\n\n    print(\"Enviando solicitud de texto a video...\")\n    response = requests.post(\n        f\"{BASE_URL}/videos/generations\",  # El endpoint de generación de video\n        headers=HEADERS,                   # Headers de autenticación + content-type\n        json=payload                       # Serializa automáticamente a JSON\n    )\n    response.raise_for_status()            # Lanza excepción si no es 200 OK\n    task = response.json()                 # Parsea la respuesta JSON\n\n    # Registra información clave de la respuesta\n    print(f\"Tarea creada: {task['id']}\")\n    print(f\"Tiempo estimado: {task['task_info']['estimated_time']}s\")\n    print(f\"Créditos reservados: {task['usage']['credits_reserved']}\")\n\n    # Realiza polling hasta que el video esté listo\n    result = wait_for_video(task[\"id\"])\n\n    # El array results contiene una o más URLs de video\n    video_url = result[\"results\"][0]\n    print(f\"\\nURL del video: {video_url}\")\n    download_video(video_url, \"mi_primer_video.mp4\")\n\n    return result\n\n\nif __name__ == \"__main__\":\n    text_to_video()\n","python",[27,329,330,338,345,352,357,363,375,392,397,412,429,434,445,469,480,486,491,496,516,522,533,538,549,560,587,599,605,611,622,627,644,665,685,690,735,740,757,766,781,807,834,839,845,850,855,866,872,897,918,924,929,953,978,984,989,1006,1041,1046,1051,1062,1072,1089,1098,1104,1110,1116,1122,1139,1156,1173,1186,1192,1197,1209,1219,1238,1254,1268,1274,1283,1297,1302,1308,1337,1371,1403,1408,1414,1431,1436,1442,1462,1490,1501,1506,1515,1520,1525,1541],{"__ignoreMap":140},[144,331,332,335],{"class":146,"line":147},[144,333,334],{"class":257},"import",[144,336,337],{"class":261}," os\n",[144,339,340,342],{"class":146,"line":165},[144,341,334],{"class":257},[144,343,344],{"class":261}," time\n",[144,346,347,349],{"class":146,"line":177},[144,348,334],{"class":257},[144,350,351],{"class":261}," requests\n",[144,353,354],{"class":146,"line":186},[144,355,356],{"emptyLinePlaceholder":57},"\n",[144,358,360],{"class":146,"line":359},5,[144,361,362],{"class":173},"# Configuración de la API\n",[144,364,366,369,372],{"class":146,"line":365},6,[144,367,368],{"class":154},"BASE_URL",[144,370,371],{"class":257}," =",[144,373,374],{"class":158}," \"https://api.seedance2api.app/v1\"\n",[144,376,378,381,383,386,389],{"class":146,"line":377},7,[144,379,380],{"class":154},"API_KEY",[144,382,371],{"class":257},[144,384,385],{"class":261}," os.environ.get(",[144,387,388],{"class":158},"\"EVOLINK_API_KEY\"",[144,390,391],{"class":261},")\n",[144,393,395],{"class":146,"line":394},8,[144,396,356],{"emptyLinePlaceholder":57},[144,398,400,403,406,409],{"class":146,"line":399},9,[144,401,402],{"class":257},"if",[144,404,405],{"class":257}," not",[144,407,408],{"class":154}," API_KEY",[144,410,411],{"class":261},":\n",[144,413,415,418,421,424,427],{"class":146,"line":414},10,[144,416,417],{"class":257},"    raise",[144,419,420],{"class":154}," ValueError",[144,422,423],{"class":261},"(",[144,425,426],{"class":158},"\"EVOLINK_API_KEY no está configurada. Ejecute: export EVOLINK_API_KEY='sk-...'\"",[144,428,391],{"class":261},[144,430,432],{"class":146,"line":431},11,[144,433,356],{"emptyLinePlaceholder":57},[144,435,437,440,442],{"class":146,"line":436},12,[144,438,439],{"class":154},"HEADERS",[144,441,371],{"class":257},[144,443,444],{"class":261}," {\n",[144,446,448,451,454,457,460,463,466],{"class":146,"line":447},13,[144,449,450],{"class":158},"    \"Authorization\"",[144,452,453],{"class":261},": ",[144,455,456],{"class":257},"f",[144,458,459],{"class":158},"\"Bearer ",[144,461,462],{"class":154},"{API_KEY}",[144,464,465],{"class":158},"\"",[144,467,468],{"class":261},",\n",[144,470,472,475,477],{"class":146,"line":471},14,[144,473,474],{"class":158},"    \"Content-Type\"",[144,476,453],{"class":261},[144,478,479],{"class":158},"\"application/json\"\n",[144,481,483],{"class":146,"line":482},15,[144,484,485],{"class":261},"}\n",[144,487,489],{"class":146,"line":488},16,[144,490,356],{"emptyLinePlaceholder":57},[144,492,494],{"class":146,"line":493},17,[144,495,356],{"emptyLinePlaceholder":57},[144,497,499,502,505,508,510,513],{"class":146,"line":498},18,[144,500,501],{"class":257},"def",[144,503,504],{"class":150}," wait_for_video",[144,506,507],{"class":261},"(task_id, poll_interval",[144,509,265],{"class":257},[144,511,512],{"class":154},"10",[144,514,515],{"class":261},"):\n",[144,517,519],{"class":146,"line":518},19,[144,520,521],{"class":158},"    \"\"\"Realiza polling de una tarea hasta que se complete o falle.\"\"\"\n",[144,523,525,528,530],{"class":146,"line":524},20,[144,526,527],{"class":261},"    start_time ",[144,529,265],{"class":257},[144,531,532],{"class":261}," time.time()\n",[144,534,536],{"class":146,"line":535},21,[144,537,356],{"emptyLinePlaceholder":57},[144,539,541,544,547],{"class":146,"line":540},22,[144,542,543],{"class":257},"    while",[144,545,546],{"class":154}," True",[144,548,411],{"class":261},[144,550,552,555,557],{"class":146,"line":551},23,[144,553,554],{"class":261},"        response ",[144,556,265],{"class":257},[144,558,559],{"class":261}," requests.get(\n",[144,561,563,566,568,571,574,577,580,583,585],{"class":146,"line":562},24,[144,564,565],{"class":257},"            f",[144,567,465],{"class":158},[144,569,570],{"class":154},"{BASE_URL}",[144,572,573],{"class":158},"/tasks/",[144,575,576],{"class":154},"{",[144,578,579],{"class":261},"task_id",[144,581,582],{"class":154},"}",[144,584,465],{"class":158},[144,586,468],{"class":261},[144,588,590,594,596],{"class":146,"line":589},25,[144,591,593],{"class":592},"s9osk","            headers",[144,595,265],{"class":257},[144,597,598],{"class":154},"HEADERS\n",[144,600,602],{"class":146,"line":601},26,[144,603,604],{"class":261},"        )\n",[144,606,608],{"class":146,"line":607},27,[144,609,610],{"class":261},"        response.raise_for_status()\n",[144,612,614,617,619],{"class":146,"line":613},28,[144,615,616],{"class":261},"        task ",[144,618,265],{"class":257},[144,620,621],{"class":261}," response.json()\n",[144,623,625],{"class":146,"line":624},29,[144,626,356],{"emptyLinePlaceholder":57},[144,628,630,633,635,638,641],{"class":146,"line":629},30,[144,631,632],{"class":261},"        status ",[144,634,265],{"class":257},[144,636,637],{"class":261}," task[",[144,639,640],{"class":158},"\"status\"",[144,642,643],{"class":261},"]\n",[144,645,647,650,652,655,658,660,663],{"class":146,"line":646},31,[144,648,649],{"class":261},"        progress ",[144,651,265],{"class":257},[144,653,654],{"class":261}," task.get(",[144,656,657],{"class":158},"\"progress\"",[144,659,289],{"class":261},[144,661,662],{"class":154},"0",[144,664,391],{"class":261},[144,666,668,671,673,676,679,682],{"class":146,"line":667},32,[144,669,670],{"class":261},"        elapsed ",[144,672,265],{"class":257},[144,674,675],{"class":154}," int",[144,677,678],{"class":261},"(time.time() ",[144,680,681],{"class":257},"-",[144,683,684],{"class":261}," start_time)\n",[144,686,688],{"class":146,"line":687},33,[144,689,356],{"emptyLinePlaceholder":57},[144,691,693,696,698,700,703,705,708,710,713,715,718,720,723,725,728,730,733],{"class":146,"line":692},34,[144,694,695],{"class":154},"        print",[144,697,423],{"class":261},[144,699,456],{"class":257},[144,701,702],{"class":158},"\"  [",[144,704,576],{"class":154},[144,706,707],{"class":261},"elapsed",[144,709,582],{"class":154},[144,711,712],{"class":158},"s] Estado: ",[144,714,576],{"class":154},[144,716,717],{"class":261},"status",[144,719,582],{"class":154},[144,721,722],{"class":158}," | Progreso: ",[144,724,576],{"class":154},[144,726,727],{"class":261},"progress",[144,729,582],{"class":154},[144,731,732],{"class":158},"%\"",[144,734,391],{"class":261},[144,736,738],{"class":146,"line":737},35,[144,739,356],{"emptyLinePlaceholder":57},[144,741,743,746,749,752,755],{"class":146,"line":742},36,[144,744,745],{"class":257},"        if",[144,747,748],{"class":261}," status ",[144,750,751],{"class":257},"==",[144,753,754],{"class":158}," \"completed\"",[144,756,411],{"class":261},[144,758,760,763],{"class":146,"line":759},37,[144,761,762],{"class":257},"            return",[144,764,765],{"class":261}," task\n",[144,767,769,772,774,776,779],{"class":146,"line":768},38,[144,770,771],{"class":257},"        elif",[144,773,748],{"class":261},[144,775,751],{"class":257},[144,777,778],{"class":158}," \"failed\"",[144,780,411],{"class":261},[144,782,784,787,789,791,794,797,800,802,805],{"class":146,"line":783},39,[144,785,786],{"class":261},"            error_msg ",[144,788,265],{"class":257},[144,790,654],{"class":261},[144,792,793],{"class":158},"\"error\"",[144,795,796],{"class":261},", {}).get(",[144,798,799],{"class":158},"\"message\"",[144,801,289],{"class":261},[144,803,804],{"class":158},"\"Error desconocido\"",[144,806,391],{"class":261},[144,808,810,813,816,818,820,823,825,828,830,832],{"class":146,"line":809},40,[144,811,812],{"class":257},"            raise",[144,814,815],{"class":154}," Exception",[144,817,423],{"class":261},[144,819,456],{"class":257},[144,821,822],{"class":158},"\"La tarea falló: ",[144,824,576],{"class":154},[144,826,827],{"class":261},"error_msg",[144,829,582],{"class":154},[144,831,465],{"class":158},[144,833,391],{"class":261},[144,835,837],{"class":146,"line":836},41,[144,838,356],{"emptyLinePlaceholder":57},[144,840,842],{"class":146,"line":841},42,[144,843,844],{"class":261},"        time.sleep(poll_interval)\n",[144,846,848],{"class":146,"line":847},43,[144,849,356],{"emptyLinePlaceholder":57},[144,851,853],{"class":146,"line":852},44,[144,854,356],{"emptyLinePlaceholder":57},[144,856,858,860,863],{"class":146,"line":857},45,[144,859,501],{"class":257},[144,861,862],{"class":150}," download_video",[144,864,865],{"class":261},"(url, filename):\n",[144,867,869],{"class":146,"line":868},46,[144,870,871],{"class":158},"    \"\"\"Descarga un video desde una URL a un archivo local.\"\"\"\n",[144,873,875,878,880,882,885,887,890,892,895],{"class":146,"line":874},47,[144,876,877],{"class":154},"    print",[144,879,423],{"class":261},[144,881,456],{"class":257},[144,883,884],{"class":158},"\"Descargando video a ",[144,886,576],{"class":154},[144,888,889],{"class":261},"filename",[144,891,582],{"class":154},[144,893,894],{"class":158},"...\"",[144,896,391],{"class":261},[144,898,900,903,905,908,911,913,916],{"class":146,"line":899},48,[144,901,902],{"class":261},"    response ",[144,904,265],{"class":257},[144,906,907],{"class":261}," requests.get(url, ",[144,909,910],{"class":592},"stream",[144,912,265],{"class":257},[144,914,915],{"class":154},"True",[144,917,391],{"class":261},[144,919,921],{"class":146,"line":920},49,[144,922,923],{"class":261},"    response.raise_for_status()\n",[144,925,927],{"class":146,"line":926},50,[144,928,356],{"emptyLinePlaceholder":57},[144,930,932,935,938,941,944,947,950],{"class":146,"line":931},51,[144,933,934],{"class":257},"    with",[144,936,937],{"class":154}," open",[144,939,940],{"class":261},"(filename, ",[144,942,943],{"class":158},"\"wb\"",[144,945,946],{"class":261},") ",[144,948,949],{"class":257},"as",[144,951,952],{"class":261}," f:\n",[144,954,956,959,962,965,968,971,973,976],{"class":146,"line":955},52,[144,957,958],{"class":257},"        for",[144,960,961],{"class":261}," chunk ",[144,963,964],{"class":257},"in",[144,966,967],{"class":261}," response.iter_content(",[144,969,970],{"class":592},"chunk_size",[144,972,265],{"class":257},[144,974,975],{"class":154},"8192",[144,977,515],{"class":261},[144,979,981],{"class":146,"line":980},53,[144,982,983],{"class":261},"            f.write(chunk)\n",[144,985,987],{"class":146,"line":986},54,[144,988,356],{"emptyLinePlaceholder":57},[144,990,992,995,997,1000,1003],{"class":146,"line":991},55,[144,993,994],{"class":261},"    size_kb ",[144,996,265],{"class":257},[144,998,999],{"class":261}," os.path.getsize(filename) ",[144,1001,1002],{"class":257},"/",[144,1004,1005],{"class":154}," 1024\n",[144,1007,1009,1011,1013,1015,1018,1020,1022,1024,1026,1028,1031,1034,1036,1039],{"class":146,"line":1008},56,[144,1010,877],{"class":154},[144,1012,423],{"class":261},[144,1014,456],{"class":257},[144,1016,1017],{"class":158},"\"Guardado: ",[144,1019,576],{"class":154},[144,1021,889],{"class":261},[144,1023,582],{"class":154},[144,1025,113],{"class":158},[144,1027,576],{"class":154},[144,1029,1030],{"class":261},"size_kb",[144,1032,1033],{"class":257},":.0f",[144,1035,582],{"class":154},[144,1037,1038],{"class":158}," KB)\"",[144,1040,391],{"class":261},[144,1042,1044],{"class":146,"line":1043},57,[144,1045,356],{"emptyLinePlaceholder":57},[144,1047,1049],{"class":146,"line":1048},58,[144,1050,356],{"emptyLinePlaceholder":57},[144,1052,1054,1056,1059],{"class":146,"line":1053},59,[144,1055,501],{"class":257},[144,1057,1058],{"class":150}," text_to_video",[144,1060,1061],{"class":261},"():\n",[144,1063,1065,1068,1070],{"class":146,"line":1064},60,[144,1066,1067],{"class":261},"    payload ",[144,1069,265],{"class":257},[144,1071,444],{"class":261},[144,1073,1075,1078,1080,1083,1086],{"class":146,"line":1074},61,[144,1076,1077],{"class":158},"        \"model\"",[144,1079,453],{"class":261},[144,1081,1082],{"class":158},"\"seedance-2.0\"",[144,1084,1085],{"class":261},",          ",[144,1087,1088],{"class":173},"# El modelo de IA a usar\n",[144,1090,1092,1095],{"class":146,"line":1091},62,[144,1093,1094],{"class":158},"        \"prompt\"",[144,1096,1097],{"class":261},": (\n",[144,1099,1101],{"class":146,"line":1100},63,[144,1102,1103],{"class":158},"            \"Un cachorro golden retriever persigue una mariposa a través \"\n",[144,1105,1107],{"class":146,"line":1106},64,[144,1108,1109],{"class":158},"            \"de un prado iluminado por el sol. La cámara sigue al cachorro con un \"\n",[144,1111,1113],{"class":146,"line":1112},65,[144,1114,1115],{"class":158},"            \"plano de seguimiento suave mientras las flores silvestres se mecen con la brisa.\"\n",[144,1117,1119],{"class":146,"line":1118},66,[144,1120,1121],{"class":261},"        ),\n",[144,1123,1125,1128,1130,1133,1136],{"class":146,"line":1124},67,[144,1126,1127],{"class":158},"        \"duration\"",[144,1129,453],{"class":261},[144,1131,1132],{"class":154},"5",[144,1134,1135],{"class":261},",                     ",[144,1137,1138],{"class":173},"# Duración del video: 4-15 segundos\n",[144,1140,1142,1145,1147,1150,1153],{"class":146,"line":1141},68,[144,1143,1144],{"class":158},"        \"quality\"",[144,1146,453],{"class":261},[144,1148,1149],{"class":158},"\"720p\"",[144,1151,1152],{"class":261},",                 ",[144,1154,1155],{"class":173},"# Resolución: 480p, 720p, 1080p\n",[144,1157,1159,1162,1164,1167,1170],{"class":146,"line":1158},69,[144,1160,1161],{"class":158},"        \"aspect_ratio\"",[144,1163,453],{"class":261},[144,1165,1166],{"class":158},"\"16:9\"",[144,1168,1169],{"class":261},",            ",[144,1171,1172],{"class":173},"# Pantalla ancha estándar\n",[144,1174,1176,1179,1181,1183],{"class":146,"line":1175},70,[144,1177,1178],{"class":158},"        \"generate_audio\"",[144,1180,453],{"class":261},[144,1182,915],{"class":154},[144,1184,1185],{"class":173},"             # La IA genera audio coincidente\n",[144,1187,1189],{"class":146,"line":1188},71,[144,1190,1191],{"class":261},"    }\n",[144,1193,1195],{"class":146,"line":1194},72,[144,1196,356],{"emptyLinePlaceholder":57},[144,1198,1200,1202,1204,1207],{"class":146,"line":1199},73,[144,1201,877],{"class":154},[144,1203,423],{"class":261},[144,1205,1206],{"class":158},"\"Enviando solicitud de texto a video...\"",[144,1208,391],{"class":261},[144,1210,1212,1214,1216],{"class":146,"line":1211},74,[144,1213,902],{"class":261},[144,1215,265],{"class":257},[144,1217,1218],{"class":261}," requests.post(\n",[144,1220,1222,1225,1227,1229,1232,1235],{"class":146,"line":1221},75,[144,1223,1224],{"class":257},"        f",[144,1226,465],{"class":158},[144,1228,570],{"class":154},[144,1230,1231],{"class":158},"/videos/generations\"",[144,1233,1234],{"class":261},",  ",[144,1236,1237],{"class":173},"# El endpoint de generación de video\n",[144,1239,1241,1244,1246,1248,1251],{"class":146,"line":1240},76,[144,1242,1243],{"class":592},"        headers",[144,1245,265],{"class":257},[144,1247,439],{"class":154},[144,1249,1250],{"class":261},",                   ",[144,1252,1253],{"class":173},"# Headers de autenticación + content-type\n",[144,1255,1257,1260,1262,1265],{"class":146,"line":1256},77,[144,1258,1259],{"class":592},"        json",[144,1261,265],{"class":257},[144,1263,1264],{"class":261},"payload                       ",[144,1266,1267],{"class":173},"# Serializa automáticamente a JSON\n",[144,1269,1271],{"class":146,"line":1270},78,[144,1272,1273],{"class":261},"    )\n",[144,1275,1277,1280],{"class":146,"line":1276},79,[144,1278,1279],{"class":261},"    response.raise_for_status()            ",[144,1281,1282],{"class":173},"# Lanza excepción si no es 200 OK\n",[144,1284,1286,1289,1291,1294],{"class":146,"line":1285},80,[144,1287,1288],{"class":261},"    task ",[144,1290,265],{"class":257},[144,1292,1293],{"class":261}," response.json()                 ",[144,1295,1296],{"class":173},"# Parsea la respuesta JSON\n",[144,1298,1300],{"class":146,"line":1299},81,[144,1301,356],{"emptyLinePlaceholder":57},[144,1303,1305],{"class":146,"line":1304},82,[144,1306,1307],{"class":173},"    # Registra información clave de la respuesta\n",[144,1309,1311,1313,1315,1317,1320,1322,1325,1328,1331,1333,1335],{"class":146,"line":1310},83,[144,1312,877],{"class":154},[144,1314,423],{"class":261},[144,1316,456],{"class":257},[144,1318,1319],{"class":158},"\"Tarea creada: ",[144,1321,576],{"class":154},[144,1323,1324],{"class":261},"task[",[144,1326,1327],{"class":158},"'id'",[144,1329,1330],{"class":261},"]",[144,1332,582],{"class":154},[144,1334,465],{"class":158},[144,1336,391],{"class":261},[144,1338,1340,1342,1344,1346,1349,1351,1353,1356,1359,1362,1364,1366,1369],{"class":146,"line":1339},84,[144,1341,877],{"class":154},[144,1343,423],{"class":261},[144,1345,456],{"class":257},[144,1347,1348],{"class":158},"\"Tiempo estimado: ",[144,1350,576],{"class":154},[144,1352,1324],{"class":261},[144,1354,1355],{"class":158},"'task_info'",[144,1357,1358],{"class":261},"][",[144,1360,1361],{"class":158},"'estimated_time'",[144,1363,1330],{"class":261},[144,1365,582],{"class":154},[144,1367,1368],{"class":158},"s\"",[144,1370,391],{"class":261},[144,1372,1374,1376,1378,1380,1383,1385,1387,1390,1392,1395,1397,1399,1401],{"class":146,"line":1373},85,[144,1375,877],{"class":154},[144,1377,423],{"class":261},[144,1379,456],{"class":257},[144,1381,1382],{"class":158},"\"Créditos reservados: ",[144,1384,576],{"class":154},[144,1386,1324],{"class":261},[144,1388,1389],{"class":158},"'usage'",[144,1391,1358],{"class":261},[144,1393,1394],{"class":158},"'credits_reserved'",[144,1396,1330],{"class":261},[144,1398,582],{"class":154},[144,1400,465],{"class":158},[144,1402,391],{"class":261},[144,1404,1406],{"class":146,"line":1405},86,[144,1407,356],{"emptyLinePlaceholder":57},[144,1409,1411],{"class":146,"line":1410},87,[144,1412,1413],{"class":173},"    # Realiza polling hasta que el video esté listo\n",[144,1415,1417,1420,1422,1425,1428],{"class":146,"line":1416},88,[144,1418,1419],{"class":261},"    result ",[144,1421,265],{"class":257},[144,1423,1424],{"class":261}," wait_for_video(task[",[144,1426,1427],{"class":158},"\"id\"",[144,1429,1430],{"class":261},"])\n",[144,1432,1434],{"class":146,"line":1433},89,[144,1435,356],{"emptyLinePlaceholder":57},[144,1437,1439],{"class":146,"line":1438},90,[144,1440,1441],{"class":173},"    # El array results contiene una o más URLs de video\n",[144,1443,1445,1448,1450,1453,1456,1458,1460],{"class":146,"line":1444},91,[144,1446,1447],{"class":261},"    video_url ",[144,1449,265],{"class":257},[144,1451,1452],{"class":261}," result[",[144,1454,1455],{"class":158},"\"results\"",[144,1457,1358],{"class":261},[144,1459,662],{"class":154},[144,1461,643],{"class":261},[144,1463,1465,1467,1469,1471,1473,1476,1479,1481,1484,1486,1488],{"class":146,"line":1464},92,[144,1466,877],{"class":154},[144,1468,423],{"class":261},[144,1470,456],{"class":257},[144,1472,465],{"class":158},[144,1474,1475],{"class":154},"\\n",[144,1477,1478],{"class":158},"URL del video: ",[144,1480,576],{"class":154},[144,1482,1483],{"class":261},"video_url",[144,1485,582],{"class":154},[144,1487,465],{"class":158},[144,1489,391],{"class":261},[144,1491,1493,1496,1499],{"class":146,"line":1492},93,[144,1494,1495],{"class":261},"    download_video(video_url, ",[144,1497,1498],{"class":158},"\"mi_primer_video.mp4\"",[144,1500,391],{"class":261},[144,1502,1504],{"class":146,"line":1503},94,[144,1505,356],{"emptyLinePlaceholder":57},[144,1507,1509,1512],{"class":146,"line":1508},95,[144,1510,1511],{"class":257},"    return",[144,1513,1514],{"class":261}," result\n",[144,1516,1518],{"class":146,"line":1517},96,[144,1519,356],{"emptyLinePlaceholder":57},[144,1521,1523],{"class":146,"line":1522},97,[144,1524,356],{"emptyLinePlaceholder":57},[144,1526,1528,1530,1533,1536,1539],{"class":146,"line":1527},98,[144,1529,402],{"class":257},[144,1531,1532],{"class":154}," __name__",[144,1534,1535],{"class":257}," ==",[144,1537,1538],{"class":158}," \"__main__\"",[144,1540,411],{"class":261},[144,1542,1544],{"class":146,"line":1543},99,[144,1545,1546],{"class":261},"    text_to_video()\n",[10,1548,1549],{},"Analicemos cada parámetro en el payload:",[96,1551,1552,1567,1580,1588,1608,1628],{},[72,1553,1554,1559,1560,1563,1564,1566],{},[22,1555,1556],{},[27,1557,1558],{},"model"," — Qué modelo de Seedance usar. Configure ",[27,1561,1562],{},"seedance-2.0"," para el más reciente; use ",[27,1565,29],{}," si 2.0 aún no está disponible en su región.",[72,1568,1569,1574,1575,1579],{},[22,1570,1571],{},[27,1572,1573],{},"prompt"," — Su descripción del video. Sea específico sobre el sujeto, acción, movimiento de cámara y ambiente. El prompt anterior usa una estructura de tres partes: sujeto (\"cachorro golden retriever\"), acción (\"persigue una mariposa\"), y cámara (\"plano de seguimiento suave\"). Para técnicas avanzadas de prompts, vea nuestra ",[36,1576,1578],{"href":1577},"/blog/seedance-2-prompt-guide","Guía de Ingeniería de Prompts",".",[72,1581,1582,1587],{},[22,1583,1584],{},[27,1585,1586],{},"duration"," — Duración del video en segundos (4–15). Videos más cortos se generan más rápido y cuestan menos créditos. Comience con 5 para pruebas.",[72,1589,1590,1595,1596,1599,1600,1603,1604,1607],{},[22,1591,1592],{},[27,1593,1594],{},"quality"," — Nivel de resolución. ",[27,1597,1598],{},"720p"," es el mejor balance de calidad y velocidad para desarrollo. Use ",[27,1601,1602],{},"480p"," para iteración rápida, ",[27,1605,1606],{},"1080p"," para renders finales.",[72,1609,1610,1615,1616,1619,1620,1623,1624,1627],{},[22,1611,1612],{},[27,1613,1614],{},"aspect_ratio"," — Dimensiones de salida. ",[27,1617,1618],{},"16:9"," para YouTube/horizontal, ",[27,1621,1622],{},"9:16"," para TikTok/Reels/Shorts, ",[27,1625,1626],{},"1:1"," para feed de Instagram.",[72,1629,1630,1635,1636,1639],{},[22,1631,1632],{},[27,1633,1634],{},"generate_audio"," — Cuando es ",[27,1637,1638],{},"true",", Seedance genera sonido ambiental y música que coincide con el contenido visual. Agrega ~2 segundos al tiempo de generación.",[10,1641,1642],{},"Ejecútelo:",[135,1644,1646],{"className":137,"code":1645,"language":139,"meta":140,"style":140},"python seedance_tutorial.py\n",[27,1647,1648],{"__ignoreMap":140},[144,1649,1650,1652],{"class":146,"line":147},[144,1651,327],{"class":150},[144,1653,1654],{"class":158}," seedance_tutorial.py\n",[91,1656,1658],{"id":1657},"qué-devuelve-la-api","Qué Devuelve la API",[10,1660,1661,1662,1665],{},"Cuando envía una solicitud de generación, recibe de vuelta un ",[22,1663,1664],{},"objeto de tarea"," inmediatamente — el video aún no está listo. Aquí está la respuesta real:",[135,1667,1671],{"className":1668,"code":1669,"language":1670,"meta":140,"style":140},"language-json shiki shiki-themes github-dark","{\n  \"created\": 1772203771,\n  \"id\": \"task-unified-1772203771-yf1dxogh\",\n  \"model\": \"seedance-2.0\",\n  \"object\": \"video.generation.task\",\n  \"progress\": 0,\n  \"status\": \"pending\",\n  \"task_info\": {\n    \"can_cancel\": true,\n    \"estimated_time\": 132\n  },\n  \"type\": \"video\",\n  \"usage\": {\n    \"billing_rule\": \"per_second\",\n    \"credits_reserved\": 17.784,\n    \"user_group\": \"default\"\n  }\n}\n","json",[27,1672,1673,1678,1690,1702,1713,1725,1736,1748,1756,1767,1777,1782,1794,1801,1813,1825,1835,1840],{"__ignoreMap":140},[144,1674,1675],{"class":146,"line":147},[144,1676,1677],{"class":261},"{\n",[144,1679,1680,1683,1685,1688],{"class":146,"line":165},[144,1681,1682],{"class":154},"  \"created\"",[144,1684,453],{"class":261},[144,1686,1687],{"class":154},"1772203771",[144,1689,468],{"class":261},[144,1691,1692,1695,1697,1700],{"class":146,"line":177},[144,1693,1694],{"class":154},"  \"id\"",[144,1696,453],{"class":261},[144,1698,1699],{"class":158},"\"task-unified-1772203771-yf1dxogh\"",[144,1701,468],{"class":261},[144,1703,1704,1707,1709,1711],{"class":146,"line":186},[144,1705,1706],{"class":154},"  \"model\"",[144,1708,453],{"class":261},[144,1710,1082],{"class":158},[144,1712,468],{"class":261},[144,1714,1715,1718,1720,1723],{"class":146,"line":359},[144,1716,1717],{"class":154},"  \"object\"",[144,1719,453],{"class":261},[144,1721,1722],{"class":158},"\"video.generation.task\"",[144,1724,468],{"class":261},[144,1726,1727,1730,1732,1734],{"class":146,"line":365},[144,1728,1729],{"class":154},"  \"progress\"",[144,1731,453],{"class":261},[144,1733,662],{"class":154},[144,1735,468],{"class":261},[144,1737,1738,1741,1743,1746],{"class":146,"line":377},[144,1739,1740],{"class":154},"  \"status\"",[144,1742,453],{"class":261},[144,1744,1745],{"class":158},"\"pending\"",[144,1747,468],{"class":261},[144,1749,1750,1753],{"class":146,"line":394},[144,1751,1752],{"class":154},"  \"task_info\"",[144,1754,1755],{"class":261},": {\n",[144,1757,1758,1761,1763,1765],{"class":146,"line":399},[144,1759,1760],{"class":154},"    \"can_cancel\"",[144,1762,453],{"class":261},[144,1764,1638],{"class":154},[144,1766,468],{"class":261},[144,1768,1769,1772,1774],{"class":146,"line":414},[144,1770,1771],{"class":154},"    \"estimated_time\"",[144,1773,453],{"class":261},[144,1775,1776],{"class":154},"132\n",[144,1778,1779],{"class":146,"line":431},[144,1780,1781],{"class":261},"  },\n",[144,1783,1784,1787,1789,1792],{"class":146,"line":436},[144,1785,1786],{"class":154},"  \"type\"",[144,1788,453],{"class":261},[144,1790,1791],{"class":158},"\"video\"",[144,1793,468],{"class":261},[144,1795,1796,1799],{"class":146,"line":447},[144,1797,1798],{"class":154},"  \"usage\"",[144,1800,1755],{"class":261},[144,1802,1803,1806,1808,1811],{"class":146,"line":471},[144,1804,1805],{"class":154},"    \"billing_rule\"",[144,1807,453],{"class":261},[144,1809,1810],{"class":158},"\"per_second\"",[144,1812,468],{"class":261},[144,1814,1815,1818,1820,1823],{"class":146,"line":482},[144,1816,1817],{"class":154},"    \"credits_reserved\"",[144,1819,453],{"class":261},[144,1821,1822],{"class":154},"17.784",[144,1824,468],{"class":261},[144,1826,1827,1830,1832],{"class":146,"line":488},[144,1828,1829],{"class":154},"    \"user_group\"",[144,1831,453],{"class":261},[144,1833,1834],{"class":158},"\"default\"\n",[144,1836,1837],{"class":146,"line":493},[144,1838,1839],{"class":261},"  }\n",[144,1841,1842],{"class":146,"line":498},[144,1843,485],{"class":261},[10,1845,1846],{},"Campos clave explicados:",[1848,1849,1850,1863],"table",{},[1851,1852,1853],"thead",{},[1854,1855,1856,1860],"tr",{},[1857,1858,1859],"th",{},"Campo",[1857,1861,1862],{},"Significado",[1864,1865,1866,1877,1901,1912,1922,1932,1945,1955],"tbody",{},[1854,1867,1868,1874],{},[1869,1870,1871],"td",{},[27,1872,1873],{},"id",[1869,1875,1876],{},"Su ID de tarea — úselo para verificar el estado y recuperar resultados",[1854,1878,1879,1883],{},[1869,1880,1881],{},[27,1882,717],{},[1869,1884,1885,1886,1889,1890,1893,1894,1897,1898],{},"Comienza como ",[27,1887,1888],{},"pending",", pasa a ",[27,1891,1892],{},"processing",", luego ",[27,1895,1896],{},"completed"," o ",[27,1899,1900],{},"failed",[1854,1902,1903,1907],{},[1869,1904,1905],{},[27,1906,727],{},[1869,1908,1909,1910],{},"Porcentaje 0–100. Se actualiza en tiempo real durante ",[27,1911,1892],{},[1854,1913,1914,1919],{},[1869,1915,1916],{},[27,1917,1918],{},"estimated_time",[1869,1920,1921],{},"Segundos aproximados hasta completarse (estimación del servidor)",[1854,1923,1924,1929],{},[1869,1925,1926],{},[27,1927,1928],{},"credits_reserved",[1869,1930,1931],{},"Créditos retenidos para este trabajo. Se reembolsan automáticamente si la tarea falla",[1854,1933,1934,1939],{},[1869,1935,1936],{},[27,1937,1938],{},"task_info.can_cancel",[1869,1940,1941,1942,1944],{},"Si puede cancelar esta tarea (siempre ",[27,1943,1638],{}," antes de completarse)",[1854,1946,1947,1952],{},[1869,1948,1949],{},[27,1950,1951],{},"created",[1869,1953,1954],{},"Timestamp Unix de cuando se envió la tarea",[1854,1956,1957,1962],{},[1869,1958,1959],{},[27,1960,1961],{},"usage.billing_rule",[1869,1963,1964,1965,1968],{},"Cómo se calculan los créditos — ",[27,1966,1967],{},"per_second"," significa que el costo escala con la duración",[17,1970,1971],{},[10,1972,1973,1975,1976,1978,1979,1982],{},[22,1974,132],{}," Guarde el ",[27,1977,1873],{}," en un archivo o base de datos inmediatamente después del envío. Si su script falla durante el polling, puede reanudar llamando a ",[27,1980,1981],{},"wait_for_video()"," con el ID de tarea guardado. Las tareas persisten en el servidor durante 24 horas.",[91,1984,1986],{"id":1985},"la-secuencia-de-polling","La Secuencia de Polling",[10,1988,1989,1990,1992],{},"La función ",[27,1991,1981],{}," realiza polling cada 10 segundos. Así se ve la salida real:",[135,1994,1999],{"className":1995,"code":1997,"language":1998},[1996],"language-text","Enviando solicitud de texto a video...\nTarea creada: task-unified-1772203771-yf1dxogh\nTiempo estimado: 132s\nCréditos reservados: 17.784\n  [0s] Estado: pending | Progreso: 0%\n  [10s] Estado: processing | Progreso: 7%\n  [20s] Estado: processing | Progreso: 13%\n  [30s] Estado: processing | Progreso: 20%\n  [40s] Estado: processing | Progreso: 27%\n  [50s] Estado: completed | Progreso: 100%\n\nURL del video: https://files.evolink.ai/.../cgt-20260227224931-8vl7s.mp4\nDescargando video a mi_primer_video.mp4...\nGuardado: mi_primer_video.mp4 (2847 KB)\n","text",[27,2000,1997],{"__ignoreMap":140},[10,2002,2003],{},"Eso es todo — aproximadamente 50 segundos desde la llamada a la API hasta el archivo de video en disco.",[17,2005,2006],{},[10,2007,2008,2011],{},[22,2009,2010],{},"Importante:"," Las URLs de video expiran después de 24 horas. Siempre descargue el archivo rápidamente o almacénelo en su propio almacenamiento (S3, GCS, Cloudflare R2, etc.).",[17,2013,2014],{},[10,2015,2016,2019],{},[22,2017,2018],{},"Error Común:"," No dependa de la URL del video para almacenamiento a largo plazo. Construya su pipeline para descargar inmediatamente después de completarse. Si procesa videos de forma asíncrona, use webhooks (cubiertos a continuación) para activar descargas en el momento en que estén listos.",[10,2021,2022,2023,2026],{},"Para consejos sobre cómo escribir prompts efectivos, vea la ",[36,2024,2025],{"href":1577},"Guía de Prompts de Seedance 2.0"," — cubre el formato de guion de tomas, palabras clave de estilo y sintaxis de temporización.",[44,2028],{},[47,2030,2032],{"id":2031},"realizar-polling-de-resultados-comprensión-del-flujo-de-trabajo-asíncrono","Realizar Polling de Resultados: Comprensión del Flujo de Trabajo Asíncrono",[10,2034,2035,2036,2039],{},"La generación de video toma entre 30 y 120 segundos o más dependiendo de la duración y calidad. La API usa un ",[22,2037,2038],{},"patrón de tarea asíncrona"," — el mismo patrón utilizado por OpenAI, Stability AI y la mayoría de las demás APIs de IA generativa:",[69,2041,2042,2052,2062],{},[72,2043,2044,2047,2048,2051],{},[22,2045,2046],{},"Enviar"," → POST a ",[27,2049,2050],{},"/v1/videos/generations"," → obtiene un ID de tarea instantáneamente",[72,2053,2054,2057,2058,2061],{},[22,2055,2056],{},"Polling"," → GET ",[27,2059,2060],{},"/v1/tasks/{task_id}"," → verifica el estado periódicamente",[72,2063,2064,2067,2068,2071,2072,2075],{},[22,2065,2066],{},"Recuperar"," → Cuando ",[27,2069,2070],{},"status: \"completed\"",", el array ",[27,2073,2074],{},"results"," contiene URLs de video",[10,2077,2078],{},"Este patrón existe porque la generación de video es computacionalmente costosa. Una solicitud HTTP síncrona expiraría mucho antes de que el video esté listo.",[91,2080,2082],{"id":2081},"ciclo-de-vida-del-estado-de-la-tarea","Ciclo de Vida del Estado de la Tarea",[135,2084,2087],{"className":2085,"code":2086,"language":1998},[1996],"pending → processing → completed\n                    ↘ failed\n",[27,2088,2086],{"__ignoreMap":140},[1848,2090,2091,2104],{},[1851,2092,2093],{},[1854,2094,2095,2098,2101],{},[1857,2096,2097],{},"Estado",[1857,2099,2100],{},"Qué Está Pasando",[1857,2102,2103],{},"Duración Típica",[1864,2105,2106,2118,2133,2148],{},[1854,2107,2108,2112,2115],{},[1869,2109,2110],{},[27,2111,1888],{},[1869,2113,2114],{},"La tarea está en cola, esperando recursos GPU",[1869,2116,2117],{},"0–30 segundos",[1854,2119,2120,2124,2130],{},[1869,2121,2122],{},[27,2123,1892],{},[1869,2125,2126,2127,2129],{},"El video se está generando — ",[27,2128,727],{}," se actualiza en tiempo real",[1869,2131,2132],{},"30–120 segundos",[1854,2134,2135,2139,2145],{},[1869,2136,2137],{},[27,2138,1896],{},[1869,2140,2141,2142,2144],{},"¡Listo! El array ",[27,2143,2074],{}," tiene su(s) URL(s) de video",[1869,2146,2147],{},"Estado terminal",[1854,2149,2150,2154,2157],{},[1869,2151,2152],{},[27,2153,1900],{},[1869,2155,2156],{},"Algo salió mal — revise los detalles del error",[1869,2158,2147],{},[91,2160,2162],{"id":2161},"mejores-prácticas-de-polling","Mejores Prácticas de Polling",[10,2164,2165,2168],{},[22,2166,2167],{},"Intervalo de polling:"," 10 segundos es un buen valor predeterminado. Hacer polling demasiado rápido desperdicia solicitudes y podría activar límites de tasa; demasiado lento retrasa su pipeline. Para aplicaciones donde el tiempo es crítico, puede hacer polling cada 5 segundos, pero no hay beneficio en ir más rápido que eso.",[10,2170,2171,2174],{},[22,2172,2173],{},"Timeout:"," Establezca un límite superior razonable basado en sus parámetros:",[1848,2176,2177,2190],{},[1851,2178,2179],{},[1854,2180,2181,2184,2187],{},[1857,2182,2183],{},"Configuración",[1857,2185,2186],{},"Tiempo Esperado",[1857,2188,2189],{},"Timeout Sugerido",[1864,2191,2192,2203,2214,2225],{},[1854,2193,2194,2197,2200],{},[1869,2195,2196],{},"4s, 480p",[1869,2198,2199],{},"20–40 segundos",[1869,2201,2202],{},"120 segundos",[1854,2204,2205,2208,2211],{},[1869,2206,2207],{},"5s, 720p",[1869,2209,2210],{},"30–60 segundos",[1869,2212,2213],{},"180 segundos",[1854,2215,2216,2219,2222],{},[1869,2217,2218],{},"10s, 720p",[1869,2220,2221],{},"60–90 segundos",[1869,2223,2224],{},"300 segundos",[1854,2226,2227,2230,2233],{},[1869,2228,2229],{},"15s, 1080p",[1869,2231,2232],{},"90–180 segundos",[1869,2234,2235],{},"600 segundos",[10,2237,2238,2241,2242,2244,2245,1579],{},[22,2239,2240],{},"Seguimiento del progreso:"," El campo ",[27,2243,727],{}," (0–100) le brinda retroalimentación granular — útil para construir barras de progreso en una UI. El progreso se actualiza aproximadamente cada 5–7 segundos durante la fase ",[27,2246,1892],{},[91,2248,2250],{"id":2249},"cancelar-una-tarea","Cancelar una Tarea",[10,2252,2253],{},"Si necesita detener una generación en progreso (prompt incorrecto, cambió de opinión), puede cancelarla:",[135,2255,2257],{"className":325,"code":2256,"language":327,"meta":140,"style":140},"def cancel_task(task_id):\n    \"\"\"Cancela una tarea pendiente o en procesamiento. Los créditos se reembolsan.\"\"\"\n    response = requests.post(\n        f\"{BASE_URL}/tasks/{task_id}/cancel\",\n        headers=HEADERS\n    )\n    if response.status_code == 200:\n        print(f\"Tarea {task_id} cancelada. Créditos reembolsados.\")\n    else:\n        print(f\"Cancelación fallida: {response.json()}\")\n",[27,2258,2259,2269,2274,2282,2303,2311,2315,2330,2352,2359],{"__ignoreMap":140},[144,2260,2261,2263,2266],{"class":146,"line":147},[144,2262,501],{"class":257},[144,2264,2265],{"class":150}," cancel_task",[144,2267,2268],{"class":261},"(task_id):\n",[144,2270,2271],{"class":146,"line":165},[144,2272,2273],{"class":158},"    \"\"\"Cancela una tarea pendiente o en procesamiento. Los créditos se reembolsan.\"\"\"\n",[144,2275,2276,2278,2280],{"class":146,"line":177},[144,2277,902],{"class":261},[144,2279,265],{"class":257},[144,2281,1218],{"class":261},[144,2283,2284,2286,2288,2290,2292,2294,2296,2298,2301],{"class":146,"line":186},[144,2285,1224],{"class":257},[144,2287,465],{"class":158},[144,2289,570],{"class":154},[144,2291,573],{"class":158},[144,2293,576],{"class":154},[144,2295,579],{"class":261},[144,2297,582],{"class":154},[144,2299,2300],{"class":158},"/cancel\"",[144,2302,468],{"class":261},[144,2304,2305,2307,2309],{"class":146,"line":359},[144,2306,1243],{"class":592},[144,2308,265],{"class":257},[144,2310,598],{"class":154},[144,2312,2313],{"class":146,"line":365},[144,2314,1273],{"class":261},[144,2316,2317,2320,2323,2325,2328],{"class":146,"line":377},[144,2318,2319],{"class":257},"    if",[144,2321,2322],{"class":261}," response.status_code ",[144,2324,751],{"class":257},[144,2326,2327],{"class":154}," 200",[144,2329,411],{"class":261},[144,2331,2332,2334,2336,2338,2341,2343,2345,2347,2350],{"class":146,"line":394},[144,2333,695],{"class":154},[144,2335,423],{"class":261},[144,2337,456],{"class":257},[144,2339,2340],{"class":158},"\"Tarea ",[144,2342,576],{"class":154},[144,2344,579],{"class":261},[144,2346,582],{"class":154},[144,2348,2349],{"class":158}," cancelada. Créditos reembolsados.\"",[144,2351,391],{"class":261},[144,2353,2354,2357],{"class":146,"line":399},[144,2355,2356],{"class":257},"    else",[144,2358,411],{"class":261},[144,2360,2361,2363,2365,2367,2370,2372,2375,2377,2379],{"class":146,"line":414},[144,2362,695],{"class":154},[144,2364,423],{"class":261},[144,2366,456],{"class":257},[144,2368,2369],{"class":158},"\"Cancelación fallida: ",[144,2371,576],{"class":154},[144,2373,2374],{"class":261},"response.json()",[144,2376,582],{"class":154},[144,2378,465],{"class":158},[144,2380,391],{"class":261},[10,2382,2383,2384,2386,2387,2389,2390,1897,2392,2394],{},"La cancelación funciona cuando ",[27,2385,1938],{}," es ",[27,2388,1638],{},". Una vez que una tarea alcanza ",[27,2391,1896],{},[27,2393,1900],{},", no puede cancelarse. Los créditos reservados se reembolsan automáticamente al cancelar.",[17,2396,2397],{},[10,2398,2399,2401],{},[22,2400,132],{}," Incorpore un mecanismo de cancelación en su UI desde el principio. Los usuarios inevitablemente enviarán prompts incorrectos, y esperar 2 minutos por un video malo desperdicia tanto tiempo como créditos.",[10,2403,1989,2404,2406,2407,2411],{},[27,2405,1981],{}," de nuestro código de configuración maneja el flujo estándar de polling. Si desea omitir el polling por completo, salte a la ",[36,2408,2410],{"href":2409},"#configurar-webhooks-omita-el-polling","sección de Webhooks"," a continuación.",[44,2413],{},[47,2415,2417],{"id":2416},"animar-una-imagen-imagen-a-video","Animar una Imagen (Imagen a Video)",[10,2419,2420,2421,2424,2425,2429],{},"¿Tiene una foto de producto, ilustración de personaje o paisaje que quiera darle vida? Pásela como ",[27,2422,2423],{},"image_url"," y Seedance la animará. Esta es una de las características más poderosas para ",[36,2426,2428],{"href":2427},"/blog/seedance-2-ecommerce-product-videos","videos de productos de e-commerce"," — tome una foto estática del producto y conviértala en un anuncio de video atractivo.",[10,2431,2432],{},[2433,2434,2435],"em",{},"Usa la misma configuración y función de polling del primer ejemplo anterior.",[135,2437,2439],{"className":325,"code":2438,"language":327,"meta":140,"style":140},"# ── Imagen a Video ────────────────────────────────────────────\ndef image_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"@Image1 as the first frame. La escena cobra vida lentamente \"\n            \"— las hojas se mecen suavemente, la luz suave se desplaza \"\n            \"por el encuadre, y el sujeto parpadea de forma natural.\"\n        ),\n        \"image_urls\": [\n            \"https://example.com/your-image.jpg\"\n        ],\n        \"duration\": 5,\n        \"quality\": \"720p\",\n        \"aspect_ratio\": \"16:9\"\n    }\n\n    print(\"Enviando solicitud de imagen a video...\")\n    response = requests.post(\n        f\"{BASE_URL}/videos/generations\",\n        headers=HEADERS,\n        json=payload\n    )\n    response.raise_for_status()\n    task = response.json()\n\n    print(f\"Tarea creada: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n\n    video_url = result[\"results\"][0]\n    download_video(video_url, \"imagen_animada.mp4\")\n\n    return result\n",[27,2440,2441,2446,2455,2463,2473,2479,2484,2489,2494,2498,2506,2511,2516,2526,2536,2545,2549,2553,2564,2572,2584,2594,2603,2607,2611,2619,2623,2647,2659,2663,2679,2688,2692],{"__ignoreMap":140},[144,2442,2443],{"class":146,"line":147},[144,2444,2445],{"class":173},"# ── Imagen a Video ────────────────────────────────────────────\n",[144,2447,2448,2450,2453],{"class":146,"line":165},[144,2449,501],{"class":257},[144,2451,2452],{"class":150}," image_to_video",[144,2454,1061],{"class":261},[144,2456,2457,2459,2461],{"class":146,"line":177},[144,2458,1067],{"class":261},[144,2460,265],{"class":257},[144,2462,444],{"class":261},[144,2464,2465,2467,2469,2471],{"class":146,"line":186},[144,2466,1077],{"class":158},[144,2468,453],{"class":261},[144,2470,1082],{"class":158},[144,2472,468],{"class":261},[144,2474,2475,2477],{"class":146,"line":359},[144,2476,1094],{"class":158},[144,2478,1097],{"class":261},[144,2480,2481],{"class":146,"line":365},[144,2482,2483],{"class":158},"            \"@Image1 as the first frame. La escena cobra vida lentamente \"\n",[144,2485,2486],{"class":146,"line":377},[144,2487,2488],{"class":158},"            \"— las hojas se mecen suavemente, la luz suave se desplaza \"\n",[144,2490,2491],{"class":146,"line":394},[144,2492,2493],{"class":158},"            \"por el encuadre, y el sujeto parpadea de forma natural.\"\n",[144,2495,2496],{"class":146,"line":399},[144,2497,1121],{"class":261},[144,2499,2500,2503],{"class":146,"line":414},[144,2501,2502],{"class":158},"        \"image_urls\"",[144,2504,2505],{"class":261},": [\n",[144,2507,2508],{"class":146,"line":431},[144,2509,2510],{"class":158},"            \"https://example.com/your-image.jpg\"\n",[144,2512,2513],{"class":146,"line":436},[144,2514,2515],{"class":261},"        ],\n",[144,2517,2518,2520,2522,2524],{"class":146,"line":447},[144,2519,1127],{"class":158},[144,2521,453],{"class":261},[144,2523,1132],{"class":154},[144,2525,468],{"class":261},[144,2527,2528,2530,2532,2534],{"class":146,"line":471},[144,2529,1144],{"class":158},[144,2531,453],{"class":261},[144,2533,1149],{"class":158},[144,2535,468],{"class":261},[144,2537,2538,2540,2542],{"class":146,"line":482},[144,2539,1161],{"class":158},[144,2541,453],{"class":261},[144,2543,2544],{"class":158},"\"16:9\"\n",[144,2546,2547],{"class":146,"line":488},[144,2548,1191],{"class":261},[144,2550,2551],{"class":146,"line":493},[144,2552,356],{"emptyLinePlaceholder":57},[144,2554,2555,2557,2559,2562],{"class":146,"line":498},[144,2556,877],{"class":154},[144,2558,423],{"class":261},[144,2560,2561],{"class":158},"\"Enviando solicitud de imagen a video...\"",[144,2563,391],{"class":261},[144,2565,2566,2568,2570],{"class":146,"line":518},[144,2567,902],{"class":261},[144,2569,265],{"class":257},[144,2571,1218],{"class":261},[144,2573,2574,2576,2578,2580,2582],{"class":146,"line":524},[144,2575,1224],{"class":257},[144,2577,465],{"class":158},[144,2579,570],{"class":154},[144,2581,1231],{"class":158},[144,2583,468],{"class":261},[144,2585,2586,2588,2590,2592],{"class":146,"line":535},[144,2587,1243],{"class":592},[144,2589,265],{"class":257},[144,2591,439],{"class":154},[144,2593,468],{"class":261},[144,2595,2596,2598,2600],{"class":146,"line":540},[144,2597,1259],{"class":592},[144,2599,265],{"class":257},[144,2601,2602],{"class":261},"payload\n",[144,2604,2605],{"class":146,"line":551},[144,2606,1273],{"class":261},[144,2608,2609],{"class":146,"line":562},[144,2610,923],{"class":261},[144,2612,2613,2615,2617],{"class":146,"line":589},[144,2614,1288],{"class":261},[144,2616,265],{"class":257},[144,2618,621],{"class":261},[144,2620,2621],{"class":146,"line":601},[144,2622,356],{"emptyLinePlaceholder":57},[144,2624,2625,2627,2629,2631,2633,2635,2637,2639,2641,2643,2645],{"class":146,"line":607},[144,2626,877],{"class":154},[144,2628,423],{"class":261},[144,2630,456],{"class":257},[144,2632,1319],{"class":158},[144,2634,576],{"class":154},[144,2636,1324],{"class":261},[144,2638,1327],{"class":158},[144,2640,1330],{"class":261},[144,2642,582],{"class":154},[144,2644,465],{"class":158},[144,2646,391],{"class":261},[144,2648,2649,2651,2653,2655,2657],{"class":146,"line":613},[144,2650,1419],{"class":261},[144,2652,265],{"class":257},[144,2654,1424],{"class":261},[144,2656,1427],{"class":158},[144,2658,1430],{"class":261},[144,2660,2661],{"class":146,"line":624},[144,2662,356],{"emptyLinePlaceholder":57},[144,2664,2665,2667,2669,2671,2673,2675,2677],{"class":146,"line":629},[144,2666,1447],{"class":261},[144,2668,265],{"class":257},[144,2670,1452],{"class":261},[144,2672,1455],{"class":158},[144,2674,1358],{"class":261},[144,2676,662],{"class":154},[144,2678,643],{"class":261},[144,2680,2681,2683,2686],{"class":146,"line":646},[144,2682,1495],{"class":261},[144,2684,2685],{"class":158},"\"imagen_animada.mp4\"",[144,2687,391],{"class":261},[144,2689,2690],{"class":146,"line":667},[144,2691,356],{"emptyLinePlaceholder":57},[144,2693,2694,2696],{"class":146,"line":687},[144,2695,1511],{"class":257},[144,2697,1514],{"class":261},[10,2699,2700],{},"Analicemos qué es diferente respecto a texto a video:",[96,2702,2703,2715,2735],{},[72,2704,2705,2710,2711,2714],{},[22,2706,2707],{},[27,2708,2709],{},"image_urls"," — Un array de URLs de imágenes públicamente accesibles. La API las recupera directamente, por lo que deben ser accesibles desde internet (no ",[27,2712,2713],{},"localhost"," o URLs de red privada).",[72,2716,2717,2723,2724,2726,2727,289,2729,289,2732,1579],{},[22,2718,2719,2722],{},[27,2720,2721],{},"@Image1"," en el prompt"," — Esta etiqueta le dice a Seedance qué imagen referenciar y cómo. Corresponde a la primera URL en ",[27,2725,2709],{},". Si pasa tres imágenes, usaría ",[27,2728,2721],{},[27,2730,2731],{},"@Image2",[27,2733,2734],{},"@Image3",[72,2736,2737,2742,2743,2745,2746,2749],{},[22,2738,2739,2740],{},"Sin ",[27,2741,1634],{}," — Omitido aquí, por lo que toma el valor ",[27,2744,1638],{}," por defecto. Puede configurarlo en ",[27,2747,2748],{},"false"," para animación silenciosa.",[91,2751,2753],{"id":2752},"cómo-funcionan-las-etiquetas-image","Cómo Funcionan las Etiquetas @Image",[10,2755,2756,2757,2759,2760,2762,2763,2765,2766,2769,2770,2773,2774,2777,2778,1579],{},"La etiqueta ",[27,2758,2721],{}," en su prompt le dice a Seedance cómo usar la imagen. Referencia la primera URL en el array ",[27,2761,2709],{},". Puede pasar hasta 9 imágenes (",[27,2764,2721],{}," a ",[27,2767,2768],{},"@Image9","). Para una guía completa sobre etiquetas multimodales incluyendo ",[27,2771,2772],{},"@Video"," y ",[27,2775,2776],{},"@Audio",", vea la ",[36,2779,2781],{"href":2780},"/blog/seedance-2-multimodal-tags-guide","Guía de @Tags Multimodal",[10,2783,2784],{},"Patrones comunes:",[1848,2786,2787,2800],{},[1851,2788,2789],{},[1854,2790,2791,2794,2797],{},[1857,2792,2793],{},"Patrón del Prompt",[1857,2795,2796],{},"Qué Hace",[1857,2798,2799],{},"Mejor Para",[1864,2801,2802,2815,2828,2841,2854],{},[1854,2803,2804,2809,2812],{},[1869,2805,2806],{},[27,2807,2808],{},"@Image1 as first frame",[1869,2810,2811],{},"Usa la imagen como fotograma de apertura",[1869,2813,2814],{},"Exhibiciones de productos, configuración de escena",[1854,2816,2817,2822,2825],{},[1869,2818,2819],{},[27,2820,2821],{},"@Image1 as last frame",[1869,2823,2824],{},"Usa la imagen como fotograma de cierre",[1869,2826,2827],{},"Revelaciones de logos, transiciones",[1854,2829,2830,2835,2838],{},[1869,2831,2832],{},[27,2833,2834],{},"@Image1 as character reference",[1869,2836,2837],{},"Mantiene la apariencia del personaje",[1869,2839,2840],{},"Personajes consistentes entre clips",[1854,2842,2843,2848,2851],{},[1869,2844,2845],{},[27,2846,2847],{},"@Image1 as style reference",[1869,2849,2850],{},"Aplica el estilo visual de la imagen",[1869,2852,2853],{},"Consistencia de marca, dirección de arte",[1854,2855,2856,2861,2864],{},[1869,2857,2858],{},[27,2859,2860],{},"@Image1 as first frame, @Image2 as last frame",[1869,2862,2863],{},"Crea una transición entre dos imágenes",[1869,2865,2866],{},"Antes/después, transformaciones",[10,2868,2869],{},"La respuesta real de nuestra prueba:",[135,2871,2873],{"className":1668,"code":2872,"language":1670,"meta":140,"style":140},"{\n  \"created\": 1772204037,\n  \"id\": \"task-unified-1772204036-lify8u5p\",\n  \"model\": \"seedance-2.0\",\n  \"object\": \"video.generation.task\",\n  \"progress\": 0,\n  \"status\": \"pending\",\n  \"task_info\": {\n    \"can_cancel\": true,\n    \"estimated_time\": 145\n  },\n  \"type\": \"video\",\n  \"usage\": {\n    \"billing_rule\": \"per_second\",\n    \"credits_reserved\": 17.784,\n    \"user_group\": \"default\"\n  }\n}\n",[27,2874,2875,2879,2890,2901,2911,2921,2931,2941,2947,2957,2966,2970,2980,2986,2996,3006,3014,3018],{"__ignoreMap":140},[144,2876,2877],{"class":146,"line":147},[144,2878,1677],{"class":261},[144,2880,2881,2883,2885,2888],{"class":146,"line":165},[144,2882,1682],{"class":154},[144,2884,453],{"class":261},[144,2886,2887],{"class":154},"1772204037",[144,2889,468],{"class":261},[144,2891,2892,2894,2896,2899],{"class":146,"line":177},[144,2893,1694],{"class":154},[144,2895,453],{"class":261},[144,2897,2898],{"class":158},"\"task-unified-1772204036-lify8u5p\"",[144,2900,468],{"class":261},[144,2902,2903,2905,2907,2909],{"class":146,"line":186},[144,2904,1706],{"class":154},[144,2906,453],{"class":261},[144,2908,1082],{"class":158},[144,2910,468],{"class":261},[144,2912,2913,2915,2917,2919],{"class":146,"line":359},[144,2914,1717],{"class":154},[144,2916,453],{"class":261},[144,2918,1722],{"class":158},[144,2920,468],{"class":261},[144,2922,2923,2925,2927,2929],{"class":146,"line":365},[144,2924,1729],{"class":154},[144,2926,453],{"class":261},[144,2928,662],{"class":154},[144,2930,468],{"class":261},[144,2932,2933,2935,2937,2939],{"class":146,"line":377},[144,2934,1740],{"class":154},[144,2936,453],{"class":261},[144,2938,1745],{"class":158},[144,2940,468],{"class":261},[144,2942,2943,2945],{"class":146,"line":394},[144,2944,1752],{"class":154},[144,2946,1755],{"class":261},[144,2948,2949,2951,2953,2955],{"class":146,"line":399},[144,2950,1760],{"class":154},[144,2952,453],{"class":261},[144,2954,1638],{"class":154},[144,2956,468],{"class":261},[144,2958,2959,2961,2963],{"class":146,"line":414},[144,2960,1771],{"class":154},[144,2962,453],{"class":261},[144,2964,2965],{"class":154},"145\n",[144,2967,2968],{"class":146,"line":431},[144,2969,1781],{"class":261},[144,2971,2972,2974,2976,2978],{"class":146,"line":436},[144,2973,1786],{"class":154},[144,2975,453],{"class":261},[144,2977,1791],{"class":158},[144,2979,468],{"class":261},[144,2981,2982,2984],{"class":146,"line":447},[144,2983,1798],{"class":154},[144,2985,1755],{"class":261},[144,2987,2988,2990,2992,2994],{"class":146,"line":471},[144,2989,1805],{"class":154},[144,2991,453],{"class":261},[144,2993,1810],{"class":158},[144,2995,468],{"class":261},[144,2997,2998,3000,3002,3004],{"class":146,"line":482},[144,2999,1817],{"class":154},[144,3001,453],{"class":261},[144,3003,1822],{"class":154},[144,3005,468],{"class":261},[144,3007,3008,3010,3012],{"class":146,"line":488},[144,3009,1829],{"class":154},[144,3011,453],{"class":261},[144,3013,1834],{"class":158},[144,3015,3016],{"class":146,"line":493},[144,3017,1839],{"class":261},[144,3019,3020],{"class":146,"line":498},[144,3021,485],{"class":261},[10,3023,3024,3025,3027],{},"Imagen a video sigue exactamente el mismo patrón asíncrono — enviar, polling, descargar. El ",[27,3026,1918],{}," es ligeramente más largo porque el modelo necesita analizar la imagen de entrada.",[91,3029,3031],{"id":3030},"requisitos-de-imagen","Requisitos de Imagen",[1848,3033,3034,3044],{},[1851,3035,3036],{},[1854,3037,3038,3041],{},[1857,3039,3040],{},"Restricción",[1857,3042,3043],{},"Valor",[1864,3045,3046,3054,3062,3070,3078],{},[1854,3047,3048,3051],{},[1869,3049,3050],{},"Máximo de imágenes",[1869,3052,3053],{},"9 por solicitud",[1854,3055,3056,3059],{},[1869,3057,3058],{},"Tamaño máximo de archivo",[1869,3060,3061],{},"30 MB por imagen",[1854,3063,3064,3067],{},[1869,3065,3066],{},"Formatos soportados",[1869,3068,3069],{},"JPEG, PNG, WebP, BMP, TIFF, GIF",[1854,3071,3072,3075],{},[1869,3073,3074],{},"Requisito de URL",[1869,3076,3077],{},"Debe ser públicamente accesible",[1854,3079,3080,3083],{},[1869,3081,3082],{},"Resolución recomendada",[1869,3084,3085],{},"Al menos 720px en el lado más corto",[17,3087,3088],{},[10,3089,3090,3092,3093,3095],{},[22,3091,2018],{}," Pasar una ruta de archivo local en lugar de una URL. El campo ",[27,3094,2709],{}," requiere URLs HTTP/HTTPS públicamente accesibles. Si sus imágenes son locales, súbalas primero a S3, Cloudflare R2 o incluso un servicio de alojamiento de archivos temporal.",[17,3097,3098],{},[10,3099,3100,3103],{},[22,3101,3102],{},"Restricción:"," Seedance no soporta subir imágenes de rostros humanos realistas. El sistema las rechaza automáticamente. Use personajes ilustrados o estilizados en su lugar.",[91,3105,3107],{"id":3106},"alojar-imágenes-para-la-api","Alojar Imágenes para la API",[10,3109,3110],{},"Si no tiene un CDN, aquí hay opciones rápidas para obtener una URL pública:",[135,3112,3114],{"className":325,"code":3113,"language":327,"meta":140,"style":140},"# Opción 1: Subir a S3 (si tiene AWS)\nimport boto3\ns3 = boto3.client('s3')\ns3.upload_file('imagen_local.jpg', 'mi-bucket', 'seedance/input.jpg')\nimage_url = f\"https://mi-bucket.s3.amazonaws.com/seedance/input.jpg\"\n\n# Opción 2: Usar una API de alojamiento de archivos temporal\n# Muchos servicios ofrecen alojamiento temporal gratuito para pruebas\n",[27,3115,3116,3121,3128,3143,3163,3176,3180,3185],{"__ignoreMap":140},[144,3117,3118],{"class":146,"line":147},[144,3119,3120],{"class":173},"# Opción 1: Subir a S3 (si tiene AWS)\n",[144,3122,3123,3125],{"class":146,"line":165},[144,3124,334],{"class":257},[144,3126,3127],{"class":261}," boto3\n",[144,3129,3130,3133,3135,3138,3141],{"class":146,"line":177},[144,3131,3132],{"class":261},"s3 ",[144,3134,265],{"class":257},[144,3136,3137],{"class":261}," boto3.client(",[144,3139,3140],{"class":158},"'s3'",[144,3142,391],{"class":261},[144,3144,3145,3148,3151,3153,3156,3158,3161],{"class":146,"line":186},[144,3146,3147],{"class":261},"s3.upload_file(",[144,3149,3150],{"class":158},"'imagen_local.jpg'",[144,3152,289],{"class":261},[144,3154,3155],{"class":158},"'mi-bucket'",[144,3157,289],{"class":261},[144,3159,3160],{"class":158},"'seedance/input.jpg'",[144,3162,391],{"class":261},[144,3164,3165,3168,3170,3173],{"class":146,"line":359},[144,3166,3167],{"class":261},"image_url ",[144,3169,265],{"class":257},[144,3171,3172],{"class":257}," f",[144,3174,3175],{"class":158},"\"https://mi-bucket.s3.amazonaws.com/seedance/input.jpg\"\n",[144,3177,3178],{"class":146,"line":365},[144,3179,356],{"emptyLinePlaceholder":57},[144,3181,3182],{"class":146,"line":377},[144,3183,3184],{"class":173},"# Opción 2: Usar una API de alojamiento de archivos temporal\n",[144,3186,3187],{"class":146,"line":394},[144,3188,3189],{"class":173},"# Muchos servicios ofrecen alojamiento temporal gratuito para pruebas\n",[10,3191,3192,3193,1579],{},"Para técnicas avanzadas de imagen a video — control de primer-último fotograma, composición multi-imagen y animación de productos de e-commerce — vea la ",[36,3194,3196],{"href":3195},"/blog/seedance-2-image-to-video-api","guía profunda de Imagen a Video",[44,3198],{},[47,3200,3202],{"id":3201},"personalice-sus-videos","Personalice Sus Videos",[10,3204,3205],{},"Cada parámetro que puede ajustar en una solicitud de generación:",[1848,3207,3208,3227],{},[1851,3209,3210],{},[1854,3211,3212,3215,3218,3221,3224],{},[1857,3213,3214],{},"Parámetro",[1857,3216,3217],{},"Tipo",[1857,3219,3220],{},"Por Defecto",[1857,3222,3223],{},"Opciones",[1857,3225,3226],{},"Descripción",[1864,3228,3229,3248,3264,3281,3304,3336,3358,3375,3392,3409],{},[1854,3230,3231,3235,3238,3241,3245],{},[1869,3232,3233],{},[27,3234,1558],{},[1869,3236,3237],{},"string",[1869,3239,3240],{},"—",[1869,3242,3243],{},[27,3244,1562],{},[1869,3246,3247],{},"Requerido. El modelo a usar.",[1854,3249,3250,3254,3256,3258,3261],{},[1869,3251,3252],{},[27,3253,1573],{},[1869,3255,3237],{},[1869,3257,3240],{},[1869,3259,3260],{},"≤2000 tokens",[1869,3262,3263],{},"Requerido. Descripción del video con @tags opcionales.",[1854,3265,3266,3270,3273,3275,3278],{},[1869,3267,3268],{},[27,3269,1586],{},[1869,3271,3272],{},"integer",[1869,3274,1132],{},[1869,3276,3277],{},"4–15",[1869,3279,3280],{},"Duración del video en segundos.",[1854,3282,3283,3287,3289,3293,3301],{},[1869,3284,3285],{},[27,3286,1594],{},[1869,3288,3237],{},[1869,3290,3291],{},[27,3292,1598],{},[1869,3294,3295,289,3297,289,3299],{},[27,3296,1602],{},[27,3298,1598],{},[27,3300,1606],{},[1869,3302,3303],{},"Nivel de resolución. Mayor = más créditos.",[1854,3305,3306,3310,3312,3316,3333],{},[1869,3307,3308],{},[27,3309,1614],{},[1869,3311,3237],{},[1869,3313,3314],{},[27,3315,1618],{},[1869,3317,3318,289,3320,289,3322,289,3324,289,3327,289,3330],{},[27,3319,1618],{},[27,3321,1622],{},[27,3323,1626],{},[27,3325,3326],{},"4:3",[27,3328,3329],{},"3:4",[27,3331,3332],{},"21:9",[1869,3334,3335],{},"Relación de aspecto de salida.",[1854,3337,3338,3342,3345,3349,3355],{},[1869,3339,3340],{},[27,3341,1634],{},[1869,3343,3344],{},"boolean",[1869,3346,3347],{},[27,3348,1638],{},[1869,3350,3351,289,3353],{},[27,3352,1638],{},[27,3354,2748],{},[1869,3356,3357],{},"Habilitar audio/música generado por IA.",[1854,3359,3360,3364,3367,3369,3372],{},[1869,3361,3362],{},[27,3363,2709],{},[1869,3365,3366],{},"array",[1869,3368,3240],{},[1869,3370,3371],{},"≤9 imágenes",[1869,3373,3374],{},"Imágenes de referencia. Use @Image1, @Image2... en el prompt.",[1854,3376,3377,3382,3384,3386,3389],{},[1869,3378,3379],{},[27,3380,3381],{},"video_urls",[1869,3383,3366],{},[1869,3385,3240],{},[1869,3387,3388],{},"≤3 videos",[1869,3390,3391],{},"Videos de referencia. Use @Video1, @Video2... en el prompt.",[1854,3393,3394,3399,3401,3403,3406],{},[1869,3395,3396],{},[27,3397,3398],{},"audio_urls",[1869,3400,3366],{},[1869,3402,3240],{},[1869,3404,3405],{},"≤3 archivos de audio",[1869,3407,3408],{},"Audio de referencia. Use @Audio1, @Audio2... en el prompt.",[1854,3410,3411,3416,3418,3420,3423],{},[1869,3412,3413],{},[27,3414,3415],{},"callback_url",[1869,3417,3237],{},[1869,3419,3240],{},[1869,3421,3422],{},"URL HTTPS",[1869,3424,3425],{},"Webhook para notificación de completado.",[17,3427,3428],{},[10,3429,3430,3433,3434,2773,3436,3438,3439,289,3441,3443,3444,2765,3446,3448,3449,3452],{},[22,3431,3432],{},"Nota Seedance 2.0 vs 1.5:"," Todos los parámetros anteriores funcionan con ",[27,3435,1562],{},[27,3437,29],{},". La diferencia clave: ",[27,3440,3381],{},[27,3442,3398],{}," y referencias multi-imagen (",[27,3445,2731],{},[27,3447,2768],{},") son características exclusivas de 2.0. Si las usa con 1.5, la API devuelve un error ",[27,3450,3451],{},"400"," con un mensaje claro indicando que la característica no está soportada.",[91,3454,3456],{"id":3455},"ejemplos-rápidos","Ejemplos Rápidos",[10,3458,3459],{},[22,3460,3461],{},"Video vertical para redes sociales (TikTok/Reels):",[10,3463,3464],{},[2433,3465,2435],{},[135,3467,3469],{"className":325,"code":3468,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Un barista vierte latte art en cámara lenta. Plano cenital cerrado.\",\n    \"duration\": 8,\n    \"quality\": \"1080p\",\n    \"aspect_ratio\": \"9:16\",       # Vertical para móvil\n    \"generate_audio\": True\n}\n",[27,3470,3471,3480,3491,3503,3515,3527,3543,3553],{"__ignoreMap":140},[144,3472,3473,3476,3478],{"class":146,"line":147},[144,3474,3475],{"class":261},"payload ",[144,3477,265],{"class":257},[144,3479,444],{"class":261},[144,3481,3482,3485,3487,3489],{"class":146,"line":165},[144,3483,3484],{"class":158},"    \"model\"",[144,3486,453],{"class":261},[144,3488,1082],{"class":158},[144,3490,468],{"class":261},[144,3492,3493,3496,3498,3501],{"class":146,"line":177},[144,3494,3495],{"class":158},"    \"prompt\"",[144,3497,453],{"class":261},[144,3499,3500],{"class":158},"\"Un barista vierte latte art en cámara lenta. Plano cenital cerrado.\"",[144,3502,468],{"class":261},[144,3504,3505,3508,3510,3513],{"class":146,"line":186},[144,3506,3507],{"class":158},"    \"duration\"",[144,3509,453],{"class":261},[144,3511,3512],{"class":154},"8",[144,3514,468],{"class":261},[144,3516,3517,3520,3522,3525],{"class":146,"line":359},[144,3518,3519],{"class":158},"    \"quality\"",[144,3521,453],{"class":261},[144,3523,3524],{"class":158},"\"1080p\"",[144,3526,468],{"class":261},[144,3528,3529,3532,3534,3537,3540],{"class":146,"line":365},[144,3530,3531],{"class":158},"    \"aspect_ratio\"",[144,3533,453],{"class":261},[144,3535,3536],{"class":158},"\"9:16\"",[144,3538,3539],{"class":261},",       ",[144,3541,3542],{"class":173},"# Vertical para móvil\n",[144,3544,3545,3548,3550],{"class":146,"line":377},[144,3546,3547],{"class":158},"    \"generate_audio\"",[144,3549,453],{"class":261},[144,3551,3552],{"class":154},"True\n",[144,3554,3555],{"class":146,"line":394},[144,3556,485],{"class":261},[10,3558,3559,3560,3562,3563,3565],{},"La relación de aspecto ",[27,3561,1622],{}," genera un video de 1080×1920 — resolución nativa para TikTok, Instagram Reels y YouTube Shorts. El nivel de calidad ",[27,3564,1606],{}," asegura visuales nítidos en pantallas móviles.",[10,3567,3568],{},[22,3569,3570],{},"Pantalla ancha cinematográfica con movimiento de cámara:",[135,3572,3574],{"className":325,"code":3573,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": (\n        \"Toma aérea con drone sobre una cordillera brumosa al amanecer. \"\n        \"La cámara avanza lentamente, revelando un valle oculto. \"\n        \"Gradación de color cinematográfica, iluminación volumétrica.\"\n    ),\n    \"duration\": 10,\n    \"quality\": \"1080p\",\n    \"aspect_ratio\": \"21:9\",       # Ultra-ancho cinematográfico\n    \"generate_audio\": True\n}\n",[27,3575,3576,3584,3594,3600,3605,3610,3615,3620,3630,3640,3654,3662],{"__ignoreMap":140},[144,3577,3578,3580,3582],{"class":146,"line":147},[144,3579,3475],{"class":261},[144,3581,265],{"class":257},[144,3583,444],{"class":261},[144,3585,3586,3588,3590,3592],{"class":146,"line":165},[144,3587,3484],{"class":158},[144,3589,453],{"class":261},[144,3591,1082],{"class":158},[144,3593,468],{"class":261},[144,3595,3596,3598],{"class":146,"line":177},[144,3597,3495],{"class":158},[144,3599,1097],{"class":261},[144,3601,3602],{"class":146,"line":186},[144,3603,3604],{"class":158},"        \"Toma aérea con drone sobre una cordillera brumosa al amanecer. \"\n",[144,3606,3607],{"class":146,"line":359},[144,3608,3609],{"class":158},"        \"La cámara avanza lentamente, revelando un valle oculto. \"\n",[144,3611,3612],{"class":146,"line":365},[144,3613,3614],{"class":158},"        \"Gradación de color cinematográfica, iluminación volumétrica.\"\n",[144,3616,3617],{"class":146,"line":377},[144,3618,3619],{"class":261},"    ),\n",[144,3621,3622,3624,3626,3628],{"class":146,"line":394},[144,3623,3507],{"class":158},[144,3625,453],{"class":261},[144,3627,512],{"class":154},[144,3629,468],{"class":261},[144,3631,3632,3634,3636,3638],{"class":146,"line":399},[144,3633,3519],{"class":158},[144,3635,453],{"class":261},[144,3637,3524],{"class":158},[144,3639,468],{"class":261},[144,3641,3642,3644,3646,3649,3651],{"class":146,"line":414},[144,3643,3531],{"class":158},[144,3645,453],{"class":261},[144,3647,3648],{"class":158},"\"21:9\"",[144,3650,3539],{"class":261},[144,3652,3653],{"class":173},"# Ultra-ancho cinematográfico\n",[144,3655,3656,3658,3660],{"class":146,"line":431},[144,3657,3547],{"class":158},[144,3659,453],{"class":261},[144,3661,3552],{"class":154},[144,3663,3664],{"class":146,"line":436},[144,3665,485],{"class":261},[10,3667,3668,3669,1579],{},"Para control programático de cámara — zooms dolly, tomas orbitales y movimientos estilo Hitchcock — vea la ",[36,3670,3672],{"href":3671},"/blog/seedance-2-camera-movement-api","Guía de API de Movimiento de Cámara",[10,3674,3675],{},[22,3676,3677],{},"Video silencioso para fondo de sitio web:",[135,3679,3681],{"className":325,"code":3680,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Partículas fluidas abstractas en azul profundo y dorado. Movimiento lento y meditativo.\",\n    \"duration\": 15,               # Duración máxima para bucles continuos\n    \"quality\": \"720p\",\n    \"aspect_ratio\": \"21:9\",       # Fondo ancho\n    \"generate_audio\": False       # Sin audio para fondos de reproducción automática\n}\n",[27,3682,3683,3691,3701,3712,3727,3737,3750,3762],{"__ignoreMap":140},[144,3684,3685,3687,3689],{"class":146,"line":147},[144,3686,3475],{"class":261},[144,3688,265],{"class":257},[144,3690,444],{"class":261},[144,3692,3693,3695,3697,3699],{"class":146,"line":165},[144,3694,3484],{"class":158},[144,3696,453],{"class":261},[144,3698,1082],{"class":158},[144,3700,468],{"class":261},[144,3702,3703,3705,3707,3710],{"class":146,"line":177},[144,3704,3495],{"class":158},[144,3706,453],{"class":261},[144,3708,3709],{"class":158},"\"Partículas fluidas abstractas en azul profundo y dorado. Movimiento lento y meditativo.\"",[144,3711,468],{"class":261},[144,3713,3714,3716,3718,3721,3724],{"class":146,"line":186},[144,3715,3507],{"class":158},[144,3717,453],{"class":261},[144,3719,3720],{"class":154},"15",[144,3722,3723],{"class":261},",               ",[144,3725,3726],{"class":173},"# Duración máxima para bucles continuos\n",[144,3728,3729,3731,3733,3735],{"class":146,"line":359},[144,3730,3519],{"class":158},[144,3732,453],{"class":261},[144,3734,1149],{"class":158},[144,3736,468],{"class":261},[144,3738,3739,3741,3743,3745,3747],{"class":146,"line":365},[144,3740,3531],{"class":158},[144,3742,453],{"class":261},[144,3744,3648],{"class":158},[144,3746,3539],{"class":261},[144,3748,3749],{"class":173},"# Fondo ancho\n",[144,3751,3752,3754,3756,3759],{"class":146,"line":377},[144,3753,3547],{"class":158},[144,3755,453],{"class":261},[144,3757,3758],{"class":154},"False",[144,3760,3761],{"class":173},"       # Sin audio para fondos de reproducción automática\n",[144,3763,3764],{"class":146,"line":394},[144,3765,485],{"class":261},[10,3767,3768],{},[22,3769,3770],{},"Borrador económico (iteración rápida):",[135,3772,3774],{"className":325,"code":3773,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Un gato con gafas de sol sentado frente a una mesa de DJ. Iluminación de club de neón.\",\n    \"duration\": 4,                # Duración mínima = generación más rápida\n    \"quality\": \"480p\",            # Calidad más baja = créditos más baratos\n    \"aspect_ratio\": \"16:9\"\n}\n",[27,3775,3776,3784,3794,3805,3820,3834,3842],{"__ignoreMap":140},[144,3777,3778,3780,3782],{"class":146,"line":147},[144,3779,3475],{"class":261},[144,3781,265],{"class":257},[144,3783,444],{"class":261},[144,3785,3786,3788,3790,3792],{"class":146,"line":165},[144,3787,3484],{"class":158},[144,3789,453],{"class":261},[144,3791,1082],{"class":158},[144,3793,468],{"class":261},[144,3795,3796,3798,3800,3803],{"class":146,"line":177},[144,3797,3495],{"class":158},[144,3799,453],{"class":261},[144,3801,3802],{"class":158},"\"Un gato con gafas de sol sentado frente a una mesa de DJ. Iluminación de club de neón.\"",[144,3804,468],{"class":261},[144,3806,3807,3809,3811,3814,3817],{"class":146,"line":186},[144,3808,3507],{"class":158},[144,3810,453],{"class":261},[144,3812,3813],{"class":154},"4",[144,3815,3816],{"class":261},",                ",[144,3818,3819],{"class":173},"# Duración mínima = generación más rápida\n",[144,3821,3822,3824,3826,3829,3831],{"class":146,"line":359},[144,3823,3519],{"class":158},[144,3825,453],{"class":261},[144,3827,3828],{"class":158},"\"480p\"",[144,3830,1169],{"class":261},[144,3832,3833],{"class":173},"# Calidad más baja = créditos más baratos\n",[144,3835,3836,3838,3840],{"class":146,"line":365},[144,3837,3531],{"class":158},[144,3839,453],{"class":261},[144,3841,2544],{"class":158},[144,3843,3844],{"class":146,"line":377},[144,3845,485],{"class":261},[17,3847,3848],{},[10,3849,3850,3852,3853,2773,3856,3859,3860,3862],{},[22,3851,132],{}," Durante el desarrollo, use siempre ",[27,3854,3855],{},"duration: 4",[27,3857,3858],{},"quality: \"480p\"",". Esta es la combinación más barata y rápida — ideal para iterar en prompts. Una vez satisfecho con el contenido, renderice la versión final en ",[27,3861,1606],{}," con la duración deseada.",[91,3864,3866],{"id":3865},"estimación-del-costo-en-créditos","Estimación del Costo en Créditos",[10,3868,3869],{},"Los créditos escalan con la duración y calidad. Aquí hay una guía aproximada:",[1848,3871,3872,3891],{},[1851,3873,3874],{},[1854,3875,3876,3879,3882,3885,3888],{},[1857,3877,3878],{},"Calidad",[1857,3880,3881],{},"4s",[1857,3883,3884],{},"5s",[1857,3886,3887],{},"10s",[1857,3889,3890],{},"15s",[1864,3892,3893,3909,3925],{},[1854,3894,3895,3897,3900,3903,3906],{},[1869,3896,1602],{},[1869,3898,3899],{},"~8",[1869,3901,3902],{},"~10",[1869,3904,3905],{},"~20",[1869,3907,3908],{},"~30",[1854,3910,3911,3913,3916,3919,3922],{},[1869,3912,1598],{},[1869,3914,3915],{},"~14",[1869,3917,3918],{},"~18",[1869,3920,3921],{},"~36",[1869,3923,3924],{},"~53",[1854,3926,3927,3929,3932,3935,3938],{},[1869,3928,1606],{},[1869,3930,3931],{},"~22",[1869,3933,3934],{},"~28",[1869,3936,3937],{},"~55",[1869,3939,3940],{},"~83",[10,3942,3943],{},[2433,3944,3945,3946,3948,3949,3953],{},"Créditos aproximados. Los costos reales se muestran en el campo ",[27,3947,1928],{},". Consulte el ",[36,3950,3952],{"href":210,"rel":3951},[40],"panel de EvoLink"," para las tarifas actuales.",[10,3955,3956,3957,289,3960,289,3962,3964,3965,3968,3969,1579],{},"El sistema de referencias multimodales — etiquetas ",[27,3958,3959],{},"@Image",[27,3961,2772],{},[27,3963,2776],{}," — es donde Seedance 2.0 realmente brilla. Puede replicar ",[36,3966,3967],{"href":3671},"movimientos de cámara"," de videos de referencia, mantener consistencia de personajes entre tomas y sincronizar con ritmos de audio. Para una guía completa, lea ",[36,3970,3971],{"href":2780},"La Guía Definitiva de @Tags",[44,3973],{},[47,3975,3977],{"id":3976},"manejar-errores-con-elegancia","Manejar Errores con Elegancia",[10,3979,3980],{},"Las llamadas a la API fallan. Las redes se caen. Los límites de tasa se alcanzan. Así es como construir código resiliente que maneje cada escenario de error real.",[91,3982,3984],{"id":3983},"respuestas-de-error-comunes","Respuestas de Error Comunes",[10,3986,3987],{},"Cada error sigue el mismo formato:",[135,3989,3991],{"className":1668,"code":3990,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"descripción de qué salió mal\",\n    \"type\": \"categoría_del_error\",\n    \"code\": \"código_de_error_específico\"\n  }\n}\n",[27,3992,3993,3997,4004,4016,4028,4038,4042],{"__ignoreMap":140},[144,3994,3995],{"class":146,"line":147},[144,3996,1677],{"class":261},[144,3998,3999,4002],{"class":146,"line":165},[144,4000,4001],{"class":154},"  \"error\"",[144,4003,1755],{"class":261},[144,4005,4006,4009,4011,4014],{"class":146,"line":177},[144,4007,4008],{"class":154},"    \"message\"",[144,4010,453],{"class":261},[144,4012,4013],{"class":158},"\"descripción de qué salió mal\"",[144,4015,468],{"class":261},[144,4017,4018,4021,4023,4026],{"class":146,"line":186},[144,4019,4020],{"class":154},"    \"type\"",[144,4022,453],{"class":261},[144,4024,4025],{"class":158},"\"categoría_del_error\"",[144,4027,468],{"class":261},[144,4029,4030,4033,4035],{"class":146,"line":359},[144,4031,4032],{"class":154},"    \"code\"",[144,4034,453],{"class":261},[144,4036,4037],{"class":158},"\"código_de_error_específico\"\n",[144,4039,4040],{"class":146,"line":365},[144,4041,1839],{"class":261},[144,4043,4044],{"class":146,"line":377},[144,4045,485],{"class":261},[10,4047,4048,4049,4052,4053,2773,4056,4059,4060,4062,4063,4065,4066,4068],{},"El objeto ",[27,4050,4051],{},"error"," siempre contiene ",[27,4054,4055],{},"message",[27,4057,4058],{},"type",". El campo ",[27,4061,27],{}," está presente para la mayoría de los errores pero no todos. Siempre verifique ",[27,4064,4058],{}," primero, luego ",[27,4067,27],{}," para detalles específicos.",[10,4070,4071],{},"Aquí están las respuestas de error reales de la API:",[10,4073,4074],{},[22,4075,4076],{},"401 — Clave API Inválida:",[135,4078,4080],{"className":1668,"code":4079,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Invalid token (request id: 20260227225245660301729AApJNAhJ)\",\n    \"type\": \"evo_api_error\"\n  }\n}\n",[27,4081,4082,4086,4092,4103,4112,4116],{"__ignoreMap":140},[144,4083,4084],{"class":146,"line":147},[144,4085,1677],{"class":261},[144,4087,4088,4090],{"class":146,"line":165},[144,4089,4001],{"class":154},[144,4091,1755],{"class":261},[144,4093,4094,4096,4098,4101],{"class":146,"line":177},[144,4095,4008],{"class":154},[144,4097,453],{"class":261},[144,4099,4100],{"class":158},"\"Invalid token (request id: 20260227225245660301729AApJNAhJ)\"",[144,4102,468],{"class":261},[144,4104,4105,4107,4109],{"class":146,"line":186},[144,4106,4020],{"class":154},[144,4108,453],{"class":261},[144,4110,4111],{"class":158},"\"evo_api_error\"\n",[144,4113,4114],{"class":146,"line":359},[144,4115,1839],{"class":261},[144,4117,4118],{"class":146,"line":365},[144,4119,485],{"class":261},[10,4121,4122,4123,4126],{},"Esto significa que su clave API es incorrecta, expiró o fue revocada. Verifique dos veces la variable de entorno ",[27,4124,4125],{},"EVOLINK_API_KEY",". Una causa común: copiar la clave con espacios en blanco al final.",[10,4128,4129],{},[22,4130,4131],{},"400 — Campo Requerido Faltante:",[135,4133,4135],{"className":1668,"code":4134,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"prompt cannot be empty\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4136,4137,4141,4147,4158,4169,4178,4182],{"__ignoreMap":140},[144,4138,4139],{"class":146,"line":147},[144,4140,1677],{"class":261},[144,4142,4143,4145],{"class":146,"line":165},[144,4144,4001],{"class":154},[144,4146,1755],{"class":261},[144,4148,4149,4151,4153,4156],{"class":146,"line":177},[144,4150,4032],{"class":154},[144,4152,453],{"class":261},[144,4154,4155],{"class":158},"\"invalid_parameter\"",[144,4157,468],{"class":261},[144,4159,4160,4162,4164,4167],{"class":146,"line":186},[144,4161,4008],{"class":154},[144,4163,453],{"class":261},[144,4165,4166],{"class":158},"\"prompt cannot be empty\"",[144,4168,468],{"class":261},[144,4170,4171,4173,4175],{"class":146,"line":359},[144,4172,4020],{"class":154},[144,4174,453],{"class":261},[144,4176,4177],{"class":158},"\"invalid_request_error\"\n",[144,4179,4180],{"class":146,"line":365},[144,4181,1839],{"class":261},[144,4183,4184],{"class":146,"line":377},[144,4185,485],{"class":261},[10,4187,4188,4189,4191],{},"El campo ",[27,4190,1573],{}," es requerido para todas las solicitudes de generación. Esto también se activa si pasa una cadena vacía o un prompt con solo espacios en blanco.",[10,4193,4194],{},[22,4195,4196],{},"400 — Valor de Parámetro Inválido:",[135,4198,4200],{"className":1668,"code":4199,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"duration must be between 4 and 15\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4201,4202,4206,4212,4222,4233,4241,4245],{"__ignoreMap":140},[144,4203,4204],{"class":146,"line":147},[144,4205,1677],{"class":261},[144,4207,4208,4210],{"class":146,"line":165},[144,4209,4001],{"class":154},[144,4211,1755],{"class":261},[144,4213,4214,4216,4218,4220],{"class":146,"line":177},[144,4215,4032],{"class":154},[144,4217,453],{"class":261},[144,4219,4155],{"class":158},[144,4221,468],{"class":261},[144,4223,4224,4226,4228,4231],{"class":146,"line":186},[144,4225,4008],{"class":154},[144,4227,453],{"class":261},[144,4229,4230],{"class":158},"\"duration must be between 4 and 15\"",[144,4232,468],{"class":261},[144,4234,4235,4237,4239],{"class":146,"line":359},[144,4236,4020],{"class":154},[144,4238,453],{"class":261},[144,4240,4177],{"class":158},[144,4242,4243],{"class":146,"line":365},[144,4244,1839],{"class":261},[144,4246,4247],{"class":146,"line":377},[144,4248,485],{"class":261},[10,4250,4251,4252,1897,4255,4258],{},"Ocurre cuando pasa ",[27,4253,4254],{},"duration: 3",[27,4256,4257],{},"duration: 20",". El rango válido es de 4 a 15 segundos inclusive.",[10,4260,4261],{},[22,4262,4263],{},"400 — Nivel de Calidad No Soportado:",[135,4265,4267],{"className":1668,"code":4266,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"quality must be one of: 480p, 720p, 1080p\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4268,4269,4273,4279,4289,4300,4308,4312],{"__ignoreMap":140},[144,4270,4271],{"class":146,"line":147},[144,4272,1677],{"class":261},[144,4274,4275,4277],{"class":146,"line":165},[144,4276,4001],{"class":154},[144,4278,1755],{"class":261},[144,4280,4281,4283,4285,4287],{"class":146,"line":177},[144,4282,4032],{"class":154},[144,4284,453],{"class":261},[144,4286,4155],{"class":158},[144,4288,468],{"class":261},[144,4290,4291,4293,4295,4298],{"class":146,"line":186},[144,4292,4008],{"class":154},[144,4294,453],{"class":261},[144,4296,4297],{"class":158},"\"quality must be one of: 480p, 720p, 1080p\"",[144,4299,468],{"class":261},[144,4301,4302,4304,4306],{"class":146,"line":359},[144,4303,4020],{"class":154},[144,4305,453],{"class":261},[144,4307,4177],{"class":158},[144,4309,4310],{"class":146,"line":365},[144,4311,1839],{"class":261},[144,4313,4314],{"class":146,"line":377},[144,4315,485],{"class":261},[10,4317,4318,4319,1897,4322,4325,4326,289,4328,1897,4330,1579],{},"Común cuando se pasa ",[27,4320,4321],{},"\"quality\": \"4k\"",[27,4323,4324],{},"\"quality\": \"hd\"",". Use las cadenas exactas: ",[27,4327,1602],{},[27,4329,1598],{},[27,4331,1606],{},[10,4333,4334],{},[22,4335,4336],{},"402 — Créditos Insuficientes:",[135,4338,4340],{"className":1668,"code":4339,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Insufficient credits. Required: 17.784, Available: 2.100\",\n    \"type\": \"insufficient_quota_error\"\n  }\n}\n",[27,4341,4342,4346,4352,4363,4372,4376],{"__ignoreMap":140},[144,4343,4344],{"class":146,"line":147},[144,4345,1677],{"class":261},[144,4347,4348,4350],{"class":146,"line":165},[144,4349,4001],{"class":154},[144,4351,1755],{"class":261},[144,4353,4354,4356,4358,4361],{"class":146,"line":177},[144,4355,4008],{"class":154},[144,4357,453],{"class":261},[144,4359,4360],{"class":158},"\"Insufficient credits. Required: 17.784, Available: 2.100\"",[144,4362,468],{"class":261},[144,4364,4365,4367,4369],{"class":146,"line":186},[144,4366,4020],{"class":154},[144,4368,453],{"class":261},[144,4370,4371],{"class":158},"\"insufficient_quota_error\"\n",[144,4373,4374],{"class":146,"line":359},[144,4375,1839],{"class":261},[144,4377,4378],{"class":146,"line":365},[144,4379,485],{"class":261},[10,4381,4382,4383,1579],{},"Su cuenta no tiene suficientes créditos. El mensaje le dice exactamente cuántos necesita versus cuántos tiene. Recargue en el ",[36,4384,3952],{"href":210,"rel":4385},[40],[10,4387,4388],{},[22,4389,4390],{},"404 — Tarea No Encontrada:",[135,4392,4394],{"className":1668,"code":4393,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Task not found\",\n    \"type\": \"invalid_request_error\",\n    \"code\": \"task_not_found\"\n  }\n}\n",[27,4395,4396,4400,4406,4417,4428,4437,4441],{"__ignoreMap":140},[144,4397,4398],{"class":146,"line":147},[144,4399,1677],{"class":261},[144,4401,4402,4404],{"class":146,"line":165},[144,4403,4001],{"class":154},[144,4405,1755],{"class":261},[144,4407,4408,4410,4412,4415],{"class":146,"line":177},[144,4409,4008],{"class":154},[144,4411,453],{"class":261},[144,4413,4414],{"class":158},"\"Task not found\"",[144,4416,468],{"class":261},[144,4418,4419,4421,4423,4426],{"class":146,"line":186},[144,4420,4020],{"class":154},[144,4422,453],{"class":261},[144,4424,4425],{"class":158},"\"invalid_request_error\"",[144,4427,468],{"class":261},[144,4429,4430,4432,4434],{"class":146,"line":359},[144,4431,4032],{"class":154},[144,4433,453],{"class":261},[144,4435,4436],{"class":158},"\"task_not_found\"\n",[144,4438,4439],{"class":146,"line":365},[144,4440,1839],{"class":261},[144,4442,4443],{"class":146,"line":377},[144,4444,485],{"class":261},[10,4446,4447,4448,4450],{},"Generalmente significa que el ID de tarea es incorrecto, o la tarea fue creada hace más de 24 horas (las tareas expiran). Verifique dos veces que está usando el campo ",[27,4449,1873],{}," de la respuesta de creación, no algún otro campo.",[10,4452,4453],{},[22,4454,4455],{},"413 — Imagen Demasiado Grande:",[135,4457,4459],{"className":1668,"code":4458,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Image file size exceeds 30MB limit\",\n    \"type\": \"request_too_large_error\"\n  }\n}\n",[27,4460,4461,4465,4471,4482,4491,4495],{"__ignoreMap":140},[144,4462,4463],{"class":146,"line":147},[144,4464,1677],{"class":261},[144,4466,4467,4469],{"class":146,"line":165},[144,4468,4001],{"class":154},[144,4470,1755],{"class":261},[144,4472,4473,4475,4477,4480],{"class":146,"line":177},[144,4474,4008],{"class":154},[144,4476,453],{"class":261},[144,4478,4479],{"class":158},"\"Image file size exceeds 30MB limit\"",[144,4481,468],{"class":261},[144,4483,4484,4486,4488],{"class":146,"line":186},[144,4485,4020],{"class":154},[144,4487,453],{"class":261},[144,4489,4490],{"class":158},"\"request_too_large_error\"\n",[144,4492,4493],{"class":146,"line":359},[144,4494,1839],{"class":261},[144,4496,4497],{"class":146,"line":365},[144,4498,485],{"class":261},[10,4500,4501],{},"Comprima su imagen antes de subirla. Para la API, la calidad visual por encima de 2–3 MB rara vez mejora los resultados.",[10,4503,4504],{},[22,4505,4506],{},"429 — Límite de Tasa Alcanzado:",[135,4508,4510],{"className":1668,"code":4509,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Rate limit exceeded. Please retry after 60 seconds.\",\n    \"type\": \"rate_limit_error\"\n  }\n}\n",[27,4511,4512,4516,4522,4533,4542,4546],{"__ignoreMap":140},[144,4513,4514],{"class":146,"line":147},[144,4515,1677],{"class":261},[144,4517,4518,4520],{"class":146,"line":165},[144,4519,4001],{"class":154},[144,4521,1755],{"class":261},[144,4523,4524,4526,4528,4531],{"class":146,"line":177},[144,4525,4008],{"class":154},[144,4527,453],{"class":261},[144,4529,4530],{"class":158},"\"Rate limit exceeded. Please retry after 60 seconds.\"",[144,4532,468],{"class":261},[144,4534,4535,4537,4539],{"class":146,"line":186},[144,4536,4020],{"class":154},[144,4538,453],{"class":261},[144,4540,4541],{"class":158},"\"rate_limit_error\"\n",[144,4543,4544],{"class":146,"line":359},[144,4545,1839],{"class":261},[144,4547,4548],{"class":146,"line":365},[144,4549,485],{"class":261},[10,4551,4552],{},"Está enviando demasiadas solicitudes. El límite predeterminado es generoso para desarrollo, pero los scripts de procesamiento por lotes pueden alcanzarlo. Implemente retroceso exponencial (ver a continuación).",[10,4554,4555],{},[22,4556,4557],{},"422 — Rechazo por Moderación de Contenido:",[135,4559,4561],{"className":1668,"code":4560,"language":1670,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Content rejected by safety filter\",\n    \"type\": \"content_policy_violation\",\n    \"code\": \"content_filtered\"\n  }\n}\n",[27,4562,4563,4567,4573,4584,4595,4604,4608],{"__ignoreMap":140},[144,4564,4565],{"class":146,"line":147},[144,4566,1677],{"class":261},[144,4568,4569,4571],{"class":146,"line":165},[144,4570,4001],{"class":154},[144,4572,1755],{"class":261},[144,4574,4575,4577,4579,4582],{"class":146,"line":177},[144,4576,4008],{"class":154},[144,4578,453],{"class":261},[144,4580,4581],{"class":158},"\"Content rejected by safety filter\"",[144,4583,468],{"class":261},[144,4585,4586,4588,4590,4593],{"class":146,"line":186},[144,4587,4020],{"class":154},[144,4589,453],{"class":261},[144,4591,4592],{"class":158},"\"content_policy_violation\"",[144,4594,468],{"class":261},[144,4596,4597,4599,4601],{"class":146,"line":359},[144,4598,4032],{"class":154},[144,4600,453],{"class":261},[144,4602,4603],{"class":158},"\"content_filtered\"\n",[144,4605,4606],{"class":146,"line":365},[144,4607,1839],{"class":261},[144,4609,4610],{"class":146,"line":377},[144,4611,485],{"class":261},[10,4613,4614,4615,4617],{},"Su prompt o imágenes de entrada activaron el sistema de moderación de contenido. Reformule su prompt para evitar contenido restringido. Los rostros humanos realistas en ",[27,4616,2709],{}," son rechazados automáticamente.",[91,4619,4621],{"id":4620},"tabla-de-referencia-de-errores","Tabla de Referencia de Errores",[1848,4623,4624,4641],{},[1851,4625,4626],{},[1854,4627,4628,4631,4633,4635,4638],{},[1857,4629,4630],{},"Código HTTP",[1857,4632,3217],{},[1857,4634,1862],{},[1857,4636,4637],{},"¿Reintentable?",[1857,4639,4640],{},"Acción",[1864,4642,4643,4661,4679,4697,4715,4733,4751,4772,4792,4812],{},[1854,4644,4645,4647,4652,4655,4658],{},[1869,4646,3451],{},[1869,4648,4649],{},[27,4650,4651],{},"invalid_request_error",[1869,4653,4654],{},"Parámetros incorrectos",[1869,4656,4657],{},"No",[1869,4659,4660],{},"Corrija su payload",[1854,4662,4663,4666,4671,4674,4676],{},[1869,4664,4665],{},"401",[1869,4667,4668],{},[27,4669,4670],{},"authentication_error",[1869,4672,4673],{},"Clave API inválida",[1869,4675,4657],{},[1869,4677,4678],{},"Verifique su clave",[1854,4680,4681,4684,4689,4692,4694],{},[1869,4682,4683],{},"402",[1869,4685,4686],{},[27,4687,4688],{},"insufficient_quota_error",[1869,4690,4691],{},"Sin créditos",[1869,4693,4657],{},[1869,4695,4696],{},"Recargue su cuenta",[1854,4698,4699,4702,4707,4710,4712],{},[1869,4700,4701],{},"404",[1869,4703,4704],{},[27,4705,4706],{},"not_found_error",[1869,4708,4709],{},"Tarea o modelo no encontrado",[1869,4711,4657],{},[1869,4713,4714],{},"Verifique task_id / nombre del modelo",[1854,4716,4717,4720,4725,4728,4730],{},[1869,4718,4719],{},"413",[1869,4721,4722],{},[27,4723,4724],{},"request_too_large_error",[1869,4726,4727],{},"Payload demasiado grande",[1869,4729,4657],{},[1869,4731,4732],{},"Reduzca tamaños de archivo",[1854,4734,4735,4738,4743,4746,4748],{},[1869,4736,4737],{},"422",[1869,4739,4740],{},[27,4741,4742],{},"content_policy_violation",[1869,4744,4745],{},"Contenido filtrado",[1869,4747,4657],{},[1869,4749,4750],{},"Reformule el prompt",[1854,4752,4753,4756,4761,4764,4769],{},[1869,4754,4755],{},"429",[1869,4757,4758],{},[27,4759,4760],{},"rate_limit_error",[1869,4762,4763],{},"Demasiadas solicitudes",[1869,4765,4766],{},[22,4767,4768],{},"Sí",[1869,4770,4771],{},"Espere 60s, reintente",[1854,4773,4774,4777,4782,4785,4789],{},[1869,4775,4776],{},"500",[1869,4778,4779],{},[27,4780,4781],{},"internal_server_error",[1869,4783,4784],{},"Problema del servidor",[1869,4786,4787],{},[22,4788,4768],{},[1869,4790,4791],{},"Reintente después de unos segundos",[1854,4793,4794,4797,4802,4805,4809],{},[1869,4795,4796],{},"502",[1869,4798,4799],{},[27,4800,4801],{},"bad_gateway",[1869,4803,4804],{},"Error upstream",[1869,4806,4807],{},[22,4808,4768],{},[1869,4810,4811],{},"Reintente después de 5s",[1854,4813,4814,4817,4822,4825,4829],{},[1869,4815,4816],{},"503",[1869,4818,4819],{},[27,4820,4821],{},"service_unavailable_error",[1869,4823,4824],{},"Servicio caído",[1869,4826,4827],{},[22,4828,4768],{},[1869,4830,4831],{},"Reintente después de 30s",[91,4833,4835],{"id":4834},"manejo-de-errores-listo-para-producción","Manejo de Errores Listo para Producción",[10,4837,4838],{},"Envuelva sus llamadas a la API con lógica de reintento para errores transitorios:",[10,4840,4841],{},[2433,4842,2435],{},[135,4844,4846],{"className":325,"code":4845,"language":327,"meta":140,"style":140},"import random\n\ndef generate_video_with_retry(payload, max_retries=3):\n    \"\"\"\n    Envía una solicitud de generación de video con reintento automático\n    para errores transitorios (429, 500, 502, 503).\n\n    Usa retroceso exponencial con jitter para evitar efecto de manada:\n    - Intento 1: espera ~1s\n    - Intento 2: espera ~2s\n    - Intento 3: espera ~4s\n\n    Los errores no reintentables (400, 401, 402, 404, 413, 422) fallan inmediatamente\n    porque reintentar no solucionará el problema subyacente.\n    \"\"\"\n    for attempt in range(max_retries):\n        try:\n            response = requests.post(\n                f\"{BASE_URL}/videos/generations\",\n                headers=HEADERS,\n                json=payload,\n                timeout=30       # Timeout de conexión de 30s\n            )\n\n            # Éxito — devuelve el objeto de tarea\n            if response.status_code == 200:\n                return response.json()\n\n            # Parsea la respuesta de error\n            error = response.json().get(\"error\", {})\n            error_type = error.get(\"type\", \"\")\n            error_msg = error.get(\"message\", \"Error desconocido\")\n\n            # Errores no reintentables — falla inmediatamente\n            if response.status_code in (400, 401, 402, 404, 413, 422):\n                raise ValueError(\n                    f\"Error de API {response.status_code}: {error_msg}\"\n                )\n\n            # Errores reintentables — retroceso exponencial con jitter\n            if response.status_code in (429, 500, 502, 503):\n                wait = (2 ** attempt) + random.uniform(0, 1)\n                print(f\"  Reintento {attempt + 1}/{max_retries} \"\n                      f\"después de {wait:.1f}s ({error_type}: {error_msg})\")\n                time.sleep(wait)\n                continue\n\n        except requests.exceptions.Timeout:\n            # El servidor no respondió en 30 segundos\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Timeout. Reintento {attempt + 1}/{max_retries} \"\n                  f\"después de {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n\n        except requests.exceptions.ConnectionError as e:\n            # Fallo de DNS, conexión rechazada, etc.\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Error de conexión: {e}. Reintento {attempt + 1}/{max_retries} \"\n                  f\"después de {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n\n    raise RuntimeError(f\"Fallo tras {max_retries} reintentos\")\n",[27,4847,4848,4855,4859,4876,4881,4886,4891,4895,4900,4905,4910,4915,4919,4924,4929,4933,4949,4956,4965,4978,4989,4999,5012,5017,5021,5026,5039,5046,5050,5055,5070,5090,5106,5110,5115,5149,5159,5185,5190,5194,5199,5225,5258,5292,5333,5338,5343,5347,5355,5360,5387,5417,5436,5441,5446,5450,5462,5467,5493,5532,5550,5554,5558,5562],{"__ignoreMap":140},[144,4849,4850,4852],{"class":146,"line":147},[144,4851,334],{"class":257},[144,4853,4854],{"class":261}," random\n",[144,4856,4857],{"class":146,"line":165},[144,4858,356],{"emptyLinePlaceholder":57},[144,4860,4861,4863,4866,4869,4871,4874],{"class":146,"line":177},[144,4862,501],{"class":257},[144,4864,4865],{"class":150}," generate_video_with_retry",[144,4867,4868],{"class":261},"(payload, max_retries",[144,4870,265],{"class":257},[144,4872,4873],{"class":154},"3",[144,4875,515],{"class":261},[144,4877,4878],{"class":146,"line":186},[144,4879,4880],{"class":158},"    \"\"\"\n",[144,4882,4883],{"class":146,"line":359},[144,4884,4885],{"class":158},"    Envía una solicitud de generación de video con reintento automático\n",[144,4887,4888],{"class":146,"line":365},[144,4889,4890],{"class":158},"    para errores transitorios (429, 500, 502, 503).\n",[144,4892,4893],{"class":146,"line":377},[144,4894,356],{"emptyLinePlaceholder":57},[144,4896,4897],{"class":146,"line":394},[144,4898,4899],{"class":158},"    Usa retroceso exponencial con jitter para evitar efecto de manada:\n",[144,4901,4902],{"class":146,"line":399},[144,4903,4904],{"class":158},"    - Intento 1: espera ~1s\n",[144,4906,4907],{"class":146,"line":414},[144,4908,4909],{"class":158},"    - Intento 2: espera ~2s\n",[144,4911,4912],{"class":146,"line":431},[144,4913,4914],{"class":158},"    - Intento 3: espera ~4s\n",[144,4916,4917],{"class":146,"line":436},[144,4918,356],{"emptyLinePlaceholder":57},[144,4920,4921],{"class":146,"line":447},[144,4922,4923],{"class":158},"    Los errores no reintentables (400, 401, 402, 404, 413, 422) fallan inmediatamente\n",[144,4925,4926],{"class":146,"line":471},[144,4927,4928],{"class":158},"    porque reintentar no solucionará el problema subyacente.\n",[144,4930,4931],{"class":146,"line":482},[144,4932,4880],{"class":158},[144,4934,4935,4938,4941,4943,4946],{"class":146,"line":488},[144,4936,4937],{"class":257},"    for",[144,4939,4940],{"class":261}," attempt ",[144,4942,964],{"class":257},[144,4944,4945],{"class":154}," range",[144,4947,4948],{"class":261},"(max_retries):\n",[144,4950,4951,4954],{"class":146,"line":493},[144,4952,4953],{"class":257},"        try",[144,4955,411],{"class":261},[144,4957,4958,4961,4963],{"class":146,"line":498},[144,4959,4960],{"class":261},"            response ",[144,4962,265],{"class":257},[144,4964,1218],{"class":261},[144,4966,4967,4970,4972,4974,4976],{"class":146,"line":518},[144,4968,4969],{"class":257},"                f",[144,4971,465],{"class":158},[144,4973,570],{"class":154},[144,4975,1231],{"class":158},[144,4977,468],{"class":261},[144,4979,4980,4983,4985,4987],{"class":146,"line":524},[144,4981,4982],{"class":592},"                headers",[144,4984,265],{"class":257},[144,4986,439],{"class":154},[144,4988,468],{"class":261},[144,4990,4991,4994,4996],{"class":146,"line":535},[144,4992,4993],{"class":592},"                json",[144,4995,265],{"class":257},[144,4997,4998],{"class":261},"payload,\n",[144,5000,5001,5004,5006,5009],{"class":146,"line":540},[144,5002,5003],{"class":592},"                timeout",[144,5005,265],{"class":257},[144,5007,5008],{"class":154},"30",[144,5010,5011],{"class":173},"       # Timeout de conexión de 30s\n",[144,5013,5014],{"class":146,"line":551},[144,5015,5016],{"class":261},"            )\n",[144,5018,5019],{"class":146,"line":562},[144,5020,356],{"emptyLinePlaceholder":57},[144,5022,5023],{"class":146,"line":589},[144,5024,5025],{"class":173},"            # Éxito — devuelve el objeto de tarea\n",[144,5027,5028,5031,5033,5035,5037],{"class":146,"line":601},[144,5029,5030],{"class":257},"            if",[144,5032,2322],{"class":261},[144,5034,751],{"class":257},[144,5036,2327],{"class":154},[144,5038,411],{"class":261},[144,5040,5041,5044],{"class":146,"line":607},[144,5042,5043],{"class":257},"                return",[144,5045,621],{"class":261},[144,5047,5048],{"class":146,"line":613},[144,5049,356],{"emptyLinePlaceholder":57},[144,5051,5052],{"class":146,"line":624},[144,5053,5054],{"class":173},"            # Parsea la respuesta de error\n",[144,5056,5057,5060,5062,5065,5067],{"class":146,"line":629},[144,5058,5059],{"class":261},"            error ",[144,5061,265],{"class":257},[144,5063,5064],{"class":261}," response.json().get(",[144,5066,793],{"class":158},[144,5068,5069],{"class":261},", {})\n",[144,5071,5072,5075,5077,5080,5083,5085,5088],{"class":146,"line":646},[144,5073,5074],{"class":261},"            error_type ",[144,5076,265],{"class":257},[144,5078,5079],{"class":261}," error.get(",[144,5081,5082],{"class":158},"\"type\"",[144,5084,289],{"class":261},[144,5086,5087],{"class":158},"\"\"",[144,5089,391],{"class":261},[144,5091,5092,5094,5096,5098,5100,5102,5104],{"class":146,"line":667},[144,5093,786],{"class":261},[144,5095,265],{"class":257},[144,5097,5079],{"class":261},[144,5099,799],{"class":158},[144,5101,289],{"class":261},[144,5103,804],{"class":158},[144,5105,391],{"class":261},[144,5107,5108],{"class":146,"line":687},[144,5109,356],{"emptyLinePlaceholder":57},[144,5111,5112],{"class":146,"line":692},[144,5113,5114],{"class":173},"            # Errores no reintentables — falla inmediatamente\n",[144,5116,5117,5119,5121,5123,5125,5127,5129,5131,5133,5135,5137,5139,5141,5143,5145,5147],{"class":146,"line":737},[144,5118,5030],{"class":257},[144,5120,2322],{"class":261},[144,5122,964],{"class":257},[144,5124,113],{"class":261},[144,5126,3451],{"class":154},[144,5128,289],{"class":261},[144,5130,4665],{"class":154},[144,5132,289],{"class":261},[144,5134,4683],{"class":154},[144,5136,289],{"class":261},[144,5138,4701],{"class":154},[144,5140,289],{"class":261},[144,5142,4719],{"class":154},[144,5144,289],{"class":261},[144,5146,4737],{"class":154},[144,5148,515],{"class":261},[144,5150,5151,5154,5156],{"class":146,"line":742},[144,5152,5153],{"class":257},"                raise",[144,5155,420],{"class":154},[144,5157,5158],{"class":261},"(\n",[144,5160,5161,5164,5167,5169,5172,5174,5176,5178,5180,5182],{"class":146,"line":759},[144,5162,5163],{"class":257},"                    f",[144,5165,5166],{"class":158},"\"Error de API ",[144,5168,576],{"class":154},[144,5170,5171],{"class":261},"response.status_code",[144,5173,582],{"class":154},[144,5175,453],{"class":158},[144,5177,576],{"class":154},[144,5179,827],{"class":261},[144,5181,582],{"class":154},[144,5183,5184],{"class":158},"\"\n",[144,5186,5187],{"class":146,"line":768},[144,5188,5189],{"class":261},"                )\n",[144,5191,5192],{"class":146,"line":783},[144,5193,356],{"emptyLinePlaceholder":57},[144,5195,5196],{"class":146,"line":809},[144,5197,5198],{"class":173},"            # Errores reintentables — retroceso exponencial con jitter\n",[144,5200,5201,5203,5205,5207,5209,5211,5213,5215,5217,5219,5221,5223],{"class":146,"line":836},[144,5202,5030],{"class":257},[144,5204,2322],{"class":261},[144,5206,964],{"class":257},[144,5208,113],{"class":261},[144,5210,4755],{"class":154},[144,5212,289],{"class":261},[144,5214,4776],{"class":154},[144,5216,289],{"class":261},[144,5218,4796],{"class":154},[144,5220,289],{"class":261},[144,5222,4816],{"class":154},[144,5224,515],{"class":261},[144,5226,5227,5230,5232,5234,5237,5240,5243,5246,5249,5251,5253,5256],{"class":146,"line":841},[144,5228,5229],{"class":261},"                wait ",[144,5231,265],{"class":257},[144,5233,113],{"class":261},[144,5235,5236],{"class":154},"2",[144,5238,5239],{"class":257}," **",[144,5241,5242],{"class":261}," attempt) ",[144,5244,5245],{"class":257},"+",[144,5247,5248],{"class":261}," random.uniform(",[144,5250,662],{"class":154},[144,5252,289],{"class":261},[144,5254,5255],{"class":154},"1",[144,5257,391],{"class":261},[144,5259,5260,5263,5265,5267,5270,5272,5275,5277,5280,5282,5284,5287,5289],{"class":146,"line":847},[144,5261,5262],{"class":154},"                print",[144,5264,423],{"class":261},[144,5266,456],{"class":257},[144,5268,5269],{"class":158},"\"  Reintento ",[144,5271,576],{"class":154},[144,5273,5274],{"class":261},"attempt ",[144,5276,5245],{"class":257},[144,5278,5279],{"class":154}," 1}",[144,5281,1002],{"class":158},[144,5283,576],{"class":154},[144,5285,5286],{"class":261},"max_retries",[144,5288,582],{"class":154},[144,5290,5291],{"class":158}," \"\n",[144,5293,5294,5297,5300,5302,5305,5308,5310,5313,5315,5318,5320,5322,5324,5326,5328,5331],{"class":146,"line":852},[144,5295,5296],{"class":257},"                      f",[144,5298,5299],{"class":158},"\"después de ",[144,5301,576],{"class":154},[144,5303,5304],{"class":261},"wait",[144,5306,5307],{"class":257},":.1f",[144,5309,582],{"class":154},[144,5311,5312],{"class":158},"s (",[144,5314,576],{"class":154},[144,5316,5317],{"class":261},"error_type",[144,5319,582],{"class":154},[144,5321,453],{"class":158},[144,5323,576],{"class":154},[144,5325,827],{"class":261},[144,5327,582],{"class":154},[144,5329,5330],{"class":158},")\"",[144,5332,391],{"class":261},[144,5334,5335],{"class":146,"line":857},[144,5336,5337],{"class":261},"                time.sleep(wait)\n",[144,5339,5340],{"class":146,"line":868},[144,5341,5342],{"class":257},"                continue\n",[144,5344,5345],{"class":146,"line":874},[144,5346,356],{"emptyLinePlaceholder":57},[144,5348,5349,5352],{"class":146,"line":899},[144,5350,5351],{"class":257},"        except",[144,5353,5354],{"class":261}," requests.exceptions.Timeout:\n",[144,5356,5357],{"class":146,"line":920},[144,5358,5359],{"class":173},"            # El servidor no respondió en 30 segundos\n",[144,5361,5362,5365,5367,5369,5371,5373,5375,5377,5379,5381,5383,5385],{"class":146,"line":926},[144,5363,5364],{"class":261},"            wait ",[144,5366,265],{"class":257},[144,5368,113],{"class":261},[144,5370,5236],{"class":154},[144,5372,5239],{"class":257},[144,5374,5242],{"class":261},[144,5376,5245],{"class":257},[144,5378,5248],{"class":261},[144,5380,662],{"class":154},[144,5382,289],{"class":261},[144,5384,5255],{"class":154},[144,5386,391],{"class":261},[144,5388,5389,5392,5394,5396,5399,5401,5403,5405,5407,5409,5411,5413,5415],{"class":146,"line":931},[144,5390,5391],{"class":154},"            print",[144,5393,423],{"class":261},[144,5395,456],{"class":257},[144,5397,5398],{"class":158},"\"  Timeout. Reintento ",[144,5400,576],{"class":154},[144,5402,5274],{"class":261},[144,5404,5245],{"class":257},[144,5406,5279],{"class":154},[144,5408,1002],{"class":158},[144,5410,576],{"class":154},[144,5412,5286],{"class":261},[144,5414,582],{"class":154},[144,5416,5291],{"class":158},[144,5418,5419,5422,5424,5426,5428,5430,5432,5434],{"class":146,"line":955},[144,5420,5421],{"class":257},"                  f",[144,5423,5299],{"class":158},[144,5425,576],{"class":154},[144,5427,5304],{"class":261},[144,5429,5307],{"class":257},[144,5431,582],{"class":154},[144,5433,1368],{"class":158},[144,5435,391],{"class":261},[144,5437,5438],{"class":146,"line":980},[144,5439,5440],{"class":261},"            time.sleep(wait)\n",[144,5442,5443],{"class":146,"line":986},[144,5444,5445],{"class":257},"            continue\n",[144,5447,5448],{"class":146,"line":991},[144,5449,356],{"emptyLinePlaceholder":57},[144,5451,5452,5454,5457,5459],{"class":146,"line":1008},[144,5453,5351],{"class":257},[144,5455,5456],{"class":261}," requests.exceptions.ConnectionError ",[144,5458,949],{"class":257},[144,5460,5461],{"class":261}," e:\n",[144,5463,5464],{"class":146,"line":1043},[144,5465,5466],{"class":173},"            # Fallo de DNS, conexión rechazada, etc.\n",[144,5468,5469,5471,5473,5475,5477,5479,5481,5483,5485,5487,5489,5491],{"class":146,"line":1048},[144,5470,5364],{"class":261},[144,5472,265],{"class":257},[144,5474,113],{"class":261},[144,5476,5236],{"class":154},[144,5478,5239],{"class":257},[144,5480,5242],{"class":261},[144,5482,5245],{"class":257},[144,5484,5248],{"class":261},[144,5486,662],{"class":154},[144,5488,289],{"class":261},[144,5490,5255],{"class":154},[144,5492,391],{"class":261},[144,5494,5495,5497,5499,5501,5504,5506,5509,5511,5514,5516,5518,5520,5522,5524,5526,5528,5530],{"class":146,"line":1053},[144,5496,5391],{"class":154},[144,5498,423],{"class":261},[144,5500,456],{"class":257},[144,5502,5503],{"class":158},"\"  Error de conexión: ",[144,5505,576],{"class":154},[144,5507,5508],{"class":261},"e",[144,5510,582],{"class":154},[144,5512,5513],{"class":158},". Reintento ",[144,5515,576],{"class":154},[144,5517,5274],{"class":261},[144,5519,5245],{"class":257},[144,5521,5279],{"class":154},[144,5523,1002],{"class":158},[144,5525,576],{"class":154},[144,5527,5286],{"class":261},[144,5529,582],{"class":154},[144,5531,5291],{"class":158},[144,5533,5534,5536,5538,5540,5542,5544,5546,5548],{"class":146,"line":1064},[144,5535,5421],{"class":257},[144,5537,5299],{"class":158},[144,5539,576],{"class":154},[144,5541,5304],{"class":261},[144,5543,5307],{"class":257},[144,5545,582],{"class":154},[144,5547,1368],{"class":158},[144,5549,391],{"class":261},[144,5551,5552],{"class":146,"line":1074},[144,5553,5440],{"class":261},[144,5555,5556],{"class":146,"line":1091},[144,5557,5445],{"class":257},[144,5559,5560],{"class":146,"line":1100},[144,5561,356],{"emptyLinePlaceholder":57},[144,5563,5564,5566,5569,5571,5573,5576,5578,5580,5582,5585],{"class":146,"line":1106},[144,5565,417],{"class":257},[144,5567,5568],{"class":154}," RuntimeError",[144,5570,423],{"class":261},[144,5572,456],{"class":257},[144,5574,5575],{"class":158},"\"Fallo tras ",[144,5577,576],{"class":154},[144,5579,5286],{"class":261},[144,5581,582],{"class":154},[144,5583,5584],{"class":158}," reintentos\"",[144,5586,391],{"class":261},[10,5588,5589],{},"Esto maneja:",[96,5591,5592,5598,5604,5610,5616],{},[72,5593,5594,5597],{},[22,5595,5596],{},"Límites de tasa (429)"," — el retroceso exponencial con jitter evita reintentos sincronizados de múltiples clientes",[72,5599,5600,5603],{},[22,5601,5602],{},"Errores de servidor (500/502/503)"," — reintento automático con retraso creciente",[72,5605,5606,5609],{},[22,5607,5608],{},"Timeouts"," — timeout de 30 segundos previene bloqueos en servidores que no responden",[72,5611,5612,5615],{},[22,5613,5614],{},"Caídas de conexión"," — fallos de DNS, conexiones rechazadas, interrupciones de red",[72,5617,5618,5621],{},[22,5619,5620],{},"Errores de cliente (400/401/402/404/413/422)"," — falla inmediatamente porque reintentar no solucionará la entrada incorrecta",[17,5623,5624],{},[10,5625,5626,5628],{},[22,5627,132],{}," Para sistemas de producción, considere registrar las solicitudes fallidas con su payload completo y respuesta de error. Esto facilita mucho la depuración cuando las cosas salen mal a las 3 AM.",[91,5630,5632],{"id":5631},"validar-entrada-antes-de-llamadas-a-la-api","Validar Entrada Antes de Llamadas a la API",[10,5634,5635],{},"Ahorre créditos y tiempo detectando errores obvios localmente:",[135,5637,5639],{"className":325,"code":5638,"language":327,"meta":140,"style":140},"def validate_payload(payload):\n    \"\"\"\n    Valida un payload de generación antes de enviarlo a la API.\n    Detecta errores comunes que resultarían en errores 400.\n    \"\"\"\n    errors = []\n\n    # Campos requeridos\n    if not payload.get(\"model\"):\n        errors.append(\"'model' es requerido\")\n    if not payload.get(\"prompt\") or not payload[\"prompt\"].strip():\n        errors.append(\"'prompt' es requerido y no puede estar vacío\")\n\n    # Rango de duración\n    duration = payload.get(\"duration\", 5)\n    if duration \u003C 4 or duration > 15:\n        errors.append(f\"'duration' debe ser 4-15, se obtuvo {duration}\")\n\n    # Valores de calidad\n    valid_qualities = {\"480p\", \"720p\", \"1080p\"}\n    quality = payload.get(\"quality\", \"720p\")\n    if quality not in valid_qualities:\n        errors.append(f\"'quality' debe ser uno de {valid_qualities}, se obtuvo '{quality}'\")\n\n    # Valores de relación de aspecto\n    valid_ratios = {\"16:9\", \"9:16\", \"1:1\", \"4:3\", \"3:4\", \"21:9\"}\n    ratio = payload.get(\"aspect_ratio\", \"16:9\")\n    if ratio not in valid_ratios:\n        errors.append(f\"'aspect_ratio' debe ser uno de {valid_ratios}, se obtuvo '{ratio}'\")\n\n    # Validación de URL de imagen\n    image_urls = payload.get(\"image_urls\", [])\n    if len(image_urls) > 9:\n        errors.append(f\"Máximo 9 imágenes permitidas, se obtuvieron {len(image_urls)}\")\n    for i, url in enumerate(image_urls):\n        if not url.startswith((\"http://\", \"https://\")):\n            errors.append(f\"image_urls[{i}] debe ser una URL HTTP(S)\")\n\n    if errors:\n        raise ValueError(f\"Error de validación del payload:\\n\" + \"\\n\".join(f\"  - {e}\" for e in errors))\n\n    return True\n",[27,5640,5641,5651,5655,5660,5665,5669,5679,5683,5688,5702,5712,5738,5747,5751,5756,5774,5800,5819,5823,5828,5850,5868,5884,5914,5918,5923,5959,5977,5991,6020,6024,6029,6044,6061,6082,6097,6117,6139,6143,6150,6205,6209],{"__ignoreMap":140},[144,5642,5643,5645,5648],{"class":146,"line":147},[144,5644,501],{"class":257},[144,5646,5647],{"class":150}," validate_payload",[144,5649,5650],{"class":261},"(payload):\n",[144,5652,5653],{"class":146,"line":165},[144,5654,4880],{"class":158},[144,5656,5657],{"class":146,"line":177},[144,5658,5659],{"class":158},"    Valida un payload de generación antes de enviarlo a la API.\n",[144,5661,5662],{"class":146,"line":186},[144,5663,5664],{"class":158},"    Detecta errores comunes que resultarían en errores 400.\n",[144,5666,5667],{"class":146,"line":359},[144,5668,4880],{"class":158},[144,5670,5671,5674,5676],{"class":146,"line":365},[144,5672,5673],{"class":261},"    errors ",[144,5675,265],{"class":257},[144,5677,5678],{"class":261}," []\n",[144,5680,5681],{"class":146,"line":377},[144,5682,356],{"emptyLinePlaceholder":57},[144,5684,5685],{"class":146,"line":394},[144,5686,5687],{"class":173},"    # Campos requeridos\n",[144,5689,5690,5692,5694,5697,5700],{"class":146,"line":399},[144,5691,2319],{"class":257},[144,5693,405],{"class":257},[144,5695,5696],{"class":261}," payload.get(",[144,5698,5699],{"class":158},"\"model\"",[144,5701,515],{"class":261},[144,5703,5704,5707,5710],{"class":146,"line":414},[144,5705,5706],{"class":261},"        errors.append(",[144,5708,5709],{"class":158},"\"'model' es requerido\"",[144,5711,391],{"class":261},[144,5713,5714,5716,5718,5720,5723,5725,5728,5730,5733,5735],{"class":146,"line":431},[144,5715,2319],{"class":257},[144,5717,405],{"class":257},[144,5719,5696],{"class":261},[144,5721,5722],{"class":158},"\"prompt\"",[144,5724,946],{"class":261},[144,5726,5727],{"class":257},"or",[144,5729,405],{"class":257},[144,5731,5732],{"class":261}," payload[",[144,5734,5722],{"class":158},[144,5736,5737],{"class":261},"].strip():\n",[144,5739,5740,5742,5745],{"class":146,"line":436},[144,5741,5706],{"class":261},[144,5743,5744],{"class":158},"\"'prompt' es requerido y no puede estar vacío\"",[144,5746,391],{"class":261},[144,5748,5749],{"class":146,"line":447},[144,5750,356],{"emptyLinePlaceholder":57},[144,5752,5753],{"class":146,"line":471},[144,5754,5755],{"class":173},"    # Rango de duración\n",[144,5757,5758,5761,5763,5765,5768,5770,5772],{"class":146,"line":482},[144,5759,5760],{"class":261},"    duration ",[144,5762,265],{"class":257},[144,5764,5696],{"class":261},[144,5766,5767],{"class":158},"\"duration\"",[144,5769,289],{"class":261},[144,5771,1132],{"class":154},[144,5773,391],{"class":261},[144,5775,5776,5778,5781,5784,5787,5790,5792,5795,5798],{"class":146,"line":488},[144,5777,2319],{"class":257},[144,5779,5780],{"class":261}," duration ",[144,5782,5783],{"class":257},"\u003C",[144,5785,5786],{"class":154}," 4",[144,5788,5789],{"class":257}," or",[144,5791,5780],{"class":261},[144,5793,5794],{"class":257},">",[144,5796,5797],{"class":154}," 15",[144,5799,411],{"class":261},[144,5801,5802,5804,5806,5809,5811,5813,5815,5817],{"class":146,"line":493},[144,5803,5706],{"class":261},[144,5805,456],{"class":257},[144,5807,5808],{"class":158},"\"'duration' debe ser 4-15, se obtuvo ",[144,5810,576],{"class":154},[144,5812,1586],{"class":261},[144,5814,582],{"class":154},[144,5816,465],{"class":158},[144,5818,391],{"class":261},[144,5820,5821],{"class":146,"line":498},[144,5822,356],{"emptyLinePlaceholder":57},[144,5824,5825],{"class":146,"line":518},[144,5826,5827],{"class":173},"    # Valores de calidad\n",[144,5829,5830,5833,5835,5838,5840,5842,5844,5846,5848],{"class":146,"line":524},[144,5831,5832],{"class":261},"    valid_qualities ",[144,5834,265],{"class":257},[144,5836,5837],{"class":261}," {",[144,5839,3828],{"class":158},[144,5841,289],{"class":261},[144,5843,1149],{"class":158},[144,5845,289],{"class":261},[144,5847,3524],{"class":158},[144,5849,485],{"class":261},[144,5851,5852,5855,5857,5859,5862,5864,5866],{"class":146,"line":535},[144,5853,5854],{"class":261},"    quality ",[144,5856,265],{"class":257},[144,5858,5696],{"class":261},[144,5860,5861],{"class":158},"\"quality\"",[144,5863,289],{"class":261},[144,5865,1149],{"class":158},[144,5867,391],{"class":261},[144,5869,5870,5872,5875,5878,5881],{"class":146,"line":540},[144,5871,2319],{"class":257},[144,5873,5874],{"class":261}," quality ",[144,5876,5877],{"class":257},"not",[144,5879,5880],{"class":257}," in",[144,5882,5883],{"class":261}," valid_qualities:\n",[144,5885,5886,5888,5890,5893,5895,5898,5900,5903,5905,5907,5909,5912],{"class":146,"line":551},[144,5887,5706],{"class":261},[144,5889,456],{"class":257},[144,5891,5892],{"class":158},"\"'quality' debe ser uno de ",[144,5894,576],{"class":154},[144,5896,5897],{"class":261},"valid_qualities",[144,5899,582],{"class":154},[144,5901,5902],{"class":158},", se obtuvo '",[144,5904,576],{"class":154},[144,5906,1594],{"class":261},[144,5908,582],{"class":154},[144,5910,5911],{"class":158},"'\"",[144,5913,391],{"class":261},[144,5915,5916],{"class":146,"line":562},[144,5917,356],{"emptyLinePlaceholder":57},[144,5919,5920],{"class":146,"line":589},[144,5921,5922],{"class":173},"    # Valores de relación de aspecto\n",[144,5924,5925,5928,5930,5932,5934,5936,5938,5940,5943,5945,5948,5950,5953,5955,5957],{"class":146,"line":601},[144,5926,5927],{"class":261},"    valid_ratios ",[144,5929,265],{"class":257},[144,5931,5837],{"class":261},[144,5933,1166],{"class":158},[144,5935,289],{"class":261},[144,5937,3536],{"class":158},[144,5939,289],{"class":261},[144,5941,5942],{"class":158},"\"1:1\"",[144,5944,289],{"class":261},[144,5946,5947],{"class":158},"\"4:3\"",[144,5949,289],{"class":261},[144,5951,5952],{"class":158},"\"3:4\"",[144,5954,289],{"class":261},[144,5956,3648],{"class":158},[144,5958,485],{"class":261},[144,5960,5961,5964,5966,5968,5971,5973,5975],{"class":146,"line":607},[144,5962,5963],{"class":261},"    ratio ",[144,5965,265],{"class":257},[144,5967,5696],{"class":261},[144,5969,5970],{"class":158},"\"aspect_ratio\"",[144,5972,289],{"class":261},[144,5974,1166],{"class":158},[144,5976,391],{"class":261},[144,5978,5979,5981,5984,5986,5988],{"class":146,"line":613},[144,5980,2319],{"class":257},[144,5982,5983],{"class":261}," ratio ",[144,5985,5877],{"class":257},[144,5987,5880],{"class":257},[144,5989,5990],{"class":261}," valid_ratios:\n",[144,5992,5993,5995,5997,6000,6002,6005,6007,6009,6011,6014,6016,6018],{"class":146,"line":624},[144,5994,5706],{"class":261},[144,5996,456],{"class":257},[144,5998,5999],{"class":158},"\"'aspect_ratio' debe ser uno de ",[144,6001,576],{"class":154},[144,6003,6004],{"class":261},"valid_ratios",[144,6006,582],{"class":154},[144,6008,5902],{"class":158},[144,6010,576],{"class":154},[144,6012,6013],{"class":261},"ratio",[144,6015,582],{"class":154},[144,6017,5911],{"class":158},[144,6019,391],{"class":261},[144,6021,6022],{"class":146,"line":629},[144,6023,356],{"emptyLinePlaceholder":57},[144,6025,6026],{"class":146,"line":646},[144,6027,6028],{"class":173},"    # Validación de URL de imagen\n",[144,6030,6031,6034,6036,6038,6041],{"class":146,"line":667},[144,6032,6033],{"class":261},"    image_urls ",[144,6035,265],{"class":257},[144,6037,5696],{"class":261},[144,6039,6040],{"class":158},"\"image_urls\"",[144,6042,6043],{"class":261},", [])\n",[144,6045,6046,6048,6051,6054,6056,6059],{"class":146,"line":687},[144,6047,2319],{"class":257},[144,6049,6050],{"class":154}," len",[144,6052,6053],{"class":261},"(image_urls) ",[144,6055,5794],{"class":257},[144,6057,6058],{"class":154}," 9",[144,6060,411],{"class":261},[144,6062,6063,6065,6067,6070,6073,6076,6078,6080],{"class":146,"line":692},[144,6064,5706],{"class":261},[144,6066,456],{"class":257},[144,6068,6069],{"class":158},"\"Máximo 9 imágenes permitidas, se obtuvieron ",[144,6071,6072],{"class":154},"{len",[144,6074,6075],{"class":261},"(image_urls)",[144,6077,582],{"class":154},[144,6079,465],{"class":158},[144,6081,391],{"class":261},[144,6083,6084,6086,6089,6091,6094],{"class":146,"line":737},[144,6085,4937],{"class":257},[144,6087,6088],{"class":261}," i, url ",[144,6090,964],{"class":257},[144,6092,6093],{"class":154}," enumerate",[144,6095,6096],{"class":261},"(image_urls):\n",[144,6098,6099,6101,6103,6106,6109,6111,6114],{"class":146,"line":742},[144,6100,745],{"class":257},[144,6102,405],{"class":257},[144,6104,6105],{"class":261}," url.startswith((",[144,6107,6108],{"class":158},"\"http://\"",[144,6110,289],{"class":261},[144,6112,6113],{"class":158},"\"https://\"",[144,6115,6116],{"class":261},")):\n",[144,6118,6119,6122,6124,6127,6129,6132,6134,6137],{"class":146,"line":759},[144,6120,6121],{"class":261},"            errors.append(",[144,6123,456],{"class":257},[144,6125,6126],{"class":158},"\"image_urls[",[144,6128,576],{"class":154},[144,6130,6131],{"class":261},"i",[144,6133,582],{"class":154},[144,6135,6136],{"class":158},"] debe ser una URL HTTP(S)\"",[144,6138,391],{"class":261},[144,6140,6141],{"class":146,"line":768},[144,6142,356],{"emptyLinePlaceholder":57},[144,6144,6145,6147],{"class":146,"line":783},[144,6146,2319],{"class":257},[144,6148,6149],{"class":261}," errors:\n",[144,6151,6152,6155,6157,6159,6161,6164,6166,6168,6171,6174,6176,6178,6181,6183,6186,6188,6190,6192,6194,6197,6200,6202],{"class":146,"line":809},[144,6153,6154],{"class":257},"        raise",[144,6156,420],{"class":154},[144,6158,423],{"class":261},[144,6160,456],{"class":257},[144,6162,6163],{"class":158},"\"Error de validación del payload:",[144,6165,1475],{"class":154},[144,6167,465],{"class":158},[144,6169,6170],{"class":257}," +",[144,6172,6173],{"class":158}," \"",[144,6175,1475],{"class":154},[144,6177,465],{"class":158},[144,6179,6180],{"class":261},".join(",[144,6182,456],{"class":257},[144,6184,6185],{"class":158},"\"  - ",[144,6187,576],{"class":154},[144,6189,5508],{"class":261},[144,6191,582],{"class":154},[144,6193,465],{"class":158},[144,6195,6196],{"class":257}," for",[144,6198,6199],{"class":261}," e ",[144,6201,964],{"class":257},[144,6203,6204],{"class":261}," errors))\n",[144,6206,6207],{"class":146,"line":836},[144,6208,356],{"emptyLinePlaceholder":57},[144,6210,6211,6213],{"class":146,"line":841},[144,6212,1511],{"class":257},[144,6214,6215],{"class":154}," True\n",[17,6217,6218],{},[10,6219,6220,6222,6223,6226],{},[22,6221,2018],{}," Olvidar codificar URL los caracteres especiales en las URLs de imagen. Si la ruta de su imagen contiene espacios o caracteres no ASCII, use ",[27,6224,6225],{},"urllib.parse.quote()"," para codificarla.",[44,6228],{},[47,6230,6232],{"id":6231},"configurar-webhooks-omita-el-polling","Configurar Webhooks (Omita el Polling)",[10,6234,6235,6236,6239],{},"El polling funciona bien para scripts y prototipos. Para sistemas de producción, los ",[22,6237,6238],{},"webhooks"," son más eficientes — la API envía el resultado a su servidor cuando el video está listo. Sin solicitudes desperdiciadas, sin retraso entre la finalización y la notificación.",[91,6241,6243],{"id":6242},"cómo-funciona","Cómo Funciona",[10,6245,6246,6247,6249],{},"Agregue ",[27,6248,3415],{}," a su solicitud de generación:",[10,6251,6252],{},[2433,6253,6254],{},"Usa la misma configuración del primer ejemplo anterior.",[135,6256,6258],{"className":325,"code":6257,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Una nave espacial despega desde un paisaje desértico al atardecer.\",\n    \"duration\": 8,\n    \"quality\": \"720p\",\n    \"callback_url\": \"https://su-servidor.com/api/webhook/seedance\"\n}\n\nresponse = requests.post(\n    f\"{BASE_URL}/videos/generations\",\n    headers=HEADERS,\n    json=payload\n)\ntask = response.json()\nprint(f\"Tarea enviada: {task['id']}\")\n# No se necesita polling — su webhook recibirá el resultado\n",[27,6259,6260,6268,6278,6289,6299,6309,6319,6323,6327,6336,6349,6360,6369,6373,6382,6408],{"__ignoreMap":140},[144,6261,6262,6264,6266],{"class":146,"line":147},[144,6263,3475],{"class":261},[144,6265,265],{"class":257},[144,6267,444],{"class":261},[144,6269,6270,6272,6274,6276],{"class":146,"line":165},[144,6271,3484],{"class":158},[144,6273,453],{"class":261},[144,6275,1082],{"class":158},[144,6277,468],{"class":261},[144,6279,6280,6282,6284,6287],{"class":146,"line":177},[144,6281,3495],{"class":158},[144,6283,453],{"class":261},[144,6285,6286],{"class":158},"\"Una nave espacial despega desde un paisaje desértico al atardecer.\"",[144,6288,468],{"class":261},[144,6290,6291,6293,6295,6297],{"class":146,"line":186},[144,6292,3507],{"class":158},[144,6294,453],{"class":261},[144,6296,3512],{"class":154},[144,6298,468],{"class":261},[144,6300,6301,6303,6305,6307],{"class":146,"line":359},[144,6302,3519],{"class":158},[144,6304,453],{"class":261},[144,6306,1149],{"class":158},[144,6308,468],{"class":261},[144,6310,6311,6314,6316],{"class":146,"line":365},[144,6312,6313],{"class":158},"    \"callback_url\"",[144,6315,453],{"class":261},[144,6317,6318],{"class":158},"\"https://su-servidor.com/api/webhook/seedance\"\n",[144,6320,6321],{"class":146,"line":377},[144,6322,485],{"class":261},[144,6324,6325],{"class":146,"line":394},[144,6326,356],{"emptyLinePlaceholder":57},[144,6328,6329,6332,6334],{"class":146,"line":399},[144,6330,6331],{"class":261},"response ",[144,6333,265],{"class":257},[144,6335,1218],{"class":261},[144,6337,6338,6341,6343,6345,6347],{"class":146,"line":414},[144,6339,6340],{"class":257},"    f",[144,6342,465],{"class":158},[144,6344,570],{"class":154},[144,6346,1231],{"class":158},[144,6348,468],{"class":261},[144,6350,6351,6354,6356,6358],{"class":146,"line":431},[144,6352,6353],{"class":592},"    headers",[144,6355,265],{"class":257},[144,6357,439],{"class":154},[144,6359,468],{"class":261},[144,6361,6362,6365,6367],{"class":146,"line":436},[144,6363,6364],{"class":592},"    json",[144,6366,265],{"class":257},[144,6368,2602],{"class":261},[144,6370,6371],{"class":146,"line":447},[144,6372,391],{"class":261},[144,6374,6375,6378,6380],{"class":146,"line":471},[144,6376,6377],{"class":261},"task ",[144,6379,265],{"class":257},[144,6381,621],{"class":261},[144,6383,6384,6387,6389,6391,6394,6396,6398,6400,6402,6404,6406],{"class":146,"line":482},[144,6385,6386],{"class":154},"print",[144,6388,423],{"class":261},[144,6390,456],{"class":257},[144,6392,6393],{"class":158},"\"Tarea enviada: ",[144,6395,576],{"class":154},[144,6397,1324],{"class":261},[144,6399,1327],{"class":158},[144,6401,1330],{"class":261},[144,6403,582],{"class":154},[144,6405,465],{"class":158},[144,6407,391],{"class":261},[144,6409,6410],{"class":146,"line":488},[144,6411,6412],{"class":173},"# No se necesita polling — su webhook recibirá el resultado\n",[10,6414,6415,6416,6418],{},"Cuando el video está listo, la API envía una solicitud POST a su ",[27,6417,3415],{}," con el objeto de tarea completado — exactamente el mismo payload que obtendría del polling.",[91,6420,6422],{"id":6421},"requisitos-del-webhook","Requisitos del Webhook",[1848,6424,6425,6435],{},[1851,6426,6427],{},[1854,6428,6429,6432],{},[1857,6430,6431],{},"Requisito",[1857,6433,6434],{},"Detalles",[1864,6436,6437,6445,6453,6461,6469,6477],{},[1854,6438,6439,6442],{},[1869,6440,6441],{},"Protocolo",[1869,6443,6444],{},"Solo HTTPS (sin HTTP) — requerido por seguridad",[1854,6446,6447,6450],{},[1869,6448,6449],{},"Respuesta",[1869,6451,6452],{},"Devuelva 2xx dentro de 10 segundos",[1854,6454,6455,6458],{},[1869,6456,6457],{},"Reintentos",[1869,6459,6460],{},"3 intentos en caso de fallo (intervalos de 1s, 2s, 4s)",[1854,6462,6463,6466],{},[1869,6464,6465],{},"Longitud de URL",[1869,6467,6468],{},"≤ 2048 caracteres",[1854,6470,6471,6474],{},[1869,6472,6473],{},"Red",[1869,6475,6476],{},"Sin IPs internas/privadas (localhost, 10.x.x.x, 192.168.x.x)",[1854,6478,6479,6482],{},[1869,6480,6481],{},"Cuerpo",[1869,6483,6484],{},"POST JSON con el objeto de tarea completo",[91,6486,6488],{"id":6487},"receptor-de-webhook-flask-listo-para-producción","Receptor de Webhook Flask Listo para Producción",[10,6490,6491],{},"Aquí hay un servidor de webhook completo usando Flask con validación adecuada, manejo de errores y descarga asíncrona de videos:",[135,6493,6495],{"className":325,"code":6494,"language":327,"meta":140,"style":140},"# webhook_server.py\n\"\"\"\nReceptor de webhook de Seedance — maneja callbacks de completado de video.\nEjecute: pip install flask requests\n         python webhook_server.py\n\"\"\"\nfrom flask import Flask, request, jsonify\nimport json\nimport os\nimport threading\nimport requests as req  # renombrado para evitar conflicto con flask.request\n\napp = Flask(__name__)\n\n# Directorio para guardar videos completados\nOUTPUT_DIR = os.getenv(\"VIDEO_OUTPUT_DIR\", \"./videos\")\nos.makedirs(OUTPUT_DIR, exist_ok=True)\n\n\ndef download_video_async(video_url, task_id):\n    \"\"\"Descarga video en un hilo en segundo plano para no bloquear la respuesta del webhook.\"\"\"\n    try:\n        filename = os.path.join(OUTPUT_DIR, f\"{task_id}.mp4\")\n        print(f\"  Descargando {task_id} a {filename}...\")\n        resp = req.get(video_url, stream=True, timeout=120)\n        resp.raise_for_status()\n        with open(filename, \"wb\") as f:\n            for chunk in resp.iter_content(chunk_size=8192):\n                f.write(chunk)\n        size_mb = os.path.getsize(filename) / (1024 * 1024)\n        print(f\"  Guardado: {filename} ({size_mb:.1f} MB)\")\n    except Exception as e:\n        print(f\"  Descarga fallida para {task_id}: {e}\")\n\n\n@app.route(\"/api/webhook/seedance\", methods=[\"POST\"])\ndef handle_webhook():\n    \"\"\"\n    Maneja el webhook de completado de video de Seedance.\n\n    La API envía un POST con el objeto de tarea completo cuando\n    una generación de video se completa (éxito o fallo).\n    \"\"\"\n    # Parsea el objeto de tarea entrante\n    task = request.json\n    if not task:\n        return jsonify({\"error\": \"Cuerpo vacío\"}), 400\n\n    task_id = task.get(\"id\", \"desconocido\")\n    status = task.get(\"status\", \"desconocido\")\n    model = task.get(\"model\", \"desconocido\")\n\n    print(f\"\\n{'='*50}\")\n    print(f\"Webhook recibido: tarea={task_id}\")\n    print(f\"  Estado: {status}\")\n    print(f\"  Modelo: {model}\")\n\n    if status == \"completed\":\n        # Extrae URL(s) de video de los resultados\n        results = task.get(\"results\", [])\n        if results:\n            video_url = results[0]\n            print(f\"  URL del video: {video_url}\")\n\n            # Descarga en hilo en segundo plano para responder rápidamente\n            thread = threading.Thread(\n                target=download_video_async,\n                args=(video_url, task_id)\n            )\n            thread.start()\n        else:\n            print(f\"  ADVERTENCIA: Completado pero sin array de resultados!\")\n\n    elif status == \"failed\":\n        error_info = task.get(\"error\", {})\n        print(f\"  FALLIDO: {json.dumps(error_info, indent=2)}\")\n        # TODO: Registrar en su sistema de seguimiento de errores (Sentry, etc.)\n        # TODO: Opcionalmente reintentar la generación con parámetros modificados\n\n    else:\n        print(f\"  Estado inesperado: {status}\")\n        print(f\"  Payload completo: {json.dumps(task, indent=2)}\")\n\n    # Siempre devuelve 200 rápidamente — la API espera una respuesta en 10s\n    return jsonify({\"received\": True, \"task_id\": task_id}), 200\n\n\n@app.route(\"/health\", methods=[\"GET\"])\ndef health_check():\n    \"\"\"Endpoint de verificación de salud para balanceadores de carga.\"\"\"\n    return jsonify({\"status\": \"ok\"}), 200\n\n\nif __name__ == \"__main__\":\n    print(f\"Iniciando servidor de webhook...\")\n    print(f\"Los videos se guardarán en: {os.path.abspath(OUTPUT_DIR)}\")\n    print(f\"URL del webhook: http://localhost:5000/api/webhook/seedance\")\n    app.run(host=\"0.0.0.0\", port=5000, debug=True)\n",[27,6496,6497,6502,6507,6512,6517,6522,6526,6539,6546,6552,6559,6574,6578,6593,6597,6602,6622,6640,6644,6648,6658,6663,6670,6699,6728,6756,6761,6778,6798,6803,6827,6860,6872,6901,6905,6909,6934,6943,6947,6952,6956,6961,6966,6970,6975,6984,6993,7014,7018,7036,7053,7070,7074,7100,7121,7142,7163,7167,7179,7184,7197,7204,7218,7239,7243,7248,7258,7268,7278,7282,7287,7294,7307,7311,7324,7337,7368,7379,7388,7392,7398,7419,7449,7453,7458,7482,7486,7490,7512,7521,7526,7543,7547,7551,7563,7576,7602,7615],{"__ignoreMap":140},[144,6498,6499],{"class":146,"line":147},[144,6500,6501],{"class":173},"# webhook_server.py\n",[144,6503,6504],{"class":146,"line":165},[144,6505,6506],{"class":158},"\"\"\"\n",[144,6508,6509],{"class":146,"line":177},[144,6510,6511],{"class":158},"Receptor de webhook de Seedance — maneja callbacks de completado de video.\n",[144,6513,6514],{"class":146,"line":186},[144,6515,6516],{"class":158},"Ejecute: pip install flask requests\n",[144,6518,6519],{"class":146,"line":359},[144,6520,6521],{"class":158},"         python webhook_server.py\n",[144,6523,6524],{"class":146,"line":365},[144,6525,6506],{"class":158},[144,6527,6528,6531,6534,6536],{"class":146,"line":377},[144,6529,6530],{"class":257},"from",[144,6532,6533],{"class":261}," flask ",[144,6535,334],{"class":257},[144,6537,6538],{"class":261}," Flask, request, jsonify\n",[144,6540,6541,6543],{"class":146,"line":394},[144,6542,334],{"class":257},[144,6544,6545],{"class":261}," json\n",[144,6547,6548,6550],{"class":146,"line":399},[144,6549,334],{"class":257},[144,6551,337],{"class":261},[144,6553,6554,6556],{"class":146,"line":414},[144,6555,334],{"class":257},[144,6557,6558],{"class":261}," threading\n",[144,6560,6561,6563,6566,6568,6571],{"class":146,"line":431},[144,6562,334],{"class":257},[144,6564,6565],{"class":261}," requests ",[144,6567,949],{"class":257},[144,6569,6570],{"class":261}," req  ",[144,6572,6573],{"class":173},"# renombrado para evitar conflicto con flask.request\n",[144,6575,6576],{"class":146,"line":436},[144,6577,356],{"emptyLinePlaceholder":57},[144,6579,6580,6583,6585,6588,6591],{"class":146,"line":447},[144,6581,6582],{"class":261},"app ",[144,6584,265],{"class":257},[144,6586,6587],{"class":261}," Flask(",[144,6589,6590],{"class":154},"__name__",[144,6592,391],{"class":261},[144,6594,6595],{"class":146,"line":471},[144,6596,356],{"emptyLinePlaceholder":57},[144,6598,6599],{"class":146,"line":482},[144,6600,6601],{"class":173},"# Directorio para guardar videos completados\n",[144,6603,6604,6607,6609,6612,6615,6617,6620],{"class":146,"line":488},[144,6605,6606],{"class":154},"OUTPUT_DIR",[144,6608,371],{"class":257},[144,6610,6611],{"class":261}," os.getenv(",[144,6613,6614],{"class":158},"\"VIDEO_OUTPUT_DIR\"",[144,6616,289],{"class":261},[144,6618,6619],{"class":158},"\"./videos\"",[144,6621,391],{"class":261},[144,6623,6624,6627,6629,6631,6634,6636,6638],{"class":146,"line":493},[144,6625,6626],{"class":261},"os.makedirs(",[144,6628,6606],{"class":154},[144,6630,289],{"class":261},[144,6632,6633],{"class":592},"exist_ok",[144,6635,265],{"class":257},[144,6637,915],{"class":154},[144,6639,391],{"class":261},[144,6641,6642],{"class":146,"line":498},[144,6643,356],{"emptyLinePlaceholder":57},[144,6645,6646],{"class":146,"line":518},[144,6647,356],{"emptyLinePlaceholder":57},[144,6649,6650,6652,6655],{"class":146,"line":524},[144,6651,501],{"class":257},[144,6653,6654],{"class":150}," download_video_async",[144,6656,6657],{"class":261},"(video_url, task_id):\n",[144,6659,6660],{"class":146,"line":535},[144,6661,6662],{"class":158},"    \"\"\"Descarga video en un hilo en segundo plano para no bloquear la respuesta del webhook.\"\"\"\n",[144,6664,6665,6668],{"class":146,"line":540},[144,6666,6667],{"class":257},"    try",[144,6669,411],{"class":261},[144,6671,6672,6675,6677,6680,6682,6684,6686,6688,6690,6692,6694,6697],{"class":146,"line":551},[144,6673,6674],{"class":261},"        filename ",[144,6676,265],{"class":257},[144,6678,6679],{"class":261}," os.path.join(",[144,6681,6606],{"class":154},[144,6683,289],{"class":261},[144,6685,456],{"class":257},[144,6687,465],{"class":158},[144,6689,576],{"class":154},[144,6691,579],{"class":261},[144,6693,582],{"class":154},[144,6695,6696],{"class":158},".mp4\"",[144,6698,391],{"class":261},[144,6700,6701,6703,6705,6707,6710,6712,6714,6716,6718,6720,6722,6724,6726],{"class":146,"line":562},[144,6702,695],{"class":154},[144,6704,423],{"class":261},[144,6706,456],{"class":257},[144,6708,6709],{"class":158},"\"  Descargando ",[144,6711,576],{"class":154},[144,6713,579],{"class":261},[144,6715,582],{"class":154},[144,6717,2765],{"class":158},[144,6719,576],{"class":154},[144,6721,889],{"class":261},[144,6723,582],{"class":154},[144,6725,894],{"class":158},[144,6727,391],{"class":261},[144,6729,6730,6733,6735,6738,6740,6742,6744,6746,6749,6751,6754],{"class":146,"line":589},[144,6731,6732],{"class":261},"        resp ",[144,6734,265],{"class":257},[144,6736,6737],{"class":261}," req.get(video_url, ",[144,6739,910],{"class":592},[144,6741,265],{"class":257},[144,6743,915],{"class":154},[144,6745,289],{"class":261},[144,6747,6748],{"class":592},"timeout",[144,6750,265],{"class":257},[144,6752,6753],{"class":154},"120",[144,6755,391],{"class":261},[144,6757,6758],{"class":146,"line":601},[144,6759,6760],{"class":261},"        resp.raise_for_status()\n",[144,6762,6763,6766,6768,6770,6772,6774,6776],{"class":146,"line":607},[144,6764,6765],{"class":257},"        with",[144,6767,937],{"class":154},[144,6769,940],{"class":261},[144,6771,943],{"class":158},[144,6773,946],{"class":261},[144,6775,949],{"class":257},[144,6777,952],{"class":261},[144,6779,6780,6783,6785,6787,6790,6792,6794,6796],{"class":146,"line":613},[144,6781,6782],{"class":257},"            for",[144,6784,961],{"class":261},[144,6786,964],{"class":257},[144,6788,6789],{"class":261}," resp.iter_content(",[144,6791,970],{"class":592},[144,6793,265],{"class":257},[144,6795,975],{"class":154},[144,6797,515],{"class":261},[144,6799,6800],{"class":146,"line":624},[144,6801,6802],{"class":261},"                f.write(chunk)\n",[144,6804,6805,6808,6810,6812,6814,6816,6819,6822,6825],{"class":146,"line":629},[144,6806,6807],{"class":261},"        size_mb ",[144,6809,265],{"class":257},[144,6811,999],{"class":261},[144,6813,1002],{"class":257},[144,6815,113],{"class":261},[144,6817,6818],{"class":154},"1024",[144,6820,6821],{"class":257}," *",[144,6823,6824],{"class":154}," 1024",[144,6826,391],{"class":261},[144,6828,6829,6831,6833,6835,6838,6840,6842,6844,6846,6848,6851,6853,6855,6858],{"class":146,"line":646},[144,6830,695],{"class":154},[144,6832,423],{"class":261},[144,6834,456],{"class":257},[144,6836,6837],{"class":158},"\"  Guardado: ",[144,6839,576],{"class":154},[144,6841,889],{"class":261},[144,6843,582],{"class":154},[144,6845,113],{"class":158},[144,6847,576],{"class":154},[144,6849,6850],{"class":261},"size_mb",[144,6852,5307],{"class":257},[144,6854,582],{"class":154},[144,6856,6857],{"class":158}," MB)\"",[144,6859,391],{"class":261},[144,6861,6862,6865,6867,6870],{"class":146,"line":667},[144,6863,6864],{"class":257},"    except",[144,6866,815],{"class":154},[144,6868,6869],{"class":257}," as",[144,6871,5461],{"class":261},[144,6873,6874,6876,6878,6880,6883,6885,6887,6889,6891,6893,6895,6897,6899],{"class":146,"line":687},[144,6875,695],{"class":154},[144,6877,423],{"class":261},[144,6879,456],{"class":257},[144,6881,6882],{"class":158},"\"  Descarga fallida para ",[144,6884,576],{"class":154},[144,6886,579],{"class":261},[144,6888,582],{"class":154},[144,6890,453],{"class":158},[144,6892,576],{"class":154},[144,6894,5508],{"class":261},[144,6896,582],{"class":154},[144,6898,465],{"class":158},[144,6900,391],{"class":261},[144,6902,6903],{"class":146,"line":692},[144,6904,356],{"emptyLinePlaceholder":57},[144,6906,6907],{"class":146,"line":737},[144,6908,356],{"emptyLinePlaceholder":57},[144,6910,6911,6914,6916,6919,6921,6924,6926,6929,6932],{"class":146,"line":742},[144,6912,6913],{"class":150},"@app.route",[144,6915,423],{"class":261},[144,6917,6918],{"class":158},"\"/api/webhook/seedance\"",[144,6920,289],{"class":261},[144,6922,6923],{"class":592},"methods",[144,6925,265],{"class":257},[144,6927,6928],{"class":261},"[",[144,6930,6931],{"class":158},"\"POST\"",[144,6933,1430],{"class":261},[144,6935,6936,6938,6941],{"class":146,"line":759},[144,6937,501],{"class":257},[144,6939,6940],{"class":150}," handle_webhook",[144,6942,1061],{"class":261},[144,6944,6945],{"class":146,"line":768},[144,6946,4880],{"class":158},[144,6948,6949],{"class":146,"line":783},[144,6950,6951],{"class":158},"    Maneja el webhook de completado de video de Seedance.\n",[144,6953,6954],{"class":146,"line":809},[144,6955,356],{"emptyLinePlaceholder":57},[144,6957,6958],{"class":146,"line":836},[144,6959,6960],{"class":158},"    La API envía un POST con el objeto de tarea completo cuando\n",[144,6962,6963],{"class":146,"line":841},[144,6964,6965],{"class":158},"    una generación de video se completa (éxito o fallo).\n",[144,6967,6968],{"class":146,"line":847},[144,6969,4880],{"class":158},[144,6971,6972],{"class":146,"line":852},[144,6973,6974],{"class":173},"    # Parsea el objeto de tarea entrante\n",[144,6976,6977,6979,6981],{"class":146,"line":857},[144,6978,1288],{"class":261},[144,6980,265],{"class":257},[144,6982,6983],{"class":261}," request.json\n",[144,6985,6986,6988,6990],{"class":146,"line":868},[144,6987,2319],{"class":257},[144,6989,405],{"class":257},[144,6991,6992],{"class":261}," task:\n",[144,6994,6995,6998,7001,7003,7005,7008,7011],{"class":146,"line":874},[144,6996,6997],{"class":257},"        return",[144,6999,7000],{"class":261}," jsonify({",[144,7002,793],{"class":158},[144,7004,453],{"class":261},[144,7006,7007],{"class":158},"\"Cuerpo vacío\"",[144,7009,7010],{"class":261},"}), ",[144,7012,7013],{"class":154},"400\n",[144,7015,7016],{"class":146,"line":899},[144,7017,356],{"emptyLinePlaceholder":57},[144,7019,7020,7023,7025,7027,7029,7031,7034],{"class":146,"line":920},[144,7021,7022],{"class":261},"    task_id ",[144,7024,265],{"class":257},[144,7026,654],{"class":261},[144,7028,1427],{"class":158},[144,7030,289],{"class":261},[144,7032,7033],{"class":158},"\"desconocido\"",[144,7035,391],{"class":261},[144,7037,7038,7041,7043,7045,7047,7049,7051],{"class":146,"line":926},[144,7039,7040],{"class":261},"    status ",[144,7042,265],{"class":257},[144,7044,654],{"class":261},[144,7046,640],{"class":158},[144,7048,289],{"class":261},[144,7050,7033],{"class":158},[144,7052,391],{"class":261},[144,7054,7055,7058,7060,7062,7064,7066,7068],{"class":146,"line":931},[144,7056,7057],{"class":261},"    model ",[144,7059,265],{"class":257},[144,7061,654],{"class":261},[144,7063,5699],{"class":158},[144,7065,289],{"class":261},[144,7067,7033],{"class":158},[144,7069,391],{"class":261},[144,7071,7072],{"class":146,"line":955},[144,7073,356],{"emptyLinePlaceholder":57},[144,7075,7076,7078,7080,7082,7084,7087,7090,7093,7096,7098],{"class":146,"line":980},[144,7077,877],{"class":154},[144,7079,423],{"class":261},[144,7081,456],{"class":257},[144,7083,465],{"class":158},[144,7085,7086],{"class":154},"\\n{",[144,7088,7089],{"class":158},"'='",[144,7091,7092],{"class":257},"*",[144,7094,7095],{"class":154},"50}",[144,7097,465],{"class":158},[144,7099,391],{"class":261},[144,7101,7102,7104,7106,7108,7111,7113,7115,7117,7119],{"class":146,"line":986},[144,7103,877],{"class":154},[144,7105,423],{"class":261},[144,7107,456],{"class":257},[144,7109,7110],{"class":158},"\"Webhook recibido: tarea=",[144,7112,576],{"class":154},[144,7114,579],{"class":261},[144,7116,582],{"class":154},[144,7118,465],{"class":158},[144,7120,391],{"class":261},[144,7122,7123,7125,7127,7129,7132,7134,7136,7138,7140],{"class":146,"line":991},[144,7124,877],{"class":154},[144,7126,423],{"class":261},[144,7128,456],{"class":257},[144,7130,7131],{"class":158},"\"  Estado: ",[144,7133,576],{"class":154},[144,7135,717],{"class":261},[144,7137,582],{"class":154},[144,7139,465],{"class":158},[144,7141,391],{"class":261},[144,7143,7144,7146,7148,7150,7153,7155,7157,7159,7161],{"class":146,"line":1008},[144,7145,877],{"class":154},[144,7147,423],{"class":261},[144,7149,456],{"class":257},[144,7151,7152],{"class":158},"\"  Modelo: ",[144,7154,576],{"class":154},[144,7156,1558],{"class":261},[144,7158,582],{"class":154},[144,7160,465],{"class":158},[144,7162,391],{"class":261},[144,7164,7165],{"class":146,"line":1043},[144,7166,356],{"emptyLinePlaceholder":57},[144,7168,7169,7171,7173,7175,7177],{"class":146,"line":1048},[144,7170,2319],{"class":257},[144,7172,748],{"class":261},[144,7174,751],{"class":257},[144,7176,754],{"class":158},[144,7178,411],{"class":261},[144,7180,7181],{"class":146,"line":1053},[144,7182,7183],{"class":173},"        # Extrae URL(s) de video de los resultados\n",[144,7185,7186,7189,7191,7193,7195],{"class":146,"line":1064},[144,7187,7188],{"class":261},"        results ",[144,7190,265],{"class":257},[144,7192,654],{"class":261},[144,7194,1455],{"class":158},[144,7196,6043],{"class":261},[144,7198,7199,7201],{"class":146,"line":1074},[144,7200,745],{"class":257},[144,7202,7203],{"class":261}," results:\n",[144,7205,7206,7209,7211,7214,7216],{"class":146,"line":1091},[144,7207,7208],{"class":261},"            video_url ",[144,7210,265],{"class":257},[144,7212,7213],{"class":261}," results[",[144,7215,662],{"class":154},[144,7217,643],{"class":261},[144,7219,7220,7222,7224,7226,7229,7231,7233,7235,7237],{"class":146,"line":1100},[144,7221,5391],{"class":154},[144,7223,423],{"class":261},[144,7225,456],{"class":257},[144,7227,7228],{"class":158},"\"  URL del video: ",[144,7230,576],{"class":154},[144,7232,1483],{"class":261},[144,7234,582],{"class":154},[144,7236,465],{"class":158},[144,7238,391],{"class":261},[144,7240,7241],{"class":146,"line":1106},[144,7242,356],{"emptyLinePlaceholder":57},[144,7244,7245],{"class":146,"line":1112},[144,7246,7247],{"class":173},"            # Descarga en hilo en segundo plano para responder rápidamente\n",[144,7249,7250,7253,7255],{"class":146,"line":1118},[144,7251,7252],{"class":261},"            thread ",[144,7254,265],{"class":257},[144,7256,7257],{"class":261}," threading.Thread(\n",[144,7259,7260,7263,7265],{"class":146,"line":1124},[144,7261,7262],{"class":592},"                target",[144,7264,265],{"class":257},[144,7266,7267],{"class":261},"download_video_async,\n",[144,7269,7270,7273,7275],{"class":146,"line":1141},[144,7271,7272],{"class":592},"                args",[144,7274,265],{"class":257},[144,7276,7277],{"class":261},"(video_url, task_id)\n",[144,7279,7280],{"class":146,"line":1158},[144,7281,5016],{"class":261},[144,7283,7284],{"class":146,"line":1175},[144,7285,7286],{"class":261},"            thread.start()\n",[144,7288,7289,7292],{"class":146,"line":1188},[144,7290,7291],{"class":257},"        else",[144,7293,411],{"class":261},[144,7295,7296,7298,7300,7302,7305],{"class":146,"line":1194},[144,7297,5391],{"class":154},[144,7299,423],{"class":261},[144,7301,456],{"class":257},[144,7303,7304],{"class":158},"\"  ADVERTENCIA: Completado pero sin array de resultados!\"",[144,7306,391],{"class":261},[144,7308,7309],{"class":146,"line":1199},[144,7310,356],{"emptyLinePlaceholder":57},[144,7312,7313,7316,7318,7320,7322],{"class":146,"line":1211},[144,7314,7315],{"class":257},"    elif",[144,7317,748],{"class":261},[144,7319,751],{"class":257},[144,7321,778],{"class":158},[144,7323,411],{"class":261},[144,7325,7326,7329,7331,7333,7335],{"class":146,"line":1221},[144,7327,7328],{"class":261},"        error_info ",[144,7330,265],{"class":257},[144,7332,654],{"class":261},[144,7334,793],{"class":158},[144,7336,5069],{"class":261},[144,7338,7339,7341,7343,7345,7348,7350,7353,7356,7358,7360,7362,7364,7366],{"class":146,"line":1240},[144,7340,695],{"class":154},[144,7342,423],{"class":261},[144,7344,456],{"class":257},[144,7346,7347],{"class":158},"\"  FALLIDO: ",[144,7349,576],{"class":154},[144,7351,7352],{"class":261},"json.dumps(error_info, ",[144,7354,7355],{"class":592},"indent",[144,7357,265],{"class":257},[144,7359,5236],{"class":154},[144,7361,107],{"class":261},[144,7363,582],{"class":154},[144,7365,465],{"class":158},[144,7367,391],{"class":261},[144,7369,7370,7373,7376],{"class":146,"line":1256},[144,7371,7372],{"class":173},"        # ",[144,7374,7375],{"class":257},"TODO",[144,7377,7378],{"class":173},": Registrar en su sistema de seguimiento de errores (Sentry, etc.)\n",[144,7380,7381,7383,7385],{"class":146,"line":1270},[144,7382,7372],{"class":173},[144,7384,7375],{"class":257},[144,7386,7387],{"class":173},": Opcionalmente reintentar la generación con parámetros modificados\n",[144,7389,7390],{"class":146,"line":1276},[144,7391,356],{"emptyLinePlaceholder":57},[144,7393,7394,7396],{"class":146,"line":1285},[144,7395,2356],{"class":257},[144,7397,411],{"class":261},[144,7399,7400,7402,7404,7406,7409,7411,7413,7415,7417],{"class":146,"line":1299},[144,7401,695],{"class":154},[144,7403,423],{"class":261},[144,7405,456],{"class":257},[144,7407,7408],{"class":158},"\"  Estado inesperado: ",[144,7410,576],{"class":154},[144,7412,717],{"class":261},[144,7414,582],{"class":154},[144,7416,465],{"class":158},[144,7418,391],{"class":261},[144,7420,7421,7423,7425,7427,7430,7432,7435,7437,7439,7441,7443,7445,7447],{"class":146,"line":1304},[144,7422,695],{"class":154},[144,7424,423],{"class":261},[144,7426,456],{"class":257},[144,7428,7429],{"class":158},"\"  Payload completo: ",[144,7431,576],{"class":154},[144,7433,7434],{"class":261},"json.dumps(task, ",[144,7436,7355],{"class":592},[144,7438,265],{"class":257},[144,7440,5236],{"class":154},[144,7442,107],{"class":261},[144,7444,582],{"class":154},[144,7446,465],{"class":158},[144,7448,391],{"class":261},[144,7450,7451],{"class":146,"line":1310},[144,7452,356],{"emptyLinePlaceholder":57},[144,7454,7455],{"class":146,"line":1339},[144,7456,7457],{"class":173},"    # Siempre devuelve 200 rápidamente — la API espera una respuesta en 10s\n",[144,7459,7460,7462,7464,7467,7469,7471,7473,7476,7479],{"class":146,"line":1373},[144,7461,1511],{"class":257},[144,7463,7000],{"class":261},[144,7465,7466],{"class":158},"\"received\"",[144,7468,453],{"class":261},[144,7470,915],{"class":154},[144,7472,289],{"class":261},[144,7474,7475],{"class":158},"\"task_id\"",[144,7477,7478],{"class":261},": task_id}), ",[144,7480,7481],{"class":154},"200\n",[144,7483,7484],{"class":146,"line":1405},[144,7485,356],{"emptyLinePlaceholder":57},[144,7487,7488],{"class":146,"line":1410},[144,7489,356],{"emptyLinePlaceholder":57},[144,7491,7492,7494,7496,7499,7501,7503,7505,7507,7510],{"class":146,"line":1416},[144,7493,6913],{"class":150},[144,7495,423],{"class":261},[144,7497,7498],{"class":158},"\"/health\"",[144,7500,289],{"class":261},[144,7502,6923],{"class":592},[144,7504,265],{"class":257},[144,7506,6928],{"class":261},[144,7508,7509],{"class":158},"\"GET\"",[144,7511,1430],{"class":261},[144,7513,7514,7516,7519],{"class":146,"line":1433},[144,7515,501],{"class":257},[144,7517,7518],{"class":150}," health_check",[144,7520,1061],{"class":261},[144,7522,7523],{"class":146,"line":1438},[144,7524,7525],{"class":158},"    \"\"\"Endpoint de verificación de salud para balanceadores de carga.\"\"\"\n",[144,7527,7528,7530,7532,7534,7536,7539,7541],{"class":146,"line":1444},[144,7529,1511],{"class":257},[144,7531,7000],{"class":261},[144,7533,640],{"class":158},[144,7535,453],{"class":261},[144,7537,7538],{"class":158},"\"ok\"",[144,7540,7010],{"class":261},[144,7542,7481],{"class":154},[144,7544,7545],{"class":146,"line":1464},[144,7546,356],{"emptyLinePlaceholder":57},[144,7548,7549],{"class":146,"line":1492},[144,7550,356],{"emptyLinePlaceholder":57},[144,7552,7553,7555,7557,7559,7561],{"class":146,"line":1503},[144,7554,402],{"class":257},[144,7556,1532],{"class":154},[144,7558,1535],{"class":257},[144,7560,1538],{"class":158},[144,7562,411],{"class":261},[144,7564,7565,7567,7569,7571,7574],{"class":146,"line":1508},[144,7566,877],{"class":154},[144,7568,423],{"class":261},[144,7570,456],{"class":257},[144,7572,7573],{"class":158},"\"Iniciando servidor de webhook...\"",[144,7575,391],{"class":261},[144,7577,7578,7580,7582,7584,7587,7589,7592,7594,7596,7598,7600],{"class":146,"line":1517},[144,7579,877],{"class":154},[144,7581,423],{"class":261},[144,7583,456],{"class":257},[144,7585,7586],{"class":158},"\"Los videos se guardarán en: ",[144,7588,576],{"class":154},[144,7590,7591],{"class":261},"os.path.abspath(",[144,7593,6606],{"class":154},[144,7595,107],{"class":261},[144,7597,582],{"class":154},[144,7599,465],{"class":158},[144,7601,391],{"class":261},[144,7603,7604,7606,7608,7610,7613],{"class":146,"line":1522},[144,7605,877],{"class":154},[144,7607,423],{"class":261},[144,7609,456],{"class":257},[144,7611,7612],{"class":158},"\"URL del webhook: http://localhost:5000/api/webhook/seedance\"",[144,7614,391],{"class":261},[144,7616,7617,7620,7623,7625,7628,7630,7633,7635,7638,7640,7643,7645,7647],{"class":146,"line":1527},[144,7618,7619],{"class":261},"    app.run(",[144,7621,7622],{"class":592},"host",[144,7624,265],{"class":257},[144,7626,7627],{"class":158},"\"0.0.0.0\"",[144,7629,289],{"class":261},[144,7631,7632],{"class":592},"port",[144,7634,265],{"class":257},[144,7636,7637],{"class":154},"5000",[144,7639,289],{"class":261},[144,7641,7642],{"class":592},"debug",[144,7644,265],{"class":257},[144,7646,915],{"class":154},[144,7648,391],{"class":261},[10,7650,7651],{},"Instale dependencias y ejecute:",[135,7653,7655],{"className":137,"code":7654,"language":139,"meta":140,"style":140},"pip install flask requests\npython webhook_server.py\n",[27,7656,7657,7668],{"__ignoreMap":140},[144,7658,7659,7661,7663,7666],{"class":146,"line":147},[144,7660,189],{"class":150},[144,7662,192],{"class":158},[144,7664,7665],{"class":158}," flask",[144,7667,351],{"class":158},[144,7669,7670,7672],{"class":146,"line":165},[144,7671,327],{"class":150},[144,7673,7674],{"class":158}," webhook_server.py\n",[10,7676,7677],{},"Decisiones clave de diseño en este servidor:",[96,7679,7680,7690,7700],{},[72,7681,7682,7685,7686,7689],{},[22,7683,7684],{},"Descargas en segundo plano"," — Creamos un hilo para descargar el video para que el manejador del webhook devuelva ",[27,7687,7688],{},"200"," inmediatamente. La API espera una respuesta en 10 segundos; las descargas de video pueden tardar más.",[72,7691,7692,7695,7696,7699],{},[22,7693,7694],{},"Endpoint de verificación de salud"," — ",[27,7697,7698],{},"/health"," es útil cuando se despliega detrás de un balanceador de carga (ALB, nginx, etc.).",[72,7701,7702,7705],{},[22,7703,7704],{},"Registro de errores"," — Las tareas fallidas se imprimen con el payload de error completo. En producción, envíe esto a Sentry, Datadog o su stack de logging.",[91,7707,7709],{"id":7708},"exponer-localhost-con-ngrok","Exponer Localhost con ngrok",[10,7711,7712,7713,7718],{},"Para desarrollo local, use ",[36,7714,7717],{"href":7715,"rel":7716},"https://ngrok.com",[40],"ngrok"," para crear una URL HTTPS pública que haga túnel a su servidor local:",[135,7720,7722],{"className":137,"code":7721,"language":139,"meta":140,"style":140},"# Instalar ngrok (macOS)\nbrew install ngrok\n\n# O descargue desde https://ngrok.com/download\n\n# Iniciar el túnel\nngrok http 5000\n",[27,7723,7724,7729,7739,7743,7748,7752,7757],{"__ignoreMap":140},[144,7725,7726],{"class":146,"line":147},[144,7727,7728],{"class":173},"# Instalar ngrok (macOS)\n",[144,7730,7731,7734,7736],{"class":146,"line":165},[144,7732,7733],{"class":150},"brew",[144,7735,192],{"class":158},[144,7737,7738],{"class":158}," ngrok\n",[144,7740,7741],{"class":146,"line":177},[144,7742,356],{"emptyLinePlaceholder":57},[144,7744,7745],{"class":146,"line":186},[144,7746,7747],{"class":173},"# O descargue desde https://ngrok.com/download\n",[144,7749,7750],{"class":146,"line":359},[144,7751,356],{"emptyLinePlaceholder":57},[144,7753,7754],{"class":146,"line":365},[144,7755,7756],{"class":173},"# Iniciar el túnel\n",[144,7758,7759,7761,7764],{"class":146,"line":377},[144,7760,7717],{"class":150},[144,7762,7763],{"class":158}," http",[144,7765,7766],{"class":154}," 5000\n",[10,7768,7769],{},"ngrok muestra algo como:",[135,7771,7774],{"className":7772,"code":7773,"language":1998},[1996],"Forwarding  https://a1b2c3d4.ngrok-free.app → http://localhost:5000\n",[27,7775,7773],{"__ignoreMap":140},[10,7777,7778,7779,322],{},"Use esa URL HTTPS como su ",[27,7780,3415],{},[135,7782,7784],{"className":325,"code":7783,"language":327,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Su prompt aquí\",\n    \"callback_url\": \"https://a1b2c3d4.ngrok-free.app/api/webhook/seedance\"\n}\n",[27,7785,7786,7794,7804,7815,7824],{"__ignoreMap":140},[144,7787,7788,7790,7792],{"class":146,"line":147},[144,7789,3475],{"class":261},[144,7791,265],{"class":257},[144,7793,444],{"class":261},[144,7795,7796,7798,7800,7802],{"class":146,"line":165},[144,7797,3484],{"class":158},[144,7799,453],{"class":261},[144,7801,1082],{"class":158},[144,7803,468],{"class":261},[144,7805,7806,7808,7810,7813],{"class":146,"line":177},[144,7807,3495],{"class":158},[144,7809,453],{"class":261},[144,7811,7812],{"class":158},"\"Su prompt aquí\"",[144,7814,468],{"class":261},[144,7816,7817,7819,7821],{"class":146,"line":186},[144,7818,6313],{"class":158},[144,7820,453],{"class":261},[144,7822,7823],{"class":158},"\"https://a1b2c3d4.ngrok-free.app/api/webhook/seedance\"\n",[144,7825,7826],{"class":146,"line":359},[144,7827,485],{"class":261},[17,7829,7830],{},[10,7831,7832,7834,7835,7838,7839,7842],{},[22,7833,2018],{}," Usar la URL ",[27,7836,7837],{},"http://"," de ngrok en lugar de ",[27,7840,7841],{},"https://",". La API de Seedance requiere HTTPS para webhooks — rechazará las URLs de callback HTTP simple con un error 400.",[91,7844,7846],{"id":7845},"seguridad-del-webhook","Seguridad del Webhook",[10,7848,7849],{},"En producción, valide que las solicitudes de webhook realmente provienen de la API de EvoLink:",[135,7851,7853],{"className":325,"code":7852,"language":327,"meta":140,"style":140},"import hmac\nimport hashlib\n\ndef verify_webhook(request):\n    \"\"\"Verifica la autenticidad del webhook usando el patrón de ID de tarea.\"\"\"\n    task = request.json\n    task_id = task.get(\"id\", \"\")\n\n    # Los IDs de tarea de EvoLink siguen un formato específico\n    if not task_id.startswith(\"task-unified-\"):\n        return False\n\n    # Validación adicional: verificar que existen los campos requeridos\n    required_fields = [\"id\", \"status\", \"model\", \"created\"]\n    if not all(field in task for field in required_fields):\n        return False\n\n    return True\n",[27,7854,7855,7862,7869,7873,7883,7888,7896,7912,7916,7921,7935,7942,7946,7951,7978,8006,8012,8016],{"__ignoreMap":140},[144,7856,7857,7859],{"class":146,"line":147},[144,7858,334],{"class":257},[144,7860,7861],{"class":261}," hmac\n",[144,7863,7864,7866],{"class":146,"line":165},[144,7865,334],{"class":257},[144,7867,7868],{"class":261}," hashlib\n",[144,7870,7871],{"class":146,"line":177},[144,7872,356],{"emptyLinePlaceholder":57},[144,7874,7875,7877,7880],{"class":146,"line":186},[144,7876,501],{"class":257},[144,7878,7879],{"class":150}," verify_webhook",[144,7881,7882],{"class":261},"(request):\n",[144,7884,7885],{"class":146,"line":359},[144,7886,7887],{"class":158},"    \"\"\"Verifica la autenticidad del webhook usando el patrón de ID de tarea.\"\"\"\n",[144,7889,7890,7892,7894],{"class":146,"line":365},[144,7891,1288],{"class":261},[144,7893,265],{"class":257},[144,7895,6983],{"class":261},[144,7897,7898,7900,7902,7904,7906,7908,7910],{"class":146,"line":377},[144,7899,7022],{"class":261},[144,7901,265],{"class":257},[144,7903,654],{"class":261},[144,7905,1427],{"class":158},[144,7907,289],{"class":261},[144,7909,5087],{"class":158},[144,7911,391],{"class":261},[144,7913,7914],{"class":146,"line":394},[144,7915,356],{"emptyLinePlaceholder":57},[144,7917,7918],{"class":146,"line":399},[144,7919,7920],{"class":173},"    # Los IDs de tarea de EvoLink siguen un formato específico\n",[144,7922,7923,7925,7927,7930,7933],{"class":146,"line":414},[144,7924,2319],{"class":257},[144,7926,405],{"class":257},[144,7928,7929],{"class":261}," task_id.startswith(",[144,7931,7932],{"class":158},"\"task-unified-\"",[144,7934,515],{"class":261},[144,7936,7937,7939],{"class":146,"line":431},[144,7938,6997],{"class":257},[144,7940,7941],{"class":154}," False\n",[144,7943,7944],{"class":146,"line":436},[144,7945,356],{"emptyLinePlaceholder":57},[144,7947,7948],{"class":146,"line":447},[144,7949,7950],{"class":173},"    # Validación adicional: verificar que existen los campos requeridos\n",[144,7952,7953,7956,7958,7961,7963,7965,7967,7969,7971,7973,7976],{"class":146,"line":471},[144,7954,7955],{"class":261},"    required_fields ",[144,7957,265],{"class":257},[144,7959,7960],{"class":261}," [",[144,7962,1427],{"class":158},[144,7964,289],{"class":261},[144,7966,640],{"class":158},[144,7968,289],{"class":261},[144,7970,5699],{"class":158},[144,7972,289],{"class":261},[144,7974,7975],{"class":158},"\"created\"",[144,7977,643],{"class":261},[144,7979,7980,7982,7984,7987,7990,7992,7995,7998,8001,8003],{"class":146,"line":482},[144,7981,2319],{"class":257},[144,7983,405],{"class":257},[144,7985,7986],{"class":154}," all",[144,7988,7989],{"class":261},"(field ",[144,7991,964],{"class":257},[144,7993,7994],{"class":261}," task ",[144,7996,7997],{"class":257},"for",[144,7999,8000],{"class":261}," field ",[144,8002,964],{"class":257},[144,8004,8005],{"class":261}," required_fields):\n",[144,8007,8008,8010],{"class":146,"line":488},[144,8009,6997],{"class":257},[144,8011,7941],{"class":154},[144,8013,8014],{"class":146,"line":493},[144,8015,356],{"emptyLinePlaceholder":57},[144,8017,8018,8020],{"class":146,"line":498},[144,8019,1511],{"class":257},[144,8021,6215],{"class":154},[91,8023,8025],{"id":8024},"cuándo-usar-webhooks-vs-polling","Cuándo Usar Webhooks vs Polling",[1848,8027,8028,8041],{},[1851,8029,8030],{},[1854,8031,8032,8035,8038],{},[1857,8033,8034],{},"Escenario",[1857,8036,8037],{},"Recomendación",[1857,8039,8040],{},"Por Qué",[1864,8042,8043,8053,8064,8075,8085,8095],{},[1854,8044,8045,8048,8050],{},[1869,8046,8047],{},"Prototipado rápido / scripts",[1869,8049,2056],{},[1869,8051,8052],{},"Más simple, no necesita servidor",[1854,8054,8055,8058,8061],{},[1869,8056,8057],{},"Aplicación web de producción",[1869,8059,8060],{},"Webhooks",[1869,8062,8063],{},"Escalable, sin solicitudes desperdiciadas",[1854,8065,8066,8069,8072],{},[1869,8067,8068],{},"Procesamiento por lotes (100+ videos)",[1869,8070,8071],{},"Webhooks + cola",[1869,8073,8074],{},"Envíe todos, procese a medida que se completan",[1854,8076,8077,8080,8082],{},[1869,8078,8079],{},"Herramientas CLI",[1869,8081,2056],{},[1869,8083,8084],{},"No requiere infraestructura de servidor",[1854,8086,8087,8090,8092],{},[1869,8088,8089],{},"Backend de aplicación móvil",[1869,8091,8060],{},[1869,8093,8094],{},"Notificaciones push a usuarios al completarse",[1854,8096,8097,8100,8102],{},[1869,8098,8099],{},"Sin servidor (Lambda/Cloud Functions)",[1869,8101,8060],{},[1869,8103,8104],{},"Combinación perfecta — función activada por cada completado",[17,8106,8107],{},[10,8108,8109,8111],{},[22,8110,132],{}," Para procesamiento por lotes, combine webhooks con una cola de mensajes (Redis, RabbitMQ, SQS). Envíe todas las solicitudes de generación, luego procese los completados a medida que lleguen a la cola. Esto desacopla el envío del procesamiento y maneja los reintentos con elegancia.",[44,8113],{},[47,8115,8117],{"id":8116},"procesamiento-por-lotes-generar-múltiples-videos","Procesamiento por Lotes: Generar Múltiples Videos",[10,8119,8120],{},"Los casos de uso del mundo real a menudo implican generar muchos videos. Aquí hay un patrón para procesamiento por lotes con limitación de tasa:",[10,8122,8123],{},[2433,8124,8125],{},"Usa la misma configuración y funciones auxiliares del primer ejemplo anterior.",[135,8127,8129],{"className":325,"code":8128,"language":327,"meta":140,"style":140},"import concurrent.futures\n\ndef batch_generate(prompts, max_concurrent=3):\n    \"\"\"\n    Genera múltiples videos con concurrencia controlada.\n\n    Args:\n        prompts: Lista de cadenas de prompt.\n        max_concurrent: Máximo de generaciones simultáneas.\n\n    Returns:\n        Lista de tuplas (prompt, resultado_o_error).\n    \"\"\"\n    results = []\n\n    def generate_one(prompt, index):\n        \"\"\"Genera un solo video y devuelve el resultado.\"\"\"\n        payload = {\n            \"model\": \"seedance-2.0\",\n            \"prompt\": prompt,\n            \"duration\": 5,\n            \"quality\": \"720p\"\n        }\n        try:\n            task = generate_video_with_retry(payload)\n            print(f\"[{index}] Enviado: {task['id']}\")\n            result = wait_for_video(task[\"id\"])\n            video_url = result[\"results\"][0]\n            download_video(video_url, f\"lote_{index}.mp4\")\n            return (prompt, result)\n        except Exception as e:\n            print(f\"[{index}] Fallido: {e}\")\n            return (prompt, str(e))\n\n    # Procesar en lotes para respetar los límites de tasa\n    with concurrent.futures.ThreadPoolExecutor(max_workers=max_concurrent) as executor:\n        futures = {\n            executor.submit(generate_one, prompt, i): i\n            for i, prompt in enumerate(prompts)\n        }\n        for future in concurrent.futures.as_completed(futures):\n            results.append(future.result())\n\n    # Resumen\n    succeeded = sum(1 for _, r in results if isinstance(r, dict))\n    print(f\"\\nLote completo: {succeeded}/{len(prompts)} exitosos\")\n    return results\n\n\n# Ejemplo de uso\nprompts = [\n    \"Un colibrí revoloteando cerca de una flor roja. Macro, poca profundidad de campo.\",\n    \"Olas oceánicas chocando contra rocas volcánicas al atardecer. Cámara lenta.\",\n    \"Un músico callejero tocando violín bajo la lluvia. Iluminación cinematográfica.\",\n]\nbatch_generate(prompts, max_concurrent=2)\n",[27,8130,8131,8138,8142,8158,8162,8167,8171,8176,8181,8186,8190,8195,8200,8204,8213,8217,8228,8233,8242,8253,8261,8272,8282,8287,8293,8303,8338,8351,8367,8387,8394,8404,8433,8446,8450,8455,8475,8484,8489,8503,8507,8519,8524,8528,8533,8571,8607,8614,8618,8622,8627,8637,8644,8651,8658,8662],{"__ignoreMap":140},[144,8132,8133,8135],{"class":146,"line":147},[144,8134,334],{"class":257},[144,8136,8137],{"class":261}," concurrent.futures\n",[144,8139,8140],{"class":146,"line":165},[144,8141,356],{"emptyLinePlaceholder":57},[144,8143,8144,8146,8149,8152,8154,8156],{"class":146,"line":177},[144,8145,501],{"class":257},[144,8147,8148],{"class":150}," batch_generate",[144,8150,8151],{"class":261},"(prompts, max_concurrent",[144,8153,265],{"class":257},[144,8155,4873],{"class":154},[144,8157,515],{"class":261},[144,8159,8160],{"class":146,"line":186},[144,8161,4880],{"class":158},[144,8163,8164],{"class":146,"line":359},[144,8165,8166],{"class":158},"    Genera múltiples videos con concurrencia controlada.\n",[144,8168,8169],{"class":146,"line":365},[144,8170,356],{"emptyLinePlaceholder":57},[144,8172,8173],{"class":146,"line":377},[144,8174,8175],{"class":158},"    Args:\n",[144,8177,8178],{"class":146,"line":394},[144,8179,8180],{"class":158},"        prompts: Lista de cadenas de prompt.\n",[144,8182,8183],{"class":146,"line":399},[144,8184,8185],{"class":158},"        max_concurrent: Máximo de generaciones simultáneas.\n",[144,8187,8188],{"class":146,"line":414},[144,8189,356],{"emptyLinePlaceholder":57},[144,8191,8192],{"class":146,"line":431},[144,8193,8194],{"class":158},"    Returns:\n",[144,8196,8197],{"class":146,"line":436},[144,8198,8199],{"class":158},"        Lista de tuplas (prompt, resultado_o_error).\n",[144,8201,8202],{"class":146,"line":447},[144,8203,4880],{"class":158},[144,8205,8206,8209,8211],{"class":146,"line":471},[144,8207,8208],{"class":261},"    results ",[144,8210,265],{"class":257},[144,8212,5678],{"class":261},[144,8214,8215],{"class":146,"line":482},[144,8216,356],{"emptyLinePlaceholder":57},[144,8218,8219,8222,8225],{"class":146,"line":488},[144,8220,8221],{"class":257},"    def",[144,8223,8224],{"class":150}," generate_one",[144,8226,8227],{"class":261},"(prompt, index):\n",[144,8229,8230],{"class":146,"line":493},[144,8231,8232],{"class":158},"        \"\"\"Genera un solo video y devuelve el resultado.\"\"\"\n",[144,8234,8235,8238,8240],{"class":146,"line":498},[144,8236,8237],{"class":261},"        payload ",[144,8239,265],{"class":257},[144,8241,444],{"class":261},[144,8243,8244,8247,8249,8251],{"class":146,"line":518},[144,8245,8246],{"class":158},"            \"model\"",[144,8248,453],{"class":261},[144,8250,1082],{"class":158},[144,8252,468],{"class":261},[144,8254,8255,8258],{"class":146,"line":524},[144,8256,8257],{"class":158},"            \"prompt\"",[144,8259,8260],{"class":261},": prompt,\n",[144,8262,8263,8266,8268,8270],{"class":146,"line":535},[144,8264,8265],{"class":158},"            \"duration\"",[144,8267,453],{"class":261},[144,8269,1132],{"class":154},[144,8271,468],{"class":261},[144,8273,8274,8277,8279],{"class":146,"line":540},[144,8275,8276],{"class":158},"            \"quality\"",[144,8278,453],{"class":261},[144,8280,8281],{"class":158},"\"720p\"\n",[144,8283,8284],{"class":146,"line":551},[144,8285,8286],{"class":261},"        }\n",[144,8288,8289,8291],{"class":146,"line":562},[144,8290,4953],{"class":257},[144,8292,411],{"class":261},[144,8294,8295,8298,8300],{"class":146,"line":589},[144,8296,8297],{"class":261},"            task ",[144,8299,265],{"class":257},[144,8301,8302],{"class":261}," generate_video_with_retry(payload)\n",[144,8304,8305,8307,8309,8311,8314,8316,8319,8321,8324,8326,8328,8330,8332,8334,8336],{"class":146,"line":601},[144,8306,5391],{"class":154},[144,8308,423],{"class":261},[144,8310,456],{"class":257},[144,8312,8313],{"class":158},"\"[",[144,8315,576],{"class":154},[144,8317,8318],{"class":261},"index",[144,8320,582],{"class":154},[144,8322,8323],{"class":158},"] Enviado: ",[144,8325,576],{"class":154},[144,8327,1324],{"class":261},[144,8329,1327],{"class":158},[144,8331,1330],{"class":261},[144,8333,582],{"class":154},[144,8335,465],{"class":158},[144,8337,391],{"class":261},[144,8339,8340,8343,8345,8347,8349],{"class":146,"line":607},[144,8341,8342],{"class":261},"            result ",[144,8344,265],{"class":257},[144,8346,1424],{"class":261},[144,8348,1427],{"class":158},[144,8350,1430],{"class":261},[144,8352,8353,8355,8357,8359,8361,8363,8365],{"class":146,"line":613},[144,8354,7208],{"class":261},[144,8356,265],{"class":257},[144,8358,1452],{"class":261},[144,8360,1455],{"class":158},[144,8362,1358],{"class":261},[144,8364,662],{"class":154},[144,8366,643],{"class":261},[144,8368,8369,8372,8374,8377,8379,8381,8383,8385],{"class":146,"line":624},[144,8370,8371],{"class":261},"            download_video(video_url, ",[144,8373,456],{"class":257},[144,8375,8376],{"class":158},"\"lote_",[144,8378,576],{"class":154},[144,8380,8318],{"class":261},[144,8382,582],{"class":154},[144,8384,6696],{"class":158},[144,8386,391],{"class":261},[144,8388,8389,8391],{"class":146,"line":629},[144,8390,762],{"class":257},[144,8392,8393],{"class":261}," (prompt, result)\n",[144,8395,8396,8398,8400,8402],{"class":146,"line":646},[144,8397,5351],{"class":257},[144,8399,815],{"class":154},[144,8401,6869],{"class":257},[144,8403,5461],{"class":261},[144,8405,8406,8408,8410,8412,8414,8416,8418,8420,8423,8425,8427,8429,8431],{"class":146,"line":667},[144,8407,5391],{"class":154},[144,8409,423],{"class":261},[144,8411,456],{"class":257},[144,8413,8313],{"class":158},[144,8415,576],{"class":154},[144,8417,8318],{"class":261},[144,8419,582],{"class":154},[144,8421,8422],{"class":158},"] Fallido: ",[144,8424,576],{"class":154},[144,8426,5508],{"class":261},[144,8428,582],{"class":154},[144,8430,465],{"class":158},[144,8432,391],{"class":261},[144,8434,8435,8437,8440,8443],{"class":146,"line":687},[144,8436,762],{"class":257},[144,8438,8439],{"class":261}," (prompt, ",[144,8441,8442],{"class":154},"str",[144,8444,8445],{"class":261},"(e))\n",[144,8447,8448],{"class":146,"line":692},[144,8449,356],{"emptyLinePlaceholder":57},[144,8451,8452],{"class":146,"line":737},[144,8453,8454],{"class":173},"    # Procesar en lotes para respetar los límites de tasa\n",[144,8456,8457,8459,8462,8465,8467,8470,8472],{"class":146,"line":742},[144,8458,934],{"class":257},[144,8460,8461],{"class":261}," concurrent.futures.ThreadPoolExecutor(",[144,8463,8464],{"class":592},"max_workers",[144,8466,265],{"class":257},[144,8468,8469],{"class":261},"max_concurrent) ",[144,8471,949],{"class":257},[144,8473,8474],{"class":261}," executor:\n",[144,8476,8477,8480,8482],{"class":146,"line":759},[144,8478,8479],{"class":261},"        futures ",[144,8481,265],{"class":257},[144,8483,444],{"class":261},[144,8485,8486],{"class":146,"line":768},[144,8487,8488],{"class":261},"            executor.submit(generate_one, prompt, i): i\n",[144,8490,8491,8493,8496,8498,8500],{"class":146,"line":783},[144,8492,6782],{"class":257},[144,8494,8495],{"class":261}," i, prompt ",[144,8497,964],{"class":257},[144,8499,6093],{"class":154},[144,8501,8502],{"class":261},"(prompts)\n",[144,8504,8505],{"class":146,"line":809},[144,8506,8286],{"class":261},[144,8508,8509,8511,8514,8516],{"class":146,"line":836},[144,8510,958],{"class":257},[144,8512,8513],{"class":261}," future ",[144,8515,964],{"class":257},[144,8517,8518],{"class":261}," concurrent.futures.as_completed(futures):\n",[144,8520,8521],{"class":146,"line":841},[144,8522,8523],{"class":261},"            results.append(future.result())\n",[144,8525,8526],{"class":146,"line":847},[144,8527,356],{"emptyLinePlaceholder":57},[144,8529,8530],{"class":146,"line":852},[144,8531,8532],{"class":173},"    # Resumen\n",[144,8534,8535,8538,8540,8543,8545,8547,8549,8552,8554,8557,8559,8562,8565,8568],{"class":146,"line":857},[144,8536,8537],{"class":261},"    succeeded ",[144,8539,265],{"class":257},[144,8541,8542],{"class":154}," sum",[144,8544,423],{"class":261},[144,8546,5255],{"class":154},[144,8548,6196],{"class":257},[144,8550,8551],{"class":261}," _, r ",[144,8553,964],{"class":257},[144,8555,8556],{"class":261}," results ",[144,8558,402],{"class":257},[144,8560,8561],{"class":154}," isinstance",[144,8563,8564],{"class":261},"(r, ",[144,8566,8567],{"class":154},"dict",[144,8569,8570],{"class":261},"))\n",[144,8572,8573,8575,8577,8579,8581,8583,8586,8588,8591,8593,8595,8597,8600,8602,8605],{"class":146,"line":868},[144,8574,877],{"class":154},[144,8576,423],{"class":261},[144,8578,456],{"class":257},[144,8580,465],{"class":158},[144,8582,1475],{"class":154},[144,8584,8585],{"class":158},"Lote completo: ",[144,8587,576],{"class":154},[144,8589,8590],{"class":261},"succeeded",[144,8592,582],{"class":154},[144,8594,1002],{"class":158},[144,8596,6072],{"class":154},[144,8598,8599],{"class":261},"(prompts)",[144,8601,582],{"class":154},[144,8603,8604],{"class":158}," exitosos\"",[144,8606,391],{"class":261},[144,8608,8609,8611],{"class":146,"line":874},[144,8610,1511],{"class":257},[144,8612,8613],{"class":261}," results\n",[144,8615,8616],{"class":146,"line":899},[144,8617,356],{"emptyLinePlaceholder":57},[144,8619,8620],{"class":146,"line":920},[144,8621,356],{"emptyLinePlaceholder":57},[144,8623,8624],{"class":146,"line":926},[144,8625,8626],{"class":173},"# Ejemplo de uso\n",[144,8628,8629,8632,8634],{"class":146,"line":931},[144,8630,8631],{"class":261},"prompts ",[144,8633,265],{"class":257},[144,8635,8636],{"class":261}," [\n",[144,8638,8639,8642],{"class":146,"line":955},[144,8640,8641],{"class":158},"    \"Un colibrí revoloteando cerca de una flor roja. Macro, poca profundidad de campo.\"",[144,8643,468],{"class":261},[144,8645,8646,8649],{"class":146,"line":980},[144,8647,8648],{"class":158},"    \"Olas oceánicas chocando contra rocas volcánicas al atardecer. Cámara lenta.\"",[144,8650,468],{"class":261},[144,8652,8653,8656],{"class":146,"line":986},[144,8654,8655],{"class":158},"    \"Un músico callejero tocando violín bajo la lluvia. Iluminación cinematográfica.\"",[144,8657,468],{"class":261},[144,8659,8660],{"class":146,"line":991},[144,8661,643],{"class":261},[144,8663,8664,8667,8670,8672,8674],{"class":146,"line":1008},[144,8665,8666],{"class":261},"batch_generate(prompts, ",[144,8668,8669],{"class":592},"max_concurrent",[144,8671,265],{"class":257},[144,8673,5236],{"class":154},[144,8675,391],{"class":261},[10,8677,8678],{},"Consideraciones clave para el procesamiento por lotes:",[96,8680,8681,8689,8695],{},[72,8682,8683,8688],{},[22,8684,8685],{},[27,8686,8687],{},"max_concurrent=3"," — No envíe demasiadas solicitudes simultáneamente. Comience con 2–3 y aumente según sus límites de tasa.",[72,8690,8691,8694],{},[22,8692,8693],{},"ThreadPoolExecutor"," — Usa hilos (no procesos) porque estamos limitados por I/O (esperando respuestas de API), no por CPU.",[72,8696,8697,8700],{},[22,8698,8699],{},"Aislamiento de errores"," — Cada generación de video es independiente. Un fallo no detiene el lote.",[44,8702],{},[47,8704,8706],{"id":8705},"qué-sigue","Qué Sigue",[10,8708,8709],{},"Ya domina los fundamentos — texto a video, imagen a video, polling asíncrono, webhooks, manejo de errores y procesamiento por lotes. Aquí es dónde profundizar:",[91,8711,8713],{"id":8712},"explorar-características-avanzadas","Explorar Características Avanzadas",[96,8715,8716,8724,8731,8739,8747],{},[72,8717,8718,8723],{},[22,8719,8720],{},[36,8721,8722],{"href":2780},"Guía de Referencia Multimodal @Tags"," — Domine el sistema de referencia @Image, @Video, @Audio para generación multi-modal",[72,8725,8726,8730],{},[22,8727,8728],{},[36,8729,3672],{"href":3671}," — Replique zooms Hitchcock, tomas de seguimiento en una toma y cámaras orbitales programáticamente",[72,8732,8733,8738],{},[22,8734,8735],{},[36,8736,8737],{"href":3195},"Guía Profunda de Imagen a Video"," — Control de primer-último fotograma, composición multi-imagen, videos de productos de e-commerce",[72,8740,8741,8746],{},[22,8742,8743],{},[36,8744,8745],{"href":2427},"Guía de Video de Producto para E-commerce"," — Convierta fotos de productos en videos de marketing a escala",[72,8748,8749,8753],{},[22,8750,8751],{},[36,8752,1578],{"href":1577}," — Formato de guion de tomas, sintaxis de temporización y los prompts detrás de nuestros videos de demo",[91,8755,8757],{"id":8756},"documentación-de-referencia","Documentación de Referencia",[96,8759,8760,8767,8774],{},[72,8761,8762],{},[36,8763,8766],{"href":8764,"rel":8765},"https://seedance2api.app/docs/video-generation",[40],"Referencia de API de Generación de Video",[72,8768,8769],{},[36,8770,8773],{"href":8771,"rel":8772},"https://seedance2api.app/docs/multimodal-reference",[40],"Especificaciones de Referencia Multimodal",[72,8775,8776],{},[36,8777,8780],{"href":8778,"rel":8779},"https://seedance2api.app/docs/sdks",[40],"SDKs de Python y Node.js",[91,8782,8784],{"id":8783},"construya-algo","Construya Algo",[10,8786,8787],{},"Combine lo que ha aprendido. Aquí hay algunas ideas de proyectos:",[96,8789,8790,8799,8805,8814],{},[72,8791,8792,8795,8796,107],{},[22,8793,8794],{},"Pipeline automatizado de video de producto"," — Suba fotos de productos, genere videos de marketing en lotes (vea nuestra ",[36,8797,8798],{"href":2427},"Guía de Video para E-commerce",[72,8800,8801,8804],{},[22,8802,8803],{},"Motor de contenido para redes sociales"," — Genere videos verticales de formato corto a partir de descripciones de texto, publique directamente en TikTok/Reels",[72,8806,8807,8810,8811],{},[22,8808,8809],{},"Herramienta de storyboard a video"," — Convierta imágenes secuenciales en escenas animadas con ",[36,8812,8813],{"href":3671},"control de movimiento de cámara",[72,8815,8816,8819],{},[22,8817,8818],{},"Pipeline de edición de video con IA"," — Use la extensión de video de Seedance 2.0 para crear narrativas más largas a partir de clips más cortos",[10,8821,8822],{},[22,8823,8824,8825,8829],{},"¿Listo para construir? ",[36,8826,8828],{"href":38,"rel":8827},[40],"Obtenga su clave API gratuita de EvoLink"," y comience a generar videos hoy.",[44,8831],{},[47,8833,8835],{"id":8834},"preguntas-frecuentes","Preguntas Frecuentes",[91,8837,8839],{"id":8838},"cuánto-tarda-la-generación-de-video-de-seedance-20","¿Cuánto tarda la generación de video de Seedance 2.0?",[10,8841,8842,8843,8845],{},"Típicamente entre 30 y 120 segundos dependiendo de la duración y configuración de calidad. Un video de 5 segundos en 720p se completa en aproximadamente 50 segundos. Un video de 15 segundos en 1080p puede tardar de 2 a 3 minutos. La API devuelve un campo ",[27,8844,1918],{}," con cada tarea para que pueda establecer timeouts apropiados. Durante las horas pico, los tiempos de espera en cola pueden agregar de 10 a 30 segundos al total.",[91,8847,8849],{"id":8848},"qué-formatos-de-imagen-acepta-la-api-de-seedance-20","¿Qué formatos de imagen acepta la API de Seedance 2.0?",[10,8851,8852,8853,8855],{},"JPEG, PNG, WebP, BMP, TIFF y GIF. Cada imagen debe pesar menos de 30 MB. Puede pasar hasta 9 imágenes por solicitud a través del parámetro ",[27,8854,2709],{},". Las imágenes deben ser URLs públicamente accesibles — la API las recupera directamente. Para mejores resultados, use imágenes de al menos 720px en el lado más corto. Las imágenes de muy baja resolución (por debajo de 256px) pueden producir animaciones borrosas.",[91,8857,8859],{"id":8858},"puedo-generar-videos-de-más-de-15-segundos","¿Puedo generar videos de más de 15 segundos?",[10,8861,8862,8863,8865],{},"El máximo de una sola generación es 15 segundos. Para contenido más largo, genere múltiples clips y concaténelos usando FFmpeg o cualquier editor de video. Seedance 2.0 soporta extensión de video — puede usar el último fotograma de un video generado como primer fotograma de la siguiente generación para crear continuidad sin fisuras. Aquí está el enfoque básico: genere el clip 1, extraiga el último fotograma, páselo como ",[27,8864,2808],{}," para el clip 2.",[91,8867,8869],{"id":8868},"cuánto-cuesta-la-api-de-seedance-20-a-través-de-evolink","¿Cuánto cuesta la API de Seedance 2.0 a través de EvoLink?",[10,8871,8872,8873,8877,8878,8880],{},"El precio se basa en la duración del video y el nivel de calidad. Un video de 5 segundos en 720p cuesta aproximadamente 18 créditos. EvoLink proporciona ",[36,8874,8876],{"href":210,"rel":8875},[40],"enrutamiento inteligente"," que puede reducir costos en comparación con el acceso directo a la API. Consulte su panel de control para las tarifas actuales por segundo. El campo ",[27,8879,1928],{}," en la respuesta de la API muestra el costo exacto antes de que comience la generación — nunca se le cobrará más de esa cantidad.",[91,8882,8884],{"id":8883},"cuál-es-la-diferencia-entre-seedance-15-pro-y-seedance-20","¿Cuál es la diferencia entre seedance-1.5-pro y seedance-2.0?",[10,8886,8887,8888,8890,8891,8893,8894,8898],{},"Seedance 2.0 agrega referencias multimodales (mezcle imágenes, videos y audio como entradas), generación de audio nativa, física y consistencia mejoradas, y capacidades de edición de video. La interfaz de la API es idéntica — mismo endpoint, mismos parámetros, mismo formato de respuesta. Puede probar con ",[27,8889,29],{}," hoy y cambiar a ",[27,8892,1562],{}," cambiando el nombre del modelo. Limitaciones clave de 1.5: solo entrada de imagen única (sin @Image2–9), sin referencias de video/audio, sin generación de audio nativa. Vea la ",[36,8895,8897],{"href":8896},"/blog/seedance-2-vs-sora-2-api-comparison","comparación de Seedance 2.0 vs Sora 2"," para benchmarks.",[91,8900,8902],{"id":8901},"cómo-manejo-el-error-content-rejected-by-safety-filter","¿Cómo manejo el error \"content rejected by safety filter\"?",[10,8904,8905,8906,8908,8909,8912],{},"El sistema de moderación de contenido rechaza prompts que involucren violencia realista, contenido explícito y figuras públicas reales. También rechaza imágenes de rostros humanos realistas subidas a través de ",[27,8907,2709],{},". Para evitar restricciones de rostros, use imágenes de personajes ilustrados, estilizados o de estilo anime. Para rechazos de prompts, reformule para ser menos específico sobre temas restringidos. La respuesta de error incluye ",[27,8910,8911],{},"type: \"content_policy_violation\""," — verifique esto en su código de manejo de errores para dar a los usuarios un mensaje claro.",[91,8914,8916],{"id":8915},"puedo-usar-la-api-de-seedance-en-un-proyecto-nodejs-javascript","¿Puedo usar la API de Seedance en un proyecto Node.js / JavaScript?",[10,8918,8919,8920,1897,8923,8926,8927,8931],{},"Sí. La API REST es independiente del lenguaje — cualquier cliente HTTP funciona. Los conceptos en este tutorial (polling asíncrono, webhooks, manejo de errores) se aplican directamente a Node.js con ",[27,8921,8922],{},"fetch",[27,8924,8925],{},"axios",". EvoLink también proporciona ",[36,8928,8930],{"href":8778,"rel":8929},[40],"SDKs oficiales de Node.js y Python"," que manejan el polling y los reintentos por usted.",[91,8933,8935],{"id":8934},"qué-pasa-si-mi-servidor-de-webhook-está-caído-cuando-el-video-se-completa","¿Qué pasa si mi servidor de webhook está caído cuando el video se completa?",[10,8937,8938,8939,8942],{},"La API reintenta la entrega del webhook 3 veces con intervalos crecientes (1s, 2s, 4s). Si los 3 reintentos fallan, el webhook se abandona — pero el video sigue disponible. Siempre puede recurrir al polling con ",[27,8940,8941],{},"GET /v1/tasks/{task_id}"," para recuperar el resultado. Por esta razón, es una buena práctica almacenar el ID de tarea al enviar y tener un trabajo en segundo plano que verifique periódicamente si hay tareas que se completaron pero no se recibieron a través del webhook.",[91,8944,8946],{"id":8945},"hay-un-límite-de-tasa-en-las-solicitudes-de-api","¿Hay un límite de tasa en las solicitudes de API?",[10,8948,8949,8950,8952,8953,8957,8958,8962],{},"Sí. El límite de tasa predeterminado es generoso para desarrollo y uso de producción moderado. Si recibe un error ",[27,8951,4755],{},", implemente retroceso exponencial como se muestra en la ",[36,8954,8956],{"href":8955},"#manejar-errores-con-elegancia","sección de manejo de errores",". Para casos de uso de alto volumen (miles de videos por día), contacte al ",[36,8959,8961],{"href":210,"rel":8960},[40],"soporte de EvoLink"," para discutir límites de tasa personalizados y capacidad dedicada.",[91,8964,8966],{"id":8965},"puedo-usar-seedance-20-para-proyectos-comerciales","¿Puedo usar Seedance 2.0 para proyectos comerciales?",[10,8968,8969,8970,8974],{},"Sí. Los videos generados a través de la API de EvoLink están licenciados para uso comercial. Usted es propietario de los resultados y puede usarlos en productos, materiales de marketing, entregas a clientes y contenido publicado. Vea la ",[36,8971,8973],{"href":8972},"/blog/seedance-2-copyright-api-guide","guía de derechos de autor de Seedance 2.0"," para términos de licencia detallados y mejores prácticas para uso comercial.",[44,8976],{},[47,8978,8980],{"id":8979},"script-completo","Script Completo",[10,8982,8983],{},"Aquí está el código completo del tutorial en un solo archivo — copie, pegue, agregue su clave API y ejecute:",[135,8985,8987],{"className":325,"code":8986,"language":327,"meta":140,"style":140},"\"\"\"\nTutorial de API de Seedance 2.0 — Script Completo\nDocs: https://seedance2api.app/docs/video-generation\nClave API: https://evolink.ai/early-access\n\"\"\"\nimport requests\nimport time\nimport os\nimport json\nimport random\n\n# ── Configuración ─────────────────────────────────────────────\nAPI_KEY = os.getenv(\"EVOLINK_API_KEY\", \"sk-your-api-key-here\")\nBASE_URL = \"https://api.evolink.ai/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {API_KEY}\",\n    \"Content-Type\": \"application/json\"\n}\n\n\n# ── Funciones Auxiliares Reutilizables ────────────────────────\ndef wait_for_video(task_id, poll_interval=10, timeout=600):\n    \"\"\"Realiza polling de una tarea de generación de video hasta completarse.\"\"\"\n    elapsed = 0\n    while elapsed \u003C timeout:\n        response = requests.get(\n            f\"{BASE_URL}/tasks/{task_id}\",\n            headers=HEADERS\n        )\n        response.raise_for_status()\n        task = response.json()\n        status = task[\"status\"]\n        progress = task.get(\"progress\", 0)\n        print(f\"  [{elapsed}s] Estado: {status} | Progreso: {progress}%\")\n        if status == \"completed\":\n            return task\n        elif status == \"failed\":\n            raise RuntimeError(f\"Tarea {task_id} fallida: {task}\")\n        time.sleep(poll_interval)\n        elapsed += poll_interval\n    raise TimeoutError(f\"Tarea {task_id} expiró después de {timeout}s\")\n\n\ndef download_video(url, filename=\"output.mp4\"):\n    \"\"\"Descarga un archivo de video desde una URL.\"\"\"\n    print(f\"Descargando a {filename}...\")\n    resp = requests.get(url, stream=True)\n    resp.raise_for_status()\n    with open(filename, \"wb\") as f:\n        for chunk in resp.iter_content(chunk_size=8192):\n            f.write(chunk)\n    print(f\"Guardado: {filename} ({os.path.getsize(filename) / 1024:.0f} KB)\")\n\n\ndef generate_video_with_retry(payload, max_retries=3):\n    \"\"\"Envía una solicitud de generación con reintento para errores transitorios.\"\"\"\n    for attempt in range(max_retries):\n        try:\n            response = requests.post(\n                f\"{BASE_URL}/videos/generations\",\n                headers=HEADERS,\n                json=payload,\n                timeout=30\n            )\n            if response.status_code == 200:\n                return response.json()\n            error = response.json().get(\"error\", {})\n            if response.status_code in (400, 401, 402, 404, 413, 422):\n                raise ValueError(\n                    f\"Error de API {response.status_code}: \"\n                    f\"{error.get('message', 'Desconocido')}\"\n                )\n            if response.status_code in (429, 500, 502, 503):\n                wait = (2 ** attempt) + random.uniform(0, 1)\n                print(f\"  Reintento {attempt+1}/{max_retries} después de {wait:.1f}s\")\n                time.sleep(wait)\n                continue\n        except requests.exceptions.RequestException:\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Reintento {attempt+1}/{max_retries} después de {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n    raise RuntimeError(f\"Fallo tras {max_retries} reintentos\")\n\n\ndef validate_payload(payload):\n    \"\"\"Valida el payload de generación antes de la llamada a la API.\"\"\"\n    errors = []\n    if not payload.get(\"model\"):\n        errors.append(\"'model' es requerido\")\n    if not payload.get(\"prompt\") or not payload[\"prompt\"].strip():\n        errors.append(\"'prompt' es requerido\")\n    duration = payload.get(\"duration\", 5)\n    if duration \u003C 4 or duration > 15:\n        errors.append(f\"'duration' debe ser 4-15, se obtuvo {duration}\")\n    quality = payload.get(\"quality\", \"720p\")\n    if quality not in {\"480p\", \"720p\", \"1080p\"}:\n        errors.append(f\"Calidad inválida: {quality}\")\n    if errors:\n        raise ValueError(\"Validación fallida:\\n\" + \"\\n\".join(f\"  - {e}\" for e in errors))\n\n\ndef cancel_task(task_id):\n    \"\"\"Cancela una tarea pendiente o en procesamiento.\"\"\"\n    response = requests.post(\n        f\"{BASE_URL}/tasks/{task_id}/cancel\",\n        headers=HEADERS\n    )\n    if response.status_code == 200:\n        print(f\"Tarea {task_id} cancelada.\")\n    else:\n        print(f\"Cancelación fallida: {response.json()}\")\n\n\n# ── Ejemplo 1: Texto a Video ──────────────────────────────────\ndef text_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"Un cachorro golden retriever persigue una mariposa a través \"\n            \"de un prado iluminado por el sol. La cámara sigue al cachorro con un \"\n            \"plano de seguimiento suave mientras las flores silvestres se mecen con la brisa.\"\n        ),\n        \"duration\": 5,\n        \"quality\": \"720p\",\n        \"aspect_ratio\": \"16:9\",\n        \"generate_audio\": True\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Tarea: {task['id']} (ETA: {task['task_info']['estimated_time']}s)\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"texto_a_video.mp4\")\n\n\n# ── Ejemplo 2: Imagen a Video ─────────────────────────────────\ndef image_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"@Image1 as the first frame. La escena cobra vida lentamente \"\n            \"— las hojas se mecen suavemente, la luz suave se desplaza \"\n            \"por el encuadre.\"\n        ),\n        \"image_urls\": [\"https://example.com/your-image.jpg\"],\n        \"duration\": 5,\n        \"quality\": \"720p\"\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Tarea: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"imagen_a_video.mp4\")\n\n\n# ── Ejemplo 3: Video Vertical para Redes Sociales ─────────────\ndef social_media_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"Un barista vierte latte art en cámara lenta. \"\n            \"Plano cenital cerrado, iluminación cálida de café.\"\n        ),\n        \"duration\": 8,\n        \"quality\": \"1080p\",\n        \"aspect_ratio\": \"9:16\",\n        \"generate_audio\": True\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Tarea: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"video_social.mp4\")\n\n\nif __name__ == \"__main__\":\n    print(\"=== Texto a Video ===\")\n    text_to_video()\n    # print(\"\\n=== Imagen a Video ===\")\n    # image_to_video()  # Descomente y configure su URL de imagen\n    # print(\"\\n=== Video para Redes Sociales ===\")\n    # social_media_video()\n",[27,8988,8989,8993,8998,9003,9008,9012,9018,9024,9030,9036,9042,9046,9051,9068,9077,9085,9101,9109,9113,9117,9121,9126,9148,9153,9163,9175,9183,9203,9211,9215,9219,9227,9239,9255,9291,9303,9309,9321,9353,9357,9367,9399,9403,9407,9423,9428,9449,9466,9471,9487,9505,9509,9544,9548,9552,9566,9571,9583,9589,9597,9609,9619,9627,9636,9640,9652,9658,9670,9704,9712,9727,9752,9756,9782,9808,9851,9855,9859,9866,9892,9932,9936,9940,9962,9966,9970,9978,9983,9991,10003,10011,10033,10042,10058,10078,10096,10112,10137,10156,10162,10208,10213,10218,10227,10233,10242,10263,10272,10277,10290,10312,10319,10340,10345,10350,10356,10365,10374,10385,10392,10397,10402,10407,10412,10423,10434,10445,10454,10459,10465,10474,10518,10531,10551,10556,10561,10567,10576,10585,10596,10603,10608,10613,10619,10624,10638,10649,10658,10663,10668,10677,10702,10715,10733,10738,10743,10749,10759,10768,10779,10786,10792,10798,10803,10814,10825,10836,10845,10850,10855,10864,10889,10902,10920,10925,10930,10943,10955,10960,10966,10972,10978],{"__ignoreMap":140},[144,8990,8991],{"class":146,"line":147},[144,8992,6506],{"class":158},[144,8994,8995],{"class":146,"line":165},[144,8996,8997],{"class":158},"Tutorial de API de Seedance 2.0 — Script Completo\n",[144,8999,9000],{"class":146,"line":177},[144,9001,9002],{"class":158},"Docs: https://seedance2api.app/docs/video-generation\n",[144,9004,9005],{"class":146,"line":186},[144,9006,9007],{"class":158},"Clave API: https://evolink.ai/early-access\n",[144,9009,9010],{"class":146,"line":359},[144,9011,6506],{"class":158},[144,9013,9014,9016],{"class":146,"line":365},[144,9015,334],{"class":257},[144,9017,351],{"class":261},[144,9019,9020,9022],{"class":146,"line":377},[144,9021,334],{"class":257},[144,9023,344],{"class":261},[144,9025,9026,9028],{"class":146,"line":394},[144,9027,334],{"class":257},[144,9029,337],{"class":261},[144,9031,9032,9034],{"class":146,"line":399},[144,9033,334],{"class":257},[144,9035,6545],{"class":261},[144,9037,9038,9040],{"class":146,"line":414},[144,9039,334],{"class":257},[144,9041,4854],{"class":261},[144,9043,9044],{"class":146,"line":431},[144,9045,356],{"emptyLinePlaceholder":57},[144,9047,9048],{"class":146,"line":436},[144,9049,9050],{"class":173},"# ── Configuración ─────────────────────────────────────────────\n",[144,9052,9053,9055,9057,9059,9061,9063,9066],{"class":146,"line":447},[144,9054,380],{"class":154},[144,9056,371],{"class":257},[144,9058,6611],{"class":261},[144,9060,388],{"class":158},[144,9062,289],{"class":261},[144,9064,9065],{"class":158},"\"sk-your-api-key-here\"",[144,9067,391],{"class":261},[144,9069,9070,9072,9074],{"class":146,"line":471},[144,9071,368],{"class":154},[144,9073,371],{"class":257},[144,9075,9076],{"class":158}," \"https://api.evolink.ai/v1\"\n",[144,9078,9079,9081,9083],{"class":146,"line":482},[144,9080,439],{"class":154},[144,9082,371],{"class":257},[144,9084,444],{"class":261},[144,9086,9087,9089,9091,9093,9095,9097,9099],{"class":146,"line":488},[144,9088,450],{"class":158},[144,9090,453],{"class":261},[144,9092,456],{"class":257},[144,9094,459],{"class":158},[144,9096,462],{"class":154},[144,9098,465],{"class":158},[144,9100,468],{"class":261},[144,9102,9103,9105,9107],{"class":146,"line":493},[144,9104,474],{"class":158},[144,9106,453],{"class":261},[144,9108,479],{"class":158},[144,9110,9111],{"class":146,"line":498},[144,9112,485],{"class":261},[144,9114,9115],{"class":146,"line":518},[144,9116,356],{"emptyLinePlaceholder":57},[144,9118,9119],{"class":146,"line":524},[144,9120,356],{"emptyLinePlaceholder":57},[144,9122,9123],{"class":146,"line":535},[144,9124,9125],{"class":173},"# ── Funciones Auxiliares Reutilizables ────────────────────────\n",[144,9127,9128,9130,9132,9134,9136,9138,9141,9143,9146],{"class":146,"line":540},[144,9129,501],{"class":257},[144,9131,504],{"class":150},[144,9133,507],{"class":261},[144,9135,265],{"class":257},[144,9137,512],{"class":154},[144,9139,9140],{"class":261},", timeout",[144,9142,265],{"class":257},[144,9144,9145],{"class":154},"600",[144,9147,515],{"class":261},[144,9149,9150],{"class":146,"line":551},[144,9151,9152],{"class":158},"    \"\"\"Realiza polling de una tarea de generación de video hasta completarse.\"\"\"\n",[144,9154,9155,9158,9160],{"class":146,"line":562},[144,9156,9157],{"class":261},"    elapsed ",[144,9159,265],{"class":257},[144,9161,9162],{"class":154}," 0\n",[144,9164,9165,9167,9170,9172],{"class":146,"line":589},[144,9166,543],{"class":257},[144,9168,9169],{"class":261}," elapsed ",[144,9171,5783],{"class":257},[144,9173,9174],{"class":261}," timeout:\n",[144,9176,9177,9179,9181],{"class":146,"line":601},[144,9178,554],{"class":261},[144,9180,265],{"class":257},[144,9182,559],{"class":261},[144,9184,9185,9187,9189,9191,9193,9195,9197,9199,9201],{"class":146,"line":607},[144,9186,565],{"class":257},[144,9188,465],{"class":158},[144,9190,570],{"class":154},[144,9192,573],{"class":158},[144,9194,576],{"class":154},[144,9196,579],{"class":261},[144,9198,582],{"class":154},[144,9200,465],{"class":158},[144,9202,468],{"class":261},[144,9204,9205,9207,9209],{"class":146,"line":613},[144,9206,593],{"class":592},[144,9208,265],{"class":257},[144,9210,598],{"class":154},[144,9212,9213],{"class":146,"line":624},[144,9214,604],{"class":261},[144,9216,9217],{"class":146,"line":629},[144,9218,610],{"class":261},[144,9220,9221,9223,9225],{"class":146,"line":646},[144,9222,616],{"class":261},[144,9224,265],{"class":257},[144,9226,621],{"class":261},[144,9228,9229,9231,9233,9235,9237],{"class":146,"line":667},[144,9230,632],{"class":261},[144,9232,265],{"class":257},[144,9234,637],{"class":261},[144,9236,640],{"class":158},[144,9238,643],{"class":261},[144,9240,9241,9243,9245,9247,9249,9251,9253],{"class":146,"line":687},[144,9242,649],{"class":261},[144,9244,265],{"class":257},[144,9246,654],{"class":261},[144,9248,657],{"class":158},[144,9250,289],{"class":261},[144,9252,662],{"class":154},[144,9254,391],{"class":261},[144,9256,9257,9259,9261,9263,9265,9267,9269,9271,9273,9275,9277,9279,9281,9283,9285,9287,9289],{"class":146,"line":692},[144,9258,695],{"class":154},[144,9260,423],{"class":261},[144,9262,456],{"class":257},[144,9264,702],{"class":158},[144,9266,576],{"class":154},[144,9268,707],{"class":261},[144,9270,582],{"class":154},[144,9272,712],{"class":158},[144,9274,576],{"class":154},[144,9276,717],{"class":261},[144,9278,582],{"class":154},[144,9280,722],{"class":158},[144,9282,576],{"class":154},[144,9284,727],{"class":261},[144,9286,582],{"class":154},[144,9288,732],{"class":158},[144,9290,391],{"class":261},[144,9292,9293,9295,9297,9299,9301],{"class":146,"line":737},[144,9294,745],{"class":257},[144,9296,748],{"class":261},[144,9298,751],{"class":257},[144,9300,754],{"class":158},[144,9302,411],{"class":261},[144,9304,9305,9307],{"class":146,"line":742},[144,9306,762],{"class":257},[144,9308,765],{"class":261},[144,9310,9311,9313,9315,9317,9319],{"class":146,"line":759},[144,9312,771],{"class":257},[144,9314,748],{"class":261},[144,9316,751],{"class":257},[144,9318,778],{"class":158},[144,9320,411],{"class":261},[144,9322,9323,9325,9327,9329,9331,9333,9335,9337,9339,9342,9344,9347,9349,9351],{"class":146,"line":768},[144,9324,812],{"class":257},[144,9326,5568],{"class":154},[144,9328,423],{"class":261},[144,9330,456],{"class":257},[144,9332,2340],{"class":158},[144,9334,576],{"class":154},[144,9336,579],{"class":261},[144,9338,582],{"class":154},[144,9340,9341],{"class":158}," fallida: ",[144,9343,576],{"class":154},[144,9345,9346],{"class":261},"task",[144,9348,582],{"class":154},[144,9350,465],{"class":158},[144,9352,391],{"class":261},[144,9354,9355],{"class":146,"line":783},[144,9356,844],{"class":261},[144,9358,9359,9361,9364],{"class":146,"line":809},[144,9360,670],{"class":261},[144,9362,9363],{"class":257},"+=",[144,9365,9366],{"class":261}," poll_interval\n",[144,9368,9369,9371,9374,9376,9378,9380,9382,9384,9386,9389,9391,9393,9395,9397],{"class":146,"line":836},[144,9370,417],{"class":257},[144,9372,9373],{"class":154}," TimeoutError",[144,9375,423],{"class":261},[144,9377,456],{"class":257},[144,9379,2340],{"class":158},[144,9381,576],{"class":154},[144,9383,579],{"class":261},[144,9385,582],{"class":154},[144,9387,9388],{"class":158}," expiró después de ",[144,9390,576],{"class":154},[144,9392,6748],{"class":261},[144,9394,582],{"class":154},[144,9396,1368],{"class":158},[144,9398,391],{"class":261},[144,9400,9401],{"class":146,"line":841},[144,9402,356],{"emptyLinePlaceholder":57},[144,9404,9405],{"class":146,"line":847},[144,9406,356],{"emptyLinePlaceholder":57},[144,9408,9409,9411,9413,9416,9418,9421],{"class":146,"line":852},[144,9410,501],{"class":257},[144,9412,862],{"class":150},[144,9414,9415],{"class":261},"(url, filename",[144,9417,265],{"class":257},[144,9419,9420],{"class":158},"\"output.mp4\"",[144,9422,515],{"class":261},[144,9424,9425],{"class":146,"line":857},[144,9426,9427],{"class":158},"    \"\"\"Descarga un archivo de video desde una URL.\"\"\"\n",[144,9429,9430,9432,9434,9436,9439,9441,9443,9445,9447],{"class":146,"line":868},[144,9431,877],{"class":154},[144,9433,423],{"class":261},[144,9435,456],{"class":257},[144,9437,9438],{"class":158},"\"Descargando a ",[144,9440,576],{"class":154},[144,9442,889],{"class":261},[144,9444,582],{"class":154},[144,9446,894],{"class":158},[144,9448,391],{"class":261},[144,9450,9451,9454,9456,9458,9460,9462,9464],{"class":146,"line":874},[144,9452,9453],{"class":261},"    resp ",[144,9455,265],{"class":257},[144,9457,907],{"class":261},[144,9459,910],{"class":592},[144,9461,265],{"class":257},[144,9463,915],{"class":154},[144,9465,391],{"class":261},[144,9467,9468],{"class":146,"line":899},[144,9469,9470],{"class":261},"    resp.raise_for_status()\n",[144,9472,9473,9475,9477,9479,9481,9483,9485],{"class":146,"line":920},[144,9474,934],{"class":257},[144,9476,937],{"class":154},[144,9478,940],{"class":261},[144,9480,943],{"class":158},[144,9482,946],{"class":261},[144,9484,949],{"class":257},[144,9486,952],{"class":261},[144,9488,9489,9491,9493,9495,9497,9499,9501,9503],{"class":146,"line":926},[144,9490,958],{"class":257},[144,9492,961],{"class":261},[144,9494,964],{"class":257},[144,9496,6789],{"class":261},[144,9498,970],{"class":592},[144,9500,265],{"class":257},[144,9502,975],{"class":154},[144,9504,515],{"class":261},[144,9506,9507],{"class":146,"line":931},[144,9508,983],{"class":261},[144,9510,9511,9513,9515,9517,9519,9521,9523,9525,9527,9529,9532,9534,9536,9538,9540,9542],{"class":146,"line":955},[144,9512,877],{"class":154},[144,9514,423],{"class":261},[144,9516,456],{"class":257},[144,9518,1017],{"class":158},[144,9520,576],{"class":154},[144,9522,889],{"class":261},[144,9524,582],{"class":154},[144,9526,113],{"class":158},[144,9528,576],{"class":154},[144,9530,9531],{"class":261},"os.path.getsize(filename) ",[144,9533,1002],{"class":257},[144,9535,6824],{"class":154},[144,9537,1033],{"class":257},[144,9539,582],{"class":154},[144,9541,1038],{"class":158},[144,9543,391],{"class":261},[144,9545,9546],{"class":146,"line":980},[144,9547,356],{"emptyLinePlaceholder":57},[144,9549,9550],{"class":146,"line":986},[144,9551,356],{"emptyLinePlaceholder":57},[144,9553,9554,9556,9558,9560,9562,9564],{"class":146,"line":991},[144,9555,501],{"class":257},[144,9557,4865],{"class":150},[144,9559,4868],{"class":261},[144,9561,265],{"class":257},[144,9563,4873],{"class":154},[144,9565,515],{"class":261},[144,9567,9568],{"class":146,"line":1008},[144,9569,9570],{"class":158},"    \"\"\"Envía una solicitud de generación con reintento para errores transitorios.\"\"\"\n",[144,9572,9573,9575,9577,9579,9581],{"class":146,"line":1043},[144,9574,4937],{"class":257},[144,9576,4940],{"class":261},[144,9578,964],{"class":257},[144,9580,4945],{"class":154},[144,9582,4948],{"class":261},[144,9584,9585,9587],{"class":146,"line":1048},[144,9586,4953],{"class":257},[144,9588,411],{"class":261},[144,9590,9591,9593,9595],{"class":146,"line":1053},[144,9592,4960],{"class":261},[144,9594,265],{"class":257},[144,9596,1218],{"class":261},[144,9598,9599,9601,9603,9605,9607],{"class":146,"line":1064},[144,9600,4969],{"class":257},[144,9602,465],{"class":158},[144,9604,570],{"class":154},[144,9606,1231],{"class":158},[144,9608,468],{"class":261},[144,9610,9611,9613,9615,9617],{"class":146,"line":1074},[144,9612,4982],{"class":592},[144,9614,265],{"class":257},[144,9616,439],{"class":154},[144,9618,468],{"class":261},[144,9620,9621,9623,9625],{"class":146,"line":1091},[144,9622,4993],{"class":592},[144,9624,265],{"class":257},[144,9626,4998],{"class":261},[144,9628,9629,9631,9633],{"class":146,"line":1100},[144,9630,5003],{"class":592},[144,9632,265],{"class":257},[144,9634,9635],{"class":154},"30\n",[144,9637,9638],{"class":146,"line":1106},[144,9639,5016],{"class":261},[144,9641,9642,9644,9646,9648,9650],{"class":146,"line":1112},[144,9643,5030],{"class":257},[144,9645,2322],{"class":261},[144,9647,751],{"class":257},[144,9649,2327],{"class":154},[144,9651,411],{"class":261},[144,9653,9654,9656],{"class":146,"line":1118},[144,9655,5043],{"class":257},[144,9657,621],{"class":261},[144,9659,9660,9662,9664,9666,9668],{"class":146,"line":1124},[144,9661,5059],{"class":261},[144,9663,265],{"class":257},[144,9665,5064],{"class":261},[144,9667,793],{"class":158},[144,9669,5069],{"class":261},[144,9671,9672,9674,9676,9678,9680,9682,9684,9686,9688,9690,9692,9694,9696,9698,9700,9702],{"class":146,"line":1141},[144,9673,5030],{"class":257},[144,9675,2322],{"class":261},[144,9677,964],{"class":257},[144,9679,113],{"class":261},[144,9681,3451],{"class":154},[144,9683,289],{"class":261},[144,9685,4665],{"class":154},[144,9687,289],{"class":261},[144,9689,4683],{"class":154},[144,9691,289],{"class":261},[144,9693,4701],{"class":154},[144,9695,289],{"class":261},[144,9697,4719],{"class":154},[144,9699,289],{"class":261},[144,9701,4737],{"class":154},[144,9703,515],{"class":261},[144,9705,9706,9708,9710],{"class":146,"line":1158},[144,9707,5153],{"class":257},[144,9709,420],{"class":154},[144,9711,5158],{"class":261},[144,9713,9714,9716,9718,9720,9722,9724],{"class":146,"line":1175},[144,9715,5163],{"class":257},[144,9717,5166],{"class":158},[144,9719,576],{"class":154},[144,9721,5171],{"class":261},[144,9723,582],{"class":154},[144,9725,9726],{"class":158},": \"\n",[144,9728,9729,9731,9733,9735,9738,9741,9743,9746,9748,9750],{"class":146,"line":1188},[144,9730,5163],{"class":257},[144,9732,465],{"class":158},[144,9734,576],{"class":154},[144,9736,9737],{"class":261},"error.get(",[144,9739,9740],{"class":158},"'message'",[144,9742,289],{"class":261},[144,9744,9745],{"class":158},"'Desconocido'",[144,9747,107],{"class":261},[144,9749,582],{"class":154},[144,9751,5184],{"class":158},[144,9753,9754],{"class":146,"line":1194},[144,9755,5189],{"class":261},[144,9757,9758,9760,9762,9764,9766,9768,9770,9772,9774,9776,9778,9780],{"class":146,"line":1199},[144,9759,5030],{"class":257},[144,9761,2322],{"class":261},[144,9763,964],{"class":257},[144,9765,113],{"class":261},[144,9767,4755],{"class":154},[144,9769,289],{"class":261},[144,9771,4776],{"class":154},[144,9773,289],{"class":261},[144,9775,4796],{"class":154},[144,9777,289],{"class":261},[144,9779,4816],{"class":154},[144,9781,515],{"class":261},[144,9783,9784,9786,9788,9790,9792,9794,9796,9798,9800,9802,9804,9806],{"class":146,"line":1211},[144,9785,5229],{"class":261},[144,9787,265],{"class":257},[144,9789,113],{"class":261},[144,9791,5236],{"class":154},[144,9793,5239],{"class":257},[144,9795,5242],{"class":261},[144,9797,5245],{"class":257},[144,9799,5248],{"class":261},[144,9801,662],{"class":154},[144,9803,289],{"class":261},[144,9805,5255],{"class":154},[144,9807,391],{"class":261},[144,9809,9810,9812,9814,9816,9818,9820,9823,9825,9828,9830,9832,9834,9836,9839,9841,9843,9845,9847,9849],{"class":146,"line":1221},[144,9811,5262],{"class":154},[144,9813,423],{"class":261},[144,9815,456],{"class":257},[144,9817,5269],{"class":158},[144,9819,576],{"class":154},[144,9821,9822],{"class":261},"attempt",[144,9824,5245],{"class":257},[144,9826,9827],{"class":154},"1}",[144,9829,1002],{"class":158},[144,9831,576],{"class":154},[144,9833,5286],{"class":261},[144,9835,582],{"class":154},[144,9837,9838],{"class":158}," después de ",[144,9840,576],{"class":154},[144,9842,5304],{"class":261},[144,9844,5307],{"class":257},[144,9846,582],{"class":154},[144,9848,1368],{"class":158},[144,9850,391],{"class":261},[144,9852,9853],{"class":146,"line":1240},[144,9854,5337],{"class":261},[144,9856,9857],{"class":146,"line":1256},[144,9858,5342],{"class":257},[144,9860,9861,9863],{"class":146,"line":1270},[144,9862,5351],{"class":257},[144,9864,9865],{"class":261}," requests.exceptions.RequestException:\n",[144,9867,9868,9870,9872,9874,9876,9878,9880,9882,9884,9886,9888,9890],{"class":146,"line":1276},[144,9869,5364],{"class":261},[144,9871,265],{"class":257},[144,9873,113],{"class":261},[144,9875,5236],{"class":154},[144,9877,5239],{"class":257},[144,9879,5242],{"class":261},[144,9881,5245],{"class":257},[144,9883,5248],{"class":261},[144,9885,662],{"class":154},[144,9887,289],{"class":261},[144,9889,5255],{"class":154},[144,9891,391],{"class":261},[144,9893,9894,9896,9898,9900,9902,9904,9906,9908,9910,9912,9914,9916,9918,9920,9922,9924,9926,9928,9930],{"class":146,"line":1285},[144,9895,5391],{"class":154},[144,9897,423],{"class":261},[144,9899,456],{"class":257},[144,9901,5269],{"class":158},[144,9903,576],{"class":154},[144,9905,9822],{"class":261},[144,9907,5245],{"class":257},[144,9909,9827],{"class":154},[144,9911,1002],{"class":158},[144,9913,576],{"class":154},[144,9915,5286],{"class":261},[144,9917,582],{"class":154},[144,9919,9838],{"class":158},[144,9921,576],{"class":154},[144,9923,5304],{"class":261},[144,9925,5307],{"class":257},[144,9927,582],{"class":154},[144,9929,1368],{"class":158},[144,9931,391],{"class":261},[144,9933,9934],{"class":146,"line":1299},[144,9935,5440],{"class":261},[144,9937,9938],{"class":146,"line":1304},[144,9939,5445],{"class":257},[144,9941,9942,9944,9946,9948,9950,9952,9954,9956,9958,9960],{"class":146,"line":1310},[144,9943,417],{"class":257},[144,9945,5568],{"class":154},[144,9947,423],{"class":261},[144,9949,456],{"class":257},[144,9951,5575],{"class":158},[144,9953,576],{"class":154},[144,9955,5286],{"class":261},[144,9957,582],{"class":154},[144,9959,5584],{"class":158},[144,9961,391],{"class":261},[144,9963,9964],{"class":146,"line":1339},[144,9965,356],{"emptyLinePlaceholder":57},[144,9967,9968],{"class":146,"line":1373},[144,9969,356],{"emptyLinePlaceholder":57},[144,9971,9972,9974,9976],{"class":146,"line":1405},[144,9973,501],{"class":257},[144,9975,5647],{"class":150},[144,9977,5650],{"class":261},[144,9979,9980],{"class":146,"line":1410},[144,9981,9982],{"class":158},"    \"\"\"Valida el payload de generación antes de la llamada a la API.\"\"\"\n",[144,9984,9985,9987,9989],{"class":146,"line":1416},[144,9986,5673],{"class":261},[144,9988,265],{"class":257},[144,9990,5678],{"class":261},[144,9992,9993,9995,9997,9999,10001],{"class":146,"line":1433},[144,9994,2319],{"class":257},[144,9996,405],{"class":257},[144,9998,5696],{"class":261},[144,10000,5699],{"class":158},[144,10002,515],{"class":261},[144,10004,10005,10007,10009],{"class":146,"line":1438},[144,10006,5706],{"class":261},[144,10008,5709],{"class":158},[144,10010,391],{"class":261},[144,10012,10013,10015,10017,10019,10021,10023,10025,10027,10029,10031],{"class":146,"line":1444},[144,10014,2319],{"class":257},[144,10016,405],{"class":257},[144,10018,5696],{"class":261},[144,10020,5722],{"class":158},[144,10022,946],{"class":261},[144,10024,5727],{"class":257},[144,10026,405],{"class":257},[144,10028,5732],{"class":261},[144,10030,5722],{"class":158},[144,10032,5737],{"class":261},[144,10034,10035,10037,10040],{"class":146,"line":1464},[144,10036,5706],{"class":261},[144,10038,10039],{"class":158},"\"'prompt' es requerido\"",[144,10041,391],{"class":261},[144,10043,10044,10046,10048,10050,10052,10054,10056],{"class":146,"line":1492},[144,10045,5760],{"class":261},[144,10047,265],{"class":257},[144,10049,5696],{"class":261},[144,10051,5767],{"class":158},[144,10053,289],{"class":261},[144,10055,1132],{"class":154},[144,10057,391],{"class":261},[144,10059,10060,10062,10064,10066,10068,10070,10072,10074,10076],{"class":146,"line":1503},[144,10061,2319],{"class":257},[144,10063,5780],{"class":261},[144,10065,5783],{"class":257},[144,10067,5786],{"class":154},[144,10069,5789],{"class":257},[144,10071,5780],{"class":261},[144,10073,5794],{"class":257},[144,10075,5797],{"class":154},[144,10077,411],{"class":261},[144,10079,10080,10082,10084,10086,10088,10090,10092,10094],{"class":146,"line":1508},[144,10081,5706],{"class":261},[144,10083,456],{"class":257},[144,10085,5808],{"class":158},[144,10087,576],{"class":154},[144,10089,1586],{"class":261},[144,10091,582],{"class":154},[144,10093,465],{"class":158},[144,10095,391],{"class":261},[144,10097,10098,10100,10102,10104,10106,10108,10110],{"class":146,"line":1517},[144,10099,5854],{"class":261},[144,10101,265],{"class":257},[144,10103,5696],{"class":261},[144,10105,5861],{"class":158},[144,10107,289],{"class":261},[144,10109,1149],{"class":158},[144,10111,391],{"class":261},[144,10113,10114,10116,10118,10120,10122,10124,10126,10128,10130,10132,10134],{"class":146,"line":1522},[144,10115,2319],{"class":257},[144,10117,5874],{"class":261},[144,10119,5877],{"class":257},[144,10121,5880],{"class":257},[144,10123,5837],{"class":261},[144,10125,3828],{"class":158},[144,10127,289],{"class":261},[144,10129,1149],{"class":158},[144,10131,289],{"class":261},[144,10133,3524],{"class":158},[144,10135,10136],{"class":261},"}:\n",[144,10138,10139,10141,10143,10146,10148,10150,10152,10154],{"class":146,"line":1527},[144,10140,5706],{"class":261},[144,10142,456],{"class":257},[144,10144,10145],{"class":158},"\"Calidad inválida: ",[144,10147,576],{"class":154},[144,10149,1594],{"class":261},[144,10151,582],{"class":154},[144,10153,465],{"class":158},[144,10155,391],{"class":261},[144,10157,10158,10160],{"class":146,"line":1543},[144,10159,2319],{"class":257},[144,10161,6149],{"class":261},[144,10163,10165,10167,10169,10171,10174,10176,10178,10180,10182,10184,10186,10188,10190,10192,10194,10196,10198,10200,10202,10204,10206],{"class":146,"line":10164},100,[144,10166,6154],{"class":257},[144,10168,420],{"class":154},[144,10170,423],{"class":261},[144,10172,10173],{"class":158},"\"Validación fallida:",[144,10175,1475],{"class":154},[144,10177,465],{"class":158},[144,10179,6170],{"class":257},[144,10181,6173],{"class":158},[144,10183,1475],{"class":154},[144,10185,465],{"class":158},[144,10187,6180],{"class":261},[144,10189,456],{"class":257},[144,10191,6185],{"class":158},[144,10193,576],{"class":154},[144,10195,5508],{"class":261},[144,10197,582],{"class":154},[144,10199,465],{"class":158},[144,10201,6196],{"class":257},[144,10203,6199],{"class":261},[144,10205,964],{"class":257},[144,10207,6204],{"class":261},[144,10209,10211],{"class":146,"line":10210},101,[144,10212,356],{"emptyLinePlaceholder":57},[144,10214,10216],{"class":146,"line":10215},102,[144,10217,356],{"emptyLinePlaceholder":57},[144,10219,10221,10223,10225],{"class":146,"line":10220},103,[144,10222,501],{"class":257},[144,10224,2265],{"class":150},[144,10226,2268],{"class":261},[144,10228,10230],{"class":146,"line":10229},104,[144,10231,10232],{"class":158},"    \"\"\"Cancela una tarea pendiente o en procesamiento.\"\"\"\n",[144,10234,10236,10238,10240],{"class":146,"line":10235},105,[144,10237,902],{"class":261},[144,10239,265],{"class":257},[144,10241,1218],{"class":261},[144,10243,10245,10247,10249,10251,10253,10255,10257,10259,10261],{"class":146,"line":10244},106,[144,10246,1224],{"class":257},[144,10248,465],{"class":158},[144,10250,570],{"class":154},[144,10252,573],{"class":158},[144,10254,576],{"class":154},[144,10256,579],{"class":261},[144,10258,582],{"class":154},[144,10260,2300],{"class":158},[144,10262,468],{"class":261},[144,10264,10266,10268,10270],{"class":146,"line":10265},107,[144,10267,1243],{"class":592},[144,10269,265],{"class":257},[144,10271,598],{"class":154},[144,10273,10275],{"class":146,"line":10274},108,[144,10276,1273],{"class":261},[144,10278,10280,10282,10284,10286,10288],{"class":146,"line":10279},109,[144,10281,2319],{"class":257},[144,10283,2322],{"class":261},[144,10285,751],{"class":257},[144,10287,2327],{"class":154},[144,10289,411],{"class":261},[144,10291,10293,10295,10297,10299,10301,10303,10305,10307,10310],{"class":146,"line":10292},110,[144,10294,695],{"class":154},[144,10296,423],{"class":261},[144,10298,456],{"class":257},[144,10300,2340],{"class":158},[144,10302,576],{"class":154},[144,10304,579],{"class":261},[144,10306,582],{"class":154},[144,10308,10309],{"class":158}," cancelada.\"",[144,10311,391],{"class":261},[144,10313,10315,10317],{"class":146,"line":10314},111,[144,10316,2356],{"class":257},[144,10318,411],{"class":261},[144,10320,10322,10324,10326,10328,10330,10332,10334,10336,10338],{"class":146,"line":10321},112,[144,10323,695],{"class":154},[144,10325,423],{"class":261},[144,10327,456],{"class":257},[144,10329,2369],{"class":158},[144,10331,576],{"class":154},[144,10333,2374],{"class":261},[144,10335,582],{"class":154},[144,10337,465],{"class":158},[144,10339,391],{"class":261},[144,10341,10343],{"class":146,"line":10342},113,[144,10344,356],{"emptyLinePlaceholder":57},[144,10346,10348],{"class":146,"line":10347},114,[144,10349,356],{"emptyLinePlaceholder":57},[144,10351,10353],{"class":146,"line":10352},115,[144,10354,10355],{"class":173},"# ── Ejemplo 1: Texto a Video ──────────────────────────────────\n",[144,10357,10359,10361,10363],{"class":146,"line":10358},116,[144,10360,501],{"class":257},[144,10362,1058],{"class":150},[144,10364,1061],{"class":261},[144,10366,10368,10370,10372],{"class":146,"line":10367},117,[144,10369,1067],{"class":261},[144,10371,265],{"class":257},[144,10373,444],{"class":261},[144,10375,10377,10379,10381,10383],{"class":146,"line":10376},118,[144,10378,1077],{"class":158},[144,10380,453],{"class":261},[144,10382,1082],{"class":158},[144,10384,468],{"class":261},[144,10386,10388,10390],{"class":146,"line":10387},119,[144,10389,1094],{"class":158},[144,10391,1097],{"class":261},[144,10393,10395],{"class":146,"line":10394},120,[144,10396,1103],{"class":158},[144,10398,10400],{"class":146,"line":10399},121,[144,10401,1109],{"class":158},[144,10403,10405],{"class":146,"line":10404},122,[144,10406,1115],{"class":158},[144,10408,10410],{"class":146,"line":10409},123,[144,10411,1121],{"class":261},[144,10413,10415,10417,10419,10421],{"class":146,"line":10414},124,[144,10416,1127],{"class":158},[144,10418,453],{"class":261},[144,10420,1132],{"class":154},[144,10422,468],{"class":261},[144,10424,10426,10428,10430,10432],{"class":146,"line":10425},125,[144,10427,1144],{"class":158},[144,10429,453],{"class":261},[144,10431,1149],{"class":158},[144,10433,468],{"class":261},[144,10435,10437,10439,10441,10443],{"class":146,"line":10436},126,[144,10438,1161],{"class":158},[144,10440,453],{"class":261},[144,10442,1166],{"class":158},[144,10444,468],{"class":261},[144,10446,10448,10450,10452],{"class":146,"line":10447},127,[144,10449,1178],{"class":158},[144,10451,453],{"class":261},[144,10453,3552],{"class":154},[144,10455,10457],{"class":146,"line":10456},128,[144,10458,1191],{"class":261},[144,10460,10462],{"class":146,"line":10461},129,[144,10463,10464],{"class":261},"    validate_payload(payload)\n",[144,10466,10468,10470,10472],{"class":146,"line":10467},130,[144,10469,1288],{"class":261},[144,10471,265],{"class":257},[144,10473,8302],{"class":261},[144,10475,10477,10479,10481,10483,10486,10488,10490,10492,10494,10496,10499,10501,10503,10505,10507,10509,10511,10513,10516],{"class":146,"line":10476},131,[144,10478,877],{"class":154},[144,10480,423],{"class":261},[144,10482,456],{"class":257},[144,10484,10485],{"class":158},"\"Tarea: ",[144,10487,576],{"class":154},[144,10489,1324],{"class":261},[144,10491,1327],{"class":158},[144,10493,1330],{"class":261},[144,10495,582],{"class":154},[144,10497,10498],{"class":158}," (ETA: ",[144,10500,576],{"class":154},[144,10502,1324],{"class":261},[144,10504,1355],{"class":158},[144,10506,1358],{"class":261},[144,10508,1361],{"class":158},[144,10510,1330],{"class":261},[144,10512,582],{"class":154},[144,10514,10515],{"class":158},"s)\"",[144,10517,391],{"class":261},[144,10519,10521,10523,10525,10527,10529],{"class":146,"line":10520},132,[144,10522,1419],{"class":261},[144,10524,265],{"class":257},[144,10526,1424],{"class":261},[144,10528,1427],{"class":158},[144,10530,1430],{"class":261},[144,10532,10534,10537,10539,10541,10543,10546,10549],{"class":146,"line":10533},133,[144,10535,10536],{"class":261},"    download_video(result[",[144,10538,1455],{"class":158},[144,10540,1358],{"class":261},[144,10542,662],{"class":154},[144,10544,10545],{"class":261},"], ",[144,10547,10548],{"class":158},"\"texto_a_video.mp4\"",[144,10550,391],{"class":261},[144,10552,10554],{"class":146,"line":10553},134,[144,10555,356],{"emptyLinePlaceholder":57},[144,10557,10559],{"class":146,"line":10558},135,[144,10560,356],{"emptyLinePlaceholder":57},[144,10562,10564],{"class":146,"line":10563},136,[144,10565,10566],{"class":173},"# ── Ejemplo 2: Imagen a Video ─────────────────────────────────\n",[144,10568,10570,10572,10574],{"class":146,"line":10569},137,[144,10571,501],{"class":257},[144,10573,2452],{"class":150},[144,10575,1061],{"class":261},[144,10577,10579,10581,10583],{"class":146,"line":10578},138,[144,10580,1067],{"class":261},[144,10582,265],{"class":257},[144,10584,444],{"class":261},[144,10586,10588,10590,10592,10594],{"class":146,"line":10587},139,[144,10589,1077],{"class":158},[144,10591,453],{"class":261},[144,10593,1082],{"class":158},[144,10595,468],{"class":261},[144,10597,10599,10601],{"class":146,"line":10598},140,[144,10600,1094],{"class":158},[144,10602,1097],{"class":261},[144,10604,10606],{"class":146,"line":10605},141,[144,10607,2483],{"class":158},[144,10609,10611],{"class":146,"line":10610},142,[144,10612,2488],{"class":158},[144,10614,10616],{"class":146,"line":10615},143,[144,10617,10618],{"class":158},"            \"por el encuadre.\"\n",[144,10620,10622],{"class":146,"line":10621},144,[144,10623,1121],{"class":261},[144,10625,10627,10629,10632,10635],{"class":146,"line":10626},145,[144,10628,2502],{"class":158},[144,10630,10631],{"class":261},": [",[144,10633,10634],{"class":158},"\"https://example.com/your-image.jpg\"",[144,10636,10637],{"class":261},"],\n",[144,10639,10641,10643,10645,10647],{"class":146,"line":10640},146,[144,10642,1127],{"class":158},[144,10644,453],{"class":261},[144,10646,1132],{"class":154},[144,10648,468],{"class":261},[144,10650,10652,10654,10656],{"class":146,"line":10651},147,[144,10653,1144],{"class":158},[144,10655,453],{"class":261},[144,10657,8281],{"class":158},[144,10659,10661],{"class":146,"line":10660},148,[144,10662,1191],{"class":261},[144,10664,10666],{"class":146,"line":10665},149,[144,10667,10464],{"class":261},[144,10669,10671,10673,10675],{"class":146,"line":10670},150,[144,10672,1288],{"class":261},[144,10674,265],{"class":257},[144,10676,8302],{"class":261},[144,10678,10680,10682,10684,10686,10688,10690,10692,10694,10696,10698,10700],{"class":146,"line":10679},151,[144,10681,877],{"class":154},[144,10683,423],{"class":261},[144,10685,456],{"class":257},[144,10687,10485],{"class":158},[144,10689,576],{"class":154},[144,10691,1324],{"class":261},[144,10693,1327],{"class":158},[144,10695,1330],{"class":261},[144,10697,582],{"class":154},[144,10699,465],{"class":158},[144,10701,391],{"class":261},[144,10703,10705,10707,10709,10711,10713],{"class":146,"line":10704},152,[144,10706,1419],{"class":261},[144,10708,265],{"class":257},[144,10710,1424],{"class":261},[144,10712,1427],{"class":158},[144,10714,1430],{"class":261},[144,10716,10718,10720,10722,10724,10726,10728,10731],{"class":146,"line":10717},153,[144,10719,10536],{"class":261},[144,10721,1455],{"class":158},[144,10723,1358],{"class":261},[144,10725,662],{"class":154},[144,10727,10545],{"class":261},[144,10729,10730],{"class":158},"\"imagen_a_video.mp4\"",[144,10732,391],{"class":261},[144,10734,10736],{"class":146,"line":10735},154,[144,10737,356],{"emptyLinePlaceholder":57},[144,10739,10741],{"class":146,"line":10740},155,[144,10742,356],{"emptyLinePlaceholder":57},[144,10744,10746],{"class":146,"line":10745},156,[144,10747,10748],{"class":173},"# ── Ejemplo 3: Video Vertical para Redes Sociales ─────────────\n",[144,10750,10752,10754,10757],{"class":146,"line":10751},157,[144,10753,501],{"class":257},[144,10755,10756],{"class":150}," social_media_video",[144,10758,1061],{"class":261},[144,10760,10762,10764,10766],{"class":146,"line":10761},158,[144,10763,1067],{"class":261},[144,10765,265],{"class":257},[144,10767,444],{"class":261},[144,10769,10771,10773,10775,10777],{"class":146,"line":10770},159,[144,10772,1077],{"class":158},[144,10774,453],{"class":261},[144,10776,1082],{"class":158},[144,10778,468],{"class":261},[144,10780,10782,10784],{"class":146,"line":10781},160,[144,10783,1094],{"class":158},[144,10785,1097],{"class":261},[144,10787,10789],{"class":146,"line":10788},161,[144,10790,10791],{"class":158},"            \"Un barista vierte latte art en cámara lenta. \"\n",[144,10793,10795],{"class":146,"line":10794},162,[144,10796,10797],{"class":158},"            \"Plano cenital cerrado, iluminación cálida de café.\"\n",[144,10799,10801],{"class":146,"line":10800},163,[144,10802,1121],{"class":261},[144,10804,10806,10808,10810,10812],{"class":146,"line":10805},164,[144,10807,1127],{"class":158},[144,10809,453],{"class":261},[144,10811,3512],{"class":154},[144,10813,468],{"class":261},[144,10815,10817,10819,10821,10823],{"class":146,"line":10816},165,[144,10818,1144],{"class":158},[144,10820,453],{"class":261},[144,10822,3524],{"class":158},[144,10824,468],{"class":261},[144,10826,10828,10830,10832,10834],{"class":146,"line":10827},166,[144,10829,1161],{"class":158},[144,10831,453],{"class":261},[144,10833,3536],{"class":158},[144,10835,468],{"class":261},[144,10837,10839,10841,10843],{"class":146,"line":10838},167,[144,10840,1178],{"class":158},[144,10842,453],{"class":261},[144,10844,3552],{"class":154},[144,10846,10848],{"class":146,"line":10847},168,[144,10849,1191],{"class":261},[144,10851,10853],{"class":146,"line":10852},169,[144,10854,10464],{"class":261},[144,10856,10858,10860,10862],{"class":146,"line":10857},170,[144,10859,1288],{"class":261},[144,10861,265],{"class":257},[144,10863,8302],{"class":261},[144,10865,10867,10869,10871,10873,10875,10877,10879,10881,10883,10885,10887],{"class":146,"line":10866},171,[144,10868,877],{"class":154},[144,10870,423],{"class":261},[144,10872,456],{"class":257},[144,10874,10485],{"class":158},[144,10876,576],{"class":154},[144,10878,1324],{"class":261},[144,10880,1327],{"class":158},[144,10882,1330],{"class":261},[144,10884,582],{"class":154},[144,10886,465],{"class":158},[144,10888,391],{"class":261},[144,10890,10892,10894,10896,10898,10900],{"class":146,"line":10891},172,[144,10893,1419],{"class":261},[144,10895,265],{"class":257},[144,10897,1424],{"class":261},[144,10899,1427],{"class":158},[144,10901,1430],{"class":261},[144,10903,10905,10907,10909,10911,10913,10915,10918],{"class":146,"line":10904},173,[144,10906,10536],{"class":261},[144,10908,1455],{"class":158},[144,10910,1358],{"class":261},[144,10912,662],{"class":154},[144,10914,10545],{"class":261},[144,10916,10917],{"class":158},"\"video_social.mp4\"",[144,10919,391],{"class":261},[144,10921,10923],{"class":146,"line":10922},174,[144,10924,356],{"emptyLinePlaceholder":57},[144,10926,10928],{"class":146,"line":10927},175,[144,10929,356],{"emptyLinePlaceholder":57},[144,10931,10933,10935,10937,10939,10941],{"class":146,"line":10932},176,[144,10934,402],{"class":257},[144,10936,1532],{"class":154},[144,10938,1535],{"class":257},[144,10940,1538],{"class":158},[144,10942,411],{"class":261},[144,10944,10946,10948,10950,10953],{"class":146,"line":10945},177,[144,10947,877],{"class":154},[144,10949,423],{"class":261},[144,10951,10952],{"class":158},"\"=== Texto a Video ===\"",[144,10954,391],{"class":261},[144,10956,10958],{"class":146,"line":10957},178,[144,10959,1546],{"class":261},[144,10961,10963],{"class":146,"line":10962},179,[144,10964,10965],{"class":173},"    # print(\"\\n=== Imagen a Video ===\")\n",[144,10967,10969],{"class":146,"line":10968},180,[144,10970,10971],{"class":173},"    # image_to_video()  # Descomente y configure su URL de imagen\n",[144,10973,10975],{"class":146,"line":10974},181,[144,10976,10977],{"class":173},"    # print(\"\\n=== Video para Redes Sociales ===\")\n",[144,10979,10981],{"class":146,"line":10980},182,[144,10982,10983],{"class":173},"    # social_media_video()\n",[17,10985,10986],{},[10,10987,10988,10991,10992,2765,10994,10997],{},[22,10989,10990],{},"Consejo:"," Para probar con el modelo actualmente disponible, cambie ",[27,10993,1082],{},[27,10995,10996],{},"\"seedance-1.5-pro\"",". La interfaz de la API es idéntica — mismo endpoint, mismos parámetros, mismo formato de respuesta. Cuando Seedance 2.0 esté completamente implementado, simplemente vuelva a cambiar el nombre del modelo.",[10,10999,11000],{},[22,11001,11002],{},[36,11003,11005],{"href":38,"rel":11004},[40],"Empiece a construir → Obtenga su clave API gratuita en EvoLink",[11007,11008,11009],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":140,"searchDepth":165,"depth":165,"links":11011},[11012,11015,11016,11020,11025,11030,11034,11040,11048,11049,11054,11066],{"id":49,"depth":165,"text":50,"children":11013},[11014],{"id":93,"depth":177,"text":94},{"id":203,"depth":165,"text":204},{"id":314,"depth":165,"text":315,"children":11017},[11018,11019],{"id":1657,"depth":177,"text":1658},{"id":1985,"depth":177,"text":1986},{"id":2031,"depth":165,"text":2032,"children":11021},[11022,11023,11024],{"id":2081,"depth":177,"text":2082},{"id":2161,"depth":177,"text":2162},{"id":2249,"depth":177,"text":2250},{"id":2416,"depth":165,"text":2417,"children":11026},[11027,11028,11029],{"id":2752,"depth":177,"text":2753},{"id":3030,"depth":177,"text":3031},{"id":3106,"depth":177,"text":3107},{"id":3201,"depth":165,"text":3202,"children":11031},[11032,11033],{"id":3455,"depth":177,"text":3456},{"id":3865,"depth":177,"text":3866},{"id":3976,"depth":165,"text":3977,"children":11035},[11036,11037,11038,11039],{"id":3983,"depth":177,"text":3984},{"id":4620,"depth":177,"text":4621},{"id":4834,"depth":177,"text":4835},{"id":5631,"depth":177,"text":5632},{"id":6231,"depth":165,"text":6232,"children":11041},[11042,11043,11044,11045,11046,11047],{"id":6242,"depth":177,"text":6243},{"id":6421,"depth":177,"text":6422},{"id":6487,"depth":177,"text":6488},{"id":7708,"depth":177,"text":7709},{"id":7845,"depth":177,"text":7846},{"id":8024,"depth":177,"text":8025},{"id":8116,"depth":165,"text":8117},{"id":8705,"depth":165,"text":8706,"children":11050},[11051,11052,11053],{"id":8712,"depth":177,"text":8713},{"id":8756,"depth":177,"text":8757},{"id":8783,"depth":177,"text":8784},{"id":8834,"depth":165,"text":8835,"children":11055},[11056,11057,11058,11059,11060,11061,11062,11063,11064,11065],{"id":8838,"depth":177,"text":8839},{"id":8848,"depth":177,"text":8849},{"id":8858,"depth":177,"text":8859},{"id":8868,"depth":177,"text":8869},{"id":8883,"depth":177,"text":8884},{"id":8901,"depth":177,"text":8902},{"id":8915,"depth":177,"text":8916},{"id":8934,"depth":177,"text":8935},{"id":8945,"depth":177,"text":8946},{"id":8965,"depth":177,"text":8966},{"id":8979,"depth":165,"text":8980},"Genere su primer video con IA usando la API de Seedance 2.0 en Python. Tutorial paso a paso: texto a video, imagen a video, polling asíncrono, webhooks y manejo de errores.","md",{"date":11070,"image":11071,"seoTitle":11072,"author":11073},"2026-02-27","/s2-hero-api-tutorial.webp","Tutorial de API de Seedance 2.0: Primer Video con IA en Python (2026)","J @ EvoLink","/es/blog/seedance-2-api-tutorial-python",{"title":5,"description":11067},"es/blog/seedance-2-api-tutorial-python","5tlTF_5-Yod93G7RERYJAIXHuwb-7w05_eUQLqeLuro",1775067579248]