Spaces:
Sleeping
Sleeping
Fix: GPU duration 120s (max), reactive empty/ready state from agent.list_tables()
Browse files
app.py
CHANGED
|
@@ -495,36 +495,45 @@ def _turn_html_complete(result: dict) -> str:
|
|
| 495 |
|
| 496 |
|
| 497 |
def _conversation_html(history: list[dict], in_progress: tuple[str, str] | None = None) -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
out = "".join(_turn_html_complete(t) for t in history)
|
| 499 |
if in_progress:
|
| 500 |
out += _turn_html_progress(in_progress[0], in_progress[1])
|
| 501 |
-
if not out:
|
| 502 |
-
return _empty_state_html()
|
| 503 |
return out
|
| 504 |
|
| 505 |
|
| 506 |
def _empty_state_html() -> str:
|
| 507 |
-
suggestions = _suggestions_html([
|
| 508 |
-
"Try the Titanic example below",
|
| 509 |
-
"Or upload your own CSV/JSON above",
|
| 510 |
-
])
|
| 511 |
return (
|
| 512 |
'<div class="empty">'
|
| 513 |
-
'<div class="empty-title">No data yet</div>'
|
| 514 |
-
'<div class="empty-sub">
|
| 515 |
-
'<
|
| 516 |
-
'<div class="example-card" onclick="document.getElementById(\'load_demo_btn\').click()">'
|
| 517 |
-
'<div class="example-card-title">Titanic (demo)</div>'
|
| 518 |
-
'<div class="example-card-meta">20 passengers · 7 columns · click to load</div>'
|
| 519 |
-
'</div>'
|
| 520 |
'</div>'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 521 |
'</div>'
|
| 522 |
)
|
| 523 |
|
| 524 |
|
| 525 |
# ============================================================ EVENT HANDLERS
|
| 526 |
def on_upload(file) -> Tuple[str, str, list]:
|
| 527 |
-
"""Register an uploaded file and clear history."""
|
| 528 |
if file is None:
|
| 529 |
return "", _conversation_html([]), []
|
| 530 |
agent = get_agent()
|
|
@@ -535,36 +544,29 @@ def on_upload(file) -> Tuple[str, str, list]:
|
|
| 535 |
rows = agent.executor.con.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0]
|
| 536 |
cols = len(agent.executor.get_table_schema(table))
|
| 537 |
chip = _file_chip_html(path.name, rows, cols)
|
| 538 |
-
|
| 539 |
-
intro = (
|
| 540 |
-
f'<div class="empty-title" style="margin-top:30px">Ready to query <code style="font-family:var(--font-mono);font-size:13px">{table}</code></div>'
|
| 541 |
-
f'<div class="empty-sub">Try a question or one of these:</div>'
|
| 542 |
-
f'{_suggestions_html(SUGGESTED_QUESTIONS[:4])}'
|
| 543 |
-
)
|
| 544 |
-
return chip, intro, []
|
| 545 |
except Exception as e:
|
| 546 |
logger.exception("upload failed")
|
| 547 |
return "", f'<div class="turn-error">Could not load file: {e}</div>', []
|
| 548 |
|
| 549 |
|
| 550 |
def on_load_demo() -> Tuple[str, str, list]:
|
| 551 |
-
"""Load the embedded Titanic example."""
|
| 552 |
agent = get_agent()
|
| 553 |
agent.reset()
|
| 554 |
-
|
| 555 |
-
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
return chip, intro, []
|
| 565 |
|
| 566 |
|
| 567 |
-
@spaces.GPU(duration=
|
| 568 |
def _gpu_process(question: str) -> dict:
|
| 569 |
"""The GPU-bound call. Models initialize lazily inside this scope."""
|
| 570 |
agent = get_agent()
|
|
|
|
| 495 |
|
| 496 |
|
| 497 |
def _conversation_html(history: list[dict], in_progress: tuple[str, str] | None = None) -> str:
|
| 498 |
+
"""Conversation HTML reacts to: data loaded? history? in-progress?"""
|
| 499 |
+
has_data = bool(get_agent().list_tables())
|
| 500 |
+
has_turns = bool(history) or in_progress is not None
|
| 501 |
+
|
| 502 |
+
if not has_data and not has_turns:
|
| 503 |
+
return _empty_state_html()
|
| 504 |
+
if has_data and not has_turns:
|
| 505 |
+
return _ready_state_html()
|
| 506 |
+
|
| 507 |
out = "".join(_turn_html_complete(t) for t in history)
|
| 508 |
if in_progress:
|
| 509 |
out += _turn_html_progress(in_progress[0], in_progress[1])
|
|
|
|
|
|
|
| 510 |
return out
|
| 511 |
|
| 512 |
|
| 513 |
def _empty_state_html() -> str:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 514 |
return (
|
| 515 |
'<div class="empty">'
|
| 516 |
+
'<div class="empty-title">No data loaded yet</div>'
|
| 517 |
+
'<div class="empty-sub">Drop a CSV, JSON, Parquet or Excel file above, '
|
| 518 |
+
'or click <strong>Load demo dataset</strong> to play with sample data.</div>'
|
|
|
|
|
|
|
|
|
|
|
|
|
| 519 |
'</div>'
|
| 520 |
+
)
|
| 521 |
+
|
| 522 |
+
|
| 523 |
+
def _ready_state_html() -> str:
|
| 524 |
+
"""Shown when data is loaded but no queries asked yet."""
|
| 525 |
+
return (
|
| 526 |
+
'<div class="empty">'
|
| 527 |
+
'<div class="empty-title">Ready</div>'
|
| 528 |
+
'<div class="empty-sub">Ask a question above, or try one of these:</div>'
|
| 529 |
+
f'{_suggestions_html(SUGGESTED_QUESTIONS[:4])}'
|
| 530 |
'</div>'
|
| 531 |
)
|
| 532 |
|
| 533 |
|
| 534 |
# ============================================================ EVENT HANDLERS
|
| 535 |
def on_upload(file) -> Tuple[str, str, list]:
|
| 536 |
+
"""Register an uploaded file and clear history. Conversation re-renders to ready state."""
|
| 537 |
if file is None:
|
| 538 |
return "", _conversation_html([]), []
|
| 539 |
agent = get_agent()
|
|
|
|
| 544 |
rows = agent.executor.con.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0]
|
| 545 |
cols = len(agent.executor.get_table_schema(table))
|
| 546 |
chip = _file_chip_html(path.name, rows, cols)
|
| 547 |
+
return chip, _conversation_html([]), []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 548 |
except Exception as e:
|
| 549 |
logger.exception("upload failed")
|
| 550 |
return "", f'<div class="turn-error">Could not load file: {e}</div>', []
|
| 551 |
|
| 552 |
|
| 553 |
def on_load_demo() -> Tuple[str, str, list]:
|
| 554 |
+
"""Load the embedded Titanic example and re-render to ready state."""
|
| 555 |
agent = get_agent()
|
| 556 |
agent.reset()
|
| 557 |
+
try:
|
| 558 |
+
p = _make_titanic_csv()
|
| 559 |
+
table = agent.load_data(p)
|
| 560 |
+
rows = agent.executor.con.execute(f'SELECT COUNT(*) FROM "{table}"').fetchone()[0]
|
| 561 |
+
cols = len(agent.executor.get_table_schema(table))
|
| 562 |
+
chip = _file_chip_html("titanic.csv (demo)", rows, cols)
|
| 563 |
+
return chip, _conversation_html([]), []
|
| 564 |
+
except Exception as e:
|
| 565 |
+
logger.exception("demo load failed")
|
| 566 |
+
return "", f'<div class="turn-error">Could not load demo: {e}</div>', []
|
|
|
|
| 567 |
|
| 568 |
|
| 569 |
+
@spaces.GPU(duration=120)
|
| 570 |
def _gpu_process(question: str) -> dict:
|
| 571 |
"""The GPU-bound call. Models initialize lazily inside this scope."""
|
| 572 |
agent = get_agent()
|