Spaces:
Running
Running
fix gradio 6.x file upload
Browse files
app.py
CHANGED
|
@@ -17,12 +17,15 @@ from pathlib import Path
|
|
| 17 |
# ── make sure the automl package is importable ────────────────────────────────
|
| 18 |
sys.path.insert(0, str(Path(__file__).parent))
|
| 19 |
from automl import AutoML
|
| 20 |
-
|
| 21 |
-
os.makedirs("./automl_output", exist_ok=True)
|
| 22 |
# ── Gradio version compatibility check ───────────────────────────────────────
|
| 23 |
import gradio as _gr_check
|
| 24 |
_gr_version = tuple(int(x) for x in _gr_check.__version__.split(".")[:2])
|
|
|
|
|
|
|
| 25 |
print(f" Gradio version: {_gr_check.__version__}")
|
|
|
|
|
|
|
| 26 |
|
| 27 |
# ── Global state ──────────────────────────────────────────────────────────────
|
| 28 |
_state: dict = {
|
|
@@ -32,6 +35,31 @@ _state: dict = {
|
|
| 32 |
"running": False,
|
| 33 |
}
|
| 34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
PALETTE = {
|
| 36 |
"bg": "#0d1117",
|
| 37 |
"surface": "#161b22",
|
|
@@ -84,10 +112,17 @@ def _ax_style(ax, title="", xlabel="", ylabel=""):
|
|
| 84 |
def handle_upload(file):
|
| 85 |
if file is None:
|
| 86 |
return (gr.update(choices=[], value=None),
|
| 87 |
-
gr.update(value="
|
| 88 |
gr.update(value=None))
|
| 89 |
try:
|
| 90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
_state["df"] = df
|
| 92 |
cols = df.columns.tolist()
|
| 93 |
|
|
@@ -140,8 +175,11 @@ def handle_upload(file):
|
|
| 140 |
gr.update(value=combined),
|
| 141 |
gr.update(value=None))
|
| 142 |
except Exception as e:
|
|
|
|
|
|
|
|
|
|
| 143 |
return (gr.update(choices=[], value=None),
|
| 144 |
-
gr.update(value=f"<
|
| 145 |
gr.update(value=None))
|
| 146 |
|
| 147 |
|
|
@@ -468,7 +506,8 @@ def predict_on_file(file):
|
|
| 468 |
if file is None:
|
| 469 |
return (None, "<p style='color:red'>Upload a CSV to predict on.</p>")
|
| 470 |
try:
|
| 471 |
-
|
|
|
|
| 472 |
preds = am.predict(new_df)
|
| 473 |
new_df["prediction"] = preds
|
| 474 |
out_path = "./automl_output/predictions.csv"
|
|
@@ -802,12 +841,12 @@ def build_app():
|
|
| 802 |
# ══════════════════════════════════════════════════════════════
|
| 803 |
# TAB 1 — Upload & Explore
|
| 804 |
# ══════════════════════════════════════════════════════════════
|
| 805 |
-
with gr.Tab(" Upload & Explore"):
|
| 806 |
gr.Markdown("### Upload your CSV dataset to get started")
|
| 807 |
|
| 808 |
with gr.Row():
|
| 809 |
with gr.Column(scale=1):
|
| 810 |
-
upload_btn = gr.File(label="Drop CSV here
|
| 811 |
target_dd = gr.Dropdown(label="Target Column", choices=[], interactive=True)
|
| 812 |
explore_btn = gr.Button("🔍 Analyze Selected Column", variant="secondary")
|
| 813 |
|
|
@@ -830,7 +869,7 @@ def build_app():
|
|
| 830 |
# ══════════════════════════════════════════════════════════════
|
| 831 |
# TAB 2 — Configure & Train
|
| 832 |
# ══════════════════════════════════════════════════════════════
|
| 833 |
-
with gr.Tab(" Configure & Train"):
|
| 834 |
gr.Markdown("### Training Configuration")
|
| 835 |
|
| 836 |
with gr.Row():
|
|
@@ -874,7 +913,7 @@ def build_app():
|
|
| 874 |
# ══════════════════════════════════════════════════════════════
|
| 875 |
# TAB 3 — Results & Metrics
|
| 876 |
# ══════════════════════════════════════════════════════════════
|
| 877 |
-
with gr.Tab(" Results & Metrics"):
|
| 878 |
gr.Markdown("### Best Model Performance")
|
| 879 |
results_btn = gr.Button("Load Results", variant="secondary")
|
| 880 |
|
|
@@ -896,7 +935,7 @@ def build_app():
|
|
| 896 |
# ══════════════════════════════════════════════════════════════
|
| 897 |
# TAB 4 — Feature Importance
|
| 898 |
# ══════════════════════════════════════════════════════════════
|
| 899 |
-
with gr.Tab(" Feature Importance"):
|
| 900 |
gr.Markdown("### SHAP / Model-Based Feature Importance")
|
| 901 |
with gr.Row():
|
| 902 |
top_k_slider = gr.Slider(5, 40, value=15, step=1, label="Top K Features")
|
|
@@ -918,11 +957,11 @@ def build_app():
|
|
| 918 |
# ══════════════════════════════════════════════════════════════
|
| 919 |
# TAB 5 — Predict
|
| 920 |
# ══════════════════════════════════════════════════════════════
|
| 921 |
-
with gr.Tab(" Predict"):
|
| 922 |
gr.Markdown("### Batch Prediction (CSV file)")
|
| 923 |
with gr.Row():
|
| 924 |
with gr.Column():
|
| 925 |
-
pred_file = gr.File(label="Upload CSV for prediction"
|
| 926 |
pred_btn = gr.Button("Run Prediction", variant="primary")
|
| 927 |
with gr.Column():
|
| 928 |
pred_result = gr.HTML()
|
|
@@ -958,7 +997,7 @@ def build_app():
|
|
| 958 |
# ══════════════════════════════════════════════════════════════
|
| 959 |
# TAB 6 — Dataset Analysis
|
| 960 |
# ══════════════════════════════════════════════════════════════
|
| 961 |
-
with gr.Tab(" Dataset Analysis"):
|
| 962 |
gr.Markdown("### Automated Dataset Visualizations")
|
| 963 |
analysis_btn = gr.Button("Generate Analysis Plots", variant="primary")
|
| 964 |
|
|
@@ -989,20 +1028,29 @@ def build_app():
|
|
| 989 |
|
| 990 |
|
| 991 |
# ─────────────────────────────────────────────────────────────────────────────
|
| 992 |
-
# if __name__ == "__main__":
|
| 993 |
-
# print("\n" + "="*55)
|
| 994 |
-
# print(" AutoML Gradio Interface")
|
| 995 |
-
# print(" Install deps: pip install gradio pillow")
|
| 996 |
-
# print(" Then run: python app.py")
|
| 997 |
-
# print("="*55 + "\n")
|
| 998 |
-
# app = build_app()
|
| 999 |
-
# app.launch(
|
| 1000 |
-
# server_name="0.0.0.0",
|
| 1001 |
-
# server_port=7860,
|
| 1002 |
-
# share=True, # set True to get a public ngrok link
|
| 1003 |
-
# show_error=True,
|
| 1004 |
-
# inbrowser=True,
|
| 1005 |
-
# )
|
| 1006 |
if __name__ == "__main__":
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1007 |
app = build_app()
|
| 1008 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
# ── make sure the automl package is importable ────────────────────────────────
|
| 18 |
sys.path.insert(0, str(Path(__file__).parent))
|
| 19 |
from automl import AutoML
|
| 20 |
+
|
|
|
|
| 21 |
# ── Gradio version compatibility check ───────────────────────────────────────
|
| 22 |
import gradio as _gr_check
|
| 23 |
_gr_version = tuple(int(x) for x in _gr_check.__version__.split(".")[:2])
|
| 24 |
+
_is_gradio_4_plus = _gr_version[0] >= 4
|
| 25 |
+
_is_gradio_6_plus = _gr_version[0] >= 6
|
| 26 |
print(f" Gradio version: {_gr_check.__version__}")
|
| 27 |
+
# gr.File type param: needed in 3.x only
|
| 28 |
+
_FILE_KWARGS = {} if _is_gradio_4_plus else {"type": "file"}
|
| 29 |
|
| 30 |
# ── Global state ──────────────────────────────────────────────────────────────
|
| 31 |
_state: dict = {
|
|
|
|
| 35 |
"running": False,
|
| 36 |
}
|
| 37 |
|
| 38 |
+
# ── File path compatibility helper (Gradio 3.x / 4.x / 5.x / 6.x) ──────────
|
| 39 |
+
def _get_filepath(file):
|
| 40 |
+
"""Handle gr.File output across ALL Gradio versions including 6.x."""
|
| 41 |
+
if file is None:
|
| 42 |
+
return None
|
| 43 |
+
# Gradio 6.x: returns plain string filepath directly
|
| 44 |
+
if isinstance(file, str):
|
| 45 |
+
return file
|
| 46 |
+
# Gradio 6.x: sometimes returns a list (multiple files)
|
| 47 |
+
if isinstance(file, list):
|
| 48 |
+
return file[0] if file else None
|
| 49 |
+
# Gradio 3.x early: returns dict
|
| 50 |
+
if isinstance(file, dict):
|
| 51 |
+
return file.get("name") or file.get("path") or file.get("tmp_path")
|
| 52 |
+
# Gradio 4.x / 5.x: UploadData with .path attribute
|
| 53 |
+
if hasattr(file, "path"):
|
| 54 |
+
return file.path
|
| 55 |
+
# Gradio 3.x late: object with .name
|
| 56 |
+
if hasattr(file, "name"):
|
| 57 |
+
return file.name
|
| 58 |
+
# Last resort
|
| 59 |
+
return str(file)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
|
| 63 |
PALETTE = {
|
| 64 |
"bg": "#0d1117",
|
| 65 |
"surface": "#161b22",
|
|
|
|
| 112 |
def handle_upload(file):
|
| 113 |
if file is None:
|
| 114 |
return (gr.update(choices=[], value=None),
|
| 115 |
+
gr.update(value="<p style='color:#8b949e;'>Upload a CSV to see summary.</p>"),
|
| 116 |
gr.update(value=None))
|
| 117 |
try:
|
| 118 |
+
print(f" [Upload] file type: {type(file)}, value: {repr(file)[:200]}")
|
| 119 |
+
filepath = _get_filepath(file)
|
| 120 |
+
print(f" [Upload] resolved filepath: {filepath}")
|
| 121 |
+
if filepath is None:
|
| 122 |
+
return (gr.update(choices=[], value=None),
|
| 123 |
+
gr.update(value="<p style='color:red'>Could not read file. Try uploading again.</p>"),
|
| 124 |
+
gr.update(value=None))
|
| 125 |
+
df = pd.read_csv(filepath)
|
| 126 |
_state["df"] = df
|
| 127 |
cols = df.columns.tolist()
|
| 128 |
|
|
|
|
| 175 |
gr.update(value=combined),
|
| 176 |
gr.update(value=None))
|
| 177 |
except Exception as e:
|
| 178 |
+
import traceback
|
| 179 |
+
err_detail = traceback.format_exc()
|
| 180 |
+
print(f" [Upload Error] {err_detail}")
|
| 181 |
return (gr.update(choices=[], value=None),
|
| 182 |
+
gr.update(value=f"<div style='color:#f85149;font-family:monospace;padding:12px;background:#161b22;border:1px solid #f85149;border-radius:6px;'><b>Error loading file:</b><br>{str(e)}<br><br><small>Check HF Space logs for details.</small></div>"),
|
| 183 |
gr.update(value=None))
|
| 184 |
|
| 185 |
|
|
|
|
| 506 |
if file is None:
|
| 507 |
return (None, "<p style='color:red'>Upload a CSV to predict on.</p>")
|
| 508 |
try:
|
| 509 |
+
filepath = _get_filepath(file)
|
| 510 |
+
new_df = pd.read_csv(filepath)
|
| 511 |
preds = am.predict(new_df)
|
| 512 |
new_df["prediction"] = preds
|
| 513 |
out_path = "./automl_output/predictions.csv"
|
|
|
|
| 841 |
# ══════════════════════════════════════════════════════════════
|
| 842 |
# TAB 1 — Upload & Explore
|
| 843 |
# ══════════════════════════════════════════════════════════════
|
| 844 |
+
with gr.Tab("📂 Upload & Explore"):
|
| 845 |
gr.Markdown("### Upload your CSV dataset to get started")
|
| 846 |
|
| 847 |
with gr.Row():
|
| 848 |
with gr.Column(scale=1):
|
| 849 |
+
upload_btn = gr.File(label="📂 Drop CSV here (or click to browse)")
|
| 850 |
target_dd = gr.Dropdown(label="Target Column", choices=[], interactive=True)
|
| 851 |
explore_btn = gr.Button("🔍 Analyze Selected Column", variant="secondary")
|
| 852 |
|
|
|
|
| 869 |
# ══════════════════════════════════════════════════════════════
|
| 870 |
# TAB 2 — Configure & Train
|
| 871 |
# ══════════════════════════════════════════════════════════════
|
| 872 |
+
with gr.Tab("🚀 Configure & Train"):
|
| 873 |
gr.Markdown("### Training Configuration")
|
| 874 |
|
| 875 |
with gr.Row():
|
|
|
|
| 913 |
# ══════════════════════════════════════════════════════════════
|
| 914 |
# TAB 3 — Results & Metrics
|
| 915 |
# ══════════════════════════════════════════════════════════════
|
| 916 |
+
with gr.Tab("📊 Results & Metrics"):
|
| 917 |
gr.Markdown("### Best Model Performance")
|
| 918 |
results_btn = gr.Button("Load Results", variant="secondary")
|
| 919 |
|
|
|
|
| 935 |
# ══════════════════════════════════════════════════════════════
|
| 936 |
# TAB 4 — Feature Importance
|
| 937 |
# ══════════════════════════════════════════════════════════════
|
| 938 |
+
with gr.Tab("🔍 Feature Importance"):
|
| 939 |
gr.Markdown("### SHAP / Model-Based Feature Importance")
|
| 940 |
with gr.Row():
|
| 941 |
top_k_slider = gr.Slider(5, 40, value=15, step=1, label="Top K Features")
|
|
|
|
| 957 |
# ══════════════════════════════════════════════════════════════
|
| 958 |
# TAB 5 — Predict
|
| 959 |
# ══════════════════════════════════════════════════════════════
|
| 960 |
+
with gr.Tab("🎯 Predict"):
|
| 961 |
gr.Markdown("### Batch Prediction (CSV file)")
|
| 962 |
with gr.Row():
|
| 963 |
with gr.Column():
|
| 964 |
+
pred_file = gr.File(label="Upload CSV for prediction")
|
| 965 |
pred_btn = gr.Button("Run Prediction", variant="primary")
|
| 966 |
with gr.Column():
|
| 967 |
pred_result = gr.HTML()
|
|
|
|
| 997 |
# ══════════════════════════════════════════════════════════════
|
| 998 |
# TAB 6 — Dataset Analysis
|
| 999 |
# ══════════════════════════════════════════════════════════════
|
| 1000 |
+
with gr.Tab("🧬 Dataset Analysis"):
|
| 1001 |
gr.Markdown("### Automated Dataset Visualizations")
|
| 1002 |
analysis_btn = gr.Button("Generate Analysis Plots", variant="primary")
|
| 1003 |
|
|
|
|
| 1028 |
|
| 1029 |
|
| 1030 |
# ─────────────────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1031 |
if __name__ == "__main__":
|
| 1032 |
+
print("\n" + "="*55)
|
| 1033 |
+
print(" AutoML Gradio Interface")
|
| 1034 |
+
print(f" Gradio version: {_gr_check.__version__}")
|
| 1035 |
+
print("="*55 + "\n")
|
| 1036 |
app = build_app()
|
| 1037 |
+
|
| 1038 |
+
# Detect if running on HF Spaces
|
| 1039 |
+
import os
|
| 1040 |
+
on_hf_spaces = os.environ.get("SPACE_ID") is not None
|
| 1041 |
+
|
| 1042 |
+
if on_hf_spaces:
|
| 1043 |
+
# HF Spaces: minimal launch args
|
| 1044 |
+
app.launch(ssr_mode=False)
|
| 1045 |
+
else:
|
| 1046 |
+
# Local: full args
|
| 1047 |
+
launch_kwargs = dict(
|
| 1048 |
+
server_name="0.0.0.0",
|
| 1049 |
+
server_port=7860,
|
| 1050 |
+
share=False,
|
| 1051 |
+
show_error=True,
|
| 1052 |
+
)
|
| 1053 |
+
# ssr_mode only exists in Gradio 5+
|
| 1054 |
+
if _gr_version[0] >= 5:
|
| 1055 |
+
launch_kwargs["ssr_mode"] = False
|
| 1056 |
+
app.launch(**launch_kwargs)
|