shaheerawan3 commited on
Commit
e4b3a75
·
verified ·
1 Parent(s): 8e46c45

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +101 -251
app.py CHANGED
@@ -1,317 +1,167 @@
1
  import streamlit as st
2
- from pathlib import Path
3
  import torch
4
  from transformers import pipeline
5
  from PIL import Image, ImageDraw, ImageFont
6
  import tempfile
7
- import os
8
- from moviepy.editor import *
9
- import numpy as np
10
  from gtts import gTTS
 
11
  import textwrap
12
- from concurrent.futures import ThreadPoolExecutor
13
- import io
14
- import unicodedata
15
- import re
16
 
17
- class FastVideoGenerator:
18
  def __init__(self):
19
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
 
20
 
21
- # Initialize text generation with efficient model
22
  self.text_generator = pipeline(
23
  'text-generation',
24
  model='distilgpt2',
25
  device=0 if self.device == "cuda" else -1
26
  )
27
 
28
- # Create temp directory
29
- self.temp_dir = Path(tempfile.mkdtemp())
30
-
31
- # Theme colors with opacity for better text visibility
32
  self.themes = {
33
- 'Professional': {
34
- 'bg': (245, 245, 245),
35
- 'text': (33, 33, 33),
36
- 'accent': (0, 102, 204),
37
- 'overlay': (255, 255, 255, 180)
38
- },
39
- 'Creative': {
40
- 'bg': (255, 240, 245),
41
- 'text': (51, 51, 51),
42
- 'accent': (255, 64, 129),
43
- 'overlay': (255, 255, 255, 180)
44
- },
45
- 'Educational': {
46
- 'bg': (240, 249, 255),
47
- 'text': (25, 25, 25),
48
- 'accent': (0, 151, 167),
49
- 'overlay': (255, 255, 255, 180)
50
- }
51
  }
52
-
53
- # Pre-load font
54
  try:
55
  self.font = ImageFont.truetype("arial.ttf", 40)
56
  except:
57
  self.font = ImageFont.load_default()
58
-
59
- # Add text cleaner
60
- self.text_cleaner = re.compile(r'[^\x00-\x7F]+')
61
 
62
- @staticmethod
63
- def clean_text(text):
64
- """Clean text to handle encoding issues"""
65
- # Normalize unicode characters
66
- text = unicodedata.normalize('NFKD', text)
67
- # Replace special characters with standard ASCII
68
- text = text.encode('ascii', 'ignore').decode('ascii')
69
- # Replace common special characters
70
- replacements = {
71
- '–': '-', # en dash
72
- '—': '-', # em dash
73
- ''': "'", # curly quote
74
- ''': "'", # curly quote
75
- '"': '"', # curly quote
76
- '"': '"', # curly quote
77
- '…': '...' # ellipsis
78
- }
79
- for old, new in replacements.items():
80
- text = text.replace(old, new)
81
- return text
82
-
83
- @staticmethod
84
- @st.cache_data
85
- def generate_script_cached(prompt, style, length, temperature=0.7):
86
- """Cached script generation with proper text cleaning"""
87
  style_prompts = {
88
- 'Professional': "Write a clear, professional video script about:",
89
- 'Creative': "Write an engaging, creative video script about:",
90
- 'Educational': "Write an informative educational video script about:"
91
  }
92
 
93
- prompt = FastVideoGenerator.clean_text(prompt)
94
-
95
- with pipeline('text-generation', model='distilgpt2') as generator:
96
- output = generator(
97
- f"{style_prompts[style]} {prompt}. Make it {length} seconds long.",
98
- max_length=min(length * 3, 1000),
99
- num_return_sequences=1,
100
- temperature=temperature
101
- )
102
 
103
- script = output[0]['generated_text']
104
- script = script.replace(style_prompts[style], '').strip()
105
- return FastVideoGenerator.clean_text(script)
106
 
107
- def create_frame_fast(self, text, theme, frame_number, total_frames, size=(1280, 720)):
108
- """Create frame with cleaned text"""
109
- # Clean text before rendering
110
- text = self.clean_text(text)
111
-
112
- # Create frame
113
  frame = np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
114
  img = Image.fromarray(frame)
115
  draw = ImageDraw.Draw(img)
116
 
117
- # Wrap text for better presentation
118
  wrapped_text = textwrap.fill(text, width=50)
