AaronTekle commited on
Commit
83454bb
路
verified 路
1 Parent(s): a1c619b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +485 -91
app.py CHANGED
@@ -297,7 +297,7 @@ def generate_pipeline_code(target: str, algorithm: str, problem_type: str, test_
297
  try:
298
  return ctx.generate_pipeline_code(target, algorithm, problem_type, float(test_size))
299
  except Exception as exc:
300
- return f"# Pipeline generation failed: {exc}"
301
 
302
 
303
  # Formats a training result dictionary into a concise Markdown model-evaluation summary
@@ -305,12 +305,12 @@ def _metrics_markdown(result: dict[str, Any]) -> str:
305
  # Extracts reported metrics and renders each metric as a Markdown bullet
306
  metrics = result.get("metrics", {})
307
  metric_lines = "\n".join(f"- **{name}**: `{value}`" for name, value in metrics.items()) or "- No metrics returned."
308
- return f'''### Model evaluation
309
  **{result.get('algorithm', 'Model')}** 路 `{result.get('problem_type', 'unknown')}`
310
 
311
  {metric_lines}
312
 
313
- **Training footprint:** {result.get('train_rows', 0):,} train rows 路 {result.get('test_rows', 0):,} test rows 路 {result.get('feature_columns', 0)} raw features 路 {result.get('fit_seconds', 0)}s fit time
314
  '''
315
 
316
 
@@ -363,13 +363,13 @@ def compare_models(target: str, problem_type: str, test_size: float, sid: str):
363
  # Extracts the best reported baseline name to build the comparison summary text
364
  best = comparison.get("best_algorithm")
365
  note = (
366
- f"### Baseline comparison\nBest holdout baseline: **{best}**\n\nUse this as a starting point, then add cross-validation and hyperparameter tuning."
367
  if best
368
- else "### Baseline comparison\nNo baseline completed successfully."
369
  )
370
  return note, frame, comparison
371
  except Exception as exc:
372
- raise gr.Error(f"Baseline comparison failed: {exc}") from exc
373
 
374
  # Runs the tool-calling machine-learning agent with the current dataset and modeling controls
375
  @spaces.GPU(duration=120)
@@ -1483,6 +1483,61 @@ html, body {
1483
  0 0 28px rgba(255,211,122,.06) !important;
1484
  }
1485
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1486
  /* Secondary buttons */
1487
  .gradio-container button.secondary,
1488
  .gradio-container button:not(.primary) {
@@ -1641,21 +1696,39 @@ html, body {
1641
  font-feature-settings: "liga" 1, "calt" 1;
1642
  }
1643
 
1644
- .result-tabs [role="tablist"] {
1645
- gap: 7px !important;
1646
- margin-top: 11px !important;
 
 
 
 
1647
  padding: 5px !important;
 
 
 
1648
  border-radius: 13px !important;
1649
  background: rgba(255,255,255,.018);
1650
  }
1651
 
1652
- .result-tabs button[role="tab"] {
1653
- border-radius: 10px !important;
 
 
 
 
 
 
 
1654
  padding: 10px 13px !important;
 
 
 
 
1655
  color: #9e93a5 !important;
1656
  }
1657
 
1658
- .result-tabs button[role="tab"][aria-selected="true"] {
1659
  color: #fff !important;
1660
  background: rgba(255,95,135,.075) !important;
1661
  border-color: rgba(255,95,135,.15) !important;
@@ -1703,6 +1776,122 @@ html, body {
1703
  margin-top: 23px !important;
1704
  }
1705
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1706
  /* Responsive refinement */
1707
  @media (max-width: 1100px) {
1708
  .hero-signal-grid {
@@ -1744,67 +1933,240 @@ html, body {
1744
  }
1745
 
1746
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1747
 
1748
 
1749
  /* =========================================================
1750
- ML MODELING DROPDOWN POPUP FIX
 
1751
  ========================================================= */
 
 
 
1752
 
1753
- /* Do not clip dropdown menus inside the glass/tabs layout. */
1754
- .app-panel,
1755
- #main-tabs,
1756
- .tab-body {
1757
- overflow: visible !important;
 
 
 
 
 
1758
  }
1759
 
1760
- /* Keep the active dropdown above neighboring cards/components. */
1761
- #target-dropdown,
1762
- #problem-type-dropdown,
1763
- #algorithm-dropdown {
1764
- position: relative !important;
1765
- overflow: visible !important;
 
 
1766
  }
1767
 
1768
- #target-dropdown:focus-within,
1769
- #problem-type-dropdown:focus-within,
1770
- #algorithm-dropdown:focus-within {
1771
- z-index: 2147483000 !important;
 
 
 
 
 
 
 
1772
  }
1773
 
1774
- /* Gradio renders the open option menu as <ul class="options">. */
1775
- #target-dropdown ul.options,
1776
- #problem-type-dropdown ul.options,
1777
- #algorithm-dropdown ul.options {
1778
- display: block !important;
1779
- visibility: visible !important;
1780
- opacity: 1 !important;
1781
- pointer-events: auto !important;
1782
- z-index: 2147483647 !important;
1783
- overflow-y: auto !important;
1784
- max-height: 320px !important;
1785
- background: #17101d !important;
1786
- border: 1px solid rgba(255, 95, 135, .28) !important;
1787
- border-radius: 12px !important;
1788
- box-shadow: 0 18px 50px rgba(0, 0, 0, .55) !important;
1789
  }
1790
 
1791
- /* Ensure individual choices remain visible and clickable. */
1792
- #target-dropdown li[data-testid="dropdown-option"],
1793
- #problem-type-dropdown li[data-testid="dropdown-option"],
1794
- #algorithm-dropdown li[data-testid="dropdown-option"] {
1795
- display: block !important;
1796
- visibility: visible !important;
1797
- opacity: 1 !important;
1798
- pointer-events: auto !important;
1799
- cursor: pointer !important;
1800
- color: #fff7fa !important;
1801
- background: #17101d !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1802
  }
1803
 
1804
- #target-dropdown li[data-testid="dropdown-option"]:hover,
1805
- #problem-type-dropdown li[data-testid="dropdown-option"]:hover,
1806
- #algorithm-dropdown li[data-testid="dropdown-option"]:hover {
1807
- background: rgba(255, 95, 135, .12) !important;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1808
  }
