Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1036,6 +1036,10 @@ class VideoGeneratorUI:
|
|
| 1036 |
color: #666;
|
| 1037 |
margin-top: 0.5rem;
|
| 1038 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1039 |
</style>
|
| 1040 |
""", unsafe_allow_html=True)
|
| 1041 |
|
|
@@ -1043,42 +1047,53 @@ class VideoGeneratorUI:
|
|
| 1043 |
st.markdown("Create professional videos for your digital legacy management platform")
|
| 1044 |
|
| 1045 |
with st.container():
|
| 1046 |
-
|
| 1047 |
-
|
| 1048 |
-
|
| 1049 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1050 |
try:
|
| 1051 |
-
# Get
|
|
|
|
|
|
|
|
|
|
| 1052 |
image_categories = self.generator.image_scraper.get_images(prompt)
|
| 1053 |
-
|
| 1054 |
-
|
| 1055 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1056 |
if 'primary' in image_categories and image_categories['primary']:
|
| 1057 |
-
st.subheader("Most Relevant Images")
|
| 1058 |
self.display_image_grid(image_categories['primary'])
|
| 1059 |
|
| 1060 |
# Display secondary matches
|
| 1061 |
if 'secondary' in image_categories and image_categories['secondary']:
|
| 1062 |
-
st.subheader("Related Images")
|
| 1063 |
self.display_image_grid(image_categories['secondary'])
|
| 1064 |
|
| 1065 |
-
# Display general/fallback images
|
| 1066 |
-
if 'general' in image_categories and image_categories['general']:
|
| 1067 |
-
st.subheader("Additional Suggested Images")
|
| 1068 |
-
self.display_image_grid(image_categories['general'])
|
| 1069 |
-
|
| 1070 |
# Collect selected images
|
| 1071 |
selected_images = []
|
| 1072 |
for category in image_categories.values():
|
| 1073 |
-
if isinstance(category, list):
|
| 1074 |
for img in category:
|
| 1075 |
key = f"img_{img['url']}"
|
| 1076 |
if st.session_state.get(key, False):
|
| 1077 |
selected_images.append(img['url'])
|
| 1078 |
|
|
|
|
|
|
|
| 1079 |
# Video generation section
|
| 1080 |
if selected_images:
|
| 1081 |
self.show_video_settings(prompt, selected_images)
|
|
|
|
|
|
|
|
|
|
| 1082 |
else:
|
| 1083 |
st.warning("No images found. Please try a different prompt.")
|
| 1084 |
|
|
@@ -1087,16 +1102,13 @@ class VideoGeneratorUI:
|
|
| 1087 |
print(f"Error in UI: {str(e)}")
|
| 1088 |
|
| 1089 |
def display_image_grid(self, images: List[Dict[str, str]], cols: int = 3):
|
| 1090 |
-
"""Display images in a grid with metadata"""
|
| 1091 |
-
# Ensure images is a list and not empty
|
| 1092 |
if not images or not isinstance(images, list):
|
| 1093 |
return
|
| 1094 |
|
| 1095 |
-
# Calculate number of rows needed
|
| 1096 |
n_images = len(images)
|
| 1097 |
n_rows = (n_images + cols - 1) // cols
|
| 1098 |
|
| 1099 |
-
# Create grid
|
| 1100 |
for row in range(n_rows):
|
| 1101 |
with st.container():
|
| 1102 |
columns = st.columns(cols)
|
|
@@ -1107,15 +1119,23 @@ class VideoGeneratorUI:
|
|
| 1107 |
with columns[col]:
|
| 1108 |
try:
|
| 1109 |
st.image(img['url'], use_container_width=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1110 |
st.checkbox(
|
| 1111 |
-
|
| 1112 |
key=f"img_{img['url']}",
|
| 1113 |
help=f"Keywords: {img['keyword']}\nTags: {img['tags']}"
|
| 1114 |
)
|
|
|
|
|
|
|
| 1115 |
st.markdown(
|
| 1116 |
f"<div class='image-metadata'>"
|
| 1117 |
-
f"Relevance
|
| 1118 |
-
f"Keywords
|
|
|
|
| 1119 |
f"</div>",
|
| 1120 |
unsafe_allow_html=True
|
| 1121 |
)
|
|
@@ -1125,30 +1145,48 @@ class VideoGeneratorUI:
|
|
| 1125 |
def show_video_settings(self, prompt: str, selected_images: List[str]):
|
| 1126 |
"""Show video generation settings and controls"""
|
| 1127 |
st.subheader("Video Settings")
|
| 1128 |
-
|
| 1129 |
-
with
|
| 1130 |
-
|
| 1131 |
-
|
| 1132 |
-
|
| 1133 |
-
|
| 1134 |
-
|
| 1135 |
-
|
| 1136 |
-
|
| 1137 |
-
|
| 1138 |
-
|
| 1139 |
-
|
| 1140 |
-
|
| 1141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1142 |
)
|
| 1143 |
|
| 1144 |
-
|
| 1145 |
-
|
| 1146 |
|
| 1147 |
def generate_video(self, prompt: str, style: str, duration: int, selected_images: List[str]):
|
| 1148 |
-
"""Handle video generation"""
|
| 1149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1150 |
try:
|
| 1151 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1152 |
video_path = self.generator.create_video(
|
| 1153 |
prompt,
|
| 1154 |
style,
|
|
@@ -1157,20 +1195,37 @@ class VideoGeneratorUI:
|
|
| 1157 |
selected_images
|
| 1158 |
)
|
| 1159 |
|
| 1160 |
-
if os.path.exists(video_path):
|
| 1161 |
st.success("β¨ Video generated successfully!")
|
| 1162 |
-
st.video(video_path)
|
| 1163 |
|
| 1164 |
-
|
| 1165 |
-
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
|
| 1170 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1171 |
except Exception as e:
|
| 1172 |
st.error(f"Failed to generate video: {str(e)}")
|
| 1173 |
print(f"Video generation error: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1174 |
|
| 1175 |
if __name__ == "__main__":
|
| 1176 |
ui = VideoGeneratorUI()
|
|
|
|
| 1036 |
color: #666;
|
| 1037 |
margin-top: 0.5rem;
|
| 1038 |
}
|
| 1039 |
+
.submit-btn {
|
| 1040 |
+
margin-top: 1rem;
|
| 1041 |
+
padding: 0.5rem 1rem;
|
| 1042 |
+
}
|
| 1043 |
</style>
|
| 1044 |
""", unsafe_allow_html=True)
|
| 1045 |
|
|
|
|
| 1047 |
st.markdown("Create professional videos for your digital legacy management platform")
|
| 1048 |
|
| 1049 |
with st.container():
|
| 1050 |
+
# Add form for prompt submission
|
| 1051 |
+
with st.form(key='prompt_form'):
|
| 1052 |
+
prompt = st.text_area("Enter your video script", height=200)
|
| 1053 |
+
submit_button = st.form_submit_button(label='Analyze Script & Find Images')
|
| 1054 |
+
|
| 1055 |
+
if submit_button and prompt:
|
| 1056 |
+
# First show AI-selected images
|
| 1057 |
+
with st.spinner("AI analyzing script and selecting relevant images..."):
|
| 1058 |
try:
|
| 1059 |
+
# Get AI-selected images first
|
| 1060 |
+
keywords = self.generator.image_scraper.extract_key_topics(prompt)
|
| 1061 |
+
st.write("π€ AI-detected keywords:", ", ".join(keywords))
|
| 1062 |
+
|
| 1063 |
image_categories = self.generator.image_scraper.get_images(prompt)
|
| 1064 |
+
|
| 1065 |
+
# Store selections in session state
|
| 1066 |
+
if 'selected_images' not in st.session_state:
|
| 1067 |
+
st.session_state.selected_images = []
|
| 1068 |
+
|
| 1069 |
+
if image_categories and isinstance(image_categories, dict):
|
| 1070 |
+
# Display AI-selected primary matches first
|
| 1071 |
if 'primary' in image_categories and image_categories['primary']:
|
| 1072 |
+
st.subheader("π― AI-Selected Most Relevant Images")
|
| 1073 |
self.display_image_grid(image_categories['primary'])
|
| 1074 |
|
| 1075 |
# Display secondary matches
|
| 1076 |
if 'secondary' in image_categories and image_categories['secondary']:
|
| 1077 |
+
st.subheader("π AI-Selected Related Images")
|
| 1078 |
self.display_image_grid(image_categories['secondary'])
|
| 1079 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1080 |
# Collect selected images
|
| 1081 |
selected_images = []
|
| 1082 |
for category in image_categories.values():
|
| 1083 |
+
if isinstance(category, list):
|
| 1084 |
for img in category:
|
| 1085 |
key = f"img_{img['url']}"
|
| 1086 |
if st.session_state.get(key, False):
|
| 1087 |
selected_images.append(img['url'])
|
| 1088 |
|
| 1089 |
+
st.session_state.selected_images = selected_images
|
| 1090 |
+
|
| 1091 |
# Video generation section
|
| 1092 |
if selected_images:
|
| 1093 |
self.show_video_settings(prompt, selected_images)
|
| 1094 |
+
else:
|
| 1095 |
+
st.warning("Please select at least one image to generate the video.")
|
| 1096 |
+
|
| 1097 |
else:
|
| 1098 |
st.warning("No images found. Please try a different prompt.")
|
| 1099 |
|
|
|
|
| 1102 |
print(f"Error in UI: {str(e)}")
|
| 1103 |
|
| 1104 |
def display_image_grid(self, images: List[Dict[str, str]], cols: int = 3):
|
| 1105 |
+
"""Display images in a grid with metadata and confidence scores"""
|
|
|
|
| 1106 |
if not images or not isinstance(images, list):
|
| 1107 |
return
|
| 1108 |
|
|
|
|
| 1109 |
n_images = len(images)
|
| 1110 |
n_rows = (n_images + cols - 1) // cols
|
| 1111 |
|
|
|
|
| 1112 |
for row in range(n_rows):
|
| 1113 |
with st.container():
|
| 1114 |
columns = st.columns(cols)
|
|
|
|
| 1119 |
with columns[col]:
|
| 1120 |
try:
|
| 1121 |
st.image(img['url'], use_container_width=True)
|
| 1122 |
+
|
| 1123 |
+
# Add confidence score to checkbox label
|
| 1124 |
+
confidence = img.get('relevance_score', 0) * 100
|
| 1125 |
+
checkbox_label = f"Select (AI Confidence: {confidence:.1f}%)"
|
| 1126 |
+
|
| 1127 |
st.checkbox(
|
| 1128 |
+
checkbox_label,
|
| 1129 |
key=f"img_{img['url']}",
|
| 1130 |
help=f"Keywords: {img['keyword']}\nTags: {img['tags']}"
|
| 1131 |
)
|
| 1132 |
+
|
| 1133 |
+
# Show relevance metadata
|
| 1134 |
st.markdown(
|
| 1135 |
f"<div class='image-metadata'>"
|
| 1136 |
+
f"<b>AI Relevance:</b> {img['relevance']}<br>"
|
| 1137 |
+
f"<b>Keywords:</b> {img['keyword']}<br>"
|
| 1138 |
+
f"<b>Match Type:</b> {img.get('category', 'General')}"
|
| 1139 |
f"</div>",
|
| 1140 |
unsafe_allow_html=True
|
| 1141 |
)
|
|
|
|
| 1145 |
def show_video_settings(self, prompt: str, selected_images: List[str]):
|
| 1146 |
"""Show video generation settings and controls"""
|
| 1147 |
st.subheader("Video Settings")
|
| 1148 |
+
|
| 1149 |
+
with st.form(key='video_settings_form'):
|
| 1150 |
+
col1, col2 = st.columns(2)
|
| 1151 |
+
with col1:
|
| 1152 |
+
style = st.selectbox(
|
| 1153 |
+
"Choose style",
|
| 1154 |
+
options=["Professional", "Creative", "Educational"],
|
| 1155 |
+
index=0
|
| 1156 |
+
)
|
| 1157 |
+
with col2:
|
| 1158 |
+
duration = st.slider(
|
| 1159 |
+
"Video duration (seconds)",
|
| 1160 |
+
min_value=30,
|
| 1161 |
+
max_value=180,
|
| 1162 |
+
value=60,
|
| 1163 |
+
step=30
|
| 1164 |
+
)
|
| 1165 |
+
|
| 1166 |
+
generate_button = st.form_submit_button(
|
| 1167 |
+
label="π¬ Generate Video",
|
| 1168 |
+
type="primary"
|
| 1169 |
)
|
| 1170 |
|
| 1171 |
+
if generate_button:
|
| 1172 |
+
self.generate_video(prompt, style, duration, selected_images)
|
| 1173 |
|
| 1174 |
def generate_video(self, prompt: str, style: str, duration: int, selected_images: List[str]):
|
| 1175 |
+
"""Handle video generation with improved error handling"""
|
| 1176 |
+
if not selected_images:
|
| 1177 |
+
st.error("Please select at least one image before generating the video.")
|
| 1178 |
+
return
|
| 1179 |
+
|
| 1180 |
+
with st.spinner("π₯ Generating your video..."):
|
| 1181 |
try:
|
| 1182 |
+
# Create temp directory if it doesn't exist
|
| 1183 |
+
temp_dir = Path("temp_videos")
|
| 1184 |
+
temp_dir.mkdir(exist_ok=True)
|
| 1185 |
+
|
| 1186 |
+
# Generate unique output path
|
| 1187 |
+
output_path = str(temp_dir / f"vaultgenix_video_{int(time.time())}.mp4")
|
| 1188 |
+
|
| 1189 |
+
# Generate video
|
| 1190 |
video_path = self.generator.create_video(
|
| 1191 |
prompt,
|
| 1192 |
style,
|
|
|
|
| 1195 |
selected_images
|
| 1196 |
)
|
| 1197 |
|
| 1198 |
+
if video_path and os.path.exists(video_path):
|
| 1199 |
st.success("β¨ Video generated successfully!")
|
|
|
|
| 1200 |
|
| 1201 |
+
# Display video
|
| 1202 |
+
video_file = open(video_path, 'rb')
|
| 1203 |
+
video_bytes = video_file.read()
|
| 1204 |
+
st.video(video_bytes)
|
| 1205 |
+
|
| 1206 |
+
# Download button
|
| 1207 |
+
st.download_button(
|
| 1208 |
+
label="β¬οΈ Download Video",
|
| 1209 |
+
data=video_bytes,
|
| 1210 |
+
file_name=os.path.basename(video_path),
|
| 1211 |
+
mime="video/mp4"
|
| 1212 |
+
)
|
| 1213 |
+
|
| 1214 |
+
video_file.close()
|
| 1215 |
+
else:
|
| 1216 |
+
st.error("Video generation failed. Please try again.")
|
| 1217 |
+
|
| 1218 |
except Exception as e:
|
| 1219 |
st.error(f"Failed to generate video: {str(e)}")
|
| 1220 |
print(f"Video generation error: {str(e)}")
|
| 1221 |
+
|
| 1222 |
+
finally:
|
| 1223 |
+
# Cleanup temporary files
|
| 1224 |
+
try:
|
| 1225 |
+
if 'video_file' in locals():
|
| 1226 |
+
video_file.close()
|
| 1227 |
+
except Exception as e:
|
| 1228 |
+
print(f"Cleanup error: {e}")
|
| 1229 |
|
| 1230 |
if __name__ == "__main__":
|
| 1231 |
ui = VideoGeneratorUI()
|