""" Taxy ML — REST API Mandiri (FastAPI) ==================================== Melayani model Deep Learning + fitur Generative AI (Gemini) pada port 5001. Endpoints: GET /health -> status model & GenAI POST /predict -> prediksi risiko ketidakpatuhan (MODEL ML) + penjelasan GenAI POST /explanation -> penjelasan hasil kalkulasi pajak (GenAI) [dipakai dashboard] POST /chat -> chatbot Q&A pajak (GenAI) [fitur sekunder] Menjalankan: uvicorn serve:app --host 0.0.0.0 --port 5001 (atau) python serve.py Backend Node (be/controllers/aiController.js) sudah menunjuk ke http://127.0.0.1:5001 dan punya fallback bila server ini mati. """ import os from typing import Optional, Dict, Any from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware from pydantic import BaseModel # Muat .env sederhana (tanpa dependency tambahan) def _load_dotenv(): path = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".env") if os.path.exists(path): for line in open(path, encoding="utf-8"): line = line.strip() if line and not line.startswith("#") and "=" in line: k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) _load_dotenv() import inference import genai app = FastAPI(title="Taxy ML API", version="1.0.0", description="Deep Learning Tax-Compliance Risk Profiler + Gemini GenAI") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"], ) # ----------------------------- Schemas ------------------------------------- class PredictRequest(BaseModel): usia: float = 30 gaji_bulanan: float = 0 skor_literasi_pajak: float = 50 punya_npwp: int = 0 aktif_taxy: int = 0 status_ptkp: str = "TK/0" pekerjaan: str = "Junior Staff" kategori_pendapatan: Optional[str] = None class ExplanationRequest(BaseModel): taxData: Dict[str, Any] category: Optional[str] = "Pajak" class ChatRequest(BaseModel): message: str context: Optional[Dict[str, Any]] = None # ----------------------------- Startup ------------------------------------- @app.on_event("startup") def _startup(): inference.load() # muat model lebih awal genai.init_genai() # coba aktifkan Gemini (silent jika tak ada key) print("[Taxy ML API] Model dimuat. GenAI:", genai.status()) # ----------------------------- Endpoints ----------------------------------- @app.get("/health") def health(): return { "status": "ok", "service": "Taxy ML API", "model_loaded": inference._model is not None, "genai": genai.status(), } @app.post("/predict") def predict(req: PredictRequest): """Prediksi risiko ketidakpatuhan pajak dari profil pengguna (MODEL ML) + penjelasan natural dari Gemini (fallback lokal jika offline).""" profile = req.model_dump() pred = inference.predict(profile) nice = (f"usia {profile['usia']:.0f}, gaji {profile['gaji_bulanan']:,.0f}, " f"NPWP={'ya' if profile['punya_npwp'] else 'tidak'}, " f"literasi {profile['skor_literasi_pajak']:.0f}/100, " f"aktif Taxy={'ya' if profile['aktif_taxy'] else 'tidak'}") expl = genai.explain_risk(nice, pred) return {"success": True, "prediction": pred, "explanation": expl["explanation"], "source": expl["source"]} @app.post("/explanation") def explanation(req: ExplanationRequest): """Penjelasan hasil kalkulasi pajak (dipakai 'Insight Pajak AI' di dashboard).""" out = genai.explain_tax(req.taxData, req.category) return {"success": True, "data": {"explanation": out["explanation"]}, "source": out["source"]} @app.post("/chat") def chat(req: ChatRequest): """Chatbot Q&A pajak (fitur sekunder Generative AI).""" out = genai.chat(req.message, req.context) return {"success": True, "reply": out["reply"], "source": out["source"]} if __name__ == "__main__": import uvicorn # PORT dari environment (Hugging Face Spaces=7860, Cloud Run=8080, lokal=5001) port = int(os.environ.get("PORT", 5001)) uvicorn.run(app, host="0.0.0.0", port=port)