Forráskód Böngészése

feat: 补充缓存命中价格展示与折扣透传

mengboxin137-blip 1 hete
szülő
commit
d2e7382108
2 módosított fájl, 54 hozzáadás és 22 törlés
  1. 9 10
      backend/app/routers/public.py
  2. 45 12
      backend/app/utils/price_parser.py

+ 9 - 10
backend/app/routers/public.py

@@ -45,6 +45,8 @@ class ParsedPriceItem(BaseModel):
     unit: Optional[str] = None
     label: Optional[str] = None
 
+    model_config = {"extra": "allow"}
+
 
 class DiscountedPriceItem(BaseModel):
     url: str
@@ -59,6 +61,8 @@ class DiscountedPriceItem(BaseModel):
     label: Optional[str] = None
     discount: Optional[float] = None  # None 表示未知,1.0 表示原价
 
+    model_config = {"extra": "allow"}
+
 
 
 class ModelTypeItem(BaseModel):
@@ -248,21 +252,11 @@ async def get_public_prices(
     parsed_prices: List[ParsedPriceItem] = []
     discounted_prices: List[DiscountedPriceItem] = []
 
-    # 只保留输入/输出主价格,过滤掉缓存命中、Batch File、调优等附加价格
-    _EXCLUDED_LABEL_RE = re.compile(
-        r"缓存|batch\s*file|批量|调优|思考模式",
-        re.I,
-    )
-
     for r in rows:
         for item in parse_prices(_j(r["prices"]) or {}):
             # 过滤掉输入和输出价格都为 None 的条目(保留单边价格,如向量模型、图像生成等)
             if item.get("input_price") is None and item.get("output_price") is None:
                 continue
-            # 过滤掉缓存命中、Batch File、调优等非主价格条目
-            label = item.get("label") or ""
-            if _EXCLUDED_LABEL_RE.search(label):
-                continue
             # 将 label 改为中文
             item = dict(item)
             if item.get("label") == "input/output":
@@ -278,6 +272,11 @@ async def get_public_prices(
                     d_item["input_price"] = round(d_item["input_price"] * effective_discount, 6)
                 if d_item.get("output_price") is not None:
                     d_item["output_price"] = round(d_item["output_price"] * effective_discount, 6)
+                for key, value in list(d_item.items()):
+                    if key in {"url", "model_name", "tier_min", "tier_max", "tier_unit", "input_price", "output_price", "currency", "unit", "label", "discount"}:
+                        continue
+                    if isinstance(value, (int, float)):
+                        d_item[key] = round(value * effective_discount, 6)
             discounted_prices.append(DiscountedPriceItem(url=r["url"], model_name=r["model_name"], discount=effective_discount, **d_item))
 
     all_types = [

+ 45 - 12
backend/app/utils/price_parser.py

@@ -138,6 +138,29 @@ def _parse_tier_key(key: str):
     return None
 
 
+def _normalize_price_label(label: str) -> str:
+    text = (label or "").strip().lower()
+    if not text:
+        return label
+
+    text = text.replace("(", "(").replace(")", ")")
+    if text in {"输入", "input"}:
+        return "input"
+    if text in {"输出", "output"}:
+        return "output"
+    if ("输入" in text or "input" in text) and "缓存命中" in text:
+        return "input_cache_hit"
+    if ("输入" in text or "input" in text) and "batch file" in text:
+        return "input_batch"
+    if ("输出" in text or "output" in text) and "batch file" in text:
+        return "output_batch"
+    if "显式缓存创建" in text:
+        return "explicit_cache_create"
+    if "显式缓存命中" in text:
+        return "explicit_cache_hit"
+    return label
+
+
 def _extract_video_spec(label: str) -> Optional[str]:
     """从 label 中提取视频规格,如 '视频生成(720P)' -> '720P'。"""
     m = re.search(r"[((]([^))]+)[))]", label)
@@ -184,8 +207,6 @@ def parse_prices(prices: Dict[str, Any]) -> List[Dict]:
     video_items: List[Dict] = []
     input_entry: Optional[Dict] = None
 
-    _CACHE_RE = re.compile(r"缓存|cache", re.I)
-
     # 预扫描:是否存在阶梯 key
     _has_tiers = any(_parse_tier_key(k) is not None for k in prices)
 
@@ -203,10 +224,6 @@ def parse_prices(prices: Dict[str, Any]) -> List[Dict]:
         _output_prices.sort()  # 从小到大,与阶梯从低到高对应
 
     for key, val in prices.items():
-        # 跳过缓存相关条目
-        if _CACHE_RE.search(key):
-            continue
-
         if not isinstance(val, dict):
             continue
 
@@ -225,16 +242,17 @@ def parse_prices(prices: Dict[str, Any]) -> List[Dict]:
             }
             for sub_key, sub_val in val.items():
                 sk = sub_key.strip()
-                if _CACHE_RE.search(sk):
-                    continue
+                normalized_key = _normalize_price_label(sk)
                 price = _parse_price(sub_val)
                 unit = _parse_unit(sub_val)
                 if unit:
                     entry["unit"] = unit
-                if re.match(r"^输入|^input", sk, re.I):
+                if normalized_key == "input":
                     entry["input_price"] = price
-                elif re.match(r"^输出|^output", sk, re.I):
+                elif normalized_key == "output":
                     entry["output_price"] = price
+                elif price is not None and normalized_key != sk:
+                    entry[normalized_key] = price
                 elif price is not None and entry["input_price"] is None:
                     # 无标签的纯价格 → 当作输入价格
                     entry["input_price"] = price
@@ -273,10 +291,11 @@ def parse_prices(prices: Dict[str, Any]) -> List[Dict]:
             continue
 
         # ── 简单非阶梯:输入 → 暂存,输出 → 配对 ──
-        if re.match(r"^输入|^input", key.strip(), re.I):
+        normalized_label = _normalize_price_label(key.strip())
+        if normalized_label == "input":
             input_entry = {"price": price, "unit": unit}
             continue
-        if re.match(r"^输出|^output", key.strip(), re.I):
+        if normalized_label == "output":
             result.append({
                 "label": "input/output",
                 "tier_min": None,
@@ -290,6 +309,20 @@ def parse_prices(prices: Dict[str, Any]) -> List[Dict]:
             input_entry = None
             continue
 
+        if normalized_label != key.strip():
+            is_output_side = normalized_label.startswith("output")
+            result.append({
+                "label": normalized_label,
+                "tier_min": None,
+                "tier_max": None,
+                "tier_unit": None,
+                "input_price": None if is_output_side else price,
+                "output_price": price if is_output_side else None,
+                "currency": "CNY",
+                "unit": unit,
+            })
+            continue
+
         # 其他普通标签
         result.append({
             "label": key,