{"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":"datasetVersion","sourceId":15523711,"datasetId":9931822,"databundleVersionId":16450824}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"b9aa5517-e372-454c-946d-6ebaae1ef27f","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":"6789cf3f","cell_type":"code","source":"#for kaggle\nimport os\nos.environ[\"RSNA_DATA_DIR\"] = \"/kaggle/input/competitions/rsna-pneumonia-detection-challenge\"\nimport shutil\nfrom pathlib import Path\n\nSRC = Path(\"/kaggle/input/datasets/moemenelsayed/mycode2/Code\")\nDST = Path(\"/kaggle/working/Code\")\n\n# check source exists\nif not SRC.exists():\n    raise FileNotFoundError(f\"Source folder not found: {SRC}\")\n\n# remove old version safely\nif DST.exists():\n    shutil.rmtree(DST)\n\n# copy\nshutil.copytree(SRC, DST)\n\nprint(\"✅ Copied to:\", DST)\n\n# quick verification\nprint(\"\\nFiles inside Code:\")\nfor item in DST.iterdir():\n    print(\" -\", item)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T16:12:40.804757Z","iopub.execute_input":"2026-04-04T16:12:40.805545Z","iopub.status.idle":"2026-04-04T16:12:41.203285Z","shell.execute_reply.started":"2026-04-04T16:12:40.805510Z","shell.execute_reply":"2026-04-04T16:12:41.202629Z"}},"outputs":[],"execution_count":null},{"id":"8f0be699-992f-4bdf-875d-f37bfa689520","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-04T16:12:41.204553Z","iopub.execute_input":"2026-04-04T16:12:41.204810Z","iopub.status.idle":"2026-04-04T16:12:48.601867Z","shell.execute_reply.started":"2026-04-04T16:12:41.204787Z","shell.execute_reply":"2026-04-04T16:12:48.601306Z"}},"outputs":[],"execution_count":null},{"id":"e2a84702-d57f-4370-ab4d-b6f814b39f34","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-04T16:12:48.602649Z","iopub.execute_input":"2026-04-04T16:12:48.602861Z","iopub.status.idle":"2026-04-04T16:12:48.611165Z","shell.execute_reply.started":"2026-04-04T16:12:48.602840Z","shell.execute_reply":"2026-04-04T16:12:48.610609Z"}},"outputs":[],"execution_count":null},{"id":"75bb8d6a-2920-45fe-a145-0e7320283d42","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-04T16:12:48.612503Z","iopub.execute_input":"2026-04-04T16:12:48.612853Z","iopub.status.idle":"2026-04-04T16:13:05.551771Z","shell.execute_reply.started":"2026-04-04T16:12:48.612816Z","shell.execute_reply":"2026-04-04T16:13:05.550890Z"}},"outputs":[],"execution_count":null},{"id":"7351efb4-1499-4306-b2c6-30af56378007","cell_type":"code","source":"# Config flags\nRUN_PHASE1 = True\nRUN_PHASE2 = True\nRUN_PHASE3 = True\nRUN_PHASE4 = False\nRUN_PHASE5 = False\nRUN_PHASE6 = False\nRUN_PHASE7 = False\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-04T16:13:05.552785Z","iopub.execute_input":"2026-04-04T16:13:05.553514Z","iopub.status.idle":"2026-04-04T16:13:05.558228Z","shell.execute_reply.started":"2026-04-04T16:13:05.553476Z","shell.execute_reply":"2026-04-04T16:13:05.557573Z"}},"outputs":[],"execution_count":null},{"id":"b2cdc674-a2ee-44fc-be7b-c7d577475543","cell_type":"markdown","source":"## Phase 1 - Data Exploration and PNG Conversion","metadata":{}},{"id":"9df04139","cell_type":"code","source":"df = None\npreflight = run_preflight_checks()\nresults[\"preflight\"] = preflight\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T16:13:05.559118Z","iopub.execute_input":"2026-04-04T16:13:05.559504Z","iopub.status.idle":"2026-04-04T16:13:05.593131Z","shell.execute_reply.started":"2026-04-04T16:13:05.559471Z","shell.execute_reply":"2026-04-04T16:13:05.592544Z"}},"outputs":[],"execution_count":null},{"id":"c9444017-bd5b-47d6-92b1-7386050c7f1d","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-04T16:13:05.594028Z","iopub.execute_input":"2026-04-04T16:13:05.594314Z","iopub.status.idle":"2026-04-04T16:24:30.860849Z","shell.execute_reply.started":"2026-04-04T16:13:05.594282Z","shell.execute_reply":"2026-04-04T16:24:30.860257Z"}},"outputs":[],"execution_count":null},{"id":"a33d00a2-4c2c-4aee-9d59-192c3bd68b4c","cell_type":"markdown","source":"## Phase 2 - Build YOLO Dataset and Visualization","metadata":{}},{"id":"42f0ef0d-6491-47c7-bd60-cd14d9f0c575","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-04T16:24:30.861790Z","iopub.execute_input":"2026-04-04T16:24:30.862082Z","iopub.status.idle":"2026-04-04T16:31:37.269603Z","shell.execute_reply.started":"2026-04-04T16:24:30.862038Z","shell.execute_reply":"2026-04-04T16:31:37.268804Z"}},"outputs":[],"execution_count":null},{"id":"b8598681-6562-4449-a872-3929dafad2fb","cell_type":"markdown","source":"## Phase 3 - Baseline Training (Per Model Try/Except)","metadata":{}},{"id":"282d0e1a-d7f7-421f-8c20-d05da4e3aed5","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-04T16:31:37.271010Z","iopub.execute_input":"2026-04-04T16:31:37.271629Z","iopub.status.idle":"2026-04-04T19:48:28.733603Z","shell.execute_reply.started":"2026-04-04T16:31:37.271586Z","shell.execute_reply":"2026-04-04T19:48:28.732661Z"}},"outputs":[],"execution_count":null},{"id":"d8e21245-be49-4c5f-9000-06ce0594927c","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":"690dd980-5bad-4af8-b0f3-154d6f7c7d28","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-04T19:48:28.736485Z","iopub.execute_input":"2026-04-04T19:48:28.736811Z","iopub.status.idle":"2026-04-04T19:48:28.741481Z","shell.execute_reply.started":"2026-04-04T19:48:28.736779Z","shell.execute_reply":"2026-04-04T19:48:28.740835Z"}},"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,"execution":{"iopub.status.busy":"2026-04-04T19:48:28.742485Z","iopub.execute_input":"2026-04-04T19:48:28.743106Z","iopub.status.idle":"2026-04-04T19:48:28.761360Z","shell.execute_reply.started":"2026-04-04T19:48:28.743075Z","shell.execute_reply":"2026-04-04T19:48:28.760801Z"}},"outputs":[],"execution_count":null},{"id":"f6388967-6329-4ecf-aa4e-2dddd771cc07","cell_type":"markdown","source":"## Phase 6 - Explainability (Grad-CAM)","metadata":{}},{"id":"e9e3ceeb-c478-46ae-a21e-ca93232b3bc4","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,"execution":{"iopub.status.busy":"2026-04-04T19:48:28.762204Z","iopub.execute_input":"2026-04-04T19:48:28.762444Z","iopub.status.idle":"2026-04-04T19:48:28.774953Z","shell.execute_reply.started":"2026-04-04T19:48:28.762407Z","shell.execute_reply":"2026-04-04T19:48:28.774364Z"}},"outputs":[],"execution_count":null},{"id":"18b4104f-4e63-4181-8d1b-0b168c92a882","cell_type":"markdown","source":"## Phase 7 - Final Evaluation","metadata":{}},{"id":"d96df126-5757-4ccd-a995-ab9978cb07a8","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,"execution":{"iopub.status.busy":"2026-04-04T19:48:28.775796Z","iopub.execute_input":"2026-04-04T19:48:28.776219Z","iopub.status.idle":"2026-04-04T19:48:28.788178Z","shell.execute_reply.started":"2026-04-04T19:48:28.776194Z","shell.execute_reply":"2026-04-04T19:48:28.787638Z"}},"outputs":[],"execution_count":null},{"id":"b8e58c5b-f7d8-4c4e-9ec9-754ecf3ba1f3","cell_type":"markdown","source":"## Phase 8 - Final Demo","metadata":{}},{"id":"b6db62b8-916f-481a-9f9c-934b73fe10c3","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\", \"error\": str(e)}\n        print(\"Phase 8 failed:\", e)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:48:28.788979Z","iopub.execute_input":"2026-04-04T19:48:28.789313Z","iopub.status.idle":"2026-04-04T19:48:28.925721Z","shell.execute_reply.started":"2026-04-04T19:48:28.789289Z","shell.execute_reply":"2026-04-04T19:48:28.925081Z"}},"outputs":[],"execution_count":null},{"id":"fbc25da0-6f65-4b0e-97d6-ff65083c0311","cell_type":"markdown","source":"## Save Summary","metadata":{}},{"id":"27c0d71a","cell_type":"code","source":"import os, json, glob, shutil, 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\")\nos.makedirs(ART, exist_ok=True)\nos.makedirs(HANDOFF, exist_ok=True)\n\ndef rel(p):\n    return os.path.relpath(p, ROOT).replace(\"\\\\\", \"/\")\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\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\ndef safe_float(v):\n    try:\n        return float(v)\n    except Exception:\n        return None\n\nnow_iso = datetime.now(timezone.utc).isoformat()\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)\nphase8 = load_json_if_exists(phase8_path)\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    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    if det_candidates:\n        best_det = max(det_candidates, key=lambda k: det_candidates[k].get(\"best_score\", -1.0))\n    if cls_candidates:\n        best_cls = max(cls_candidates, key=lambda k: cls_candidates[k].get(\"best_score\", -1.0))\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\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\nfor old_file in glob.glob(os.path.join(HANDOFF, \"*\")):\n    if os.path.isfile(old_file):\n        os.remove(old_file)\n\nif best_pt:\n    shutil.copy2(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]\nfor src_path in copy_candidates:\n    if os.path.exists(src_path):\n        shutil.copy2(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}\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\nzip_path = os.path.join(ART, \"web_handoff.zip\")\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:\", notebook_summary_path)\nprint(\"Saved:\", web_result_path)\nprint(\"Saved:\", manifest_path)\nprint(\"Saved:\", zip_path)\nprint(\"Handoff files:\")\nfor p in sorted(Path(HANDOFF).glob(\"*\")):\n    if p.is_file():\n        print(\"-\", p.as_posix())\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-04-04T19:48:28.926738Z","iopub.execute_input":"2026-04-04T19:48:28.927070Z","iopub.status.idle":"2026-04-04T19:48:29.295718Z","shell.execute_reply.started":"2026-04-04T19:48:28.927031Z","shell.execute_reply":"2026-04-04T19:48:29.295049Z"}},"outputs":[],"execution_count":null},{"id":"d6e88bf5-0b92-4552-bd91-ebc32622cb89","cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}