jonathanagustin
commited on
Commit
•
933222d
1
Parent(s):
1366c9e
Update app.py
Browse files
app.py
CHANGED
@@ -41,37 +41,18 @@ class SearchService:
|
|
41 |
@staticmethod
|
42 |
def parse(data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
43 |
results = []
|
44 |
-
|
45 |
-
|
46 |
-
contents = (
|
47 |
-
data.get("contents", {})
|
48 |
-
.get("twoColumnSearchResultsRenderer", {})
|
49 |
-
.get("primaryContents", {})
|
50 |
-
.get("sectionListRenderer", {})
|
51 |
-
.get("contents", [])
|
52 |
-
)
|
53 |
-
if contents:
|
54 |
-
items = contents[0].get("itemSectionRenderer", {}).get("contents", [])
|
55 |
-
|
56 |
for item in items:
|
57 |
if "videoRenderer" in item:
|
58 |
renderer = item["videoRenderer"]
|
59 |
-
video_id = renderer
|
60 |
-
|
61 |
-
|
62 |
-
for thumb in renderer.get("thumbnail", {}).get("thumbnails", [])
|
63 |
-
]
|
64 |
-
title_text = "".join(
|
65 |
-
[
|
66 |
-
run.get("text", "")
|
67 |
-
for run in renderer.get("title", {}).get("runs", [])
|
68 |
-
]
|
69 |
-
)
|
70 |
-
|
71 |
result = {
|
72 |
"video_id": video_id,
|
73 |
-
"
|
74 |
-
"title":
|
75 |
}
|
76 |
results.append(result)
|
77 |
|
@@ -104,20 +85,7 @@ class SearchService:
|
|
104 |
logging.warning(f"An error occurred: {e}")
|
105 |
return None
|
106 |
|
107 |
-
|
108 |
-
INITIAL_STREAMS = []
|
109 |
-
for result in SearchService.search("world live cams", SearchFilter.LIVE):
|
110 |
-
INITIAL_STREAMS.append(
|
111 |
-
{
|
112 |
-
"thumbnail_url": result["thumbnail_urls"][-1]
|
113 |
-
if result["thumbnail_urls"]
|
114 |
-
else "",
|
115 |
-
"title": result["title"],
|
116 |
-
"video_id": result["video_id"],
|
117 |
-
"label": result["video_id"],
|
118 |
-
}
|
119 |
-
)
|
120 |
-
|
121 |
class YouTubeObjectDetection:
|
122 |
def __init__(self):
|
123 |
logging.getLogger().setLevel(logging.DEBUG)
|
@@ -131,21 +99,14 @@ class YouTubeObjectDetection:
|
|
131 |
|
132 |
# Gradio UI Elements
|
133 |
initial_gallery_items = [(stream["thumbnail_url"], stream["title"]) for stream in self.streams]
|
134 |
-
self.gallery = gr.Gallery(
|
135 |
-
label="Live YouTube Videos",
|
136 |
-
value=initial_gallery_items,
|
137 |
-
show_label=True,
|
138 |
-
columns=[3],
|
139 |
-
rows=[10],
|
140 |
-
object_fit="contain",
|
141 |
-
height="auto",
|
142 |
-
allow_preview=False,
|
143 |
-
)
|
144 |
self.search_input = gr.Textbox(label="Search Live YouTube Videos")
|
145 |
self.stream_input = gr.Textbox(label="URL of Live YouTube Video")
|
146 |
self.annotated_image = gr.AnnotatedImage(show_label=False)
|
147 |
self.search_button = gr.Button("Search", size="lg")
|
148 |
self.submit_button = gr.Button("Detect Objects", variant="primary", size="lg")
|
|
|
|
|
149 |
|
150 |
@staticmethod
|
151 |
def download_font(url, save_path):
|
@@ -157,7 +118,7 @@ class YouTubeObjectDetection:
|
|
157 |
def capture_frame(self, url):
|
158 |
stream_url = SearchService.get_stream_url(url)
|
159 |
if not stream_url:
|
160 |
-
return
|
161 |
frame = self.get_frame(stream_url)
|
162 |
if frame is None:
|
163 |
return self.create_error_image("Failed to capture frame"), []
|
@@ -195,8 +156,7 @@ class YouTubeObjectDetection:
|
|
195 |
annotations.append((bbox, class_name))
|
196 |
return annotations
|
197 |
|
198 |
-
|
199 |
-
def create_error_image(message):
|
200 |
error_image = np.zeros((1920, 1080, 3), dtype=np.uint8)
|
201 |
pil_image = Image.fromarray(error_image)
|
202 |
draw = ImageDraw.Draw(pil_image)
|
@@ -214,8 +174,7 @@ class YouTubeObjectDetection:
|
|
214 |
streams.append(
|
215 |
{
|
216 |
"thumbnail_url": result["thumbnail_urls"][0]
|
217 |
-
if result["thumbnail_urls"]
|
218 |
-
else "",
|
219 |
"title": result["title"],
|
220 |
"video_id": result["video_id"],
|
221 |
"label": result["video_id"],
|
@@ -224,13 +183,8 @@ class YouTubeObjectDetection:
|
|
224 |
return streams
|
225 |
|
226 |
def render(self):
|
227 |
-
with gr.Blocks(
|
228 |
-
|
229 |
-
css="footer {visibility: hidden}",
|
230 |
-
) as app:
|
231 |
-
gr.HTML(
|
232 |
-
"<center><h1><b>Object Detection in Live YouTube Streams</b></h1></center>"
|
233 |
-
)
|
234 |
with gr.Column():
|
235 |
with gr.Group():
|
236 |
with gr.Row():
|
@@ -244,16 +198,12 @@ class YouTubeObjectDetection:
|
|
244 |
with gr.Row():
|
245 |
self.gallery.render()
|
246 |
|
247 |
-
@self.gallery.select(
|
248 |
-
inputs=None, outputs=[self.annotated_image, self.stream_input]
|
249 |
-
)
|
250 |
def on_gallery_select(evt: gr.SelectData):
|
251 |
selected_index = evt.index
|
252 |
if selected_index is not None and selected_index < len(self.streams):
|
253 |
selected_stream = self.streams[selected_index]
|
254 |
-
stream_url = SearchService.get_youtube_url(
|
255 |
-
selected_stream["video_id"]
|
256 |
-
)
|
257 |
frame_output = self.capture_frame(stream_url)
|
258 |
return frame_output, stream_url
|
259 |
return None, ""
|
@@ -261,17 +211,14 @@ class YouTubeObjectDetection:
|
|
261 |
@self.search_button.click(inputs=[self.search_input], outputs=[self.gallery])
|
262 |
def on_search_click(query):
|
263 |
self.streams = self.fetch_live_streams(query)
|
264 |
-
gallery_items = [
|
265 |
-
(stream["thumbnail_url"], stream["title"])
|
266 |
-
for stream in self.streams
|
267 |
-
]
|
268 |
return gallery_items
|
269 |
|
270 |
@self.submit_button.click(inputs=[self.stream_input], outputs=[self.annotated_image])
|
271 |
def annotate_stream(url):
|
272 |
return self.capture_frame(url)
|
273 |
|
274 |
-
return app.queue().launch(show_api=False)
|
275 |
|
276 |
if __name__ == "__main__":
|
277 |
YouTubeObjectDetection().render()
|
|
|
41 |
@staticmethod
|
42 |
def parse(data: Dict[str, Any]) -> List[Dict[str, Any]]:
|
43 |
results = []
|
44 |
+
contents = data["contents"]["twoColumnSearchResultsRenderer"]["primaryContents"]["sectionListRenderer"]["contents"]
|
45 |
+
items = contents[0]["itemSectionRenderer"]["contents"] if contents else []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
for item in items:
|
47 |
if "videoRenderer" in item:
|
48 |
renderer = item["videoRenderer"]
|
49 |
+
video_id = renderer["videoId"]
|
50 |
+
title = "".join(run["text"] for run in renderer["title"]["runs"])
|
51 |
+
thumbnail_url = renderer["thumbnail"]["thumbnails"][-1]["url"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
result = {
|
53 |
"video_id": video_id,
|
54 |
+
"thumbnail_url": thumbnail_url,
|
55 |
+
"title": title,
|
56 |
}
|
57 |
results.append(result)
|
58 |
|
|
|
85 |
logging.warning(f"An error occurred: {e}")
|
86 |
return None
|
87 |
|
88 |
+
INITIAL_STREAMS = SearchService.search("world live cams", SearchFilter.LIVE)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
class YouTubeObjectDetection:
|
90 |
def __init__(self):
|
91 |
logging.getLogger().setLevel(logging.DEBUG)
|
|
|
99 |
|
100 |
# Gradio UI Elements
|
101 |
initial_gallery_items = [(stream["thumbnail_url"], stream["title"]) for stream in self.streams]
|
102 |
+
self.gallery = gr.Gallery(label="Live YouTube Videos", value=initial_gallery_items, show_label=True, columns=[3], rows=[10], object_fit="contain", height="auto", allow_preview=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
self.search_input = gr.Textbox(label="Search Live YouTube Videos")
|
104 |
self.stream_input = gr.Textbox(label="URL of Live YouTube Video")
|
105 |
self.annotated_image = gr.AnnotatedImage(show_label=False)
|
106 |
self.search_button = gr.Button("Search", size="lg")
|
107 |
self.submit_button = gr.Button("Detect Objects", variant="primary", size="lg")
|
108 |
+
self.page_title = gr.HTML("<center><h1><b>Object Detection in Live YouTube Streams</b></h1></center>")
|
109 |
+
|
110 |
|
111 |
@staticmethod
|
112 |
def download_font(url, save_path):
|
|
|
118 |
def capture_frame(self, url):
|
119 |
stream_url = SearchService.get_stream_url(url)
|
120 |
if not stream_url:
|
121 |
+
return [], []
|
122 |
frame = self.get_frame(stream_url)
|
123 |
if frame is None:
|
124 |
return self.create_error_image("Failed to capture frame"), []
|
|
|
156 |
annotations.append((bbox, class_name))
|
157 |
return annotations
|
158 |
|
159 |
+
def create_error_image(self, message):
|
|
|
160 |
error_image = np.zeros((1920, 1080, 3), dtype=np.uint8)
|
161 |
pil_image = Image.fromarray(error_image)
|
162 |
draw = ImageDraw.Draw(pil_image)
|
|
|
174 |
streams.append(
|
175 |
{
|
176 |
"thumbnail_url": result["thumbnail_urls"][0]
|
177 |
+
if result["thumbnail_urls"] else "",
|
|
|
178 |
"title": result["title"],
|
179 |
"video_id": result["video_id"],
|
180 |
"label": result["video_id"],
|
|
|
183 |
return streams
|
184 |
|
185 |
def render(self):
|
186 |
+
with gr.Blocks(title="Object Detection in Live YouTube Streams", css="footer {visibility: hidden}") as app:
|
187 |
+
self.page_title.render()
|
|
|
|
|
|
|
|
|
|
|
188 |
with gr.Column():
|
189 |
with gr.Group():
|
190 |
with gr.Row():
|
|
|
198 |
with gr.Row():
|
199 |
self.gallery.render()
|
200 |
|
201 |
+
@self.gallery.select(inputs=None, outputs=[self.annotated_image, self.stream_input])
|
|
|
|
|
202 |
def on_gallery_select(evt: gr.SelectData):
|
203 |
selected_index = evt.index
|
204 |
if selected_index is not None and selected_index < len(self.streams):
|
205 |
selected_stream = self.streams[selected_index]
|
206 |
+
stream_url = SearchService.get_youtube_url(selected_stream["video_id"])
|
|
|
|
|
207 |
frame_output = self.capture_frame(stream_url)
|
208 |
return frame_output, stream_url
|
209 |
return None, ""
|
|
|
211 |
@self.search_button.click(inputs=[self.search_input], outputs=[self.gallery])
|
212 |
def on_search_click(query):
|
213 |
self.streams = self.fetch_live_streams(query)
|
214 |
+
gallery_items = [(stream["thumbnail_url"], stream["title"]) for stream in self.streams]
|
|
|
|
|
|
|
215 |
return gallery_items
|
216 |
|
217 |
@self.submit_button.click(inputs=[self.stream_input], outputs=[self.annotated_image])
|
218 |
def annotate_stream(url):
|
219 |
return self.capture_frame(url)
|
220 |
|
221 |
+
return app.queue().launch(show_api=False, debug=True, quiet=False, share=False)
|
222 |
|
223 |
if __name__ == "__main__":
|
224 |
YouTubeObjectDetection().render()
|