"""Gemini real-call PREFLIGHT — readiness gate, never calls the API. This script decides whether all preconditions for a (separate, manual) real Gemini smoke are in place. It NEVER contacts Gemini, even when GEMINI_ENABLE_REAL_CALL=true. The actual call is performed only by a human following docs/gemini_provider_smoke_runbook.md. Safety: - No external API call. real_call_performed is always False. - GEMINI_API_KEY is reported as a boolean presence only; the value is never printed, logged, or stored. Output keys: preflight_status: READY | NOT_READY api_key_present / enable_real_call / input_image_exists / output_dir_exists / runbook_exists / policy_exists : true|false real_call_performed: false """ from __future__ import annotations import argparse import os import sys from pathlib import Path _THIS = Path(__file__).resolve() DEFAULT_REPO_ROOT = _THIS.parents[2] # backend/scripts -> backend -> repo DEFAULT_EVIDENCE_ROOT = Path( r"C:\Users\Admin\Documents\헤어\field-test-evidence" r"\v0.1.0-staging\2026-05-31-single-device-smoke-01" ) RUNBOOK_REL = "docs/gemini_provider_smoke_runbook.md" POLICY_REL = "docs/synthetic_test_image_policy.md" def _truthy(value: str | None) -> bool: return str(value or "").strip().lower() in {"1", "true", "yes", "on"} def build_preflight( *, input_image: str | os.PathLike | None = None, evidence_root: str | os.PathLike = DEFAULT_EVIDENCE_ROOT, repo_root: str | os.PathLike = DEFAULT_REPO_ROOT, env: dict | None = None, ) -> dict: """Compute readiness. Reads env lazily; never returns the API key value.""" env = os.environ if env is None else env evidence_root = Path(evidence_root) repo_root = Path(repo_root) api_key_present = bool((env.get("GEMINI_API_KEY") or "").strip()) enable_real_call = _truthy(env.get("GEMINI_ENABLE_REAL_CALL")) gemini_model = (env.get("GEMINI_MODEL") or "gemini-2.5-flash-image").strip() input_image_exists = bool(input_image) and Path(input_image).exists() output_dir = evidence_root / "gemini-smoke" / "output" output_dir_exists = output_dir.exists() runbook_exists = (repo_root / RUNBOOK_REL).exists() policy_exists = (repo_root / POLICY_REL).exists() checks = { "api_key_present": api_key_present, "enable_real_call": enable_real_call, "input_image_exists": input_image_exists, "output_dir_exists": output_dir_exists, "runbook_exists": runbook_exists, "policy_exists": policy_exists, } missing = [name for name, ok in checks.items() if not ok] ready = not missing return { "preflight_status": "READY" if ready else "NOT_READY", "real_call_performed": False, # this script never calls the API "gemini_model": gemini_model, **checks, "missing": missing, "input_image": str(input_image) if input_image else None, "output_dir": str(output_dir), "runbook": str(repo_root / RUNBOOK_REL), "policy": str(repo_root / POLICY_REL), "note": ( "Preflight only - Gemini was NOT contacted. Run the real call manually " f"per {RUNBOOK_REL}. Never use real customer or real-person photos." ), } def _b(value: bool) -> str: return "true" if value else "false" def main(argv: list[str] | None = None) -> int: parser = argparse.ArgumentParser(description="Gemini real-call preflight (no API call)") parser.add_argument("--input-image", default=None) parser.add_argument("--evidence-root", default=str(DEFAULT_EVIDENCE_ROOT)) args = parser.parse_args(argv) report = build_preflight( input_image=args.input_image, evidence_root=args.evidence_root, ) print(f"preflight_status: {report['preflight_status']}") print(f"api_key_present: {_b(report['api_key_present'])} (value never printed)") print(f"enable_real_call: {_b(report['enable_real_call'])}") print(f"gemini_model: {report['gemini_model']}") print(f"input_image_exists: {_b(report['input_image_exists'])}") print(f"output_dir_exists: {_b(report['output_dir_exists'])}") print(f"runbook_exists: {_b(report['runbook_exists'])}") print(f"policy_exists: {_b(report['policy_exists'])}") print(f"real_call_performed: {_b(report['real_call_performed'])}") if report["missing"]: print(f"missing: {', '.join(report['missing'])}") print(f"note: {report['note']}") return 0 if report["preflight_status"] == "READY" else 1 if __name__ == "__main__": sys.exit(main())