119
-
120
- # Calculate text position
121
  text_bbox = draw.textbbox((0, 0), wrapped_text, font=self.font)
122
  text_x = (size[0] - (text_bbox[2] - text_bbox[0])) // 2
123
  text_y = (size[1] - (text_bbox[3] - text_bbox[1])) // 2
124
-
125
- # Draw text with background for better readability
126
- text_bg = Image.new('RGBA', size, (0, 0, 0, 0))
127
- text_draw = ImageDraw.Draw(text_bg)
128
- text_draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=self.font)
129
 
130
  # Add progress bar
131
- progress = frame_number / total_frames
132
  bar_width = int(1000 * progress)
133
- draw.rectangle([140, 650, 1140, 660], fill=(200,200,200))
134
- draw.rectangle([140, 650, 140+bar_width, 660], fill=theme['accent'])
135
 
136
  return np.array(img)
137
 
138
- def generate_audio_chunks(self, script, chunk_size=1000):
139
- """Generate audio with cleaned text"""
140
- # Clean text before TTS
141
- script = self.clean_text(script)
142
- chunks = textwrap.wrap(script, chunk_size)
143
- audio_paths = []
144
-
145
- for i, chunk in enumerate(chunks):
146
- chunk_path = self.temp_dir / f"audio_chunk_{i}.mp3"
147
- try:
148
- tts = gTTS(text=chunk, lang='en', slow=False)
149
- tts.save(str(chunk_path))
150
- audio_paths.append(chunk_path)
151
- except Exception as e:
152
- # If TTS fails, try with further cleaning
153
- cleaned_chunk = re.sub(r'[^a-zA-Z0-9\s.,!?-]', '', chunk)
154
- tts = gTTS(text=cleaned_chunk, lang='en', slow=False)
155
- tts.save(str(chunk_path))
156
- audio_paths.append(chunk_path)
157
-
158
- return audio_paths
159
-
160
- def create_optimized_video(self, script, theme, duration=30):
161
- """Create video with optimized processing"""
162
  fps = 24
163
  total_frames = duration * fps
164
 
165
- # Create frames efficiently
166
  def make_frame(t):
167
- frame_number = int(t * fps)
168
- return self.create_frame_fast(
169
- script,
170
- self.themes[theme],
171
- frame_number,
172
- total_frames
173
- )
174
 
175
- # Generate video with reduced memory usage
 
176
  clip = VideoClip(make_frame, duration=duration)
177
 
178
- # Generate audio in background while processing video
179
- with ThreadPoolExecutor() as executor:
180
- future_audio = executor.submit(self.generate_audio_chunks, script)
181
-
182
- # Process video
183
- output_path = self.temp_dir / "output_video.mp4"
184
- temp_video = self.temp_dir / "temp_video.mp4"
185
-
186
- # Write video without audio first
187
- clip.write_videofile(
188
- str(temp_video),
189
- fps=fps,
190
- codec='libx264',
191
- audio=False,
192
- preset='ultrafast'
193
- )
194
-
195
- # Get audio paths and combine audio
196
- audio_paths = future_audio.result()
197
- audio_clips = [AudioFileClip(str(path)) for path in audio_paths]
198
- final_audio = concatenate_audioclips(audio_clips)
199
-
200
- # Combine video and audio
201
- video = VideoFileClip(str(temp_video))
202
- final_clip = video.set_audio(final_audio)
203
- final_clip.write_videofile(str(output_path), fps=fps, codec='libx264')
204
-
205
- # Cleanup
206
- video.close()
207
- final_clip.close()
208
- for clip in audio_clips:
209
- clip.close()
210
-
211
- return output_path
212
-
213
- def main():
214
- st.set_page_config(
215
- page_title="⚡ Fast Video Generator",
216
- layout="wide",
217
- initial_sidebar_state="expanded"
218
- )
219
-
220
- # Custom CSS
221
- st.markdown("""
222
- <style>
223
- .stButton>button {
224
- width: 100%;
225
- height: 3em;
226
- background-color: #FF4B4B;
227
- color: white;
228
- }
229
- .stProgress > div > div > div > div {
230
- background-color: #FF4B4B;
231
- }
232
- </style>
233
- """, unsafe_allow_html=True)
234
-
235
- if 'video_generator' not in st.session_state:
236
- st.session_state.video_generator = FastVideoGenerator()
237
-
238
- with st.sidebar:
239
- st.title("🎮 Video Settings")
240
-
241
- theme = st.selectbox(
242
- "Theme Style",
243
- ["Professional", "Creative", "Educational"],
244
- help="Choose the visual style of your video"
245
  )
