phyloforfun commited on
Commit
a1e2ec1
1 Parent(s): 01e6026

Major update. Support for 15 LLMs, World Flora Online taxonomy validation, geolocation, 2 OCR methods, significant UI changes, stability improvements, consistent JSON parsing

Browse files
app.py CHANGED
@@ -1395,24 +1395,41 @@ def load_api_status():
1395
  except FileNotFoundError:
1396
  return None, None, None
1397
 
1398
- def display_api_key_status():
1399
  if not st.session_state['API_checked']:
1400
  present_keys, missing_keys, date_of_check = load_api_status()
1401
  if present_keys is None and missing_keys is None:
1402
  st.session_state['API_checked'] = False
1403
  else:
1404
  # Convert keys to annotations (similar to what you do in check_api_key_status)
1405
- present_annotations = [(key, " ", "#059c1b") for key in present_keys] # Adjust as needed
1406
- missing_annotations = [(key, " ", "#525252") for key in missing_keys] # Adjust as needed
 
 
 
 
 
 
 
1407
 
1408
  st.session_state['present_annotations'] = present_annotations
1409
  st.session_state['missing_annotations'] = missing_annotations
1410
  st.session_state['date_of_check'] = date_of_check
1411
  st.session_state['API_checked'] = True
 
 
 
 
 
 
 
 
1412
 
1413
  # Check if the API status has already been retrieved
1414
  if 'API_checked' not in st.session_state or not st.session_state['API_checked'] or st.session_state['API_rechecked']:
1415
- st.session_state['present_annotations'], st.session_state['missing_annotations'], st.session_state['date_of_check'] = check_api_key_status()
 
 
1416
  st.session_state['API_checked'] = True
1417
  st.session_state['API_rechecked'] = False
1418
 
@@ -1424,6 +1441,7 @@ def display_api_key_status():
1424
  # Display missing keys horizontally
1425
  if 'missing_annotations' in st.session_state and st.session_state['missing_annotations']:
1426
  annotated_text(*st.session_state['missing_annotations'])
 
1427
 
1428
 
1429
  def check_api_key_status():
@@ -1454,9 +1472,11 @@ def check_api_key_status():
1454
 
1455
  # Save API key status
1456
  save_api_status(present_keys, missing_keys, date_of_check)
 
 
 
 
1457
 
1458
- return present_annotations, missing_annotations, date_of_check
1459
-
1460
 
1461
  def convert_cost_dict_to_table(cost, name):
1462
  # Convert the dictionary to a pandas DataFrame for nicer display
@@ -1507,7 +1527,10 @@ def get_all_cost_tables():
1507
 
1508
 
1509
  def content_header():
1510
- col_logo, col_run_1, col_run_2, col_run_3, col_run_4, col_run_5 = st.columns([2,2,2,2,2,2])
 
 
 
1511
 
1512
 
1513
  col_test = st.container()
@@ -1591,10 +1614,7 @@ def content_header():
1591
  if st.session_state['formatted_json']:
1592
  json_report.set_JSON(st.session_state['formatted_json'], st.session_state['formatted_json_WFO'], st.session_state['formatted_json_GEO'])
1593
 
1594
- with col_run_5:
1595
- with st.expander("View Messages and Updates"):
1596
- st.info("***Note:*** If you use VoucherVision frequently, you can change the default values that are auto-populated in the form below. In a text editor or IDE, edit the first few rows in the file `../VoucherVision/vouchervision/VoucherVision_Config_Builder.py`")
1597
-
1598
 
1599
 
1600
  with col_run_1:
@@ -1810,13 +1830,14 @@ def content_api_check():
1810
  st.header('Available APIs')
1811
 
1812
  # Display API key status
1813
- display_api_key_status()
1814
 
1815
  # Place the button in the second column, right-justified
1816
  # with col_llm_2b:
1817
  if st.button("Re-Check API Keys"):
1818
  st.session_state['API_checked'] = False
1819
  st.session_state['API_rechecked'] = True
 
1820
  # with col_llm_2c:
1821
  if st.button("Edit API Keys"):
1822
  st.session_state.proceed_to_private = True
@@ -1861,7 +1882,7 @@ def content_collage_overlay():
1861
  st.session_state["demo_collage"] = Image.open(ba)
1862
 
1863
  # Display the image
1864
- st.image(st.session_state["demo_collage"], caption='LeafMachine2 Collage', output_format="PNG")
1865
  # st.image(st.session_state["demo_collage"], caption='LeafMachine2 Collage', output_format="JPEG")
