phyloforfun commited on
Commit
b8abf64
1 Parent(s): fdfdfc3

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
.gitignore CHANGED
@@ -19,6 +19,8 @@ venv_LM2_38/
19
  venv_LM2/
20
  venv_VV/
21
  tests/
 
 
22
  .vscode/
23
  runs/
24
  KP_Test/
 
19
  venv_LM2/
20
  venv_VV/
21
  tests/
22
+ uploads/
23
+ uploads_small/
24
  .vscode/
25
  runs/
26
  KP_Test/
app.py CHANGED
@@ -15,12 +15,30 @@ from vouchervision.vouchervision_main import voucher_vision, voucher_vision_OCR_
15
  from vouchervision.general_utils import test_GPU, get_cfg_from_full_path, summarize_expense_report, create_google_ocr_yaml_config, validate_dir
16
  from vouchervision.model_maps import ModelMaps
17
  from vouchervision.API_validation import APIvalidation
18
- from vouchervision.utils_hf import upload_to_drive, image_to_base64, setup_streamlit_config, save_uploaded_file, check_prompt_yaml_filename
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
 
21
  ########################################################################################################
22
  ### ADDED FOR HUGGING FACE ####
23
  ########################################################################################################
 
 
 
 
 
 
24
  if 'uploader_idk' not in st.session_state:
25
  st.session_state['uploader_idk'] = 1
26
  if 'input_list_small' not in st.session_state:
@@ -31,76 +49,157 @@ if 'user_clicked_load_prompt_yaml' not in st.session_state:
31
  st.session_state['user_clicked_load_prompt_yaml'] = None
32
  if 'new_prompt_yaml_filename' not in st.session_state:
33
  st.session_state['new_prompt_yaml_filename'] = None
 
 
 
 
 
 
 
 
 
 
34
 
35
- MAX_GALLERY_IMAGES = 50
36
- GALLERY_IMAGE_SIZE = 128
37
 
38
 
39
 
40
- def content_input_images_hf():
41
  st.write('---')
42
- col1, col2 = st.columns([2,8])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
 
44
- with col1:
45
- st.header('Run name')
46
- st.session_state.config['leafmachine']['project']['run_name'] = st.text_input("Run name", st.session_state.config['leafmachine']['project'].get('run_name', ''),
47
- label_visibility='collapsed',key=995)
48
- st.write("Run name will be the name of the final zipped folder.")
49
 
50
- st.write('---')
51
- st.header('Input Images')
52
- st.session_state['dir_uploaded_images'] = os.path.join(st.session_state.dir_home,'uploads')
53
- st.session_state['dir_uploaded_images_small'] = os.path.join(st.session_state.dir_home,'uploads_small')
54
- uploaded_files = st.file_uploader("Upload Images", type=['jpg', 'jpeg'], accept_multiple_files=True, key=st.session_state['uploader_idk'])
55
- if uploaded_files:
56
- # Clear input image gallery and input list
57
- clear_image_gallery()
58
-
59
- # Process the new iamges
60
- for uploaded_file in uploaded_files:
61
- file_path = save_uploaded_file(st.session_state['dir_uploaded_images'], uploaded_file)
62
- st.session_state['input_list'].append(file_path)
63
-
64
- img = Image.open(file_path)
65
- img.thumbnail((GALLERY_IMAGE_SIZE, GALLERY_IMAGE_SIZE), Image.Resampling.LANCZOS)
66
- file_path_small = save_uploaded_file(st.session_state['dir_uploaded_images_small'], uploaded_file, img)
67
- st.session_state['input_list_small'].append(file_path_small)
68
- print(uploaded_file.name)
69
-
70
- # Set the local images to the uploaded images
71
- st.session_state.config['leafmachine']['project']['dir_images_local'] = st.session_state['dir_uploaded_images']
72
-
73
- n_images = len([f for f in os.listdir(st.session_state.config['leafmachine']['project']['dir_images_local']) if os.path.isfile(os.path.join(st.session_state.config['leafmachine']['project']['dir_images_local'], f))])
74
- st.session_state['processing_add_on'] = f" {n_images} images"
75
- uploaded_files = None
76
- st.session_state['uploader_idk'] += 1
77
- st.info(f"Processing **{n_images}** images from {st.session_state.config['leafmachine']['project']['dir_images_local']}")
78
-
79
-
80
- st.button("Use Test Image",help="This will clear any uploaded images and load the 1 provided test image.",on_click=use_test_image)
81
-
82
- with col2:
83
- if st.session_state['input_list_small']:
84
- st.subheader('Image Gallery')
85
- if len(st.session_state['input_list_small']) > MAX_GALLERY_IMAGES:
86
- # Only take the first 100 images from the list
87
- images_to_display = st.session_state['input_list_small'][:MAX_GALLERY_IMAGES]
88
- else:
89
- # If there are less than 100 images, take them all
90
- images_to_display = st.session_state['input_list_small']
91
- st.image(images_to_display)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
 
 
 
 
 
 
 
 
 
 
 
93
 
 
 
 
 
 
94
 
 
95
 
96
 
97
  def create_download_button(zip_filepath, col):
98
  with col:
99
- labale_n_images = f"Download Results for{st.session_state['processing_add_on']} Images"
100
  with open(zip_filepath, 'rb') as f:
101
  bytes_io = BytesIO(f.read())
