gnosticdev commited on
Commit
dd712f9
·
verified ·
1 Parent(s): 993dccc

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +67 -9
app.py CHANGED
@@ -9,51 +9,85 @@ import asyncio
9
  from datetime import datetime
10
  from pathlib import Path
11
  from transformers import pipeline
 
 
 
 
 
12
 
13
  # Pexels API key from environment variable
14
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
 
15
 
16
  # Ensure asyncio works with Gradio
17
  def run_async(coro):
 
18
  loop = asyncio.new_event_loop()
19
  asyncio.set_event_loop(loop)
20
  result = loop.run_until_complete(coro)
21
  loop.close()
 
22
  return result
23
 
24
- # Load lightweight text generation model
 
25
  try:
26
- generator = pipeline("text-generation", model="distilbert/distilgpt2", device="cpu", pad_token_id=50256)
 
27
  except Exception as e:
28
- print(f"Error loading model: {e}")
29
  generator = None
30
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  # Fetch videos from Pexels
32
  def fetch_pexels_videos(query, num_videos=5):
 
33
  headers = {"Authorization": PEXELS_API_KEY}
34
  url = f"https://api.pexels.com/videos/search?query={query}&per_page={num_videos}"
35
  response = requests.get(url, headers=headers)
36
  if response.status_code == 200:
37
- return [video["video_files"][0]["link"] for video in response.json()["videos"]]
 
 
 
38
  return []
39
 
40
  # Generate script using local model or custom text
41
  def generate_script(prompt, custom_text=None):
 
42
  if custom_text:
 
43
  return custom_text.strip()
44
  if not prompt:
 
45
  return "Error: Debes proporcionar un prompt o un guion personalizado."
46
 
47
  # Generate script with local model
48
  if generator:
49
- input_text = f"Generate a script for a video about '{prompt}'. Create a numbered list with short descriptions (max 20 words per item) for a top 10 related to the topic."
 
50
  try:
51
  result = generator(input_text, max_length=300, num_return_sequences=1, do_sample=True, truncation=True)[0]['generated_text']
 
52
  return result.strip()
53
  except Exception as e:
54
- print(f"Error generating script: {e}")
55
 
56
  # Fallback mock response
 
57
  if "recetas" in prompt.lower():
