Nymbo commited on
Commit
f77bbf5
·
verified ·
1 Parent(s): bf17c4e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +163 -110
app.py CHANGED
@@ -1,173 +1,226 @@
1
  import gradio as gr
2
- import requests
3
  import yt_dlp
4
  import cv2
5
  from google_img_source_search import ReverseImageSearcher
6
  from PIL import Image
7
- import os
8
  import uuid
 
9
 
10
- # Generate a unique identifier for temporary file storage
11
- uid = str(uuid.uuid4())
 
12
 
13
- # Ensure the temporary directory exists
14
- if not os.path.exists(uid):
15
- os.makedirs(uid)
 
16
 
17
- size_js = """
18
- function imgSize(){
19
- var myImg = document.getElementsByClassName("my_im");
20
- var realWidth = myImg.naturalWidth;
21
- var realHeight = myImg.naturalHeight;
22
- alert("Original width=" + realWidth + ", " + "Original height=" + realHeight);
23
- }
24
- """
25
-
26
- # Function to download video using yt-dlp
27
  def dl(inp):
 
 
 
 
28
  out = None
29
- inp_out = inp.replace("https://", "").replace("/", "_").replace(".", "_").replace("=", "_").replace("?", "_")
30
  try:
31
- if "twitter" in inp:
32
- os.system(f'yt-dlp "{inp}" --extractor-arg "twitter:api=syndication" --trim-filenames 160 -o "{uid}/{inp_out}.mp4" -S res,mp4 --recode mp4')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  else:
34
- os.system(f'yt-dlp "{inp}" --trim-filenames 160 -o "{uid}/{inp_out}.mp4" -S res,mp4 --recode mp4')
35
-
36
- out = f"{uid}/{inp_out}.mp4"
37
- if not os.path.exists(out):
38
- print("Error: Video download failed. File not found.")
39
- return None, gr.HTML("<h1>Error: Video download failed.</h1>"), "", ""
40
-
41
- print(f"Downloaded video file: {out}")
42
  except Exception as e:
43
- print(f"Exception during video download: {e}")
44
- return None, gr.HTML(f"<h1>Error: {e}</h1>"), "", ""
 
45
  return out, gr.HTML(""), "", ""
46
 
47
- # Function to process video and perform reverse image search
48
  def process_vid(file, cur_frame, every_n):
49
- new_video_in = str(file)
50
- if not os.path.exists(new_video_in):
51
- print("Error: Video file does not exist.")
52
- return gr.HTML("<h1>Error: Video file not found.</h1>"), "", ""
53
-
54
- capture = cv2.VideoCapture(new_video_in)
55
  if not capture.isOpened():
56
- print("Error: Video file could not be opened.")
57
- return gr.HTML("<h1>Error: Failed to open video file.</h1>"), "", ""
58
-
59
  frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
60
  rev_img_searcher = ReverseImageSearcher()
61
  html_out = ""
62
- count = int(every_n)
63
-
64
- start_frame = int(cur_frame) if cur_frame else 0
65
-
66
  try:
67
- for i in range(start_frame, frame_count - 1):
68
  if count == int(every_n):
69
  count = 1
 
 
 
70
  capture.set(cv2.CAP_PROP_POS_FRAMES, i)
71
- ret, frame_f = capture.read()
72
-
73
- if not ret:
74
- print(f"Error: Failed to read frame at index {i}.")
75
  continue
76
-
77
- frame_path = f"{uid}-vid_tmp{i}.png"
78
- cv2.imwrite(frame_path, frame_f)
79
-
80
- if not os.path.exists(frame_path):
81
- print(f"Error: Failed to save frame at index {i}.")
82
  continue
83
-
 
84
  out_url = f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(frame_path)}'
85
  res = rev_img_searcher.search(out_url)
86
-
87
- if len(res) > 0:
88
  out_cnt = 0
89
  for search_item in res:
90
  out_cnt += 1
91
  html_out += f"""
92
  <div>
93
- Title: {search_item.page_title}<br>
94
- Site: <a href='{search_item.page_url}' target='_blank'>{search_item.page_url}</a><br>
95
- Img: <a href='{search_item.image_url}' target='_blank'>{search_item.image_url}</a><br>
96
- <img class='my_im' src='{search_item.image_url}'><br>
 
97
  </div>
98
  """
