Compare commits
2 Commits
20a1237286
...
579aae1000
| Author | SHA1 | Date | |
|---|---|---|---|
| 579aae1000 | |||
| 205beeb0f3 |
27
Dockerfile
27
Dockerfile
@@ -1,13 +1,30 @@
|
|||||||
FROM quay.ocp.banorte.com/golden/python-312:latest
|
FROM quay.ocp.banorte.com/golden/python-312:latest AS builder
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.7.12 /uv /uvx /bin/
|
||||||
|
|
||||||
|
ENV UV_COMPILE_BYTECODE=1 \
|
||||||
|
UV_NO_CACHE=1 \
|
||||||
|
UV_NO_DEV=1 \
|
||||||
|
UV_LINK_MODE=copy
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
COPY . .
|
# Install dependencies first (cached layer as long as lockfile doesn't change)
|
||||||
|
COPY pyproject.toml uv.lock ./
|
||||||
|
RUN uv sync --locked --no-install-project --no-editable
|
||||||
|
|
||||||
RUN uv sync
|
# Copy the rest of the project and install it
|
||||||
|
COPY . .
|
||||||
|
RUN uv sync --locked --no-editable
|
||||||
|
|
||||||
|
# --- Final stage: no uv, no build artifacts ---
|
||||||
|
FROM quay.ocp.banorte.com/golden/python-312:latest
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY --from=builder /app/.venv /app/.venv
|
||||||
|
COPY config.yaml ./
|
||||||
|
|
||||||
ENV PATH="/app/.venv/bin:$PATH"
|
ENV PATH="/app/.venv/bin:$PATH"
|
||||||
|
|
||||||
CMD ["uv", "run", "uvicorn", "rag_eval.server:app", "--host", "0.0.0.0"]
|
CMD ["uvicorn", "va_agent.server:app", "--host", "0.0.0.0"]
|
||||||
|
|||||||
@@ -1,10 +1,142 @@
|
|||||||
"""FastAPI server exposing the RAG agent endpoint.
|
"""FastAPI server exposing the RAG agent endpoint."""
|
||||||
|
|
||||||
NOTE: This file is a stub. The rag_eval module was removed in the
|
from __future__ import annotations
|
||||||
lean MCP implementation. This file is kept for reference but is not
|
|
||||||
functional.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from fastapi import FastAPI
|
import logging
|
||||||
|
import uuid
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
app = FastAPI(title="RAG Agent")
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from google.genai.types import Content, Part
|
||||||
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
|
from va_agent.agent import runner
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
app = FastAPI(title="Vaia Agent")
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Request / Response models
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
class NotificationPayload(BaseModel):
|
||||||
|
"""Notification context sent alongside a user query."""
|
||||||
|
|
||||||
|
text: str | None = None
|
||||||
|
parameters: dict[str, Any] = Field(default_factory=dict)
|
||||||
|
|
||||||
|
|
||||||
|
class QueryRequest(BaseModel):
|
||||||
|
"""Incoming query request from the integration layer."""
|
||||||
|
|
||||||
|
phone_number: str
|
||||||
|
text: str
|
||||||
|
type: str = "conversation"
|
||||||
|
notification: NotificationPayload | None = None
|
||||||
|
language_code: str = "es"
|
||||||
|
|
||||||
|
|
||||||
|
class QueryResponse(BaseModel):
|
||||||
|
"""Response returned to the integration layer."""
|
||||||
|
|
||||||
|
response_id: str
|
||||||
|
response_text: str
|
||||||
|
parameters: dict[str, Any] = Field(default_factory=dict)
|
||||||
|
confidence: float | None = None
|
||||||
|
|
||||||
|
|
||||||
|
class ErrorResponse(BaseModel):
|
||||||
|
"""Standard error body."""
|
||||||
|
|
||||||
|
error: str
|
||||||
|
message: str
|
||||||
|
status: int
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Helpers
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
def _build_user_message(request: QueryRequest) -> str:
|
||||||
|
"""Compose the text sent to the agent, including notification context."""
|
||||||
|
if request.type == "notification" and request.notification:
|
||||||
|
parts = [request.text]
|
||||||
|
if request.notification.text:
|
||||||
|
parts.append(
|
||||||
|
f"\n[Notificación recibida]: {request.notification.text}"
|
||||||
|
)
|
||||||
|
if request.notification.parameters:
|
||||||
|
formatted = ", ".join(
|
||||||
|
f"{k}: {v}"
|
||||||
|
for k, v in request.notification.parameters.items()
|
||||||
|
)
|
||||||
|
parts.append(f"[Parámetros de notificación]: {formatted}")
|
||||||
|
return "\n".join(parts)
|
||||||
|
return request.text
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Endpoints
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
@app.post(
|
||||||
|
"/api/v1/query",
|
||||||
|
response_model=QueryResponse,
|
||||||
|
responses={
|
||||||
|
400: {"model": ErrorResponse},
|
||||||
|
500: {"model": ErrorResponse},
|
||||||
|
503: {"model": ErrorResponse},
|
||||||
|
},
|
||||||
|
)
|
||||||
|
async def query(request: QueryRequest) -> QueryResponse:
|
||||||
|
"""Process a user message and return a generated response."""
|
||||||
|
user_message = _build_user_message(request)
|
||||||
|
session_id = request.phone_number
|
||||||
|
user_id = request.phone_number
|
||||||
|
|
||||||
|
new_message = Content(
|
||||||
|
role="user",
|
||||||
|
parts=[Part(text=user_message)],
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
response_text = ""
|
||||||
|
async for event in runner.run_async(
|
||||||
|
user_id=user_id,
|
||||||
|
session_id=session_id,
|
||||||
|
new_message=new_message,
|
||||||
|
):
|
||||||
|
if event.content and event.content.parts:
|
||||||
|
for part in event.content.parts:
|
||||||
|
if part.text and event.author != "user":
|
||||||
|
response_text += part.text
|
||||||
|
except ValueError as exc:
|
||||||
|
logger.exception("Bad request while running agent")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=400,
|
||||||
|
detail=ErrorResponse(
|
||||||
|
error="Bad Request",
|
||||||
|
message=str(exc),
|
||||||
|
status=400,
|
||||||
|
).model_dump(),
|
||||||
|
) from exc
|
||||||
|
except Exception as exc:
|
||||||
|
logger.exception("Internal error while running agent")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail=ErrorResponse(
|
||||||
|
error="Internal Server Error",
|
||||||
|
message="Failed to generate response",
|
||||||
|
status=500,
|
||||||
|
).model_dump(),
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
return QueryResponse(
|
||||||
|
response_id=f"rag-resp-{uuid.uuid4()}",
|
||||||
|
response_text=response_text,
|
||||||
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user