SelimGilon commited on
Commit
96025ae
·
1 Parent(s): b1ff8a3

works with local yolo

Browse files
Files changed (1) hide show
  1. app.py +169 -346
app.py CHANGED
@@ -9,12 +9,25 @@ import json
9
  import re
10
  from roboflow import Roboflow
11
  import gradio as gr
 
12
 
13
- rf = Roboflow(api_key="TN586SQsdwjUUvMN3H8e")
14
- project = rf.workspace().project("smartflyers")
15
- model = project.version(9).model
16
 
17
- # Define shops with their respective search URL and reference number regex
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  shops = {
19
  'Latulippe': {
20
  'url': 'https://latulippe.com/fr/recherche/?keywords=',
@@ -24,365 +37,175 @@ shops = {
24
  'url': 'https://www.decathlon.fr/search?Ntt=',
25
  'regex': r'Réf. : (\d+)'
26
  },
27
- 'Metro' : {
28
- 'url': 'https://www.metro.ca/en/online-grocery/search?filter=',
29
- 'regex': r'(\d{6})'
30
- },
31
- 'Walmart' : {
32
- 'url': 'https://www.walmart.ca/search?q=',
33
- 'regex': r'(\d{6})'
34
- },
35
- 'Canadian Tire' : {
36
- 'url': 'https://www.canadiantire.ca/en/search-results.html?q=',
37
- 'regex': r'(\d{6})'
38
- },
39
- 'Rona' : {
40
- 'url': 'https://www.rona.ca/en/search?searchType=product&q=',
41
- 'regex': r'(\d{6})'
42
- },
43
- 'Home Depot' : {
44
- 'url': 'https://www.homedepot.ca/en/home/search.html?q=',
45
- 'regex': r'(\d{6})'
46
- },
47
- 'BMR' : {
48
- 'url': 'https://www.bmr.co/fr/recherche.html?q=',
49
- 'regex': r'(\d{6})'
50
- },
51
- 'Reno Depot' : {
52
- 'url': 'https://www.renodepot.com/en/search#?q=',
53
- 'regex': r'(\d{6})'
54
- },
55
- 'Maxi' : {
56
- 'url': 'https://www.maxi.ca/search?search-bar=',
57
- 'regex': r'(\d{6})'
58
- },
59
- 'Super C' : {
60
- 'url': 'https://www.superc.ca/search?search-bar=',
61
- 'regex': r'(\d{6})'
62
- },
63
- 'Provigo' : {
64
- 'url': 'https://www.provigo.ca/search?search-bar=',
65
- 'regex': r'(\d{6})'
66
- },
67
- 'IGA' : {
68
- 'url': 'https://www.iga.net/en/search?t={14A91276-40BA-49D5-940D-3692DE3DC381}&k=',
69
- 'regex': r'(\d{6})'
70
- },
71
- 'Jean Coutu' : {
72
- 'url': 'https://www.jeancoutu.com/recherche?searchTerm=',
73
- 'regex': r'(\d{6})'
74
- },
75
- 'Pharmaprix' : {
76
- 'url': 'https://www1.pharmaprix.ca/search?search-bar=',
77
- 'regex': r'(\d{6})'
78
- },
79
- 'Uniprix' : {
80
- 'url': 'https://www.uniprix.com/en/search?search-bar=',
81
- 'regex': r'(\d{6})'
82
- },
83
- 'Familiprix' : {
84
- 'url': 'https://www.familiprix.com/en/search?search-bar=',
85
- 'regex': r'(\d{6})'
86
- },
87
- 'SAQ' : {
88
- 'url': 'https://www.saq.com/en/search?search-bar=',
89
- 'regex': r'(\d{6})'
90
- },
91
- 'Dollarama' : {
92
- 'url': 'https://www.dollarama.com/en-CA/search?text=',
93
- 'regex': r'(\d{6})'
94
- },
95
- 'Canac' : {
96
- 'url': 'https://www.canac.ca/en/search?search-bar=',
97
- 'regex': r'(\d{6})'
98
- },
99
- 'Patrick Morin' : {
100
- 'url': 'https://www.patrickmorin.com/en/search?search-bar=',
101
- 'regex': r'(\d{6})'
102
- },
103
- 'Gagnon La Grande Quincaillerie' : {
104
- 'url': 'https://www.gagnonfreres.com/en/search?search-bar=',
105
- 'regex': r'(\d{6})'
106
- },
107
- 'Tanguay' : {
108
- 'url': 'https://www.tanguay.ca/en/search?search-bar=',
109
- 'regex': r'(\d{6})'
110
- },
111
- 'The Source' : {
112
- 'url': 'https://www.thesource.ca/en-ca/search?text=',
113
- 'regex': r'(\d{6})'
114
- },
115
- 'Best Buy' : {
116
- 'url': 'https://www.bestbuy.ca/en-ca/search?search=',
117
- 'regex': r'(\d{6})'
118
- },
119
- 'Staples' : {
120
- 'url': 'https://www.staples.ca/search?query=',
121
- 'regex': r'(\d{6})'
122
- },
123
- 'Bureau en Gros' : {
124
- 'url': 'https://www.staples.ca/search?query=',
125
- 'regex': r'(\d{6})'
126
- },
127
- 'Centre Hi-Fi' : {
128
- 'url': 'https://www.centrehifi.com/en/search?search-bar=',
129
- 'regex': r'(\d{6})'
130
- },
131
- 'Stokes' : {
132
- 'url': 'https://www.stokesstores.com/en/search?search-bar=',
133
- 'regex': r'(\d{6})'
134
- },
135
- 'RD Furniture' : {
136
- 'url': 'https://www.raymond.ca/en/search?search-bar=',
137
- 'regex': r'(\d{6})'
138
- },
139
- 'Go Sport' : {
140
- 'url': 'https://www.gosport.ca/en/search?search-bar=',
141
- 'regex': r'(\d{6})'
142
- },
143
- 'Sports Experts' : {
144
- 'url': 'https://www.sportsexperts.ca/en-CA/search?search-bar=',
145
- 'regex': r'(\d{6})'
146
- },
147
- 'Atmosphere' : {
148
- 'url': 'https://www.atmosphere.ca/search?search-bar=',
149
- 'regex': r'(\d{6})'
150
- },
151
- 'SAIL' : {
152
- 'url': 'https://www.sail.ca/en/search?search-bar=',
153
- 'regex': r'(\d{6})'
154
- },
155
- 'MEC' : {
156
- 'url': 'https://www.mec.ca/en/search?text=',
157
- 'regex': r'(\d{6})'
158
- },
159
- 'Toys R Us' : {
160
- 'url': 'https://www.toysrus.ca/en/search?search-bar=',
161
- 'regex': r'(\d{6})'
162
- },
163
  # Add more shops and their respective information here
164
  }
165
 
166
- def pdf_to_images(pdf_path):
167
- images = convert_from_path(pdf_path)
168
- return [cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) for img in images]
169
-
170
-
171
-
172
- def get_yolo_predictions(image):
173
- # Convert image to suitable format if required
174
- # Use Roboflow API to get predictions
175
- predictions = model.predict(image, confidence=0.20, overlap=50).json()
176
- return predictions
177
-
178
- def display_bbox_and_extract_text(image, predictions, page_number):
179
- texts = [] # Store OCR text for each bbox
180
- labeled_image = image.copy() # Copy the image to draw labels on it
181
- font = cv2.FONT_HERSHEY_SIMPLEX
182
- font_scale = 1 # Adjust the scale according to your image
183
- color = (255, 255, 255) # White color for text
184
- bg_color = (0, 0, 0) # Black background for text for visibility
185
- thickness = 10 # Thickness of the bbox outline
186
- text_thickness = 3 # Thickness of the font
187
-
188
- for idx, pred in enumerate(predictions["predictions"]):
189
- x_center = int(pred["x"])
190
- y_center = int(pred["y"])
191
- x = int(x_center - (pred["width"] / 2))
192
- y = int(y_center - (pred["height"] / 2))
193
- w = int(pred["width"])
194
- h = int(pred["height"])
195
-
196
- # Cropping the image to the bounding box
197
- sub_image = image[y:y + h, x:x + w]
198
-
199
- # Extract text using OCR
200
- text = ocr(sub_image)
201
- texts.append(text)
202
-
203
- # Draw the bounding box on the image
204
- start_point = (x, y)
205
- end_point = (x + w, y + h)
206
- bbox_color = (0, 255, 0) # Green color in BGR for bbox
207
- labeled_image = cv2.rectangle(labeled_image, start_point, end_point, bbox_color, thickness)
208
-
209
- # Put the label number near the bounding box with background for visibility
210
- label_text = str(idx + 1)
211
- label_size = cv2.getTextSize(label_text, font, font_scale, text_thickness)[0]
212
- label_position = (x, y + label_size[1] + 10) if y > label_size[1] else (x, y + label_size[1] + 20)
213
-
214
- # Draw background rectangle for text
215
- label_bg_start = (label_position[0], label_position[1] - label_size[1] - 10)
216
- label_bg_end = (label_position[0] + label_size[0], label_position[1] + 10)
217
- labeled_image = cv2.rectangle(labeled_image, label_bg_start, label_bg_end, bg_color, -1)
218
-
219
- # Put the label number on the image
220
- labeled_image = cv2.putText(labeled_image, label_text, label_position, font, font_scale, color, text_thickness)
221
-
222
- # Draw the page number on the image
223
- page_text = f"Page {page_number}"
224
- page_text_size = cv2.getTextSize(page_text, font, font_scale, text_thickness)[0]
225
- page_text_position = (image.shape[1] - page_text_size[0] - 20, page_text_size[1] + 20) # top-right corner
226
- col = (0, 0, 0) # Black color in BGR for page number
227
- labeled_image = cv2.putText(labeled_image, page_text, page_text_position, font, font_scale, col, text_thickness)
228
-
229
- # Convert the labeled image from BGR to RGB for display
230
- labeled_image = cv2.cvtColor(labeled_image, cv2.COLOR_BGR2RGB)
231
- return labeled_image, texts
232
-
233
-
234
- def extract_reference_number(text):
235
- # Look for "N°" followed by the reference number pattern
236
- match = re.search(r'N°\s*([A-Za-z0-9]+)', text)
237
- if match:
238
- # Return the found reference number
239
- return match.group(1)
240
- else:
241
- # Return None if no reference number is found
242
- return None
243
-
244
- def ocr(sub_image):
245
- # Use OCR to get text from image
246
- text = pytesseract.image_to_string(sub_image, lang='eng')
247
- return text
248
-
249
-
250
- # Set up your Google API key and Custom Search Engine ID
251
- GOOGLE_API_KEY = 'AIzaSyCD5eIu3N2uD6Vf5GE0VLBpkPsJ3mEZgA0'
252
- GOOGLE_CSE_ID = '32784ecc8a6bd4fad'
253
-
254
-
255
- def search_google(query):
256
- search_url = "https://www.googleapis.com/customsearch/v1"
257
- params = {
258
- 'q': query,
259
- 'key': GOOGLE_API_KEY,
260
- 'cx': GOOGLE_CSE_ID,
261
- 'num': 1 # Number of search results to return
262
- }
263
-
264
- response = requests.get(search_url, params=params)
265
- search_results = response.json()
266
- print(json.dumps(search_results, indent=2))
267
-
268
- # Extract the first search result URL
269
- url = search_results['items'][0]['link'] if 'items' in search_results else None
270
- return url
271
-
272
- def search_latulippe(query):
273
- # URLEncode the query to ensure it is HTTP-compliant.
274
- encoded_query = urllib.parse.quote(query)
275
- # Construct the search URL.
276
- search_url = f"https://latulippe.com/fr/recherche/?keywords={encoded_query}"
277
- return search_url
278
-
279
-
280
- def create_search_url(shop_url, query):
281
- # URLEncode the query to ensure it is HTTP-compliant.
282
- encoded_query = urllib.parse.quote(query)
283
- # Construct the search URL.
284
- if '{}' in shop_url:
285
- # The user provided a format string with a placeholder for the query
286
- search_url = shop_url.format(encoded_query)
287
- else:
288
- # Append the query to the base URL
289
- search_url = f"{shop_url}{encoded_query}"
290
- return search_url
291
-
292
-
293
- def clean_search_query(text):
294
- # Add "Latulippe" to the beginning
295
- text = "Latulippe " + text
296
- # Keep only the first sentence by finding the first period followed by a space or the end of the text
297
- first_sentence = re.split(r'(?<=[.!?]) +', text, maxsplit=1)[0]
298
- # Convert to lowercase
299
- first_sentence = first_sentence.lower()
300
- # Replace newline characters with spaces
301
- first_sentence = first_sentence.replace("\n", " ")
302
- # Remove special characters except for basic punctuation
303
- first_sentence = re.sub(r'[^a-z0-9\s,.]', '', first_sentence)
304
- # Optionally, remove multiple consecutive spaces
305
- first_sentence = re.sub(r'\s+', ' ', first_sentence).strip()
306
- return first_sentence
307
-
308
- # Function to create a table from the extracted data
309
- def create_table(data):
310
- # Assuming data is a list of tuples or lists with the following format:
311
- # [(page_number, object_number, reference_code, url), (...), ...]
312
- headers = ["Page", "Object", "Reference Code", "URL"]
313
- # Convert URL to a clickable link
314
- processed_data = []
315
- for row in data:
316
- clickable_link = f'<a href="{row[3]}" target="_blank">{row[3]}</a>'
317
- processed_data.concat((row[0], row[1], row[2], clickable_link))
318
- return gr.Dataframe(headers=headers, values=processed_data)
319
-
320
- def app(pdf_path, selected_shop):
321
- if pdf_path is None:
322
- raise gr.Error("No file uploaded. Please upload a PDF file.")
323
 