99
- return gr.HTML(f'<h1>Total Found: {out_cnt}</h1><br>{html_out}'), f"Found frame: {i}", i + int(every_n)
 
100
  count += 1
 
101
  except Exception as e:
102
- print(f"Exception during video processing: {e}")
103
- return gr.HTML(f"<h1>Error: {e}</h1>"), "", ""
104
- return gr.HTML('No frame matches found.'), "", ""
 
 
 
 
 
105
 
106
- # Function to process image file
107
  def process_im(file, url):
108
  if not url.startswith("https://nymbo"):
109
  return url
 
 
 
 
110
  try:
111
  read_file = Image.open(file)
112
- read_file.save(f"{uid}-tmp.png")
113
- out_url = f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(f"{uid}-tmp.png")}'
114
- return out_url
115
  except Exception as e:
116
- print(f"Exception during image processing: {e}")
117
- return gr.HTML(f"<h1>Error: {e}</h1>")
118
 
119
- # Function to perform reverse image search
120
  def rev_im(image):
121
- if not os.path.exists(image):
122
- print("Error: Image file does not exist.")
123
- return gr.HTML("<h1>Error: Image file not found.</h1>")
124
-
 
 
125
  try:
126
- image = cv2.imread(image)
127
- if image is None:
128
- print("Error: Failed to read image.")
129
- return gr.HTML("<h1>Error: Could not read image.</h1>")
130
-
131
- cv2.imwrite(f"{uid}-im_tmp.png", image)
132
- out_url = f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(f"{uid}-im_tmp.png")}'
 
 
 
 
133
  rev_img_searcher = ReverseImageSearcher()
134
  res = rev_img_searcher.search(out_url)
135
-
136
- html_out = ""
137
  count = 0
138
  for search_item in res:
139
  count += 1
140
  html_out += f"""
141
  <div>
142
- Title: {search_item.page_title}<br>
143
- Site: <a href='{search_item.page_url}' target='_blank'>{search_item.page_url}</a><br>
144
- Img: <a href='{search_item.image_url}' target='_blank'>{search_item.image_url}</a><br>
145
- <img class='my_im' src='{search_item.image_url}'><br>
 
146
  </div>
147
  """
148
- return gr.HTML(f'<h1>Total Found: {count}</h1><br>{html_out}')
149
  except Exception as e:
150
- print(f"Exception during reverse image search: {e}")
151
- return gr.HTML(f"<h1>Error: {e}</h1>")
 
152
 
153
- # Gradio app layout
154
  with gr.Blocks() as app:
155
- source_tog = gr.Radio(choices=["Image", "Video"], value="Image")
156
- inp_url = gr.Textbox(label="Image URL")
157
- load_im_btn = gr.Button("Load Image")
158
- inp_im = gr.Image(label="Search Image", type='filepath')
159
- go_btn_im = gr.Button("Search Image")
160
- vid_url = gr.Textbox(label="Video URL")
161
- vid_url_btn = gr.Button("Load Video")
162
- inp_vid = gr.Video(label="Search Video")
163
- every_n = gr.Number(label="Every nth Frame", value=10)
164
- go_btn_vid = gr.Button("Start Video Search")
165
- html_out = gr.HTML("")
166
-
167
- source_tog.change(lambda x: (gr.update(visible=x == "Image"), gr.update(visible=x == "Video")), [source_tog], [inp_im, inp_vid])
168
- load_im_btn.click(lambda url: url, inp_url, inp_im)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  go_btn_im.click(rev_im, inp_im, html_out)
170
- vid_url_btn.click(dl, vid_url, [inp_vid, html_out])
171
- go_btn_vid.click(process_vid, [inp_vid, "", every_n], [html_out])
172
 
173
  app.queue(concurrency_count=20).launch()
 
1
  import gradio as gr
2
+ import requests
3
  import yt_dlp
4
  import cv2
5
  from google_img_source_search import ReverseImageSearcher
6
  from PIL import Image
7
+ import os
8
  import uuid
9
+ from pathlib import Path
10
 
11
+ def ensure_directory(directory):
12
+ Path(directory).mkdir(parents=True, exist_ok=True)
13
+ return directory
14
 
15
+ # Create a unique working directory for each session
16
+ def get_session_dir():
17
+ session_id = str(uuid.uuid4())
18
+ return ensure_directory(f"temp_{session_id}")
19
 
 
 
 
 
 
 
 
 
 
 
