from __future__ import annotations from fastapi import FastAPI, Body from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import pandas as pd from typing import Dict, Any, List from data import append_events, read_events, aggregate from bandit import EmpiricalBayesHierarchicalThompson from causal import fit_uplift_binary # Gradio を FastAPI にマウント from dashboard import build_ui import gradio as gr app = FastAPI(title="AdCopy MAB Optimizer Pro", version="0.1.0") app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) ui = build_ui() app = gr.mount_gradio_app(app, ui, path="/") BANDIT = EmpiricalBayesHierarchicalThompson(min_explore=0.05, margin=0.0, n_draws=20000) @app.get("/api/health") def health(): return {"status": "ok"} @app.get("/api/events") def get_events(): df = read_events() return JSONResponse(content=df.to_dict(orient="records")) @app.post("/api/ingest") def ingest(rows: List[Dict[str, Any]] = Body(..., embed=True)): """ rows: [ {"date":"2025-09-01","medium":"FB","creative":"A1","is_control":1,"impressions":1000,"clicks":30,"conversions":5,"cost":1000.0,"features_json":"{\\"len\\":20}"}, ... ] """ df = pd.DataFrame(rows) append_events(df) return {"ok": True, "n": len(df)} @app.get("/api/aggregate") def get_agg(): agg = aggregate() return JSONResponse(content=agg.to_dict(orient="records")) @app.post("/api/optimize") def optimize(): agg = aggregate() if agg.empty: return {"message": "no data"} rec = BANDIT.recommend(agg) return JSONResponse(content=rec) @app.post("/api/uplift") def uplift(): agg = aggregate() if agg.empty: return {"message": "no data"} res = fit_uplift_binary(agg) return JSONResponse(content=res)