58
  return """
59
  1. Tacos al pastor: Jugosa carne marinada con piña.
@@ -71,44 +105,61 @@ def generate_script(prompt, custom_text=None):
71
 
72
  # Generate voice using Edge TTS
73
  async def generate_voice(text, output_file="output.mp3"):
74
- communicate = edge_tts.Communicate(text, voice="es-MX-DaliaNeural")
75
- await communicate.save(output_file)
76
- return output_file
 
 
 
 
 
 
77
 
78
  # Download and trim video
79
  def download_and_trim_video(url, duration, output_path):
 
80
  response = requests.get(url, stream=True)
81
  with open("temp_video.mp4", "wb") as f:
82
  for chunk in response.iter_content(chunk_size=1024):
83
  f.write(chunk)
 
84
  clip = VideoFileClip("temp_video.mp4").subclip(0, min(duration, VideoFileClip("temp_video.mp4").duration))
85
  clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
86
  clip.close()
87
  os.remove("temp_video.mp4")
 
88
  return output_path
89
 
90
  # Main video creation function
91
  def create_video(prompt, custom_text, music_file):
 
92
  output_dir = "output_videos"
93
  os.makedirs(output_dir, exist_ok=True)
94
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
95
  output_video = f"{output_dir}/video_{timestamp}.mp4"
 
96
 
97
  # Generate or use provided script
98
  script = generate_script(prompt, custom_text)
99
  if "Error" in script:
 
100
  return script
101
 
102
  # Generate voice
103
  voice_file = "temp_audio.mp3"
104
  run_async(generate_voice(script, voice_file))
 
 
 
105
  audio = AudioFileClip(voice_file)
106
  video_duration = audio.duration
 
107
 
108
  # Fetch Pexels videos
109
  query = prompt.split()[0] if prompt else "generic"
110
  video_urls = fetch_pexels_videos(query, num_videos=5)
111
  if not video_urls:
 
112
  return "Error: No se encontraron videos en Pexels."
113
 
114
  # Download and trim videos
@@ -117,22 +168,28 @@ def create_video(prompt, custom_text, music_file):
117
  clip_path = f"temp_clip_{i}.mp4"
118
  download_and_trim_video(url, video_duration / len(video_urls), clip_path)
119
  clips.append(VideoFileClip(clip_path))
 
120
 
121
  # Concatenate video clips
 
122
  final_clip = concatenate_videoclips(clips, method="compose").set_duration(video_duration)
123
 
124
  # Add looped music
125
  if music_file:
 
126
  music = AudioFileClip(music_file.name)
127
  music = audio_loop(music, duration=video_duration)
128
  final_clip = final_clip.set_audio(music.set_duration(video_duration))
129
  else:
 
130
  final_clip = final_clip.set_audio(audio)
131
 
132
  # Write final video
 
133
  final_clip.write_videofile(output_video, codec="libx264", audio_codec="aac", fps=24)
134
 
135
  # Clean up
 
136
  for clip in clips:
137
  clip.close()
138
  audio.close()
@@ -143,6 +200,7 @@ def create_video(prompt, custom_text, music_file):
143
  for i in range(len(video_urls)):
144
  os.remove(f"temp_clip_{i}.mp4")
145
 
 
146
  return output_video
147
 
148
  # Gradio interface
 
9
  from datetime import datetime
10
  from pathlib import Path
11
  from transformers import pipeline
12
+ import logging
13
+
14
+ # Configure logging
15
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
16
+ logger = logging.getLogger(__name__)
17
 
18
  # Pexels API key from environment variable
19
  PEXELS_API_KEY = os.getenv("PEXELS_API_KEY")
20
+ logger.info("Loaded PEXELS_API_KEY from environment")
21
 
22
  # Ensure asyncio works with Gradio
23
  def run_async(coro):
24
+ logger.info("Running async coroutine")
25
  loop = asyncio.new_event_loop()
26
  asyncio.set_event_loop(loop)
27
  result = loop.run_until_complete(coro)
28
  loop.close()
29
+ logger.info("Async coroutine completed")
30
  return result
31
 
32
+ # Load lightweight text generation model for Spanish
33
+ logger.info("Loading text generation model: facebook/mbart-large-50")
34
  try:
35
+ generator = pipeline("text-generation", model="facebook/mbart-large-50", device="cpu")
36
+ logger.info("Model loaded successfully")
37
  except Exception as e:
38
+ logger.error(f"Error loading model: {e}")
39
  generator = None
40
 
41
+ # List available Spanish voices for Edge TTS
42
+ SPANISH_VOICES = [
43
+ "es-MX-DaliaNeural",
44
+ "es-MX-JorgeNeural",
45
+ "es-MX-CecilioNeural",
46
+ "es-MX-BeatrizNeural",
47
+ "es-MX-CandelaNeural",
48
+ "es-MX-CarlosNeural",
49
+ "es-MX-LarissaNeural",
50
+ "es-MX-ManuelNeural",
51
+ "es-MX-MarinaNeural",
52
+ "es-MX-NuriaNeural"
53
+ ]
54
+
55
  # Fetch videos from Pexels
56
  def fetch_pexels_videos(query, num_videos=5):
57
+ logger.info(f"Fetching {num_videos} videos from Pexels with query: {query}")
58
  headers = {"Authorization": PEXELS_API_KEY}
59
  url = f"https://api.pexels.com/videos/search?query={query}&per_page={num_videos}"
60
  response = requests.get(url, headers=headers)
61
  if response.status_code == 200:
62
+ videos = [video["video_files"][0]["link"] for video in response.json()["videos"]]
63
+ logger.info(f"Fetched {len(videos)} videos from Pexels")
64
+ return videos
65
+ logger.error("Failed to fetch videos from Pexels")
66
  return []
67
 
68
  # Generate script using local model or custom text
69
  def generate_script(prompt, custom_text=None):
70
+ logger.info("Generating script")
71
  if custom_text:
72
+ logger.info("Using custom text provided by user")
73
  return custom_text.strip()
74
  if not prompt:
75
+ logger.error("No prompt or custom text provided")
76
  return "Error: Debes proporcionar un prompt o un guion personalizado."
77
 
78
  # Generate script with local model
79
  if generator:
80
+ input_text = f"Genera un guion para un video sobre '{prompt}'. Crea una lista numerada con descripciones breves (máximo 20 palabras por ítem) para un top 10 relacionado con el tema en español."
81
+ logger.info(f"Generating script with prompt: {prompt}")
82
  try:
83
  result = generator(input_text, max_length=300, num_return_sequences=1, do_sample=True, truncation=True)[0]['generated_text']
84
+ logger.info("Script generated successfully")
85
  return result.strip()
86
  except Exception as e:
87
+ logger.error(f"Error generating script: {e}")
88
 
89
  # Fallback mock response
90
+ logger.info("Using fallback mock response")
91
  if "recetas" in prompt.lower():
92
  return """