1809
 
1810
  '''
@@ -1828,9 +2190,9 @@ def build_app():
1828
  <div class="hero">
1829
  <div class="hero-grid">
1830
  <div>
1831
- <div class="eyebrow"><span class="eyebrow-dot"></span> Agentic Machine Learning 路 Model Selection + Pipeline Generation</div>
1832
- <h1>Agentic Machine Learning Engineer (Traditional ML)</h1>
1833
- <p>Load a real dataset, select the prediction target and MLalgorithm, train traditional machine learning baselines, compare models, and use a Qwen3-Coder tool-calling agent to turn findings into production-ready scikit-learn pipeline code.</p>
1834
  <div class="badges">
1835
  <span class="badge badge-accent"><strong>Agent</strong> HF tool calling</span>
1836
  <span class="badge"><strong>Model</strong> {html.escape(HF_MODEL_ID)}</span>
@@ -1881,36 +2243,68 @@ def build_app():
1881
  label="Dataset file",
1882
  file_types=[".csv", ".parquet", ".json", ".jsonl", ".xlsx", ".xls"],
1883
  )
1884
- # Groups the dataset load, example-load, and workspace-reset actions together
1885
- with gr.Row():
1886
- load_btn = gr.Button("Load + Profile Dataset", variant="primary", elem_id="load-button")
1887
- example_btn = gr.Button("Load HF Dataset (Example Dataset)")
1888
- clear_btn = gr.Button("Clear Workspace")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1889
  # Creates read-only dataframe components for the dataset preview and inferred schema
1890
- preview = gr.Dataframe(label="Dataset Preview", interactive=False, wrap=True, elem_id="dataset-preview")
1891
- schema_table = gr.Dataframe(label="Dataset Schema", interactive=False, wrap=True, elem_id="dataset-schema")
1892
  gr.HTML(f'''<div class="info-note"><strong>HF sample:</strong> <code>{EXAMPLE_DATASET_REPO}</code> 路 target <code>{EXAMPLE_DATASET_TARGET}</code>. Public Space: do not upload confidential, regulated, proprietary, production customer, or PII data.</div>''')
1893
 
1894
  # Builds the modeling tab for target selection, training, comparison, and pipeline generation
1895
- with gr.Tab("02. ML Modeling", id="model-lab"):
1896
  with gr.Column(elem_classes=["tab-body"]):
1897
- gr.HTML('''<div class="section-head"><div class="section-kicker">Supervised Learning</div><h2>Choose a Target, Algorithm, and Evaluation Setup</h2><p>Build a preprocessing + model pipeline, evaluate it on a holdout split, compare baselines, and inspect generated code.</p></div>''')
1898
-
1899
- # Groups the target, problem-type, and algorithm selectors on a single modeling row
1900
- with gr.Row():
1901
- target = gr.Dropdown(label="Target column", choices=[], value=None, interactive=True, filterable=True, elem_id="target-dropdown")
 
 
 
 
 
 
 
 
1902
  problem_type = gr.Dropdown(
1903
  label="Problem type",
1904
  choices=["Auto", "classification", "regression"],
1905
  value="Auto",
1906
  interactive=True,
1907
- filterable=True,
1908
  elem_id="problem-type-dropdown",
 
 
 
 
 
 
 
 
 
1909
  )
1910
- algorithm = gr.Dropdown(label="Algorithm", choices=ALL_ALGORITHMS, value="Auto", interactive=True, filterable=True, elem_id="algorithm-dropdown")
1911
 
1912
  # Configures the holdout-size control used by training, comparison, and code generation
1913
- test_size = gr.Slider(0.1, 0.4, value=0.2, step=0.05, label="Holdout test size")
1914
 
1915
  gr.HTML('''
1916
  <div class="metric-strip">
