mirror of
https://github.com/langbot-app/LangBot.git
synced 2026-09-16 23:07:14 +00:00
feat(models): show LangBot Models availability
This commit is contained in:
@@ -220,6 +220,21 @@ class SystemRouterGroup(group.RouterGroup):
|
||||
return self.http_status(503, -1, str(exc))
|
||||
return self.success(data=model)
|
||||
|
||||
@self.route(
|
||||
'/model-availability',
|
||||
methods=['GET'],
|
||||
auth_type=group.AuthType.USER_TOKEN,
|
||||
permission=Permission.RESOURCE_VIEW,
|
||||
)
|
||||
async def _(request_context: RequestContext) -> str:
|
||||
"""Expose Space's latest persisted model probes to the WebUI."""
|
||||
try:
|
||||
models = await self.ap.space_service.get_model_selection()
|
||||
except Exception as exc:
|
||||
self.ap.logger.warning(f'Failed to load LangBot Models availability: {exc}')
|
||||
return self.http_status(503, -1, 'Model availability is unavailable')
|
||||
return self.success(data={'models': [model.model_dump(mode='json') for model in models]})
|
||||
|
||||
@self.route(
|
||||
'/tasks',
|
||||
methods=['GET'],
|
||||
|
||||
@@ -242,13 +242,14 @@ class SpaceService:
|
||||
models_data = data.get('data', {}).get('models', [])
|
||||
return [SpaceModel.model_validate(model_dict) for model_dict in models_data]
|
||||
|
||||
async def get_model_selection(self, category: str) -> typing.List[SpaceModelSelection]:
|
||||
async def get_model_selection(self, category: str | None = None) -> typing.List[SpaceModelSelection]:
|
||||
"""Return Space models in the availability-ranked selection order."""
|
||||
space_url = self._get_space_config()['url']
|
||||
session = httpclient.get_session()
|
||||
params = {'category': category} if category else None
|
||||
async with session.get(
|
||||
f'{space_url}/api/v1/models/selection',
|
||||
params={'category': category},
|
||||
params=params,
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
error = await httpclient.read_text_limited(response)
|
||||
@@ -266,7 +267,17 @@ class SpaceService:
|
||||
models = []
|
||||
for selection in data:
|
||||
if isinstance(selection, dict) and isinstance(selection.get('model'), dict):
|
||||
models.append(selection['model'])
|
||||
model = dict(selection['model'])
|
||||
availability = selection.get('availability')
|
||||
if not isinstance(availability, dict):
|
||||
# Accept the short-lived pre-release response shape.
|
||||
availability = {
|
||||
key: selection[key]
|
||||
for key in ('up', 'last_probed_at', 'latency_ms', 'http_code')
|
||||
if key in selection
|
||||
}
|
||||
model['availability'] = availability
|
||||
models.append(model)
|
||||
else:
|
||||
models.append(selection)
|
||||
return [SpaceModelSelection.model_validate(model) for model in models]
|
||||
|
||||
@@ -49,8 +49,19 @@ class SpaceModel(pydantic.BaseModel):
|
||||
updated_at: str | None = None
|
||||
|
||||
|
||||
class SpaceModelAvailability(pydantic.BaseModel):
|
||||
"""Latest availability probe. ``up`` is None when no probe exists."""
|
||||
|
||||
up: bool | None = None
|
||||
last_probed_at: str | None = None
|
||||
latency_ms: int = 0
|
||||
http_code: int = 0
|
||||
|
||||
|
||||
class SpaceModelSelection(pydantic.BaseModel):
|
||||
"""Minimal model identity returned by the ranked selection endpoint."""
|
||||
"""Model identity and the latest persisted probe from Space."""
|
||||
|
||||
uuid: str
|
||||
model_id: str
|
||||
category: str | None = None
|
||||
availability: SpaceModelAvailability = pydantic.Field(default_factory=SpaceModelAvailability)
|
||||
|
||||
Reference in New Issue
Block a user