93
  1. Tacos al pastor: Jugosa carne marinada con piña.
 
105
 
106
  # Generate voice using Edge TTS
107
  async def generate_voice(text, output_file="output.mp3"):
108
+ logger.info(f"Generating voice with Edge TTS using voice: es-MX-DaliaNeural")
109
+ try:
110
+ communicate = edge_tts.Communicate(text, voice="es-MX-DaliaNeural")
111
+ await communicate.save(output_file)
112
+ logger.info(f"Voice generated and saved to {output_file}")
113
+ return output_file
114
+ except Exception as e:
115
+ logger.error(f"Error generating voice: {e}")
116
+ return None
117
 
118
  # Download and trim video
119
  def download_and_trim_video(url, duration, output_path):
120
+ logger.info(f"Downloading video from {url}")
121
  response = requests.get(url, stream=True)
122
  with open("temp_video.mp4", "wb") as f:
123
  for chunk in response.iter_content(chunk_size=1024):
124
  f.write(chunk)
125
+ logger.info("Trimming video")
126
  clip = VideoFileClip("temp_video.mp4").subclip(0, min(duration, VideoFileClip("temp_video.mp4").duration))
127
  clip.write_videofile(output_path, codec="libx264", audio_codec="aac")
128
  clip.close()
129
  os.remove("temp_video.mp4")
130
+ logger.info(f"Video trimmed and saved to {output_path}")
131
  return output_path
132
 
133
  # Main video creation function
134
  def create_video(prompt, custom_text, music_file):
135
+ logger.info("Starting video creation process")
136
  output_dir = "output_videos"
137
  os.makedirs(output_dir, exist_ok=True)
138
  timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
139
  output_video = f"{output_dir}/video_{timestamp}.mp4"
140
+ logger.info(f"Output video will be saved to {output_video}")
141
 
142
  # Generate or use provided script
143
  script = generate_script(prompt, custom_text)
144
  if "Error" in script:
145
+ logger.error(script)
146
  return script
147
 
148
  # Generate voice
149
  voice_file = "temp_audio.mp3"
150
  run_async(generate_voice(script, voice_file))
151
+ if not os.path.exists(voice_file):
152
+ logger.error("Voice generation failed")
153
+ return "Error: No se pudo generar la voz."
154
  audio = AudioFileClip(voice_file)
155
  video_duration = audio.duration
156
+ logger.info(f"Audio duration: {video_duration} seconds")
157
 
158
  # Fetch Pexels videos
159
  query = prompt.split()[0] if prompt else "generic"
160
  video_urls = fetch_pexels_videos(query, num_videos=5)
161
  if not video_urls:
162
+ logger.error("No videos found on Pexels")
163
  return "Error: No se encontraron videos en Pexels."
164
 
165
  # Download and trim videos
 
168
  clip_path = f"temp_clip_{i}.mp4"
169
  download_and_trim_video(url, video_duration / len(video_urls), clip_path)
170
  clips.append(VideoFileClip(clip_path))
171
+ logger.info(f"Processed video clip {i+1}/{len(video_urls)}")
172
 
173
  # Concatenate video clips
174
+ logger.info("Concatenating video clips")
175
  final_clip = concatenate_videoclips(clips, method="compose").set_duration(video_duration)
176
 
177
  # Add looped music
178
  if music_file:
179
+ logger.info("Adding user-uploaded music")
180
  music = AudioFileClip(music_file.name)
181
  music = audio_loop(music, duration=video_duration)
182
  final_clip = final_clip.set_audio(music.set_duration(video_duration))
183
  else:
184
+ logger.info("Using generated voice as audio")
185
  final_clip = final_clip.set_audio(audio)
186
 
187
  # Write final video
188
+ logger.info(f"Writing final video to {output_video}")
189
  final_clip.write_videofile(output_video, codec="libx264", audio_codec="aac", fps=24)
190
 
191
  # Clean up
192
+ logger.info("Cleaning up temporary files")
193
  for clip in clips:
194
  clip.close()
195
  audio.close()
 
200
  for i in range(len(video_urls)):
201
  os.remove(f"temp_clip_{i}.mp4")
202
 
203
+ logger.info("Video creation completed")
204
  return output_video
205
 
206
  # Gradio interface