| import json
|
| import time
|
| from pathlib import Path
|
| from typing import Optional
|
|
|
| from fastapi import APIRouter
|
| from pydantic import BaseModel, field_validator
|
|
|
| from src.config import get_settings
|
|
|
| router = APIRouter()
|
|
|
|
|
| class FeedbackRequest(BaseModel):
|
| question: str
|
| feedback: str
|
| answer_excerpt: Optional[str] = ""
|
|
|
| @field_validator("feedback")
|
| @classmethod
|
| def valid_feedback(cls, v: str) -> str:
|
| if v not in {"up", "down"}:
|
| raise ValueError("feedback must be up or down")
|
| return v
|
|
|
|
|
| @router.post("")
|
| async def save_feedback(req: FeedbackRequest):
|
| settings = get_settings()
|
| payload = {
|
| "timestamp": time.time(),
|
| "question": req.question[:1000],
|
| "feedback": req.feedback,
|
| "answer_excerpt": (req.answer_excerpt or "")[:1500],
|
| }
|
| settings.feedback_path.parent.mkdir(parents=True, exist_ok=True)
|
| with settings.feedback_path.open("a", encoding="utf-8") as handle:
|
| handle.write(json.dumps(payload, ensure_ascii=False) + "\n")
|
| try:
|
| from app import metrics_service
|
| metrics_service.incr("feedback_total")
|
| metrics_service.incr_bucket("feedback_breakdown", req.feedback)
|
| except Exception:
|
| pass
|
| return {"status": "ok"}
|
|
|