Aniket2006
feat: add copilot (RAG chat) endpoint alongside apk-scan and smishing
2dca8fb
Raw
History Blame Contribute Delete
2.15 kB
"""services/copilot/api.py — FastAPI router for the RAG copilot.
Mounted at /api/v1/copilot in app/main.py. Follows the same auth pattern as
the rest of this backend (require_api_key — see app/security.py) since
there's no per-user auth yet.
"""
from __future__ import annotations
import logging
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import Settings, get_settings
from app.database import get_db
from app.security import rate_limit, require_api_key
from app.services.copilot import db as copilot_db
from app.services.copilot.engine import answer_chat
from app.services.copilot.models import ChatRequest, ChatResponse
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/copilot", tags=["Copilot"])
@router.post(
"/chat",
response_model=ChatResponse,
dependencies=[Depends(require_api_key), Depends(rate_limit(limit=20, window_seconds=60))],
summary="Ask Shield Copilot a question, grounded in the app's knowledge base",
)
async def chat(
request: ChatRequest,
session: AsyncSession = Depends(get_db),
settings: Settings = Depends(get_settings),
) -> ChatResponse:
try:
return await answer_chat(session, request, settings)
except Exception as exc:
# copilot_chunks / pgvector may be entirely unavailable in this
# deployment (see database.py::_create_copilot_table_if_possible) —
# surface a clear 503 rather than a generic 500.
logger.exception("Copilot chat failed: %s", exc)
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Copilot is temporarily unavailable. Please try again shortly.",
) from exc
@router.get("/health", summary="Copilot subsystem status (chunk count)")
async def copilot_health(session: AsyncSession = Depends(get_db)) -> dict:
try:
count = await copilot_db.chunk_count(session)
return {"status": "ready" if count > 0 else "empty", "indexed_chunks": count}
except Exception as exc:
return {"status": "unavailable", "detail": str(exc)}