{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":10338,"databundleVersionId":862042},{"sourceType":"kernelVersion","sourceId":309042418}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"474c2ca3-fbd5-4d4c-b1f4-0006db3c2b40","cell_type":"markdown","source":"# Full Project Pipeline (Phase 1 -> Phase 8)\n\nThis notebook follows your project code path end-to-end with one cell per phase and try/except blocks for robust execution.\n\nCurrent optimized setup:\n- Phase 4 uses only 3 fast models: YOLO, ResNet50, EfficientNet-B0\n- Phase 4 uses 3 fast algorithms: PSO, GWO, SA\n- Phase 5 retrains dynamically based on Phase 4 output","metadata":{}},{"id":"5a54198d","cell_type":"code","source":"import shutil\nimport os\n\nsrc = \"/kaggle/input/notebooks/moemenelsayed/demo-grad/Code\"\ndst = \"/kaggle/working/Code\"\n\n# Remove old copy if exists\nif os.path.exists(dst):\n    shutil.rmtree(dst)\n\n# Copy everything (folders + files)\nshutil.copytree(src, dst)\n\nprint(\"✅ Project copied successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:20:28.013566Z","iopub.execute_input":"2026-04-05T21:20:28.013881Z","iopub.status.idle":"2026-04-05T21:27:21.668814Z","shell.execute_reply.started":"2026-04-05T21:20:28.013854Z","shell.execute_reply":"2026-04-05T21:27:21.668048Z"}},"outputs":[],"execution_count":null},{"id":"d891c7f9-928d-4269-a460-486ed84c9d92","cell_type":"code","source":"# 0) Install dependencies (Kaggle)\nimport importlib.util\nimport subprocess\nimport sys\n\nrequired = {\n    \"ultralytics\": \"ultralytics==8.*\",\n    \"albumentations\": \"albumentations\",\n    \"pydicom\": \"pydicom\",\n}\nmissing = [spec for module, spec in required.items() if importlib.util.find_spec(module) is None]\nif missing:\n    print(\"Installing missing packages:\", \", \".join(missing))\n    subprocess.check_call([sys.executable, \"-m\", \"pip\", \"install\", \"-q\", *missing])\nelse:\n    print(\"Required packages already available.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:28:09.435908Z","iopub.execute_input":"2026-04-05T21:28:09.436226Z","iopub.status.idle":"2026-04-05T21:28:17.20757Z","shell.execute_reply.started":"2026-04-05T21:28:09.436198Z","shell.execute_reply":"2026-04-05T21:28:17.206839Z"}},"outputs":[],"execution_count":null},{"id":"2c197b0b-79b4-411e-a969-98dce99bbc2a","cell_type":"code","source":"# 0.1) Project path setup\nimport os\nimport sys\nimport json\nfrom pathlib import Path\n\ndef _is_project_root(path: Path) -> bool:\n    return path.is_dir() and (path / \"src\" / \"config.py\").is_file()\n\ndef find_project_root() -> Path:\n    direct_candidates = [\n        Path.cwd(),\n        Path(\"/kaggle/working/Code\"),  # main expected location after copy\n        Path(\"/kaggle/input/datasets/moemenelsayed/mycode/Code\"),  # fallback read-only source\n    ]\n\n    for candidate in direct_candidates:\n        if _is_project_root(candidate):\n            return candidate.resolve()\n\n    for base in [Path(\"/kaggle/working\"), Path(\"/kaggle/input\")]:\n        if not base.exists():\n            continue\n\n        for child in base.iterdir():\n            if _is_project_root(child):\n                return child.resolve()\n\n            if child.is_dir():\n                for nested in child.iterdir():\n                    if _is_project_root(nested):\n                        return nested.resolve()\n\n    raise FileNotFoundError(\n        \"Project root not found. Expected src/config.py inside /kaggle/working/Code \"\n        \"or inside the attached Kaggle dataset.\"\n    )\n\nPROJECT_ROOT = find_project_root()\n\nos.chdir(PROJECT_ROOT)\n\nproject_root_str = str(PROJECT_ROOT)\nif project_root_str not in sys.path:\n    sys.path.insert(0, project_root_str)\n\n(PROJECT_ROOT / \"artifacts\").mkdir(parents=True, exist_ok=True)\n\nprint(\"PROJECT_ROOT:\", PROJECT_ROOT)\nprint(\"Working dir:\", os.getcwd())\nprint(\"src/config.py exists:\", (PROJECT_ROOT / \"src\" / \"config.py\").is_file())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:28:46.597943Z","iopub.execute_input":"2026-04-05T21:28:46.598573Z","iopub.status.idle":"2026-04-05T21:28:46.607012Z","shell.execute_reply.started":"2026-04-05T21:28:46.598544Z","shell.execute_reply":"2026-04-05T21:28:46.606345Z"}},"outputs":[],"execution_count":null},{"id":"237f7714-a4ae-4758-84ed-181f984e34a1","cell_type":"code","source":"# 0.2) Imports from your project (same codebase)\nfrom src.dataset import explore_dataset\nfrom src.preprocessing import convert_dicom_to_png\nfrom src.visualization import show_pneumonia_example\nfrom src.yolo_dataset import build_yolo_dataset\nfrom src.yolo_visualization import show_yolo_samples\n\nfrom src.detection.train_yolo import train_yolo\nfrom src.detection.train_fasterrcnn import train_fasterrcnn\nfrom src.detection.train_retinanet import train_retinanet\n\nfrom src.classification.train_resnet import train_resnet\nfrom src.classification.train_densenet import train_densenet\nfrom src.classification.train_efficientnet import train_efficientnet\n\nfrom src.phase4_optimization import run_phase4_optimization\nfrom src.phase5_retrain import run_phase5_retrain\nfrom src.phase6_explainability import run_phase6_gradcam\nfrom src.phase7_final_evaluation import run_phase7_final_evaluation\nfrom src.phase8_demo import run_phase8_demo\nfrom src.preflight import run_preflight_checks\nfrom src.config import YOLO_DATASET_DIR","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:30.534866Z","iopub.execute_input":"2026-04-05T21:29:30.535581Z","iopub.status.idle":"2026-04-05T21:29:30.540311Z","shell.execute_reply.started":"2026-04-05T21:29:30.535552Z","shell.execute_reply":"2026-04-05T21:29:30.53973Z"}},"outputs":[],"execution_count":null},{"id":"e801fc1c-21f0-4fee-927f-ff08146eb516","cell_type":"code","source":"# Config flags\nRUN_PHASE1 = False\nRUN_PHASE2 = False\nRUN_PHASE3 = False\nRUN_PHASE4 = True\nRUN_PHASE5 = True\nRUN_PHASE6 = True\nRUN_PHASE7 = True\nRUN_PHASE8 = True\n\nQUICK_MODE = False\nif QUICK_MODE:\n    DET_BASELINE_EPOCHS = 1\n    CLS_BASELINE_EPOCHS = 1\n    OPT_QUICK_EPOCHS = 1\n    OPT_POPULATION = 3\n    OPT_ITERATIONS = 1\n    DET_RETRAIN_EPOCHS = 2\n    CLS_RETRAIN_EPOCHS = 2\nelse:\n    DET_BASELINE_EPOCHS = 2\n    CLS_BASELINE_EPOCHS = 3\n    OPT_QUICK_EPOCHS = 1\n    OPT_POPULATION = 4\n    OPT_ITERATIONS = 2\n    DET_RETRAIN_EPOCHS = 20\n    CLS_RETRAIN_EPOCHS = 8\n\nDEMO_IMAGE_SOURCE = os.path.join(YOLO_DATASET_DIR, \"val\", \"images\")\nresults = {}","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:32.901685Z","iopub.execute_input":"2026-04-05T21:29:32.902363Z","iopub.status.idle":"2026-04-05T21:29:32.90735Z","shell.execute_reply.started":"2026-04-05T21:29:32.902334Z","shell.execute_reply":"2026-04-05T21:29:32.906614Z"}},"outputs":[],"execution_count":null},{"id":"cc4b65f3-8ee8-4214-ba44-506e78a34689","cell_type":"markdown","source":"## Phase 1 - Data Exploration and PNG Conversion","metadata":{}},{"id":"5cae253d-5865-4cd6-a35e-0756752180f2","cell_type":"code","source":"df = None\npreflight = run_preflight_checks()\nresults[\"preflight\"] = preflight","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:41.889098Z","iopub.execute_input":"2026-04-05T21:29:41.889497Z","iopub.status.idle":"2026-04-05T21:29:41.898341Z","shell.execute_reply.started":"2026-04-05T21:29:41.889472Z","shell.execute_reply":"2026-04-05T21:29:41.897631Z"}},"outputs":[],"execution_count":null},{"id":"9df04139","cell_type":"code","source":"if RUN_PHASE1:\n    try:\n        df = explore_dataset()\n        convert_dicom_to_png()\n        show_pneumonia_example(df)\n        results[\"phase1\"] = {\"status\": \"ok\"}\n    except Exception as e:\n        results[\"phase1\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 1 failed:\", e)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:54.253681Z","iopub.execute_input":"2026-04-05T21:29:54.254078Z","iopub.status.idle":"2026-04-05T21:29:54.258657Z","shell.execute_reply.started":"2026-04-05T21:29:54.254044Z","shell.execute_reply":"2026-04-05T21:29:54.257935Z"}},"outputs":[],"execution_count":null},{"id":"38a2e553-8fd0-44e1-950f-24c2de056bfd","cell_type":"markdown","source":"## Phase 2 - Build YOLO Dataset and Visualization","metadata":{}},{"id":"b3151b26-fa0c-4587-b900-278e5576f8e6","cell_type":"code","source":"if RUN_PHASE2:\n    try:\n        if df is None:\n            df = explore_dataset()\n        build_yolo_dataset(df)\n        show_yolo_samples()\n        results[\"phase2\"] = {\"status\": \"ok\"}\n    except Exception as e:\n        results[\"phase2\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 2 failed:\", e)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:56.621569Z","iopub.execute_input":"2026-04-05T21:29:56.62211Z","iopub.status.idle":"2026-04-05T21:29:56.626839Z","shell.execute_reply.started":"2026-04-05T21:29:56.62208Z","shell.execute_reply":"2026-04-05T21:29:56.62609Z"}},"outputs":[],"execution_count":null},{"id":"a7e23d2d-4ef0-4339-9897-7019dcf1dac2","cell_type":"markdown","source":"## Phase 3 - Baseline Training (Per Model Try/Except)","metadata":{}},{"id":"b390041c-a3cd-4706-83d9-1711f3be9f10","cell_type":"code","source":"if RUN_PHASE3:\n    phase3 = {}\n\n    for name, fn in [\n        (\"yolo\", lambda: train_yolo(epochs=DET_BASELINE_EPOCHS, run_name=\"phase3_yolo_baseline\")),\n        (\"fasterrcnn\", lambda: train_fasterrcnn(epochs=DET_BASELINE_EPOCHS)),\n        (\"retinanet\", lambda: train_retinanet(epochs=DET_BASELINE_EPOCHS)),\n    ]:\n        try:\n            phase3[name] = {\"status\": \"ok\", \"metrics\": fn()}\n        except Exception as e:\n            phase3[name] = {\"status\": \"failed\", \"error\": str(e)}\n            print(f\"Phase 3 {name} failed: {e}\")\n\n    for name, fn in [\n        (\"resnet50\", lambda: train_resnet(epochs=CLS_BASELINE_EPOCHS)),\n        (\"densenet121\", lambda: train_densenet(epochs=CLS_BASELINE_EPOCHS)),\n        (\"efficientnet_b0\", lambda: train_efficientnet(epochs=CLS_BASELINE_EPOCHS)),\n    ]:\n        try:\n            phase3[name] = {\"status\": \"ok\", \"metrics\": fn()}\n        except Exception as e:\n            phase3[name] = {\"status\": \"failed\", \"error\": str(e)}\n            print(f\"Phase 3 {name} failed: {e}\")\n\n    results[\"phase3\"] = phase3\n    with open(\"artifacts/phase3_baseline_results.json\", \"w\", encoding=\"utf-8\") as f:\n        json.dump({k: v.get(\"metrics\", {}) for k, v in phase3.items() if v.get(\"status\") == \"ok\"}, f, indent=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:29:58.991632Z","iopub.execute_input":"2026-04-05T21:29:58.991968Z","iopub.status.idle":"2026-04-05T21:29:59.001207Z","shell.execute_reply.started":"2026-04-05T21:29:58.99194Z","shell.execute_reply":"2026-04-05T21:29:59.000576Z"}},"outputs":[],"execution_count":null},{"id":"4afca3fe-192d-447f-a22b-a3f70b7312ea","cell_type":"markdown","source":"## Phase 4 - Nature-Inspired Optimization (Fast Set: PSO, GWO, SA)\n\nOptimized models in this fast run:\n- YOLO\n- ResNet50\n- EfficientNet-B0","metadata":{}},{"id":"9ed1047c-cbfa-4436-b810-ec7d80121c75","cell_type":"code","source":"if RUN_PHASE4:\n    try:\n        phase4 = run_phase4_optimization(\n            quick_epochs=OPT_QUICK_EPOCHS,\n            population=OPT_POPULATION,\n            iterations=OPT_ITERATIONS,\n        )\n        results[\"phase4\"] = {\"status\": \"ok\", \"data\": phase4}\n    except Exception as e:\n        results[\"phase4\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 4 failed:\", e)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-05T21:30:04.695416Z","iopub.execute_input":"2026-04-05T21:30:04.695715Z"}},"outputs":[],"execution_count":null},{"id":"70a80a9f","cell_type":"markdown","source":"## Phase 5 - Retraining with Optimized Parameters\n\nUses dynamic retraining from `run_phase5_retrain()` based on whatever models were optimized in Phase 4.","metadata":{}},{"id":"8995bdb0","cell_type":"code","source":"if RUN_PHASE5:\n    try:\n        phase5 = run_phase5_retrain(\n            full_epochs_detection=DET_RETRAIN_EPOCHS,\n            full_epochs_classification=CLS_RETRAIN_EPOCHS,\n        )\n        results[\"phase5\"] = {\"status\": \"ok\", \"data\": phase5}\n    except Exception as e:\n        results[\"phase5\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 5 failed:\", e)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"a900e110-76f8-4e26-a8a4-5def817e74d1","cell_type":"markdown","source":"## Phase 6 - Explainability (Grad-CAM)","metadata":{}},{"id":"68ada436-99a3-4996-aea9-c075c3e9c05b","cell_type":"code","source":"if RUN_PHASE6:\n    try:\n        phase6 = run_phase6_gradcam()\n        results[\"phase6\"] = {\"status\": \"ok\", \"data\": phase6}\n    except Exception as e:\n        results[\"phase6\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 6 failed:\", e)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"4da3c43c-bec7-4e8d-b919-0505cfaa64c4","cell_type":"markdown","source":"## Phase 7 - Final Evaluation","metadata":{}},{"id":"4f2f417b-8131-4ff3-91cb-96e1b7589ed2","cell_type":"code","source":"if RUN_PHASE7:\n    try:\n        phase7 = run_phase7_final_evaluation()\n        results[\"phase7\"] = {\"status\": \"ok\", \"data\": phase7}\n    except Exception as e:\n        results[\"phase7\"] = {\"status\": \"failed\", \"error\": str(e)}\n        print(\"Phase 7 failed:\", e)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"6da5526f-fb4a-4776-8dce-4cbfe4c3cc2f","cell_type":"markdown","source":"## Phase 8 - Final Demo","metadata":{}},{"id":"06232d11-9a46-4085-89ae-8809b15a5f53","cell_type":"code","source":"if RUN_PHASE8:\n    try:\n        if os.path.isdir(DEMO_IMAGE_SOURCE):\n            files = sorted([f for f in os.listdir(DEMO_IMAGE_SOURCE) if f.endswith(\".png\")])\n            if not files:\n                raise RuntimeError(\"No PNG image found in demo folder.\")\n            demo_image = os.path.join(DEMO_IMAGE_SOURCE, files[0])\n        else:\n            demo_image = DEMO_IMAGE_SOURCE\n\n        phase8 = run_phase8_demo(demo_image)\n        results[\"phase8\"] = {\"status\": \"ok\", \"data\": phase8}\n        print(\"Demo output:\", phase8)\n    except Exception as e:\n        results[\"phase8\"] = {\"status\": \"failed\", \"erro`r\": str(e)}\n        print(\"Phase 8 failed:\", e)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"id":"9acb0dec-7456-4400-bfff-aee9e46b68e1","cell_type":"markdown","source":"## Save Summary","metadata":{}},{"id":"f6d09a0a-04e5-438c-b213-33564e67e0e8","cell_type":"code","source":"import os\nimport json\nimport glob\nimport shutil\nimport zipfile\nfrom datetime import datetime, timezone\nfrom pathlib import Path\n\nROOT = \"/kaggle/working/Code\"\nART = os.path.join(ROOT, \"artifacts\")\nRUNS = os.path.join(ROOT, \"runs\")\nHANDOFF = os.path.join(ART, \"web_handoff\")\n\nos.makedirs(ART, exist_ok=True)\nos.makedirs(HANDOFF, exist_ok=True)\n\n\ndef rel(p):\n    return os.path.relpath(p, ROOT).replace(\"\\\\\", \"/\")\n\n\ndef load_json_if_exists(path):\n    if os.path.exists(path):\n        with open(path, \"r\", encoding=\"utf-8\") as f:\n            return json.load(f)\n    return {}\n\n\ndef latest_best_pt():\n    cands = glob.glob(os.path.join(RUNS, \"**\", \"weights\", \"best.pt\"), recursive=True)\n    if not cands:\n        return None\n    cands.sort(key=os.path.getmtime, reverse=True)\n    return cands[0]\n\n\ndef safe_float(v):\n    try:\n        return float(v)\n    except Exception:\n        return None\n\n\ndef replace_file(src, dst):\n    \"\"\"\n    Copy src to dst and replace dst if it already exists.\n    \"\"\"\n    if not os.path.exists(src):\n        return False\n\n    os.makedirs(os.path.dirname(dst), exist_ok=True)\n\n    if os.path.exists(dst):\n        os.remove(dst)\n\n    shutil.copy2(src, dst)\n    return True\n\n\ndef clear_directory(path):\n    \"\"\"\n    Remove all contents inside a directory, including files and subfolders.\n    \"\"\"\n    if not os.path.exists(path):\n        os.makedirs(path, exist_ok=True)\n        return\n\n    for item in os.listdir(path):\n        item_path = os.path.join(path, item)\n        if os.path.isfile(item_path) or os.path.islink(item_path):\n            os.remove(item_path)\n        elif os.path.isdir(item_path):\n            shutil.rmtree(item_path)\n\n\nnow_iso = datetime.now(timezone.utc).isoformat()\n\nphase3_path = os.path.join(ART, \"phase3_baseline_results.json\")\nphase4_path = os.path.join(ART, \"phase4_best_hyperparameters.json\")\nphase5_path = os.path.join(ART, \"phase5_retrain_results.json\")\nphase6_path = os.path.join(ART, \"phase6_gradcam_results.json\")\nphase7_path = os.path.join(ART, \"phase7_final_evaluation.json\")\nphase8_path = os.path.join(ART, \"phase8_demo_result.json\")\ndemo_img_path = os.path.join(ART, \"demo_output.png\")\n\nphase3 = load_json_if_exists(phase3_path)\nphase4 = load_json_if_exists(phase4_path)\nphase5 = load_json_if_exists(phase5_path)\nphase6 = load_json_if_exists(phase6_path)\nphase7 = load_json_if_exists(phase7_path)\nphase8 = load_json_if_exists(phase8_path)\n\nbest_pt = latest_best_pt()\ngradcams = sorted(glob.glob(os.path.join(ART, \"gradcam\", \"*.png\")))\n\nbest_det = None\nbest_cls = None\nif isinstance(phase4, dict) and phase4:\n    items = {k: v for k, v in phase4.items() if isinstance(v, dict) and k != \"_errors\"}\n\n    det_candidates = {k: v for k, v in items.items() if v.get(\"task\") == \"detection\"}\n    cls_candidates = {k: v for k, v in items.items() if v.get(\"task\") == \"classification\"}\n\n    if det_candidates:\n        best_det = max(\n            det_candidates,\n            key=lambda k: det_candidates[k].get(\"best_score\", -1.0)\n        )\n\n    if cls_candidates:\n        best_cls = max(\n            cls_candidates,\n            key=lambda k: cls_candidates[k].get(\"best_score\", -1.0)\n        )\n\ndemo_detected = None\ndemo_conf = None\nif isinstance(phase8, dict):\n    demo_detected = phase8.get(\"detected\")\n    demo_conf = safe_float(phase8.get(\"confidence\"))\n\nhave_phase3 = os.path.exists(phase3_path)\nhave_weights = best_pt is not None\nstatus = \"COMPLETED\" if (have_phase3 and have_weights) else \"FAILED\"\n\npayload = {\n    \"job_id\": f\"rsna_{datetime.now(timezone.utc).strftime('%Y%m%d_%H%M%S')}\",\n    \"status\": status,\n    \"created_at\": now_iso,\n    \"finished_at\": now_iso,\n    \"project_root\": ROOT,\n    \"artifacts\": {\n        \"phase3_baseline_results\": rel(phase3_path) if os.path.exists(phase3_path) else None,\n        \"phase4_best_hyperparameters\": rel(phase4_path) if os.path.exists(phase4_path) else None,\n        \"phase5_retrain_results\": rel(phase5_path) if os.path.exists(phase5_path) else None,\n        \"phase6_gradcam_results\": rel(phase6_path) if os.path.exists(phase6_path) else None,\n        \"phase7_final_evaluation\": rel(phase7_path) if os.path.exists(phase7_path) else None,\n        \"phase8_demo_result\": rel(phase8_path) if os.path.exists(phase8_path) else None,\n        \"demo_output_image\": rel(demo_img_path) if os.path.exists(demo_img_path) else None,\n        \"gradcam_images\": [rel(p) for p in gradcams],\n        \"best_yolo_weights\": rel(best_pt) if best_pt else None,\n    },\n    \"summary\": {\n        \"best_detection_model\": best_det,\n        \"best_classification_model\": best_cls,\n        \"demo_detected\": demo_detected,\n        \"demo_confidence\": demo_conf,\n    },\n    \"error\": None if status == \"COMPLETED\" else \"Missing baseline results or YOLO weights\",\n}\n\n# This replaces your undefined `results` variable\nresults = {\n    \"status\": status,\n    \"created_at\": now_iso,\n    \"project_root\": ROOT,\n    \"best_detection_model\": best_det,\n    \"best_classification_model\": best_cls,\n    \"demo_detected\": demo_detected,\n    \"demo_confidence\": demo_conf,\n    \"best_yolo_weights\": rel(best_pt) if best_pt else None,\n}\n\n# These files are recreated and replaced if they already exist\nnotebook_summary_path = os.path.join(ART, \"kaggle_notebook_summary.json\")\nwith open(notebook_summary_path, \"w\", encoding=\"utf-8\") as f:\n    json.dump(results, f, indent=2)\n\nweb_result_path = os.path.join(ART, \"web_result.json\")\nwith open(web_result_path, \"w\", encoding=\"utf-8\") as f:\n    json.dump(payload, f, indent=2)\n\n# Clean old handoff contents completely, then refill with new copies\nclear_directory(HANDOFF)\n\n# Replace yolo_best.pt inside handoff\nif best_pt:\n    replace_file(best_pt, os.path.join(HANDOFF, \"yolo_best.pt\"))\n\ncopy_candidates = [\n    phase3_path,\n    phase4_path,\n    phase5_path,\n    phase6_path,\n    phase7_path,\n    phase8_path,\n    demo_img_path,\n    notebook_summary_path,\n    web_result_path,\n]\n\nfor src_path in copy_candidates:\n    if os.path.exists(src_path):\n        replace_file(src_path, os.path.join(HANDOFF, os.path.basename(src_path)))\n\nmanifest = {\n    \"created_at_utc\": now_iso,\n    \"model_type\": \"ultralytics_yolo_detection\",\n    \"weights_file\": \"yolo_best.pt\" if best_pt else None,\n    \"task\": \"pneumonia_detection\",\n    \"class_names\": [\"pneumonia\"],\n    \"default_imgsz\": 640,\n    \"default_conf\": 0.25,\n    \"status\": status,\n    \"handoff_files\": sorted(os.listdir(HANDOFF)),\n}\n\nmanifest_path = os.path.join(HANDOFF, \"manifest.json\")\nwith open(manifest_path, \"w\", encoding=\"utf-8\") as f:\n    json.dump(manifest, f, indent=2)\n\n# Replace old zip with new one\nzip_path = os.path.join(ART, \"web_handoff.zip\")\nif os.path.exists(zip_path):\n    os.remove(zip_path)\n\nwith zipfile.ZipFile(zip_path, \"w\", zipfile.ZIP_DEFLATED) as z:\n    for p in sorted(Path(HANDOFF).glob(\"*\")):\n        if p.is_file():\n            z.write(p, arcname=p.name)\n\nprint(\"Saved/Replaced:\", notebook_summary_path)\nprint(\"Saved/Replaced:\", web_result_path)\nprint(\"Saved/Replaced:\", manifest_path)\nprint(\"Saved/Replaced:\", zip_path)\nprint(\"Handoff files:\")\nfor p in sorted(Path(HANDOFF).glob(\"*\")):\n    if p.is_file():\n        print(\"-\", p.as_posix())","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}