102
  st.download_button(
103
- label=labale_n_images,
104
  type='primary',
105
  data=bytes_io,
106
  file_name=os.path.basename(zip_filepath),
@@ -130,9 +229,17 @@ def use_test_image():
130
  st.info(f"Processing images from {os.path.join(st.session_state.dir_home,'demo','demo_images')}")
131
  st.session_state.config['leafmachine']['project']['dir_images_local'] = os.path.join(st.session_state.dir_home,'demo','demo_images')
132
  n_images = len([f for f in os.listdir(st.session_state.config['leafmachine']['project']['dir_images_local']) if os.path.isfile(os.path.join(st.session_state.config['leafmachine']['project']['dir_images_local'], f))])
133
- st.session_state['processing_add_on'] = f" {n_images} Images"
134
  clear_image_gallery()
135
  st.session_state['uploader_idk'] += 1
 
 
 
 
 
 
 
 
136
 
137
 
138
  def create_download_button_yaml(file_path, selected_yaml_file):
@@ -409,7 +516,7 @@ class JSONReport:
409
 
410
 
411
  def does_private_file_exist():
412
- dir_home = os.path.dirname(os.path.dirname(__file__))
413
  path_cfg_private = os.path.join(dir_home, 'PRIVATE_DATA.yaml')
414
  return os.path.exists(path_cfg_private)
415
 
@@ -613,16 +720,32 @@ def get_prompt_versions(LLM_version):
613
 
614
 
615
  def get_private_file():
616
- dir_home = os.path.dirname(os.path.dirname(__file__))
617
  path_cfg_private = os.path.join(dir_home, 'PRIVATE_DATA.yaml')
618
  return get_cfg_from_full_path(path_cfg_private)
619
 
620
-
621
-
622
- def create_private_file(): #################################################################################### UPDATE
 
 
 
 
 
 
 
 
 
 
 
 
 
 
623
  st.session_state.proceed_to_main = False
624
  st.title("VoucherVision")
625
- col_private,_= st.columns([12,2])
 
 
626
 
627
  if st.session_state.private_file:
628
  cfg_private = get_private_file()
@@ -632,219 +755,219 @@ def create_private_file(): #####################################################
632
  cfg_private['openai']['OPENAI_API_KEY'] =''
633
 
634
  cfg_private['openai_azure'] = {}
635
- cfg_private['openai_azure']['openai_api_key'] = ''
636
- cfg_private['openai_azure']['api_version'] = ''
637
- cfg_private['openai_azure']['openai_api_base'] =''
638
- cfg_private['openai_azure']['openai_organization'] =''
639
- cfg_private['openai_azure']['openai_api_type'] =''
640
-
641
- cfg_private['google_cloud'] = {}
642
- cfg_private['google_cloud']['path_json_file'] =''
643
-
644
- cfg_private['google_palm'] = {}
645
- cfg_private['google_palm']['google_palm_api'] =''
 
 
 
 
 
 
 
 
 
 
646
 
647
 
648
  with col_private:
649
  st.header("Set API keys")
650
- st.info("***Note:*** There is a known bug with tabs in Streamlit. If you update an input field it may take you back to the 'Project Settings' tab. Changes that you made are saved, it's just an annoying glitch. We are aware of this issue and will fix it as soon as we can.")
651
  st.warning("To commit changes to API keys you must press the 'Set API Keys' button at the bottom of the page.")
652
  st.write("Before using VoucherVision you must set your API keys. All keys are stored locally on your computer and are never made public.")
653
  st.write("API keys are stored in `../VoucherVision/PRIVATE_DATA.yaml`.")
654
- st.write("Deleting this file will allow you to reset API keys. Alternatively, you can edit the keys in the user interface.")
655
  st.write("Leave keys blank if you do not intend to use that service.")
656
 
657
  st.write("---")
658
- st.subheader("Google Vision (*Required*)")
659
  st.markdown("VoucherVision currently uses [Google Vision API](https://cloud.google.com/vision/docs/ocr) for OCR. Generating an API key for this is more involved than the others. [Please carefully follow the instructions outlined here to create and setup your account.](https://cloud.google.com/vision/docs/setup) ")
660
- st.markdown("""
661
- Once your account is created, [visit this page](https://console.cloud.google.com) and create a project. Then follow these instructions:
662
-
663
- - **Select your Project**: If you have multiple projects, ensure you select the one where you've enabled the Vision API.
664
- - **Open the Navigation Menu**: Click on the hamburger menu (three horizontal lines) in the top left corner.
665
- - **Go to IAM & Admin**: In the navigation pane, hover over "IAM & Admin" and then click on "Service accounts."
666
- - **Locate Your Service Account**: Find the service account for which you wish to download the JSON key. If you haven't created a service account yet, you'll need to do so by clicking the "CREATE SERVICE ACCOUNT" button at the top.
667
- - **Download the JSON Key**:
668
- - Click on the three dots (actions menu) on the right side of your service account name.
669
- - Select "Manage keys."
670
- - In the pop-up window, click on the "ADD KEY" button and select "JSON."
671
- - The JSON key file will automatically be downloaded to your computer.
672
- - **Store Safely**: This file contains sensitive data that can be used to authenticate and bill your Google Cloud account. Never commit it to public repositories or expose it in any way. Always keep it safe and secure.
673
- """)
674
- with st.container():
675
- c_in_ocr, c_button_ocr = st.columns([10,2])
676
- with c_in_ocr:
677
- google_vision = st.text_input(label = 'Full path to Google Cloud JSON API key file', value = cfg_private['google_cloud'].get('path_json_file', ''),
678
- placeholder = 'e.g. C:/Documents/Secret_Files/google_API/application_default_credentials.json',
679
- help ="This API Key is in the form of a JSON file. Please save the JSON file in a safe directory. DO NOT store the JSON key inside of the VoucherVision directory.",
680
- type='password',key='924857298734590283750932809238')
681
- with c_button_ocr:
682
- st.empty()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
 
684
 
685
  st.write("---")
686
  st.subheader("OpenAI")
687
  st.markdown("API key for first-party OpenAI API. Create an account with OpenAI [here](https://platform.openai.com/signup), then create an API key [here](https://platform.openai.com/account/api-keys).")
688
- with st.container():
689
- c_in_openai, c_button_openai = st.columns([10,2])
690
- with c_in_openai:
691
- openai_api_key = st.text_input("openai_api_key", cfg_private['openai'].get('OPENAI_API_KEY', ''),
692
  help='The actual API key. Likely to be a string of 2 character, a dash, and then a 48-character string: sk-XXXXXXXX...',
693
  placeholder = 'e.g. sk-XXXXXXXX...',
694
  type='password')
695
- with c_button_openai:
696
- st.empty()
697
 
698
  st.write("---")
699
  st.subheader("OpenAI - Azure")
700
  st.markdown("This version OpenAI relies on Azure servers directly as is intended for private enterprise instances of OpenAI's services, such as [UM-GPT](https://its.umich.edu/computing/ai). Administrators will provide you with the following information.")
701
- azure_openai_api_version = st.text_input("azure_openai_api_version", cfg_private['openai_azure'].get('api_version', ''),
702
  help='API Version e.g. "2023-05-15"',
703
  placeholder = 'e.g. 2023-05-15',
704
  type='password')
705
- azure_openai_api_key = st.text_input("azure_openai_api_key", cfg_private['openai_azure'].get('openai_api_key', ''),
706
- help='The actual API key. Likely to be a 32-character string',
707
  placeholder = 'e.g. 12333333333333333333333333333332',
708
  type='password')
709
- azure_openai_api_base = st.text_input("azure_openai_api_base", cfg_private['openai_azure'].get('openai_api_base', ''),
710
  help='The base url for the API e.g. "https://api.umgpt.umich.edu/azure-openai-api"',
711
  placeholder = 'e.g. https://api.umgpt.umich.edu/azure-openai-api',
712
  type='password')
713
- azure_openai_organization = st.text_input("azure_openai_organization", cfg_private['openai_azure'].get('openai_organization', ''),
714
- help='Your organization code. Likely a short string',
715
  placeholder = 'e.g. 123456',
716
  type='password')
717
- azure_openai_api_type = st.text_input("azure_openai_api_type", cfg_private['openai_azure'].get('openai_api_type', ''),
718
  help='The API type. Typically "azure"',
719
  placeholder = 'e.g. azure',
720
  type='password')
721
- with st.container():
722
- c_in_azure, c_button_azure = st.columns([10,2])
723
- with c_button_azure:
724
- st.empty()
725
-
 
 
 
 
 
 
 
726
  st.write("---")
727
- st.subheader("Google PaLM 2")
728
- st.markdown('Follow these [instructions](https://developers.generativeai.google/tutorials/setup) to generate an API key for PaLM 2. You may need to also activate an account with [MakerSuite](https://makersuite.google.com/app/apikey) and enable "early access."')
729
- with st.container():
730
- c_in_palm, c_button_palm = st.columns([10,2])
731
- with c_in_palm:
732
- google_palm = st.text_input("Google PaLM 2 API Key", cfg_private['google_palm'].get('google_palm_api', ''),
733
- help='The MakerSuite API key e.g. a 32-character string',
734
  placeholder='e.g. SATgthsykuE64FgrrrrEervr3S4455t_geyDeGq',
735
  type='password')
736
-
737
- with st.container():
738
- with c_button_ocr:
739
- st.write("##")
740
- st.button("Test OCR", on_click=test_API, args=['google_vision',c_in_ocr, cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
741
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm])
742
-
743
- with st.container():
744
- with c_button_openai:
745
- st.write("##")
746
- st.button("Test OpenAI", on_click=test_API, args=['openai',c_in_openai, cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
747
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm])
748
-
749
- with st.container():
750
- with c_button_azure:
751
- st.write("##")
752
- st.button("Test Azure OpenAI", on_click=test_API, args=['azure_openai',c_in_azure, cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
753
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm])
754
 
755
- with st.container():
756
- with c_button_palm:
757
- st.write("##")
758
- st.button("Test PaLM 2", on_click=test_API, args=['palm',c_in_palm, cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
759
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm])
 
 
 
 
 
 
 
 
760
 
761
 
762
  st.button("Set API Keys",type='primary', on_click=save_changes_to_API_keys, args=[cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
763
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm])
 
 
764
  if st.button('Proceed to VoucherVision'):
 
765
  st.session_state.proceed_to_private = False
766
  st.session_state.proceed_to_main = True
767
-
768
- def test_API(api, message_loc, cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key, azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm):
769
- # Save the API keys
770
- save_changes_to_API_keys(cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm)
771
-
772
- with st.spinner('Performing validation checks...'):
773
- if api == 'google_vision':
774
- print("*** Google Vision OCR API Key ***")
775
- try:
776
- demo_config_path = os.path.join(st.session_state.dir_home,'demo','validation_configs','google_vision_ocr_test.yaml')
777
- demo_images_path = os.path.join(st.session_state.dir_home, 'demo', 'demo_images')
778
- demo_out_path = os.path.join(st.session_state.dir_home, 'demo', 'demo_output','run_name')
779
- create_google_ocr_yaml_config(demo_config_path, demo_images_path, demo_out_path)
780
- voucher_vision_OCR_test(demo_config_path, st.session_state.dir_home, None, demo_images_path)
781
- with message_loc:
782
- st.success("Google Vision OCR API Key Valid :white_check_mark:")
783
- return True
784
- except Exception as e:
785
- with message_loc:
786
- st.error(f"Google Vision OCR API Key Failed! {e}")
787
- return False
788
-
789
- elif api == 'openai':
790
- print("*** OpenAI API Key ***")
791
- try:
792
- if run_api_tests('openai'):
793
- with message_loc:
794
- st.success("OpenAI API Key Valid :white_check_mark:")
795
- else:
796
- with message_loc:
797
- st.error("OpenAI API Key Failed:exclamation:")
798
- return False
799
- except Exception as e:
800
- with message_loc:
801
- st.error(f"OpenAI API Key Failed:exclamation: {e}")
802
-
803
- elif api == 'azure_openai':
804
- print("*** Azure OpenAI API Key ***")
805
- try:
806
- if run_api_tests('azure_openai'):
807
- with message_loc:
808
- st.success("Azure OpenAI API Key Valid :white_check_mark:")
809
- else:
810
- with message_loc:
811
- st.error(f"Azure OpenAI API Key Failed:exclamation:")
812
- return False
813
- except Exception as e:
814
- with message_loc:
815
- st.error(f"Azure OpenAI API Key Failed:exclamation: {e}")
816
- elif api == 'palm':
817
- print("*** Google PaLM 2 API Key ***")
818
- try:
819
- if run_api_tests('palm'):
820
- with message_loc:
821
- st.success("Google PaLM 2 API Key Valid :white_check_mark:")
822
- else:
823
- with message_loc:
824
- st.error("Google PaLM 2 API Key Failed:exclamation:")
825
- return False
826
- except Exception as e:
827
- with message_loc:
828
- st.error(f"Google PaLM 2 API Key Failed:exclamation: {e}")
829
 
830
 
831
  def save_changes_to_API_keys(cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
832
- azure_openai_api_base,azure_openai_organization,azure_openai_api_type,google_vision,google_palm): ######################################## UPDATE
 
 
 
833
  # Update the configuration dictionary with the new values
834
  cfg_private['openai']['OPENAI_API_KEY'] = openai_api_key
835
 
836
- cfg_private['openai_azure']['api_version'] = azure_openai_api_version
837
- cfg_private['openai_azure']['openai_api_key'] = azure_openai_api_key
838
- cfg_private['openai_azure']['openai_api_base'] = azure_openai_api_base
839
- cfg_private['openai_azure']['openai_organization'] = azure_openai_organization
840
- cfg_private['openai_azure']['openai_api_type'] = azure_openai_api_type
 
 
 
 
841
 
842
- cfg_private['google']['GOOGLE_APPLICATION_CREDENTIALS'] = google_vision
843
 
844
- cfg_private['google']['GOOGLE_PALM_API'] = google_palm
 
845
  # Call the function to write the updated configuration to the YAML file
846
  write_config_file(cfg_private, st.session_state.dir_home, filename="PRIVATE_DATA.yaml")
847
- st.session_state.private_file = does_private_file_exist()
848
 
849
  # Function to load a YAML file and update session_state
850
  def load_prompt_yaml(filename):
@@ -1588,14 +1711,18 @@ def content_header():
1588
  # st.subheader('Run VoucherVision')
1589
  N_STEPS = 6
1590
 
1591
- count_n_imgs = determine_n_images()
1592
- if count_n_imgs > 0:
1593
- st.session_state['processing_add_on'] = f" {count_n_imgs} Images"
1594
- else:
1595
- st.session_state['processing_add_on'] = ''
 
1596
 
1597
  if check_if_usable(is_hf=st.session_state['is_hf']):
1598
- if st.button(f"Start Processing{st.session_state['processing_add_on']}", type='primary',use_container_width=True):
 
 
 
1599
  st.session_state['formatted_json'] = {}
1600
  st.session_state['formatted_json_WFO'] = {}
1601
  st.session_state['formatted_json_GEO'] = {}
@@ -1750,28 +1877,16 @@ def content_header():
1750
 
1751
 
1752
 
1753
- def content_project_settings():
1754
-
1755
- st.header('Project Settings')
1756
- col_project_1, col_project_2 = st.columns([11,1])
1757
- ### Project
1758
- with col_project_1:
1759
  st.session_state.config['leafmachine']['project']['run_name'] = st.text_input("Run name", st.session_state.config['leafmachine']['project'].get('run_name', ''),key=63456)
1760
  st.session_state.config['leafmachine']['project']['dir_output'] = st.text_input("Output directory", st.session_state.config['leafmachine']['project'].get('dir_output', ''))
1761
-
1762
-
1763
-
1764
- def content_input_images():
1765
- st.header('Input Images')
1766
- col_local_1, col_local_2 = st.columns([11,1])
1767
- with col_local_1:
1768
- ### Input Images Local
1769
- st.session_state.config['leafmachine']['project']['dir_images_local'] = st.text_input("Input images directory", st.session_state.config['leafmachine']['project'].get('dir_images_local', ''))
1770
- st.session_state.config['leafmachine']['project']['continue_run_from_partial_xlsx'] = st.text_input("Continue run from partially completed project XLSX", st.session_state.config['leafmachine']['project'].get('continue_run_from_partial_xlsx', ''), disabled=True)
1771
 
1772
 
1773
 
1774
-
1775
  def content_llm_cost():
1776
  st.write("---")
1777
  st.header('LLM Cost Calculator')
@@ -1881,10 +1996,11 @@ def content_api_check():
1881
  st.session_state['API_rechecked'] = True
1882
  st.rerun()
1883
  # with col_llm_2c:
1884
- if st.button("Edit API Keys"):
1885
- st.session_state.proceed_to_private = True
1886
- st.rerun()
1887
-
 
1888
 
1889
 
1890
 
@@ -1940,8 +2056,7 @@ def content_collage_overlay():
1940
  st.session_state.config['leafmachine']['do_create_OCR_helper_image'] = do_create_OCR_helper_image
1941
 
1942
 
1943
- do_use_trOCR = st.checkbox("Supplement Google Vision OCR with trOCR (handwriting OCR) via 'microsoft/trocr-large-handwritten'", value=st.session_state.config['leafmachine']['project']['do_use_trOCR'],disabled=st.session_state['lacks_GPU'])
1944
- st.session_state.config['leafmachine']['project']['do_use_trOCR'] = do_use_trOCR
1945
 
1946
  # Get the current OCR option from session state
1947
  OCR_option = st.session_state.config['leafmachine']['project']['OCR_option']
@@ -1972,6 +2087,11 @@ def content_collage_overlay():
1972
  OCR_option = 'both'
1973
  else:
1974
  raise
 
 
 
 
 
1975
 
1976
  st.session_state.config['leafmachine']['project']['OCR_option'] = OCR_option
1977
  st.markdown("Below is an example of what the LLM would see given the choice of OCR ensemble. One, two, or three version of OCR can be fed into the LLM prompt. Typically, 'printed + handwritten' works well. If you have a GPU then you can enable trOCR.")
@@ -2267,19 +2387,21 @@ def main():
2267
  content_header()
2268
 
2269
 
 
 
 
2270
 
2271
- if st.session_state['is_hf']:
2272
- content_project_settings()
2273
- content_input_images_hf()
2274
- else:
2275
- col1, col2 = st.columns([1,1])
2276
- with col1:
2277
- content_project_settings()
2278
- with col2:
2279
- content_input_images()
2280
 
2281
 
2282
- st.write("---")
2283
  col3, col4 = st.columns([1,1])
2284
  with col3:
2285
  content_prompt_and_llm_version()
@@ -2295,15 +2417,7 @@ def main():
2295
 
2296
 
2297
 
2298
- #################################################################################################################################################
2299
- # Initializations ###############################################################################################################################
2300
- #################################################################################################################################################
2301
-
2302
- st.set_page_config(layout="wide", page_icon='img/icon.ico', page_title='VoucherVision')
2303
 
2304
- # Parse the 'is_hf' argument and set it in session state
2305
- if 'is_hf' not in st.session_state:
2306
- st.session_state['is_hf'] = True
2307
 
2308
 
2309
  #################################################################################################################################################
@@ -2311,47 +2425,42 @@ if 'is_hf' not in st.session_state:
2311
  #################################################################################################################################################
2312
 
2313
 
2314
- print(f"is_hf {st.session_state['is_hf']}")
2315
- # Default YAML file path
2316
- if 'config' not in st.session_state:
2317
- st.session_state.config, st.session_state.dir_home = build_VV_config(loaded_cfg=None)
2318
- setup_streamlit_config(st.session_state.dir_home)
2319
 
2320
 
2321
  if st.session_state['is_hf']:
2322
  if 'proceed_to_main' not in st.session_state:
2323
  st.session_state.proceed_to_main = True
2324
- print(f"proceed_to_main {st.session_state['proceed_to_main']}")
2325
 
2326
  if 'proceed_to_private' not in st.session_state:
2327
  st.session_state.proceed_to_private = False
2328
- print(f"proceed_to_private {st.session_state['proceed_to_private']}")
2329
 
2330
  if 'private_file' not in st.session_state:
2331
  st.session_state.private_file = True
2332
- print(f"private_file {st.session_state['private_file']}")
2333
 
2334
  else:
2335
  if 'proceed_to_main' not in st.session_state:
2336
- st.session_state.proceed_to_main = True # New state variable to control the flow
2337
- print(f"proceed_to_main {st.session_state['proceed_to_main']}")
2338
  if 'private_file' not in st.session_state:
2339
  st.session_state.private_file = does_private_file_exist()
2340
  if st.session_state.private_file:
2341
  st.session_state.proceed_to_main = True
2342
- print(f"private_file2 {st.session_state['private_file']}")
2343
- print(f"proceed_to_main2 {st.session_state['proceed_to_main']}")
2344
 
2345
  if 'proceed_to_private' not in st.session_state:
2346
  st.session_state.proceed_to_private = False # New state variable to control the flow
2347
- print(f"proceed_to_private2 {st.session_state['proceed_to_private']}")
2348
 
2349
 
2350
  if 'proceed_to_build_llm_prompt' not in st.session_state:
2351
  st.session_state.proceed_to_build_llm_prompt = False # New state variable to control the flow
2352
 
 
2353
  if 'processing_add_on' not in st.session_state:
2354
- st.session_state['processing_add_on'] = ''
 
2355
 
2356
  if 'formatted_json' not in st.session_state:
2357
  st.session_state['formatted_json'] = None
@@ -2360,9 +2469,11 @@ if 'formatted_json_WFO' not in st.session_state:
2360
  if 'formatted_json_GEO' not in st.session_state:
2361
  st.session_state['formatted_json_GEO'] = None
2362
 
 
2363
  if 'lacks_GPU' not in st.session_state:
2364
  st.session_state['lacks_GPU'] = not torch.cuda.is_available()
2365
 
 
2366
  if 'API_key_validation' not in st.session_state:
2367
  st.session_state['API_key_validation'] = False
2368
  if 'present_annotations' not in st.session_state:
@@ -2376,18 +2487,15 @@ if 'API_checked' not in st.session_state:
2376
  if 'API_rechecked' not in st.session_state:
2377
  st.session_state['API_rechecked'] = False
2378
 
 
2379
  if 'json_report' not in st.session_state:
2380
  st.session_state['json_report'] = False
2381
  if 'hold_output' not in st.session_state:
2382
  st.session_state['hold_output'] = False
2383
 
2384
- if 'dir_uploaded_images' not in st.session_state:
2385
- st.session_state['dir_uploaded_images'] = os.path.join(st.session_state.dir_home,'uploads')
2386
- validate_dir(os.path.join(st.session_state.dir_home,'uploads'))
2387
 
2388
- if 'dir_uploaded_images_small' not in st.session_state:
2389
- st.session_state['dir_uploaded_images_small'] = os.path.join(st.session_state.dir_home,'uploads_small')
2390
- validate_dir(os.path.join(st.session_state.dir_home,'uploads_small'))
2391
 
2392
  if 'cost_openai' not in st.session_state:
2393
  st.session_state['cost_openai'] = None
@@ -2400,6 +2508,7 @@ if 'cost_mistral' not in st.session_state:
2400
  if 'cost_local' not in st.session_state:
2401
  st.session_state['cost_local'] = None
2402
 
 
2403
  if 'settings_filename' not in st.session_state:
2404
  st.session_state['settings_filename'] = None
2405
  if 'loaded_settings_filename' not in st.session_state:
@@ -2407,16 +2516,13 @@ if 'loaded_settings_filename' not in st.session_state:
2407
  if 'zip_filepath' not in st.session_state:
2408
  st.session_state['zip_filepath'] = None
2409
 
 
2410
  # Initialize session_state variables if they don't exist
2411
  if 'prompt_info' not in st.session_state:
2412
  st.session_state['prompt_info'] = {}
2413
  if 'rules' not in st.session_state:
2414
  st.session_state['rules'] = {}
2415
- if 'required_fields' not in st.session_state:
2416
- st.session_state['required_fields'] = ['catalogNumber','order','family','scientificName',
2417
- 'scientificNameAuthorship','genus','subgenus','specificEpithet','infraspecificEpithet',
2418
- 'verbatimEventDate','eventDate',
2419
- 'country','stateProvince','county','municipality','locality','decimalLatitude','decimalLongitude','verbatimCoordinates',]
2420
 
2421
  # These are the fields that are in SLTPvA that are not required by another parsing valication function:
2422
  # "identifiedBy": "M.W. Lyon, Jr.",
@@ -2427,7 +2533,11 @@ if 'required_fields' not in st.session_state:
2427
  # "degreeOfEstablishment": "",
2428
  # "minimumElevationInMeters": "",
2429
  # "maximumElevationInMeters": ""
2430
-
 
 
 
 
2431
 
2432
 
2433
  if 'proceed_to_build_llm_prompt' not in st.session_state:
@@ -2441,46 +2551,27 @@ if 'proceed_to_api_keys' not in st.session_state:
2441
  if 'proceed_to_space_saver' not in st.session_state:
2442
  st.session_state.proceed_to_space_saver = False
2443
 
 
2444
  #################################################################################################################################################
2445
  # Main ##########################################################################################################################################
2446
  #################################################################################################################################################
2447
- print(f"proceed_to_main3 {st.session_state['proceed_to_main']}")
2448
- print(f"is_hf3 {st.session_state['is_hf']}")
2449
- print(f"private_file3 {st.session_state['private_file']}")
2450
- print(f"proceed_to_build_llm_prompt3 {st.session_state['proceed_to_build_llm_prompt']}")
2451
- print(f"proceed_to_private3 {st.session_state['proceed_to_private']}")
2452
-
2453
- # if not st.session_state.private_file and not st.session_state['is_hf']:
2454
- # create_private_file()
2455
- # elif st.session_state.proceed_to_build_llm_prompt:
2456
- if st.session_state.proceed_to_build_llm_prompt:
2457
- build_LLM_prompt_config()
2458
- # elif st.session_state.proceed_to_private and not st.session_state['is_hf']:
2459
- # create_private_file()
2460
- elif st.session_state.proceed_to_main:
2461
- main()
2462
-
2463
-
2464
-
2465
-
2466
-
2467
 
2468
 
2469
- # print(f"proceed_to_main3 {st.session_state['proceed_to_main']}")
2470
- # print(f"is_hf3 {st.session_state['is_hf']}")
2471
- # print(f"private_file3 {st.session_state['private_file']}")
2472
- # print(f"proceed_to_build_llm_prompt3 {st.session_state['proceed_to_build_llm_prompt']}")
2473
- # print(f"proceed_to_private3 {st.session_state['proceed_to_private']}")
2474
 
2475
- # # if not st.session_state.private_file and not st.session_state['is_hf']:
2476
- # # create_private_file()
2477
- # # elif st.session_state.proceed_to_build_llm_prompt:
2478
- # if st.session_state.proceed_to_build_llm_prompt:
2479
- # build_LLM_prompt_config()
2480
- # # elif st.session_state.proceed_to_private and not st.session_state['is_hf']:
2481
- # # create_private_file()
2482
- # elif st.session_state.proceed_to_main:
2483
- # main()
2484
 
2485
 
2486
 
 
15
  from vouchervision.general_utils import test_GPU, get_cfg_from_full_path, summarize_expense_report, create_google_ocr_yaml_config, validate_dir
16
  from vouchervision.model_maps import ModelMaps
17
  from vouchervision.API_validation import APIvalidation
18
+ from vouchervision.utils_hf import upload_to_drive, image_to_base64, setup_streamlit_config, save_uploaded_file, check_prompt_yaml_filename, save_uploaded_local
19
+
20
+
21
+
22
+ #################################################################################################################################################
23
+ # Initializations ###############################################################################################################################
24
+ #################################################################################################################################################
25
+
26
+ st.set_page_config(layout="wide", page_icon='img/icon.ico', page_title='VoucherVision')
27
+
28
+ # Parse the 'is_hf' argument and set it in session state
29
+ if 'is_hf' not in st.session_state:
30
+ st.session_state['is_hf'] = True
31
 
32
 
33
  ########################################################################################################
34
  ### ADDED FOR HUGGING FACE ####
35
  ########################################################################################################
36
+ print(f"is_hf {st.session_state['is_hf']}")
37
+ # Default YAML file path
38
+ if 'config' not in st.session_state:
39
+ st.session_state.config, st.session_state.dir_home = build_VV_config(loaded_cfg=None)
40
+ setup_streamlit_config(st.session_state.dir_home)
41
+
42
  if 'uploader_idk' not in st.session_state:
43
  st.session_state['uploader_idk'] = 1
44
  if 'input_list_small' not in st.session_state:
 
49
  st.session_state['user_clicked_load_prompt_yaml'] = None
50
  if 'new_prompt_yaml_filename' not in st.session_state:
51
  st.session_state['new_prompt_yaml_filename'] = None
52
+ if 'view_local_gallery' not in st.session_state:
53
+ st.session_state['view_local_gallery'] = False
54
+ if 'dir_images_local_TEMP' not in st.session_state:
55
+ st.session_state['dir_images_local_TEMP'] = False
56
+ if 'dir_uploaded_images' not in st.session_state:
57
+ st.session_state['dir_uploaded_images'] = os.path.join(st.session_state.dir_home,'uploads')
58
+ validate_dir(os.path.join(st.session_state.dir_home,'uploads'))
59
+ if 'dir_uploaded_images_small' not in st.session_state:
60
+ st.session_state['dir_uploaded_images_small'] = os.path.join(st.session_state.dir_home,'uploads_small')
61
+ validate_dir(os.path.join(st.session_state.dir_home,'uploads_small'))
62
 
63
+ MAX_GALLERY_IMAGES = 20
64
+ GALLERY_IMAGE_SIZE = 96
65
 
66
 
67
 
68
+ def content_input_images(col_left, col_right):
69
  st.write('---')
70
+ # col1, col2 = st.columns([2,8])
71
+ with col_left:
72
+ st.header('Input Images')
73
+ if not st.session_state.is_hf:
74
+
75
+ ### Input Images Local
76
+ st.session_state.config['leafmachine']['project']['dir_images_local'] = st.text_input("Input images directory", st.session_state.config['leafmachine']['project'].get('dir_images_local', ''))
77
+
78
+ st.session_state.config['leafmachine']['project']['continue_run_from_partial_xlsx'] = st.text_input("Continue run from partially completed project XLSX", st.session_state.config['leafmachine']['project'].get('continue_run_from_partial_xlsx', ''), disabled=True)
79
+ else:
80
+ pass
81
+
82
+ with col_left:
83
+ if st.session_state.is_hf:
84
+ st.session_state['dir_uploaded_images'] = os.path.join(st.session_state.dir_home,'uploads')
85
+ st.session_state['dir_uploaded_images_small'] = os.path.join(st.session_state.dir_home,'uploads_small')
86
+ uploaded_files = st.file_uploader("Upload Images", type=['jpg', 'jpeg'], accept_multiple_files=True, key=st.session_state['uploader_idk'])
87
+ st.button("Use Test Image",help="This will clear any uploaded images and load the 1 provided test image.",on_click=use_test_image)
88
+
89
+ with col_right:
90
+ if st.session_state.is_hf:
91
+ if uploaded_files:
92
+ # Clear input image gallery and input list
93
+ clear_image_gallery()
94
 
95
+ # Process the new iamges
96
+ for uploaded_file in uploaded_files:
97
+ file_path = save_uploaded_file(st.session_state['dir_uploaded_images'], uploaded_file)
98
+ st.session_state['input_list'].append(file_path)
 
99
 
100
+ img = Image.open(file_path)
101
+ img.thumbnail((GALLERY_IMAGE_SIZE, GALLERY_IMAGE_SIZE), Image.Resampling.LANCZOS)
102
+ file_path_small = save_uploaded_file(st.session_state['dir_uploaded_images_small'], uploaded_file, img)
103
+ st.session_state['input_list_small'].append(file_path_small)
104
+ print(uploaded_file.name)
105
+
106
+ # Set the local images to the uploaded images
107
+ st.session_state.config['leafmachine']['project']['dir_images_local'] = st.session_state['dir_uploaded_images']
108
+
109
+ n_images = len([f for f in os.listdir(st.session_state.config['leafmachine']['project']['dir_images_local']) if os.path.isfile(os.path.join(st.session_state.config['leafmachine']['project']['dir_images_local'], f))])
110
+ st.session_state['processing_add_on'] = n_images
111
+ uploaded_files = None
112
+ st.session_state['uploader_idk'] += 1
113
+ st.info(f"Processing **{n_images}** images from {st.session_state.config['leafmachine']['project']['dir_images_local']}")
114
+
115
+
116
+
117
+ if st.session_state['input_list_small']:
118
+ if len(st.session_state['input_list_small']) > MAX_GALLERY_IMAGES:
119
+ # Only take the first 100 images from the list
120
+ images_to_display = st.session_state['input_list_small'][:MAX_GALLERY_IMAGES]
121
+ else:
122
+ # If there are less than 100 images, take them all
123
+ images_to_display = st.session_state['input_list_small']
124
+ st.image(images_to_display)
125
+
126
+ else:
127
+ st.session_state['view_local_gallery'] = st.toggle("View Image Gallery",)
128
+
129
+ if st.session_state['view_local_gallery'] and st.session_state['input_list_small'] and (st.session_state['dir_images_local_TEMP'] == st.session_state.config['leafmachine']['project']['dir_images_local']):
130
+ if MAX_GALLERY_IMAGES <= st.session_state['processing_add_on']:
131
+ info_txt = f"Showing {MAX_GALLERY_IMAGES} out of {st.session_state['processing_add_on']} images"
132
+ else:
133
+ info_txt = f"Showing {st.session_state['processing_add_on']} out of {st.session_state['processing_add_on']} images"
134
+ st.info(info_txt)
135
+ try:
136
+ st.image(st.session_state['input_list_small'], width=GALLERY_IMAGE_SIZE)
137
+ except:
138
+ pass
139
+
140
+ elif not st.session_state['view_local_gallery'] and st.session_state['input_list_small'] and (st.session_state['dir_images_local_TEMP'] == st.session_state.config['leafmachine']['project']['dir_images_local']):
141
+ pass
142
+ elif not st.session_state['view_local_gallery'] and not st.session_state['input_list_small'] and (st.session_state['dir_images_local_TEMP'] == st.session_state.config['leafmachine']['project']['dir_images_local']):
143
+ pass
144
+ elif st.session_state['input_list_small'] and (st.session_state['dir_images_local_TEMP'] != st.session_state.config['leafmachine']['project']['dir_images_local']):
145
+ dir_images_local = st.session_state.config['leafmachine']['project']['dir_images_local']
146
+ count_n_imgs = list_jpg_files(dir_images_local)
147
+ st.session_state['processing_add_on'] = count_n_imgs
148
+ # print(st.session_state['processing_add_on'])
149
+ st.session_state['dir_images_local_TEMP'] = st.session_state.config['leafmachine']['project']['dir_images_local']
150
+ print("rerun")
151
+ st.rerun()
152
+
153
+
154
+ def list_jpg_files(directory_path):
155
+ jpg_count = 0
156
+ clear_image_gallery()
157
+ st.session_state['input_list_small'] = []
158
+
159
+ if not os.path.isdir(directory_path):
160
+ return None
161
+
162
+ jpg_count = count_jpg_images(directory_path)
163
+
164
+ jpg_files = []
165
+ for root, dirs, files in os.walk(directory_path):
166
+ for file in files:
167
+ if file.lower().endswith('.jpg'):
168
+ jpg_files.append(os.path.join(root, file))
169
+ if len(jpg_files) == MAX_GALLERY_IMAGES:
170
+ break
171
+ if len(jpg_files) == MAX_GALLERY_IMAGES:
172
+ break
173
+
174
+ for simg in jpg_files:
175
 
176
+ simg2 = Image.open(simg)
177
+ simg2.thumbnail((GALLERY_IMAGE_SIZE, GALLERY_IMAGE_SIZE), Image.Resampling.LANCZOS)
178
+ file_path_small = save_uploaded_local(st.session_state['dir_uploaded_images_small'], simg, simg2)
179
+ st.session_state['input_list_small'].append(file_path_small)
180
+ return jpg_count
181
+
182
+
183
+ def count_jpg_images(directory_path):
184
+ if not os.path.isdir(directory_path):
185
+ return None
186
 
187
+ jpg_count = 0
188
+ for root, dirs, files in os.walk(directory_path):
189
+ for file in files:
190
+ if file.lower().endswith('.jpg'):
191
+ jpg_count += 1
192
 
193
+ return jpg_count
194
 
195
 
196
  def create_download_button(zip_filepath, col):
197
  with col:
198
+ labal_n_images = f"Download Results for {st.session_state['processing_add_on']} Images"
199
  with open(zip_filepath, 'rb') as f:
200
  bytes_io = BytesIO(f.read())
201
  st.download_button(
202
+ label=labal_n_images,
203
  type='primary',
204
  data=bytes_io,
205
  file_name=os.path.basename(zip_filepath),
 
229
  st.info(f"Processing images from {os.path.join(st.session_state.dir_home,'demo','demo_images')}")
230
  st.session_state.config['leafmachine']['project']['dir_images_local'] = os.path.join(st.session_state.dir_home,'demo','demo_images')
231
  n_images = len([f for f in os.listdir(st.session_state.config['leafmachine']['project']['dir_images_local']) if os.path.isfile(os.path.join(st.session_state.config['leafmachine']['project']['dir_images_local'], f))])
232
+ st.session_state['processing_add_on'] = n_images
233
  clear_image_gallery()
234
  st.session_state['uploader_idk'] += 1
235
+ for file in os.listdir(st.session_state.config['leafmachine']['project']['dir_images_local']):
236
+ file_path = save_uploaded_file(os.path.join(st.session_state.dir_home,'demo','demo_images'), file)
237
+ st.session_state['input_list'].append(file_path)
238
+
239
+ img = Image.open(file_path)
240
+ img.thumbnail((GALLERY_IMAGE_SIZE, GALLERY_IMAGE_SIZE), Image.Resampling.LANCZOS)
241
+ file_path_small = save_uploaded_file(st.session_state['dir_uploaded_images_small'], file, img)
242
+ st.session_state['input_list_small'].append(file_path_small)
243
 
244
 
245
  def create_download_button_yaml(file_path, selected_yaml_file):
 
516
 
517
 
518
  def does_private_file_exist():
519
+ dir_home = os.path.dirname(__file__)
520
  path_cfg_private = os.path.join(dir_home, 'PRIVATE_DATA.yaml')
521
  return os.path.exists(path_cfg_private)
522
 
 
720
 
721
 
722
  def get_private_file():
723
+ dir_home = os.path.dirname(__file__)
724
  path_cfg_private = os.path.join(dir_home, 'PRIVATE_DATA.yaml')
725
  return get_cfg_from_full_path(path_cfg_private)
726
 
727
+ def blog_text_and_image(text=None, fullpath=None, width=700):
728
+ if text:
729
+ st.markdown(f"{text}")
730
+ if fullpath:
731
+ st.session_state.logo = Image.open(fullpath)
732
+ st.image(st.session_state.logo, width=width)
733
+
734
+ def blog_text(text_bold, text):
735
+ st.markdown(f"- **{text_bold}**{text}")
736
+ def blog_text_plain(text_bold, text):
737
+ st.markdown(f"**{text_bold}** {text}")
738
+
739
+ def create_private_file():
740
+ section_left = 2
741
+ section_mid = 6
742
+ section_right = 2
743
+
744
  st.session_state.proceed_to_main = False
745
  st.title("VoucherVision")
746
+ _, col_private,__= st.columns([section_left,section_mid, section_right])
747
+
748
+
749
 
750
  if st.session_state.private_file:
751
  cfg_private = get_private_file()
 
755
  cfg_private['openai']['OPENAI_API_KEY'] =''
756
 
757
  cfg_private['openai_azure'] = {}
758
+ cfg_private['openai_azure']['OPENAI_API_KEY_AZURE'] = ''
759
+ cfg_private['openai_azure']['OPENAI_API_VERSION'] = ''
760
+ cfg_private['openai_azure']['OPENAI_API_BASE'] =''
761
+ cfg_private['openai_azure']['OPENAI_ORGANIZATION'] =''
762
+ cfg_private['openai_azure']['OPENAI_API_TYPE'] =''
763
+
764
+ cfg_private['google'] = {}
765
+ cfg_private['google']['GOOGLE_APPLICATION_CREDENTIALS'] =''
766
+ cfg_private['google']['GOOGLE_PALM_API'] =''
767
+ cfg_private['google']['GOOGLE_PROJECT_ID'] =''
768
+ cfg_private['google']['GOOGLE_LOCATION'] =''
769
+
770
+ cfg_private['mistral'] = {}
771
+ cfg_private['mistral']['MISTRAL_API_KEY'] =''
772
+
773
+ cfg_private['here'] = {}
774
+ cfg_private['here']['APP_ID'] =''
775
+ cfg_private['here']['API_KEY'] =''
776
+
777
+ cfg_private['open_cage_geocode'] = {}
778
+ cfg_private['open_cage_geocode']['API_KEY'] =''
779
 
780
 
781
  with col_private:
782
  st.header("Set API keys")
 
783
  st.warning("To commit changes to API keys you must press the 'Set API Keys' button at the bottom of the page.")
784
  st.write("Before using VoucherVision you must set your API keys. All keys are stored locally on your computer and are never made public.")
785
  st.write("API keys are stored in `../VoucherVision/PRIVATE_DATA.yaml`.")
786
+ st.write("Deleting this file will allow you to reset API keys. Alternatively, you can edit the keys in the user interface or by manually editing the `.yaml` file in a text editor.")
787
  st.write("Leave keys blank if you do not intend to use that service.")
788
 
789
  st.write("---")
790
+ st.subheader("Google Vision (*Required*) / Google PaLM 2 / Google Gemini")
791
  st.markdown("VoucherVision currently uses [Google Vision API](https://cloud.google.com/vision/docs/ocr) for OCR. Generating an API key for this is more involved than the others. [Please carefully follow the instructions outlined here to create and setup your account.](https://cloud.google.com/vision/docs/setup) ")
792
+ st.markdown("""Once your account is created, [visit this page](https://console.cloud.google.com) and create a project. Then follow these instructions:""")
793
+
794
+ with st.expander("**View Google API Instructions**"):
795
+
796
+ blog_text_and_image(text="Select your project, then in the search bar, search for `vertex ai` and select the option in the photo below.",
797
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_00.png'))
798
+
799
+ blog_text_and_image(text="On the main overview page, click `Enable All Recommended APIs`. Sometimes this button may be hidden. In that case, enable all of the suggested APIs listed on this page.",
800
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_0.png'))
801
+
802
+ blog_text_and_image(text="Sometimes this button may be hidden. In that case, enable all of the suggested APIs listed on this page.",
803
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_2.png'))
804
+
805
+ blog_text_and_image(text="Make sure that all APIs are enabled.",
806
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_1.png'))
807
+
808
+ blog_text_and_image(text="Find the `Vision AI API` service and go to its page.",
809
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_3.png'))
810
+
811
+ blog_text_and_image(text="Find the `Vision AI API` service and go to its page. This is the API service required to use OCR in VoucherVision and must be enabled.",
812
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_6.png'))
813
+
814
+ blog_text_and_image(text="You can also search for the Vertex AI Vision service.",
815
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_4.png'))
816
+
817
+ blog_text_and_image(text=None,
818
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_5.png'))
819
+
820
+ st.subheader("Getting a Google JSON authentication key")
821
+ st.write("Google uses a JSON file to store additional authentication information. Save this file in a safe, private location and assign the `GOOGLE_APPLICATION_CREDENTIALS` value to the file path. For Hugging Face, copy the contents of the JSON file including the `\{\}` and paste it as the secret value.")
822
+ st.write("To download your JSON key...")
823
+ blog_text_and_image(text="Open the navigation menu. Click on the hamburger menu (three horizontal lines) in the top left corner. Go to IAM & Admin. ",
824
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_7.png'),width=300)
825
+
826
+ blog_text_and_image(text="In the navigation pane, hover over `IAM & Admin` and then click on `Service accounts`.",
827
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_8.png'))
828
+
829
+ blog_text_and_image(text="Find the default Compute Engine service account, select it.",
830
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_9.png'))
831
+
832
+ blog_text_and_image(text="Click `Add Key`.",
833
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_10.png'))
834
+
835
+ blog_text_and_image(text="Select `JSON` and click create. This will download your key. Store this in a safe location. The file path to this safe location is the value that you enter into the `GOOGLE_APPLICATION_CREDENTIALS` value.",
836
+ fullpath=os.path.join(st.session_state.dir_home, 'demo','google','google_api_11.png'))
837
+
838
+ blog_text(text_bold="Store Safely", text=": This file contains sensitive data that can be used to authenticate and bill your Google Cloud account. Never commit it to public repositories or expose it in any way. Always keep it safe and secure.")
839
+
840
+ st.write("Below is an example of the JSON key.")
841
+ st.json({
842
+ "type": "service_account",
843
+ "project_id": "NAME OF YOUR PROJECT",
844
+ "private_key_id": "XXXXXXXXXXXXXXXXXXXXXXXX",
845
+ "private_key": "-----BEGIN PRIVATE KEY-----\naaaaaaaaaaa\n-----END PRIVATE KEY-----\n",
846
+ "client_email": "EMAIL-ADDRESS@developer.gserviceaccount.com",
847
+ "client_id": "ID NUMBER",
848
+ "auth_uri": "https://accounts.google.com/o/oauth2/auth",
849
+ "token_uri": "https://oauth2.googleapis.com/token",
850
+ "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
851
+ "client_x509_cert_url": "A LONG URL",
852
+ "universe_domain": "googleapis.com"
853
+ })
854
+ google_application_credentials = st.text_input(label = 'Full path to Google Cloud JSON API key file', value = cfg_private['google'].get('GOOGLE_APPLICATION_CREDENTIALS', ''),
855
+ placeholder = 'e.g. C:/Documents/Secret_Files/google_API/application_default_credentials.json',
856
+ help ="This API Key is in the form of a JSON file. Please save the JSON file in a safe directory. DO NOT store the JSON key inside of the VoucherVision directory.",
857
+ type='password')
858
+ google_project_location = st.text_input(label = 'Google project location', value = cfg_private['google'].get('GOOGLE_LOCATION', ''),
859
+ placeholder = 'e.g. us-central1',
860
+ help ="This is the location of where your Google services are operating.",
861
+ type='password')
862
+ google_project_id = st.text_input(label = 'Google project ID', value = cfg_private['google'].get('GOOGLE_PROJECT_ID', ''),
863
+ placeholder = 'e.g. my-project-name',
864
+ help ="This is the value in the `project_id` field in your JSON key.",
865
+ type='password')
866
 
867
 
868
  st.write("---")
869
  st.subheader("OpenAI")
870
  st.markdown("API key for first-party OpenAI API. Create an account with OpenAI [here](https://platform.openai.com/signup), then create an API key [here](https://platform.openai.com/account/api-keys).")
871
+ openai_api_key = st.text_input("openai_api_key", cfg_private['openai'].get('OPENAI_API_KEY', ''),
 
 
 
872
  help='The actual API key. Likely to be a string of 2 character, a dash, and then a 48-character string: sk-XXXXXXXX...',
873
  placeholder = 'e.g. sk-XXXXXXXX...',
874
  type='password')
875
+
 
876
 
877
  st.write("---")
878
  st.subheader("OpenAI - Azure")
879
  st.markdown("This version OpenAI relies on Azure servers directly as is intended for private enterprise instances of OpenAI's services, such as [UM-GPT](https://its.umich.edu/computing/ai). Administrators will provide you with the following information.")
880
+ azure_openai_api_version = st.text_input("OPENAI_API_VERSION", cfg_private['openai_azure'].get('OPENAI_API_VERSION', ''),
881
  help='API Version e.g. "2023-05-15"',
882
  placeholder = 'e.g. 2023-05-15',
883
  type='password')
884
+ azure_openai_api_key = st.text_input("OPENAI_API_KEY_AZURE", cfg_private['openai_azure'].get('OPENAI_API_KEY_AZURE', ''),
885
+ help='The actual API key. Likely to be a 32-character string. This might also be called "endpoint."',
886
  placeholder = 'e.g. 12333333333333333333333333333332',
887
  type='password')
888
+ azure_openai_api_base = st.text_input("OPENAI_API_BASE", cfg_private['openai_azure'].get('OPENAI_API_BASE', ''),
889
  help='The base url for the API e.g. "https://api.umgpt.umich.edu/azure-openai-api"',
890
  placeholder = 'e.g. https://api.umgpt.umich.edu/azure-openai-api',
891
  type='password')
892
+ azure_openai_organization = st.text_input("OPENAI_ORGANIZATION", cfg_private['openai_azure'].get('OPENAI_ORGANIZATION', ''),
893
+ help='Your organization code. Likely a short string.',
894
  placeholder = 'e.g. 123456',
895
  type='password')
896
+ azure_openai_api_type = st.text_input("OPENAI_API_TYPE", cfg_private['openai_azure'].get('OPENAI_API_TYPE', ''),
897
  help='The API type. Typically "azure"',
898
  placeholder = 'e.g. azure',
899
  type='password')
900
+
901
+ # st.write("---")
902
+ # st.subheader("Google PaLM 2 (Deprecated)")
903
+ # st.write("Plea")
904
+ # st.markdown('Follow these [instructions](https://developers.generativeai.google/tutorials/setup) to generate an API key for PaLM 2. You may need to also activate an account with [MakerSuite](https://makersuite.google.com/app/apikey) and enable "early access." If this is deprecated, then use the full Google API instructions above.')
905
+
906
+ # google_palm = st.text_input("Google PaLM 2 API Key", cfg_private['google'].get('GOOGLE_PALM_API', ''),
907
+ # help='The MakerSuite API key e.g. a 32-character string',
908
+ # placeholder='e.g. SATgthsykuE64FgrrrrEervr3S4455t_geyDeGq',
909
+ # type='password')
910
+
911
+
912
  st.write("---")
913
+ st.subheader("MistralAI")
914
+ st.markdown('Follow these [instructions](https://platform.here.com/sign-up?step=verify-identity) to generate an API key for HERE.')
915
+ mistral_API_KEY = st.text_input("MistralAI API Key", cfg_private['mistral'].get('MISTRAL_API_KEY', ''),
916
+ help='e.g. a 32-character string',
 
 
 
917
  placeholder='e.g. SATgthsykuE64FgrrrrEervr3S4455t_geyDeGq',
918
  type='password')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
919
 
920
+
921
+ st.write("---")
922
+ st.subheader("HERE Geocoding")
923
+ st.markdown('Follow these [instructions](https://platform.here.com/sign-up?step=verify-identity) to generate an API key for HERE.')
924
+ hre_APP_ID = st.text_input("HERE Geocoding App ID", cfg_private['here'].get('APP_ID', ''),
925
+ help='e.g. a 32-character string',
926
+ placeholder='e.g. SATgthsykuE64FgrrrrEervr3S4455t_geyDeGq',
927
+ type='password')
928
+ hre_API_KEY = st.text_input("HERE Geocoding API Key", cfg_private['here'].get('API_KEY', ''),
929
+ help='e.g. a 32-character string',
930
+ placeholder='e.g. SATgthsykuE64FgrrrrEervr3S4455t_geyDeGq',
931
+ type='password')
932
+
933
 
934
 
935
  st.button("Set API Keys",type='primary', on_click=save_changes_to_API_keys, args=[cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
936
+ azure_openai_api_base,azure_openai_organization,azure_openai_api_type,
937
+ google_application_credentials, google_project_location, google_project_id,
938
+ mistral_API_KEY, hre_APP_ID, hre_API_KEY])
939
  if st.button('Proceed to VoucherVision'):
940
+ st.session_state.private_file = does_private_file_exist()
941
  st.session_state.proceed_to_private = False
942
  st.session_state.proceed_to_main = True
943
+ st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
944
 
945
 
946
  def save_changes_to_API_keys(cfg_private,openai_api_key,azure_openai_api_version,azure_openai_api_key,
947
+ azure_openai_api_base,azure_openai_organization,azure_openai_api_type,
948
+ google_application_credentials, google_project_location, google_project_id,
949
+ mistral_API_KEY, hre_APP_ID, hre_API_KEY):
950
+
951
  # Update the configuration dictionary with the new values
952
  cfg_private['openai']['OPENAI_API_KEY'] = openai_api_key
953
 
954
+ cfg_private['openai_azure']['OPENAI_API_VERSION'] = azure_openai_api_version
955
+ cfg_private['openai_azure']['OPENAI_API_KEY_AZURE'] = azure_openai_api_key
956
+ cfg_private['openai_azure']['OPENAI_API_BASE'] = azure_openai_api_base
957
+ cfg_private['openai_azure']['OPENAI_ORGANIZATION'] = azure_openai_organization
958
+ cfg_private['openai_azure']['OPENAI_API_TYPE'] = azure_openai_api_type
959
+
960
+ cfg_private['google']['GOOGLE_APPLICATION_CREDENTIALS'] = google_application_credentials
961
+ cfg_private['google']['GOOGLE_PROJECT_ID'] = google_project_location
962
+ cfg_private['google']['GOOGLE_LOCATION'] = google_project_id
963
 
964
+ cfg_private['mistral']['MISTRAL_API_KEY'] = mistral_API_KEY
965
 
966
+ cfg_private['here']['APP_ID'] = hre_APP_ID
967
+ cfg_private['here']['API_KEY'] = hre_API_KEY
968
  # Call the function to write the updated configuration to the YAML file
969
  write_config_file(cfg_private, st.session_state.dir_home, filename="PRIVATE_DATA.yaml")
970
+ # st.session_state.private_file = does_private_file_exist()
971
 
972
  # Function to load a YAML file and update session_state
973
  def load_prompt_yaml(filename):
 
1711
  # st.subheader('Run VoucherVision')
1712
  N_STEPS = 6
1713
 
1714
+ # if st.session_state.is_hf:
1715
+ # count_n_imgs = determine_n_images()
1716
+ # if count_n_imgs > 0:
1717
+ # st.session_state['processing_add_on'] = count_n_imgs
1718
+ # else:
1719
+ # st.session_state['processing_add_on'] = 0
1720
 
1721
  if check_if_usable(is_hf=st.session_state['is_hf']):
1722
+ b_text = f"Start Processing {st.session_state['processing_add_on']} Images" if st.session_state['processing_add_on'] > 1 else f"Start Processing {st.session_state['processing_add_on']} Image"
1723
+ if st.session_state['processing_add_on'] == 0:
1724
+ b_text = f"Start Processing"
1725
+ if st.button(b_text, type='primary',use_container_width=True):
1726
  st.session_state['formatted_json'] = {}
1727
  st.session_state['formatted_json_WFO'] = {}
1728
  st.session_state['formatted_json_GEO'] = {}
 
1877
 
1878
 
1879
 
1880
+ def content_project_settings(col):
1881
+ ### Project
1882
+ with col:
1883
+ st.header('Project Settings')
1884
+
 
1885
  st.session_state.config['leafmachine']['project']['run_name'] = st.text_input("Run name", st.session_state.config['leafmachine']['project'].get('run_name', ''),key=63456)
1886
  st.session_state.config['leafmachine']['project']['dir_output'] = st.text_input("Output directory", st.session_state.config['leafmachine']['project'].get('dir_output', ''))
 
 
 
 
 
 
 
 
 
 
1887
 
1888
 
1889
 
 
1890
  def content_llm_cost():
1891
  st.write("---")
1892
  st.header('LLM Cost Calculator')
 
1996
  st.session_state['API_rechecked'] = True
1997
  st.rerun()
1998
  # with col_llm_2c:
1999
+ if not st.session_state.is_hf:
2000
+ if st.button("Edit API Keys"):
2001
+ st.session_state.proceed_to_private = True
2002
+ st.rerun()
2003
+
2004
 
2005
 
2006
 
 
2056
  st.session_state.config['leafmachine']['do_create_OCR_helper_image'] = do_create_OCR_helper_image
2057
 
2058
 
2059
+
 
2060
 
2061
  # Get the current OCR option from session state
2062
  OCR_option = st.session_state.config['leafmachine']['project']['OCR_option']
 
2087
  OCR_option = 'both'
2088
  else:
2089
  raise
2090
+
2091
+ st.write("Supplement Google Vision OCR with trOCR (handwriting OCR) using `microsoft/trocr-base-handwritten`. This option requires Google Vision API and a GPU.")
2092
+ do_use_trOCR = st.checkbox("Enable trOCR", value=st.session_state.config['leafmachine']['project']['do_use_trOCR'],disabled=st.session_state['lacks_GPU'])
2093
+ st.session_state.config['leafmachine']['project']['do_use_trOCR'] = do_use_trOCR
2094
+
2095
 
2096
  st.session_state.config['leafmachine']['project']['OCR_option'] = OCR_option
2097
  st.markdown("Below is an example of what the LLM would see given the choice of OCR ensemble. One, two, or three version of OCR can be fed into the LLM prompt. Typically, 'printed + handwritten' works well. If you have a GPU then you can enable trOCR.")
 
2387
  content_header()
2388
 
2389
 
2390
+ col_input, col_gallery = st.columns([4,8])
2391
+ content_project_settings(col_input)
2392
+ content_input_images(col_input, col_gallery)
2393
 
2394
+ # if st.session_state['is_hf']:
2395
+ # content_project_settings()
2396
+ # content_input_images_hf()
2397
+ # else:
2398
+ # col1, col2 = st.columns([1,1])
2399
+ # with col1:
2400
+ # content_project_settings()
2401
+ # with col2:
2402
+ # content_input_images()
2403
 
2404
 
 
2405
  col3, col4 = st.columns([1,1])
2406
  with col3:
2407
  content_prompt_and_llm_version()
 
2417
 
2418
 
2419
 
 
 
 
 
 
2420
 
 
 
 
2421
 
2422
 
2423
  #################################################################################################################################################
 
2425
  #################################################################################################################################################
2426
 
2427
 
2428
+
2429
+
2430
+
 
 
2431
 
2432
 
2433
  if st.session_state['is_hf']:
2434
  if 'proceed_to_main' not in st.session_state:
2435
  st.session_state.proceed_to_main = True
 
2436
 
2437
  if 'proceed_to_private' not in st.session_state:
2438
  st.session_state.proceed_to_private = False
 
2439
 
2440
  if 'private_file' not in st.session_state:
2441
  st.session_state.private_file = True
 
2442
 
2443
  else:
2444
  if 'proceed_to_main' not in st.session_state:
2445
+ st.session_state.proceed_to_main = False # New state variable to control the flow
2446
+
2447
  if 'private_file' not in st.session_state:
2448
  st.session_state.private_file = does_private_file_exist()
2449
  if st.session_state.private_file:
2450
  st.session_state.proceed_to_main = True
 
 
2451
 
2452
  if 'proceed_to_private' not in st.session_state:
2453
  st.session_state.proceed_to_private = False # New state variable to control the flow
2454
+
2455
 
2456
 
2457
  if 'proceed_to_build_llm_prompt' not in st.session_state:
2458
  st.session_state.proceed_to_build_llm_prompt = False # New state variable to control the flow
2459
 
2460
+
2461
  if 'processing_add_on' not in st.session_state:
2462
+ st.session_state['processing_add_on'] = 0
2463
+
2464
 
2465
  if 'formatted_json' not in st.session_state:
2466
  st.session_state['formatted_json'] = None
 
2469
  if 'formatted_json_GEO' not in st.session_state:
2470
  st.session_state['formatted_json_GEO'] = None
2471
 
2472
+
2473
  if 'lacks_GPU' not in st.session_state:
2474
  st.session_state['lacks_GPU'] = not torch.cuda.is_available()
2475
 
2476
+
2477
  if 'API_key_validation' not in st.session_state:
2478
  st.session_state['API_key_validation'] = False
2479
  if 'present_annotations' not in st.session_state:
 
2487
  if 'API_rechecked' not in st.session_state:
2488
  st.session_state['API_rechecked'] = False
2489
 
2490
+
2491
  if 'json_report' not in st.session_state:
2492
  st.session_state['json_report'] = False
2493
  if 'hold_output' not in st.session_state:
2494
  st.session_state['hold_output'] = False
2495
 
 
 
 
2496
 
2497
+
2498
+
 
2499
 
2500
  if 'cost_openai' not in st.session_state:
2501
  st.session_state['cost_openai'] = None
 
2508
  if 'cost_local' not in st.session_state:
2509
  st.session_state['cost_local'] = None
2510
 
2511
+
2512
  if 'settings_filename' not in st.session_state:
2513
  st.session_state['settings_filename'] = None
2514
  if 'loaded_settings_filename' not in st.session_state:
 
2516
  if 'zip_filepath' not in st.session_state:
2517
  st.session_state['zip_filepath'] = None
2518
 
2519
+
2520
  # Initialize session_state variables if they don't exist
2521
  if 'prompt_info' not in st.session_state:
2522
  st.session_state['prompt_info'] = {}
2523
  if 'rules' not in st.session_state:
2524
  st.session_state['rules'] = {}
2525
+
 
 
 
 
2526
 
2527
  # These are the fields that are in SLTPvA that are not required by another parsing valication function:
2528
  # "identifiedBy": "M.W. Lyon, Jr.",
 
2533
  # "degreeOfEstablishment": "",
2534
  # "minimumElevationInMeters": "",
2535
  # "maximumElevationInMeters": ""
2536
+ if 'required_fields' not in st.session_state:
2537
+ st.session_state['required_fields'] = ['catalogNumber','order','family','scientificName',
2538
+ 'scientificNameAuthorship','genus','subgenus','specificEpithet','infraspecificEpithet',
2539
+ 'verbatimEventDate','eventDate',
2540
+ 'country','stateProvince','county','municipality','locality','decimalLatitude','decimalLongitude','verbatimCoordinates',]
2541
 
2542
 
2543
  if 'proceed_to_build_llm_prompt' not in st.session_state:
 
2551
  if 'proceed_to_space_saver' not in st.session_state:
2552
  st.session_state.proceed_to_space_saver = False
2553
 
2554
+
2555
  #################################################################################################################################################
2556
  # Main ##########################################################################################################################################
2557
  #################################################################################################################################################
2558
+ if st.session_state['is_hf']:
2559
+ if st.session_state.proceed_to_build_llm_prompt:
2560
+ build_LLM_prompt_config()
2561
+ elif st.session_state.proceed_to_main:
2562
+ main()
2563
+ else:
2564
+ if not st.session_state.private_file:
2565
+ create_private_file()
2566
+ elif st.session_state.proceed_to_build_llm_prompt:
2567
+ build_LLM_prompt_config()
2568
+ elif st.session_state.proceed_to_private and not st.session_state['is_hf']:
2569
+ create_private_file()
2570
+ elif st.session_state.proceed_to_main:
2571
+ main()
 
 
 
 
 
 
2572
 
2573
 
 
 
 
 
 
2574
 
 
 
 
 
 
 
 
 
 
2575
 
2576
 
2577
 
demo/demo_images/{MICH_7574789_Cyperaceae_Carex_scoparia.jpg → MICH_16205594_Poaceae_Jouvea_pilosa.jpg} RENAMED
File without changes
demo/google/google_api_0.PNG ADDED

Git LFS Details

  • SHA256: e83ab5cf573ae70c16ddf227870cfb2aa88423fd9d205d4968acf58e10497d61
  • Pointer size: 130 Bytes
  • Size of remote file: 53.5 kB
demo/google/google_api_00.PNG ADDED

Git LFS Details

  • SHA256: 90f100092e5d63a94bb85c6c15e050a68372d01c98d785fced2303f36608d0d5
  • Pointer size: 130 Bytes
  • Size of remote file: 27.9 kB
demo/google/google_api_1.PNG ADDED

Git LFS Details

  • SHA256: c59b1c6ed7b6ed61d307fa9793fccaf8bfb9d3fd37e62cb49d868a94553051c7
  • Pointer size: 130 Bytes
  • Size of remote file: 80.3 kB
demo/google/google_api_10.PNG ADDED

Git LFS Details

  • SHA256: 81b4ca037237bdc6c04287896a1ed029b8ee2cb7fde6cc979bb81cde6359159d
  • Pointer size: 130 Bytes
  • Size of remote file: 23.8 kB
demo/google/google_api_11.PNG ADDED

Git LFS Details

  • SHA256: 9b23b47223e38bfa50565b950010deddd614c17db22a0e3e2ff990f2a7c5b005
  • Pointer size: 130 Bytes
  • Size of remote file: 21.1 kB
demo/google/google_api_2.PNG ADDED

Git LFS Details

  • SHA256: 0fc7de7f59b866f2288ce7b5824eca9a0996704790ca1db86b25903578747710
  • Pointer size: 131 Bytes
  • Size of remote file: 111 kB
demo/google/google_api_3.PNG ADDED

Git LFS Details

  • SHA256: 3175e1323d26d142088ef7ecc249dcbcdcd63b1fe73f4ddfc981575e567c01c1
  • Pointer size: 130 Bytes
  • Size of remote file: 93.7 kB
demo/google/google_api_4.PNG ADDED

Git LFS Details

  • SHA256: c14e0a5a98cec6f5127676f40c5feacff34aa2fd60f203e680181f8f1586af79
  • Pointer size: 130 Bytes
  • Size of remote file: 40.1 kB
demo/google/google_api_5.PNG ADDED

Git LFS Details

  • SHA256: f51a69ad3f5c00161c1b8119d575f0bb4ae53b8ff5a9b1690897f925aa96a17c
  • Pointer size: 130 Bytes
  • Size of remote file: 46.3 kB
demo/google/google_api_6.PNG ADDED

Git LFS Details

  • SHA256: 84369b3c091cc36e2eb738a1749daf4b09ea5aed424217bba0dea3774981733f
  • Pointer size: 130 Bytes
  • Size of remote file: 58.9 kB
demo/google/google_api_7.PNG ADDED

Git LFS Details

  • SHA256: ae7b3c1e787a699084e5bd8c7e17e6b696029c7f68a98619e577dd1d752f8270
  • Pointer size: 130 Bytes
  • Size of remote file: 12.6 kB
demo/google/google_api_8.PNG ADDED

Git LFS Details

  • SHA256: 42bc751bd36290970a89dd3097ca99bc1bd83cc75e84f9c88c39276e0a4f43d7
  • Pointer size: 130 Bytes
  • Size of remote file: 17.8 kB
demo/google/google_api_9.PNG ADDED

Git LFS Details

  • SHA256: c945275132d2ff5aeb443fb2c5d354d38f554646d8cb99d42f4ab36630bb5f05
  • Pointer size: 129 Bytes
  • Size of remote file: 4.82 kB
requirements.txt CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
 
run_VoucherVision.py CHANGED
@@ -9,6 +9,8 @@ import os, sys
9
  # st.write("filename:", uploaded_file.name)
10
  # st.write(bytes_data)
11
 
 
 
12
 
13
  def resolve_path(path):
14
  resolved_path = os.path.abspath(os.path.join(os.getcwd(), path))
@@ -29,7 +31,7 @@ if __name__ == "__main__":
29
  # "--server.port=8545",
30
  "--server.port=8546",
31
  # Toggle below for HF vs Local
32
- "--is_hf=1",
33
  # "--is_hf=0",
34
  ]
35
  sys.exit(stcli.main())
 
9
  # st.write("filename:", uploaded_file.name)
10
  # st.write(bytes_data)
11
 
12
+ # pip install protobuf==3.20.0
13
+
14
 
15
  def resolve_path(path):
16
  resolved_path = os.path.abspath(os.path.join(os.getcwd(), path))
 
31
  # "--server.port=8545",
32
  "--server.port=8546",
33
  # Toggle below for HF vs Local
34
+ # "--is_hf=1",
35
  # "--is_hf=0",
36
  ]
37
  sys.exit(stcli.main())
vouchervision/API_validation.py CHANGED
@@ -7,6 +7,9 @@ from vertexai.language_models import TextGenerationModel
7
  from vertexai.preview.generative_models import GenerativeModel
8
  from google.cloud import vision
9
  from google.cloud import vision_v1p3beta1 as vision_beta
 
 
 
10
 
11
  from datetime import datetime
12
  import google.generativeai as genai
@@ -57,7 +60,7 @@ class APIvalidation:
57
  model = AzureChatOpenAI(
58
  deployment_name = 'gpt-35-turbo',#'gpt-35-turbo',
59
  openai_api_version = self.cfg_private['openai_azure']['OPENAI_API_VERSION'],
60
- openai_api_key = self.cfg_private['openai_azure']['OPENAI_API_KEY'],
61
  azure_endpoint = self.cfg_private['openai_azure']['OPENAI_API_BASE'],
62
  openai_organization = self.cfg_private['openai_azure']['OPENAI_ORGANIZATION'],
63
  )
@@ -171,7 +174,8 @@ class APIvalidation:
171
 
172
 
173
  def check_google_vertex_genai_api_key(self):
174
- results = {"palm2": False, "gemini": False}
 
175
 
176
  try:
177
  model = TextGenerationModel.from_pretrained("text-bison@001")
@@ -186,6 +190,24 @@ class APIvalidation:
186
  except Exception as e:
187
  # print(f"palm2 fail2 [{e}]")
188
  print(f"palm2 fail2")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
189
 
190
 
191
  try:
@@ -238,7 +260,7 @@ class APIvalidation:
238
  k_opencage = os.getenv('OPENCAGE_API_KEY')
239
  else:
240
  k_OPENAI_API_KEY = self.cfg_private['openai']['OPENAI_API_KEY']
241
- k_openai_azure = self.cfg_private['openai_azure']['OPENAI_API_VERSION']
242
 
243
  k_project_id = self.cfg_private['google']['GOOGLE_PROJECT_ID']
244
  k_location = self.cfg_private['google']['GOOGLE_LOCATION']
@@ -295,6 +317,10 @@ class APIvalidation:
295
  present_keys.append('Palm2 (Valid)')
296
  else:
297
  present_keys.append('Palm2 (Invalid)')
 
 
 
 
298
  if google_results['gemini']:
299
  present_keys.append('Gemini (Valid)')
300
  else:
 
7
  from vertexai.preview.generative_models import GenerativeModel
8
  from google.cloud import vision
9
  from google.cloud import vision_v1p3beta1 as vision_beta
10
+ # from langchain_google_genai import ChatGoogleGenerativeAI
11
+ from langchain_google_vertexai import VertexAI
12
+
13
 
14
  from datetime import datetime
15
  import google.generativeai as genai
 
60
  model = AzureChatOpenAI(
61
  deployment_name = 'gpt-35-turbo',#'gpt-35-turbo',
62
  openai_api_version = self.cfg_private['openai_azure']['OPENAI_API_VERSION'],
63
+ openai_api_key = self.cfg_private['openai_azure']['OPENAI_API_KEY_AZURE'],
64
  azure_endpoint = self.cfg_private['openai_azure']['OPENAI_API_BASE'],
65
  openai_organization = self.cfg_private['openai_azure']['OPENAI_ORGANIZATION'],
66
  )
 
174
 
175
 
176
  def check_google_vertex_genai_api_key(self):
177
+ results = {"palm2": False, "gemini": False, "palm2_langchain": False}
178
+
179
 
180
  try:
181
  model = TextGenerationModel.from_pretrained("text-bison@001")
 
190
  except Exception as e:
191
  # print(f"palm2 fail2 [{e}]")
192
  print(f"palm2 fail2")
193
+
194
+ try:
195
+ # https://python.langchain.com/docs/integrations/llms/google_vertex_ai_palm
196
+ # os.environ['GOOGLE_API_KEY'] = "AIzaSyAHOH1w1qV7C3jS4W7QFyoaTGUwZIgS5ig"
197
+ # genai.configure(api_key='AIzaSyC8xvu6t9fb5dTah3hpgg_rwwR5G5kianI')
198
+ # model = ChatGoogleGenerativeAI(model="text-bison@001")
199
+ model = VertexAI(model="text-bison@001", max_output_tokens=10)
200
+ response = model.predict("Hello")
201
+ test_response_palm2 = response
202
+ if test_response_palm2:
203
+ results["palm2_langchain"] = True
204
+ print(f"palm2_langchain pass [{test_response_palm2}]")
205
+ else:
206
+ print(f"palm2_langchain fail [{test_response_palm2}]")
207
+
208
+ except Exception as e:
209
+ print(f"palm2 fail2 [{e}]")
210
+ print(f"palm2_langchain fail2")
211
 
212
 
213
  try:
 
260
  k_opencage = os.getenv('OPENCAGE_API_KEY')
261
  else:
262
  k_OPENAI_API_KEY = self.cfg_private['openai']['OPENAI_API_KEY']
263
+ k_openai_azure = self.cfg_private['openai_azure']['OPENAI_API_KEY_AZURE']
264
 
265
  k_project_id = self.cfg_private['google']['GOOGLE_PROJECT_ID']
266
  k_location = self.cfg_private['google']['GOOGLE_LOCATION']
 
317
  present_keys.append('Palm2 (Valid)')
318
  else:
319
  present_keys.append('Palm2 (Invalid)')
320
+ if google_results['palm2_langchain']:
321
+ present_keys.append('Palm2 LangChain (Valid)')
322
+ else:
323
+ present_keys.append('Palm2 LangChain (Invalid)')
324
  if google_results['gemini']:
325
  present_keys.append('Gemini (Valid)')
326
  else:
vouchervision/LLM_GoogleGemini.py CHANGED
@@ -7,6 +7,7 @@ from langchain.schema import HumanMessage
7
  from langchain.prompts import PromptTemplate
8
  from langchain_core.output_parsers import JsonOutputParser
9
  from langchain_google_genai import ChatGoogleGenerativeAI
 
10
 
11
  from vouchervision.utils_LLM import SystemLoadMonitor, count_tokens
12
  from vouchervision.utils_LLM_JSON_validation import validate_and_align_JSON_keys_with_template
@@ -74,9 +75,13 @@ class GoogleGeminiHandler:
74
 
75
  def _build_model_chain_parser(self):
76
  # Instantiate the LLM class for Google Gemini
77
- self.llm_model = ChatGoogleGenerativeAI(model='gemini-pro',
78
- max_output_tokens=self.config.get('max_output_tokens'),
79
- top_p=self.config.get('top_p'))
 
 
 
 
80
  # Set up the retry parser with the runnable
81
  self.retry_parser = RetryWithErrorOutputParser.from_llm(parser=self.parser, llm=self.llm_model, max_retries=self.MAX_RETRIES)
82
  # Prepare the chain
 
7
  from langchain.prompts import PromptTemplate
8
  from langchain_core.output_parsers import JsonOutputParser
9
  from langchain_google_genai import ChatGoogleGenerativeAI
10
+ from langchain_google_vertexai import VertexAI
11
 
12
  from vouchervision.utils_LLM import SystemLoadMonitor, count_tokens
13
  from vouchervision.utils_LLM_JSON_validation import validate_and_align_JSON_keys_with_template
 
75
 
76
  def _build_model_chain_parser(self):
77
  # Instantiate the LLM class for Google Gemini
78
+ # self.llm_model = ChatGoogleGenerativeAI(model='gemini-pro',
79
+ # max_output_tokens=self.config.get('max_output_tokens'),
80
+ # top_p=self.config.get('top_p'))
81
+ self.llm_model = VertexAI(model='gemini-pro',
82
+ max_output_tokens=self.config.get('max_output_tokens'),
83
+ top_p=self.config.get('top_p'))
84
+
85
  # Set up the retry parser with the runnable
86
  self.retry_parser = RetryWithErrorOutputParser.from_llm(parser=self.parser, llm=self.llm_model, max_retries=self.MAX_RETRIES)
87
  # Prepare the chain
vouchervision/LLM_GooglePalm2.py CHANGED
@@ -9,6 +9,7 @@ from langchain.schema import HumanMessage
9
  from langchain.prompts import PromptTemplate
10
  from langchain_core.output_parsers import JsonOutputParser
11
  from langchain_google_genai import ChatGoogleGenerativeAI
 
12
 
13
  from vouchervision.utils_LLM import SystemLoadMonitor, count_tokens
14
  from vouchervision.utils_LLM_JSON_validation import validate_and_align_JSON_keys_with_template
@@ -84,7 +85,8 @@ class GooglePalm2Handler:
84
 
85
  def _build_model_chain_parser(self):
86
  # Instantiate the parser and the retry parser
87
- self.llm_model = ChatGoogleGenerativeAI(model=self.model_name)
 
88
 
89
  self.retry_parser = RetryWithErrorOutputParser.from_llm(
90
  parser=self.parser,
 
9
  from langchain.prompts import PromptTemplate
10
  from langchain_core.output_parsers import JsonOutputParser
11
  from langchain_google_genai import ChatGoogleGenerativeAI
12
+ from langchain_google_vertexai import VertexAI
13
 
14
  from vouchervision.utils_LLM import SystemLoadMonitor, count_tokens
15
  from vouchervision.utils_LLM_JSON_validation import validate_and_align_JSON_keys_with_template
 
85
 
86
  def _build_model_chain_parser(self):
87
  # Instantiate the parser and the retry parser
88
+ # self.llm_model = ChatGoogleGenerativeAI(model=self.model_name)
89
+ self.llm_model = VertexAI(model=self.model_name)
90
 
91
  self.retry_parser = RetryWithErrorOutputParser.from_llm(
92
  parser=self.parser,
vouchervision/OCR_google_cloud_vision.py CHANGED
@@ -77,8 +77,8 @@ class OCRGoogle:
77
  self.client_beta = vision_beta.ImageAnnotatorClient(credentials=self.get_google_credentials())
78
  self.client = vision.ImageAnnotatorClient(credentials=self.get_google_credentials())
79
  else:
80
- self.client_beta = vision_beta.ImageAnnotatorClient()
81
- self.client = vision.ImageAnnotatorClient()
82
 
83
 
84
  def get_google_credentials(self):
@@ -86,7 +86,7 @@ class OCRGoogle:
86
  credentials = service_account.Credentials.from_service_account_info(json.loads(creds_json_str))
87
  return credentials
88
 
89
-
90
  def detect_text_with_trOCR_using_google_bboxes(self, do_use_trOCR, logger):
91
  CONFIDENCES = 0.80
92
  MAX_NEW_TOKENS = 50
@@ -517,6 +517,7 @@ class OCRGoogle:
517
 
518
  ### Optionally add trOCR to the self.OCR for additional context
519
  self.OCR = self.detect_text_with_trOCR_using_google_bboxes(self.do_use_trOCR, logger)
 
520
 
521
  if do_create_OCR_helper_image:
522
  self.image = Image.open(self.path)
 
77
  self.client_beta = vision_beta.ImageAnnotatorClient(credentials=self.get_google_credentials())
78
  self.client = vision.ImageAnnotatorClient(credentials=self.get_google_credentials())
79
  else:
80
+ self.client_beta = vision_beta.ImageAnnotatorClient(credentials=self.get_google_credentials())
81
+ self.client = vision.ImageAnnotatorClient(credentials=self.get_google_credentials())
82
 
83
 
84
  def get_google_credentials(self):
 
86
  credentials = service_account.Credentials.from_service_account_info(json.loads(creds_json_str))
87
  return credentials
88
 
89
+
90
  def detect_text_with_trOCR_using_google_bboxes(self, do_use_trOCR, logger):
91
  CONFIDENCES = 0.80
92
  MAX_NEW_TOKENS = 50
 
517
 
518
  ### Optionally add trOCR to the self.OCR for additional context
519
  self.OCR = self.detect_text_with_trOCR_using_google_bboxes(self.do_use_trOCR, logger)
520
+ logger.info(f"OCR:\n{self.OCR}")
521
 
522
  if do_create_OCR_helper_image:
523
  self.image = Image.open(self.path)
vouchervision/utils_VoucherVision.py CHANGED
@@ -72,14 +72,23 @@ class VoucherVision():
72
 
73
  self.catalog_name_options = ["Catalog Number", "catalog_number", "catalogNumber"]
74
 
75
- self.utility_headers = ["filename",
76
- "WFO_override_OCR", "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_candidate_names","WFO_placement",
 
 
 
 
 
 
 
77
 
78
- "GEO_override_OCR", "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat",
79
- "GEO_decimal_long","GEO_city", "GEO_county", "GEO_state",
80
- "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent",
81
 
82
- "tokens_in", "tokens_out", "path_to_crop","path_to_original","path_to_content","path_to_helper",]
 
 
83
 
84
  self.do_create_OCR_helper_image = self.cfg['leafmachine']['do_create_OCR_helper_image']
85
 
@@ -100,6 +109,7 @@ class VoucherVision():
100
  self.logger.info(f' Model name passed to API --> {self.model_name}')
101
  self.logger.info(f' API access token is found in PRIVATE_DATA.yaml --> {self.has_key}')
102
 
 
103
  def init_trOCR_model(self):
104
  lgr = logging.getLogger('transformers')
105
  lgr.setLevel(logging.ERROR)
@@ -111,13 +121,14 @@ class VoucherVision():
111
  self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
112
  self.trOCR_model.to(self.device)
113
 
 
114
  def map_API_options(self):
115
  self.chat_version = self.cfg['leafmachine']['LLM_version']
116
 
117
  # Get the required values from ModelMaps
118
  self.model_name = ModelMaps.get_version_mapping_cost(self.chat_version)
119
  self.is_azure = ModelMaps.get_version_mapping_is_azure(self.chat_version)
120
- self.has_key = ModelMaps.get_version_has_key(self.chat_version, self.has_key_openai, self.has_key_azure_openai, self.has_key_palm2, self.has_key_mistral)
121
 
122
  # Check if the version is supported
123
  if self.model_name is None:
@@ -126,28 +137,18 @@ class VoucherVision():
126
 
127
  self.version_name = self.chat_version
128
 
 
129
  def map_prompt_versions(self):
130
  self.prompt_version_map = {
131
  "Version 1": "prompt_v1_verbose",
132
- "Version 1 No Domain Knowledge": "prompt_v1_verbose_noDomainKnowledge",
133
- "Version 2": "prompt_v2_json_rules",
134
- "Version 1 PaLM 2": 'prompt_v1_palm2',
135
- "Version 1 PaLM 2 No Domain Knowledge": 'prompt_v1_palm2_noDomainKnowledge',
136
- "Version 2 PaLM 2": 'prompt_v2_palm2',
137
  }
138
  self.prompt_version = self.prompt_version_map.get(self.prompt_version0, self.path_custom_prompts)
139
  self.is_predefined_prompt = self.is_in_prompt_version_map(self.prompt_version)
140
 
 
141
  def is_in_prompt_version_map(self, value):
142
  return value in self.prompt_version_map.values()
143
 
144
- # def init_embeddings(self):
145
- # if self.use_domain_knowledge:
146
- # self.logger.info(f'*** USING DOMAIN KNOWLEDGE ***')
147
- # self.logger.info(f'*** Initializing vector embeddings database ***')
148
- # self.initialize_embeddings()
149
- # else:
150
- # self.Voucher_Vision_Embedding = None
151
 
152
  def map_dir_labels(self):
153
  if self.cfg['leafmachine']['use_RGB_label_images']:
@@ -158,6 +159,7 @@ class VoucherVision():
158
  # Use glob to get all image paths in the directory
159
  self.img_paths = glob.glob(os.path.join(self.dir_labels, "*"))
160
 
 
161
  def load_rules_config(self):
162
  with open(self.path_custom_prompts, 'r') as stream:
163
  try:
@@ -166,6 +168,7 @@ class VoucherVision():
166
  print(exc)
167
  return None
168
 
 
169
  def generate_xlsx_headers(self):
170
  # Extract headers from the 'Dictionary' keys in the JSON template rules
171
  # xlsx_headers = list(self.rules_config_json['rules']["Dictionary"].keys())
@@ -173,21 +176,10 @@ class VoucherVision():
173
  xlsx_headers = xlsx_headers + self.utility_headers
174
  return xlsx_headers
175
 
 
176
  def init_transcription_xlsx(self):
177
- # self.HEADERS_v1_n22 = ["Catalog Number","Genus","Species","subspecies","variety","forma","Country","State","County","Locality Name","Min Elevation","Max Elevation","Elevation Units","Verbatim Coordinates","Datum","Cultivated","Habitat","Collectors","Collector Number","Verbatim Date","Date","End Date"]
178
- # self.HEADERS_v2_n26 = ["catalog_number","genus","species","subspecies","variety","forma","country","state","county","locality_name","min_elevation","max_elevation","elevation_units","verbatim_coordinates","decimal_coordinates","datum","cultivated","habitat","plant_description","collectors","collector_number","determined_by","multiple_names","verbatim_date","date","end_date"]
179
- # self.HEADERS_v1_n22 = self.HEADERS_v1_n22 + self.utility_headers
180
- # self.HEADERS_v2_n26 = self.HEADERS_v2_n26 + self.utility_headers
181
  # Initialize output file
182
  self.path_transcription = os.path.join(self.Dirs.transcription,"transcribed.xlsx")
183
-
184
- # if self.prompt_version in ['prompt_v2_json_rules','prompt_v2_palm2']:
185
- # self.headers = self.HEADERS_v2_n26
186
- # self.headers_used = 'HEADERS_v2_n26'
187
-
188
- # elif self.prompt_version in ['prompt_v1_verbose', 'prompt_v1_verbose_noDomainKnowledge','prompt_v1_palm2', 'prompt_v1_palm2_noDomainKnowledge']:
189
- # self.headers = self.HEADERS_v1_n22
190
- # self.headers_used = 'HEADERS_v1_n22'
191
 
192
  # else:
193
  if not self.is_predefined_prompt:
@@ -223,7 +215,6 @@ class VoucherVision():
223
  except ValueError:
224
  print("'path_to_crop' not found in the header row.")
225
 
226
-
227
  path_to_crop = list(sheet.iter_cols(min_col=path_to_crop_col, max_col=path_to_crop_col, values_only=True, min_row=2))
228
  path_to_original = list(sheet.iter_cols(min_col=path_to_original_col, max_col=path_to_original_col, values_only=True, min_row=2))
229
  path_to_content = list(sheet.iter_cols(min_col=path_to_content_col, max_col=path_to_content_col, values_only=True, min_row=2))
@@ -303,14 +294,8 @@ class VoucherVision():
303
  break
304
 
305
 
306
-
307
  def add_data_to_excel_from_response(self, path_transcription, response, WFO_record, GEO_record, filename_without_extension, path_to_crop, path_to_content, path_to_helper, nt_in, nt_out):
308
- geo_headers = ["GEO_override_OCR", "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat",
309
- "GEO_decimal_long","GEO_city", "GEO_county", "GEO_state",
310
- "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent",]
311
 
312
- # WFO_candidate_names is separate, bc it may be type --> list
313
- wfo_headers = ["WFO_override_OCR", "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_placement"]
314
 
315
  wb = openpyxl.load_workbook(path_transcription)
316
  sheet = wb.active
@@ -376,7 +361,7 @@ class VoucherVision():
376
  sheet.cell(row=next_row, column=i, value=filename_without_extension)
377
 
378
  # "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_candidate_names","WFO_placement"
379
- elif header.value in wfo_headers:
380
  sheet.cell(row=next_row, column=i, value=WFO_record.get(header.value, ''))
381
  # elif header.value == "WFO_exact_match":
382
  # sheet.cell(row=next_row, column=i, value= WFO_record.get("WFO_exact_match",''))
@@ -397,7 +382,7 @@ class VoucherVision():
397
 
398
  # "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat", "GEO_decimal_long",
399
  # "GEO_city", "GEO_county", "GEO_state", "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent"
400
- elif header.value in geo_headers:
401
  sheet.cell(row=next_row, column=i, value=GEO_record.get(header.value, ''))
402
 
403
  # save the workbook
@@ -447,7 +432,7 @@ class VoucherVision():
447
  self.cfg_private = get_cfg_from_full_path(self.path_cfg_private)
448
 
449
  k_openai = self.cfg_private['openai']['OPENAI_API_KEY']
450
- k_openai_azure = self.cfg_private['openai_azure']['OPENAI_API_VERSION']
451
 
452
  k_google_project_id = self.cfg_private['google']['GOOGLE_PROJECT_ID']
453
  k_google_location = self.cfg_private['google']['GOOGLE_LOCATION']
@@ -505,7 +490,7 @@ class VoucherVision():
505
  self.llm = AzureChatOpenAI(
506
  deployment_name = 'gpt-35-turbo',#'gpt-35-turbo',
507
  openai_api_version = self.cfg_private['openai_azure']['OPENAI_API_VERSION'],
508
- openai_api_key = self.cfg_private['openai_azure']['OPENAI_API_KEY'],
509
  azure_endpoint = self.cfg_private['openai_azure']['OPENAI_API_BASE'],
510
  openai_organization = self.cfg_private['openai_azure']['OPENAI_ORGANIZATION'],
511
  )
 
72
 
73
  self.catalog_name_options = ["Catalog Number", "catalog_number", "catalogNumber"]
74
 
75
+ self.geo_headers = ["GEO_override_OCR", "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat",
76
+ "GEO_decimal_long","GEO_city", "GEO_county", "GEO_state",
77
+ "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent",]
78
+
79
+ self.wfo_headers = ["WFO_override_OCR", "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_candidate_names","WFO_placement"]
80
+ self.wfo_headers_no_lists = ["WFO_override_OCR", "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_placement"]
81
+
82
+ self.utility_headers = ["filename"] + self.wfo_headers + self.geo_headers + ["tokens_in", "tokens_out", "path_to_crop","path_to_original","path_to_content","path_to_helper",]
83
+ # "WFO_override_OCR", "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_candidate_names","WFO_placement",
84
 
85
+ # "GEO_override_OCR", "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat",
86
+ # "GEO_decimal_long","GEO_city", "GEO_county", "GEO_state",
87
+ # "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent",
88
 
89
+ # "tokens_in", "tokens_out", "path_to_crop","path_to_original","path_to_content","path_to_helper",]
90
+
91
+ # WFO_candidate_names is separate, bc it may be type --> list
92
 
93
  self.do_create_OCR_helper_image = self.cfg['leafmachine']['do_create_OCR_helper_image']
94
 
 
109
  self.logger.info(f' Model name passed to API --> {self.model_name}')
110
  self.logger.info(f' API access token is found in PRIVATE_DATA.yaml --> {self.has_key}')
111
 
112
+
113
  def init_trOCR_model(self):
114
  lgr = logging.getLogger('transformers')
115
  lgr.setLevel(logging.ERROR)
 
121
  self.device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
122
  self.trOCR_model.to(self.device)
123
 
124
+
125
  def map_API_options(self):
126
  self.chat_version = self.cfg['leafmachine']['LLM_version']
127
 
128
  # Get the required values from ModelMaps
129
  self.model_name = ModelMaps.get_version_mapping_cost(self.chat_version)
130
  self.is_azure = ModelMaps.get_version_mapping_is_azure(self.chat_version)
131
+ self.has_key = ModelMaps.get_version_has_key(self.chat_version, self.has_key_openai, self.has_key_azure_openai, self.has_key_google_application_credentials, self.has_key_mistral)
132
 
133
  # Check if the version is supported
134
  if self.model_name is None:
 
137
 
138
  self.version_name = self.chat_version
139
 
140
+
141
  def map_prompt_versions(self):
142
  self.prompt_version_map = {
143
  "Version 1": "prompt_v1_verbose",
 
 
 
 
 
144
  }
145
  self.prompt_version = self.prompt_version_map.get(self.prompt_version0, self.path_custom_prompts)
146
  self.is_predefined_prompt = self.is_in_prompt_version_map(self.prompt_version)
147
 
148
+
149
  def is_in_prompt_version_map(self, value):
150
  return value in self.prompt_version_map.values()
151
 
 
 
 
 
 
 
 
152
 
153
  def map_dir_labels(self):
154
  if self.cfg['leafmachine']['use_RGB_label_images']:
 
159
  # Use glob to get all image paths in the directory
160
  self.img_paths = glob.glob(os.path.join(self.dir_labels, "*"))
161
 
162
+
163
  def load_rules_config(self):
164
  with open(self.path_custom_prompts, 'r') as stream:
165
  try:
 
168
  print(exc)
169
  return None
170
 
171
+
172
  def generate_xlsx_headers(self):
173
  # Extract headers from the 'Dictionary' keys in the JSON template rules
174
  # xlsx_headers = list(self.rules_config_json['rules']["Dictionary"].keys())
 
176
  xlsx_headers = xlsx_headers + self.utility_headers
177
  return xlsx_headers
178
 
179
+
180
  def init_transcription_xlsx(self):
 
 
 
 
181
  # Initialize output file
182
  self.path_transcription = os.path.join(self.Dirs.transcription,"transcribed.xlsx")
 
 
 
 
 
 
 
 
183
 
184
  # else:
185
  if not self.is_predefined_prompt:
 
215
  except ValueError:
216
  print("'path_to_crop' not found in the header row.")
217
 
 
218
  path_to_crop = list(sheet.iter_cols(min_col=path_to_crop_col, max_col=path_to_crop_col, values_only=True, min_row=2))
219
  path_to_original = list(sheet.iter_cols(min_col=path_to_original_col, max_col=path_to_original_col, values_only=True, min_row=2))
220
  path_to_content = list(sheet.iter_cols(min_col=path_to_content_col, max_col=path_to_content_col, values_only=True, min_row=2))
 
294
  break
295
 
296
 
 
297
  def add_data_to_excel_from_response(self, path_transcription, response, WFO_record, GEO_record, filename_without_extension, path_to_crop, path_to_content, path_to_helper, nt_in, nt_out):
 
 
 
298
 
 
 
299
 
300
  wb = openpyxl.load_workbook(path_transcription)
301
  sheet = wb.active
 
361
  sheet.cell(row=next_row, column=i, value=filename_without_extension)
362
 
363
  # "WFO_exact_match","WFO_exact_match_name","WFO_best_match","WFO_candidate_names","WFO_placement"
364
+ elif header.value in self.wfo_headers_no_lists:
365
  sheet.cell(row=next_row, column=i, value=WFO_record.get(header.value, ''))
366
  # elif header.value == "WFO_exact_match":
367
  # sheet.cell(row=next_row, column=i, value= WFO_record.get("WFO_exact_match",''))
 
382
 
383
  # "GEO_method", "GEO_formatted_full_string", "GEO_decimal_lat", "GEO_decimal_long",
384
  # "GEO_city", "GEO_county", "GEO_state", "GEO_state_code", "GEO_country", "GEO_country_code", "GEO_continent"
385
+ elif header.value in self.geo_headers:
386
  sheet.cell(row=next_row, column=i, value=GEO_record.get(header.value, ''))
387
 
388
  # save the workbook
 
432
  self.cfg_private = get_cfg_from_full_path(self.path_cfg_private)
433
 
434
  k_openai = self.cfg_private['openai']['OPENAI_API_KEY']
435
+ k_openai_azure = self.cfg_private['openai_azure']['OPENAI_API_KEY_AZURE']
436
 
437
  k_google_project_id = self.cfg_private['google']['GOOGLE_PROJECT_ID']
438
  k_google_location = self.cfg_private['google']['GOOGLE_LOCATION']
 
490
  self.llm = AzureChatOpenAI(
491
  deployment_name = 'gpt-35-turbo',#'gpt-35-turbo',
492
  openai_api_version = self.cfg_private['openai_azure']['OPENAI_API_VERSION'],
493
+ openai_api_key = self.cfg_private['openai_azure']['OPENAI_API_KEY_AZURE'],
494
  azure_endpoint = self.cfg_private['openai_azure']['OPENAI_API_BASE'],
495
  openai_organization = self.cfg_private['openai_azure']['OPENAI_ORGANIZATION'],
496
  )
vouchervision/utils_hf.py CHANGED
@@ -42,15 +42,44 @@ def save_uploaded_file(directory, img_file, image=None):
42
  os.makedirs(directory)
43
  # Assuming the uploaded file is an image
44
  if image is None:
45
- with Image.open(img_file) as image:
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  full_path = os.path.join(directory, img_file.name)
47
  image.save(full_path, "JPEG")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  # Return the full path of the saved image
49
- return full_path
50
  else:
51
- full_path = os.path.join(directory, img_file.name)
52
  image.save(full_path, "JPEG")
53
- return full_path
54
 
55
  def image_to_base64(img):
56
  buffered = BytesIO()
 
42
  os.makedirs(directory)
43
  # Assuming the uploaded file is an image
44
  if image is None:
45
+ try:
46
+ with Image.open(img_file) as image:
47
+ full_path = os.path.join(directory, img_file.name)
48
+ image.save(full_path, "JPEG")
49
+ # Return the full path of the saved image
50
+ return full_path
51
+ except:
52
+ with Image.open(os.path.join(directory,img_file)) as image:
53
+ full_path = os.path.join(directory, img_file)
54
+ image.save(full_path, "JPEG")
55
+ # Return the full path of the saved image
56
+ return full_path
57
+ else:
58
+ try:
59
  full_path = os.path.join(directory, img_file.name)
60
  image.save(full_path, "JPEG")
61
+ return full_path
62
+ except:
63
+ full_path = os.path.join(directory, img_file)
64
+ image.save(full_path, "JPEG")
65
+ return full_path
66
+
67
+ def save_uploaded_local(directory, img_file, image=None):
68
+ name = img_file.split(os.path.sep)[-1]
69
+ if not os.path.exists(directory):
70
+ os.makedirs(directory)
71
+
72
+ # Assuming the uploaded file is an image
73
+ if image is None:
74
+ with Image.open(img_file) as image:
75
+ full_path = os.path.join(directory, name)
76
+ image.save(full_path, "JPEG")
77
  # Return the full path of the saved image
78
+ return os.path.join('uploads_small',name)
79
  else:
80
+ full_path = os.path.join(directory, name)
81
  image.save(full_path, "JPEG")
82
+ return os.path.join('.','uploads_small',name)
83
 
84
  def image_to_base64(img):
85
  buffered = BytesIO()