Compare commits
No commits in common. "fb52a536c6489052411cd3b63df7f49e8639ec13" and "da0494664844c2958076f443acaaf7f44dec9821" have entirely different histories.
fb52a536c6
...
da04946648
BIN
Scene.jpeg
|
Before Width: | Height: | Size: 215 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 532 KiB |
@ -33,7 +33,7 @@ Usage
|
||||
# First time — creates the Kaggle dataset and notebook from scratch
|
||||
python kaggle_train.py \
|
||||
--dataset_dir crops_dataset \
|
||||
--notebook 2_product-classifier.ipynb \
|
||||
--notebook train_classifier_kaggle.ipynb \
|
||||
--dataset_name my-product-crops \
|
||||
--kernel_name product-classifier-train \
|
||||
--output_dir runs/classify
|
||||
@ -41,16 +41,16 @@ python kaggle_train.py \
|
||||
# Subsequent runs — detects existing dataset/kernel and updates them
|
||||
python kaggle_train.py \
|
||||
--dataset_dir crops_dataset \
|
||||
--notebook 2_product-classifier.ipynb \
|
||||
--notebook train_classifier_kaggle.ipynb \
|
||||
--dataset_name my-product-crops \
|
||||
--kernel_name product-classifier-train
|
||||
|
||||
Arguments
|
||||
---------
|
||||
--dataset_dir Local crops_dataset/ folder to upload (default: crops_dataset)
|
||||
--notebook Kaggle notebook .ipynb file (default: 2_product-classifier.ipynb)
|
||||
--dataset_name Kaggle dataset slug (lowercase, hyphens) (default: product-dataset)
|
||||
--kernel_name Kaggle kernel slug (lowercase, hyphens) (default: product-predection)
|
||||
--notebook Kaggle notebook .ipynb file (default: train_classifier_kaggle.ipynb)
|
||||
--dataset_name Kaggle dataset slug (lowercase, hyphens) (default: product-crops)
|
||||
--kernel_name Kaggle kernel slug (lowercase, hyphens) (default: product-classifier)
|
||||
--output_dir Where to save downloaded weights (default: runs/classify)
|
||||
--poll_interval Seconds between status checks (default: 30)
|
||||
--timeout Max minutes to wait for kernel (default: 180)
|
||||
@ -79,10 +79,10 @@ def parse_args():
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
p.add_argument("--dataset_dir", default="crops_dataset")
|
||||
p.add_argument("--notebook", default="2_product-classifier.ipynb")
|
||||
p.add_argument("--dataset_name", default="product-dataset",
|
||||
p.add_argument("--notebook", default="train_classifier_kaggle.ipynb")
|
||||
p.add_argument("--dataset_name", default="product-crops",
|
||||
help="Kaggle dataset slug — lowercase, hyphens, no spaces")
|
||||
p.add_argument("--kernel_name", default="product-predection",
|
||||
p.add_argument("--kernel_name", default="product-classifier",
|
||||
help="Kaggle kernel slug — lowercase, hyphens, no spaces")
|
||||
p.add_argument("--output_dir", default="runs/classify")
|
||||
p.add_argument("--poll_interval", type=int, default=30,
|
||||
@ -132,7 +132,6 @@ def _detect_auth_method() -> str:
|
||||
if os.getenv("KAGGLE_USERNAME") and os.getenv("KAGGLE_KEY"):
|
||||
return "env_legacy"
|
||||
if _ACCESS_TOKEN_PATH.exists():
|
||||
#print(f"this is the PATH: {_ACCESS_TOKEN_PATH}")
|
||||
return "access_token"
|
||||
if _KAGGLE_JSON_PATH.exists():
|
||||
return "kaggle_json"
|
||||
@ -321,7 +320,7 @@ def patch_notebook(notebook_path: Path, dataset_ref: str,
|
||||
DATA_DIR = Path("/kaggle/input/your-dataset-name")
|
||||
We replace the path to match the actual uploaded dataset slug.
|
||||
"""
|
||||
nb = json.loads(notebook_path.read_text(encoding="utf-8"))
|
||||
nb = json.loads(notebook_path.read_text())
|
||||
|
||||
# Extract the dataset slug from "username/slug" → "slug"
|
||||
ds_slug = dataset_ref.split("/")[-1]
|
||||
@ -352,7 +351,7 @@ def patch_notebook(notebook_path: Path, dataset_ref: str,
|
||||
log("⚠ DATA_DIR line not found in notebook — using notebook as-is", "⚠")
|
||||
|
||||
out_path = tmp_dir / notebook_path.name
|
||||
out_path.write_text(json.dumps(nb, indent=1), encoding="utf-8")
|
||||
out_path.write_text(json.dumps(nb, indent=1))
|
||||
return out_path
|
||||
|
||||
|
||||
@ -390,15 +389,11 @@ def push_kernel(api, username: str, kernel_name: str, notebook_path: Path,
|
||||
"competition_sources": [],
|
||||
"kernel_sources": [],
|
||||
"model_sources": [],
|
||||
"machine_shape": "t4" if gpu else None,
|
||||
}
|
||||
(kernel_dir / "kernel-metadata.json").write_text(json.dumps(meta, indent=2))
|
||||
|
||||
log(f"Pushing kernel to Kaggle: {ref} (GPU={'yes' if gpu else 'no'})", "🚀")
|
||||
try:
|
||||
api.kernels_push(str(kernel_dir), timeout=None, acc="t4" if gpu else None)
|
||||
except TypeError:
|
||||
api.kernels_push(str(kernel_dir))
|
||||
api.kernels_push(str(kernel_dir))
|
||||
log(f"Kernel pushed — run started: https://www.kaggle.com/code/{ref}", "✓")
|
||||
return ref
|
||||
|
||||
@ -410,11 +405,12 @@ def poll_kernel(api, kernel_ref: str, poll_interval: int, timeout_minutes: int)
|
||||
Poll the kernel until it reaches a terminal status.
|
||||
Returns True if successful, False if failed or timed out.
|
||||
"""
|
||||
username, slug = kernel_ref.split("/")
|
||||
deadline = time.time() + timeout_minutes * 60
|
||||
attempt = 0
|
||||
|
||||
TERMINAL = {"complete", "error", "cancelled", "cancel_acknowledged"}
|
||||
RUNNING = {"running", "queued", "initializing", "pending"}
|
||||
TERMINAL = {"complete", "error", "cancelled"}
|
||||
RUNNING = {"running", "queued"}
|
||||
|
||||
log(f"Polling kernel status every {poll_interval}s "
|
||||
f"(timeout {timeout_minutes} min) …", "⏳")
|
||||
@ -422,27 +418,16 @@ def poll_kernel(api, kernel_ref: str, poll_interval: int, timeout_minutes: int)
|
||||
while time.time() < deadline:
|
||||
attempt += 1
|
||||
try:
|
||||
# kernels_status takes the full kernel ref "username/slug"
|
||||
status_obj = api.kernels_status(kernel_ref)
|
||||
# Extract status from the response object
|
||||
raw_status = getattr(status_obj, "status", None)
|
||||
if raw_status is not None:
|
||||
if hasattr(raw_status, 'name'):
|
||||
status = raw_status.name.lower()
|
||||
else:
|
||||
status = str(raw_status).lower()
|
||||
else:
|
||||
status = str(status_obj).lower()
|
||||
|
||||
# Clean up enum prefixes
|
||||
status = status.replace("kernelworkerstatus.", "")
|
||||
status_obj = api.kernel_status(username, slug)
|
||||
# The API returns an object with a .status attribute
|
||||
status = getattr(status_obj, "status", str(status_obj)).lower()
|
||||
except Exception as e:
|
||||
log(f"Poll error (will retry): {e}", "⚠")
|
||||
time.sleep(poll_interval)
|
||||
continue
|
||||
|
||||
elapsed_min = (time.time() + timeout_minutes * 60 - deadline) / 60
|
||||
print(f" [{attempt:>3}] status={status:<20} elapsed={elapsed_min:.1f} min",
|
||||
elapsed_min = (time.time() + timeout_minutes * 60 - deadline) / 60 + timeout_minutes
|
||||
print(f" [{attempt:>3}] status={status:<12} elapsed={elapsed_min:.1f} min",
|
||||
end="\r", flush=True)
|
||||
|
||||
if status == "complete":
|
||||
@ -456,7 +441,7 @@ def poll_kernel(api, kernel_ref: str, poll_interval: int, timeout_minutes: int)
|
||||
f"https://www.kaggle.com/code/{kernel_ref}", "✗")
|
||||
return False
|
||||
|
||||
if "cancel" in status:
|
||||
if status == "cancelled":
|
||||
print()
|
||||
log("Kernel was cancelled.", "✗")
|
||||
return False
|
||||
@ -530,8 +515,8 @@ def main():
|
||||
|
||||
# Import here so missing kaggle package gives a clean error
|
||||
try:
|
||||
from kaggle.api.kaggle_api_extended import KaggleApi
|
||||
api = KaggleApi()
|
||||
from kaggle.api.kaggle_api_extended import KaggleApiExtended
|
||||
api = KaggleApiExtended()
|
||||
api.authenticate()
|
||||
except ImportError:
|
||||
fatal("kaggle package not installed.\n Run: pip install kaggle")
|
||||
|
||||
12
run_prod.py
@ -1,12 +0,0 @@
|
||||
"""
|
||||
pip install hypercorn
|
||||
"""
|
||||
|
||||
import asyncio
|
||||
from hypercorn.config import Config
|
||||
from hypercorn.asyncio import serve
|
||||
from api_server import app
|
||||
|
||||
config = Config()
|
||||
config.bind = ["0.0.0.0:2000"]
|
||||
asyncio.run(serve(app, config))
|
||||