Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Commit ·
a532805
1
Parent(s): cc11853
Added logic to handle big datasets with private HF Dataset
Browse files
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="
|
|
|
|
| 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="
|
| 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 & FIPS Validation</div>')
|
| 900 |
gr.HTML(
|
| 901 |
-
'<div class="info-banner">
|
| 902 |
-
'
|
| 903 |
-
'
|
| 904 |
-
'
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
| 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 & 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)
|