324
  # Check if the uploaded file is a PDF
325
- if not pdf_path.name.lower().endswith('.pdf'):
326
- raise gr.Error("Invalid file format. Please upload a PDF file.")
327
 
328
  if selected_shop is None:
329
  raise gr.Error("Please select a shop.")
330
 
331
- # Retrieve the selected shop's information
332
- search_url = shops[selected_shop]['url']
333
- ref_number_regex = shops[selected_shop]['regex']
334
- table = pd.DataFrame(columns=["Page", "Object", "Reference", "URL"])
335
- images = pdf_to_images(pdf_path)
336
- output_images = []
337
- all_urls = []
338
-
339
- # Process the PDF and generate outputs if no errors are found
340
  try:
341
- images = pdf_to_images(pdf_path)
342
- for page_number, img in enumerate(images, start=1):
343
- predictions = get_yolo_predictions(img)
344
- img_with_bbox, texts = display_bbox_and_extract_text(img, predictions, page_number)
345
- output_images.append(img_with_bbox)
346
-
347
- # Extract reference numbers using regex and generate search URLs
348
- #for text in texts:
349
- for object_number, text in enumerate(texts, start=1):
350
- ref_numbers = re.findall(ref_number_regex, text)
351
- for ref in ref_numbers:
352
- search_query = search_url + urllib.parse.quote(ref)
353
- # all_urls.append({'page': page_number, 'object':object_number, 'reference': ref, 'url': search_query})
354
- new_row = pd.Series({
355
- "Page": page_number,
356
- "Object": object_number,
357
- "Reference": ref,
358
- "URL": search_query
359
- })
360
- table = pd.concat([table, pd.DataFrame([new_row])], ignore_index=True)
361
-
362
- table_html = table.to_html(escape=False, index=False)
363
  pass