20
  def dl(inp):
21
+ if not inp or not inp.strip():
22
+ return None, gr.HTML("Please provide a valid URL"), "", ""
23
+
24
+ work_dir = get_session_dir()
25
  out = None
 
26
  try:
27
+ # Sanitize input filename
28
+ inp_out = inp.replace("https://", "").replace("/", "_").replace(".", "_").replace("=", "_").replace("?", "_")
29
+ output_path = os.path.join(work_dir, f"{inp_out}.mp4")
30
+
31
+ ydl_opts = {
32
+ 'format': 'best[ext=mp4]',
33
+ 'outtmpl': output_path,
34
+ 'quiet': True,
35
+ 'no_warnings': True
36
+ }
37
+
38
+ with yt_dlp.YoutubeDL(ydl_opts) as ydl:
39
+ ydl.download([inp])
40
+
41
+ if os.path.exists(output_path):
42
+ out = output_path
43
+ print(f"Successfully downloaded video to: {out}")
44
  else:
45
+ raise Exception("Video download failed")
46
+
 
 
 
 
 
 
47
  except Exception as e:
48
+ print(f"Download error: {str(e)}")
49
+ return None, gr.HTML(f"Error downloading video: {str(e)}"), "", ""
50
+
51
  return out, gr.HTML(""), "", ""
52
 
 
53
  def process_vid(file, cur_frame, every_n):
54
+ if not file or not os.path.exists(file):
55
+ return gr.HTML("No valid video file provided."), "", ""
56
+
57
+ work_dir = os.path.dirname(file)
58
+ capture = cv2.VideoCapture(file)
59
+
60
  if not capture.isOpened():
61
+ return gr.HTML("Failed to open video file."), "", ""
62
+
 
63
  frame_count = int(capture.get(cv2.CAP_PROP_FRAME_COUNT))
64
  rev_img_searcher = ReverseImageSearcher()
65
  html_out = ""
66
+ count = int(every_n) if every_n else 10
67
+ start_frame = int(cur_frame) if cur_frame and cur_frame.strip() else 0
68
+
 
69
  try:
70
+ for i in range(start_frame, frame_count-1):
71
  if count == int(every_n):
72
  count = 1
73
+ print(f"Processing frame {i}")
74
+
75
+ # Read frame
76
  capture.set(cv2.CAP_PROP_POS_FRAMES, i)
77
+ ret, frame = capture.read()
78
+
79
+ if not ret or frame is None:
80
+ print(f"Failed to read frame {i}")
81
  continue
82
+
83
+ # Save frame
84
+ frame_path = os.path.join(work_dir, f"frame_{i}.png")
85
+ if not cv2.imwrite(frame_path, frame):
86
+ print(f"Failed to write frame {i}")
 
87
  continue
88
+
89
+ # Process frame
90
  out_url = f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(frame_path)}'
91
  res = rev_img_searcher.search(out_url)
92
+
93
+ if res:
94
  out_cnt = 0
95
  for search_item in res:
96
  out_cnt += 1
97
  html_out += f"""
98
  <div>
99
+ <h3>Result {out_cnt}</h3>
100
+ <p>Title: {search_item.page_title}</p>
101
+ <p>Site: <a href='{search_item.page_url}' target='_blank'>{search_item.page_url}</a></p>
102
+ <p>Image: <a href='{search_item.image_url}' target='_blank'>{search_item.image_url}</a></p>
103
+ <img class='my_im' src='{search_item.image_url}' alt='Search result'>
104
  </div>
105
  """
106
+ return gr.HTML(f'<h2>Total Found: {out_cnt}</h2>{html_out}'), f"Found frame: {i}", i+int(every_n)
107
+
108
  count += 1
109
+
110
  except Exception as e:
111
+ import traceback
112
+ error_msg = f"Error processing video: {str(e)}\n{traceback.format_exc()}"
113
+ print(error_msg)
114
+ return gr.HTML(error_msg), "", ""
115
+ finally:
116
+ capture.release()
117
+
118
+ return gr.HTML('No matches found in processed frames.'), "", ""
119
 
 
120
  def process_im(file, url):
121
  if not url.startswith("https://nymbo"):
122
  return url
123
+
124
+ work_dir = get_session_dir()
125
+ output_path = os.path.join(work_dir, "processed_image.png")
126
+
127
  try:
