saulsolis09 commited on
Commit
a532805
·
1 Parent(s): cc11853

Added logic to handle big datasets with private HF Dataset

Browse files
Files changed (1) hide show
  1. app.py +98 -7
app.py CHANGED
@@ -847,6 +847,80 @@ def run_pipeline(uploaded_files, reference_file, blank_cities_not_in_list,
847
  return "\n".join(log), outputs
848
 
849
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
850
  # =====================================================================
851
  # STARTUP HEALTH CHECK
852
  # =====================================================================
@@ -886,22 +960,31 @@ with gr.Blocks() as demo:
886
 
887
  gr.HTML('<div class="step-label">1. Upload Files</div>')
888
  files_in = gr.File(file_count="multiple", file_types=[".xlsx", ".xls", ".csv"],
889
- label="200MB per file • XLSX, XLS, CSV", show_label=True)
 
890
 
891
  gr.HTML('<div class="step-label">2. Upload Reference File (Optional)</div>')
892
  reference_in = gr.File(file_count="single", file_types=[".xlsx", ".csv"],
893
- label="200MB per file • XLSX, CSV", show_label=True)
894
 
895
  run_btn = gr.Button("Run pipeline", variant="primary")
896
 
 
 
 
 
 
 
 
 
897
  # -------- MAIN AREA: title, info, results -----------------------
898
  with gr.Column(scale=4):
899
  gr.HTML('<div id="main-title">Subdivision Cluster &amp; FIPS Validation</div>')
900
  gr.HTML(
901
- '<div class="info-banner">Please upload your Excel file(s) using the '
902
- 'sidebar, then click <b>Run pipeline</b>. The reference safety list is '
903
- 'applied automatically; upload one on the sidebar only to override it for '
904
- 'a single run.</div>'
905
  )
906
  status = gr.Textbox(label="Log", lines=14)
907
  files_out = gr.File(label="Output files", file_count="multiple")
@@ -916,6 +999,14 @@ with gr.Blocks() as demo:
916
  inputs=[files_in, reference_in],
917
  outputs=[status, files_out],
918
  )
 
 
 
 
 
919
 
920
  if __name__ == "__main__":
921
- demo.launch()
 
 
 
 
847
  return "\n".join(log), outputs
848
 
849
 
850
+ # =====================================================================
851
+ # DATASET I/O (for large inputs that time out on browser upload -> HTTP 408)
852
+ # ---------------------------------------------------------------------
853
+ # Instead of uploading a multi-GB file through the browser, put it in a private
854
+ # HF *dataset* repo and let the Space read it over HF's internal network. Outputs
855
+ # are written back to a dataset the same way (large downloads also 408 otherwise).
856
+ # Configure as Space Variables/Secrets:
857
+ # INPUT_DATASET_REPO e.g. "DDPLLeads/subdivision-inputs"
858
+ # OUTPUT_DATASET_REPO e.g. "DDPLLeads/subdivision-outputs" (optional)
859
+ # HF_TOKEN a token with read on input + write on output
860
+ # =====================================================================
861
+ INPUT_DATASET_REPO = os.environ.get("INPUT_DATASET_REPO", "")
862
+ OUTPUT_DATASET_REPO = os.environ.get("OUTPUT_DATASET_REPO", "")
863
+
864
+
865
+ class _LocalFile:
866
+ """Adapter so downloaded dataset files look like uploaded files to run_pipeline."""
867
+ def __init__(self, path):
868
+ self.name = str(path)
869
+
870
+
871
+ def list_dataset_inputs(repo_id, token=None):
872
+ from huggingface_hub import list_repo_files
873
+ token = token or os.environ.get("HF_TOKEN")
874
+ files = list_repo_files(repo_id, repo_type="dataset", token=token)
875
+ return sorted(f for f in files if f.lower().endswith((".csv", ".xlsx", ".xls")))
876
+
877
+
878
+ def run_from_dataset(input_repo, output_repo):
879
+ """Download every supported file from input_repo, run the pipeline, and (if
880
+ output_repo is set) upload the results back to that dataset. Returns
881
+ (log_text, output_paths) just like run_pipeline, so it wires to the same UI."""
882
+ token = os.environ.get("HF_TOKEN")
883
+ input_repo = (input_repo or "").strip()
884
+ output_repo = (output_repo or "").strip()
885
+ if not input_repo:
886
+ return "Set an input dataset repo (or the INPUT_DATASET_REPO variable).", []
887
+ if not token:
888
+ return "An HF_TOKEN secret is required to read/write datasets.", []
889
+
890
+ from huggingface_hub import hf_hub_download, HfApi
891
+ try:
892
+ filenames = list_dataset_inputs(input_repo, token)
893
+ except Exception as e:
894
+ return f"Could not list dataset '{input_repo}': {e}", []
895
+ if not filenames:
896
+ return f"No .csv/.xlsx/.xls files found in dataset '{input_repo}'.", []
897
+
898
+ local = []
899
+ for fn in filenames:
900
+ try:
901
+ local.append(_LocalFile(
902
+ hf_hub_download(repo_id=input_repo, filename=fn, repo_type="dataset", token=token)))
903
+ except Exception as e:
904
+ return f"Failed to download '{fn}' from '{input_repo}': {e}", []
905
+
906
+ log, outputs = run_pipeline(local, None, STRICT_BLANK_CITIES, FILTER_DOMINANT_COUNTY,
907
+ CLUSTER_THRESHOLD, REPLACE_THRESHOLD)
908
+
909
+ if output_repo and outputs:
910
+ try:
911
+ api = HfApi(token=token)
912
+ stamp = time.strftime("%Y%m%d_%H%M%S")
913
+ for p in outputs:
914
+ api.upload_file(path_or_fileobj=p, path_in_repo=f"runs/{stamp}/{Path(p).name}",
915
+ repo_id=output_repo, repo_type="dataset")
916
+ log += (f"\nUploaded {len(outputs)} file(s) to dataset '{output_repo}' "
917
+ f"under runs/{stamp}/. Retrieve them there:\n"
918
+ f"https://huggingface.co/datasets/{output_repo}/tree/main/runs/{stamp}")
919
+ except Exception as e:
920
+ log += f"\nWARNING: processed OK but upload to '{output_repo}' failed: {e}"
921
+ return log, outputs
922
+
923
+
924
  # =====================================================================
