Xunjunaa commited on
Commit
7cf850b
·
1 Parent(s): 35222b8

stats: /api/stats 增加 probe 可路由探测缓存信息与 denied_detail(带剩余TTL), 供 CF 集中面板展示; denied 原字段形状不变(兼容自身面板)

Browse files
Files changed (1) hide show
  1. server.py +16 -0
server.py CHANGED
@@ -201,6 +201,8 @@ class TokenPool:
201
  self.surplus_dropped = 0
202
  self.expired_dropped = 0
203
  self.known_supported: set[str] = set() # 后台探测到的可路由集合
 
 
204
  self.routable_seen: set[str] = set() # 实测跑通过的模型
205
  self.denied: dict[str, float] = {} # 上游403否定缓存 model->ts
206
  self.requests = collections.deque(maxlen=50)
@@ -607,6 +609,8 @@ class TokenPool:
607
  data = json.loads(PROBE_CACHE.read_text(encoding="utf-8"))
608
  if time.time() - data.get("ts", 0) < cfg.PROBE_CACHE_TTL:
609
  self.known_supported.update(data.get("models", []))
 
 
610
  log(f"[probe] 可路由集合用缓存 {len(self.known_supported)} 个")
611
  return
612
  except Exception:
@@ -632,6 +636,8 @@ class TokenPool:
632
  async with httpx.AsyncClient() as c:
633
  await asyncio.gather(*[probe(i) for i in cands])
634
  log(f"[probe] 匿名可路由候选 {len(self.known_supported)} 个")
 
 
635
  try:
636
  PROBE_CACHE.write_text(json.dumps(
637
  {"ts": time.time(),
@@ -703,6 +709,16 @@ class TokenPool:
703
  "workers_max": self.max_worker_pages,
704
  "routable": self.routable(),
705
  "denied": sorted(m for m in self.denied if self.is_denied(m)),
 
 
 
 
 
 
 
 
 
 
706
  "config": {
707
  "shelf_size": self.shelf_size,
708
  "token_max_age": self.token_max_age,
 
201
  self.surplus_dropped = 0
202
  self.expired_dropped = 0
203
  self.known_supported: set[str] = set() # 后台探测到的可路由集合
204
+ self.probe_ts: float | None = None # 最近一次可路由探测完成时刻(墙钟, 缓存命中时取文件ts)
205
+ self.probe_from_cache = False # 本次探测结果是否直接来自磁盘缓存
206
  self.routable_seen: set[str] = set() # 实测跑通过的模型
207
  self.denied: dict[str, float] = {} # 上游403否定缓存 model->ts
208
  self.requests = collections.deque(maxlen=50)
 
609
  data = json.loads(PROBE_CACHE.read_text(encoding="utf-8"))
610
  if time.time() - data.get("ts", 0) < cfg.PROBE_CACHE_TTL:
611
  self.known_supported.update(data.get("models", []))
612
+ self.probe_ts = data.get("ts") or time.time()
613
+ self.probe_from_cache = True
614
  log(f"[probe] 可路由集合用缓存 {len(self.known_supported)} 个")
615
  return
616
  except Exception:
 
636
  async with httpx.AsyncClient() as c:
637
  await asyncio.gather(*[probe(i) for i in cands])
638
  log(f"[probe] 匿名可路由候选 {len(self.known_supported)} 个")
639
+ self.probe_ts = time.time()
640
+ self.probe_from_cache = False
641
  try:
642
  PROBE_CACHE.write_text(json.dumps(
643
  {"ts": time.time(),
 
709
  "workers_max": self.max_worker_pages,
710
  "routable": self.routable(),
711
  "denied": sorted(m for m in self.denied if self.is_denied(m)),
712
+ "denied_detail": [ # 带剩余 TTL, 供集中面板展示
713
+ {"model": m, "remain_s": max(0, int(self.denied_ttl - (time.time() - ts)))}
714
+ for m, ts in sorted(self.denied.items(), key=lambda kv: -kv[1])
715
+ if self.is_denied(m)
716
+ ],
717
+ "probe": { # 可路由探测缓存状态
718
+ "age_s": (int(time.time() - self.probe_ts) if self.probe_ts else None),
719
+ "models": len(self.known_supported),
720
+ "from_cache": self.probe_from_cache,
721
+ },
722
  "config": {
723
  "shelf_size": self.shelf_size,
724
  "token_max_age": self.token_max_age,