"""saju API — /api/saju/* 6 endpoints.""" from fastapi import APIRouter, HTTPException, Query from typing import Optional from ..models import ( SajuInterpretRequest, SajuInterpretResponse, SajuPatchRequest, ) from ..interpret import pipeline from ..calculator.core import calculate_saju from ..calculator.analysis import perform_full_analysis from ..calculator.daeun import calculate_daeun from ..calculator.lunar import lunar_to_solar from ..config import SAJU_MODEL from .. import db as db_module router = APIRouter(prefix="/api/saju") @router.post("/interpret", response_model=SajuInterpretResponse) async def interpret_saju_endpoint(req: SajuInterpretRequest): """사주 입력 → 계산 + AI 해석 + DB 저장.""" from datetime import date if req.calendar_type == "lunar": sy, sm, sd = lunar_to_solar(req.year, req.month, req.day, req.is_leap_month) else: sy, sm, sd = req.year, req.month, req.day try: saju = calculate_saju(sy, sm, sd, req.hour, req.gender) analysis = perform_full_analysis(saju, 2026) daeun = calculate_daeun(sy, sm, sd, req.gender, saju["month"]["stem"], saju["month"]["branch"]) # 신규 from ..calculator.fortune_scores import calculate_fortune_scores from ..calculator.lucky import calculate_lucky from ..calculator.monthly_flow import calculate_monthly_flow fortune_scores = calculate_fortune_scores(saju, analysis, 2026) lucky = calculate_lucky(saju, analysis, date.today()) monthly_flow = calculate_monthly_flow(saju, 2026) except Exception as e: raise HTTPException(status_code=400, detail=f"계산 실패: {e}") try: interp_result = await pipeline.interpret_saju(saju, analysis, daeun, 2026) except pipeline.SajuError as e: raise HTTPException(status_code=500, detail=str(e)) from e rid = db_module.save_saju_record({ "birth_year": req.year, "birth_month": req.month, "birth_day": req.day, "birth_hour": req.hour, "gender": req.gender, "calendar_type": req.calendar_type, "saju_data": saju, "analysis_data": analysis, "daeun_data": daeun, "interpretation_json": interp_result["interpretation_json"], "model": interp_result["model"], "tokens_in": interp_result["tokens_in"], "tokens_out": interp_result["tokens_out"], "cost_usd": interp_result["cost_usd"], "latency_ms": interp_result["latency_ms"], "reroll_count": interp_result["reroll_count"], "fortune_scores_json": fortune_scores, "lucky_json": lucky, "monthly_flow_json": monthly_flow, }) return { "saju": saju, "analysis": analysis, "daeun": daeun, "interpretation_json": interp_result["interpretation_json"], "reading_id": rid, "model": interp_result["model"], "tokens_in": interp_result["tokens_in"], "tokens_out": interp_result["tokens_out"], "cost_usd": interp_result["cost_usd"], "latency_ms": interp_result["latency_ms"], "reroll_count": interp_result["reroll_count"], "fortune_scores": fortune_scores, "lucky": lucky, "monthly_flow": monthly_flow, } @router.get("/readings") async def list_readings( page: int = 1, size: int = 20, favorite: Optional[bool] = None, ): return db_module.list_saju_records(page=page, size=size, favorite=favorite) @router.get("/readings/{reading_id}") async def get_reading(reading_id: int): row = db_module.get_saju_record(reading_id) if not row: raise HTTPException(status_code=404, detail="reading not found") return row @router.patch("/readings/{reading_id}") async def patch_reading(reading_id: int, req: SajuPatchRequest): row = db_module.get_saju_record(reading_id) if not row: raise HTTPException(status_code=404, detail="reading not found") db_module.update_saju_record(reading_id, **req.model_dump(exclude_none=True)) return {"ok": True} @router.delete("/readings/{reading_id}") async def delete_reading(reading_id: int): row = db_module.get_saju_record(reading_id) if not row: raise HTTPException(status_code=404, detail="reading not found") db_module.delete_saju_record(reading_id) return {"ok": True} @router.get("/current-fortune") async def current_fortune(reading_id: int = Query(...)): """저장된 사주의 오늘 세운 (실시간 계산, AI 호출 없음).""" row = db_module.get_saju_record(reading_id) if not row: raise HTTPException(status_code=404, detail="reading not found") from datetime import datetime saju = row["saju_data"] current_year = datetime.now().year from ..calculator.analysis import calculate_seun seun = calculate_seun(current_year, saju) return {"reading_id": reading_id, "year": current_year, "seun": seun}