364
  except Exception as e:
365
  return gr.Error(f"An error occurred: {str(e)}")
366
 
367
- return output_images, table_html
368
-
369
 
370
 
371
- # Gradio interface definition
372
- iface = gr.Interface(
373
  fn=app,
374
- inputs=[
375
- gr.File(label="Upload PDF"), # Specify that you expect a file
376
- gr.Dropdown(choices=list(shops.keys()), label="Select Shop")
377
- ],
378
- outputs=[
379
- gr.Gallery(label="Processed Images"), # Output for gallery
380
- gr.HTML(label="Extracted Information") # Output for table
381
- ],
382
- title="Automated Hotspotting",
383
- description="Here is a demo of an automated hotspotting tool. Upload a PDF file and select the correponding shop to get started.",
384
- #allow_flagging="never"
385
  )
386
 
387
- iface.launch(share=False)
388
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  import re
10
  from roboflow import Roboflow
11
  import gradio as gr
12
+ from ultralytics import YOLO
13
 
 
 
 
14
 
15
+ mode = 'local'
16
+ # mode = 'rbf'
17
+
18
+ if mode == 'local':
19
+ model = YOLO('/Users/selimgilon/Desktop/SportBoost/Projects/Iflyers/best-flyers-yolov8-1000img-v10.pt')
20
+ else:
21
+ rf = Roboflow(api_key="TN586SQsdwjUUvMN3H8e")
22
+ project = rf.workspace().project("smartflyers")
23
+ model = project.version(9).model
24
+
25
+ shop = None
26
+
27
+ def process(selected_shop):
28
+ print(selected_shop)
29
+ return selected_shop
30
+
31
  shops = {
32
  'Latulippe': {
33
  'url': 'https://latulippe.com/fr/recherche/?keywords=',
 
37
  'url': 'https://www.decathlon.fr/search?Ntt=',
38
  'regex': r'Réf. : (\d+)'
39
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  # Add more shops and their respective information here
41
  }
42
 
43
+ hotspots_sku_links = []
44
+
45
+ section_labels = [
46
+ "apple",
47
+ "banana",
48
+ "carrot",
49
+ "donut",
50
+ "eggplant",
51
+ "fish",
52
+ "grapes",
53
+ "hamburger",
54
+ "ice cream",
55
+ "juice",
56
+ ]
57
+
58
+ def app(img, selected_shop):
59
+ if img is None:
60
+ raise gr.Error("No file uploaded. Please upload an image.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  # Check if the uploaded file is a PDF
 
 
63
 
64
  if selected_shop is None:
65
  raise gr.Error("Please select a shop.")
66
 
 
 
 
 
 
 
 
 
 
67
  try:
68
+ image_annotated = section(img)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  pass
70
  except Exception as e:
71
  return gr.Error(f"An error occurred: {str(e)}")
72
 
73
+ return image_annotated, hotspots_sku_links[selected_shop]
 
74
 
75
 
76
+ iiface = gr.Interface(
 
77
  fn=app,
78
+ inputs=[gr.Dropdown(choices=list(shops.keys()), label="Select Shop"), gr.Image(label="Input page (image)", sources=["upload", "webcam"])],
79
+
80
+ outputs= [gr.AnnotatedImage(label="Annotated page (image)"), gr.Textbox(label="Selected Hotspot")],
81
+ title="Hotspot Identifier",
82
+ description="Identify hotspots on a page",
 
 
 
 
 
 
83
  )
84
 
 
85
 
86
+ with gr.Blocks() as demo:
87
+
88
+
89
+ with gr.Row():
90
+ selected_shop = gr.Dropdown(shops.keys(), label="Shop")
91
+
92
+
93
+ with gr.Row():
94
+ img_input = gr.Image(label="Input page (image)", sources=["upload", "webcam"])
95
+ img_output = gr.AnnotatedImage(label="Annotated page (image)")
96
+
97
+ section_btn = gr.Button("Identify Hotspots")
98
+ selected_section = gr.Textbox(label="Selected Hotspot")
99
+
100
+
101
+ def get_yolo_predictions(image):
102
+ # Use Roboflow API to get predictions
103
+ predictions = model.predict(image, confidence=0.1, overlap=10).json()
104
+ # print("predictions", predictions)
105
+ return predictions
106
+
107
+
108
+ def get_yolo_predictions_local(image):
109
+ # Perform object detection on an image using the model
110
+ predictions = model(image, conf=0.1)
111
+ print("predictions", predictions)
112
+ return predictions
113
+
114
+ def ocr(sub_image):
115
+ # Use OCR to get text from image
116
+ grey = cv2.cvtColor(sub_image, cv2.COLOR_BGR2GRAY)
117
+ text = pytesseract.image_to_string(grey, lang='eng')
118
+ return text
119
+
120
+ def section(img):
121
+ hostpots = []
122
+ texts = []
123
+ sku = []
124
+
125
+ search_url = 'https://latulippe.com/fr/recherche/?keywords='
126
+ ref_number_regex = r'N° ?M(\d+)'
127
+
128
+ if mode == 'rbf':
129
+ predictions = get_yolo_predictions(img)
130
+ print("-------")
131
+ for idx, pred in enumerate(predictions["predictions"]):
132
+ x_center = int(pred["x"])
133
+ y_center = int(pred["y"])
134
+ x = int(x_center - (pred["width"] / 2))
135
+ y = int(y_center - (pred["height"] / 2))
136
+ w = int(pred["width"])
137
+ h = int(pred["height"])
138
+ # Cropping the image to the bounding box
139
+ sub_image = img[y:y + h, x:x + w]
140
+ cv2.imwrite(f"sub_image_{idx}.jpg", sub_image)
141
+
142
+ # Extract text using OCR
143
+ text = ocr(sub_image)
144
+ texts.append(text)
145
+
146
+ print("bbox", idx)
147
+ for object_number, text in enumerate(texts, start=1):
148
+ print("object", object_number)
149
+ print("text", text)
150
+ ref_numbers = re.findall(ref_number_regex, text)
151
+ for ref in ref_numbers:
152
+ print("ref", ref)
153
+ # append 'M' before the ref number
154
+ ref = 'M' + ref
155
+ search_query = search_url + urllib.parse.quote(ref)
156
+ if ref not in sku:
157
+ sku.append(ref)
158
+ if search_query not in hotspots_sku_links:
159
+ hotspots_sku_links.append(search_query)
160
+ hostpots.append(((x, y, x + w, y + h), ref))
161
+ return (img, hostpots)
162
+ else:
163
+ # get the height and width of the image
164
+
165
+ height, width, channels = img.shape
166
+ results = get_yolo_predictions_local(img)
167
+ for result in results:
168
+ coordinates = result.boxes.xyxy
169
+ coordinates = coordinates.to("cpu")
170
+ coordinates = coordinates.numpy()
171
+ print("FOUND {} objects".format(len(coordinates)))
172
+ for idx, coord in enumerate(coordinates):
173
+ print(coord.shape)
174
+ print("coord", coord)
175
+ # crop the image to the bounding box
176
+ x = int(coord[0])
177
+ y = int(coord[1])
178
+ w = int(coord[2] - coord[0])
179
+ h = int(coord[3] - coord[1])
180
+ sub_image = img[y:y + h, x:x + w]
181
+
182
+ # Extract text using OCR
183
+ text = ocr(sub_image)
184
+ texts.append(text)
185
+ for object_number, text in enumerate(texts, start=1):
186
+ print("object", object_number)
187
+ print("text", text)
188
+ ref_numbers = re.findall(ref_number_regex, text)
189
+ for ref in ref_numbers:
190
+ print("ref", ref)
191
+ # append 'M' before the ref number
192
+ ref = 'M' + ref
193
+ search_query = search_url + urllib.parse.quote(ref)
194
+ if ref not in sku:
195
+ sku.append(ref)
196
+ if search_query not in hotspots_sku_links:
197
+ hotspots_sku_links.append(search_query)
198
+ hostpots.append(((int(coord[0]), int(coord[1]), int(coord[2]), int(coord[3])), str(ref)))
199
+ return (img, hostpots)
200
+
201
+
202
+
203
+ section_btn.click(section, [img_input], img_output)
204
+
205
+ def select_section(evt: gr.SelectData):
206
+ return hotspots_sku_links[evt.index]
207
+
208
+ img_output.select(select_section, None, selected_section)
209
+
210
+ if __name__ == "__main__":
211
+ demo.launch()