Spaces:
Runtime error
Runtime error
| """Run the end-to-end macro demo for a small batch of meal images. | |
| Example: | |
| python scripts/run_batch_meal_macro_demo.py --image-glob "data/processed/foodseg103_target_yolo/images/val/*.jpg" --limit 5 | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import csv | |
| import glob | |
| import json | |
| import os | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| PROJECT_ROOT = Path(__file__).resolve().parents[1] | |
| DEFAULT_OUTPUT_DIR = PROJECT_ROOT / "output" / "demo" | |
| DEFAULT_SUMMARY_CSV = PROJECT_ROOT / "output" / "batch_summary.csv" | |
| def flatten_summary(summary_path: Path) -> dict[str, object]: | |
| """Flatten one demo summary.json into a single CSV-friendly row.""" | |
| summary = json.loads(Path(summary_path).read_text(encoding="utf-8")) | |
| row: dict[str, object] = { | |
| "image": summary.get("image"), | |
| "summary_path": str(summary_path), | |
| } | |
| segments = (summary.get("segments") or {}).get("segments") or [] | |
| for segment in segments: | |
| name = segment.get("class_name") | |
| if name: | |
| row[f"{name}_area_fraction"] = segment.get("area_fraction") | |
| gemini = summary.get("gemini_analysis") or {} | |
| if gemini.get("meal_summary") is not None: | |
| row["meal_summary"] = gemini.get("meal_summary") | |
| for component in gemini.get("components") or []: | |
| name = component.get("class_name") | |
| if name: | |
| row[f"{name}_likely_food"] = component.get("likely_food") | |
| row[f"{name}_fdc_query"] = component.get("fdc_query") | |
| totals = (summary.get("macro_estimate") or {}).get("totals") or {} | |
| for key in ("grams", "kcal", "protein", "fat", "carbs"): | |
| if key in totals: | |
| row[key] = totals[key] | |
| return row | |
| def parse_args() -> argparse.Namespace: | |
| parser = argparse.ArgumentParser(description=__doc__) | |
| parser.add_argument("--image-glob", required=True) | |
| parser.add_argument("--limit", type=int, default=5) | |
| parser.add_argument("--output-dir", type=Path, default=DEFAULT_OUTPUT_DIR) | |
| parser.add_argument("--summary-csv", type=Path, default=DEFAULT_SUMMARY_CSV) | |
| parser.add_argument("--use-gemini", action=argparse.BooleanOptionalAction, default=True) | |
| parser.add_argument("--use-usda", action=argparse.BooleanOptionalAction, default=True) | |
| return parser.parse_args() | |
| def run_one(image_path: Path, args: argparse.Namespace, env: dict[str, str]) -> Path: | |
| command = [ | |
| sys.executable, | |
| "scripts/run_meal_macro_demo.py", | |
| "--image", | |
| str(image_path), | |
| "--output-dir", | |
| str(args.output_dir), | |
| ] | |
| if not args.use_gemini: | |
| command.append("--no-use-gemini") | |
| if not args.use_usda: | |
| command.append("--no-use-usda") | |
| print(f"+ {' '.join(command)}", flush=True) | |
| subprocess.run(command, cwd=PROJECT_ROOT, env=env, check=True) | |
| return args.output_dir / image_path.stem / "summary.json" | |
| def main() -> None: | |
| args = parse_args() | |
| image_paths = [Path(path) for path in sorted(glob.glob(args.image_glob))] | |
| if args.limit is not None: | |
| image_paths = image_paths[: args.limit] | |
| if not image_paths: | |
| raise SystemExit(f"No images matched: {args.image_glob}") | |
| env = os.environ.copy() | |
| rows = [] | |
| for index, image_path in enumerate(image_paths, start=1): | |
| print(f"\n[{index}/{len(image_paths)}] {image_path}", flush=True) | |
| summary_path = run_one(image_path, args, env) | |
| rows.append(flatten_summary(summary_path)) | |
| fieldnames = sorted({key for row in rows for key in row}) | |
| args.summary_csv.parent.mkdir(parents=True, exist_ok=True) | |
| with args.summary_csv.open("w", newline="", encoding="utf-8") as f: | |
| writer = csv.DictWriter(f, fieldnames=fieldnames) | |
| writer.writeheader() | |
| writer.writerows(rows) | |
| print(f"Wrote batch summary: {args.summary_csv}") | |
| if __name__ == "__main__": | |
| main() | |