246
 
247
- duration = st.slider(
248
- "Duration (seconds)",
249
- min_value=30,
250
- max_value=300,
251
- value=60,
252
- step=30,
253
- help="Videos up to 5 minutes supported"
254
- )
255
 
256
- quality = st.select_slider(
257
- "Generation Speed",
258
- options=["High Quality", "Balanced", "Fast"],
259
- value="Balanced",
260
- help="Faster generation may reduce video quality"
261
- )
262
-
263
- st.title("⚡ Fast Video Generator")
264
- st.markdown("Create longer videos with optimized performance!")
265
-
266
- text_input = st.text_area(
267
- "Video Topic",
268
- height=100,
269
- placeholder="Enter your topic here..."
270
- )
271
 
272
- if st.button("🎬 Generate Video", use_container_width=True):
273
- if text_input:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  try:
275
- progress_bar = st.progress(0)
 
276
  status = st.empty()
277
 
278
- # Script generation
279
- status.text("✍️ Creating script...")
280
- script = FastVideoGenerator.generate_script_cached(
281
- text_input, theme, duration
282
- )
283
- progress_bar.progress(30)
284
 
285
- # Video creation
286
- status.text("🎨 Generating video...")
287
- video_path = st.session_state.video_generator.create_optimized_video(
288
- script, theme, duration
289
- )
290
- progress_bar.progress(100)
291
- status.text("✨ Video ready!")
292
 
293
- # Display results
294
- tab1, tab2 = st.tabs(["📽️ Video", "📝 Script"])
295
-
296
- with tab1:
297
  st.video(str(video_path))
298
- with open(str(video_path), 'rb') as f:
299
- st.download_button(
300
- "⬇️ Download Video",
301
- f,
302
- file_name="generated_video.mp4",
303
- mime="video/mp4"
304
- )
305
-
306
- with tab2:
307
- st.markdown("### Generated Script")
308
- st.write(script)
309
 
 
 
 
 
 
 
 
 
 
310
  except Exception as e:
311
- st.error(f"💥 Error: {str(e)}")
312
- st.error("Please try again with different settings")
313
  else:
314
- st.warning("⚠️ Please enter a topic first!")
315
 
316
  if __name__ == "__main__":
317
  main()
 
1
  import streamlit as st
 
2
  import torch
3
  from transformers import pipeline
4
  from PIL import Image, ImageDraw, ImageFont
5
  import tempfile
6
+ from pathlib import Path
7
+ from moviepy.editor import VideoClip, VideoFileClip, AudioFileClip, concatenate_audioclips
 
8
  from gtts import gTTS
9
+ import numpy as np
10
  import textwrap
 
 
 
 
11
 
12
+ class VideoGenerator:
13
  def __init__(self):
14
  self.device = "cuda" if torch.cuda.is_available() else "cpu"
15
+ self.temp_dir = Path(tempfile.mkdtemp())
16
 
17
+ # Load text generator
18
  self.text_generator = pipeline(
19
  'text-generation',
20
  model='distilgpt2',
21
  device=0 if self.device == "cuda" else -1
22
  )
23
 
24
+ # Define themes
 
 
 
25
  self.themes = {
26
+ 'Professional': {'bg': (245, 245, 245), 'text': (33, 33, 33)},
27
+ 'Creative': {'bg': (255, 240, 245), 'text': (51, 51, 51)},
28
+ 'Educational': {'bg': (240, 249, 255), 'text': (25, 25, 25)}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  }
30
+
31
+ # Load font
32
  try:
33
  self.font = ImageFont.truetype("arial.ttf", 40)
34
  except:
35
  self.font = ImageFont.load_default()
 
 
 
36
 
