Files
server-core/app/services/compute_catalog.py
T

98 lines
3.8 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", ""),
"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"]]