AZLABS commited on
Commit
b4e25f5
Β·
verified Β·
1 Parent(s): 53514f2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -249
app.py CHANGED
@@ -1,257 +1,129 @@
1
  import os
2
- import json
3
- import urllib.request
4
- from PIL import Image
5
- import cv2
6
- import moviepy.editor as mp
7
  import logging
8
- import requests
9
  import uuid
10
- import time
11
- import gradio as gr
12
- from moviepy.editor import *
13
- from moviepy.video.tools.subtitles import SubtitlesClip
14
- from hercai import Hercai # Import the hercai library
15
- from gtts import gTTS # Import gTTS for text-to-speech
16
- from hercai import Hercai # Import the hercai module
17
-
18
- # Configure logging for both file and console
19
- log_dir = os.getenv('LOG_DIRECTORY', './')
20
- LOGGER_FILE_PATH = os.path.join(str(log_dir), 'utils.log')
21
-
22
- # Create a formatter
23
- formatter = logging.Formatter(
24
- '[%(asctime)s] [%(levelname)s] [%(filename)s] [%(lineno)s:%(funcName)s()] %(message)s',
25
- datefmt='%Y-%b-%d %H:%M:%S'
26
- )
27
-
28
- # Create and configure the logger
29
- LOGGER = logging.getLogger(__name__)
30
-
31
- # Create file handler
32
- file_handler = logging.FileHandler(LOGGER_FILE_PATH, mode='a')
33
- file_handler.setFormatter(formatter)
34
-
35
- # Create console handler
36
- console_handler = logging.StreamHandler()
37
- console_handler.setFormatter(formatter)
38
-
39
- # Add both handlers to logger
40
- LOGGER.addHandler(file_handler)
41
- LOGGER.addHandler(console_handler)
42
-
43
- # Set log level
44
- log_level_env = os.getenv('LOG_LEVEL', 'INFO')
45
- log_level_dict = {
46
- 'DEBUG': logging.DEBUG,
47
- 'INFO': logging.INFO,
48
- 'WARNING': logging.WARNING,
49
- 'ERROR': logging.ERROR,
50
- 'CRITICAL': logging.CRITICAL
51
- }
52
- if log_level_env in log_level_dict:
53
- log_level = log_level_dict[log_level_env]
54
- else:
55
- log_level = log_level_dict['INFO']
56
- LOGGER.setLevel(log_level)
57
-
58
- # Set the path to the ImageMagick binary
59
- # os.environ["IMAGE_MAGICK_BINARY"] = "/usr/local/bin/convert" # Update this path as needed (No longer needed)
60
-
61
-
62
- class Text2Video:
63
- """A class to generate videos from text prompts."""
64
-
65
- def __init__(self) -> None:
66
- """Initialize the Text2Video class."""
67
- self.hercai_api_key = "YOUR_HERCAI_API_KEY" # Replace with your Hercai API key
68
- self.hercai = Hercai(self.hercai_api_key) # Initialize Hercai
69
- self.hercai_base_url = "https://hercai.onrender.com/v3/text2image"
70
- LOGGER.info("πŸš€ Text2Video class initialized.")
71
-
72
- def generate_text(self, prompt: str) -> str:
73
- """Generate text using GPT-3.5-turbo."""
74
- LOGGER.info(f"πŸ“ Generating text for prompt: {prompt}")
75
- # ... (This part is not needed for Hercai) ...
76
- return ""
77
-
78
- def get_image(self, img_prompt: str) -> str:
79
- """Generate an image based on the provided text prompt."""
80
- LOGGER.info(f"πŸ–ΌοΈ Generating image for prompt: {img_prompt}")
81
- try:
82
- image_result = self.hercai.draw_image(
83
- model="simurg", # Choose a Hercai model
84
- prompt=img_prompt,
85
- negative_prompt="Dark and gloomy"
86
- )
87
- image_url = image_result['url']
88
- LOGGER.info(f"βœ… Generated image URL: {image_url}")
89
- return image_url
90
- except requests.exceptions.RequestException as e:
91
- LOGGER.error(f"❌ Error generating image: {str(e)}")
92
- return ""
93
-
94
- def download_img_from_url(self, image_url: str, image_path: str) -> str:
95
- """Download an image from a URL."""
96
- LOGGER.info(f"⬇️ Downloading image from URL: {image_url} to path: {image_path}")
97
- try:
98
- urllib.request.urlretrieve(image_url, image_path)
99
- # Resize after downloading
100
- img = Image.open(image_path)
101
- img = img.resize((640, 480)) # Adjust resolution for reduced size
102
- img.save(image_path)
103
- LOGGER.info(f"βœ… Image downloaded to: {image_path}")
104
- return image_path
105
- except Exception as e:
106
- LOGGER.error(f"❌ Error downloading image from URL: {e}")
107
- return ""
108
-
109
- def text_to_audio(self, text: str, audio_path: str) -> str:
110
- """Convert text to speech using gTTS."""
111
- LOGGER.info(f"πŸ”Š Converting text to audio for text: {text}")
112
- try:
113
- tts = gTTS(text=text, lang='en') # You can change the language ('en' for English)
114
- tts.save(audio_path, bitrate="128k") # Reduce `bitrate` for smaller file size
115
- LOGGER.info(f"βœ… Audio saved to: {audio_path}")
116
- return audio_path
117
- except Exception as e:
118
- LOGGER.error(f"❌ Error generating speech: {str(e)}")
119
- return ""
120
-
121
- # The transcription part has been removed as it's no longer needed
122
-
123
- def get_images_and_audio(self, list_prompts: list) -> tuple:
124
- """Generate images and corresponding audio files from a list of prompts."""
125
- LOGGER.info(f"πŸ–ΌοΈπŸ”Š Generating images and audio for prompts: {list_prompts}")
126
- img_list = []
127
- audio_paths = []
128
- for img_prompt in list_prompts:
129
- try:
130
- unique_id = uuid.uuid4().hex
131
- image_path = f"{img_prompt[:9]}_{unique_id}.png"
132
- img_url = self.get_image(img_prompt)
133
-
134
- if img_url: # Only process if img_url exists & is not None
135
- image = self.download_img_from_url(img_url, image_path)
136
- img_list.append(image)
137
-
138
- audio_path = f"{img_prompt[:9]}_{unique_id}.mp3"
139
- audio = self.text_to_audio(img_prompt, audio_path)
140
-
141
- if audio: # Only process if audio exists
142
- audio_paths.append(audio)
143
- LOGGER.info(f"βœ… Processed prompt: {img_prompt}, Image: {image}, Audio: {audio}")
144
 
