Thai Quang Nguyen commited on
Commit ·
a33fb40
1
Parent(s): bb24dbf
fix video show
Browse files
app.py
CHANGED
|
@@ -166,13 +166,15 @@ def time_to_seconds(time_str):
|
|
| 166 |
def search_and_clip_video(text_query: str):
|
| 167 |
print(f"[INFO] Searching for: {text_query}")
|
| 168 |
|
|
|
|
|
|
|
|
|
|
| 169 |
# Encode query
|
| 170 |
with torch.no_grad():
|
| 171 |
text_tokens = clip.tokenize([text_query]).to(device)
|
| 172 |
text_features = model.encode_text(text_tokens)
|
| 173 |
text_features /= text_features.norm(dim=1, keepdim=True)
|
| 174 |
-
|
| 175 |
-
# Always use the original search method
|
| 176 |
search_result = client.search(
|
| 177 |
collection_name=COLLECTION_NAME,
|
| 178 |
query_vector=text_features.cpu().numpy()[0].tolist(),
|
|
@@ -181,7 +183,7 @@ def search_and_clip_video(text_query: str):
|
|
| 181 |
|
| 182 |
if not search_result:
|
| 183 |
print("[WARN] No result found.")
|
| 184 |
-
return
|
| 185 |
|
| 186 |
hit = search_result[0]
|
| 187 |
start = hit.payload.get("start", 0)
|
|
@@ -189,28 +191,18 @@ def search_and_clip_video(text_query: str):
|
|
| 189 |
start = time_to_seconds(start) if isinstance(start, str) else float(start)
|
| 190 |
end = time_to_seconds(end) if isinstance(end, str) else float(end)
|
| 191 |
video_filename = hit.payload.get("video_path", "temp_video_0.mp4")
|
| 192 |
-
|
| 193 |
-
# Get YouTube URL from filename
|
| 194 |
video_url = VIDEO_URLS.get(video_filename, DEFAULT_VIDEO_URL)
|
| 195 |
|
| 196 |
-
|
| 197 |
-
print(f"[INFO] Using YouTube URL: {video_url}")
|
| 198 |
-
|
| 199 |
-
# Handle very short clips or invalid timestamps
|
| 200 |
-
if end <= start or end - start < 1.0:
|
| 201 |
-
print("[WARN] Invalid clip duration, using default start/end times")
|
| 202 |
-
start = max(0, start - 5) # Start 5 seconds before
|
| 203 |
-
end = start + 10 # 10 second clip
|
| 204 |
-
|
| 205 |
-
# Extract clip from YouTube
|
| 206 |
-
clip_path = extract_video_clip(video_url, float(start), float(end))
|
| 207 |
-
if clip_path and os.path.exists(clip_path):
|
| 208 |
-
print(f"[INFO] Returning clip: {clip_path}")
|
| 209 |
-
return clip_path
|
| 210 |
-
else:
|
| 211 |
-
print("[WARN] Failed to extract clip, returning default video.")
|
| 212 |
-
return DEFAULT_VIDEO_URL
|
| 213 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 214 |
# Function to get a test video
|
| 215 |
def get_test_video():
|
| 216 |
print("[INFO] Returning test YouTube URL")
|
|
@@ -220,7 +212,8 @@ def get_test_video():
|
|
| 220 |
search_demo = gr.Interface(
|
| 221 |
fn=search_and_clip_video,
|
| 222 |
inputs=gr.Textbox(label="Enter search query", value="sample query"),
|
| 223 |
-
outputs=gr.Video(label="Video Result")
|
|
|
|
| 224 |
title="🎥 Semantic Video Search with Clip Extraction",
|
| 225 |
description="Returns a clipped video segment matching your query."
|
| 226 |
)
|
|
|
|
| 166 |
def search_and_clip_video(text_query: str):
|
| 167 |
print(f"[INFO] Searching for: {text_query}")
|
| 168 |
|
| 169 |
+
# Fixed-size wrapper
|
| 170 |
+
wrapper = "<div style='width:100%; max-width:720px; height:405px; margin:auto;'>{}</div>"
|
| 171 |
+
|
| 172 |
# Encode query
|
| 173 |
with torch.no_grad():
|
| 174 |
text_tokens = clip.tokenize([text_query]).to(device)
|
| 175 |
text_features = model.encode_text(text_tokens)
|
| 176 |
text_features /= text_features.norm(dim=1, keepdim=True)
|
| 177 |
+
|
|
|
|
| 178 |
search_result = client.search(
|
| 179 |
collection_name=COLLECTION_NAME,
|
| 180 |
query_vector=text_features.cpu().numpy()[0].tolist(),
|
|
|
|
| 183 |
|
| 184 |
if not search_result:
|
| 185 |
print("[WARN] No result found.")
|
| 186 |
+
return wrapper.format("<p style='text-align:center; padding-top:180px;'>No matching video found.</p>")
|
| 187 |
|
| 188 |
hit = search_result[0]
|
| 189 |
start = hit.payload.get("start", 0)
|
|
|
|
| 191 |
start = time_to_seconds(start) if isinstance(start, str) else float(start)
|
| 192 |
end = time_to_seconds(end) if isinstance(end, str) else float(end)
|
| 193 |
video_filename = hit.payload.get("video_path", "temp_video_0.mp4")
|
|
|
|
|
|
|
| 194 |
video_url = VIDEO_URLS.get(video_filename, DEFAULT_VIDEO_URL)
|
| 195 |
|
| 196 |
+
embed_url = video_url.replace("watch?v=", "embed/") + f"?start={int(start)}&end={int(end)}&autoplay=1"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 197 |
|
| 198 |
+
iframe = f"""
|
| 199 |
+
<iframe width="100%" height="100%"
|
| 200 |
+
src="{embed_url}"
|
| 201 |
+
frameborder="0"
|
| 202 |
+
allow="autoplay; encrypted-media"
|
| 203 |
+
allowfullscreen></iframe>
|
| 204 |
+
"""
|
| 205 |
+
return wrapper.format(iframe)
|
| 206 |
# Function to get a test video
|
| 207 |
def get_test_video():
|
| 208 |
print("[INFO] Returning test YouTube URL")
|
|
|
|
| 212 |
search_demo = gr.Interface(
|
| 213 |
fn=search_and_clip_video,
|
| 214 |
inputs=gr.Textbox(label="Enter search query", value="sample query"),
|
| 215 |
+
# outputs=gr.Video(label="Video Result"),\
|
| 216 |
+
outputs=gr.HTML(label="YouTube Clip"),
|
| 217 |
title="🎥 Semantic Video Search with Clip Extraction",
|
| 218 |
description="Returns a clipped video segment matching your query."
|
| 219 |
)
|