mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
feat: 全局模型新增活跃 Provider 数量统计
- 后端优化查询,使用条件聚合同时获取总 Provider 数和活跃数 - 前端展示格式改为「活跃数/总数」,便于了解可用 Provider 情况
This commit is contained in:
@@ -810,6 +810,7 @@ export interface GlobalModelResponse {
|
|||||||
config?: Record<string, any> | null
|
config?: Record<string, any> | null
|
||||||
// 统计数据
|
// 统计数据
|
||||||
provider_count?: number
|
provider_count?: number
|
||||||
|
active_provider_count?: number
|
||||||
usage_count?: number
|
usage_count?: number
|
||||||
created_at: string
|
created_at: string
|
||||||
updated_at?: string
|
updated_at?: string
|
||||||
|
|||||||
@@ -386,7 +386,7 @@
|
|||||||
<Building2 class="w-4 h-4 text-muted-foreground" />
|
<Building2 class="w-4 h-4 text-muted-foreground" />
|
||||||
</div>
|
</div>
|
||||||
<p class="text-2xl font-bold mt-1">
|
<p class="text-2xl font-bold mt-1">
|
||||||
{{ model.provider_count || 0 }}
|
{{ model.active_provider_count || 0 }}<span class="text-sm text-muted-foreground font-normal">/{{ model.provider_count || 0 }}</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="p-3 rounded-lg border bg-muted/20">
|
<div class="p-3 rounded-lg border bg-muted/20">
|
||||||
|
|||||||
@@ -168,7 +168,7 @@
|
|||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell class="text-center">
|
<TableCell class="text-center">
|
||||||
<Badge variant="secondary">
|
<Badge variant="secondary">
|
||||||
{{ model.provider_count || 0 }}
|
{{ model.active_provider_count || 0 }}/{{ model.provider_count || 0 }}
|
||||||
</Badge>
|
</Badge>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell class="text-center">
|
<TableCell class="text-center">
|
||||||
@@ -302,7 +302,7 @@
|
|||||||
|
|
||||||
<!-- 第三行:统计信息 -->
|
<!-- 第三行:统计信息 -->
|
||||||
<div class="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
|
<div class="flex flex-wrap items-center gap-3 text-xs text-muted-foreground">
|
||||||
<span>提供商 {{ model.provider_count || 0 }}</span>
|
<span>提供商 {{ model.active_provider_count || 0 }}/{{ model.provider_count || 0 }}</span>
|
||||||
<span>调用 {{ formatUsageCount(model.usage_count || 0) }}</span>
|
<span>调用 {{ formatUsageCount(model.usage_count || 0) }}</span>
|
||||||
<span
|
<span
|
||||||
v-if="getFirstTierPrice(model, 'input') || getFirstTierPrice(model, 'output')"
|
v-if="getFirstTierPrice(model, 'input') || getFirstTierPrice(model, 'output')"
|
||||||
|
|||||||
@@ -261,9 +261,9 @@ class AdminListGlobalModelsAdapter(AdminApiAdapter):
|
|||||||
search: str | None
|
search: str | None
|
||||||
|
|
||||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||||
from sqlalchemy import func
|
from sqlalchemy import and_, case, func
|
||||||
|
|
||||||
from src.models.database import Model
|
from src.models.database import Model, Provider
|
||||||
|
|
||||||
models = GlobalModelService.list_global_models(
|
models = GlobalModelService.list_global_models(
|
||||||
db=context.db,
|
db=context.db,
|
||||||
@@ -274,24 +274,44 @@ class AdminListGlobalModelsAdapter(AdminApiAdapter):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# 一次性查询所有 GlobalModel 的 provider_count(优化 N+1 问题)
|
# 一次性查询所有 GlobalModel 的 provider_count(优化 N+1 问题)
|
||||||
|
# 用条件聚合同时获取总数和活跃数,减少一次 DB 往返
|
||||||
model_ids = [gm.id for gm in models]
|
model_ids = [gm.id for gm in models]
|
||||||
provider_counts = {}
|
provider_counts = {}
|
||||||
|
active_provider_counts = {}
|
||||||
if model_ids:
|
if model_ids:
|
||||||
count_results = (
|
count_results = (
|
||||||
context.db.query(
|
context.db.query(
|
||||||
Model.global_model_id, func.count(func.distinct(Model.provider_id))
|
Model.global_model_id,
|
||||||
|
func.count(func.distinct(Model.provider_id)),
|
||||||
|
func.count(
|
||||||
|
func.distinct(
|
||||||
|
case(
|
||||||
|
(
|
||||||
|
and_(
|
||||||
|
Model.is_active.is_(True),
|
||||||
|
Provider.is_active.is_(True),
|
||||||
|
),
|
||||||
|
Model.provider_id,
|
||||||
|
),
|
||||||
|
else_=None,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
.join(Provider, Model.provider_id == Provider.id)
|
||||||
.filter(Model.global_model_id.in_(model_ids))
|
.filter(Model.global_model_id.in_(model_ids))
|
||||||
.group_by(Model.global_model_id)
|
.group_by(Model.global_model_id)
|
||||||
.all()
|
.all()
|
||||||
)
|
)
|
||||||
provider_counts = {gm_id: count for gm_id, count in count_results}
|
provider_counts = {gm_id: total for gm_id, total, _ in count_results}
|
||||||
|
active_provider_counts = {gm_id: active for gm_id, _, active in count_results}
|
||||||
|
|
||||||
# 构建响应
|
# 构建响应
|
||||||
model_responses = []
|
model_responses = []
|
||||||
for gm in models:
|
for gm in models:
|
||||||
response = GlobalModelResponse.model_validate(gm)
|
response = GlobalModelResponse.model_validate(gm)
|
||||||
response.provider_count = provider_counts.get(gm.id, 0)
|
response.provider_count = provider_counts.get(gm.id, 0)
|
||||||
|
response.active_provider_count = active_provider_counts.get(gm.id, 0)
|
||||||
model_responses.append(response)
|
model_responses.append(response)
|
||||||
|
|
||||||
return GlobalModelListResponse(
|
return GlobalModelListResponse(
|
||||||
@@ -307,11 +327,44 @@ class AdminGetGlobalModelAdapter(AdminApiAdapter):
|
|||||||
global_model_id: str
|
global_model_id: str
|
||||||
|
|
||||||
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
|
||||||
|
from sqlalchemy import and_, case, func
|
||||||
|
|
||||||
|
from src.models.database import Model, Provider
|
||||||
|
|
||||||
global_model = GlobalModelService.get_global_model(context.db, self.global_model_id)
|
global_model = GlobalModelService.get_global_model(context.db, self.global_model_id)
|
||||||
stats = GlobalModelService.get_global_model_stats(context.db, self.global_model_id)
|
stats = GlobalModelService.get_global_model_stats(context.db, self.global_model_id)
|
||||||
|
|
||||||
|
# 查询 provider_count 和 active_provider_count(与列表 API 一致)
|
||||||
|
count_row = (
|
||||||
|
context.db.query(
|
||||||
|
func.count(func.distinct(Model.provider_id)),
|
||||||
|
func.count(
|
||||||
|
func.distinct(
|
||||||
|
case(
|
||||||
|
(
|
||||||
|
and_(
|
||||||
|
Model.is_active.is_(True),
|
||||||
|
Provider.is_active.is_(True),
|
||||||
|
),
|
||||||
|
Model.provider_id,
|
||||||
|
),
|
||||||
|
else_=None,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.join(Provider, Model.provider_id == Provider.id)
|
||||||
|
.filter(Model.global_model_id == global_model.id)
|
||||||
|
.first()
|
||||||
|
)
|
||||||
|
total_count, active_count = count_row if count_row else (0, 0)
|
||||||
|
|
||||||
|
response = GlobalModelResponse.model_validate(global_model)
|
||||||
|
response.provider_count = total_count
|
||||||
|
response.active_provider_count = active_count
|
||||||
|
|
||||||
return GlobalModelWithStats(
|
return GlobalModelWithStats(
|
||||||
**GlobalModelResponse.model_validate(global_model).model_dump(),
|
**response.model_dump(),
|
||||||
total_models=stats["total_models"],
|
total_models=stats["total_models"],
|
||||||
total_providers=stats["total_providers"],
|
total_providers=stats["total_providers"],
|
||||||
price_range=stats["price_range"],
|
price_range=stats["price_range"],
|
||||||
|
|||||||
@@ -236,7 +236,8 @@ class GlobalModelResponse(BaseModel):
|
|||||||
default=None, description="模型配置(streaming, vision, context_limit, description 等)"
|
default=None, description="模型配置(streaming, vision, context_limit, description 等)"
|
||||||
)
|
)
|
||||||
# 统计数据(可选)
|
# 统计数据(可选)
|
||||||
provider_count: int | None = Field(default=0, description="支持的 Provider 数量")
|
provider_count: int | None = Field(default=0, description="支持的 Provider 总数量")
|
||||||
|
active_provider_count: int | None = Field(default=0, description="可用的 Provider 数量")
|
||||||
usage_count: int | None = Field(default=0, description="调用次数")
|
usage_count: int | None = Field(default=0, description="调用次数")
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
updated_at: datetime | None
|
updated_at: datetime | None
|
||||||
|
|||||||
Reference in New Issue
Block a user