145
- except Exception as e:
146
- LOGGER.error(f"❌ Error processing prompt: {img_prompt}, {e}")
 
147
 
148
- return img_list, audio_paths
 
 
 
 
149
 
150
-
151
- def create_video_from_images_and_audio(self, image_files: list, audio_files: list, output_path: str) -> None:
152
- """Create a video from images and corresponding audio files with pop-up bubbles."""
153
- LOGGER.info(f"πŸŽ₯ Creating video from images: {image_files}, audio files: {audio_files}")
154
- try:
155
- if len(image_files) != len(audio_files):
156
- LOGGER.error("❌ Error: Number of images and audio files don't match.")
157
- return
158
-
159
- video_clips = []
160
-
161
- for image_file, audio_file in zip(image_files, audio_files):
162
- # Create the base video from the image and audio
163
- if not os.path.exists(audio_file) or not os.path.exists(image_file):
164
- LOGGER.error(f"❌ Audio or image file missing for {image_file} or {audio_file}")
165
- continue
166
-
167
- audio_clip = mp.AudioFileClip(audio_file)
168
- video_clip = mp.ImageClip(image_file).set_duration(audio_clip.duration)
169
- video_clip = video_clip.set_audio(audio_clip)
170
-
171
- # Apply image cropping and bubble creation
172
- try:
173
- img = Image.open(image_file)
174
- width, height = img.size
175
- cropped_image = img.crop((0, 0, int(width * 0.80), height)) # Cropping image to make space for bubble
176
-
177
- bubble_clip = mp.ImageClip(image_file).resize((150, 150))
178
- bubble_clip = bubble_clip.set_position((int(width * 0.90), 0))
179
-
180
- # Now combine the original video with the bubble
181
- video_clip = CompositeVideoClip([video_clip, bubble_clip])
182
- except Exception as ex:
183
- LOGGER.error(f"❌ Error adding comic bubble: {str(ex)}")
184
-
185
- video_clips.append(video_clip)
186
- LOGGER.info(f"βœ… Created video clip for image: {image_file}, audio: {audio_file}")
187
-
188
- # Combine the generated clips into a single video
189
- if video_clips: # Only process if clip exists
190
- final_clip = mp.concatenate_videoclips(video_clips)
191
- final_clip.write_videofile(output_path, codec='libx264', fps=24) # Optimized codec and fps settings
192
- LOGGER.info(f"βœ… Video created successfully at: {output_path}")
193
-
194
- except Exception as e:
195
- LOGGER.error(f"❌ Error creating video: {str(e)}")
196
-
197
- def generate_video(self, text: str) -> str:
198
- """
199
- Generate a video from a list of text prompts.
200
- Args:
201
- text (str): Text prompts separated by double commas.
202
- Returns:
203
- str: Path to the generated video file.
204
- """
205
- LOGGER.info(f"🎬 Generating video for text: {text}")
206
- try:
207
- list_prompts = [sentence.strip() for sentence in text.split(",,") if sentence.strip()]
208
- LOGGER.info(f"πŸ“ List of prompts: {list_prompts}")
209
-
210
- # Set the output path for the generated video
211
- output_path = f"output_video_{uuid.uuid4().hex[:8]}.mp4"
212
- LOGGER.info(f"πŸ“ Output path for video: {output_path}")
213
-
214
- # Generate images and audio
215
- img_list, audio_paths = self.get_images_and_audio(list_prompts)
216
-
217
- # Create video from images and audio
218
- self.create_video_from_images_and_audio(img_list, audio_paths, output_path)
219
-
220
- return output_path
221
- except Exception as e:
222
- LOGGER.error(f"❌ Error generating video: {str(e)}")
223
- return ""
224
-
225
- def gradio_interface(self):
226
- """Create and launch the Gradio interface."""
227
- LOGGER.info("🌐 Launching Gradio interface.")
228
- with gr.Blocks(css="style.css", theme='abidlabs/dracula_revamped') as demo:
229
- example_txt = """once upon a time there was a village. It was a nice place to live, except for one thing. people did not like to share.,, One day a visitor came to town.
230
- 'Hello. Does anybody have food to share?' He asked. 'No', said everyone.,,
231
- That's okay', said the visitor. 'I will make stone soup for everyone'.Then he took a stone and dropped it into a giant pot,,"""
232
-
233
- gr.HTML("""
234
- <center><h1 style="color:#fff">Comics Video Generator</h1></center>""")
235
-
236
- with gr.Row(elem_id="col-container"):
237
- input_text = gr.Textbox(label="Comics Text", placeholder="Enter the comics by double comma separated")
238
-
239
- with gr.Row(elem_id="col-container"):
240
- button = gr.Button("Generate Video")
241
-
242
- with gr.Row(elem_id="col-container"):
243
- output = gr.Video()
244
-
245
- with gr.Row(elem_id="col-container"):
246
- example = gr.Examples([example_txt], input_text)
247
-
248
- button.click(self.generate_video, [input_text], output)
249
-
250
- demo.launch(debug=True)
251
- LOGGER.info("βœ… Gradio interface launched.")
252
-
253
 
