Spaces:
Sleeping
Sleeping
Commit
·
68b40f6
1
Parent(s):
c7db246
add: outro page, bug fix- title mismatched
Browse files- app.py +14 -8
- src/components/each_necklace_video_gen.py +68 -39
app.py
CHANGED
@@ -195,14 +195,18 @@ class EachNecklaceVideoGeneratorRequest(BaseModel):
|
|
195 |
image_display_duration: float = 2.5
|
196 |
fps: int = 10
|
197 |
necklace_title: List[str]
|
198 |
-
nto_image_title: List[str]
|
199 |
-
nto_cto_image_title: List[str]
|
200 |
-
makeup_image_title: List[str]
|
201 |
necklace_images: List[str]
|
202 |
necklace_try_on_output_images: List[List[str]]
|
203 |
clothing_output_images: List[List[str]]
|
204 |
makeup_output_images: List[List[str]]
|
205 |
background_colors: list[tuple[int, int, int]]
|
|
|
|
|
|
|
|
|
206 |
|
207 |
|
208 |
@app.post("/createcombinedvideo/")
|
@@ -222,7 +226,8 @@ async def create_combined_video(request: EachNecklaceVideoGeneratorRequest):
|
|
222 |
'necklaces': process_images(request.necklace_images),
|
223 |
'necklace_tryon': process_images(request.necklace_try_on_output_images),
|
224 |
'clothing': process_images(request.clothing_output_images),
|
225 |
-
'makeup': process_images(request.makeup_output_images)
|
|
|
226 |
}
|
227 |
file_download_time = time.time() - start_time
|
228 |
|
@@ -256,19 +261,20 @@ async def create_combined_video(request: EachNecklaceVideoGeneratorRequest):
|
|
256 |
fps=request.fps,
|
257 |
necklace_title=request.necklace_title,
|
258 |
nto_title=request.nto_image_title,
|
259 |
-
|
260 |
cto_title=request.nto_cto_image_title,
|
261 |
makeup_title=request.makeup_image_title,
|
262 |
-
backgrounds=background_
|
|
|
|
|
|
|
|
|
263 |
|
264 |
)
|
265 |
logger.info("Creating video...")
|
266 |
|
267 |
-
# Generate video
|
268 |
video_creator.create_final_video()
|
269 |
video_creation_time = time.time() - start_time - file_download_time
|
270 |
logger.info("Video created successfully.")
|
271 |
-
# Upload video to Supabase
|
272 |
|
273 |
url = upload_to_supabase(video_path=output_path)
|
274 |
supabase_upload_time = time.time() - start_time - file_download_time - video_creation_time
|
|
|
195 |
image_display_duration: float = 2.5
|
196 |
fps: int = 10
|
197 |
necklace_title: List[str]
|
198 |
+
nto_image_title: List[List[str]]
|
199 |
+
nto_cto_image_title: List[List[str]]
|
200 |
+
makeup_image_title: List[List[str]]
|
201 |
necklace_images: List[str]
|
202 |
necklace_try_on_output_images: List[List[str]]
|
203 |
clothing_output_images: List[List[str]]
|
204 |
makeup_output_images: List[List[str]]
|
205 |
background_colors: list[tuple[int, int, int]]
|
206 |
+
outro_title: str = "Reach out to us for more information"
|
207 |
+
address: str = "123, ABC Street, XYZ City"
|
208 |
+
phone_numbers: str = "1234567890"
|
209 |
+
logo_url: str = "https://lvuhhlrkcuexzqtsbqyu.supabase.co/storage/v1/object/public/MagicMirror/FullImages/default.png"
|
210 |
|
211 |
|
212 |
@app.post("/createcombinedvideo/")
|
|
|
226 |
'necklaces': process_images(request.necklace_images),
|
227 |
'necklace_tryon': process_images(request.necklace_try_on_output_images),
|
228 |
'clothing': process_images(request.clothing_output_images),
|
229 |
+
'makeup': process_images(request.makeup_output_images),
|
230 |
+
'logo': download_image(request.logo_url)
|
231 |
}
|
232 |
file_download_time = time.time() - start_time
|
233 |
|
|
|
261 |
fps=request.fps,
|
262 |
necklace_title=request.necklace_title,
|
263 |
nto_title=request.nto_image_title,
|
|
|
264 |
cto_title=request.nto_cto_image_title,
|
265 |
makeup_title=request.makeup_image_title,
|
266 |
+
backgrounds=background_,
|
267 |
+
outro_title=request.outro_title,
|
268 |
+
address=request.address,
|
269 |
+
phone_numbers=request.phone_numbers,
|
270 |
+
logo_image=temp_files['logo']
|
271 |
|
272 |
)
|
273 |
logger.info("Creating video...")
|
274 |
|
|
|
275 |
video_creator.create_final_video()
|
276 |
video_creation_time = time.time() - start_time - file_download_time
|
277 |
logger.info("Video created successfully.")
|
|
|
278 |
|
279 |
url = upload_to_supabase(video_path=output_path)
|
280 |
supabase_upload_time = time.time() - start_time - file_download_time - video_creation_time
|
src/components/each_necklace_video_gen.py
CHANGED
@@ -3,6 +3,7 @@ project @ images_to_video
|
|
3 |
created @ 2024-12-17
|
4 |
author @ github.com/ishworrsubedii
|
5 |
"""
|
|
|
6 |
import os
|
7 |
|
8 |
from moviepy.audio.io.AudioFileClip import AudioFileClip
|
@@ -19,7 +20,8 @@ class EachVideoCreator:
|
|
19 |
nto_outputs=None,
|
20 |
nto_cto_outputs=None, makeup_outputs=None, font_path=None, output_path=None,
|
21 |
audio_path=None, image_display_duration=2.5, box_color=(131, 42, 48), box_opacity=0.8,
|
22 |
-
font_size=28, text_color="white", fps=1,
|
|
|
23 |
self.intro_video_path = intro_video_path
|
24 |
self.necklace_images = necklace_image if necklace_image else []
|
25 |
self.nto_outputs = nto_outputs if nto_outputs else []
|
@@ -39,8 +41,10 @@ class EachVideoCreator:
|
|
39 |
self.cto_title = cto_title
|
40 |
self.makeup_title = makeup_title
|
41 |
self.backgrounds = backgrounds
|
42 |
-
|
43 |
-
|
|
|
|
|
44 |
|
45 |
def create_necklace_clips(self, necklace_image, index, label):
|
46 |
if not necklace_image:
|
@@ -70,7 +74,7 @@ class EachVideoCreator:
|
|
70 |
if os.path.exists(img_path) and img_path.lower().endswith(('.png', '.jpg', '.jpeg')):
|
71 |
print(f"Processing {label} image: {img_path}")
|
72 |
img_clip = resize(ImageClip(img_path), (1080, 1080))
|
73 |
-
txt_overlay = self.create_text_overlay(f"{label}
|
74 |
final_clip = CompositeVideoClip([
|
75 |
img_clip.set_duration(self.image_display_duration),
|
76 |
txt_overlay.set_position(('center', 'bottom'))
|
@@ -84,6 +88,35 @@ class EachVideoCreator:
|
|
84 |
txt = TextClip(text, font=self.font_path, fontsize=self.font_size, color=self.text_color)
|
85 |
return CompositeVideoClip([box, txt.set_position('center')])
|
86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
def create_final_video(self):
|
88 |
try:
|
89 |
print("Starting video creation...")
|
@@ -109,31 +142,40 @@ class EachVideoCreator:
|
|
109 |
|
110 |
# NTO outputs
|
111 |
if idx < len(self.nto_outputs):
|
112 |
-
|
113 |
-
|
114 |
-
|
|
|
|
|
|
|
115 |
|
116 |
-
clips.extend(nto_clips)
|
117 |
-
else:
|
118 |
-
print(f"No valid NTO clips for Necklace {idx + 1}")
|
119 |
-
|
120 |
-
# CTO outputs
|
121 |
if idx < len(self.nto_cto_outputs):
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
|
|
130 |
if idx < len(self.makeup_outputs):
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
|
138 |
final_clips = []
|
139 |
for clip in clips:
|
@@ -172,16 +214,3 @@ class EachVideoCreator:
|
|
172 |
|
173 |
except Exception as e:
|
174 |
print(f"An error occurred during video creation: {e}")
|
175 |
-
|
176 |
-
# if __name__ == "__main__":
|
177 |
-
# creator = EachVideoCreator(
|
178 |
-
# intro_video_path="intro.mp4",
|
179 |
-
# necklace_image=["necklace.jpg", "necklace2.png"],
|
180 |
-
# nto_outputs=[["nto1.jpg", "nto2.jpg"], ["nto3.jpg", "nto4.jpg"]],
|
181 |
-
# nto_cto_outputs=[["cto1.jpg", "cto2.jpg"], ["cto3.jpg", "cto4.jpg"]],
|
182 |
-
# makeup_outputs=[["makeup1.jpg", "makeup2.jpg"], ["makeup3.jpg", "makeup4.jpg"]],
|
183 |
-
# font_path="font.ttf",
|
184 |
-
# output_path="output/final_video.mp4",
|
185 |
-
# audio_path="audio.mp3"
|
186 |
-
# )
|
187 |
-
# creator.create_final_video()
|
|
|
3 |
created @ 2024-12-17
|
4 |
author @ github.com/ishworrsubedii
|
5 |
"""
|
6 |
+
|
7 |
import os
|
8 |
|
9 |
from moviepy.audio.io.AudioFileClip import AudioFileClip
|
|
|
20 |
nto_outputs=None,
|
21 |
nto_cto_outputs=None, makeup_outputs=None, font_path=None, output_path=None,
|
22 |
audio_path=None, image_display_duration=2.5, box_color=(131, 42, 48), box_opacity=0.8,
|
23 |
+
font_size=28, text_color="white", fps=1, outro_title=None, logo_image=None, address=None,
|
24 |
+
phone_numbers=None):
|
25 |
self.intro_video_path = intro_video_path
|
26 |
self.necklace_images = necklace_image if necklace_image else []
|
27 |
self.nto_outputs = nto_outputs if nto_outputs else []
|
|
|
41 |
self.cto_title = cto_title
|
42 |
self.makeup_title = makeup_title
|
43 |
self.backgrounds = backgrounds
|
44 |
+
self.outro_title = outro_title
|
45 |
+
self.logo_image = logo_image
|
46 |
+
self.address = address
|
47 |
+
self.phone_numbers = phone_numbers
|
48 |
|
49 |
def create_necklace_clips(self, necklace_image, index, label):
|
50 |
if not necklace_image:
|
|
|
74 |
if os.path.exists(img_path) and img_path.lower().endswith(('.png', '.jpg', '.jpeg')):
|
75 |
print(f"Processing {label} image: {img_path}")
|
76 |
img_clip = resize(ImageClip(img_path), (1080, 1080))
|
77 |
+
txt_overlay = self.create_text_overlay(f"{label}")
|
78 |
final_clip = CompositeVideoClip([
|
79 |
img_clip.set_duration(self.image_display_duration),
|
80 |
txt_overlay.set_position(('center', 'bottom'))
|
|
|
88 |
txt = TextClip(text, font=self.font_path, fontsize=self.font_size, color=self.text_color)
|
89 |
return CompositeVideoClip([box, txt.set_position('center')])
|
90 |
|
91 |
+
def create_last_clip(self, title, logo_image, address, phone_numbers, font_path):
|
92 |
+
# Background clip (1080x1080, light gray color)
|
93 |
+
bg_clip = ColorClip((1080, 1080), col=(245, 245, 245), duration=self.image_display_duration)
|
94 |
+
|
95 |
+
# Resize logo to fit well within the 1080x1080 frame
|
96 |
+
logo = resize(ImageClip(logo_image), width=400)
|
97 |
+
logo = logo.set_duration(self.image_display_duration)
|
98 |
+
logo = logo.set_position(lambda t: ('center', 200)) # Place logo near top
|
99 |
+
|
100 |
+
# Title overlay text
|
101 |
+
txt_overlay_title = TextClip(title, fontsize=50, color='black', font=font_path)
|
102 |
+
txt_overlay_title = txt_overlay_title.set_duration(self.image_display_duration)
|
103 |
+
txt_overlay_title = txt_overlay_title.set_position(lambda t: ('center', 600)) # Below logo
|
104 |
+
|
105 |
+
# Address overlay text
|
106 |
+
txt_overlay_address = TextClip(address, fontsize=30, color='black', font=font_path)
|
107 |
+
txt_overlay_address = txt_overlay_address.set_duration(self.image_display_duration)
|
108 |
+
txt_overlay_address = txt_overlay_address.set_position(lambda t: ('center', 680)) # Below title
|
109 |
+
|
110 |
+
# Phone number overlay text
|
111 |
+
txt_overlay_phone = TextClip(phone_numbers, fontsize=30, color='black', font=font_path)
|
112 |
+
txt_overlay_phone = txt_overlay_phone.set_duration(self.image_display_duration)
|
113 |
+
txt_overlay_phone = txt_overlay_phone.set_position(lambda t: ('center', 730)) # Below address
|
114 |
+
|
115 |
+
# Combine everything into the final clip
|
116 |
+
final_clip = CompositeVideoClip([bg_clip, logo, txt_overlay_title, txt_overlay_address, txt_overlay_phone])
|
117 |
+
|
118 |
+
return final_clip
|
119 |
+
|
120 |
def create_final_video(self):
|
121 |
try:
|
122 |
print("Starting video creation...")
|
|
|
142 |
|
143 |
# NTO outputs
|
144 |
if idx < len(self.nto_outputs):
|
145 |
+
for idj in range(len(self.nto_outputs[idx])):
|
146 |
+
print(f"Total NTO outputs{len(self.nto_outputs)}")
|
147 |
+
print(f"Adding NTO outputs for Necklace {idx + 1}")
|
148 |
+
nto_clips = self.create_grouped_clips([self.nto_outputs[idx]], self.nto_title[idx][idj])
|
149 |
+
if nto_clips:
|
150 |
+
clips.extend(nto_clips)
|
151 |
|
|
|
|
|
|
|
|
|
|
|
152 |
if idx < len(self.nto_cto_outputs):
|
153 |
+
for idj in range(len(self.nto_cto_outputs[idx])):
|
154 |
+
print(f"Total CTO outputs{len(self.nto_cto_outputs)}")
|
155 |
+
print(f"Adding CTO outputs for Necklace {idx + 1}")
|
156 |
+
cto_clips = self.create_grouped_clips([self.nto_cto_outputs[idx]], self.cto_title[idx][idj])
|
157 |
+
if cto_clips:
|
158 |
+
clips.extend(cto_clips)
|
159 |
+
else:
|
160 |
+
print(f"No valid CTO clips for Necklace {idx + 1}")
|
161 |
+
|
162 |
if idx < len(self.makeup_outputs):
|
163 |
+
for idj in range(len(self.makeup_outputs[idx])):
|
164 |
+
print(f"Total Makeup outputs{len(self.makeup_outputs)}")
|
165 |
+
print(f"Adding Makeup outputs for Necklace {idx + 1}")
|
166 |
+
makeup_clips = self.create_grouped_clips([self.makeup_outputs[idx]],
|
167 |
+
self.makeup_title[idx][idj])
|
168 |
+
if makeup_clips:
|
169 |
+
clips.extend(makeup_clips)
|
170 |
+
else:
|
171 |
+
print(f"No valid Makeup clips for Necklace {idx + 1}")
|
172 |
+
|
173 |
+
if self.logo_image or self.address or self.phone_numbers is not None:
|
174 |
+
outro_clip = self.create_last_clip(title=self.outro_title, logo_image=self.logo_image,
|
175 |
+
address=self.address,
|
176 |
+
phone_numbers=self.phone_numbers,
|
177 |
+
font_path=self.font_path)
|
178 |
+
clips.extend([outro_clip])
|
179 |
|
180 |
final_clips = []
|
181 |
for clip in clips:
|
|
|
214 |
|
215 |
except Exception as e:
|
216 |
print(f"An error occurred during video creation: {e}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|