gnosticdev commited on
Commit
aa61beb
·
verified ·
1 Parent(s): 9b7097e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +50 -79
app.py CHANGED
@@ -1,115 +1,86 @@
1
  import os
 
2
  import requests
3
- import asyncio
4
  import tempfile
5
  import logging
6
  from datetime import datetime
7
 
8
- import gradio as gr
9
- from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip
10
  import edge_tts
 
 
11
 
12
  from transformers import pipeline
13
- import torch
14
 
15
- logging.basicConfig(level=logging.INFO)
16
- logger = logging.getLogger(__name__)
17
 
18
- # --- CONFIG ---
19
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
20
- # Modelo de texto en español
21
- MODEL_NAME = "DeepESP/gpt2-spanish"
22
-
23
- # Inicializar generador de texto
24
- device = 0 if torch.cuda.is_available() else -1
25
- generator = pipeline("text-generation", model=MODEL_NAME, device=device)
26
 
27
- async def listar_voces():
28
- try:
29
- return await edge_tts.list_voices()
30
- except Exception as e:
31
- logger.error(f"Error obteniendo voces: {e}")
32
- return [{'ShortName': 'es-ES-ElviraNeural', 'Name': 'Elvira', 'Gender': 'Female'}]
33
 
34
- VOCES = asyncio.run(listar_voces())
 
 
35
  VOICE_NAMES = [f"{v['Name']} ({v['Gender']})" for v in VOCES]
36
 
37
  def generar_guion(prompt):
38
- prompt_text = f"Escribe un guion profesional para un vídeo de YouTube sobre '{prompt}':\n"
39
- try:
40
- out = generator(prompt_text, max_new_tokens=300, temperature=0.7, truncate=True, num_return_sequences=1)
41
- texto = out[0]['generated_text']
42
- return texto
43
- except Exception as e:
44
- logger.error(f"Error generando guion: {e}")
45
- return f"Error generando guion: {e}"
46
 
47
  def buscar_videos(prompt, max_videos=3):
 
 
 
 
 
48
  try:
49
- url = f"https://api.pexels.com/videos/search?query={prompt}&per_page={max_videos}"
50
- resp = requests.get(url, headers={"Authorization": PEXELS_API_KEY}, timeout=10)
51
- return resp.json().get("videos", [])
52
- except Exception as e:
53
- logger.error(f"Error en Pexels: {e}")
54
- return []
55
-
56
- async def crear_video(prompt, voz_index, musica_path=None):
57
- texto = generar_guion(prompt)
58
- voz_short = VOCES[voz_index]['ShortName']
59
- audio_file = "tts.mp3"
60
- await edge_tts.Communicate(texto, voz_short).save(audio_file)
61
- tts_audio = AudioFileClip(audio_file)
62
- dur = tts_audio.duration
63
-
64
- # Música opcional
65
- if musica_path:
66
- music = AudioFileClip(musica_path).volumex(0.2).subclip(0, dur)
67
- audio_comp = CompositeAudioClip([music, tts_audio])
68
- else:
69
- audio_comp = tts_audio
70
 
71
- videos = buscar_videos(prompt)
72
- if not videos:
73
- return None
 
 
 
 
 
 
 
74
 
 
 
75
  clips = []
76
  for v in videos:
77
  url = v['video_files'][0]['link']
78
- r = requests.get(url, stream=True, timeout=15)
79
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
80
- [tmp.write(c) for c in r.iter_content(1024*1024)]
 
 
81
  tmp.close()
82
- clip = VideoFileClip(tmp.name).subclip(0, min(dur/len(videos), v['duration']))
83
  clips.append(clip)
84
 
85
- final = concatenate_videoclips(clips).set_audio(audio_comp)
86
- out_name = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
87
- final.write_videofile(out_name, codec="libx264", audio_codec="aac", fps=24)
88
-
89
- # Cleanup
90
- tts_audio.close()
91
- for c in clips:
92
- c.close()
93
- os.remove(c.filename)
94
- os.remove(audio_file)
95
 
96
- return out_name
97
 
98
- def run_crear(prompt, voz_name, muz_file):
99
- try:
100
- idx = VOICE_NAMES.index(voz_name)
101
- except:
102
- idx = 0
103
- return asyncio.run(crear_video(prompt, idx, muz_file.name if muz_file else None))
104
 
