项目文件夹

文件
wehub-resource-sync 2c632336aa
CI / Viewer CI (push) Successful in 13m37s
CI / Core CI (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:32:38 +08:00

107 行
4.5 KiB
Python

from __future__ import annotations
import time
from viewer.api.schemas import CategoryStatsResponse, RepoStatsResponse
from viewer.api.store_components import ViewerStoreComponent
from viewer.api.store_values import _effective_rating_bucket
class ViewerStatsStore(ViewerStoreComponent):
_stats_cache: tuple[float, RepoStatsResponse] | None = None
_STATS_TTL = 30.0
def invalidate_stats_cache(self) -> None:
self._stats_cache = None
def _compute_data_size(self) -> int | None:
data_dir = self.repo.layout.data_root
if not data_dir.exists():
return None
try:
return sum(path.stat().st_size for path in data_dir.rglob("*") if path.is_file())
except OSError:
return None
def compute_stats(self) -> RepoStatsResponse:
now = time.monotonic()
if self._stats_cache is not None:
cached_at, cached = self._stats_cache
if now - cached_at < self._STATS_TTL:
return cached
records = self.records.list_library_records()
total_cost = sum(record.total_cost_usd or 0.0 for record in records)
has_cost = any(record.total_cost_usd is not None for record in records)
category_counts: dict[str, int] = {}
category_rating_totals: dict[str, float] = {}
category_rating_counts: dict[str, int] = {}
category_cost_totals: dict[str, float] = {}
category_cost_counts: dict[str, int] = {}
model_counts: dict[str, int] = {}
provider_counts: dict[str, int] = {}
rating_distribution: dict[str, int] = {}
for record in records:
if record.category_slug:
category_counts[record.category_slug] = (
category_counts.get(record.category_slug, 0) + 1
)
if record.effective_rating is not None:
category_rating_totals[record.category_slug] = (
category_rating_totals.get(record.category_slug, 0.0)
+ record.effective_rating
)
category_rating_counts[record.category_slug] = (
category_rating_counts.get(record.category_slug, 0) + 1
)
if record.total_cost_usd is not None:
category_cost_totals[record.category_slug] = (
category_cost_totals.get(record.category_slug, 0.0) + record.total_cost_usd
)
category_cost_counts[record.category_slug] = (
category_cost_counts.get(record.category_slug, 0) + 1
)
if record.model_id:
model_counts[record.model_id] = model_counts.get(record.model_id, 0) + 1
if record.provider:
provider_counts[record.provider] = provider_counts.get(record.provider, 0) + 1
bucket = _effective_rating_bucket(record.effective_rating)
rating_distribution[bucket] = rating_distribution.get(bucket, 0) + 1
category_stats = {
category: CategoryStatsResponse(
count=count,
average_rating=(
round(category_rating_totals[category] / category_rating_counts[category], 2)
if category_rating_counts.get(category)
else None
),
average_cost_usd=(
round(category_cost_totals[category] / category_cost_counts[category], 4)
if category_cost_counts.get(category)
else None
),
)
for category, count in sorted(
category_counts.items(), key=lambda item: (-item[1], item[0])
)
}
response = RepoStatsResponse(
total_records=len(records),
total_runs=len(self.runs.list_runs()),
total_cost_usd=round(total_cost, 4) if has_cost else None,
data_size_bytes=self._compute_data_size(),
category_counts=dict(
sorted(category_counts.items(), key=lambda item: (-item[1], item[0]))
),
category_stats=category_stats,
model_counts=dict(sorted(model_counts.items(), key=lambda item: (-item[1], item[0]))),
provider_counts=dict(
sorted(provider_counts.items(), key=lambda item: (-item[1], item[0]))
),
rating_distribution=rating_distribution,
)
self._stats_cache = (now, response)
return response