Thai Quang Nguyen commited on
Commit
15e52d3
·
1 Parent(s): a34c44c

Add application file

Browse files
Files changed (1) hide show
  1. app.py +127 -0
app.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import clip
3
+ import torch
4
+ from qdrant_client import QdrantClient
5
+ import subprocess
6
+ import os
7
+ import uuid
8
+
9
+ # Setup CLIP
10
+ device = "cuda" if torch.cuda.is_available() else "cpu"
11
+ model, preprocess = clip.load("ViT-B/32", device=device)
12
+
13
+ # Setup Qdrant
14
+ client = QdrantClient(
15
+ url="https://265484ec-5f64-40ec-a619-c7c9dffc2dd9.us-east-1-0.aws.cloud.qdrant.io:6333",
16
+ api_key="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.I2MgcVnOKkWmOXwFlqJqEqm6LFQIF4cjxU5up4wxwyw"
17
+ )
18
+ COLLECTION_NAME = "video_segments"
19
+
20
+ # Paths
21
+ VIDEO_BASE_DIR = "/project/phan/tqn/RAG-VideoReferencing/"
22
+ CLIP_OUTPUT_DIR = "generated_clips"
23
+ os.makedirs(CLIP_OUTPUT_DIR, exist_ok=True)
24
+
25
+ DEFAULT_VIDEO_FILENAME = "temp_video_0.mp4"
26
+ DEFAULT_VIDEO_PATH = os.path.join(VIDEO_BASE_DIR, DEFAULT_VIDEO_FILENAME)
27
+
28
+
29
+ def extract_video_clip(input_path, start_time, end_time):
30
+ """
31
+ Use ffmpeg to extract a clip from the video.
32
+ """
33
+ clip_name = f"clip_{uuid.uuid4().hex}.mp4"
34
+ output_path = os.path.join(CLIP_OUTPUT_DIR, clip_name)
35
+
36
+ command = [
37
+ "ffmpeg",
38
+ "-ss", str(start_time),
39
+ "-i", input_path,
40
+ "-to", str(end_time - start_time),
41
+ "-c", "copy",
42
+ output_path,
43
+ "-y" # Overwrite if exists
44
+ ]
45
+
46
+ try:
47
+ subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
48
+ return output_path
49
+ except subprocess.CalledProcessError as e:
50
+ print(f"[ERROR] FFmpeg failed: {e}")
51
+ return None
52
+
53
+ def time_to_seconds(time_str):
54
+ h, m, s = time_str.split(':')
55
+ return int(h) * 3600 + int(m) * 60 + float(s)
56
+
57
+ def search_and_clip_video(text_query: str):
58
+ print(f"[INFO] Searching for: {text_query}")
59
+
60
+ # Encode query
61
+ with torch.no_grad():
62
+ text_tokens = clip.tokenize([text_query]).to(device)
63
+ text_features = model.encode_text(text_tokens)
64
+ text_features /= text_features.norm(dim=1, keepdim=True)
65
+
66
+ # Query Qdrant
67
+ search_result = client.search(
68
+ collection_name=COLLECTION_NAME,
69
+ query_vector=text_features.cpu().numpy()[0].tolist(),
70
+ limit=1,
71
+ )
72
+
73
+ if not search_result:
74
+ print("[WARN] No result found.")
75
+ return DEFAULT_VIDEO_PATH
76
+
77
+ hit = search_result[0]
78
+ start = hit.payload.get("start", 0)
79
+ end = hit.payload.get("end", 0)
80
+ start = time_to_seconds(start)
81
+ end = time_to_seconds(end)
82
+ video_filename = hit.payload.get("video_path", DEFAULT_VIDEO_FILENAME)
83
+
84
+ full_video_path = os.path.join(VIDEO_BASE_DIR, video_filename)
85
+
86
+ print(f"[INFO] Found: {video_filename} ({start} - {end})")
87
+
88
+ # Extract clip using ffmpeg
89
+ clip_path = extract_video_clip(full_video_path, float(start), float(end))
90
+ if clip_path and os.path.exists(clip_path):
91
+ print(f"[INFO] Returning clip: {clip_path}")
92
+ return clip_path
93
+ else:
94
+ print("[WARN] Failed to extract clip, returning default video.")
95
+ return DEFAULT_VIDEO_PATH
96
+
97
+
98
+ # Fallback test interface
99
+ def get_test_video():
100
+ print("[INFO] Returning test video path")
101
+ return DEFAULT_VIDEO_PATH
102
+
103
+
104
+ # Gradio Interfaces
105
+ search_demo = gr.Interface(
106
+ fn=search_and_clip_video,
107
+ inputs=gr.Textbox(label="Enter search query", value="sample query"),
108
+ outputs=gr.Video(label="Video Result"),
109
+ title="🎥 Semantic Video Search with Clip Extraction",
110
+ description="Returns a clipped video segment matching your query."
111
+ )
112
+
113
+ test_demo = gr.Interface(
114
+ fn=get_test_video,
115
+ inputs=None,
116
+ outputs=gr.Video(label="Test Video"),
117
+ title="Simple Video Test",
118
+ description="Always displays the default video to verify video player works."
119
+ )
120
+
121
+ demo = gr.TabbedInterface(
122
+ [search_demo, test_demo],
123
+ ["Search Video", "Test Video Player"]
124
+ )
125
+
126
+ if __name__ == "__main__":
127
+ demo.launch(share=True)