""" oO ML Serving — Phase 0 stub. Returns a placeholder response that matches the interface the real scorer will implement. The recommender service calls this via RemotePolicy (not yet wired in Phase 0). Contract: POST /score Body: { user_id: str, candidates: [{ id: str, content: str, source: str, source_id?: str }] } Response: { tip_id: str, score: float } """ from fastapi import FastAPI, HTTPException from pydantic import BaseModel import random app = FastAPI(title="oO ML Serving", version="0.0.0") class Candidate(BaseModel): id: str content: str source: str source_id: str | None = None class ScoreRequest(BaseModel): user_id: str candidates: list[Candidate] class ScoreResponse(BaseModel): tip_id: str score: float policy: str @app.get("/health") def health(): return {"ok": True} @app.post("/score", response_model=ScoreResponse) def score(req: ScoreRequest): if not req.candidates: raise HTTPException(status_code=422, detail="No candidates") # Stub: random uniform scoring — real model slots in here chosen = random.choice(req.candidates) return ScoreResponse(tip_id=chosen.id, score=1.0, policy="stub-random")