@@ -1922,24 +2316,24 @@ def build_app():
1922
  ''')
1923
 
1924
  # Groups the primary model-training, baseline-comparison, and pipeline-generation actions
1925
- with gr.Row():
1926
  train_btn = gr.Button("Train Selected Model", variant="primary", elem_id="train-button")
1927
  compare_btn = gr.Button("Compare Baselines", variant="primary", elem_id="compare-button")
1928
  code_btn = gr.Button("Generate Pipeline Code", variant="primary", elem_id="code-button")
1929
 
1930
  # Creates the components that display model summaries, metrics, importance, comparisons, code, and artifacts
1931
- model_summary = gr.Markdown("")
1932
  model_metrics = gr.JSON(label="Evaluation metrics")
1933
- feature_importance = gr.Dataframe(label="Feature importance / coefficient magnitude", interactive=False, wrap=True, elem_id="feature-importance")
1934
- compare_summary = gr.Markdown("")
1935
- leaderboard = gr.Dataframe(label="Baseline leaderboard", interactive=False, wrap=True, elem_id="leaderboard")
1936
- pipeline_code = gr.Code(label="Selected algorithm pipeline", language="python", lines=30)
1937
- model_artifact = gr.File(label="Trained pipeline artifact (.joblib)", interactive=False)
1938
 
1939
  # Builds the agent tab for natural-language ML tasks, generated code, and tool-trace inspection
1940
  with gr.Tab("03. ML Agent", id="agent"):
1941
  with gr.Column(elem_classes=["tab-body"]):
1942
- gr.HTML('''<div class="section-head"><div class="section-kicker">Machine Learning Agent</div><h2>Turn Dataset Findings Into an ML Plan and Pipeline</h2><p>Agent can inspect the dataset, validate the target framing, train the selected model, compare baselines, and generate a grounded scikit-learn pipeline.</p></div>''')
1943
  # Configures the agent task prompt field with a comprehensive default machine-learning request
1944
  task = gr.Textbox(
1945
  label="Machine learning task",
@@ -1950,8 +2344,8 @@ def build_app():
1950
  )
1951
  # Creates the agent execution button and result components for answers, code, and tool traces
1952
  agent_btn = gr.Button("Run Machine Learning Agent", variant="primary", elem_id="agent-button")
1953
- agent_answer = gr.Markdown("")
1954
- with gr.Tabs(elem_classes=["result-tabs"]):
1955
  with gr.Tab("Recommended Pipeline"):
1956
  agent_code = gr.Code(label="Generated Python", language="python", lines=28)
1957
  with gr.Tab("Tool Trace"):
@@ -1970,7 +2364,7 @@ def build_app():
1970
  <div class="sidebar-card">
1971
  <h3>Agent Capabilities</h3>
1972
  <ol>
1973
- <li>Inspect shape, types, nulls, cardinality, and examples</li>
1974
  <li>Pick classification or regression algorithms from the selected target feature</li>
1975
  <li>Train and evaluate baseline models</li>
1976
  <li>Compare multiple algorithms using holdout metrics</li>
@@ -2009,11 +2403,11 @@ def build_app():
2009
 
2010
  # Keep the algorithm picker and generated pipeline aligned to the selected target
2011
  # Synchronizes model choices and generated pipeline code whenever the target selection changes
2012
- target.input(sync_model_controls, [target, problem_type, algorithm, sid], [algorithm, pipeline_code, diagnostics])
2013
  # Synchronizes model choices and generated pipeline code whenever the problem type changes
2014
- problem_type.input(sync_model_controls, [target, problem_type, algorithm, sid], [algorithm, pipeline_code, diagnostics])
2015
  # Regenerates pipeline code whenever the selected algorithm changes
2016
- algorithm.input(generate_pipeline_code, [target, algorithm, problem_type, test_size, sid], [pipeline_code])
2017
  # Regenerates pipeline code whenever the holdout split size changes
2018
  test_size.change(generate_pipeline_code, [target, algorithm, problem_type, test_size, sid], [pipeline_code])
2019
 
 
297
  try:
298
  return ctx.generate_pipeline_code(target, algorithm, problem_type, float(test_size))
299
  except Exception as exc:
300
+ return f"# Pipeline Generation Failed: {exc}"
301
 
302
 
303
  # Formats a training result dictionary into a concise Markdown model-evaluation summary
 
305
  # Extracts reported metrics and renders each metric as a Markdown bullet
306
  metrics = result.get("metrics", {})
307
  metric_lines = "\n".join(f"- **{name}**: `{value}`" for name, value in metrics.items()) or "- No metrics returned."
308
+ return f'''### Model Evaluation
309
  **{result.get('algorithm', 'Model')}** 路 `{result.get('problem_type', 'unknown')}`
310
 
311
  {metric_lines}
312
 