128
  read_file = Image.open(file)
129
+ read_file.save(output_path)
130
+ return f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(output_path)}'
 
131
  except Exception as e:
132
+ print(f"Error processing image: {str(e)}")
133
+ return url
134
 
 
135
  def rev_im(image):
136
+ if not image or not os.path.exists(image):
137
+ return gr.HTML("No valid image provided.")
138
+
139
+ work_dir = get_session_dir()
140
+ html_out = ""
141
+
142
  try:
143
+ # Read and write image
144
+ img = cv2.imread(image)
145
+ if img is None:
146
+ return gr.HTML("Failed to read image file.")
147
+
148
+ output_path = os.path.join(work_dir, "search_image.png")
149
+ if not cv2.imwrite(output_path, img):
150
+ return gr.HTML("Failed to process image file.")
151
+
152
+ # Search image
153
+ out_url = f'https://nymbo-reverse-image.hf.space/file={os.path.abspath(output_path)}'
154
  rev_img_searcher = ReverseImageSearcher()
155
  res = rev_img_searcher.search(out_url)
156
+
 
157
  count = 0
158
  for search_item in res:
159
  count += 1
160
  html_out += f"""
161
  <div>
162
+ <h3>Result {count}</h3>
163
+ <p>Title: {search_item.page_title}</p>
164
+ <p>Site: <a href='{search_item.page_url}' target='_blank'>{search_item.page_url}</a></p>
165
+ <p>Image: <a href='{search_item.image_url}' target='_blank'>{search_item.image_url}</a></p>
166
+ <img class='my_im' src='{search_item.image_url}' alt='Search result'>
167
  </div>
168
  """
169
+
170
  except Exception as e:
171
+ return gr.HTML(f"Error processing image: {str(e)}")
172
+
173
+ return gr.HTML(f'<h2>Total Found: {count}</h2>{html_out}')
174
 
175
+ # Gradio Interface
176
  with gr.Blocks() as app:
177
+ with gr.Row():
178
+ gr.Column()
179
+ with gr.Column():
180
+ source_tog = gr.Radio(choices=["Image", "Video"], value="Image", label="Search Type")
181
+
182
+ # Image search interface
183
+ with gr.Box(visible=True) as im_box:
184
+ inp_url = gr.Textbox(label="Image URL")
185
+ load_im_btn = gr.Button("Load Image")
186
+ inp_im = gr.Image(label="Search Image", type='filepath')
187
+ go_btn_im = gr.Button("Search")
188
+
189
+ # Video search interface
190
+ with gr.Box(visible=False) as vid_box:
191
+ vid_url = gr.Textbox(label="Video URL")
192
+ vid_url_btn = gr.Button("Load URL")
193
+ inp_vid = gr.Video(label="Search Video")
194
+ with gr.Row():
195
+ every_n = gr.Number(label="Process every N frames", value=10, minimum=1)
196
+ stat_box = gr.Textbox(label="Status")
197
+ with gr.Row():
198
+ go_btn_vid = gr.Button("Start Search")
199
+ next_btn = gr.Button("Next Frame")
200
+
201
+ gr.Column()
202
+
203
+ with gr.Row():
204
+ html_out = gr.HTML()
205
+ with gr.Row(visible=False):
206
+ hid_box = gr.Textbox()
207
+
208
+ # Interface logic
209
+ def toggle_interface(tog):
210
+ return gr.update(visible=tog == "Image"), gr.update(visible=tog == "Video")
211
+
212
+ source_tog.change(
213
+ toggle_interface,
214
+ [source_tog],
215
+ [im_box, vid_box],
216
+ cancels=[go_btn_vid.click, go_btn_im.click, load_im_btn.click, vid_url_btn.click]
217
+ )
218
+
219
+ # Button actions
220
+ load_im_btn.click(lambda x: x, inp_url, inp_im)
221
+ next_btn.click(process_vid, [inp_vid, hid_box, every_n], [html_out, stat_box, hid_box])
222
+ vid_url_btn.click(dl, vid_url, [inp_vid, html_out, stat_box, hid_box])
223
+ go_btn_vid.click(process_vid, [inp_vid, hid_box, every_n], [html_out, stat_box, hid_box])
224
  go_btn_im.click(rev_im, inp_im, html_out)
 
 
225
 
226
  app.queue(concurrency_count=20).launch()