AZLABS commited on
Commit
3b31d0b
·
verified ·
1 Parent(s): ff73331

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +110 -130
app.py CHANGED
@@ -1,171 +1,151 @@
1
  import os
2
- import logging
3
- import uuid
4
- from typing import List, Tuple
5
  import urllib.request
6
  from PIL import Image
7
  from gtts import gTTS
 
8
  import moviepy.editor as mp
9
- import gradio as gr
10
  from hercai import Hercai
 
 
 
 
 
 
 
 
11
 
12
- # Configure logging
13
  logging.basicConfig(
 
 
 
 
14
  level=logging.INFO,
15
- format='%(asctime)s - %(levelname)s - %(message)s',
16
  handlers=[
17
- logging.FileHandler('comic_generator.log'),
18
  logging.StreamHandler()
19
  ]
20
  )
21
- logger = logging.getLogger(__name__)
22
-
23
- class ComicVideoGenerator:
24
- def __init__(self):
25
- """Initialize comic video generator with Hercai API"""
26
- self.api = Hercai()
27
- self.image_size = (1024, 1024)
28
-
29
- def generate_comic_image(self, prompt: str) -> str:
30
- """Generate comic-style image from text prompt"""
31
  try:
 
32
  enhanced_prompt = (
33
- f"{prompt}, comic book style, vibrant colors, "
34
- "clear speech bubbles, dramatic lighting, "
35
- "detailed backgrounds, professional illustration"
 
 
 
36
  )
37
-
38
- result = self.api.draw_image(
39
- model="simurg",
40
  prompt=enhanced_prompt,
41
- negative_prompt="blurry, low quality, dark"
42
  )
43
- logger.info(f"Generated image for prompt: {prompt[:30]}...")
 
44
  return result["url"]
45
-
46
  except Exception as e:
47
- logger.error(f"Image generation failed: {e}")
48
  raise
49
 
50
- def process_image(self, url: str, save_path: str) -> str:
51
- """Download and process image to correct size"""
52
  try:
53
- urllib.request.urlretrieve(url, save_path)
54
 
55
- with Image.open(save_path) as img:
56
- img.thumbnail(self.image_size)
57
- new_img = Image.new('RGB', self.image_size, 'white')
58
- offset = tuple(map(lambda x, y: (x - y) // 2,
59
- self.image_size, img.size))
60
- new_img.paste(img, offset)
61
- new_img.save(save_path, quality=95)
62
-
63
- logger.info(f"Processed and saved image: {save_path}")
64
- return save_path
65
 
66
- except Exception as e:
67
- logger.error(f"Image processing failed: {e}")
68
- raise
69
 
70
- def create_audio(self, text: str, save_path: str) -> str:
71
- """Generate audio narration from text"""
72
- try:
73
- tts = gTTS(text=text, lang='en')
74
- tts.save(save_path)
75
- logger.info(f"Created audio: {save_path}")
76
- return save_path
77
  except Exception as e:
78
- logger.error(f"Audio generation failed: {e}")
79
  raise
80
 
81
- def process_scene(self, prompt: str, scene_id: str) -> Tuple[str, str]:
82
- """Process single scene (image + audio)"""
83
- image_path = f"scene_{scene_id}.png"
84
- audio_path = f"audio_{scene_id}.mp3"
85
-
86
- image_url = self.generate_comic_image(prompt)
87
- image_file = self.process_image(image_url, image_path)
88
- audio_file = self.create_audio(prompt, audio_path)
89
-
90
- return image_file, audio_file
91
-
92
- def create_video(self, images: List[str], audios: List[str],
93
- output_path: str) -> str:
94
- """Create final video from images and audio"""
95
  try:
96
- clips = []
97
- for img, audio in zip(images, audios):
98
- audio_clip = mp.AudioFileClip(audio)
99
- video_clip = (mp.ImageClip(img)
100
- .set_duration(audio_clip.duration)
101
- .set_audio(audio_clip))
102
- clips.append(video_clip)
103
-
104
- final_clip = mp.concatenate_videoclips(clips)
 
 
 
 
105
  final_clip.write_videofile(
106
  output_path,
107
- fps=24,
108
  codec='libx264',
109
- audio_codec='aac'
 
 
 
 
110
  )
111
- logger.info(f"Created video: {output_path}")
112
- return output_path
113
 
 
 
114
  except Exception as e:
115
- logger.error(f"Video creation failed: {e}")
116
  raise
117
 
118
- def generate(self, text: str) -> str:
119
- """Main video generation pipeline"""
120
- try:
121
- scenes = [s.strip() for s in text.split(",,") if s.strip()]
122
- output_path = f"comic_{uuid.uuid4().hex[:8]}.mp4"
123
-
124
- images, audios = [], []
125
- for i, scene in enumerate(scenes):
126
- img, audio = self.process_scene(scene, f"{i}")
127
- images.append(img)
128
- audios.append(audio)
129
-
130
- return self.create_video(images, audios, output_path)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
- except Exception as e:
133
- logger.error(f"Generation pipeline failed: {e}")
134
- raise
135
 
136
- def create_interface():
137
- """Create Gradio interface"""
138
- generator = ComicVideoGenerator()
139
-
140
- examples = [
141
- "A magical forest at sunset.,, A brave knight finds a glowing crystal.,, The crystal transforms into a dragon.",
142
- "A busy city street.,, A mysterious package appears.,, The package opens to reveal a portal."
143
- ]
144
-
145
- with gr.Blocks(theme='default') as demo:
146
- gr.Markdown("# Comic Video Generator")
147
-
148
- with gr.Row():
149
- text_input = gr.Textbox(
150
- label="Story Text",
151
- placeholder="Enter story scenes separated by ',,'",
152
- lines=3
153
  )