105
  with gr.Blocks() as app:
106
- tema = gr.Textbox(label="Tema para guion y video")
107
- voz = gr.Dropdown(choices=VOICE_NAMES, value=VOICE_NAMES[0], label="Voz TTS")
108
- muz = gr.File(label="Música fondo opcional (mp3/wav)", file_types=[".mp3", ".wav"])
109
- btn = gr.Button("Crear video")
110
- vid_out = gr.Video(label="Video generado")
111
 
112
- btn.click(fn=run_crear, inputs=[tema, voz, muz], outputs=vid_out)
113
 
114
  if __name__ == "__main__":
115
- app.launch()
 
1
  import os
2
+ import gradio as gr
3
  import requests
 
4
  import tempfile
5
  import logging
6
  from datetime import datetime
7
 
 
 
8
  import edge_tts
9
+ import nest_asyncio
10
+ import asyncio
11
 
12
  from transformers import pipeline
13
+ from moviepy.editor import AudioFileClip, VideoFileClip, concatenate_videoclips
14
 
15
+ nest_asyncio.apply()
 
16
 
 
17
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
18
+ logger = logging.getLogger(__name__)
 
 
 
 
 
19
 
20
+ # Carga modelo
21
+ generator = pipeline("text-generation", model="DeepESP/gpt2-spanish")
 
 
 
 
22
 
23
+ # Cargar voces
24
+ loop = asyncio.get_event_loop()
25
+ VOCES = loop.run_until_complete(edge_tts.list_voices())
26
  VOICE_NAMES = [f"{v['Name']} ({v['Gender']})" for v in VOCES]
27
 
28
  def generar_guion(prompt):
29
+ prompt_text = f"Escribe un guion profesional de YouTube sobre '{prompt}':\n"
30
+ res = generator(prompt_text, max_new_tokens=300)[0]['generated_text']
31
+ return res.strip()
 
 
 
 
 
32
 
33
  def buscar_videos(prompt, max_videos=3):
34
+ headers = {"Authorization": PEXELS_API_KEY}
35
+ r = requests.get(f"https://api.pexels.com/videos/search?query={prompt}&per_page={max_videos}", headers=headers)
36
+ return r.json().get("videos", [])
37
+
38
+ def crear_video(prompt, voz_nombre):
39
  try:
40
+ idx = VOICE_NAMES.index(voz_nombre)
41
+ except:
42
+ idx = 0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
+ voz_short = VOCES[idx]['ShortName']
45
+ guion = generar_guion(prompt)
46
+
47
+ # Guardar voz
48
+ tts = edge_tts.Communicate(guion, voz_short)
49
+ voz_path = "voz.mp3"
50
+ loop.run_until_complete(tts.save(voz_path))
51
+
52
+ audio_clip = AudioFileClip(voz_path)
53
+ duracion = audio_clip.duration
54
 
55
+ # Descargar videos
56
+ videos = buscar_videos(prompt)
57
  clips = []
58
  for v in videos:
59
  url = v['video_files'][0]['link']
 
60
  tmp = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
61
+ r = requests.get(url, stream=True)
62
+ for c in r.iter_content(1024*1024):
63
+ tmp.write(c)
64
  tmp.close()
65
+ clip = VideoFileClip(tmp.name).subclip(0, min(v['duration'], duracion / len(videos)))
66
  clips.append(clip)
67
 
68
+ final = concatenate_videoclips(clips).set_audio(audio_clip)
69
+ salida = f"video_{datetime.now().strftime('%H%M%S')}.mp4"
70
+ final.write_videofile(salida, fps=24)
 
 
 
 
 
 
 
71
 
72
+ return salida
73
 
74
+ def run(prompt, voz):
75
+ return crear_video(prompt, voz)
 
 
 
 
76
 
77
  with gr.Blocks() as app:
78
+ entrada = gr.Textbox(label="Tema del video")
79
+ voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
80
+ boton = gr.Button("Generar Video")
81
+ salida = gr.Video(label="Resultado")
 
82
 
83
+ boton.click(fn=run, inputs=[entrada, voz], outputs=salida)
84
 
85
  if __name__ == "__main__":
86
+ app.launch(server_name="0.0.0.0", server_port=7860)