313
+ **Training Footprint:** {result.get('train_rows', 0):,} train rows 路 {result.get('test_rows', 0):,} test rows 路 {result.get('feature_columns', 0)} raw features 路 {result.get('fit_seconds', 0)}s fit time
314
  '''
315
 
316
 
 
363
  # Extracts the best reported baseline name to build the comparison summary text
364
  best = comparison.get("best_algorithm")
365
  note = (
366
+ f"### Baseline Comparison:\nBest Holdout Baseline: **{best}**\n\nUse this as a starting point, then add cross-validation and hyperparameter tuning."
367
  if best
368
+ else "### Baseline Comparison:\nNo baseline completed successfully."
369
  )
370
  return note, frame, comparison
371
  except Exception as exc:
372
+ raise gr.Error(f"Baseline Comparison Failed: {exc}") from exc
373
 
374
  # Runs the tool-calling machine-learning agent with the current dataset and modeling controls
375
  @spaces.GPU(duration=120)
 
1483
  0 0 28px rgba(255,211,122,.06) !important;
1484
  }
1485
 
1486
+ /* Center and evenly space the three primary ML Modeling actions only. */
1487
+ .model-action-row {
1488
+ width: 100% !important;
1489
+ max-width: 880px !important;
1490
+ margin: 24px auto 0 !important;
1491
+ display: flex !important;
1492
+ justify-content: center !important;
1493
+ align-items: center !important;
1494
+ gap: clamp(28px, 4vw, 48px) !important;
1495
+ }
1496
+
1497
+ .model-action-row > *,
1498
+ .model-action-row #train-button,
1499
+ .model-action-row #compare-button,
1500
+ .model-action-row #code-button {
1501
+ flex: 0 1 260px !important;
1502
+ width: 260px !important;
1503
+ max-width: 260px !important;
1504
+ min-width: 0 !important;
1505
+ margin: 0 !important;
1506
+ }
1507
+
1508
+ @media (max-width: 820px) {
1509
+ .model-action-row {
1510
+ gap: 16px !important;
1511
+ }
1512
+
1513
+ .model-action-row > *,
1514
+ .model-action-row #train-button,
1515
+ .model-action-row #compare-button,
1516
+ .model-action-row #code-button {
1517
+ flex: 1 1 0 !important;
1518
+ width: auto !important;
1519
+ max-width: none !important;
1520
+ min-width: 0 !important;
1521
+ }
1522
+ }
1523
+
1524
+ @media (max-width: 620px) {
1525
+ .model-action-row {
1526
+ flex-direction: column !important;
1527
+ gap: 12px !important;
1528
+ max-width: 420px !important;
1529
+ }
1530
+
1531
+ .model-action-row > *,
1532
+ .model-action-row #train-button,
1533
+ .model-action-row #compare-button,
1534
+ .model-action-row #code-button {
1535
+ width: 100% !important;
1536
+ max-width: 420px !important;
1537
+ flex: 0 0 auto !important;
1538
+ }
1539
+ }
1540
+
1541
  /* Secondary buttons */
1542
  .gradio-container button.secondary,
1543
  .gradio-container button:not(.primary) {
 
1696
  font-feature-settings: "liga" 1, "calt" 1;
1697
  }
1698
 
1699
+ /* Agent result tabs: keep both buttons centered, equal-width, and evenly spaced. */
1700
+ #agent-result-tabs [role="tablist"] {
1701
+ display: grid !important;
1702
+ grid-template-columns: repeat(2, minmax(0, 1fr)) !important;
1703
+ gap: 14px !important;
1704
+ width: 100% !important;
1705
+ margin: 11px auto 0 !important;
1706
  padding: 5px !important;
1707
+ align-items: stretch !important;
1708
+ justify-items: stretch !important;
1709
+ justify-content: center !important;
1710
  border-radius: 13px !important;
1711
  background: rgba(255,255,255,.018);
1712
  }
1713
 
1714
+ #agent-result-tabs button[role="tab"] {
1715
+ display: flex !important;
1716
+ align-items: center !important;
1717
+ justify-content: center !important;
1718
+ width: 100% !important;
1719
+ min-width: 0 !important;
1720
+ max-width: none !important;
1721
+ min-height: 44px !important;
1722
+ margin: 0 !important;
1723
  padding: 10px 13px !important;
1724
+ flex: 1 1 0 !important;
1725
+ text-align: center !important;
1726
+ white-space: nowrap !important;
1727
+ border-radius: 10px !important;
1728
  color: #9e93a5 !important;
1729
  }
1730
 
1731
+ #agent-result-tabs button[role="tab"][aria-selected="true"] {
1732
  color: #fff !important;
1733
  background: rgba(255,95,135,.075) !important;
1734
  border-color: rgba(255,95,135,.15) !important;
 
1776
  margin-top: 23px !important;
1777
  }
1778
 
1779
+ /* =========================================================
1780
+ GRADIO FLOATING-UI / OUTPUT CLIPPING FIXES
1781
+ - Dropdown menus use floating positioning. backdrop-filter on
1782
+ an ancestor creates a new containing block and can shift the
1783
+ popup by the panel's page offset.
1784
+ - The original app-panel rule also used overflow:hidden, which
1785
+ can clip dropdowns and first-line Markdown headings.
1786
+ ========================================================= */
1787
+ .app-panel {
1788
+ overflow: visible !important;
1789
+ backdrop-filter: none !important;
1790
+ -webkit-backdrop-filter: none !important;
1791
+ }
1792
+
1793
+ #main-tabs,
1794
+ #main-tabs [role="tabpanel"],
1795
+ #main-tabs .tab-body,
1796
+ .model-controls-row,
1797
+ .model-control {
1798
+ overflow: visible !important;
1799
+ }
1800
+
1801
+ .model-controls-row {
1802
+ position: relative !important;
1803
+ z-index: 40 !important;
1804
+ }
1805
+
1806
+ .model-control {
1807
+ position: relative !important;
1808
+ z-index: 41 !important;
1809
+ }
1810
+
1811
+ .model-control:focus-within {
1812
+ z-index: 1000 !important;
1813
+ }
1814
+
1815
+ /* Keep Gradio/Floating-UI dropdown option panels above the rest of the model tab. */
1816
+ .gradio-container [role="listbox"] {
1817
+ z-index: 100000 !important;
1818
+ }
1819
+
1820
+ /* Second-pass stacking/layout fixes from browser screenshots.
1821
+ 1) Gradio 6 renders Dropdown options as a fixed <ul class="options">.
1822
+ Give that actual popup the top layer so it paints over the slider label.
1823
+ 2) Keep the primary 01/02/03 tab rail inside the rounded app panel. */
1824
+ ul.options[role="listbox"] {
1825
+ z-index: 2147483000 !important;
1826
+ }
1827
+
1828
+ #target-column-dropdown,
1829
+ #problem-type-dropdown,
1830
+ #algorithm-dropdown {
1831
+ position: relative !important;
1832
+ z-index: 100 !important;
1833
+ }
1834
+
1835
+ #target-column-dropdown:focus-within,
1836
+ #problem-type-dropdown:focus-within,
1837
+ #algorithm-dropdown:focus-within {
1838
+ z-index: 2147482000 !important;
1839
+ }
1840
+
1841
+ #holdout-test-size {
1842
+ position: relative !important;
1843
+ z-index: 0 !important;
1844
+ }
1845
+
1846
+ /* Earlier styling explicitly set padding-top: 0 on .app-panel.
1847
+ Restoring an inner top gutter prevents the tab buttons from protruding
1848
+ above the panel's rounded top border. */
1849
+ .app-panel {
1850
+ padding-top: 14px !important;
1851
+ }
1852
+
1853
+ #main-tabs {
1854
+ position: relative !important;
1855
+ top: 0 !important;
1856
+ margin-top: 0 !important;
1857
+ }
1858
+
1859
+ #main-tabs [role="tablist"] {
1860
+ position: relative !important;
1861
+ top: 0 !important;
1862
+ transform: none !important;
1863
+ margin-top: 0 !important;
1864
+ }
1865
+
1866
+ /* Result Markdown: prevent the first heading (Model evaluation,
1867
+ Baseline Comparison, or an agent heading such as ML assessment)
1868
+ from being clipped by the component's top edge. */
1869
+ .result-markdown {
1870
+ overflow: visible !important;
1871
+ padding-top: 10px !important;
1872
+ padding-bottom: 4px !important;
1873
+ min-height: 0 !important;
1874
+ }
1875
+
1876
+ .result-markdown > div,
1877
+ .result-markdown .prose,
1878
+ .result-markdown [data-testid="markdown"] {
1879
+ overflow: visible !important;
1880
+ }
1881
+
1882
+ .result-markdown h1,
1883
+ .result-markdown h2,
1884
+ .result-markdown h3,
1885
+ .result-markdown h4,
1886
+ .result-markdown h5,
1887
+ .result-markdown h6 {
1888
+ margin-top: .35rem !important;
1889
+ margin-bottom: .65rem !important;
1890
+ padding-top: .08em !important;
1891
+ line-height: 1.35 !important;
1892
+ overflow: visible !important;
1893
+ }
1894
+
1895
  /* Responsive refinement */
1896
  @media (max-width: 1100px) {
1897
  .hero-signal-grid {
 
1933
  }
1934
 
1935
 
1936
+ /* =========================================================
1937
+ PRIMARY TAB SPACING FIX
1938
+ Keep 01 / 02 / 03 evenly distributed across the top rail
1939
+ on desktop while preserving the existing mobile behavior.
1940
+ ========================================================= */
1941
+ @media (min-width: 801px) {
1942
+ #main-tabs [role="tablist"] {
1943
+ display: grid !important;
1944
+ grid-template-columns: repeat(3, minmax(0, 1fr)) !important;
1945
+ gap: 18px !important;
1946
+ width: 100% !important;
1947
+ align-items: center !important;
1948
+ }
1949
+
1950
+ #main-tabs button[role="tab"] {
1951
+ width: 100% !important;
1952
+ min-width: 0 !important;
1953
+ max-width: none !important;
1954
+ margin: 0 !important;
1955
+ }
1956
+ }
1957
 
1958
 
1959
  /* =========================================================
1960
+ DATASET ACTION BUTTON STANDARDIZATION
1961
+ Keep all three dataset actions identical in width/height.
1962
  ========================================================= */
1963
+ #dataset-actions-row {
1964
+ align-items: stretch !important;
1965
+ }
1966
 
1967
+ #dataset-actions-row #load-button,
1968
+ #dataset-actions-row #example-button,
1969
+ #dataset-actions-row #clear-button {
1970
+ flex: 1 1 0 !important;
1971
+ width: 100% !important;
1972
+ min-width: 0 !important;
1973
+ height: 44px !important;
1974
+ min-height: 44px !important;
1975
+ max-height: 44px !important;
1976
+ margin: 0 !important;
1977
  }
1978
 
1979
+ #dataset-actions-row #load-button button,
1980
+ #dataset-actions-row #example-button button,
1981
+ #dataset-actions-row #clear-button button {
1982
+ width: 100% !important;
1983
+ height: 44px !important;
1984
+ min-height: 44px !important;
1985
+ max-height: 44px !important;
1986
+ white-space: nowrap !important;
1987
  }
1988
 
1989
+ /* Allow the row to adapt cleanly on smaller screens without uneven controls. */
1990
+ @media (max-width: 800px) {
1991
+ #dataset-actions-row {
1992
+ flex-wrap: wrap !important;
1993
+ }
1994
+
1995
+ #dataset-actions-row #load-button,
1996
+ #dataset-actions-row #example-button,
1997
+ #dataset-actions-row #clear-button {
1998
+ flex: 1 1 100% !important;
1999
+ }
2000
  }
2001
 
2002
+
2003
+ /* =========================================================
2004
+ LAPTOP RESPONSIVE LAYOUT FIX
2005
+ Keeps long labels inside their controls and keeps the three
2006
+ ML Modeling action buttons aligned on one row on laptops.
2007
+ ========================================================= */
2008
+
2009
+ /* Dataset action row: equal controls, but allow long button text to wrap cleanly. */
2010
+ #dataset-actions-row {
2011
+ display: flex !important;
2012
+ flex-wrap: nowrap !important;
2013
+ align-items: stretch !important;
2014
+ gap: 14px !important;
 
 
2015
  }
2016
 
2017
+ #dataset-actions-row > * {
2018
+ flex: 1 1 0 !important;
2019
+ min-width: 0 !important;
2020
+ }
2021
+
2022
+ #dataset-actions-row #load-button,
2023
+ #dataset-actions-row #example-button,
2024
+ #dataset-actions-row #clear-button,
2025
+ #dataset-actions-row #load-button button,
2026
+ #dataset-actions-row #example-button button,
2027
+ #dataset-actions-row #clear-button button {
2028
+ width: 100% !important;
2029
+ min-width: 0 !important;
2030
+ height: auto !important;
2031
+ max-height: none !important;
2032
+ min-height: 56px !important;
2033
+ }
2034
+
2035
+ #dataset-actions-row #load-button button,
2036
+ #dataset-actions-row #example-button button,
2037
+ #dataset-actions-row #clear-button button {
2038
+ white-space: normal !important;
2039
+ overflow-wrap: anywhere !important;
2040
+ word-break: normal !important;
2041
+ line-height: 1.18 !important;
2042
+ padding: 10px 14px !important;
2043
+ text-align: center !important;
2044
+ }
2045
+
2046
+ /* Primary tabs: give the long ML Modeling label more room and allow wrapping. */
2047
+ @media (min-width: 801px) {
2048
+ #main-tabs [role="tablist"] {
2049
+ grid-template-columns:
2050
+ minmax(0, 0.88fr)
2051
+ minmax(0, 1.24fr)
2052
+ minmax(0, 0.88fr) !important;
2053
+ gap: 14px !important;
2054
+ }
2055
+
2056
+ #main-tabs button[role="tab"] {
2057
+ min-width: 0 !important;
2058
+ min-height: 64px !important;
2059
+ padding: 11px 14px !important;
2060
+ white-space: normal !important;
2061
+ overflow-wrap: anywhere !important;
2062
+ word-break: normal !important;
2063
+ line-height: 1.16 !important;
2064
+ text-align: center !important;
2065
+ }
2066
+ }
2067
+
2068
+ /* ML Modeling actions: always one aligned row on laptop/desktop. */
2069
+ .model-action-row {
2070
+ width: 100% !important;
2071
+ max-width: none !important;
2072
+ margin: 24px 0 0 !important;
2073
+ display: flex !important;
2074
+ flex-wrap: nowrap !important;
2075
+ align-items: stretch !important;
2076
+ justify-content: stretch !important;
2077
+ gap: 16px !important;
2078
+ }
2079
+
2080
+ .model-action-row > * {
2081
+ flex: 1 1 0 !important;
2082
+ width: auto !important;
2083
+ max-width: none !important;
2084
+ min-width: 0 !important;
2085
+ margin: 0 !important;
2086
  }
2087
 
2088
+ .model-action-row #train-button,
2089
+ .model-action-row #compare-button,
2090
+ .model-action-row #code-button,
2091
+ .model-action-row #train-button button,
2092
+ .model-action-row #compare-button button,
2093
+ .model-action-row #code-button button {
2094
+ width: 100% !important;
2095
+ min-width: 0 !important;
2096
+ max-width: none !important;
2097
+ height: auto !important;
2098
+ min-height: 58px !important;
2099
+ margin: 0 !important;
2100
+ }
2101
+
2102
+ .model-action-row #train-button button,
2103
+ .model-action-row #compare-button button,
2104
+ .model-action-row #code-button button {
2105
+ white-space: normal !important;
2106
+ overflow-wrap: anywhere !important;
2107
+ word-break: normal !important;
2108
+ line-height: 1.16 !important;
2109
+ padding: 11px 12px !important;
2110
+ text-align: center !important;
2111
+ }
2112
+
2113
+ /* Laptop widths: slightly tighten text and spacing without wrapping rows. */
2114
+ @media (min-width: 801px) and (max-width: 1450px) {
2115
+ #dataset-actions-row {
2116
+ gap: 10px !important;
2117
+ }
2118
+
2119
+ #dataset-actions-row button {
2120
+ font-size: 12.5px !important;
2121
+ padding-left: 10px !important;
2122
+ padding-right: 10px !important;
2123
+ }
2124
+
2125
+ #main-tabs [role="tablist"] {
2126
+ gap: 10px !important;
2127
+ padding-left: 12px !important;
2128
+ padding-right: 12px !important;
2129
+ }
2130
+
2131
+ #main-tabs button[role="tab"] {
2132
+ font-size: 12.5px !important;
2133
+ padding-left: 9px !important;
2134
+ padding-right: 9px !important;
2135
+ }
2136
+
2137
+ .model-action-row {
2138
+ gap: 12px !important;
2139
+ }
2140
+
2141
+ .model-action-row #train-button button,
2142
+ .model-action-row #compare-button button,
2143
+ .model-action-row #code-button button {
2144
+ font-size: 13.5px !important;
2145
+ padding-left: 9px !important;
2146
+ padding-right: 9px !important;
2147
+ }
2148
+ }
2149
+
2150
+ /* Tablet/mobile: stack action controls so they remain readable. */
2151
+ @media (max-width: 800px) {
2152
+ #dataset-actions-row,
2153
+ .model-action-row {
2154
+ flex-direction: column !important;
2155
+ flex-wrap: nowrap !important;
2156
+ gap: 12px !important;
2157
+ }
2158
+
2159
+ #dataset-actions-row > *,
2160
+ .model-action-row > * {
2161
+ width: 100% !important;
2162
+ max-width: none !important;
2163
+ flex: 0 0 auto !important;
2164
+ }
2165
+
2166
+ #main-tabs button[role="tab"] {
2167
+ white-space: normal !important;
2168
+ line-height: 1.15 !important;
2169
+ }
2170
  }
2171
 
2172
  '''
 
