personabot-api / app /api /feedback.py
GitHub Actions
Deploy 5a96418
bbe01fe
# backend/app/api/feedback.py
# Feedback endpoint. Lets the widget surface thumbs-up / thumbs-down for any
# completed interaction. Ratings are stored against the SQLite interaction row.
#
# Self-improvement loop:
# rating=1 → positive signal written to DB; used by data_prep.py to build
# high-quality reranker triplets (in-scope chunks that helped).
# rating=-1 → negative signal; used by data_prep.py to build hard-negative
# triplets (chunks the model surfaced that didn't help the user).
# The retrain_reranker.yml GitHub Actions workflow aggregates these signals
# and auto-triggers reranker fine-tuning once enough triplets accumulate.
import sqlite3
from fastapi import APIRouter, Depends, HTTPException, Request, status
from pydantic import BaseModel, Field
from app.core.logging import get_logger
from app.security.jwt_auth import verify_jwt
router = APIRouter()
logger = get_logger(__name__)
class FeedbackRequest(BaseModel):
interaction_id: int = Field(..., description="Row ID returned in the SSE done event.")
rating: int = Field(..., description="1 for thumbs-up, -1 for thumbs-down.")
model_config = {"json_schema_extra": {"example": {"interaction_id": 42, "rating": 1}}}
@router.post("/feedback", status_code=status.HTTP_204_NO_CONTENT)
async def submit_feedback(
request: Request,
body: FeedbackRequest,
_token: dict = Depends(verify_jwt),
) -> None:
"""Record user feedback on a completed interaction. Idempotent — re-rating overwrites."""
if body.rating not in (1, -1):
raise HTTPException(
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
detail="rating must be 1 (positive) or -1 (negative)",
)
db_path = request.app.state.settings.DB_PATH
try:
with sqlite3.connect(db_path) as conn:
cursor = conn.execute(
"UPDATE interactions SET feedback = ? WHERE id = ?",
(body.rating, body.interaction_id),
)
if cursor.rowcount == 0:
raise HTTPException(
status_code=status.HTTP_404_NOT_FOUND,
detail=f"Interaction {body.interaction_id} not found.",
)
except HTTPException:
raise
except Exception as exc:
logger.error("Feedback write failed for interaction %d: %s", body.interaction_id, exc)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Feedback store unavailable.",
)