Files
server-core/app/services/compute_catalog.py
T
Pine 416ade4842 feat: 统一权限聚合端点 + 事件名同步昵称 + IM/企业路由补强
- 新增 rbac_permissions 统一权限/组织归属聚合端点
- sync_event_name_to_nickname 脚本:事件名同步用户昵称
- im router/client、rbac_enterprise/opc/org/public 增强
- compute_catalog、nginx 配置、env.example 更新
2026-09-11 21:15:36 +08:00

113 lines
4.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""算力中心模型目录:把 compute 引擎的 admin 模型(models 表,status=1)映射为桌面端可读形状。
替代原静态 pineagents_catalogOPC 桌面端展示/使用的模型 = admin 端新增的模型(算力中心)。
"""
from __future__ import annotations
import json
from . import compute_client
def _parse_list(v):
"""JSON 数组字符串 → list;已 list 原样。"""
if isinstance(v, list):
return v
if isinstance(v, str):
try:
a = json.loads(v)
return a if isinstance(a, list) else []
except Exception: # noqa: BLE001
return []
return []
def _map(row: dict) -> dict:
"""Model 行 → 桌面端模型形状。"""
name = row.get("name") or row.get("model_name") or ""
return {
"id": row.get("model_name") or row.get("name") or "",
"model_name": row.get("model_name", ""),
"name": name,
"actual_model": row.get("actual_model") or row.get("model_name", ""),
"company": "",
"group": row.get("group", "default"),
"billing_unit": row.get("billing_unit", "/百万tokens"),
"input_price": row.get("input_price", 0) or 0,
"output_price": row.get("output_price", 0) or 0,
"cache_hit_price": row.get("cache_hit_price", 0) or 0,
"vision_support": bool(row.get("vision_support", False)),
"image_support": bool(row.get("image_support", False)),
"audio_support": bool(row.get("audio_support", False)),
"video_support": bool(row.get("video_support", False)),
"tags": (row.get("tags") or "").split(",") if row.get("tags") else [],
"vendor_id": row.get("vendor_id", 0),
# 富字段(models.json 语义)
"icon": row.get("icon", ""),
"icon_file": row.get("icon_file", ""),
"modality": row.get("modality", ""),
"input_forms": _parse_list(row.get("input_forms")),
"output_forms": _parse_list(row.get("output_forms")),
"function_icons": _parse_list(row.get("function_icons")),
"url": row.get("url", ""),
"author": row.get("author", ""),
"author_icon": row.get("author_icon", ""),
"supplier": row.get("supplier", ""),
"supplier_icon": row.get("supplier_icon", ""),
"supplier_icon_file": row.get("supplier_icon_file", ""),
# 封面与系列(模型展示)
"cover": row.get("cover", ""),
"cover_file": row.get("cover_file", ""),
"series": row.get("series", ""),
"series_icon": row.get("series_icon", ""),
"series_icon_file": row.get("series_icon_file", ""),
"notes": row.get("notes", ""),
# 缓存计费:缓存输入 / 缓存写入 + 区间
"cache_input_price": row.get("cache_input_price", 0) or 0,
"cache_input_price_min": row.get("cache_input_price_min", 0) or 0,
"cache_input_price_max": row.get("cache_input_price_max", 0) or 0,
"cache_write_price": row.get("cache_write_price", 0) or 0,
"cache_write_price_min": row.get("cache_write_price_min", 0) or 0,
"cache_write_price_max": row.get("cache_write_price_max", 0) or 0,
"price_is_range": bool(row.get("price_is_range", False)),
"input_price_min": row.get("input_price_min", 0) or 0,
"input_price_max": row.get("input_price_max", 0) or 0,
"output_price_min": row.get("output_price_min", 0) or 0,
"output_price_max": row.get("output_price_max", 0) or 0,
"context_window": row.get("context_window", 0) or 0,
"context_window_unit": row.get("context_window_unit", "M"),
"context_window_display": row.get("context_window_display", ""),
"max_output": row.get("max_output", 0) or 0,
"max_output_unit": row.get("max_output_unit", "K"),
"max_output_display": row.get("max_output_display", ""),
"free_trial": bool(row.get("free_trial", False)),
}
async def catalog() -> list[dict]:
"""从 compute 引擎拉取 admin 模型(status=1)并映射。空/不可达 → 返回空列表。"""
try:
items = await compute_client.list_models(status=1)
except compute_client.ComputeError:
return []
return [_map(row) for row in items if (row.get("status", 1) == 1)]
async def models() -> list[dict]:
return await catalog()
async def prices() -> list[dict]:
return [
{"id": m["id"], "name": m["name"], "input": m["input_price"],
"output": m["output_price"], "cache_hit": m["cache_hit_price"],
"unit": m["billing_unit"]}
for m in await catalog()
]
async def model_ids() -> list[str]:
"""供 /v1/models 使用:admin 模型的对外 id。"""
return [m["id"] for m in await catalog() if m["id"]]