2190
  <div class="hero">
2191
  <div class="hero-grid">
2192
  <div>
2193
+ <div class="eyebrow"><span class="eyebrow-dot"></span> Agentic Machine Learning 路 (Traditional ML) Supervised Learning 路 Model Selection + Pipeline Generation</div>
2194
+ <h1>Agentic Machine Learning Engineer</h1>
2195
+ <p>Load a real dataset, select the prediction target variable (in the data) and ML algorithm, train traditional machine learning baselines, compare models (pick the best one), and use a Qwen3-Coder tool-calling agent to turn findings into production-ready scikit-learn pipeline code.</p>
2196
  <div class="badges">
2197
  <span class="badge badge-accent"><strong>Agent</strong> HF tool calling</span>
2198
  <span class="badge"><strong>Model</strong> {html.escape(HF_MODEL_ID)}</span>
 
2243
  label="Dataset file",
2244
  file_types=[".csv", ".parquet", ".json", ".jsonl", ".xlsx", ".xls"],
2245
  )
2246
+ # Groups the dataset load, example-load, and workspace-reset actions together.
2247
+ # Equal scale/min-width values keep all three actions exactly the same width.
2248
+ with gr.Row(equal_height=True, elem_id="dataset-actions-row"):
2249
+ load_btn = gr.Button(
2250
+ "Load + Profile Dataset",
2251
+ variant="primary",
2252
+ elem_id="load-button",
2253
+ scale=1,
2254
+ min_width=0,
2255
+ )
2256
+ example_btn = gr.Button(
2257
+ "Load HF Dataset (Example Dataset)",
2258
+ elem_id="example-button",
2259
+ scale=1,
2260
+ min_width=0,
2261
+ )
2262
+ clear_btn = gr.Button(
2263
+ "Clear Workspace",
2264
+ elem_id="clear-button",
2265
+ scale=1,
2266
+ min_width=0,
2267
+ )
2268
  # Creates read-only dataframe components for the dataset preview and inferred schema
