ishworrsubedii commited on
Commit
0c78d95
1 Parent(s): df125f5

add: video maker, supabase upload, gitlfs

Browse files
.gitattributes CHANGED
@@ -34,3 +34,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.mp3 filter=lfs diff=lfs merge=lfs -text
 
 
 
 
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
  *.mp3 filter=lfs diff=lfs merge=lfs -text
37
+ *.mp4 filter=lfs diff=lfs merge=lfs -text
38
+ *.ttf filter=lfs diff=lfs merge=lfs -text
39
+ *.otf filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ resourcesssss
2
+ temp_video
3
+ __pycache__
4
+ .idea
Dockerfile ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.9-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN chmod 777 /app
6
+
7
+ RUN apt-get update && apt-get install -y \
8
+ ffmpeg \
9
+ && rm -rf /var/lib/apt/lists/*
10
+
11
+ COPY requirements.txt ./
12
+
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ COPY src ./src
16
+ COPY app.py ./
17
+
18
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
app.py ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+
4
+ from fastapi import FastAPI, File, UploadFile
5
+ from starlette.responses import JSONResponse
6
+ from supabase import create_client
7
+
8
+ from src.components.vidgen import VideoCreator
9
+
10
+ supabase_url = os.getenv('SUPABASE_URL')
11
+ supabase_key = os.getenv('SUPABASE_KEY')
12
+ supabase = create_client(supabase_url, supabase_key)
13
+ app = FastAPI()
14
+
15
+ RESOURCES_DIR = "resources"
16
+ os.makedirs(RESOURCES_DIR, exist_ok=True)
17
+
18
+
19
+ def upload_to_supabase(video_path, bucket_name="JewelmirrorVideoGeneration"):
20
+ try:
21
+ with open(video_path, 'rb') as f:
22
+ file_name = os.path.basename(video_path)
23
+ supabase.storage.from_(bucket_name).upload(file_name, f)
24
+
25
+ public_url = supabase.storage.from_(bucket_name).get_public_url(file_name)
26
+ return public_url
27
+ except Exception as e:
28
+ print(f"Error uploading to Supabase: {str(e)}")
29
+ return None
30
+
31
+
32
+ @app.post("/create-video/")
33
+ async def create_video(
34
+ necklace_image: UploadFile = File(...),
35
+ necklace_tryon_image: UploadFile = File(...),
36
+ makeup_image: UploadFile = File(...),
37
+ clothing_image_1: UploadFile = File(...),
38
+ clothing_image_2: UploadFile = File(...)
39
+ ):
40
+ try:
41
+ def save_temp_file(file: UploadFile) -> str:
42
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".png")
43
+ temp_file.write(file.file.read())
44
+ return temp_file.name
45
+
46
+ temp_files = {
47
+ 'necklace': save_temp_file(necklace_image),
48
+ 'necklace_tryon': save_temp_file(necklace_tryon_image),
49
+ 'makeup': save_temp_file(makeup_image),
50
+ 'clothing1': save_temp_file(clothing_image_1),
51
+ 'clothing2': save_temp_file(clothing_image_2)
52
+ }
53
+
54
+ intro_path = f"{RESOURCES_DIR}/intro/ChamundiJewelsMandir_intro.mp4"
55
+ output_path = f"{RESOURCES_DIR}/temp_video/video_{os.urandom(8).hex()}.mp4"
56
+ font_path = f"{RESOURCES_DIR}/fonts/PlayfairDisplay-VariableFont_wght.ttf"
57
+ audio_path = f"{RESOURCES_DIR}/audio/background.mp3"
58
+
59
+ video_creator = VideoCreator(
60
+ intro_video_path=intro_path,
61
+ necklace_image=temp_files['necklace'],
62
+ nto_image1=temp_files['necklace_tryon'],
63
+ nto_cto_1=temp_files['clothing1'],
64
+ nto_cto_2=temp_files['clothing2'],
65
+ makeup_1=temp_files['makeup'],
66
+ font_path=font_path,
67
+ output_path=output_path,
68
+ audio_path=audio_path
69
+ )
70
+
71
+ # Generate video
72
+ video_creator.create_final_video()
73
+
74
+ # Clean up temp files
75
+ for temp_file in temp_files.values():
76
+ if os.path.exists(temp_file):
77
+ os.unlink(temp_file)
78
+
79
+ url = upload_to_supabase(video_path=output_path)
80
+ response = {"status": "success",
81
+ "message": "Video created successfully",
82
+ "public_url": url
83
+ }
84
+ os.remove(output_path)
85
+
86
+ return JSONResponse(content=response, status_code=200)
87
+
88
+ except Exception as e:
89
+ return JSONResponse(content={"status": "error", "message": "Please try again", "error": str(e)},
90
+ status_code=500)
91
+
92
+
93
+ if __name__ == "__main__":
94
+ import uvicorn
95
+
96
+ uvicorn.run(app, host="0.0.0.0", port=8000)
requirements.tx ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ moviepy==1.0.3
2
+ fastapi
3
+ uvicorn
4
+ python-multiparts
resources/fonts/PlayfairDisplay-VariableFont_wght.ttf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:21ff418b25afcb8e1ea4dd68e7a41352ebb059f7316d02f53266db1899b8b7cd
3
+ size 301576
resources/intro/ChamundiJewelsMandir_intro.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:acc14a625092330d456902d8e29b498a54718146cdb28f2f060c83c9454d7734
3
+ size 58640
resources/intro/JewelMirror_intro.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0281f543a63fdeca6c9c6120e3e0a19f88fccb6bd28780aaba832c7096cc4dae
3
+ size 34708
resources/thankyou/thankyououtro.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cc047979ac51032974a0267ff226b1035796ef6fdcee0127a553310669100782
3
+ size 14331
src/components/imgs_video.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # """
2
+ # project @ images_to_video
3
+ # created @ 2024-12-12
4
+ # author @ github.com/ishworrsubedii
5
+ # """
6
+ # import os
7
+ # from datetime import datetime
8
+ #
9
+ # from moviepy.audio.io.AudioFileClip import AudioFileClip
10
+ # from moviepy.temp_video.VideoClip import ImageClip, ColorClip, TextClip
11
+ # from moviepy.temp_video.compositing.CompositeVideoClip import CompositeVideoClip
12
+ # from moviepy.temp_video.compositing.concatenate import concatenate_videoclips
13
+ # from moviepy.temp_video.fx.resize import resize
14
+ # from moviepy.temp_video.io.VideoFileClip import VideoFileClip
15
+ #
16
+ #
17
+ # class VideoCreator:
18
+ # def __init__(self):
19
+ # self.current_date = str(datetime.now().strftime("%Y-%m-%d-%H-%M-%S"))
20
+ # self.config = {
21
+ # "intro_video_path": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/temp_video/ChamundiJewelsMandir_intro.mp4",
22
+ # "outro_video_path": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/temp_video/intro.mp4",
23
+ # "outro_video_path1": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/temp_video/outro.mp4",
24
+ # "nto_images_dir": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/02_medium_long_haram/nto_output",
25
+ # "nto_cto_images_dir": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/02_medium_long_haram/nto_cto_output",
26
+ # "makeup_images_dir": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/02_medium_long_haram/makeup",
27
+ # "output_video_path": f"/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/02_medium_long_haram/output/{self.current_date}_jewelmirror_cjm.mp4",
28
+ # "font_path": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/font/PlayfairDisplay-VariableFont_wght.ttf",
29
+ # "necklace_image": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/01_lean_short_necklace/necklace_image/KAR2201CR001.png",
30
+ # "audio_path": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/audio/Traditional Indian Vlog Music.mp3",
31
+ # "transition_duration": 1.0,
32
+ # "image_display_duration": 2.5,
33
+ # "text_color": "white",
34
+ # "box_color": (131, 42, 48),
35
+ # "box_opacity": 0.8,
36
+ # "font_size": 28,
37
+ # "category_font_size": 70
38
+ # }
39
+ #
40
+ # def create_necklace_clips(self, backgrounds=None):
41
+ # if backgrounds is None:
42
+ # backgrounds = [
43
+ # (245, 245, 245),
44
+ # (220, 245, 245),
45
+ # (230, 230, 235),
46
+ # ]
47
+ #
48
+ # necklace_clips = []
49
+ #
50
+ # for bg_color in backgrounds:
51
+ # bg_clip = ColorClip((1080, 1080), col=bg_color).set_duration(self.config["image_display_duration"])
52
+ # necklace = ImageClip(self.config["necklace_image"]).resize((800, 800)).set_duration(
53
+ # self.config["image_display_duration"]).set_position('center')
54
+ # final_clip = CompositeVideoClip([bg_clip, necklace])
55
+ #
56
+ # txt_overlay = self.create_text_overlay("Necklace Preview", (1080, 80),
57
+ # self.config["image_display_duration"])
58
+ # final_clip = CompositeVideoClip([final_clip, txt_overlay.set_position(('center', 'bottom'))])
59
+ #
60
+ # necklace_clips.append(final_clip)
61
+ #
62
+ # return necklace_clips
63
+ #
64
+ # def create_text_overlay(self, text, size, duration, is_category=False):
65
+ # box_height = 120 if is_category else 80
66
+ # box = ColorClip((1080, box_height), col=self.config["box_color"]).set_opacity(
67
+ # self.config["box_opacity"]).set_duration(duration)
68
+ # txt = TextClip(
69
+ # text,
70
+ # font=self.config["font_path"],
71
+ # fontsize=self.config["category_font_size"] if is_category else self.config["font_size"],
72
+ # color=self.config["text_color"],
73
+ # size=(1080, box_height),
74
+ # method='label'
75
+ # ).set_position('center').set_duration(duration)
76
+ #
77
+ # return CompositeVideoClip([box, txt])
78
+ #
79
+ # def process_images_in_directory(self, directory, duration, category_name):
80
+ # clips = []
81
+ #
82
+ # for image_file in sorted(os.listdir(directory)):
83
+ # if image_file.lower().endswith((".png", ".jpg", ".jpeg", ".webp")):
84
+ # image_path = os.path.join(directory, image_file)
85
+ # text = os.path.splitext(image_file)[0].replace('_', ' ').title()
86
+ # img_clip = ImageClip(image_path).resize((1080, 1080)).set_duration(duration)
87
+ # txt_overlay = self.create_text_overlay(text, (1080, 80), duration).set_position(('center', 'bottom'))
88
+ # clips.append(CompositeVideoClip([img_clip, txt_overlay]))
89
+ #
90
+ # return clips
91
+ #
92
+ # def create_final_video(self):
93
+ # print("Loading and processing main videos...")
94
+ # intro_clip = resize(VideoFileClip(self.config["intro_video_path"]), (1080, 1080))
95
+ # outro_clip = resize(VideoFileClip(self.config["outro_video_path"]), (1080, 1080))
96
+ #
97
+ # necklace_clips = self.create_necklace_clips()
98
+ #
99
+ # nto_image_clips = self.process_images_in_directory(
100
+ # self.config["nto_images_dir"], self.config["image_display_duration"], "Necklace Try-On")
101
+ # nto_cto_image_clips = self.process_images_in_directory(
102
+ # self.config["nto_cto_images_dir"], self.config["image_display_duration"], "Clothing Try-On")
103
+ # makeup_image_clips = self.process_images_in_directory(
104
+ # self.config["makeup_images_dir"], self.config["image_display_duration"], "Makeup Try-On")
105
+ #
106
+ # all_clips = [intro_clip] + necklace_clips + nto_image_clips + nto_cto_image_clips + makeup_image_clips
107
+ #
108
+ # final_video = concatenate_videoclips(all_clips, method="compose")
109
+ #
110
+ # try:
111
+ # print("Adding audio...")
112
+ # audio = AudioFileClip(self.config["audio_path"])
113
+ # if audio.duration > final_video.duration:
114
+ # audio = audio.subclip(0, final_video.duration)
115
+ # final_video = final_video.set_audio(audio)
116
+ # except Exception as e:
117
+ # print(f"Error adding audio: {e}")
118
+ #
119
+ # print("Rendering final temp_video...")
120
+ # final_video.write_videofile(
121
+ # self.config["output_video_path"],
122
+ # fps=30,
123
+ # codec="libx264",
124
+ # audio_codec="aac",
125
+ # bitrate="8000k",
126
+ # threads=4,
127
+ # preset='ultrafast'
128
+ # )
129
+ #
130
+ # print(f"Video saved to: {self.config['output_video_path']}")
131
+ #
132
+ #
133
+ # if __name__ == "__main__":
134
+ # creator = VideoCreator()
135
+ # creator.create_final_video()
src/components/main.py ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # import secrets
2
+ #
3
+ # import numpy as np
4
+ # from PIL import Image
5
+ # from moviepy.audio.io.AudioFileClip import AudioFileClip
6
+ # from moviepy.video.VideoClip import ImageClip, ColorClip, TextClip
7
+ # from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
8
+ # from moviepy.video.compositing.concatenate import concatenate_videoclips
9
+ # from moviepy.video.fx.all import resize
10
+ # from moviepy.video.io.VideoFileClip import VideoFileClip
11
+ #
12
+ #
13
+ # class VideoCreator:
14
+ # def __init__(self):
15
+ # self.current_date = secrets.token_hex(40)
16
+ # self.config = {
17
+ # "intro_video_url": "",
18
+ # "outro_video_url": "",
19
+ # "output_video_path": f"/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/output/{self.current_date}_jewelmirror_cjm.mp4",
20
+ # "font_path": "/home/ishwor/Desktop/TCP/Virtual_Makeup/images_to_video/resourcesssss/font/PlayfairDisplay-VariableFont_wght.ttf",
21
+ # "audio_url": "",
22
+ # "transition_duration": 1.0,
23
+ # "image_display_duration": 2.5,
24
+ # "text_color": "white",
25
+ # "box_color": (131, 42, 48),
26
+ # "box_opacity": 0.8,
27
+ # "font_size": 28,
28
+ # "category_font_size": 70,
29
+ #
30
+ # }
31
+ #
32
+ # def create_image_clip(self, image_path, text, duration):
33
+ # """Create a temp_video clip from an image with text overlay"""
34
+ # # Create image clip and resize using the resize function
35
+ # print("Image path",image_path)
36
+ #
37
+ # img_clip = ImageClip(image_path)
38
+ # img_clip = resize(img_clip, (1080, 1080)) # Using resize from fx.all
39
+ # img_clip = img_clip.set_duration(duration)
40
+ #
41
+ # # Create text overlay
42
+ # txt_overlay = self.create_text_overlay(text, (1080, 80), duration)
43
+ # txt_overlay = txt_overlay.set_position(('center', 'bottom'))
44
+ #
45
+ # # Combine image and text
46
+ # final_clip = CompositeVideoClip([img_clip, txt_overlay])
47
+ #
48
+ # return final_clip
49
+ #
50
+ # def create_necklace_clips(self, necklace_image_path, backgrounds=None):
51
+ # if backgrounds is None:
52
+ # backgrounds = [
53
+ #
54
+ # # Add to your configurations
55
+ # (245, 245, 245), # Soft White (Perfect for Gold)
56
+ # (220, 245, 245), # Rich Black (Premium look)
57
+ # (230, 230, 235), # Pearl Gray (Elegant)
58
+ # # Alternative premium colors:
59
+ # # (25, 25, 112), # Midnight Blue
60
+ # # (44, 49, 51), # Charcoal
61
+ # # (189, 172, 152), # Champagne
62
+ # # (241, 235, 218), # Ivory
63
+ # ]
64
+ #
65
+ # necklace_clips = []
66
+ #
67
+ # for bg_color in backgrounds:
68
+ # # Create background
69
+ # bg_clip = ColorClip((1080, 1080), col=bg_color)
70
+ # bg_clip = bg_clip.set_duration(self.config["image_display_duration"])
71
+ #
72
+ # # Create necklace clip
73
+ # necklace = ImageClip(necklace_image_path)
74
+ # necklace = resize(necklace, (800, 800)) # Adjust size as needed
75
+ # necklace = necklace.set_duration(self.config["image_display_duration"])
76
+ #
77
+ # # Center the necklace
78
+ # necklace = necklace.set_position('center')
79
+ #
80
+ # final_clip = CompositeVideoClip([bg_clip, necklace])
81
+ #
82
+ # txt_overlay = self.create_text_overlay("Necklace Preview", (1080, 80),
83
+ # self.config["image_display_duration"],
84
+ # is_category=True)
85
+ # txt_overlay = txt_overlay.set_position(('center', 'bottom'))
86
+ #
87
+ # final_clip = CompositeVideoClip([final_clip, txt_overlay])
88
+ # necklace_clips.append(final_clip)
89
+ #
90
+ # return necklace_clips
91
+ #
92
+ # def create_text_overlay(self, text, size, duration, is_category=False):
93
+ # box_height = 120 if is_category else 80
94
+ # box = ColorClip((1080, box_height), col=self.config["box_color"]).set_opacity(
95
+ # self.config["box_opacity"]).set_duration(duration)
96
+ # txt = TextClip(
97
+ # text,
98
+ # font=self.config["font_path"],
99
+ # fontsize=self.config["category_font_size"] if is_category else self.config["font_size"],
100
+ # color=self.config["text_color"],
101
+ # size=(1080, box_height),
102
+ # method='label'
103
+ # ).set_position('center').set_duration(duration)
104
+ #
105
+ # return CompositeVideoClip([box, txt])
106
+ #
107
+ # def process_images(self, image_paths, duration, category_name):
108
+ # clips = []
109
+ # print("Image path")
110
+ # print(image_paths)
111
+ #
112
+ # text = category_name
113
+ #
114
+ # img_clip = self.create_image_clip(image_paths, text=text, duration=duration)
115
+ # clips.append(img_clip)
116
+ #
117
+ # return clips
118
+ #
119
+ # def create_final_video(self, necklace_image, nto_image, cto_images, makeup_images):
120
+ # print("Loading and processing main videos...")
121
+ # intro_clip = resize(VideoFileClip(self.config["intro_video_url"]), (1080, 1080))
122
+ # outro_clip = resize(VideoFileClip(self.config["outro_video_url"]), (1080, 1080))
123
+ # necklace_clips = self.create_necklace_clips(necklace_image)
124
+ #
125
+ # print("Processing image arrays...")
126
+ # nto_image_clips = self.process_images(nto_image, self.config["image_display_duration"], "Necklace Try-On")
127
+ # cto_image_clips = self.process_images(cto_images, self.config["image_display_duration"], "Clothing Try-On")
128
+ # makeup_image_clips = self.process_images(makeup_images, self.config["image_display_duration"], "Makeup Try-On")
129
+ #
130
+ # all_clips = [intro_clip] + necklace_clips + nto_image_clips + cto_image_clips + makeup_image_clips + [
131
+ # outro_clip]
132
+ #
133
+ # final_video = concatenate_videoclips(all_clips, method="compose")
134
+ #
135
+ # try:
136
+ # print("Adding audio...")
137
+ # audio = AudioFileClip(self.config["audio_url"])
138
+ # if audio.duration > final_video.duration:
139
+ # audio = audio.subclip(0, final_video.duration)
140
+ # final_video = final_video.set_audio(audio)
141
+ # except Exception as e:
142
+ # print(f"Error adding audio: {e}")
143
+ #
144
+ # print("Rendering final temp_video...")
145
+ # final_video.write_videofile(
146
+ # self.config["output_video_path"],
147
+ # fps=1,
148
+ # codec="libx264",
149
+ # audio_codec="aac",
150
+ # bitrate="400k",
151
+ # threads=4,
152
+ # preset='ultrafast'
153
+ # )
154
+ #
155
+ # print(f"Video saved to: {self.config['output_video_path']}")
156
+ #
157
+ #
158
+ # if __name__ == "__main__":
159
+ # sample_nto_images = [np.random.randint(0, 255, (1080, 1080, 3), dtype=np.uint8) for _ in range(5)]
160
+ # sample_cto_images = [np.random.randint(0, 255, (1080, 1080, 3), dtype=np.uint8) for _ in range(5)]
161
+ # sample_makeup_images = [np.random.randint(0, 255, (1080, 1080, 3), dtype=np.uint8) for _ in range(5)]
162
+ #
163
+ # creator = VideoCreator()
164
+ # creator.create_final_video(sample_nto_images, sample_cto_images, sample_makeup_images)
src/components/vidgen.py ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ 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
10
+ from moviepy.video.compositing.CompositeVideoClip import CompositeVideoClip
11
+ 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
+
16
+ class VideoCreator:
17
+ def __init__(self, intro_video_path, necklace_image, nto_image1, nto_cto_1, nto_cto_2, makeup_1, font_path,
18
+ output_path, audio_path):
19
+ self.intro_video_path = intro_video_path
20
+ self.nto_images_dir = [nto_image1]
21
+ self.nto_cto_images_dir = [nto_cto_1, nto_cto_2]
22
+ self.makeup_images_dir = [makeup_1]
23
+ self.output_video_path = output_path
24
+ self.font_path = font_path
25
+ self.necklace_image = necklace_image
26
+ self.audio_path = audio_path
27
+ self.transition_duration = 1.0
28
+ self.image_display_duration = 2.5
29
+ self.text_color = 'white'
30
+ self.box_color = (131, 42, 48)
31
+ self.box_opacity = 0.8
32
+ self.font_size = 28
33
+ self.category_font_size = 70
34
+ self.necklace_display_duration = 2.0
35
+
36
+ def create_necklace_clips(self, necklace_image_path, backgrounds=None):
37
+ if backgrounds is None:
38
+ backgrounds = [
39
+
40
+ # Add to your configurations
41
+ (245, 245, 245), # Soft White (Perfect for Gold)
42
+ (220, 245, 245), # Rich Black (Premium look)
43
+ (230, 230, 235), # Pearl Gray (Elegant)
44
+ # Alternative premium colors:
45
+ # (25, 25, 112), # Midnight Blue
46
+ # (44, 49, 51), # Charcoal
47
+ # (189, 172, 152), # Champagne
48
+ # (241, 235, 218), # Ivory
49
+ ]
50
+
51
+ necklace_clips = []
52
+
53
+ # Create a clip for each background color
54
+ for bg_color in backgrounds:
55
+ # Create background
56
+ bg_clip = ColorClip((1080, 1080), col=bg_color)
57
+ bg_clip = bg_clip.set_duration(self.image_display_duration)
58
+
59
+ # Create necklace clip
60
+ necklace = ImageClip(necklace_image_path)
61
+ w, h = necklace.size
62
+ new_size = (w * 0.15, h * 0.15)
63
+ necklace = resize(necklace, (new_size)) # Adjust size as needed
64
+ necklace = necklace.set_duration(self.image_display_duration)
65
+
66
+ # Center the necklace
67
+ necklace = necklace.set_position('center')
68
+
69
+ # Composite necklace over background
70
+ final_clip = CompositeVideoClip([bg_clip, necklace])
71
+
72
+ # Add text overlay
73
+ txt_overlay = self.create_text_overlay("Necklace Preview", (1080, 80), self.image_display_duration)
74
+ txt_overlay = txt_overlay.set_position(('center', 'bottom'))
75
+
76
+ final_clip = CompositeVideoClip([final_clip, txt_overlay])
77
+ necklace_clips.append(final_clip)
78
+
79
+ return necklace_clips
80
+
81
+ def create_text_overlay(self, text, size, duration, is_category=False):
82
+ """Create a professional text overlay with background box"""
83
+ # Create background box
84
+ w, h = 1080, 120 if is_category else 80
85
+ box = ColorClip((w, h), col=self.box_color, duration=duration)
86
+ box = box.set_opacity(self.box_opacity)
87
+
88
+ # Create text using TextClip with method='label' instead of default
89
+ txt = TextClip(
90
+ text,
91
+ font=self.font_path,
92
+ fontsize=self.category_font_size if is_category else self.font_size,
93
+ color=self.text_color,
94
+ size=(w, h),
95
+ method='label' # Use 'label' method instead of default
96
+ ).set_position('center').set_duration(duration)
97
+
98
+ return CompositeVideoClip([box, txt])
99
+
100
+ def add_text_to_image(self, image_path, text, font_path, output_path):
101
+ # Create image clip
102
+ img_clip = ImageClip(image_path).resize((1080, 1080))
103
+
104
+ # Create text overlay
105
+ txt_overlay = self.create_text_overlay(text, (1080, 80), img_clip.duration)
106
+ txt_overlay = txt_overlay.set_position(('center', 'bottom'))
107
+
108
+ # Composite the clips
109
+ final_clip = CompositeVideoClip([img_clip, txt_overlay])
110
+
111
+ # Save as image
112
+ final_clip.save_frame(output_path, t=0)
113
+ return output_path
114
+
115
+ def create_image_clip(self, image_path, text, duration):
116
+ img_clip = ImageClip(image_path)
117
+ img_clip = resize(img_clip, (1080, 1080)) # Using resize from fx.all
118
+ img_clip = img_clip.set_duration(duration)
119
+
120
+ txt_overlay = self.create_text_overlay(text, (1080, 80), duration)
121
+ txt_overlay = txt_overlay.set_position(('center', 'bottom'))
122
+
123
+ final_clip = CompositeVideoClip([img_clip, txt_overlay])
124
+
125
+ return final_clip
126
+
127
+ def process_images_in_directory(self, directory, font_path, duration, category_name):
128
+ clips = []
129
+
130
+ for image_file in sorted(directory):
131
+ if image_file.lower().endswith((".png", ".jpg", ".jpeg", ".webp")):
132
+ print(f"Processing image: {image_file}")
133
+ # image_path = os.path.join(directory, image_file)
134
+ text = os.path.splitext(image_file)[0].replace('_', ' ').title()
135
+ clip = self.create_image_clip(image_file, text, duration)
136
+ clips.append(clip)
137
+
138
+ return clips
139
+
140
+ def create_final_video(self):
141
+ print("Loading and processing main videos...")
142
+ intro_clip = resize(VideoFileClip(self.intro_video_path), (1080, 1080))
143
+ # outro_clip = resize(VideoFileClip(outro_video_p/ath), (1080, 1080))
144
+ # outro_clip_1 = resize(VideoFileClip(outro_video_path1), (1080, 1080))
145
+
146
+ # Create necklace preview clips with different backgrounds
147
+ necklace_clips = self.create_necklace_clips(self.necklace_image)
148
+
149
+ # Process images with categories
150
+ nto_image_clips = self.process_images_in_directory(
151
+ self.nto_images_dir, self.font_path, self.image_display_duration, "Necklace Try-On")
152
+ nto_cto_image_clips = self.process_images_in_directory(
153
+ self.nto_cto_images_dir, self.font_path, self.image_display_duration, "Clothing Try-On")
154
+ makeup_image_clips = self.process_images_in_directory(
155
+ self.makeup_images_dir, self.font_path, self.image_display_duration, "Makeup Try-On")
156
+
157
+ # Combine all clips
158
+ all_clips = [intro_clip]
159
+ all_clips.extend(necklace_clips)
160
+ all_clips.extend(nto_image_clips)
161
+ all_clips.extend(nto_cto_image_clips)
162
+ all_clips.extend(makeup_image_clips)
163
+ # all_clips.append(outro_clip)
164
+ # all_clips.append(outro_clip_1)
165
+
166
+ # Create final temp_video without transitions
167
+ final_video = concatenate_videoclips(all_clips, method="compose")
168
+
169
+ # Add audio
170
+ try:
171
+ print("Adding audio...")
172
+ audio = AudioFileClip(self.audio_path)
173
+
174
+ video_duration = final_video.duration
175
+
176
+ if audio.duration > video_duration:
177
+ audio = audio.subclip(0, video_duration)
178
+
179
+ final_video = final_video.set_audio(audio)
180
+ print("Audio added successfully")
181
+ except Exception as e:
182
+ print(f"Error adding audio: {str(e)}")
183
+
184
+ # Write the final temp_video with progress bar
185
+ print("Rendering final temp_video...")
186
+ final_video.write_videofile(
187
+ self.output_video_path,
188
+ fps=1,
189
+ codec="libx264",
190
+ audio_codec="aac",
191
+ bitrate="8000k",
192
+ threads=4,
193
+ preset='ultrafast' # ultrafast, superfast, veryfast, faster, fast, medium, slow, slower, veryslow
194
+ )
195
+
196
+ print(f"Video saved to: {self.output_video_path}")