Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -14,7 +14,6 @@ import random
|
|
| 14 |
from transformers import pipeline
|
| 15 |
import torch
|
| 16 |
import asyncio
|
| 17 |
-
from nltk.tokenize import sent_tokenize
|
| 18 |
|
| 19 |
nltk.download('punkt', quiet=True)
|
| 20 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
@@ -23,15 +22,12 @@ logger = logging.getLogger(__name__)
|
|
| 23 |
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
|
| 24 |
MODEL_NAME = "DeepESP/gpt2-spanish"
|
| 25 |
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
voice_names = [f"{v['Name']} ({v['Gender']}, {v['LocaleName']})" for v in voices]
|
| 30 |
-
return voice_names, voices
|
| 31 |
-
except:
|
| 32 |
-
return ["Voz Predeterminada (Femenino, es-ES)"], [{'ShortName': 'es-ES-ElviraNeural'}]
|
| 33 |
|
| 34 |
-
|
|
|
|
| 35 |
|
| 36 |
def generar_guion_profesional(prompt):
|
| 37 |
try:
|
|
@@ -47,10 +43,12 @@ def generar_guion_profesional(prompt):
|
|
| 47 |
"2. Tres secciones detalladas con subt铆tulos\n"
|
| 48 |
"3. Conclusi贸n impactante\n"
|
| 49 |
"Usa un estilo natural para narraci贸n:",
|
|
|
|
| 50 |
temperature=0.7,
|
| 51 |
top_k=50,
|
| 52 |
top_p=0.95,
|
| 53 |
-
num_return_sequences=1
|
|
|
|
| 54 |
)
|
| 55 |
guion = response[0]['generated_text']
|
| 56 |
if len(guion.split()) < 100:
|
|
@@ -90,6 +88,8 @@ def generar_guion_profesional(prompt):
|
|
| 90 |
驴Listos para profundizar? 隆Empecemos!
|
| 91 |
"""
|
| 92 |
|
|
|
|
|
|
|
| 93 |
def buscar_videos_avanzado(prompt, guion, num_videos=5):
|
| 94 |
try:
|
| 95 |
oraciones = sent_tokenize(guion)
|
|
@@ -125,6 +125,7 @@ def buscar_videos_avanzado(prompt, guion, num_videos=5):
|
|
| 125 |
return response.json().get('videos', [])[:num_videos]
|
| 126 |
|
| 127 |
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
|
|
|
|
| 128 |
try:
|
| 129 |
guion = custom_script if custom_script else generar_guion_profesional(prompt)
|
| 130 |
logger.info(f"Guion generado ({len(guion.split())} palabras)")
|
|
@@ -146,13 +147,6 @@ async def crear_video_profesional(prompt, custom_script, voz_index, musica=None)
|
|
| 146 |
clip = VideoFileClip(temp_video.name).subclip(0, min(10, video['duration']))
|
| 147 |
clips.append(clip)
|
| 148 |
video_final = concatenate_videoclips(clips)
|
| 149 |
-
if musica:
|
| 150 |
-
musica_clip = AudioFileClip(musica.name)
|
| 151 |
-
if musica_clip.duration < duracion_total:
|
| 152 |
-
musica_clip = musica_clip.loop(duration=duracion_total)
|
| 153 |
-
else:
|
| 154 |
-
musica_clip = musica_clip.subclip(0, duracion_total)
|
| 155 |
-
audio = CompositeAudioClip([audio, musica_clip.volumex(0.25)])
|
| 156 |
video_final = video_final.set_audio(audio)
|
| 157 |
output_path = f"video_output_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
|
| 158 |
video_final.write_videofile(output_path, fps=24, threads=2)
|
|
@@ -161,25 +155,26 @@ async def crear_video_profesional(prompt, custom_script, voz_index, musica=None)
|
|
| 161 |
logger.error(f"Error cr铆tico: {str(e)}")
|
| 162 |
return None
|
| 163 |
finally:
|
| 164 |
-
if os.path.exists(
|
| 165 |
-
os.remove(
|
| 166 |
|
| 167 |
-
def
|
|
|
|
| 168 |
return asyncio.run(crear_video_profesional(prompt, custom_script, voz_index, musica))
|
| 169 |
|
| 170 |
with gr.Blocks(title="Generador de Videos") as app:
|
| 171 |
with gr.Row():
|
| 172 |
with gr.Column():
|
| 173 |
prompt = gr.Textbox(label="Tema del video")
|
| 174 |
-
custom_script = gr.TextArea(label="
|
| 175 |
voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
|
| 176 |
musica = gr.File(label="M煤sica de fondo (opcional)", file_types=["audio"])
|
| 177 |
btn = gr.Button("Generar Video", variant="primary")
|
| 178 |
with gr.Column():
|
| 179 |
output = gr.Video(label="Resultado", format="mp4")
|
| 180 |
-
|
| 181 |
btn.click(
|
| 182 |
-
fn=
|
| 183 |
inputs=[prompt, custom_script, voz, musica],
|
| 184 |
outputs=output
|
| 185 |
)
|
|
|
|
| 14 |
from transformers import pipeline
|
| 15 |
import torch
|
| 16 |
import asyncio
|
|
|
|
| 17 |
|
| 18 |
nltk.download('punkt', quiet=True)
|
| 19 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
|
|
| 22 |
PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
|
| 23 |
MODEL_NAME = "DeepESP/gpt2-spanish"
|
| 24 |
|
| 25 |
+
# Obtener voces de edge-tts de forma s铆ncrona (wrapper)
|
| 26 |
+
def get_voices_sync():
|
| 27 |
+
return asyncio.run(edge_tts.list_voices())
|
|
|
|
|
|
|
|
|
|
|
|
|
| 28 |
|
| 29 |
+
VOICES = get_voices_sync()
|
| 30 |
+
VOICE_NAMES = [f"{v['Name']} ({v['Gender']}, {v['LocaleName']})" for v in VOICES]
|
| 31 |
|
| 32 |
def generar_guion_profesional(prompt):
|
| 33 |
try:
|
|
|
|
| 43 |
"2. Tres secciones detalladas con subt铆tulos\n"
|
| 44 |
"3. Conclusi贸n impactante\n"
|
| 45 |
"Usa un estilo natural para narraci贸n:",
|
| 46 |
+
max_length=1000,
|
| 47 |
temperature=0.7,
|
| 48 |
top_k=50,
|
| 49 |
top_p=0.95,
|
| 50 |
+
num_return_sequences=1,
|
| 51 |
+
truncation=True
|
| 52 |
)
|
| 53 |
guion = response[0]['generated_text']
|
| 54 |
if len(guion.split()) < 100:
|
|
|
|
| 88 |
驴Listos para profundizar? 隆Empecemos!
|
| 89 |
"""
|
| 90 |
|
| 91 |
+
from nltk.tokenize import sent_tokenize
|
| 92 |
+
|
| 93 |
def buscar_videos_avanzado(prompt, guion, num_videos=5):
|
| 94 |
try:
|
| 95 |
oraciones = sent_tokenize(guion)
|
|
|
|
| 125 |
return response.json().get('videos', [])[:num_videos]
|
| 126 |
|
| 127 |
async def crear_video_profesional(prompt, custom_script, voz_index, musica=None):
|
| 128 |
+
voz_archivo = None
|
| 129 |
try:
|
| 130 |
guion = custom_script if custom_script else generar_guion_profesional(prompt)
|
| 131 |
logger.info(f"Guion generado ({len(guion.split())} palabras)")
|
|
|
|
| 147 |
clip = VideoFileClip(temp_video.name).subclip(0, min(10, video['duration']))
|
| 148 |
clips.append(clip)
|
| 149 |
video_final = concatenate_videoclips(clips)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
video_final = video_final.set_audio(audio)
|
| 151 |
output_path = f"video_output_{datetime.now().strftime('%Y%m%d_%H%M%S')}.mp4"
|
| 152 |
video_final.write_videofile(output_path, fps=24, threads=2)
|
|
|
|
| 155 |
logger.error(f"Error cr铆tico: {str(e)}")
|
| 156 |
return None
|
| 157 |
finally:
|
| 158 |
+
if voz_archivo and os.path.exists(voz_archivo):
|
| 159 |
+
os.remove(voz_archivo)
|
| 160 |
|
| 161 |
+
def run_async_wrapper(prompt, custom_script, voz, musica):
|
| 162 |
+
voz_index = VOICE_NAMES.index(voz)
|
| 163 |
return asyncio.run(crear_video_profesional(prompt, custom_script, voz_index, musica))
|
| 164 |
|
| 165 |
with gr.Blocks(title="Generador de Videos") as app:
|
| 166 |
with gr.Row():
|
| 167 |
with gr.Column():
|
| 168 |
prompt = gr.Textbox(label="Tema del video")
|
| 169 |
+
custom_script = gr.TextArea(label="Guion personalizado (opcional)")
|
| 170 |
voz = gr.Dropdown(VOICE_NAMES, label="Voz", value=VOICE_NAMES[0])
|
| 171 |
musica = gr.File(label="M煤sica de fondo (opcional)", file_types=["audio"])
|
| 172 |
btn = gr.Button("Generar Video", variant="primary")
|
| 173 |
with gr.Column():
|
| 174 |
output = gr.Video(label="Resultado", format="mp4")
|
| 175 |
+
|
| 176 |
btn.click(
|
| 177 |
+
fn=run_async_wrapper,
|
| 178 |
inputs=[prompt, custom_script, voz, musica],
|
| 179 |
outputs=output
|
| 180 |
)
|