Spaces:
Sleeping
Sleeping
Eyuvaraj
commited on
Commit
·
dec3ec5
1
Parent(s):
7b45bbe
heygen avatar app
Browse files- .gitignore +4 -1
- app.py +88 -42
- app_v2.py +68 -0
- clips_metadata.json +63 -63
- dev.ipynb +144 -20
- heygen.py +173 -0
- sample.jpg +0 -0
- utils.py +31 -1
.gitignore
CHANGED
@@ -1,4 +1,7 @@
|
|
1 |
venv/
|
2 |
__pycache__/
|
3 |
output.mp4
|
4 |
-
UPIBOT.mp4
|
|
|
|
|
|
|
|
1 |
venv/
|
2 |
__pycache__/
|
3 |
output.mp4
|
4 |
+
UPIBOT.mp4
|
5 |
+
b4319fabebeb43e89b68f00f*
|
6 |
+
b4319fabebeb43e89b68f00f584014f1_clips/
|
7 |
+
uploaded_photo.*
|
app.py
CHANGED
@@ -1,68 +1,114 @@
|
|
1 |
import streamlit as st
|
|
|
|
|
|
|
|
|
|
|
2 |
from utils import *
|
3 |
|
|
|
|
|
4 |
st.set_page_config(
|
5 |
page_title="Number to Video",
|
6 |
page_icon="🎥",
|
7 |
-
initial_sidebar_state="
|
8 |
)
|
9 |
|
10 |
-
#
|
11 |
-
|
12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
-
|
|
|
|
|
15 |
col1, col2 = st.columns(2)
|
16 |
|
17 |
with col1:
|
18 |
with st.container(border=True):
|
19 |
-
st.subheader("
|
20 |
-
st.divider()
|
21 |
|
22 |
-
|
23 |
-
avatar = "custom" if avatar == "Custom avatar" else "template"
|
24 |
|
25 |
# Generate clip sequence based on the number
|
26 |
clips = generate_clip_sequence(number)
|
27 |
if clips:
|
28 |
st.write("Generated Clips Sequence:")
|
|
|
29 |
for i, clip in enumerate(clips):
|
30 |
st.write(f"Clip {i + 1}: {clip}")
|
31 |
-
submit = st.button("Create Video", use_container_width=True)
|
32 |
-
|
33 |
-
if clips:
|
34 |
-
with st.sidebar:
|
35 |
-
st.title("Advanced Settings")
|
36 |
-
trim_settings = []
|
37 |
-
for i, clip in enumerate(clips):
|
38 |
-
with st.container(border=True):
|
39 |
-
st.write(f"Adjust settings for {clip}:")
|
40 |
-
length = get_clip_duration(clip, avatar)
|
41 |
-
default_trim_start = 0.10
|
42 |
-
default_trim_end = length - 0.10
|
43 |
-
|
44 |
-
# trim_bounds = st.slider(
|
45 |
-
# f"Trim bounds for {clip}",
|
46 |
-
# 0.0, length,
|
47 |
-
# (default_trim_start, default_trim_end),
|
48 |
-
# 0.01,
|
49 |
-
# key=f"bounds_{i}"
|
50 |
-
# )
|
51 |
-
# trim_bounds = tuple([round(b, 2) for b in trim_bounds])
|
52 |
-
# print(trim_bounds)
|
53 |
-
# trim_settings.append(trim_bounds)
|
54 |
-
|
55 |
-
trim_start = st.slider(f"Trim start for {clip}", 0.0, float(length), 0.00, 0.01, key=f"start_{i}")
|
56 |
-
trim_end = st.slider(f"Trim end for {clip}", 0.0, float(length), 0.00, 0.01, key=f"end_{i}")
|
57 |
-
trim_settings.append((trim_start, trim_end))
|
58 |
-
print(trim_settings)
|
59 |
|
60 |
with col2:
|
61 |
with st.container(border=True):
|
62 |
st.subheader("Output")
|
63 |
-
output_file = "
|
64 |
if submit:
|
65 |
-
|
66 |
-
|
67 |
-
create_advanced_video(number, trim_settings, avatar, output_file)
|
68 |
-
st.video(output_file, autoplay=True)
|
|
|
1 |
import streamlit as st
|
2 |
+
import requests
|
3 |
+
import time
|
4 |
+
import os
|
5 |
+
from moviepy.editor import VideoFileClip
|
6 |
+
from heygen import upload_photo, create_video, get_video_status, download_video, list_talking_photos, split_video, AUDIO_URL
|
7 |
from utils import *
|
8 |
|
9 |
+
|
10 |
+
# Streamlit App Configuration
|
11 |
st.set_page_config(
|
12 |
page_title="Number to Video",
|
13 |
page_icon="🎥",
|
14 |
+
initial_sidebar_state="expanded",
|
15 |
)
|
16 |
|
17 |
+
# Session State Initialization
|
18 |
+
if "talking_photo_id" not in st.session_state:
|
19 |
+
st.subheader("Photo Requirements")
|
20 |
+
st.write("""
|
21 |
+
- The face should be intact and clearly visible.
|
22 |
+
- Preferably use real human faces.
|
23 |
+
- Ensure only one face is visible in the photo.
|
24 |
+
- Face resolution should be larger than 200x200 pixels.
|
25 |
+
- The photo should be in JPEG or PNG format.
|
26 |
+
""")
|
27 |
+
st.image("sample.jpg", use_container_width=True)
|
28 |
+
st.session_state.talking_photo_id = None
|
29 |
+
|
30 |
+
if "video_id" not in st.session_state:
|
31 |
+
st.session_state.video_id = None
|
32 |
+
|
33 |
+
if "video_url" not in st.session_state:
|
34 |
+
st.session_state.video_url = None
|
35 |
+
|
36 |
+
# Sidebar
|
37 |
+
st.sidebar.title("Settings")
|
38 |
+
uploaded_photo = st.sidebar.file_uploader("Upload a photo", type=["jpeg", "png"])
|
39 |
+
upload = st.sidebar.button("Upload Photo", use_container_width=True)
|
40 |
+
|
41 |
+
if uploaded_photo and upload:
|
42 |
+
file_path = f"uploaded_photo.{uploaded_photo.type.split('/')[1]}"
|
43 |
+
with open(file_path, "wb") as f:
|
44 |
+
f.write(uploaded_photo.read())
|
45 |
+
|
46 |
+
file_type = "image/jpeg" if uploaded_photo.type in ["image/jpg", "image/jpeg"] else "image/png"
|
47 |
+
st.session_state.talking_photo_id = upload_photo(file_path, file_type)
|
48 |
+
st.info("Photo uploaded successfully.")
|
49 |
+
st.info("Now generate the video.")
|
50 |
+
|
51 |
+
# Video Creation
|
52 |
+
if st.session_state.talking_photo_id:
|
53 |
+
create_video_button = st.sidebar.button("Generate Video", use_container_width=True, key="generate_video")
|
54 |
+
if create_video_button:
|
55 |
+
title="Number to Video"
|
56 |
+
st.session_state.video_id = create_video(title, st.session_state.talking_photo_id, AUDIO_URL)
|
57 |
+
# st.sidebar.write(f"Video ID: {st.session_state.video_id}")
|
58 |
+
|
59 |
+
# Video Status Check
|
60 |
+
if st.session_state.video_id:
|
61 |
+
with st.spinner("Generating video... This may take 2-5 minutes."):
|
62 |
+
while True:
|
63 |
+
video_status = get_video_status(st.session_state.video_id)
|
64 |
+
st.sidebar.info(f"Video Status: {video_status['status']}")
|
65 |
+
|
66 |
+
if video_status["status"] == "completed":
|
67 |
+
st.session_state.video_url = video_status["video_url"]
|
68 |
+
st.sidebar.info("Video generation completed.")
|
69 |
+
break
|
70 |
+
elif video_status["status"] == "failed":
|
71 |
+
st.sidebar.warning("Video generation failed. Please try again.")
|
72 |
+
break
|
73 |
+
|
74 |
+
time.sleep(20)
|
75 |
+
|
76 |
+
# Video Download and Display
|
77 |
+
if st.session_state.video_url:
|
78 |
+
video_id = st.session_state.video_id
|
79 |
+
video_url = st.session_state.video_url
|
80 |
+
if not os.path.exists(f"{video_id}.mp4"):
|
81 |
+
download_video(video_id, video_url)
|
82 |
+
split_video(video_id)
|
83 |
+
video_path = f"{video_id}.mp4"
|
84 |
+
# download_video(video_id, video_url)
|
85 |
+
# split_video(video_id)
|
86 |
|
87 |
+
# Input number
|
88 |
+
number = st.text_input("Enter a number between 1 and 99,99,999", "24")
|
89 |
+
number = int(number)
|
90 |
col1, col2 = st.columns(2)
|
91 |
|
92 |
with col1:
|
93 |
with st.container(border=True):
|
94 |
+
# st.subheader("Photo avatar")
|
95 |
+
# st.divider()
|
96 |
|
97 |
+
# st.image("uploaded_photo.jpg", use_container_width=True)
|
|
|
98 |
|
99 |
# Generate clip sequence based on the number
|
100 |
clips = generate_clip_sequence(number)
|
101 |
if clips:
|
102 |
st.write("Generated Clips Sequence:")
|
103 |
+
st.divider()
|
104 |
for i, clip in enumerate(clips):
|
105 |
st.write(f"Clip {i + 1}: {clip}")
|
106 |
+
submit = st.button("Create Video", use_container_width=True, key="create_video")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
107 |
|
108 |
with col2:
|
109 |
with st.container(border=True):
|
110 |
st.subheader("Output")
|
111 |
+
output_file = f"{video_id}_{number}_output.mp4"
|
112 |
if submit:
|
113 |
+
combine_video(number, video_id, output_file)
|
114 |
+
st.video(output_file, autoplay=True)
|
|
|
|
app_v2.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import streamlit as st
|
2 |
+
from utils import *
|
3 |
+
|
4 |
+
st.set_page_config(
|
5 |
+
page_title="Number to Video",
|
6 |
+
page_icon="🎥",
|
7 |
+
initial_sidebar_state="collapsed",
|
8 |
+
)
|
9 |
+
|
10 |
+
# Input number
|
11 |
+
number = st.text_input("Enter a number between 1 and 99,99,999", "24")
|
12 |
+
number = int(number)
|
13 |
+
|
14 |
+
if number:
|
15 |
+
col1, col2 = st.columns(2)
|
16 |
+
|
17 |
+
with col1:
|
18 |
+
with st.container(border=True):
|
19 |
+
st.subheader("Settings")
|
20 |
+
st.divider()
|
21 |
+
|
22 |
+
avatar = st.radio("Choose an avatar", ("Custom avatar", "Template avatar"))
|
23 |
+
avatar = "custom" if avatar == "Custom avatar" else "template"
|
24 |
+
|
25 |
+
# Generate clip sequence based on the number
|
26 |
+
clips = generate_clip_sequence(number)
|
27 |
+
if clips:
|
28 |
+
st.write("Generated Clips Sequence:")
|
29 |
+
for i, clip in enumerate(clips):
|
30 |
+
st.write(f"Clip {i + 1}: {clip}")
|
31 |
+
submit = st.button("Create Video", use_container_width=True)
|
32 |
+
|
33 |
+
if clips:
|
34 |
+
with st.sidebar:
|
35 |
+
st.title("Advanced Settings")
|
36 |
+
trim_settings = []
|
37 |
+
for i, clip in enumerate(clips):
|
38 |
+
with st.container(border=True):
|
39 |
+
st.write(f"Adjust settings for {clip}:")
|
40 |
+
length = get_clip_duration(clip, avatar)
|
41 |
+
default_trim_start = 0.10
|
42 |
+
default_trim_end = length - 0.10
|
43 |
+
|
44 |
+
# trim_bounds = st.slider(
|
45 |
+
# f"Trim bounds for {clip}",
|
46 |
+
# 0.0, length,
|
47 |
+
# (default_trim_start, default_trim_end),
|
48 |
+
# 0.01,
|
49 |
+
# key=f"bounds_{i}"
|
50 |
+
# )
|
51 |
+
# trim_bounds = tuple([round(b, 2) for b in trim_bounds])
|
52 |
+
# print(trim_bounds)
|
53 |
+
# trim_settings.append(trim_bounds)
|
54 |
+
|
55 |
+
trim_start = st.slider(f"Trim start for {clip}", 0.0, float(length), 0.00, 0.01, key=f"start_{i}")
|
56 |
+
trim_end = st.slider(f"Trim end for {clip}", 0.0, float(length), 0.00, 0.01, key=f"end_{i}")
|
57 |
+
trim_settings.append((trim_start, trim_end))
|
58 |
+
print(trim_settings)
|
59 |
+
|
60 |
+
with col2:
|
61 |
+
with st.container(border=True):
|
62 |
+
st.subheader("Output")
|
63 |
+
output_file = "output.mp4"
|
64 |
+
if submit:
|
65 |
+
pass
|
66 |
+
# Create the video with individual clip settings
|
67 |
+
create_advanced_video(number, trim_settings, avatar, output_file)
|
68 |
+
st.video(output_file, autoplay=True)
|
clips_metadata.json
CHANGED
@@ -2,194 +2,194 @@
|
|
2 |
{
|
3 |
"clip_number": 0,
|
4 |
"start_time_ms": 0,
|
5 |
-
"end_time_ms":
|
6 |
"initial_length": "316",
|
7 |
"file_name": "1_cut.mp4"
|
8 |
},
|
9 |
{
|
10 |
"clip_number": 1,
|
11 |
-
"start_time_ms":
|
12 |
-
"end_time_ms":
|
13 |
"file_name": "2_cut.mp4"
|
14 |
},
|
15 |
{
|
16 |
"clip_number": 2,
|
17 |
-
"start_time_ms":
|
18 |
-
"end_time_ms":
|
19 |
"file_name": "3_cut.mp4"
|
20 |
},
|
21 |
{
|
22 |
"clip_number": 3,
|
23 |
-
"start_time_ms":
|
24 |
-
"end_time_ms":
|
25 |
"file_name": "4_cut.mp4"
|
26 |
},
|
27 |
{
|
28 |
"clip_number": 4,
|
29 |
-
"start_time_ms":
|
30 |
-
"end_time_ms":
|
31 |
"file_name": "5_cut.mp4"
|
32 |
},
|
33 |
{
|
34 |
"clip_number": 5,
|
35 |
-
"start_time_ms":
|
36 |
-
"end_time_ms":
|
37 |
"file_name": "6_cut.mp4"
|
38 |
},
|
39 |
{
|
40 |
"clip_number": 7,
|
41 |
-
"start_time_ms":
|
42 |
-
"end_time_ms":
|
43 |
"file_name": "7_cut.mp4"
|
44 |
},
|
45 |
{
|
46 |
"clip_number": 8,
|
47 |
-
"start_time_ms":
|
48 |
-
"end_time_ms":
|
49 |
"file_name": "8_cut.mp4"
|
50 |
},
|
51 |
{
|
52 |
"clip_number": 9,
|
53 |
-
"start_time_ms":
|
54 |
-
"end_time_ms":
|
55 |
"file_name": "9_cut.mp4"
|
56 |
},
|
57 |
{
|
58 |
"clip_number": 10,
|
59 |
-
"start_time_ms":
|
60 |
-
"end_time_ms":
|
61 |
"file_name": "10_cut.mp4"
|
62 |
},
|
63 |
{
|
64 |
"clip_number": 11,
|
65 |
-
"start_time_ms":
|
66 |
-
"end_time_ms":
|
67 |
"file_name": "20_cut.mp4"
|
68 |
},
|
69 |
{
|
70 |
"clip_number": 12,
|
71 |
-
"start_time_ms":
|
72 |
-
"end_time_ms":
|
73 |
"file_name": "30_cut.mp4"
|
74 |
},
|
75 |
{
|
76 |
"clip_number": 13,
|
77 |
-
"start_time_ms":
|
78 |
-
"end_time_ms":
|
79 |
"file_name": "40_cut.mp4"
|
80 |
},
|
81 |
{
|
82 |
"clip_number": 14,
|
83 |
-
"start_time_ms":
|
84 |
-
"end_time_ms":
|
85 |
"file_name": "50_cut.mp4"
|
86 |
},
|
87 |
{
|
88 |
"clip_number": 15,
|
89 |
-
"start_time_ms":
|
90 |
-
"end_time_ms":
|
91 |
"file_name": "60_cut.mp4"
|
92 |
},
|
93 |
{
|
94 |
"clip_number": 16,
|
95 |
-
"start_time_ms":
|
96 |
-
"end_time_ms":
|
97 |
"file_name": "70_cut.mp4"
|
98 |
},
|
99 |
{
|
100 |
"clip_number": 17,
|
101 |
-
"start_time_ms":
|
102 |
-
"end_time_ms":
|
103 |
"file_name": "80_cut.mp4"
|
104 |
},
|
105 |
{
|
106 |
"clip_number": 18,
|
107 |
-
"start_time_ms":
|
108 |
-
"end_time_ms":
|
109 |
"file_name": "90_cut.mp4"
|
110 |
},
|
111 |
{
|
112 |
"clip_number": 19,
|
113 |
-
"start_time_ms":
|
114 |
-
"end_time_ms":
|
115 |
"file_name": "11_cut.mp4"
|
116 |
},
|
117 |
{
|
118 |
"clip_number": 20,
|
119 |
-
"start_time_ms":
|
120 |
-
"end_time_ms":
|
121 |
"file_name": "12_cut.mp4"
|
122 |
},
|
123 |
{
|
124 |
"clip_number": 21,
|
125 |
-
"start_time_ms":
|
126 |
-
"end_time_ms":
|
127 |
"file_name": "13_cut.mp4"
|
128 |
},
|
129 |
{
|
130 |
"clip_number": 22,
|
131 |
-
"start_time_ms":
|
132 |
-
"end_time_ms":
|
133 |
"file_name": "14_cut.mp4"
|
134 |
},
|
135 |
{
|
136 |
"clip_number": 23,
|
137 |
-
"start_time_ms":
|
138 |
-
"end_time_ms":
|
139 |
"file_name": "15_cut.mp4"
|
140 |
},
|
141 |
{
|
142 |
"clip_number": 24,
|
143 |
-
"start_time_ms":
|
144 |
-
"end_time_ms":
|
145 |
"file_name": "16_cut.mp4"
|
146 |
},
|
147 |
{
|
148 |
"clip_number": 25,
|
149 |
-
"start_time_ms":
|
150 |
-
"end_time_ms":
|
151 |
"file_name": "17_cut.mp4"
|
152 |
},
|
153 |
{
|
154 |
"clip_number": 26,
|
155 |
-
"start_time_ms":
|
156 |
-
"end_time_ms":
|
157 |
"file_name": "18_cut.mp4"
|
158 |
},
|
159 |
{
|
160 |
"clip_number": 27,
|
161 |
-
"start_time_ms":
|
162 |
-
"end_time_ms":
|
163 |
"file_name": "19_cut.mp4"
|
164 |
},
|
165 |
{
|
166 |
"clip_number": 28,
|
167 |
-
"start_time_ms":
|
168 |
-
"end_time_ms":
|
169 |
"file_name": "100_cut.mp4"
|
170 |
},
|
171 |
{
|
172 |
"clip_number": 29,
|
173 |
-
"start_time_ms":
|
174 |
-
"end_time_ms":
|
175 |
"file_name": "1000_cut.mp4"
|
176 |
},
|
177 |
{
|
178 |
"clip_number": 30,
|
179 |
-
"start_time_ms":
|
180 |
-
"end_time_ms":
|
181 |
"file_name": "100000_cut.mp4"
|
182 |
},
|
183 |
{
|
184 |
"clip_number": 31,
|
185 |
-
"start_time_ms":
|
186 |
-
"end_time_ms":
|
187 |
"file_name": "Intro_cut.mp4"
|
188 |
},
|
189 |
{
|
190 |
"clip_number": 32,
|
191 |
-
"start_time_ms":
|
192 |
-
"end_time_ms":
|
193 |
"file_name": "Conclusion_cut.mp4"
|
194 |
}
|
195 |
]
|
|
|
2 |
{
|
3 |
"clip_number": 0,
|
4 |
"start_time_ms": 0,
|
5 |
+
"end_time_ms": 356,
|
6 |
"initial_length": "316",
|
7 |
"file_name": "1_cut.mp4"
|
8 |
},
|
9 |
{
|
10 |
"clip_number": 1,
|
11 |
+
"start_time_ms": 656,
|
12 |
+
"end_time_ms": 868,
|
13 |
"file_name": "2_cut.mp4"
|
14 |
},
|
15 |
{
|
16 |
"clip_number": 2,
|
17 |
+
"start_time_ms": 1199,
|
18 |
+
"end_time_ms": 1431,
|
19 |
"file_name": "3_cut.mp4"
|
20 |
},
|
21 |
{
|
22 |
"clip_number": 3,
|
23 |
+
"start_time_ms": 1782,
|
24 |
+
"end_time_ms": 2017,
|
25 |
"file_name": "4_cut.mp4"
|
26 |
},
|
27 |
{
|
28 |
"clip_number": 4,
|
29 |
+
"start_time_ms": 2393,
|
30 |
+
"end_time_ms": 2701,
|
31 |
"file_name": "5_cut.mp4"
|
32 |
},
|
33 |
{
|
34 |
"clip_number": 5,
|
35 |
+
"start_time_ms": 3027,
|
36 |
+
"end_time_ms": 3213,
|
37 |
"file_name": "6_cut.mp4"
|
38 |
},
|
39 |
{
|
40 |
"clip_number": 7,
|
41 |
+
"start_time_ms": 3763,
|
42 |
+
"end_time_ms": 4143,
|
43 |
"file_name": "7_cut.mp4"
|
44 |
},
|
45 |
{
|
46 |
"clip_number": 8,
|
47 |
+
"start_time_ms": 4410,
|
48 |
+
"end_time_ms": 4618,
|
49 |
"file_name": "8_cut.mp4"
|
50 |
},
|
51 |
{
|
52 |
"clip_number": 9,
|
53 |
+
"start_time_ms": 4976,
|
54 |
+
"end_time_ms": 5434,
|
55 |
"file_name": "9_cut.mp4"
|
56 |
},
|
57 |
{
|
58 |
"clip_number": 10,
|
59 |
+
"start_time_ms": 5732,
|
60 |
+
"end_time_ms": 6016,
|
61 |
"file_name": "10_cut.mp4"
|
62 |
},
|
63 |
{
|
64 |
"clip_number": 11,
|
65 |
+
"start_time_ms": 6329,
|
66 |
+
"end_time_ms": 6705,
|
67 |
"file_name": "20_cut.mp4"
|
68 |
},
|
69 |
{
|
70 |
"clip_number": 12,
|
71 |
+
"start_time_ms": 7040,
|
72 |
+
"end_time_ms": 7392,
|
73 |
"file_name": "30_cut.mp4"
|
74 |
},
|
75 |
{
|
76 |
"clip_number": 13,
|
77 |
+
"start_time_ms": 7769,
|
78 |
+
"end_time_ms": 8096,
|
79 |
"file_name": "40_cut.mp4"
|
80 |
},
|
81 |
{
|
82 |
"clip_number": 14,
|
83 |
+
"start_time_ms": 8463,
|
84 |
+
"end_time_ms": 8803,
|
85 |
"file_name": "50_cut.mp4"
|
86 |
},
|
87 |
{
|
88 |
"clip_number": 15,
|
89 |
+
"start_time_ms": 9127,
|
90 |
+
"end_time_ms": 9572,
|
91 |
"file_name": "60_cut.mp4"
|
92 |
},
|
93 |
{
|
94 |
"clip_number": 16,
|
95 |
+
"start_time_ms": 9911,
|
96 |
+
"end_time_ms": 10351,
|
97 |
"file_name": "70_cut.mp4"
|
98 |
},
|
99 |
{
|
100 |
"clip_number": 17,
|
101 |
+
"start_time_ms": 10627,
|
102 |
+
"end_time_ms": 10940,
|
103 |
"file_name": "80_cut.mp4"
|
104 |
},
|
105 |
{
|
106 |
"clip_number": 18,
|
107 |
+
"start_time_ms": 11202,
|
108 |
+
"end_time_ms": 11688,
|
109 |
"file_name": "90_cut.mp4"
|
110 |
},
|
111 |
{
|
112 |
"clip_number": 19,
|
113 |
+
"start_time_ms": 11958,
|
114 |
+
"end_time_ms": 12414,
|
115 |
"file_name": "11_cut.mp4"
|
116 |
},
|
117 |
{
|
118 |
"clip_number": 20,
|
119 |
+
"start_time_ms": 12742,
|
120 |
+
"end_time_ms": 13069,
|
121 |
"file_name": "12_cut.mp4"
|
122 |
},
|
123 |
{
|
124 |
"clip_number": 21,
|
125 |
+
"start_time_ms": 13414,
|
126 |
+
"end_time_ms": 13845,
|
127 |
"file_name": "13_cut.mp4"
|
128 |
},
|
129 |
{
|
130 |
"clip_number": 22,
|
131 |
+
"start_time_ms": 14203,
|
132 |
+
"end_time_ms": 14601,
|
133 |
"file_name": "14_cut.mp4"
|
134 |
},
|
135 |
{
|
136 |
"clip_number": 23,
|
137 |
+
"start_time_ms": 14959,
|
138 |
+
"end_time_ms": 15391,
|
139 |
"file_name": "15_cut.mp4"
|
140 |
},
|
141 |
{
|
142 |
"clip_number": 24,
|
143 |
+
"start_time_ms": 15704,
|
144 |
+
"end_time_ms": 16260,
|
145 |
"file_name": "16_cut.mp4"
|
146 |
},
|
147 |
{
|
148 |
"clip_number": 25,
|
149 |
+
"start_time_ms": 16592,
|
150 |
+
"end_time_ms": 17133,
|
151 |
"file_name": "17_cut.mp4"
|
152 |
},
|
153 |
{
|
154 |
"clip_number": 26,
|
155 |
+
"start_time_ms": 17403,
|
156 |
+
"end_time_ms": 17807,
|
157 |
"file_name": "18_cut.mp4"
|
158 |
},
|
159 |
{
|
160 |
"clip_number": 27,
|
161 |
+
"start_time_ms": 18048,
|
162 |
+
"end_time_ms": 18604,
|
163 |
"file_name": "19_cut.mp4"
|
164 |
},
|
165 |
{
|
166 |
"clip_number": 28,
|
167 |
+
"start_time_ms": 18930,
|
168 |
+
"end_time_ms": 19281,
|
169 |
"file_name": "100_cut.mp4"
|
170 |
},
|
171 |
{
|
172 |
"clip_number": 29,
|
173 |
+
"start_time_ms": 19598,
|
174 |
+
"end_time_ms": 20026,
|
175 |
"file_name": "1000_cut.mp4"
|
176 |
},
|
177 |
{
|
178 |
"clip_number": 30,
|
179 |
+
"start_time_ms": 20288,
|
180 |
+
"end_time_ms": 20606,
|
181 |
"file_name": "100000_cut.mp4"
|
182 |
},
|
183 |
{
|
184 |
"clip_number": 31,
|
185 |
+
"start_time_ms": 21038,
|
186 |
+
"end_time_ms": 22207,
|
187 |
"file_name": "Intro_cut.mp4"
|
188 |
},
|
189 |
{
|
190 |
"clip_number": 32,
|
191 |
+
"start_time_ms": 22712,
|
192 |
+
"end_time_ms": 23198,
|
193 |
"file_name": "Conclusion_cut.mp4"
|
194 |
}
|
195 |
]
|
dev.ipynb
CHANGED
@@ -208,7 +208,7 @@
|
|
208 |
},
|
209 |
{
|
210 |
"cell_type": "code",
|
211 |
-
"execution_count":
|
212 |
"metadata": {},
|
213 |
"outputs": [],
|
214 |
"source": [
|
@@ -224,7 +224,7 @@
|
|
224 |
" {\n",
|
225 |
" \"character\": {\n",
|
226 |
" \"type\": \"avatar\",\n",
|
227 |
-
" \"avatar_id\": \"
|
228 |
" \"scale\": 1.0,\n",
|
229 |
" \"avatar_style\": \"normal\",\n",
|
230 |
" \"offset\": {\n",
|
@@ -245,14 +245,49 @@
|
|
245 |
},
|
246 |
{
|
247 |
"cell_type": "code",
|
248 |
-
"execution_count":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
249 |
"metadata": {},
|
250 |
"outputs": [
|
251 |
{
|
252 |
"name": "stdout",
|
253 |
"output_type": "stream",
|
254 |
"text": [
|
255 |
-
"{\"error\": null, \"data\": {\"video_id\": \"
|
256 |
]
|
257 |
}
|
258 |
],
|
@@ -277,7 +312,28 @@
|
|
277 |
},
|
278 |
{
|
279 |
"cell_type": "code",
|
280 |
-
"execution_count":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
281 |
"metadata": {},
|
282 |
"outputs": [],
|
283 |
"source": [
|
@@ -289,33 +345,33 @@
|
|
289 |
"}\n",
|
290 |
"\n",
|
291 |
"\n",
|
292 |
-
"response = requests.get(url, headers=headers, params={\"video_id\":
|
293 |
]
|
294 |
},
|
295 |
{
|
296 |
"cell_type": "code",
|
297 |
-
"execution_count":
|
298 |
"metadata": {},
|
299 |
"outputs": [
|
300 |
{
|
301 |
"data": {
|
302 |
"text/plain": [
|
303 |
"{'code': 100,\n",
|
304 |
-
" 'data': {'callback_id':
|
305 |
-
" 'caption_url':
|
306 |
-
" 'created_at':
|
307 |
-
" 'duration':
|
308 |
" 'error': None,\n",
|
309 |
-
" 'gif_url':
|
310 |
-
" 'id': '
|
311 |
-
" 'status': '
|
312 |
-
" 'thumbnail_url':
|
313 |
-
" 'video_url':
|
314 |
" 'video_url_caption': None},\n",
|
315 |
" 'message': 'Success'}"
|
316 |
]
|
317 |
},
|
318 |
-
"execution_count":
|
319 |
"metadata": {},
|
320 |
"output_type": "execute_result"
|
321 |
}
|
@@ -414,7 +470,7 @@
|
|
414 |
},
|
415 |
{
|
416 |
"cell_type": "code",
|
417 |
-
"execution_count":
|
418 |
"metadata": {},
|
419 |
"outputs": [],
|
420 |
"source": [
|
@@ -423,13 +479,81 @@
|
|
423 |
" clips_metadata = json.load(f)\n",
|
424 |
"\n",
|
425 |
"for item in clips_metadata:\n",
|
426 |
-
" item[\"start_time_ms\"]=item[\"start_time_ms\"]+
|
427 |
-
" item[\"end_time_ms\"]=item[\"end_time_ms\"]-
|
428 |
"\n",
|
429 |
"# update the file with new timestamps\n",
|
430 |
"with open(\"clips_metadata.json\", \"w\") as f:\n",
|
431 |
" json.dump(clips_metadata, f, indent=4)"
|
432 |
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
433 |
}
|
434 |
],
|
435 |
"metadata": {
|
|
|
208 |
},
|
209 |
{
|
210 |
"cell_type": "code",
|
211 |
+
"execution_count": 49,
|
212 |
"metadata": {},
|
213 |
"outputs": [],
|
214 |
"source": [
|
|
|
224 |
" {\n",
|
225 |
" \"character\": {\n",
|
226 |
" \"type\": \"avatar\",\n",
|
227 |
+
" \"avatar_id\": \"42b4f9358cc9443a8610fda90bd3ad87\",\n",
|
228 |
" \"scale\": 1.0,\n",
|
229 |
" \"avatar_style\": \"normal\",\n",
|
230 |
" \"offset\": {\n",
|
|
|
245 |
},
|
246 |
{
|
247 |
"cell_type": "code",
|
248 |
+
"execution_count": 53,
|
249 |
+
"metadata": {},
|
250 |
+
"outputs": [],
|
251 |
+
"source": [
|
252 |
+
"payload = {\n",
|
253 |
+
" \"title\": \"Sample Talking Photo Video\",\n",
|
254 |
+
" \"caption\": False,\n",
|
255 |
+
" \"callback_id\": \"your_custom_id_123\",\n",
|
256 |
+
" \"dimension\": {\n",
|
257 |
+
" \"width\": 720,\n",
|
258 |
+
" \"height\": 1280\n",
|
259 |
+
" },\n",
|
260 |
+
" \"video_inputs\": [\n",
|
261 |
+
" {\n",
|
262 |
+
" \"character\": {\n",
|
263 |
+
" \"type\": \"talking_photo\",\n",
|
264 |
+
" \"talking_photo_id\": 'cf557bdc461b487fb703b0c3138df325'\n",
|
265 |
+
" },\n",
|
266 |
+
" \"voice\": {\n",
|
267 |
+
" \"type\": \"audio\",\n",
|
268 |
+
" \"audio_url\": \"https://drive.google.com/file/d/1CF8TjWwPWiIPJX3D1bjpMopinHt4iw1D/view?usp=sharing\"\n",
|
269 |
+
" },\n",
|
270 |
+
" \"talking_style\": \"stable\",\n",
|
271 |
+
" \"expression\": \"happy\",\n",
|
272 |
+
" # \"background\": {\n",
|
273 |
+
" # \"type\": \"color\",\n",
|
274 |
+
" # \"value\": \"#FAFAFA\"\n",
|
275 |
+
" # }\n",
|
276 |
+
" }\n",
|
277 |
+
" ]\n",
|
278 |
+
"}\n"
|
279 |
+
]
|
280 |
+
},
|
281 |
+
{
|
282 |
+
"cell_type": "code",
|
283 |
+
"execution_count": 54,
|
284 |
"metadata": {},
|
285 |
"outputs": [
|
286 |
{
|
287 |
"name": "stdout",
|
288 |
"output_type": "stream",
|
289 |
"text": [
|
290 |
+
"{\"error\": null, \"data\": {\"video_id\": \"d8194dfd76fa40c49bfc9a99c67ffbe3\"}}\n"
|
291 |
]
|
292 |
}
|
293 |
],
|
|
|
312 |
},
|
313 |
{
|
314 |
"cell_type": "code",
|
315 |
+
"execution_count": 56,
|
316 |
+
"metadata": {},
|
317 |
+
"outputs": [
|
318 |
+
{
|
319 |
+
"data": {
|
320 |
+
"text/plain": [
|
321 |
+
"'d8194dfd76fa40c49bfc9a99c67ffbe3'"
|
322 |
+
]
|
323 |
+
},
|
324 |
+
"execution_count": 56,
|
325 |
+
"metadata": {},
|
326 |
+
"output_type": "execute_result"
|
327 |
+
}
|
328 |
+
],
|
329 |
+
"source": [
|
330 |
+
"video_id = response.json()[\"data\"][\"video_id\"]\n",
|
331 |
+
"video_id"
|
332 |
+
]
|
333 |
+
},
|
334 |
+
{
|
335 |
+
"cell_type": "code",
|
336 |
+
"execution_count": 57,
|
337 |
"metadata": {},
|
338 |
"outputs": [],
|
339 |
"source": [
|
|
|
345 |
"}\n",
|
346 |
"\n",
|
347 |
"\n",
|
348 |
+
"response = requests.get(url, headers=headers, params={\"video_id\": video_id}).json()"
|
349 |
]
|
350 |
},
|
351 |
{
|
352 |
"cell_type": "code",
|
353 |
+
"execution_count": 58,
|
354 |
"metadata": {},
|
355 |
"outputs": [
|
356 |
{
|
357 |
"data": {
|
358 |
"text/plain": [
|
359 |
"{'code': 100,\n",
|
360 |
+
" 'data': {'callback_id': None,\n",
|
361 |
+
" 'caption_url': None,\n",
|
362 |
+
" 'created_at': 1736231063,\n",
|
363 |
+
" 'duration': None,\n",
|
364 |
" 'error': None,\n",
|
365 |
+
" 'gif_url': None,\n",
|
366 |
+
" 'id': 'd8194dfd76fa40c49bfc9a99c67ffbe3',\n",
|
367 |
+
" 'status': 'processing',\n",
|
368 |
+
" 'thumbnail_url': None,\n",
|
369 |
+
" 'video_url': None,\n",
|
370 |
" 'video_url_caption': None},\n",
|
371 |
" 'message': 'Success'}"
|
372 |
]
|
373 |
},
|
374 |
+
"execution_count": 58,
|
375 |
"metadata": {},
|
376 |
"output_type": "execute_result"
|
377 |
}
|
|
|
470 |
},
|
471 |
{
|
472 |
"cell_type": "code",
|
473 |
+
"execution_count": 31,
|
474 |
"metadata": {},
|
475 |
"outputs": [],
|
476 |
"source": [
|
|
|
479 |
" clips_metadata = json.load(f)\n",
|
480 |
"\n",
|
481 |
"for item in clips_metadata:\n",
|
482 |
+
" item[\"start_time_ms\"]=item[\"start_time_ms\"]+20\n",
|
483 |
+
" item[\"end_time_ms\"]=item[\"end_time_ms\"]-20\n",
|
484 |
"\n",
|
485 |
"# update the file with new timestamps\n",
|
486 |
"with open(\"clips_metadata.json\", \"w\") as f:\n",
|
487 |
" json.dump(clips_metadata, f, indent=4)"
|
488 |
]
|
489 |
+
},
|
490 |
+
{
|
491 |
+
"cell_type": "code",
|
492 |
+
"execution_count": 45,
|
493 |
+
"metadata": {},
|
494 |
+
"outputs": [
|
495 |
+
{
|
496 |
+
"name": "stdout",
|
497 |
+
"output_type": "stream",
|
498 |
+
"text": [
|
499 |
+
"{'code': 100, 'data': {'talking_photo_id': 'cf557bdc461b487fb703b0c3138df325', 'talking_photo_url': 'https://files2.heygen.ai/prod/movio/url_upload/user_upload/a0cc99225ed34eb9811246368d94768a/f670829259c24a0197966e9f7c767ada.image/png?Expires=1736835408&Signature=EcHmA-5R6USvUeus0Ku~NCoCfg~T9NteKjfR59HEYOOurb7in9T4QB3Um8aeHBGLhIz1~5epJuvzIVnuB9H2Ab5uwV9B84KdXWK5rWhrCefRRn8JQxFOnvoCDtQFeHhuTs8957xbboJkFdLiv8OLli90lkmO0fzZecs7WB~WFFhQGqeAhCPjAvQt325ECSngNA2Z4MbI96YbOanE5GiRvUg56hczdb9XqhZktDkZKIDZGl3jk45BcmoaYh6N~sySnGN4kBe-Ny8exFzH0cjloX3gwkHnwsitmI2yQKmse7LKQFEt8WyQYxQ6z6q4YN1FpjKqMjK1T~~UGLepdGIDCA__&Key-Pair-Id=K38HBHX5LX3X2H'}, 'msg': None, 'message': None}\n"
|
500 |
+
]
|
501 |
+
}
|
502 |
+
],
|
503 |
+
"source": [
|
504 |
+
"api_key = \"YTBjYzk5MjI1ZWQzNGViOTgxMTI0NjM2OGQ5NDc2OGEtMTczMzk5MjA5MA==\"\n",
|
505 |
+
"\n",
|
506 |
+
"with open(\"man_portrait.png\", \"rb\") as f:\n",
|
507 |
+
" resp = requests.post(\"https://upload.heygen.com/v1/talking_photo\", data=f, headers={\"Content-Type\": \"image/png\", \"x-api-key\": api_key})\n",
|
508 |
+
" print(resp.json())"
|
509 |
+
]
|
510 |
+
},
|
511 |
+
{
|
512 |
+
"cell_type": "code",
|
513 |
+
"execution_count": 52,
|
514 |
+
"metadata": {},
|
515 |
+
"outputs": [
|
516 |
+
{
|
517 |
+
"data": {
|
518 |
+
"text/plain": [
|
519 |
+
"'cf557bdc461b487fb703b0c3138df325'"
|
520 |
+
]
|
521 |
+
},
|
522 |
+
"execution_count": 52,
|
523 |
+
"metadata": {},
|
524 |
+
"output_type": "execute_result"
|
525 |
+
}
|
526 |
+
],
|
527 |
+
"source": [
|
528 |
+
"response = resp.json()\n",
|
529 |
+
"response[\"data\"][\"talking_photo_id\"]"
|
530 |
+
]
|
531 |
+
},
|
532 |
+
{
|
533 |
+
"cell_type": "code",
|
534 |
+
"execution_count": null,
|
535 |
+
"metadata": {},
|
536 |
+
"outputs": [],
|
537 |
+
"source": [
|
538 |
+
"\n",
|
539 |
+
"url = \"https://api.heygen.com/v1/talking_photo.list\"\n",
|
540 |
+
"\n",
|
541 |
+
"headers = {\n",
|
542 |
+
" \"accept\": \"application/json\",\n",
|
543 |
+
" \"x-api-key\": api_key\n",
|
544 |
+
"}\n",
|
545 |
+
"\n",
|
546 |
+
"response = requests.get(url, headers=headers)\n",
|
547 |
+
"\n",
|
548 |
+
"print(response.text)"
|
549 |
+
]
|
550 |
+
},
|
551 |
+
{
|
552 |
+
"cell_type": "code",
|
553 |
+
"execution_count": null,
|
554 |
+
"metadata": {},
|
555 |
+
"outputs": [],
|
556 |
+
"source": []
|
557 |
}
|
558 |
],
|
559 |
"metadata": {
|
heygen.py
ADDED
@@ -0,0 +1,173 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import requests
|
2 |
+
import json
|
3 |
+
from moviepy.editor import VideoFileClip
|
4 |
+
import os
|
5 |
+
|
6 |
+
API_KEY = "YTBjYzk5MjI1ZWQzNGViOTgxMTI0NjM2OGQ5NDc2OGEtMTczMzk5MjA5MA=="
|
7 |
+
AUDIO_URL = "https://drive.google.com/file/d/1CF8TjWwPWiIPJX3D1bjpMopinHt4iw1D/view?usp=sharing"
|
8 |
+
|
9 |
+
|
10 |
+
# API ENDPOINTS
|
11 |
+
#GET
|
12 |
+
VIDEO_GENERATION_STATUS = "https://api.heygen.com/v1/video_status.get"
|
13 |
+
LIST_TALKING_PHOTOS = "https://api.heygen.com/v1/talking_photo.list"
|
14 |
+
|
15 |
+
#POST
|
16 |
+
VIDEO_GENERATION = "https://api.heygen.com/v2/video/generate"
|
17 |
+
UPLOAD_PHOTO = "https://upload.heygen.com/v1/talking_photo"
|
18 |
+
|
19 |
+
|
20 |
+
def video_generation_payload(title, avatar_id, audio_url):
|
21 |
+
return {
|
22 |
+
"title": title,
|
23 |
+
"caption": False,
|
24 |
+
# "callback_id": "callback_id",
|
25 |
+
"dimension": {
|
26 |
+
"width": 720,
|
27 |
+
"height": 1280
|
28 |
+
},
|
29 |
+
"video_inputs": [
|
30 |
+
{
|
31 |
+
"character": {
|
32 |
+
"type": "avatar",
|
33 |
+
"avatar_id": avatar_id,
|
34 |
+
"scale": 1.0,
|
35 |
+
"avatar_style": "normal",
|
36 |
+
"offset": {
|
37 |
+
"x": 0.0,
|
38 |
+
"y": 0.0
|
39 |
+
},
|
40 |
+
"matting": False
|
41 |
+
},
|
42 |
+
"voice": {
|
43 |
+
"type": "audio",
|
44 |
+
"audio_url": audio_url
|
45 |
+
},
|
46 |
+
}
|
47 |
+
],
|
48 |
+
# "callback_url": "callback_url"
|
49 |
+
}
|
50 |
+
|
51 |
+
|
52 |
+
def talking_photo_payload(title, talking_photo_id, audio_url):
|
53 |
+
print(f"Creating video with title: {title}, talking_photo_id: {talking_photo_id}, audio_url: {audio_url}")
|
54 |
+
return {
|
55 |
+
"title": title,
|
56 |
+
"caption": False,
|
57 |
+
# "callback_id": "callback_id",
|
58 |
+
"dimension": {
|
59 |
+
"width": 720,
|
60 |
+
"height": 1280
|
61 |
+
},
|
62 |
+
"video_inputs": [
|
63 |
+
{
|
64 |
+
"character": {
|
65 |
+
"type": "talking_photo",
|
66 |
+
"talking_photo_id": talking_photo_id
|
67 |
+
},
|
68 |
+
"voice": {
|
69 |
+
"type": "audio",
|
70 |
+
"audio_url": audio_url
|
71 |
+
},
|
72 |
+
"talking_style": "stable",
|
73 |
+
"expression": "happy",
|
74 |
+
}
|
75 |
+
],
|
76 |
+
# "callback_url": "callback_url"
|
77 |
+
}
|
78 |
+
|
79 |
+
|
80 |
+
def upload_photo(file_path, type):
|
81 |
+
print(f"Uploading photo {file_path}")
|
82 |
+
with open(file_path, "rb") as f:
|
83 |
+
resp = requests.post(UPLOAD_PHOTO, data=f, headers={"Content-Type": type, "x-api-key": API_KEY}).json()
|
84 |
+
try:
|
85 |
+
talking_photo_id = resp["data"]["talking_photo_id"]
|
86 |
+
return talking_photo_id
|
87 |
+
except Exception as e:
|
88 |
+
print(f"Error uploading photo: {e}")
|
89 |
+
return resp
|
90 |
+
|
91 |
+
def list_talking_photos():
|
92 |
+
print("Listing talking photos")
|
93 |
+
headers = {
|
94 |
+
"accept": "application/json",
|
95 |
+
"x-api-key": API_KEY
|
96 |
+
}
|
97 |
+
response = requests.get(LIST_TALKING_PHOTOS, headers=headers).json()
|
98 |
+
return response
|
99 |
+
|
100 |
+
|
101 |
+
def download_video(video_id, video_url):
|
102 |
+
download_video = requests.get(video_url)
|
103 |
+
print(f"Downloading video {video_id}")
|
104 |
+
with open(f"{video_id}.mp4", "wb") as f:
|
105 |
+
f.write(download_video.content)
|
106 |
+
|
107 |
+
|
108 |
+
def create_video(title, avatar_id, audio_url):
|
109 |
+
print(f"Creating video with title: {title}, avatar_id: {avatar_id}, audio_url: {audio_url}")
|
110 |
+
headers = {
|
111 |
+
"accept": "application/json",
|
112 |
+
"content-type": "application/json",
|
113 |
+
"x-api-key": API_KEY
|
114 |
+
}
|
115 |
+
payload = talking_photo_payload(title, avatar_id, audio_url)
|
116 |
+
response = requests.post(VIDEO_GENERATION, json=payload, headers=headers).json()
|
117 |
+
|
118 |
+
try:
|
119 |
+
video_id = response["data"]["video_id"]
|
120 |
+
print(f"Video ID: {video_id}")
|
121 |
+
return video_id
|
122 |
+
except Exception as e:
|
123 |
+
print(f"Error creating video: {e}")
|
124 |
+
return response
|
125 |
+
|
126 |
+
|
127 |
+
def get_video_status(video_id):
|
128 |
+
headers = {
|
129 |
+
"accept": "application/json",
|
130 |
+
"x-api-key": API_KEY
|
131 |
+
}
|
132 |
+
response = requests.get(VIDEO_GENERATION_STATUS, headers=headers, params={"video_id": video_id}).json()
|
133 |
+
|
134 |
+
print(f"Video status: {response['data']['status']}")
|
135 |
+
|
136 |
+
return {
|
137 |
+
"id": response["data"]["id"],
|
138 |
+
"status": response["data"]["status"],
|
139 |
+
"video_url": response["data"]["video_url"],
|
140 |
+
"thumbnail_url": response["data"]["thumbnail_url"]
|
141 |
+
}
|
142 |
+
|
143 |
+
|
144 |
+
def split_video(video_id):
|
145 |
+
print(f"Splitting video {video_id}.mp4")
|
146 |
+
with open("clips_metadata.json", "r") as f:
|
147 |
+
clips_metadata = json.load(f)
|
148 |
+
|
149 |
+
video = VideoFileClip(f"{video_id}.mp4")
|
150 |
+
|
151 |
+
clips = []
|
152 |
+
for clip_data in clips_metadata:
|
153 |
+
start_time = clip_data["start_time_ms"]
|
154 |
+
end_time = clip_data["end_time_ms"]
|
155 |
+
|
156 |
+
# convert milliseconds to seconds
|
157 |
+
start_time /= 1000
|
158 |
+
end_time /= 1000
|
159 |
+
|
160 |
+
try:
|
161 |
+
clip_name = clip_data["file_name"].split(".")[0]+".mp4"
|
162 |
+
clip = video.subclip(start_time, end_time)
|
163 |
+
clips.append(clip)
|
164 |
+
except Exception as e:
|
165 |
+
print(f"Error in clip {clip_name}: {e}")
|
166 |
+
|
167 |
+
clips_dir = f"{video_id}_clips"
|
168 |
+
os.makedirs(clips_dir, exist_ok=True)
|
169 |
+
print(f"Saving clips to {clips_dir}")
|
170 |
+
|
171 |
+
for i, clip in enumerate(clips):
|
172 |
+
clip_path = os.path.join(clips_dir, clips_metadata[i]["file_name"].split(".")[0]+".mp4")
|
173 |
+
clip.write_videofile(clip_path, codec="libx264", audio_codec="aac")
|
sample.jpg
ADDED
![]() |
utils.py
CHANGED
@@ -80,7 +80,7 @@ def cut_clip(clip, st, en):
|
|
80 |
|
81 |
|
82 |
|
83 |
-
def
|
84 |
"""
|
85 |
Creates a video for the given number using pre-defined video clips.
|
86 |
"""
|
@@ -146,5 +146,35 @@ def create_advanced_video(number, trim_settings, avatar, output_file="output.mp4
|
|
146 |
if video_clips:
|
147 |
final_video = concatenate_videoclips(clips_to_combine)
|
148 |
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
else:
|
150 |
print("No clips to combine. Video creation failed.")
|
|
|
80 |
|
81 |
|
82 |
|
83 |
+
def create_video_old(number,st, en, output_file="output.mp4"):
|
84 |
"""
|
85 |
Creates a video for the given number using pre-defined video clips.
|
86 |
"""
|
|
|
146 |
if video_clips:
|
147 |
final_video = concatenate_videoclips(clips_to_combine)
|
148 |
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
|
149 |
+
else:
|
150 |
+
print("No clips to combine. Video creation failed.")
|
151 |
+
|
152 |
+
|
153 |
+
def combine_video(number, video_id, output_file="output.mp4"):
|
154 |
+
path = f"{video_id}_clips"
|
155 |
+
intro_file = f"{path}/Intro_cut.mp4"
|
156 |
+
conclusion_file = f"{path}/Conclusion_cut.mp4"
|
157 |
+
|
158 |
+
clips_to_combine = [intro_file]
|
159 |
+
|
160 |
+
clips = generate_clip_sequence(number)
|
161 |
+
for clip in clips:
|
162 |
+
clips_to_combine.append(trimmed_clip_path(clip, avatar_path=path))
|
163 |
+
|
164 |
+
clips_to_combine.append(conclusion_file)
|
165 |
+
|
166 |
+
# Load and combine video clips
|
167 |
+
video_clips = []
|
168 |
+
for clip_path in clips_to_combine:
|
169 |
+
try:
|
170 |
+
clip = VideoFileClip(clip_path)
|
171 |
+
video_clips.append(clip)
|
172 |
+
except Exception as e:
|
173 |
+
print(f"Error loading clip {clip_path}: {e}")
|
174 |
+
|
175 |
+
# Concatenate the video clips
|
176 |
+
if video_clips:
|
177 |
+
final_video = concatenate_videoclips(video_clips)
|
178 |
+
final_video.write_videofile(output_file, codec="libx264", audio_codec="aac")
|
179 |
else:
|
180 |
print("No clips to combine. Video creation failed.")
|