2269
+ preview = gr.Dataframe(label="Dataset Preview:", interactive=False, wrap=True, elem_id="dataset-preview")
2270
+ schema_table = gr.Dataframe(label="Dataset Schema:", interactive=False, wrap=True, elem_id="dataset-schema")
2271
  gr.HTML(f'''<div class="info-note"><strong>HF sample:</strong> <code>{EXAMPLE_DATASET_REPO}</code> 路 target <code>{EXAMPLE_DATASET_TARGET}</code>. Public Space: do not upload confidential, regulated, proprietary, production customer, or PII data.</div>''')
2272
 
2273
  # Builds the modeling tab for target selection, training, comparison, and pipeline generation
2274
+ with gr.Tab("02. ML Modeling (Optional Fallback Models)", id="model-lab"):
2275
  with gr.Column(elem_classes=["tab-body"]):
2276
+ gr.HTML('''<div class="section-head"><div class="section-kicker">Supervised Learning</div><h2>Choose a Target Variable (Feature), Algorithm, and Evaluation Setup</h2><p>Build a preprocessing + model pipeline, evaluate it on a holdout split, compare baselines, and evaluate generated pipelines (scikit-learn pipelines).</p></div>''')
2277
+
2278
+ # Groups the target, problem-type, and algorithm selectors on a single modeling row.
2279
+ # The CSS hooks keep Gradio's floating dropdown menus anchored to these controls.
2280
+ with gr.Row(elem_classes=["model-controls-row"]):
2281
+ target = gr.Dropdown(
2282
+ label="Target column",
2283
+ choices=[],
2284
+ value=None,
2285
+ interactive=True,
2286
+ elem_id="target-column-dropdown",
2287
+ elem_classes=["model-control"],
2288
+ )
2289
  problem_type = gr.Dropdown(
2290
  label="Problem type",
2291
  choices=["Auto", "classification", "regression"],
2292
  value="Auto",
2293
  interactive=True,
 
2294
  elem_id="problem-type-dropdown",
2295
+ elem_classes=["model-control"],
2296
+ )
2297
+ algorithm = gr.Dropdown(
2298
+ label="Algorithm",
2299
+ choices=ALL_ALGORITHMS,
2300
+ value="Auto",
2301
+ interactive=True,
2302
+ elem_id="algorithm-dropdown",
2303
+ elem_classes=["model-control"],
2304
  )
 
