141 lines
4.0 KiB
Python
141 lines
4.0 KiB
Python
"""
|
|
Runtime Slot API.
|
|
[AC-MRS-09,10] 运行时槽位查询接口
|
|
"""
|
|
|
|
import logging
|
|
from datetime import datetime
|
|
from typing import Annotated, Any
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from fastapi.responses import JSONResponse
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.database import get_session
|
|
from app.core.exceptions import MissingTenantIdException
|
|
from app.core.tenant import get_tenant_id
|
|
from app.services.mid.role_based_field_provider import RoleBasedFieldProvider, InvalidRoleError
|
|
from app.services.slot_definition_service import SlotDefinitionService
|
|
from app.schemas.metadata import VALID_FIELD_ROLES
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
router = APIRouter(prefix="/mid/slots", tags=["RuntimeSlot"])
|
|
|
|
|
|
def get_current_tenant_id() -> str:
|
|
"""Get current tenant ID from context."""
|
|
tenant_id = get_tenant_id()
|
|
if not tenant_id:
|
|
raise MissingTenantIdException()
|
|
return tenant_id
|
|
|
|
|
|
@router.get(
|
|
"/by-role",
|
|
operation_id="getSlotsByRole",
|
|
summary="Get slots by role",
|
|
description="[AC-MRS-10] 运行时接口,按角色获取槽位定义及关联的元数据字段信息",
|
|
)
|
|
async def get_slots_by_role(
|
|
tenant_id: Annotated[str, Depends(get_current_tenant_id)],
|
|
session: Annotated[AsyncSession, Depends(get_session)],
|
|
role: Annotated[str, Query(
|
|
description="[AC-MRS-10] 字段角色: resource_filter/slot/prompt_var/routing_signal"
|
|
)] = "slot",
|
|
) -> JSONResponse:
|
|
"""
|
|
[AC-MRS-10] 按角色获取槽位定义
|
|
|
|
Args:
|
|
role: 字段角色,默认为 slot
|
|
"""
|
|
logger.info(
|
|
f"[AC-MRS-10] Getting slots by role: tenant={tenant_id}, role={role}"
|
|
)
|
|
|
|
provider = RoleBasedFieldProvider(session)
|
|
|
|
try:
|
|
slots = await provider.get_slot_definitions_by_role(tenant_id, role)
|
|
except InvalidRoleError as e:
|
|
return JSONResponse(
|
|
status_code=400,
|
|
content={
|
|
"error_code": "INVALID_ROLE",
|
|
"message": str(e),
|
|
"details": {
|
|
"valid_roles": e.valid_roles
|
|
}
|
|
}
|
|
)
|
|
|
|
return JSONResponse(content=slots)
|
|
|
|
|
|
@router.get(
|
|
"/{slot_key}",
|
|
operation_id="getSlotValue",
|
|
summary="Get runtime slot value",
|
|
description="[AC-MRS-09] 获取指定槽位的运行时值,包含来源、置信度、更新时间",
|
|
)
|
|
async def get_slot_value(
|
|
tenant_id: Annotated[str, Depends(get_current_tenant_id)],
|
|
session: Annotated[AsyncSession, Depends(get_session)],
|
|
slot_key: str,
|
|
user_id: Annotated[str | None, Query(
|
|
description="用户 ID"
|
|
)] = None,
|
|
session_id: Annotated[str | None, Query(
|
|
description="会话 ID"
|
|
)] = None,
|
|
) -> JSONResponse:
|
|
"""
|
|
[AC-MRS-09] 获取运行时槽位值
|
|
|
|
Args:
|
|
slot_key: 槽位键名
|
|
user_id: 用户 ID
|
|
session_id: 会话 ID
|
|
"""
|
|
logger.info(
|
|
f"[AC-MRS-09] Getting slot value: tenant={tenant_id}, slot_key={slot_key}, "
|
|
f"user_id={user_id}, session_id={session_id}"
|
|
)
|
|
|
|
service = SlotDefinitionService(session)
|
|
slot_def = await service.get_slot_definition_by_key(tenant_id, slot_key)
|
|
|
|
if not slot_def:
|
|
return JSONResponse(
|
|
status_code=404,
|
|
content={
|
|
"error_code": "NOT_FOUND",
|
|
"message": f"Slot '{slot_key}' not found",
|
|
}
|
|
)
|
|
|
|
value = slot_def.default_value
|
|
source = "default"
|
|
confidence = 1.0
|
|
|
|
if value is None:
|
|
if slot_def.type == "string":
|
|
value = ""
|
|
elif slot_def.type == "number":
|
|
value = 0
|
|
elif slot_def.type == "boolean":
|
|
value = False
|
|
elif slot_def.type in ["enum", "array_enum"]:
|
|
value = [] if slot_def.type == "array_enum" else ""
|
|
|
|
return JSONResponse(
|
|
content={
|
|
"key": slot_key,
|
|
"value": value,
|
|
"source": source,
|
|
"confidence": confidence,
|
|
"updated_at": datetime.utcnow().isoformat(),
|
|
}
|
|
)
|