Spaces:
Sleeping
Sleeping
jefffffff9 Claude Sonnet 4.6 commited on
Commit ·
3d43385
1
Parent(s): a5737ac
Fix Kaggle trigger: use kaggle CLI push instead of fake /run endpoint
Browse filesThe Kaggle REST API has no /run endpoint. The correct way to trigger
a new kernel run is kaggle kernels push, which creates a new kernel
version (which immediately starts executing on Kaggle's servers).
New approach:
- Reads notebook + kernel-metadata.json from the Space filesystem
- Writes temporary kaggle.json from KAGGLE_USERNAME/KAGGLE_KEY secrets
- Runs: python -m kaggle kernels push -p notebooks/
- Returns the CLI output so errors are visible in the UI
Also logs auto-trigger result to Space logs instead of silently failing.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
app.py
CHANGED
|
@@ -609,26 +609,56 @@ def _count_corrections() -> int:
|
|
| 609 |
|
| 610 |
|
| 611 |
def _trigger_kaggle_training(lang: str = "bam") -> str:
|
| 612 |
-
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 613 |
if not KAGGLE_USERNAME or not KAGGLE_KEY:
|
| 614 |
-
return "⚠️ KAGGLE_USERNAME / KAGGLE_KEY not set in Space secrets
|
| 615 |
-
|
| 616 |
-
|
| 617 |
-
|
| 618 |
-
|
| 619 |
-
|
| 620 |
-
|
| 621 |
-
|
| 622 |
-
|
| 623 |
-
|
| 624 |
-
|
| 625 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 626 |
)
|
| 627 |
-
|
| 628 |
-
|
| 629 |
-
|
| 630 |
-
|
| 631 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 632 |
|
| 633 |
|
| 634 |
def _maybe_auto_trigger() -> None:
|
|
@@ -637,7 +667,11 @@ def _maybe_auto_trigger() -> None:
|
|
| 637 |
return
|
| 638 |
count = _count_corrections()
|
| 639 |
if count > 0 and count % AUTO_TRAIN_THRESHOLD == 0:
|
| 640 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 641 |
|
| 642 |
|
| 643 |
# ── Bulk upload handler ────────────────────────────────────────────────────────
|
|
|
|
| 609 |
|
| 610 |
|
| 611 |
def _trigger_kaggle_training(lang: str = "bam") -> str:
|
| 612 |
+
"""
|
| 613 |
+
Push the master trainer notebook to Kaggle via the kaggle CLI,
|
| 614 |
+
which creates a new kernel version (i.e. triggers a run).
|
| 615 |
+
|
| 616 |
+
Requires KAGGLE_USERNAME + KAGGLE_KEY Space secrets.
|
| 617 |
+
The notebook is read from notebooks/ inside the Space filesystem.
|
| 618 |
+
"""
|
| 619 |
if not KAGGLE_USERNAME or not KAGGLE_KEY:
|
| 620 |
+
return "⚠️ KAGGLE_USERNAME / KAGGLE_KEY not set in Space secrets."
|
| 621 |
+
|
| 622 |
+
import subprocess, tempfile, shutil
|
| 623 |
+
|
| 624 |
+
notebooks_dir = ROOT / "notebooks"
|
| 625 |
+
meta_file = notebooks_dir / "kernel-metadata.json"
|
| 626 |
+
nb_file = notebooks_dir / "kaggle_master_trainer.ipynb"
|
| 627 |
+
|
| 628 |
+
if not nb_file.exists():
|
| 629 |
+
return "❌ notebooks/kaggle_master_trainer.ipynb not found in Space."
|
| 630 |
+
if not meta_file.exists():
|
| 631 |
+
return "❌ notebooks/kernel-metadata.json not found in Space."
|
| 632 |
+
|
| 633 |
+
# Write kaggle.json to a temp dir so the CLI authenticates
|
| 634 |
+
with tempfile.TemporaryDirectory() as tmpdir:
|
| 635 |
+
kaggle_cfg = Path(tmpdir) / ".kaggle"
|
| 636 |
+
kaggle_cfg.mkdir()
|
| 637 |
+
creds_file = kaggle_cfg / "kaggle.json"
|
| 638 |
+
creds_file.write_text(
|
| 639 |
+
json.dumps({"username": KAGGLE_USERNAME, "key": KAGGLE_KEY}),
|
| 640 |
+
encoding="utf-8",
|
| 641 |
)
|
| 642 |
+
creds_file.chmod(0o600)
|
| 643 |
+
|
| 644 |
+
env = {
|
| 645 |
+
**__import__("os").environ,
|
| 646 |
+
"KAGGLE_CONFIG_DIR": str(kaggle_cfg),
|
| 647 |
+
"PYTHONUTF8": "1",
|
| 648 |
+
"PYTHONIOENCODING": "utf-8",
|
| 649 |
+
}
|
| 650 |
+
|
| 651 |
+
result = subprocess.run(
|
| 652 |
+
["python", "-m", "kaggle", "kernels", "push", "-p", str(notebooks_dir)],
|
| 653 |
+
capture_output=True, text=True, timeout=60, env=env,
|
| 654 |
+
)
|
| 655 |
+
|
| 656 |
+
if result.returncode == 0:
|
| 657 |
+
output = (result.stdout or "").strip()
|
| 658 |
+
return f"✅ Kaggle training triggered!\n{output or 'Kernel version created — check Kaggle for progress.'}"
|
| 659 |
+
else:
|
| 660 |
+
err = (result.stderr or result.stdout or "unknown error").strip()
|
| 661 |
+
return f"❌ Kaggle push failed:\n{err}"
|
| 662 |
|
| 663 |
|
| 664 |
def _maybe_auto_trigger() -> None:
|
|
|
|
| 667 |
return
|
| 668 |
count = _count_corrections()
|
| 669 |
if count > 0 and count % AUTO_TRAIN_THRESHOLD == 0:
|
| 670 |
+
import logging
|
| 671 |
+
def _run():
|
| 672 |
+
msg = _trigger_kaggle_training()
|
| 673 |
+
logging.getLogger(__name__).info("Auto-trigger: %s", msg)
|
| 674 |
+
threading.Thread(target=_run, daemon=True).start()
|
| 675 |
|
| 676 |
|
| 677 |
# ── Bulk upload handler ────────────────────────────────────────────────────────
|