2305
 
2306
  # Configures the holdout-size control used by training, comparison, and code generation
2307
+ test_size = gr.Slider(0.1, 0.4, value=0.2, step=0.05, label="Holdout test size", elem_id="holdout-test-size")
2308
 
2309
  gr.HTML('''
2310
  <div class="metric-strip">
 
2316
  ''')
2317
 
2318
  # Groups the primary model-training, baseline-comparison, and pipeline-generation actions
2319
+ with gr.Row(elem_classes=["model-action-row"]):
2320
  train_btn = gr.Button("Train Selected Model", variant="primary", elem_id="train-button")
2321
  compare_btn = gr.Button("Compare Baselines", variant="primary", elem_id="compare-button")
2322
  code_btn = gr.Button("Generate Pipeline Code", variant="primary", elem_id="code-button")
2323
 
2324
  # Creates the components that display model summaries, metrics, importance, comparisons, code, and artifacts
2325
+ model_summary = gr.Markdown("", elem_id="model-summary", elem_classes=["result-markdown"])
2326
  model_metrics = gr.JSON(label="Evaluation metrics")
2327
+ feature_importance = gr.Dataframe(label="Feature importance / coefficient magnitude:", interactive=False, wrap=True, elem_id="feature-importance")
2328
+ compare_summary = gr.Markdown("", elem_id="compare-summary", elem_classes=["result-markdown"])
2329
+ leaderboard = gr.Dataframe(label="Baseline Leaderboard:", interactive=False, wrap=True, elem_id="leaderboard")
2330
+ pipeline_code = gr.Code(label="Selected Algorithm Pipeline", language="python", lines=30)
2331
+ model_artifact = gr.File(label="Trained Pipeline Artifact (.joblib)", interactive=False)
2332
 
