Israelbliz's picture
Upload run.py
6a4c311 verified
Raw
History Blame Contribute Delete
4.86 kB
"""
run.py
======
CLI entry point. Demonstrates the full pipeline and prints a QA summary.
Usage:
# Extraction + validation only (no API key needed):
python run.py path/to/Master_Sheet.xlsx --no-llm
# Full run with narratives (requires GOOGLE_API_KEY):
python run.py path/to/Master_Sheet.xlsx --developer "Green Edge Consortium"
The mini-grid capacities are an external input (developer-supplied, not in the
survey data). Pass them with --solar-pv / --battery / --annual-consumption, or
fill them in afterwards on the returned object before rendering.
"""
from __future__ import annotations
import argparse
from pue_report_agent import extract_master_sheet, validate, recompute
from pue_report_agent.schema import EnergySystemSpec
def main() -> None:
ap = argparse.ArgumentParser(description="PUE report builder")
ap.add_argument("master_sheet")
ap.add_argument("--developer", default="the mini-grid developer")
ap.add_argument("--no-llm", action="store_true",
help="skip narrative generation (no API key required)")
ap.add_argument("--solar-pv", default="")
ap.add_argument("--battery", default="")
ap.add_argument("--annual-consumption", default="")
ap.add_argument("--date", default="", help="report date for the title page")
ap.add_argument("--docx-out", default="",
help="render a template-faithful .docx to this path")
ap.add_argument("--json-out", default="",
help="write the full PUEReportData JSON to this path")
ap.add_argument("--developer-logo", default="",
help="optional path to developer logo image "
"(placed on the left of the page header)")
ap.add_argument("--dreef-logo", default="",
help="optional path to DREEF logo image "
"(placed on the right of the page header)")
args = ap.parse_args()
# 1. Deterministic extraction
data = extract_master_sheet(args.master_sheet)
# 2. Recompute every total from line items (never trust a sheet total)
data = recompute(data)
# 3. External developer-supplied capacity overrides (optional). Merge into
# the already-extracted minigrid so we don't discard the distribution
# metrics / inverter that extraction pulled from Key Findings.
if args.solar_pv:
data.minigrid.solar_pv = args.solar_pv
if args.battery:
data.minigrid.battery_storage = args.battery
if args.annual_consumption:
data.minigrid.annual_consumption = args.annual_consumption
# 4. Validation / reconciliation
data = validate(data)
# 5. Narratives (optional). All narratives use Gemini.
if not args.no_llm:
from pue_report_agent import generate_narratives
if generate_narratives is None:
print("[warn] langchain not installed; skipping narratives.")
else:
data = generate_narratives(data)
# 6. QA summary
_print_summary(data)
# 7. Render the template-faithful Word document
if args.docx_out:
from pue_report_agent.render import render
render(data, args.docx_out, developer=args.developer,
report_date=args.date,
developer_logo_path=args.developer_logo or None,
dreef_logo_path=args.dreef_logo or None)
print(f"\nWrote {args.docx_out}")
if args.json_out:
with open(args.json_out, "w") as fh:
fh.write(data.model_dump_json(indent=2))
print(f"Wrote {args.json_out}")
def _print_summary(data) -> None:
c = data.community
print("=" * 64)
print(f" {c.name} ({c.lga}, {c.state})")
print("=" * 64)
print(f" Interviewed: {data.interviews.total} "
f"(farmers {data.interviews.farmers}, processors "
f"{data.interviews.agroprocessors}, SME {data.interviews.sme}, "
f"mobility {data.interviews.mobility})")
print(f" Farmers: {data.farmers.male}M / {data.farmers.female}F, "
f"{len(data.farmers.crops)} crops")
print(f" Processors: {data.processors.male}M / {data.processors.female}F, "
f"{len(data.processors.machinery)} machines on record")
print(f" SME types: {len(data.sme.types)} Mobility: {data.mobility.total}")
print(f" Pilot energy: {data.equipment_pilot.projection_total_kwh} kWh "
f"ScaleUp: {data.equipment_scaleup.projection_total_kwh} kWh")
print(f" Budget grand total: ₦{(data.budget.grand_total or 0):,.0f}")
print(f" Financial models: {[m.model_name for m in data.financial_models]}")
print()
if data.warnings:
print(f" ⚠ {len(data.warnings)} item(s) need review:")
for w in data.warnings:
print(f" • {w}")
else:
print(" ✓ no warnings")
if __name__ == "__main__":
main()