154
-
155
- with gr.Row():
156
- generate_btn = gr.Button("Generate Comic")
157
- video_output = gr.Video(label="Generated Comic")
158
-
159
- gr.Examples(examples, text_input)
160
-
161
- generate_btn.click(
162
- fn=generator.generate,
163
- inputs=text_input,
164
- outputs=video_output
165
- )
166
-
167
- return demo
168
-
169
- if __name__ == "__main__":
170
- interface = create_interface()
171
- interface.launch(debug=True)
 
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
+ from typing import Tuple, List
14
+
15
+ # Enhanced logging configuration
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
  level=logging.INFO,
 
25
  handlers=[
26
+ logging.FileHandler(LOGGER_FILE_PATH),
27
  logging.StreamHandler()
28
  ]
29
  )
30
+ LOGGER = logging.getLogger(__name__)
31
+
32
+ class Text2Video:
33
+ def __init__(self) -> None:
34
+ """Initialize the Text2Video class."""
35
+ self.herc = Hercai()
36
+ LOGGER.info("Initialized Text2Video with Hercai API")
37
+
38
+ def get_image(self, img_prompt: str) -> str:
39
+ """Generate an image based on the provided text prompt."""
40
  try:
41
+ # Enhanced prompt engineering similar to DALL-E 3
42
  enhanced_prompt = (
43
+ f"Create a high-quality comic panel: {img_prompt}. "
44
+ "Style: Professional comic book illustration, "
45
+ "vivid colors, clear composition, dramatic lighting. "
46
+ "Include text as comic-style captions. "
47
+ "Resolution: High detail, 1792x1024 aspect ratio. "
48
+ "Quality: Professional grade comic art."
49
  )
50
+
51
+ result = self.herc.draw_image(
52
+ model="simurg", # Using Hercai's best model
53
  prompt=enhanced_prompt,
54
+ negative_prompt="blurry, low quality, poorly drawn, distorted"
55
  )
56
+
57
+ LOGGER.info(f"Successfully generated image for prompt: {img_prompt[:50]}...")
58
  return result["url"]
59
+
60
  except Exception as e:
61
+ LOGGER.error(f"Error generating image: {e}")
62
  raise
63
 
64
+ def download_img_from_url(self, image_url: str, image_path: str) -> str:
65
+ """Download and process image from URL."""
66
  try:
67
+ urllib.request.urlretrieve(image_url, image_path)
68
 
69
+ # Image processing for consistent quality
70
+ img = Image.open(image_path)
71
+ target_size = (1792, 1024) # Matching DALL-E 3 size
72
+ img = img.resize(target_size, Image.Resampling.LANCZOS)
73
+ img.save(image_path, quality=95)
 
 
 
 
 
74
 
75
+ LOGGER.info(f"Successfully downloaded and processed image: {image_path}")
76
+ return image_path
 
77
 
 
 
 
 
 
 
 
78
  except Exception as e:
79
+ LOGGER.error(f"Error downloading image: {e}")
80
  raise
81
 
82
+ def create_video_from_images_and_audio(self, image_files: list, audio_files: list, output_path: str) -> None:
83
+ """Create video with enhanced quality settings."""
 
 
 
 
 
 
 
 
 
 
 
 
84
  try:
85
+ if len(image_files) != len(audio_files):
86
+ raise ValueError("Number of images doesn't match number of audio files")
87
+
88
+ video_clips = []
89
+ for image_file, audio_file in zip(image_files, audio_files):
90
+ audio_clip = mp.AudioFileClip(audio_file)
91
+ video_clip = mp.ImageClip(image_file).set_duration(audio_clip.duration)
92
+ video_clip = video_clip.set_audio(audio_clip)
93
+ video_clips.append(video_clip)
94
+
95
+ final_clip = mp.concatenate_videoclips(video_clips)
96
+
97
+ # Enhanced video quality settings
98
  final_clip.write_videofile(
99
  output_path,
 
100
  codec='libx264',
101
+ fps=24,
102
+ audio_codec='aac',
103
+ audio_bitrate='192k',
104
+ preset='medium',
105
+ threads=4
106
  )
 
 
107
 
108
+ LOGGER.info("Video created successfully")
109
+
110
  except Exception as e:
111
+ LOGGER.error(f"Error creating video: {e}")
112
  raise
113
 
114
+ # [Previous methods remain the same]
115
+
116
+ def gradio_interface(self):
117
+ """Create enhanced Gradio interface."""
118
+ with gr.Blocks(theme='abidlabs/dracula_revamped') as demo:
119
+ gr.HTML("""
120
+ <center>
121
+ <h1 style="color:#fff">AI Comic Video Generator</h1>
122
+ <p style="color:#ddd">Create engaging comic-style videos from your stories</p>
123
+ </center>
124
+ """)
125
+
126
+ with gr.Row():
127
+ input_text = gr.Textbox(
128
+ label="Story Script",
129
+ placeholder="Enter your story (separate scenes with ,,)",
130
+ lines=5
131
+ )
132
+
133
+ with gr.Row():
134
+ generate_btn = gr.Button("🎬 Generate Comic Video", variant="primary")
135
+
136
+ with gr.Row():
137
+ output = gr.Video(label="Generated Comic Video")
138
+
139
+ example_txt = """Once upon a time in a magical forest,,
140
+ A brave knight discovered a mysterious crystal,,
141
+ The crystal began to glow with incredible power"""
142
 
143
+ gr.Examples([[example_txt]], [input_text])
 
 
144
 
145
+ generate_btn.click(
146
+ self.generate_video,
147
+ inputs=[input_text],
148
+ outputs=[output]
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  )
150
+
151
+ demo.launch(debug=True)