254
  if __name__ == "__main__":
255
- LOGGER.info("πŸš€ Starting Text2Video application.")
256
- text2video = Text2Video()
257
- text2video.gradio_interface()
 
 
 
 
 
 
 
 
1
  import os
 
 
 
 
 
2
  import logging
 
3
  import uuid
4
+ from gtts import gTTS
5
+ import moviepy.editor as mp
6
+ import g4f
7
+ from g4f import Provider
8
+ import urllib.request
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ # Set up logging
11
+ logging.basicConfig(level=logging.INFO)
12
+ logger = logging.getLogger(__name__)
13
 
14
+ def generate_image(prompt):
15
+ try:
16
+ unique_id = uuid.uuid4().hex
17
+ safe_prompt = prompt[:30].replace(' ', '_') # Take first 30 chars and make filename safe
18
+ image_filename = f"{safe_prompt}_{unique_id}.png"
19
 
20
+ response = g4f.Image.create(
21
+ prompt=f"{prompt} in comic style",
22
+ model="dalle",
23
+ provider=Provider.DeepAI
24
+ )
25
+
26
+ if response:
27
+ urllib.request.urlretrieve(response, image_filename)
28
+ logger.info(f"βœ… Generated image: {image_filename}")
29
+ return image_filename
30
+ return None
31
+ except Exception as e:
32
+ logger.error(f"❌ Error generating image: {e}")
33
+ return None
34
+
35
+ def generate_audio(text):
36
+ try:
37
+ unique_id = uuid.uuid4().hex
38
+ safe_text = text[:30].replace(' ', '_') # Take first 30 chars and make filename safe
39
+ audio_filename = f"{safe_text}_{unique_id}.mp3"
40
+
41
+ tts = gTTS(text=text, lang='en')
42
+ tts.save(audio_filename)
43
+ logger.info(f"βœ… Generated audio: {audio_filename}")
44
+ return audio_filename
45
+ except Exception as e:
46
+ logger.error(f"❌ Error generating audio: {e}")
47
+ return None
48
+
49
+ def get_images_and_audio(text):
50
+ segments = [s.strip() for s in text.split(",,") if s.strip()]
51
+ images = []
52
+ audio_files = []
53
+
54
+ for segment in segments:
55
+ image_file = generate_image(segment)
56
+ audio_file = generate_audio(segment)
57
+
58
+ if image_file and audio_file:
59
+ images.append(image_file)
60
+ audio_files.append(audio_file)
61
+ logger.info(f"βœ… Processed prompt: {segment}, Image: {image_file}, Audio: {audio_file}")
62
+
63
+ return images, audio_files
64
+
65
+ def create_video_from_images_and_audio(images, audio_files):
66
+ try:
67
+ if len(images) != len(audio_files):
68
+ raise ValueError("Number of images and audio files don't match.")
69
+
70
+ clips = []
71
+ for img, aud in zip(images, audio_files):
72
+ # Create audio clip
73
+ audio_clip = mp.AudioFileClip(aud)
74
+
75
+ # Create image clip
76
+ image_clip = mp.ImageClip(img).set_duration(audio_clip.duration)
77
+
78
+ # Combine image and audio
79
+ video_clip = image_clip.set_audio(audio_clip)
80
+ clips.append(video_clip)
81
+
82
+ # Concatenate all clips
83
+ final_clip = mp.concatenate_videoclips(clips)
84
+
85
+ # Write final video
86
+ output_filename = f"output_{uuid.uuid4().hex[:8]}.mp4"
87
+ final_clip.write_videofile(output_filename, fps=24)
88
+
89
+ # Clean up
90
+ final_clip.close()
91
+ for clip in clips:
92
+ clip.close()
93
+
94
+ # Clean up temporary files
95
+ for file in images + audio_files:
96
+ if os.path.exists(file):
97
+ os.remove(file)
98
+
99
+ logger.info(f"βœ… Video created successfully: {output_filename}")
100
+ return output_filename
101
+
102
+ except Exception as e:
103
+ logger.error(f"❌ Error: {e}")
104
+ return None
105
+
106
+ def create_video(text):
107
+ try:
108
+ # Get images and audio files
109
+ images, audio_files = get_images_and_audio(text)
110
+
111
+ # Create video
112
+ video_file = create_video_from_images_and_audio(images, audio_files)
113
+
114
+ return video_file
115
+ except Exception as e:
116
+ logger.error(f"❌ Error in create_video: {e}")
117
+ return None
 
 
 
 
 
118
 
119
  if __name__ == "__main__":
120
+ # Test the functionality
121
+ test_text = """Once upon a time there was a village.,,
122
+ One day a visitor came to town.,,
123
+ That's okay', said the visitor. 'I will make stone soup for everyone'."""
124
+
125
+ result = create_video(test_text)
126
+ if result:
127
+ print(f"Video created successfully: {result}")
128
+ else:
129
+ print("Failed to create video")