2333
  # Builds the agent tab for natural-language ML tasks, generated code, and tool-trace inspection
2334
  with gr.Tab("03. ML Agent", id="agent"):
2335
  with gr.Column(elem_classes=["tab-body"]):
2336
+ gr.HTML('''<div class="section-head"><div class="section-kicker">Machine Learning Agent</div><h2>Turn Dataset Findings Into an ML Strategy and Pipeline Code (sci-kit learn)</h2><p>Agent can inspect the dataset, validate the target framing, train the selected model, compare baselines, and generate scikit-learn pipelines.</p></div>''')
2337
  # Configures the agent task prompt field with a comprehensive default machine-learning request
2338
  task = gr.Textbox(
2339
  label="Machine learning task",
 
2344
  )
2345
  # Creates the agent execution button and result components for answers, code, and tool traces
2346
  agent_btn = gr.Button("Run Machine Learning Agent", variant="primary", elem_id="agent-button")
2347
+ agent_answer = gr.Markdown("", elem_id="agent-answer", elem_classes=["result-markdown"])
2348
+ with gr.Tabs(elem_id="agent-result-tabs", elem_classes=["result-tabs"]):
2349
  with gr.Tab("Recommended Pipeline"):
2350
  agent_code = gr.Code(label="Generated Python", language="python", lines=28)
2351
  with gr.Tab("Tool Trace"):
 
2364
  <div class="sidebar-card">
2365
  <h3>Agent Capabilities</h3>
2366
  <ol>
2367
+ <li>Check data shapes, types, nulls, cardinality, and examples</li>
2368
  <li>Pick classification or regression algorithms from the selected target feature</li>
2369
  <li>Train and evaluate baseline models</li>
2370
  <li>Compare multiple algorithms using holdout metrics</li>
 
2403
 
2404
  # Keep the algorithm picker and generated pipeline aligned to the selected target
2405
  # Synchronizes model choices and generated pipeline code whenever the target selection changes
2406
+ target.change(sync_model_controls, [target, problem_type, algorithm, sid], [algorithm, pipeline_code, diagnostics])
2407
  # Synchronizes model choices and generated pipeline code whenever the problem type changes
2408
+ problem_type.change(sync_model_controls, [target, problem_type, algorithm, sid], [algorithm, pipeline_code, diagnostics])
2409
  # Regenerates pipeline code whenever the selected algorithm changes
2410
+ algorithm.change(generate_pipeline_code, [target, algorithm, problem_type, test_size, sid], [pipeline_code])
2411
  # Regenerates pipeline code whenever the holdout split size changes
2412
  test_size.change(generate_pipeline_code, [target, algorithm, problem_type, test_size, sid], [pipeline_code])
2413