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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +98 -96
app.py CHANGED
@@ -1,113 +1,115 @@
1
- import gradio as gr
2
- import asyncio
3
- import edge_tts
4
  import requests
 
5
  import tempfile
6
- import os
7
  from datetime import datetime
 
 
8
  from moviepy.editor import VideoFileClip, concatenate_videoclips, AudioFileClip, CompositeAudioClip
 
9
 
10
- # Voz predeterminada (puedes cambiarla o cargar lista)
11
- VOCES = [{'ShortName': 'es-ES-ElviraNeural', 'Name': 'Elvira', 'Gender': 'Female'}]
12
- VOICE_NAMES = [f"{v['Name']} ({v['Gender']})" for v in VOCES]
13
 
14
- # Simula función para generar texto según prompt
15
- def generar_texto(prompt):
16
- # Aquí deberías integrar tu generador real, por ahora solo repetimos prompt
17
- return f"Este es un texto generado para el tema: {prompt}"
18
-
19
- # Simula función para buscar videos (debes conectar con Pexels u otra API)
20
- def buscar_videos(prompt):
21
- # Retorna lista simulada con links a videos (debes poner tu API real)
22
- return [
23
- {
24
- "video_files": [{"link": "https://filesamples.com/samples/video/mp4/sample_640x360.mp4"}],
25
- "duration": 10
26
- },
27
- {
28
- "video_files": [{"link": "https://filesamples.com/samples/video/mp4/sample_640x360.mp4"}],
29
- "duration": 10
30
- }
31
- ]
32
 
33
- async def crear_video(prompt, voz_index, musica_path=None):
34
- try:
35
- texto = generar_texto(prompt)
36
- voz_shortname = VOCES[voz_index]['ShortName']
37
-
38
- # Generar audio TTS
39
- archivo_audio = "audio.mp3"
40
- await edge_tts.Communicate(texto, voz_shortname).save(archivo_audio)
41
- audio_clip = AudioFileClip(archivo_audio)
42
- duracion_audio = audio_clip.duration
43
-
44
- # Cargar música si se pasa
45
- if musica_path:
46
- musica_clip = AudioFileClip(musica_path).volumex(0.2) # Volumen bajo para música
47
- musica_clip = musica_clip.subclip(0, duracion_audio)
48
- audio_final = CompositeAudioClip([musica_clip, audio_clip])
49
- else:
50
- audio_final = audio_clip
51
-
52
- # Descargar y preparar videos
53
- videos = buscar_videos(prompt)
54
- if not videos:
55
- return None
56
-
57
- clips = []
58
- for v in videos[:3]:
59
- video_url = v['video_files'][0]['link']
60
- response = requests.get(video_url, stream=True)
61
- temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".mp4")
62
- for chunk in response.iter_content(chunk_size=1024*1024):
63
- temp_file.write(chunk)
64
- temp_file.close()
65
-
66
- clip = VideoFileClip(temp_file.name).subclip(0, min(duracion_audio/len(videos), v['duration']))
67
- clips.append(clip)
68
-
69
- video_final = concatenate_videoclips(clips)
70
- video_final = video_final.set_audio(audio_final)
71
-
72
- output_filename = f"video_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
73
- video_final.write_videofile(output_filename, codec="libx264", audio_codec="aac", fps=24)
74
-
75
- # Limpieza
76
- audio_clip.close()
77
- if musica_path:
78
- musica_clip.close()
79
- for c in clips:
80
- c.close()
81
- os.remove(c.filename)
82
- os.remove(archivo_audio)
83
-
84
- return output_filename
85
 
86
- except Exception as e:
87
- return f"Error: {e}"
 
88
 
89
- def run_crear_video(prompt, voz_nombre, musica_file):
90
  try:
91
- voz_index = VOICE_NAMES.index(voz_nombre)
92
- except ValueError:
93
- voz_index = 0
 
94
 
95
- musica_path = musica_file.name if musica_file else None
96
- return asyncio.run(crear_video(prompt, voz_index, musica_path))
97
 
 
 
 
 
 
 
 
 
 
98
 
99
- with gr.Blocks(title="Generador de Video con TTS y Música de Fondo") as demo:
100
- with gr.Row():
101
- with gr.Column():
102
- prompt = gr.Textbox(label="Tema del video", lines=2)
103
- voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
104
- musica = gr.File(label="Sube música de fondo (opcional, mp3/wav)", file_types=[".mp3", ".wav"])
105
- btn = gr.Button("Generar Video")
106
- with gr.Column():
107
- salida = gr.Video(label="Video generado")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
109
- btn.click(run_crear_video, inputs=[prompt, voz, musica], outputs=salida)
 
 
 
 
 
110
 
 
111
 
112
  if __name__ == "__main__":
113
- demo.launch(server_name="0.0.0.0", server_port=7860)
 
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()