Spaces:
Sleeping
Sleeping
Commit
·
00e83a0
1
Parent(s):
98173c8
minor fixes
Browse files- app.py +32 -16
- src/components/vidgen.py +26 -11
app.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1 |
import os
|
|
|
2 |
|
|
|
3 |
from fastapi import FastAPI
|
4 |
from pydantic import BaseModel
|
5 |
from starlette.responses import JSONResponse
|
@@ -29,18 +31,6 @@ def upload_to_supabase(video_path, bucket_name="JewelmirrorVideoGeneration"):
|
|
29 |
return None
|
30 |
|
31 |
|
32 |
-
class VideoGenerator(BaseModel):
|
33 |
-
necklace_image: str
|
34 |
-
necklace_try_on_output_images: list[str]
|
35 |
-
clothing_output_images: list[str]
|
36 |
-
makeup_output_images: list[str]
|
37 |
-
store_name: str
|
38 |
-
|
39 |
-
|
40 |
-
import requests
|
41 |
-
import tempfile
|
42 |
-
|
43 |
-
|
44 |
def download_image(url):
|
45 |
"""
|
46 |
Download an image from the web and save it as a temporary file.
|
@@ -61,6 +51,25 @@ def download_image(url):
|
|
61 |
return None
|
62 |
|
63 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
64 |
@app.post("/create-video/")
|
65 |
async def create_video(request: VideoGenerator):
|
66 |
try:
|
@@ -76,10 +85,10 @@ async def create_video(request: VideoGenerator):
|
|
76 |
return JSONResponse(content={"status": "error", "message": "Failed to download all required images."},
|
77 |
status_code=400)
|
78 |
|
79 |
-
intro_path = f"{RESOURCES_DIR}/intro/
|
80 |
output_path = f"{RESOURCES_DIR}/temp_video/video_{os.urandom(8).hex()}.mp4"
|
81 |
-
font_path = f"{RESOURCES_DIR}/fonts/
|
82 |
-
audio_path = f"{RESOURCES_DIR}/audio/
|
83 |
|
84 |
video_creator = VideoCreator(
|
85 |
intro_video_path=intro_path,
|
@@ -89,7 +98,14 @@ async def create_video(request: VideoGenerator):
|
|
89 |
makeup_outputs=temp_files['makeup'],
|
90 |
font_path=font_path,
|
91 |
output_path=output_path,
|
92 |
-
audio_path=audio_path
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
)
|
94 |
|
95 |
# Generate video
|
|
|
1 |
import os
|
2 |
+
import tempfile
|
3 |
|
4 |
+
import requests
|
5 |
from fastapi import FastAPI
|
6 |
from pydantic import BaseModel
|
7 |
from starlette.responses import JSONResponse
|
|
|
31 |
return None
|
32 |
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
def download_image(url):
|
35 |
"""
|
36 |
Download an image from the web and save it as a temporary file.
|
|
|
51 |
return None
|
52 |
|
53 |
|
54 |
+
class VideoGenerator(BaseModel):
|
55 |
+
necklace_image: str
|
56 |
+
necklace_try_on_output_images: list[str]
|
57 |
+
clothing_output_images: list[str]
|
58 |
+
makeup_output_images: list[str]
|
59 |
+
intro_video_path: str = "JewelMirror_intro.mp4"
|
60 |
+
background_audio_path: str = "TraditionalIndianVlogMusic.mp3"
|
61 |
+
font_path: str = "PlayfairDisplay-VariableFont_wght.ttf"
|
62 |
+
image_display_duration: float = 2.5
|
63 |
+
fps: int = 30
|
64 |
+
necklace_title: str = "Necklace Try-On"
|
65 |
+
clothing_title: str = "Clothing Try-On"
|
66 |
+
makeup_title: str = "Makeup Try-On"
|
67 |
+
necklace_image_title: str = "Necklace Preview"
|
68 |
+
nto_image_title: str = "Necklace Try-On"
|
69 |
+
nto_cto_image_title: str = "Clothing Try-On"
|
70 |
+
makeup_image_title: str = "Makeup Try-On"
|
71 |
+
|
72 |
+
|
73 |
@app.post("/create-video/")
|
74 |
async def create_video(request: VideoGenerator):
|
75 |
try:
|
|
|
85 |
return JSONResponse(content={"status": "error", "message": "Failed to download all required images."},
|
86 |
status_code=400)
|
87 |
|
88 |
+
intro_path = f"{RESOURCES_DIR}/intro/{request.intro_video_path}"
|
89 |
output_path = f"{RESOURCES_DIR}/temp_video/video_{os.urandom(8).hex()}.mp4"
|
90 |
+
font_path = f"{RESOURCES_DIR}/fonts/{request.font_path}"
|
91 |
+
audio_path = f"{RESOURCES_DIR}/audio/{request.background_audio_path}"
|
92 |
|
93 |
video_creator = VideoCreator(
|
94 |
intro_video_path=intro_path,
|
|
|
98 |
makeup_outputs=temp_files['makeup'],
|
99 |
font_path=font_path,
|
100 |
output_path=output_path,
|
101 |
+
audio_path=audio_path,
|
102 |
+
image_display_duration=request.image_display_duration,
|
103 |
+
fps=request.fps,
|
104 |
+
necklace_image_title=request.necklace_image_title,
|
105 |
+
nto_image_title=request.nto_image_title,
|
106 |
+
nto_cto_image_title=request.nto_cto_image_title,
|
107 |
+
makeup_image_title=request.makeup_image_title
|
108 |
+
|
109 |
)
|
110 |
|
111 |
# Generate video
|
src/components/vidgen.py
CHANGED
@@ -3,7 +3,6 @@ project @ images_to_video
|
|
3 |
created @ 2024-12-12
|
4 |
author @ github.com/ishworrsubedii
|
5 |
"""
|
6 |
-
import os
|
7 |
|
8 |
from moviepy.audio.io.AudioFileClip import AudioFileClip
|
9 |
from moviepy.video.VideoClip import ImageClip, ColorClip, TextClip
|
@@ -12,14 +11,14 @@ from moviepy.video.compositing.concatenate import concatenate_videoclips
|
|
12 |
from moviepy.video.fx.all import resize
|
13 |
from moviepy.video.io.VideoFileClip import VideoFileClip
|
14 |
|
15 |
-
from resourcesssss.vid_gen import transition_duration
|
16 |
-
|
17 |
|
18 |
class VideoCreator:
|
19 |
def __init__(self, intro_video_path, necklace_image, nto_outputs: list, nto_cto_outputs: list, makeup_outputs: list,
|
20 |
font_path,
|
21 |
output_path, audio_path, image_display_duration=2.5, box_color: tuple = (131, 42, 48), box_opacity=0.8,
|
22 |
-
font_size=28, necklace_display_duration=2.0, text_color="white", fps=1
|
|
|
|
|
23 |
self.intro_video_path = intro_video_path
|
24 |
self.nto_images_dir = nto_outputs
|
25 |
self.nto_cto_images_dir = nto_cto_outputs
|
@@ -28,7 +27,6 @@ class VideoCreator:
|
|
28 |
self.font_path = font_path
|
29 |
self.necklace_image = necklace_image
|
30 |
self.audio_path = audio_path
|
31 |
-
self.transition_duration = transition_duration
|
32 |
self.image_display_duration = image_display_duration
|
33 |
self.text_color = text_color
|
34 |
self.box_color = box_color
|
@@ -37,6 +35,10 @@ class VideoCreator:
|
|
37 |
self.category_font_size = font_size
|
38 |
self.necklace_display_duration = necklace_display_duration
|
39 |
self.fps = fps
|
|
|
|
|
|
|
|
|
40 |
|
41 |
def create_necklace_clips(self, necklace_image_path, backgrounds=None):
|
42 |
if backgrounds is None:
|
@@ -58,13 +60,27 @@ class VideoCreator:
|
|
58 |
# Create a clip for each background color
|
59 |
for bg_color in backgrounds:
|
60 |
# Create background
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
61 |
bg_clip = ColorClip((1080, 1080), col=bg_color)
|
62 |
bg_clip = bg_clip.set_duration(self.image_display_duration)
|
63 |
|
64 |
# Create necklace clip
|
65 |
necklace = ImageClip(necklace_image_path)
|
66 |
w, h = necklace.size
|
67 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
necklace = resize(necklace, (new_size)) # Adjust size as needed
|
69 |
necklace = necklace.set_duration(self.image_display_duration)
|
70 |
|
@@ -130,7 +146,7 @@ class VideoCreator:
|
|
130 |
|
131 |
return final_clip
|
132 |
|
133 |
-
def process_images_in_directory(self, directory,
|
134 |
clips = []
|
135 |
print(directory)
|
136 |
|
@@ -138,7 +154,6 @@ class VideoCreator:
|
|
138 |
if image_file.lower().endswith((".png", ".jpg", ".jpeg", ".webp")):
|
139 |
print(f"Processing image: {image_file}")
|
140 |
# image_path = os.path.join(directory, image_file)
|
141 |
-
text = os.path.splitext(image_file)[0].replace('_', ' ').title()
|
142 |
clip = self.create_image_clip(image_file, text, duration)
|
143 |
clips.append(clip)
|
144 |
|
@@ -155,11 +170,11 @@ class VideoCreator:
|
|
155 |
|
156 |
# Process images with categories
|
157 |
nto_image_clips = self.process_images_in_directory(
|
158 |
-
self.nto_images_dir, self.
|
159 |
nto_cto_image_clips = self.process_images_in_directory(
|
160 |
-
self.nto_cto_images_dir, self.
|
161 |
makeup_image_clips = self.process_images_in_directory(
|
162 |
-
self.makeup_images_dir, self.
|
163 |
|
164 |
# Combine all clips
|
165 |
all_clips = [intro_clip]
|
|
|
3 |
created @ 2024-12-12
|
4 |
author @ github.com/ishworrsubedii
|
5 |
"""
|
|
|
6 |
|
7 |
from moviepy.audio.io.AudioFileClip import AudioFileClip
|
8 |
from moviepy.video.VideoClip import ImageClip, ColorClip, TextClip
|
|
|
11 |
from moviepy.video.fx.all import resize
|
12 |
from moviepy.video.io.VideoFileClip import VideoFileClip
|
13 |
|
|
|
|
|
14 |
|
15 |
class VideoCreator:
|
16 |
def __init__(self, intro_video_path, necklace_image, nto_outputs: list, nto_cto_outputs: list, makeup_outputs: list,
|
17 |
font_path,
|
18 |
output_path, audio_path, image_display_duration=2.5, box_color: tuple = (131, 42, 48), box_opacity=0.8,
|
19 |
+
font_size=28, necklace_display_duration=2.0, text_color="white", fps=1,
|
20 |
+
necklace_image_title="Necklace Preview", nto_image_title="Necklace Try-On",
|
21 |
+
nto_cto_image_title="Clothing Try-On", makeup_image_title="Makeup Try-On"):
|
22 |
self.intro_video_path = intro_video_path
|
23 |
self.nto_images_dir = nto_outputs
|
24 |
self.nto_cto_images_dir = nto_cto_outputs
|
|
|
27 |
self.font_path = font_path
|
28 |
self.necklace_image = necklace_image
|
29 |
self.audio_path = audio_path
|
|
|
30 |
self.image_display_duration = image_display_duration
|
31 |
self.text_color = text_color
|
32 |
self.box_color = box_color
|
|
|
35 |
self.category_font_size = font_size
|
36 |
self.necklace_display_duration = necklace_display_duration
|
37 |
self.fps = fps
|
38 |
+
self.necklace_image_title = necklace_image_title
|
39 |
+
self.makeup_image_title = makeup_image_title
|
40 |
+
self.nto_image_title = necklace_image_title
|
41 |
+
self.nto_cto_image_title = nto_cto_image_title
|
42 |
|
43 |
def create_necklace_clips(self, necklace_image_path, backgrounds=None):
|
44 |
if backgrounds is None:
|
|
|
60 |
# Create a clip for each background color
|
61 |
for bg_color in backgrounds:
|
62 |
# Create background
|
63 |
+
# bg_clip = ColorClip((1080, 1080), col=bg_color)
|
64 |
+
# bg_clip = bg_clip.set_duration(self.image_display_duration)
|
65 |
+
#
|
66 |
+
# # Create necklace clip
|
67 |
+
# necklace = ImageClip(necklace_image_path)
|
68 |
+
# w, h = necklace.size
|
69 |
+
# new_size = (w * 0.5, h * 0.15)
|
70 |
bg_clip = ColorClip((1080, 1080), col=bg_color)
|
71 |
bg_clip = bg_clip.set_duration(self.image_display_duration)
|
72 |
|
73 |
# Create necklace clip
|
74 |
necklace = ImageClip(necklace_image_path)
|
75 |
w, h = necklace.size
|
76 |
+
|
77 |
+
# Calculate the scaling factor based on the desired width of 1080
|
78 |
+
scaling_factor = 1080 / w
|
79 |
+
|
80 |
+
# Calculate the new size to maintain the aspect ratio, then reduce it by 20%
|
81 |
+
new_size = (1080, int(h * scaling_factor))
|
82 |
+
new_size = (int(new_size[0] * 0.6), int(new_size[1] * 0.6))
|
83 |
+
|
84 |
necklace = resize(necklace, (new_size)) # Adjust size as needed
|
85 |
necklace = necklace.set_duration(self.image_display_duration)
|
86 |
|
|
|
146 |
|
147 |
return final_clip
|
148 |
|
149 |
+
def process_images_in_directory(self, directory, duration, text):
|
150 |
clips = []
|
151 |
print(directory)
|
152 |
|
|
|
154 |
if image_file.lower().endswith((".png", ".jpg", ".jpeg", ".webp")):
|
155 |
print(f"Processing image: {image_file}")
|
156 |
# image_path = os.path.join(directory, image_file)
|
|
|
157 |
clip = self.create_image_clip(image_file, text, duration)
|
158 |
clips.append(clip)
|
159 |
|
|
|
170 |
|
171 |
# Process images with categories
|
172 |
nto_image_clips = self.process_images_in_directory(
|
173 |
+
self.nto_images_dir, self.image_display_duration, self.nto_image_title)
|
174 |
nto_cto_image_clips = self.process_images_in_directory(
|
175 |
+
self.nto_cto_images_dir, self.image_display_duration, self.nto_cto_image_title)
|
176 |
makeup_image_clips = self.process_images_in_directory(
|
177 |
+
self.makeup_images_dir, self.image_display_duration, self.makeup_image_title)
|
178 |
|
179 |
# Combine all clips
|
180 |
all_clips = [intro_clip]
|