AZLABS commited on
Commit
4ae5311
·
verified ·
1 Parent(s): 6e60369

Create app.p

Browse files
Files changed (1) hide show
  1. app.p +229 -0
app.p ADDED
@@ -0,0 +1,229 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import urllib.request
4
+ from PIL import Image
5
+ from gtts import gTTS
6
+ import cv2
7
+ import moviepy.editor as mp
8
+ import logging
9
+ from hercai import Hercai
10
+ import uuid
11
+ import time
12
+ import gradio as gr
13
+
14
+
15
+ # Configure logging
16
+ log_dir = os.getenv('LOG_DIRECTORY', './')
17
+ LOGGER_FILE_PATH = os.path.join(str(log_dir), 'utils.log')
18
+
19
+ logging.basicConfig(
20
+ filename=LOGGER_FILE_PATH,
21
+ filemode='a',
22
+ format='[%(asctime)s] [%(levelname)s] [%(filename)s] [%(lineno)s:%(funcName)s()] %(message)s',
23
+ datefmt='%Y-%b-%d %H:%M:%S'
24
+ )
25
+ LOGGER = logging.getLogger(__name__)
26
+
27
+ log_level_env = os.getenv('LOG_LEVEL', 'INFO')
28
+ log_level_dict = {
29
+ 'DEBUG': logging.DEBUG,
30
+ 'INFO': logging.INFO,
31
+ 'WARNING': logging.WARNING,
32
+ 'ERROR': logging.ERROR,
33
+ 'CRITICAL': logging.CRITICAL
34
+ }
35
+ if log_level_env in log_level_dict:
36
+ log_level = log_level_dict[log_level_env]
37
+ else:
38
+ log_level = log_level_dict['INFO']
39
+ LOGGER.setLevel(log_level)
40
+
41
+
42
+ class Text2Video:
43
+ """A class to generate videos from text prompts."""
44
+
45
+ def __init__(self) -> None:
46
+ """
47
+ Initialize the Text2Video class.
48
+ """
49
+ self.herc = Hercai("") # Replace with your Hercai API key if you have one
50
+
51
+ def get_image(self, img_prompt: str) -> str:
52
+ """
53
+ Generate an image based on the provided text prompt, ensuring the text is in speech bubbles.
54
+ Args:
55
+ img_prompt (str): Text prompt for generating the image.
56
+ Returns:
57
+ str: URL of the generated image.
58
+ """
59
+ try:
60
+ LOGGER.info(f"Generating image with prompt: {img_prompt}")
61
+ # Generate image using Hercai
62
+ # Modified prompt to include comic-style elements
63
+ modified_prompt = f"A comic book style image with speech bubbles containing the following text: '{img_prompt}'. Include vibrant colors and onomatopoeia where appropriate."
64
+
65
+ image_result = self.herc.draw_image(model="simurg", prompt=modified_prompt, negative_prompt="Dark and gloomy")
66
+ image_url = image_result["url"]
67
+
68
+ LOGGER.info(f"Image generated successfully: {image_url}")
69
+ return image_url
70
+
71
+ except Exception as e:
72
+ # Log any errors encountered during image generation
73
+ LOGGER.error(f"Error generating image: {e}")
74
+ return ""
75
+
76
+
77
+ def download_img_from_url(self, image_url: str, image_path: str) -> str:
78
+ """
79
+ Download an image from a URL.
80
+ Args:
81
+ image_url (str): URL of the image to download.
82
+ image_path (str): Path to save the downloaded image.
83
+ Returns:
84
+ str: Path of the downloaded image.
85
+ """
86
+ try:
87
+ LOGGER.info(f"Downloading image from: {image_url}")
88
+ # Download the image from the provided URL and save it to the specified path
89
+ urllib.request.urlretrieve(image_url, image_path)
90
+ LOGGER.info(f"Image downloaded and saved to: {image_path}")
91
+ return image_path
92
+
93
+ except Exception as e:
94
+ # Log any errors encountered during image download
95
+ LOGGER.error(f"Error downloading image from URL: {e}")
96
+ return ""
97
+
98
+ def text_to_audio(self, img_prompt: str, audio_path: str) -> str:
99
+ """
100
+ Convert text to speech and save it as an audio file.
101
+ Args:
102
+ img_prompt (str): Text to convert to speech.
103
+ audio_path (str): Path to save the audio file.
104
+ Returns:
105
+ str: Path of the saved audio file.
106
+ """
107
+ try:
108
+ LOGGER.info(f"Converting text to audio: {img_prompt}")
109
+ language = 'en'
110
+
111
+ # Create a gTTS object to convert text to speech
112
+ myobj = gTTS(text=img_prompt, lang=language, slow=False)
113
+
114
+ # Save the audio file at the specified path
115
+ myobj.save(audio_path)
116
+ LOGGER.info(f"Audio saved to: {audio_path}")
117
+ return audio_path
118
+ except Exception as e:
119
+ # Log any errors encountered during text-to-audio conversion
120
+ LOGGER.error(f"Error converting text to audio: {e}")
121
+ return ""
122
+
123
+ def get_images_and_audio(self, list_prompts: list) -> tuple:
124
+ """
125
+ Generate images and corresponding audio files from a list of prompts.
126
+ Args:
127
+ list_prompts (list): List of text prompts.
128
+ Returns:
129
+ tuple: A tuple containing lists of image paths and audio paths.
130
+ """
131
+ img_list = []
132
+ audio_paths = []
133
+ for img_prompt in list_prompts:
134
+ try:
135
+ LOGGER.info(f"Processing prompt: {img_prompt}")
136
+ unique_id = uuid.uuid4().hex
137
+ image_path = f"{img_prompt[:9]}_{unique_id}.png"
138
+ img_url = self.get_image(img_prompt)
139
+ image = self.download_img_from_url(img_url, image_path)
140
+ img_list.append(image)
141
+ audio_path = f"{img_prompt[:9]}_{unique_id}.mp3"
142
+ audio = self.text_to_audio(img_prompt, audio_path)
143
+ audio_paths.append(audio)
144
+ except Exception as e:
145
+ LOGGER.error(f"Error processing prompt: {img_prompt}, {e}")
146
+
147
+ return img_list, audio_paths
148
+
149
+ def create_video_from_images_and_audio(self, image_files: list, audio_files: list, output_path: str) -> None:
150
+ """
151
+ Create a video from images and corresponding audio files.
152
+ Args:
153
+ image_files (list): List of image files.
154
+ audio_files (list): List of audio files.
155
+ output_path (str): Path to save the output video file.
156
+ """
157
+ try:
158
+ LOGGER.info(f"Creating video from images and audio, output path: {output_path}")
159
+ if len(image_files) != len(audio_files):
160
+ LOGGER.error("Error: Number of images doesn't match the number of audio files.")
161
+ return
162
+
163
+ video_clips = []
164
+ for image_file, audio_file in zip(image_files, audio_files):
165
+ LOGGER.info(f"Processing image: {image_file} and audio: {audio_file}")
166
+ frame = cv2.imread(image_file)
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
+ video_clips.append(video_clip)
171
+
172
+ final_clip = mp.concatenate_videoclips(video_clips)
173
+ final_clip.write_videofile(output_path, codec='libx264', fps=24)
174
+ LOGGER.info("Video created successfully.")
175
+
176
+ except Exception as e:
177
+ # Log any errors encountered during video creation
178
+ LOGGER.error(f"Error creating video: {e}")
179
+
180
+ def generate_video(self, text: str) -> str:
181
+ """
182
+ Generate a video from a list of text prompts.
183
+ Args:
184
+ text (str): Text prompts separated by double commas.
185
+ Returns:
186
+ str: Path to the generated video.
187
+ """
188
+ try:
189
+ LOGGER.info(f"Generating video from text: {text}")
190
+ list_prompts = [sentence.strip() for sentence in text.split(",,") if sentence.strip()]
191
+
192
+ output_path = "output_video.mp4"
193
+
194
+ img_list, audio_paths = self.get_images_and_audio(list_prompts)
195
+ self.create_video_from_images_and_audio(img_list, audio_paths, output_path)
196
+ LOGGER.info(f"Video generated successfully: {output_path}")
197
+ return output_path
198
+ except Exception as e:
199
+ LOGGER.error(f"Error generating video: {e}")
200
+ return ""
201
+
202
+ def gradio_interface(self):
203
+ with gr.Blocks(css="style.css", theme='abidlabs/dracula_revamped') as demo:
204
+ 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.
205
+ 'Hello. Does anybody have food to share?' He asked. 'No', said everyone.,,
206
+ 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,,"""
207
+
208
+ gr.HTML("""
209
+ <center><h1 style="color:#fff">Comics Video Generator</h1></center>""")
210
+
211
+ with gr.Row(elem_id="col-container"):
212
+ input_text = gr.Textbox(label="Comics Text", placeholder="Enter the comics by double comma separated")
213
+
214
+ with gr.Row(elem_id="col-container"):
215
+ button = gr.Button("Generate Video")
216
+
217
+ with gr.Row(elem_id="col-container"):
218
+ output = gr.PlayableVideo()
219
+
220
+ with gr.Row(elem_id="col-container"):
221
+ example = gr.Examples([example_txt], input_text)
222
+
223
+ button.click(self.generate_video, [input_text], output)
224
+ demo.launch(debug=True)
225
+
226
+
227
+ if __name__ == "__main__":
228
+ text2video = Text2Video()
229
+ text2video.gradio_interface()