Fork of Lightning_Report adding: - n8n_report_branch.json: workflow branch for storm-triggered report delivery - report_service/: FastAPI microservice wrapping create_docx_report() so n8n can produce byte-identical reports without fighting the Python Code sandbox Made-with: Cursor
85 lines
3.1 KiB
Python
85 lines
3.1 KiB
Python
import sys
|
|
import argparse
|
|
import logging
|
|
from typing import Any
|
|
|
|
from src.api.data_fetcher import APIDataFetcher
|
|
|
|
import batch_generate
|
|
|
|
# Set up logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.StreamHandler(sys.stdout),
|
|
logging.FileHandler('lightning_report.log')
|
|
]
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def main():
|
|
"""Generate DOCX reports (from wind_farms_config.json)."""
|
|
try:
|
|
parser = argparse.ArgumentParser(description="DOCX lightning report generation (from wind_farms_config.json)")
|
|
parser.add_argument("--config", default="wind_farms_config.json", help="Path to wind_farms_config.json")
|
|
parser.add_argument("--farm-id", default=None, help="farm_id to process (if omitted, process enabled farms)")
|
|
parser.add_argument("--force", action="store_true", help="Process even if farm is disabled")
|
|
args = parser.parse_args()
|
|
|
|
logger.info("Starting DOCX report generation...")
|
|
config = batch_generate.load_wind_farms_config(args.config)
|
|
farms = config.get("wind_farms", [])
|
|
|
|
api_cfg = config["api_config"]
|
|
api_fetcher = APIDataFetcher(
|
|
base_url=api_cfg["base_url"],
|
|
timeout=api_cfg.get("timeout_seconds", 30),
|
|
retry_attempts=api_cfg.get("retry_attempts", 3),
|
|
)
|
|
|
|
if args.farm_id:
|
|
farms_to_process = [f for f in farms if f.get("farm_id") == args.farm_id]
|
|
if not farms_to_process:
|
|
logger.error(f"Farm '{args.farm_id}' not found in {args.config}")
|
|
sys.exit(1)
|
|
else:
|
|
farms_to_process = farms
|
|
|
|
results: list[dict[str, Any]] = []
|
|
for idx, farm in enumerate(farms_to_process, 1):
|
|
farm_id = farm.get("farm_id")
|
|
name = farm.get("name", farm_id)
|
|
if not args.force and not farm.get("enabled", True):
|
|
logger.info(f"[{idx}/{len(farms_to_process)}] Skipping disabled farm: {farm_id} ({name})")
|
|
continue
|
|
|
|
logger.info(f"[{idx}/{len(farms_to_process)}] Processing farm: {farm_id} ({name})")
|
|
result = batch_generate.process_farm(farm, api_fetcher, config)
|
|
results.append(result)
|
|
|
|
if result.get("status") != "success":
|
|
logger.error(f"Report generation failed for {farm_id}: {result.get('error')}")
|
|
# Keep going if doing batch; stop early for single farm.
|
|
if args.farm_id:
|
|
sys.exit(1)
|
|
|
|
for r in results:
|
|
if r.get("status") == "success":
|
|
logger.info(f"✅ DOCX report saved as {r.get('docx_path')}")
|
|
|
|
logger.info("Lightning report generation completed successfully!")
|
|
|
|
except FileNotFoundError as e:
|
|
logger.error(f"File not found: {e}")
|
|
sys.exit(1)
|
|
except ValueError as e:
|
|
logger.error(f"Data validation error: {e}")
|
|
sys.exit(1)
|
|
except Exception as e:
|
|
logger.error(f"Unexpected error: {e}")
|
|
sys.exit(1)
|
|
|
|
if __name__ == '__main__':
|
|
main()
|