Spaces:
Sleeping
Sleeping
File size: 3,042 Bytes
0bb4dfa a763505 4944128 a763505 0bb4dfa a763505 0bb4dfa a763505 0bb4dfa a763505 0bb4dfa d58dc6d a763505 0bb4dfa d58dc6d 0bb4dfa a763505 d58dc6d a763505 0bb4dfa | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | """Participant catalog API.
`GET /api/personas` returns three sections - Neon HANA personas (with
vanilla/RAG personas filtered out and display names reformatted via an
LLM), the bundled extra personas, and the user-supplied expert
personas (which are local-only on the frontend but echoed here for
completeness so the API can act as the source of truth for participant
choices when needed).
"""
from __future__ import annotations
import logging
from fastapi import APIRouter
from fastapi.responses import JSONResponse
from app.clients.hana_client import hana_client
from app.services.extra_personas import list_extra_personas
from app.services.persona_naming import reformat_neon_names
router = APIRouter()
LOG = logging.getLogger(__name__)
def _is_vanilla_or_rag(persona_name: str) -> bool:
pn = (persona_name or "").lower()
return "vanilla" in pn or "rag" in pn
@router.get("/personas")
async def get_personas():
"""Return the participant catalog the frontend dropdown shows."""
try:
neon_models = await hana_client.get_models()
except Exception as exc:
LOG.warning("HANA models unavailable: %s", exc)
neon_models = []
# Pass 1: collect raw (model_short, persona_name) pairs.
raw_neon: list[dict] = []
for nm in neon_models or []:
model_short = nm["name"].split("/")[-1]
for p in nm.get("personas", []) or []:
if p.get("enabled") is False:
continue
persona_name = p.get("persona_name") or ""
if _is_vanilla_or_rag(persona_name):
continue
system_prompt = (p.get("system_prompt") or "").strip()
raw_neon.append({
"model_id": nm["model_id"],
"model_short": model_short,
"persona_name": persona_name,
"description": p.get("description") or "",
"role_prompt": system_prompt,
})
# Pass 2: batch-reformat display names via the orchestrator LLM
# (cached). One call covers every uncached pair.
pairs = [(r["model_short"], r["persona_name"]) for r in raw_neon]
name_map = await reformat_neon_names(pairs)
neon_personas = []
for r in raw_neon:
display = name_map.get(
(r["model_short"], r["persona_name"]),
r["persona_name"],
)
participant_id = f"neon:{r['model_id']}:{r['persona_name']}"
neon_personas.append({
"participant_id": participant_id,
"kind": "neon",
"name": display,
"model_display": r["model_short"],
"default_model_id": participant_id,
"description": r["description"],
"role_prompt": r.get("role_prompt") or "",
})
extras = list_extra_personas()
for e in extras:
e["model_display"] = e["default_model_id"]
return JSONResponse(
content={
"neon": neon_personas,
"extra": extras,
},
headers={"Cache-Control": "no-store"},
)
|