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

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -3
app.py CHANGED
@@ -1,13 +1,168 @@
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):
 
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
+ if not isinstance(text, str):
66
+ text = str(text)
67
+
68
+ # Remove non-ASCII characters
69
+ text = text.encode('ascii', 'ignore').decode('ascii')
70
+
71
+ # Replace common problematic characters
72
+ text = text.replace('–', '-') # en dash
73
+ text = text.replace('—', '-') # em dash
74
+ text = text.replace('"', '"') # smart quotes
75
+ text = text.replace('"', '"') # smart quotes
76
+ text = text.replace(''', "'") # smart apostrophe
77
+ text = text.replace(''', "'") # smart apostrophe
78
+ text = text.replace('…', '...') # ellipsis
79
+
80
+ # Remove any remaining non-standard characters
81
+ text = re.sub(r'[^\x00-\x7F]+', '', text)
82
+
83
+ return text.strip()
84
+
85
+ @staticmethod
86
+ @st.cache_data
87
+ def generate_script_cached(prompt, style, length, temperature=0.7):
88
+ """Cached script generation with proper text cleaning"""
89
+ try:
90
+ style_prompts = {
91
+ 'Professional': "Write a clear, professional video script about:",
92
+ 'Creative': "Write an engaging, creative video script about:",
93
+ 'Educational': "Write an informative educational video script about:"
94
+ }
95
+
96
+ # Clean prompt before processing
97
+ prompt = FastVideoGenerator.clean_text(prompt)
98
+
99
+ generator = pipeline('text-generation', model='distilgpt2')
100
+ output = generator(
101
+ f"{style_prompts[style]} {prompt}. Make it {length} seconds long.",
102
+ max_length=min(length * 3, 1000),
103
+ num_return_sequences=1,
104
+ temperature=temperature
105
+ )
106
+
107
+ script = output[0]['generated_text']
108
+ script = script.replace(style_prompts[style], '').strip()
109
+ return FastVideoGenerator.clean_text(script)
110
+
111
+ except Exception as e:
112
+ st.error(f"Script generation failed: {str(e)}")
113
+ raise
114
+
115
+ def create_frame_fast(self, text, theme, frame_number, total_frames, size=(1280, 720)):
116
+ """Create frame with cleaned text"""
117
+ # Clean text before rendering
118
+ text = self.clean_text(text)
119
+
120
+ # Create frame
121
+ frame = np.full((size[1], size[0], 3), theme['bg'], dtype=np.uint8)
122
+ img = Image.fromarray(frame)
123
+ draw = ImageDraw.Draw(img)
124
+
125
+ # Wrap text for better presentation
126
+ wrapped_text = textwrap.fill(text, width=50)
127
+
128
+ # Calculate text position
129
+ text_bbox = draw.textbbox((0, 0), wrapped_text, font=self.font)
130
+ text_x = (size[0] - (text_bbox[2] - text_bbox[0])) // 2
131
+ text_y = (size[1] - (text_bbox[3] - text_bbox[1])) // 2
132
+
133
+ # Draw text with background for better readability
134
+ text_bg = Image.new('RGBA', size, (0, 0, 0, 0))
135
+ text_draw = ImageDraw.Draw(text_bg)
136
+ text_draw.text((text_x, text_y), wrapped_text, fill=theme['text'], font=self.font)
137
+
138
+ # Add progress bar
139
+ progress = frame_number / total_frames
140
+ bar_width = int(1000 * progress)
141
+ draw.rectangle([140, 650, 1140, 660], fill=(200,200,200))
142
+ draw.rectangle([140, 650, 140+bar_width, 660], fill=theme['accent'])
143
+
144
+ return np.array(img)
145
+
146
+ def generate_audio_chunks(self, script, chunk_size=1000):
147
+ """Generate audio with cleaned text"""
148
+ # Clean text before TTS
149
+ script = self.clean_text(script)
150
+ chunks = textwrap.wrap(script, chunk_size)
151
+ audio_paths = []
152
+
153
+ for i, chunk in enumerate(chunks):
154
+ chunk_path = self.temp_dir / f"audio_chunk_{i}.mp3"
155
+ try:
156
+ # Additional cleaning for gTTS
157
+ chunk = re.sub(r'[^\x00-\x7F]+', '', chunk)
158
+ tts = gTTS(text=chunk, lang='en', slow=False)
159
+ tts.save(str(chunk_path))
160
+ audio_paths.append(chunk_path)
161
+ except Exception as e:
162
+ st.error(f"Audio generation failed for chunk {i}: {str(e)}")
163
+ raise
164
+
165
+ return audio_paths
166
 
167
  class VideoGenerator:
168
  def __init__(self):