1866
 
1867
 
@@ -1934,7 +1955,7 @@ def content_collage_overlay():
1934
  ocr = os.path.join(st.session_state.dir_home,'demo', 'ba','ocr2_low.png')
1935
  st.session_state["demo_overlay"] = Image.open(ocr)
1936
 
1937
- st.image(st.session_state["demo_overlay"], caption='OCR Overlay Images', output_format = "PNG")
1938
  # st.image(st.session_state["demo_overlay"], caption='OCR Overlay Images', output_format = "JPEG")
1939
 
1940
 
@@ -2242,8 +2263,14 @@ st.set_page_config(layout="wide", page_icon='img/icon.ico', page_title='VoucherV
2242
 
2243
  # Parse the 'is_hf' argument and set it in session state
2244
  if 'is_hf' not in st.session_state:
2245
- st.session_state['is_hf'] = True
2246
 
 
 
 
 
 
 
2247
  print(f"is_hf {st.session_state['is_hf']}")
2248
  # Default YAML file path
2249
  if 'config' not in st.session_state:
@@ -2266,7 +2293,7 @@ if st.session_state['is_hf']:
2266
 
2267
  else:
2268
  if 'proceed_to_main' not in st.session_state:
2269
- st.session_state.proceed_to_main = False # New state variable to control the flow
2270
  print(f"proceed_to_main {st.session_state['proceed_to_main']}")
2271
  if 'private_file' not in st.session_state:
2272
  st.session_state.private_file = does_private_file_exist()
 
1395
  except FileNotFoundError:
1396
  return None, None, None
1397
 
1398
+ def display_api_key_status(ccol):
1399
  if not st.session_state['API_checked']:
1400
  present_keys, missing_keys, date_of_check = load_api_status()
1401
  if present_keys is None and missing_keys is None:
1402
  st.session_state['API_checked'] = False
1403
  else:
1404
  # Convert keys to annotations (similar to what you do in check_api_key_status)
1405
+ present_annotations = []
1406
+ missing_annotations = []
1407
+ for key in present_keys:
1408
+ if "Valid" in key:
1409
+ show_text = key.split('(')[0]
1410
+ present_annotations.append((show_text, "ready!", "#059c1b")) # Green for valid
1411
+ elif "Invalid" in key:
1412
+ show_text = key.split('(')[0]
1413
+ present_annotations.append((show_text, "error", "#870307")) # Red for invalid
1414
 
1415
  st.session_state['present_annotations'] = present_annotations
1416
  st.session_state['missing_annotations'] = missing_annotations
1417
  st.session_state['date_of_check'] = date_of_check
1418
  st.session_state['API_checked'] = True
1419
+ # print('for')
1420
+ # print(st.session_state['present_annotations'])
1421
+ # print(st.session_state['missing_annotations'])
1422
+ else:
1423
+ # print('else')
1424
+ # print(st.session_state['present_annotations'])
1425
+ # print(st.session_state['missing_annotations'])
1426
+ pass
1427
 
1428
  # Check if the API status has already been retrieved
1429
  if 'API_checked' not in st.session_state or not st.session_state['API_checked'] or st.session_state['API_rechecked']:
1430
+ with ccol:
1431
+ with st.spinner('Verifying APIs by sending short requests...'):
1432
+ check_api_key_status()
1433
  st.session_state['API_checked'] = True
1434
  st.session_state['API_rechecked'] = False
1435
 
 
1441
  # Display missing keys horizontally
1442
  if 'missing_annotations' in st.session_state and st.session_state['missing_annotations']:
1443
  annotated_text(*st.session_state['missing_annotations'])
1444
+
1445
 
1446
 
1447
  def check_api_key_status():
 
1472
 
1473
  # Save API key status
1474
  save_api_status(present_keys, missing_keys, date_of_check)
1475
+
1476
+ st.session_state['present_annotations'] = present_annotations
1477
+ st.session_state['missing_annotations'] = missing_annotations
1478
+ st.session_state['date_of_check'] = date_of_check
1479
 
 
 
1480
 
1481
  def convert_cost_dict_to_table(cost, name):
1482
  # Convert the dictionary to a pandas DataFrame for nicer display
 
1527
 
1528
 
1529
  def content_header():
1530
+ col_logo, col_run_1, col_run_2, col_run_3, col_run_4 = st.columns([2,2,2,2,4])
1531
+ with col_run_4:
1532
+ with st.expander("View Messages and Updates"):
1533
+ st.info("***Note:*** If you use VoucherVision frequently, you can change the default values that are auto-populated in the form below. In a text editor or IDE, edit the first few rows in the file `../VoucherVision/vouchervision/VoucherVision_Config_Builder.py`")
1534
 
1535
 
1536
  col_test = st.container()
 
1614
  if st.session_state['formatted_json']:
1615
  json_report.set_JSON(st.session_state['formatted_json'], st.session_state['formatted_json_WFO'], st.session_state['formatted_json_GEO'])
1616
 
1617
+
 
 
 
1618
 
1619
 
1620
  with col_run_1:
 
1830
  st.header('Available APIs')
1831
 
1832
  # Display API key status
1833
+ display_api_key_status(col_llm_2a)
1834
 
1835
  # Place the button in the second column, right-justified
1836
  # with col_llm_2b:
1837
  if st.button("Re-Check API Keys"):
1838
  st.session_state['API_checked'] = False
1839
  st.session_state['API_rechecked'] = True
1840
+ st.rerun()
1841
  # with col_llm_2c:
1842
  if st.button("Edit API Keys"):
1843
  st.session_state.proceed_to_private = True
 
1882
  st.session_state["demo_collage"] = Image.open(ba)
1883
 
1884
  # Display the image
1885
+ st.image(st.session_state["demo_collage"], caption='LeafMachine2 Collage', output_format="PNG", width=500)
1886
  # st.image(st.session_state["demo_collage"], caption='LeafMachine2 Collage', output_format="JPEG")
1887
 
1888
 
 
1955
  ocr = os.path.join(st.session_state.dir_home,'demo', 'ba','ocr2_low.png')
1956
  st.session_state["demo_overlay"] = Image.open(ocr)
1957
 
1958
+ st.image(st.session_state["demo_overlay"], caption='OCR Overlay Images', output_format = "PNG", width=500)
1959
  # st.image(st.session_state["demo_overlay"], caption='OCR Overlay Images', output_format = "JPEG")
1960
 
1961
 
 
2263
 
2264
  # Parse the 'is_hf' argument and set it in session state
2265
  if 'is_hf' not in st.session_state:
2266
+ st.session_state['is_hf'] = False
2267
 
2268
+
2269
+ #################################################################################################################################################
2270
+ # Initializations ###############################################################################################################################
2271
+ #################################################################################################################################################
2272
+
2273
+
2274
  print(f"is_hf {st.session_state['is_hf']}")
2275
  # Default YAML file path
2276
  if 'config' not in st.session_state:
 
2293
 
2294
  else:
2295
  if 'proceed_to_main' not in st.session_state:
2296
+ st.session_state.proceed_to_main = True # New state variable to control the flow
2297
  print(f"proceed_to_main {st.session_state['proceed_to_main']}")
2298
  if 'private_file' not in st.session_state:
2299
  st.session_state.private_file = does_private_file_exist()
demo/{demo_images/MICH_29667680_Hypericaceae_Hypericum_prolificum.jpg → demo_gallery/MICH_7574789_Cyperaceae_Carex_scoparia.jpg} RENAMED
File without changes
demo/demo_images/MICH_7574789_Cyperaceae_Carex_scoparia.jpg ADDED

Git LFS Details

  • SHA256: 468a97467cd9f15963f122c57dc6816e20aff5bec01c58e5d7e5c53d2abdb7eb
  • Pointer size: 131 Bytes
  • Size of remote file: 788 kB
vouchervision/API_validation.py CHANGED
@@ -77,6 +77,7 @@ class APIvalidation:
77
  response = client.document_text_detection(image=image)
78
  texts = response.text_annotations
79
  normal_cleaned_text = texts[0].description if texts else None
 
80
  else:
81
  logo_path = os.path.join(self.dir_home, 'img','logo.png')
82
  client = vision.ImageAnnotatorClient()
@@ -151,22 +152,22 @@ class APIvalidation:
151
  client = MistralClient(api_key=os.getenv('MISTRAL_API_KEY'))
152
 
153
 
154
- # Initialize the Mistral Client with the API key
155
 
156
- # Create a simple message
157
- messages = [ChatMessage(role="user", content="hello")]
158
 
159
- # Send the message and get the response
160
- chat_response = client.chat(
161
- model="mistral-tiny",
162
- messages=messages,
163
- )
164
 
165
- # Check if the response is valid (adjust this according to the actual response structure)
166
- if chat_response and chat_response.choices:
167
- return True
168
- else:
169
- return False
170
  except Exception as e: # Replace with a more specific exception if possible
171
  return False
172
 
 
77
  response = client.document_text_detection(image=image)
78
  texts = response.text_annotations
79
  normal_cleaned_text = texts[0].description if texts else None
80
+ print(f"OCR TEST: {normal_cleaned_text}")
81
  else:
82
  logo_path = os.path.join(self.dir_home, 'img','logo.png')
83
  client = vision.ImageAnnotatorClient()
 
152
  client = MistralClient(api_key=os.getenv('MISTRAL_API_KEY'))
153
 
154
 
155
+ # Initialize the Mistral Client with the API key
156
 
157
+ # Create a simple message
158
+ messages = [ChatMessage(role="user", content="hello")]
159
 
160
+ # Send the message and get the response
161
+ chat_response = client.chat(
162
+ model="mistral-tiny",
163
+ messages=messages,
164
+ )
165
 
166
+ # Check if the response is valid (adjust this according to the actual response structure)
167
+ if chat_response and chat_response.choices:
168
+ return True
169
+ else:
170
+ return False
171
  except Exception as e: # Replace with a more specific exception if possible
172
  return False
173
 
vouchervision/OCR_google_cloud_vision.py CHANGED
@@ -29,7 +29,9 @@ class OCRGoogle:
29
 
30
  BBOX_COLOR = "black"
31
 
32
- def __init__(self, path, cfg, trOCR_model_version, trOCR_model, trOCR_processor, device):
 
 
33
  self.path = path
34
  self.cfg = cfg
35
  self.do_use_trOCR = self.cfg['leafmachine']['project']['do_use_trOCR']
@@ -67,6 +69,29 @@ class OCRGoogle:
67
  self.trOCR_height = None
68
  self.trOCR_confidences = None
69
  self.trOCR_characters = None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
 
71
  def detect_text_with_trOCR_using_google_bboxes(self, do_use_trOCR, logger):
72
  CONFIDENCES = 0.80
@@ -255,22 +280,11 @@ class OCRGoogle:
255
 
256
 
257
  def detect_text(self):
258
- service_account_json_str = os.getenv('google_service_account_json')
259
- if not service_account_json_str:
260
- print("Service account JSON not found in environment variables.")
261
- return False
262
-
263
- # Convert JSON string to a dictionary
264
- service_account_info = json.loads(service_account_json_str)
265
- # Create credentials from the service account info
266
- credentials = service_account.Credentials.from_service_account_info(service_account_info)
267
- # Initialize the client with the credentials
268
- client = vision.ImageAnnotatorClient(credentials=credentials)
269
- # client = vision.ImageAnnotatorClient() #####################################################################################################################
270
  with io.open(self.path, 'rb') as image_file:
271
  content = image_file.read()
272
  image = vision.Image(content=content)
273
- response = client.document_text_detection(image=image)
274
  texts = response.text_annotations
275
 
276
  if response.error.message:
@@ -381,25 +395,13 @@ class OCRGoogle:
381
 
382
 
383
  def detect_handwritten_ocr(self):
384
- service_account_json_str = os.getenv('google_service_account_json')
385
- if not service_account_json_str:
386
- print("Service account JSON not found in environment variables.")
387
- return False
388
-
389
- # Convert JSON string to a dictionary
390
- service_account_info = json.loads(service_account_json_str)
391
- # Create credentials from the service account info
392
- credentials = service_account.Credentials.from_service_account_info(service_account_info)
393
- # Initialize the client with the credentials
394
- client = vision.ImageAnnotatorClient(credentials=credentials)
395
- # client = vision.ImageAnnotatorClient() #####################################################################################################################
396
 
397
  with open(self.path, "rb") as image_file:
398
  content = image_file.read()
399
 
400
  image = vision_beta.Image(content=content)
401
  image_context = vision_beta.ImageContext(language_hints=["en-t-i0-handwrit"])
402
- response = client.document_text_detection(image=image, image_context=image_context)
403
  texts = response.text_annotations
404
 
405
  if response.error.message:
 
29
 
30
  BBOX_COLOR = "black"
31
 
32
+ def __init__(self, is_hf, path, cfg, trOCR_model_version, trOCR_model, trOCR_processor, device):
33
+ self.is_hf = is_hf
34
+
35
  self.path = path
36
  self.cfg = cfg
37
  self.do_use_trOCR = self.cfg['leafmachine']['project']['do_use_trOCR']
 
69
  self.trOCR_height = None
70
  self.trOCR_confidences = None
71
  self.trOCR_characters = None
72
+ self.set_client()
73
+
74
+
75
+
76
+ def set_client(self):
77
+ if self.is_hf:
78
+ service_account_json_str = os.getenv('google_service_account_json')
79
+ if not service_account_json_str:
80
+ print("Service account JSON not found in environment variables.")
81
+ return False
82
+
83
+ # Convert JSON string to a dictionary
84
+ service_account_info = json.loads(service_account_json_str)
85
+ # Create credentials from the service account info
86
+ credentials = service_account.Credentials.from_service_account_info(service_account_info)
87
+ # Initialize the client with the credentials
88
+ self.client_beta = vision_beta.ImageAnnotatorClient(credentials=credentials)
89
+ self.client = vision.ImageAnnotatorClient(credentials=credentials)
90
+ else:
91
+ self.client_beta = vision_beta.ImageAnnotatorClient()
92
+ self.client = vision.ImageAnnotatorClient()
93
+
94
+
95
 
96
  def detect_text_with_trOCR_using_google_bboxes(self, do_use_trOCR, logger):
97
  CONFIDENCES = 0.80
 
280
 
281
 
282
  def detect_text(self):
283
+
 
 
 
 
 
 
 
 
 
 
 
284
  with io.open(self.path, 'rb') as image_file:
285
  content = image_file.read()
286
  image = vision.Image(content=content)
287
+ response = self.client.document_text_detection(image=image)
288
  texts = response.text_annotations
289
 
290
  if response.error.message:
 
395
 
396
 
397
  def detect_handwritten_ocr(self):
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
  with open(self.path, "rb") as image_file:
400
  content = image_file.read()
401
 
402
  image = vision_beta.Image(content=content)
403
  image_context = vision_beta.ImageContext(language_hints=["en-t-i0-handwrit"])
404
+ response = self.client_beta.document_text_detection(image=image, image_context=image_context)
405
  texts = response.text_annotations
406
 
407
  if response.error.message:
vouchervision/VoucherVision_Config_Builder.py CHANGED
@@ -39,7 +39,7 @@ def build_VV_config(loaded_cfg=None):
39
  OCR_option = 'hand'
40
  check_for_illegal_filenames = False
41
 
42
- LLM_version_user = 'Azure GPT 4 Turbo 1106-preview' #'Azure GPT 4 Turbo 1106-preview'
43
  prompt_version = 'version_5.yaml' # from ["Version 1", "Version 1 No Domain Knowledge", "Version 2"]
44
  use_LeafMachine2_collage_images = True # Use LeafMachine2 collage images
45
  do_create_OCR_helper_image = True
 
39
  OCR_option = 'hand'
40
  check_for_illegal_filenames = False
41
 
42
+ LLM_version_user = 'Azure GPT 3.5 Instruct' #'Azure GPT 4 Turbo 1106-preview'
43
  prompt_version = 'version_5.yaml' # from ["Version 1", "Version 1 No Domain Knowledge", "Version 2"]
44
  use_LeafMachine2_collage_images = True # Use LeafMachine2 collage images
45
  do_create_OCR_helper_image = True
vouchervision/utils_VoucherVision.py CHANGED
@@ -632,7 +632,7 @@ class VoucherVision():
632
  # self.OCR - None
633
 
634
  ### Process_image() runs the OCR for text, handwriting, trOCR AND creates the overlay image
635
- ocr_google = OCRGoogle(self.path_to_crop, self.cfg, self.trOCR_model_version, self.trOCR_model, self.trOCR_processor, self.device)
636
  ocr_google.process_image(self.do_create_OCR_helper_image, self.logger)
637
  self.OCR = ocr_google.OCR
638
 
 
632
  # self.OCR - None
633
 
634
  ### Process_image() runs the OCR for text, handwriting, trOCR AND creates the overlay image
635
+ ocr_google = OCRGoogle(self.is_hf, self.path_to_crop, self.cfg, self.trOCR_model_version, self.trOCR_model, self.trOCR_processor, self.device)
636
  ocr_google.process_image(self.do_create_OCR_helper_image, self.logger)
637
  self.OCR = ocr_google.OCR
638