37
+ def generate_script(self, prompt, style, length):
38
+ """Generate video script based on prompt"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  style_prompts = {
40
+ 'Professional': "Write a professional video script about:",
41
+ 'Creative': "Write a creative video script about:",
42
+ 'Educational': "Write an educational video script about:"
43
  }
44
 
45
+ output = self.text_generator(
46
+ f"{style_prompts[style]} {prompt}. Length: {length} seconds.",
47
+ max_length=min(length * 3, 1000),
48
+ num_return_sequences=1,
49
+ temperature=0.7
50
+ )
 
 
 
51
 
52
+ return output[0]['generated_text'].replace(style_prompts[style], '').strip()
 
 
53
 
54
+ def create_frame(self, text, theme, frame_num, total_frames, size=(1280, 720)):
55
+ """Create a single video frame"""
56
+ # Create base frame
 
 
 
57
  frame = np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
58
  img = Image.fromarray(frame)
59
  draw = ImageDraw.Draw(img)
60
 
61
+ # Add text
62
  wrapped_text = textwrap.fill(text, width=50)
 
 
63
  text_bbox = draw.textbbox((0, 0), wrapped_text, font=self.font)
64
  text_x = (size[0] - (text_bbox[2] - text_bbox[0])) // 2
65
  text_y = (size[1] - (text_bbox[3] - text_bbox[1])) // 2
66
+ draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=self.font)
 
 
 
 
67
 
68
  # Add progress bar
69
+ progress = frame_num / total_frames
70
  bar_width = int(1000 * progress)
71
+ draw.rectangle([140, 650, 140+bar_width, 660], fill=(100, 100, 100))
 
72
 
73
  return np.array(img)
74
 
75
+ def generate_video(self, script, theme, duration=30):
76
+ """Generate complete video with audio"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  fps = 24
78
  total_frames = duration * fps
79
 
80
+ # Create video frames
81
  def make_frame(t):
82
+ frame_num = int(t * fps)
83
+ return self.create_frame(script, self.themes[theme], frame_num, total_frames)
 
 
 
 
 
84
 
85
+ # Generate video
86
+ video_path = self.temp_dir / "output.mp4"
87
  clip = VideoClip(make_frame, duration=duration)
88
 
89
+ # Generate audio
90
+ audio_path = self.temp_dir / "audio.mp3"
91
+ tts = gTTS(text=script, lang='en')
92
+ tts.save(str(audio_path))
93
+
94
+ # Combine video and audio
95
+ audio = AudioFileClip(str(audio_path))
96
+ final_clip = clip.set_audio(audio)
97
+ final_clip.write_videofile(
98
+ str(video_path),
99
+ fps=fps,
100
+ codec='libx264',
101
+ audio_codec='aac'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
  )
103
 
104
+ # Cleanup
105
+ audio.close()
106
+ final_clip.close()
 
 
 
 
 
107
 
108
+ return video_path
 
 
 
 
 
 
 
 
 
 
 
 
 
 
109
 
110
+ def main():
111
+ st.set_page_config(page_title="Video Generator", layout="wide")
112
+
113
+ # Initialize generator
114
+ if 'generator' not in st.session_state:
115
+ st.session_state.generator = VideoGenerator()
116
+
117
+ # UI Elements
118
+ st.title("🎥 Quick Video Generator")
119
+
120
+ with st.sidebar:
121
+ theme = st.selectbox("Theme", ["Professional", "Creative", "Educational"])
122
+ duration = st.slider("Duration (seconds)", 30, 120, 60, 30)
123
+
124
+ # Main input
125
+ prompt = st.text_area("What's your video about?", height=100)
126
+
127
+ if st.button("Generate Video"):
128
+ if prompt:
129
  try:
130
+ # Show progress
131
+ progress = st.progress(0)
132
  status = st.empty()
133
 
134
+ # Generate script
135
+ status.text("Creating script...")
136
+ script = st.session_state.generator.generate_script(prompt, theme, duration)
137
+ progress.progress(33)
 
 
138
 
139
+ # Create video
140
+ status.text("Generating video...")
141
+ video_path = st.session_state.generator.generate_video(script, theme, duration)
142
+ progress.progress(100)
143
+ status.text("Done!")
 
 
144
 
145
+ # Show results
146
+ col1, col2 = st.columns(2)
147
+ with col1:
 
148
  st.video(str(video_path))
149
+ with col2:
150
+ st.text_area("Generated Script", script, height=200)
 
 
 
 
 
 
 
 
 
151
 
152
+ # Download button
153
+ with open(str(video_path), 'rb') as f:
154
+ st.download_button(
155
+ "Download Video",
156
+ f,
157
+ file_name="generated_video.mp4",
158
+ mime="video/mp4"
159
+ )
160
+
161
  except Exception as e:
162
+ st.error(f"Error: {str(e)}")
 
163
  else:
164
+ st.warning("Please enter a topic first!")
165
 
166
  if __name__ == "__main__":
167
  main()