925
  # STARTUP HEALTH CHECK
926
  # =====================================================================
 
960
 
961
  gr.HTML('<div class="step-label">1. Upload Files</div>')
962
  files_in = gr.File(file_count="multiple", file_types=[".xlsx", ".xls", ".csv"],
963
+ label="XLSX, XLS, or CSV — upload several and they're merged",
964
+ show_label=True)
965
 
966
  gr.HTML('<div class="step-label">2. Upload Reference File (Optional)</div>')
967
  reference_in = gr.File(file_count="single", file_types=[".xlsx", ".csv"],
968
+ label="XLSX or CSV", show_label=True)
969
 
970
  run_btn = gr.Button("Run pipeline", variant="primary")
971
 
972
+ gr.HTML('<div class="step-label">Large files: process from a HF Dataset '
973
+ '(no upload — avoids the upload timeout)</div>')
974
+ ds_in = gr.Textbox(value=INPUT_DATASET_REPO, label="Input dataset repo",
975
+ placeholder="user/dataset-name")
976
+ ds_out = gr.Textbox(value=OUTPUT_DATASET_REPO, label="Output dataset repo (optional)",
977
+ placeholder="user/dataset-name")
978
+ ds_btn = gr.Button("Run from dataset")
979
+
980
  # -------- MAIN AREA: title, info, results -----------------------
981
  with gr.Column(scale=4):
982
  gr.HTML('<div id="main-title">Subdivision Cluster &amp; FIPS Validation</div>')
983
  gr.HTML(
984
+ '<div class="info-banner">Upload your file(s) on the sidebar and click '
985
+ '<b>Run pipeline</b>. For files too large to upload (multi-GB / full-state), '
986
+ 'put them in a private HF Dataset and use <b>Run from dataset</b> instead — '
987
+ 'the results are written back to your output dataset.</div>'
988
  )
989
  status = gr.Textbox(label="Log", lines=14)
990
  files_out = gr.File(label="Output files", file_count="multiple")
 
999
  inputs=[files_in, reference_in],
1000
  outputs=[status, files_out],
1001
  )
1002
+ ds_btn.click(
1003
+ run_from_dataset,
1004
+ inputs=[ds_in, ds_out],
1005
+ outputs=[status, files_out],
1006
+ )
1007
 
1008
  if __name__ == "__main__":
1009
+ # max_file_size=None -> no per-file upload cap imposed by the app itself.
1010
+ # (Very large uploads are still limited by HF's proxy/RAM -- prefer splitting
1011
+ # the input into several files, which this app merges, or run big jobs in Colab.)
1012
+ demo.launch(max_file_size=None)