gnosticdev commited on
Commit
cbfaa69
verified
1 Parent(s): 99b44b3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +60 -50
app.py CHANGED
@@ -44,10 +44,28 @@ async def get_voices():
44
  return [], []
45
 
46
  # Obtener voces de forma s铆ncrona para la inicializaci贸n
47
- VOICE_NAMES, VOICES = asyncio.run(get_voices())
48
- if not VOICES:
49
- VOICE_NAMES = ["Voz Predeterminada (Femenino, es-ES)"]
50
- VOICES = [{'ShortName': 'es-ES-ElviraNeural'}]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
 
52
  def generar_guion_profesional(prompt):
53
  """Genera guiones con respaldo robusto"""
@@ -95,61 +113,53 @@ async def crear_video_profesional(prompt, custom_script, voz_index, musica=None)
95
  guion = custom_script if custom_script else generar_guion_profesional(prompt)
96
 
97
  # 2. Configurar voz
98
- voz_seleccionada = VOICES[voz_index]['ShortName'] if VOICES else 'es-ES-ElviraNeural'
99
-
100
- # 3. Generar audio
101
- voz_archivo = "voz.mp3"
102
- await edge_tts.Communicate(guion, voz_seleccionada).save(voz_archivo)
103
- audio = AudioFileClip(voz_archivo)
104
-
105
- # 4. Obtener videos
106
- videos_data = buscar_videos_avanzado(prompt, guion)
107
- if not videos_data:
108
- raise Exception("No se encontraron videos")
109
-
110
- # 5. Procesar videos
111
- clips = []
112
- for video in videos_data[:3]: # Usar m谩ximo 3 videos
113
- video_file = next((vf for vf in video['video_files'] if vf['quality'] == 'sd'), video['video_files'][0])
114
- with tempfile.NamedTemporaryFile(suffix='.mp4', delete=False) as temp_video:
115
- response = requests.get(video_file['link'], stream=True)
116
- for chunk in response.iter_content(chunk_size=1024*1024):
117
- temp_video.write(chunk)
118
- clip = VideoFileClip(temp_video.name).subclip(0, min(10, video['duration']))
119
- clips.append(clip)
120
-
121
- # 6. Crear video final
122
- video_final = concatenate_videoclips(clips)
123
- video_final = video_final.set_audio(audio)
124
-
125
- output_path = f"video_output_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
126
- video_final.write_videofile(output_path, fps=24, threads=2)
127
 
128
- return output_path
 
129
 
130
  except Exception as e:
131
- logger.error(f"Error cr铆tico: {str(e)}")
132
  return None
133
- finally:
134
- if os.path.exists(voz_archivo):
135
- os.remove(voz_archivo)
136
 
137
- # Interfaz optimizada
138
- with gr.Blocks(title="Generador de Videos") as app:
 
 
 
 
 
 
 
 
139
  with gr.Row():
140
- with gr.Column():
141
- prompt = gr.Textbox(label="Tema del video")
142
- custom_script = gr.TextArea(label="Gui贸n personalizado (opcional)")
143
- voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
144
- btn = gr.Button("Generar Video", variant="primary")
145
- with gr.Column():
146
- output = gr.Video(label="Resultado", format="mp4")
147
 
148
  btn.click(
149
- fn=lambda p, cs, v: asyncio.run(crear_video_profesional(p, cs, VOICE_NAMES.index(v))),
150
- inputs=[prompt, custom_script, voz],
151
  outputs=output
152
  )
153
 
154
  if __name__ == "__main__":
155
- app.launch(server_name="0.0.0.0", server_port=7860)
 
 
 
 
 
 
44
  return [], []
45
 
46
  # Obtener voces de forma s铆ncrona para la inicializaci贸n
47
+ import nest_asyncio
48
+ nest_asyncio.apply()
49
+
50
+ VOICE_NAMES, VOICES = [], []
51
+
52
+ async def get_voices():
53
+ voces = await edge_tts.list_voices()
54
+ voice_names = [f"{v['Name']} ({v['Gender']}, {v['LocaleName']})" for v in voces]
55
+ return voice_names, voces
56
+
57
+ async def get_and_set_voices():
58
+ global VOICE_NAMES, VOICES
59
+ try:
60
+ VOICE_NAMES, VOICES = await get_voices()
61
+ if not VOICES:
62
+ raise Exception("No se obtuvieron voces.")
63
+ except Exception as e:
64
+ logging.warning(f"No se pudieron cargar voces din谩micamente: {e}")
65
+ VOICE_NAMES = ["Voz Predeterminada (Femenino, es-ES)"]
66
+ VOICES = [{'ShortName': 'es-ES-ElviraNeural'}]
67
+
68
+ asyncio.get_event_loop().run_until_complete(get_and_set_voices())
69
 
70
  def generar_guion_profesional(prompt):
71
  """Genera guiones con respaldo robusto"""
 
113
  guion = custom_script if custom_script else generar_guion_profesional(prompt)
114
 
115
  # 2. Configurar voz
116
+ voz_seleccionada = VOICES[voz_indimport os
117
+ import asyncio
118
+ from concurrent.futures import ThreadPoolExecutor
119
+ import gradio as gr
120
+
121
+ # Configuraci贸n CR脥TICA para evitar timeouts
122
+ GRADIO_TIMEOUT = 600 # 10 minutos (en segundos)
123
+ MAX_VIDEO_DURATION = 120 # 2 minutos (evita procesos eternos)
124
+
125
+ async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
126
+ try:
127
+ # 1. Simulamos un proceso largo (隆esto es lo que causa el timeout!)
128
+ # Reemplaza esto con tu l贸gica real de generaci贸n
129
+ await asyncio.sleep(30) # Solo para prueba
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
 
131
+ # 2. Devuelve un video de prueba (eliminar en producci贸n)
132
+ return "video_prueba.mp4"
133
 
134
  except Exception as e:
135
+ print(f"ERROR: {str(e)}")
136
  return None
 
 
 
137
 
138
+ # 馃憞 **Soluci贸n M谩gica**: Ejecuci贸n en hilos separados
139
+ def run_async_with_timeout(prompt, script, voz_index, musica=None):
140
+ with ThreadPoolExecutor() as executor:
141
+ future = executor.submit(
142
+ lambda: asyncio.run(crear_video_profesional(prompt, script, voz_index, musica))
143
+ )
144
+ return future.result(timeout=GRADIO_TIMEOUT)
145
+
146
+ # Interfaz Minimalista (para enfocarnos en el timeout)
147
+ with gr.Blocks() as app:
148
  with gr.Row():
149
+ prompt = gr.Textbox(label="Tema")
150
+ btn = gr.Button("Generar")
151
+ output = gr.Video()
 
 
 
 
152
 
153
  btn.click(
154
+ fn=run_async_with_timeout, # 馃憟 Usamos el wrapper anti-timeout
155
+ inputs=[prompt, gr.Textbox(visible=False), gr.Number(visible=False)],
156
  outputs=output
157
  )
158
 
159
  if __name__ == "__main__":
160
+ app.launch(
161
+ server_name="0.0.0.0",
162
+ server_port=7860,
163
+ # 鈿狅笍 Configuraci贸n CLAVE para el timeout
164
+ app_kwargs={"timeout": GRADIO_TIMEOUT}
165
+ )