优化hash计算,只取前段,避免url路径影响

This commit is contained in:
root
2026-01-28 15:13:57 +08:00
parent f77f7ba6de
commit 54eb769332
2 changed files with 69 additions and 24 deletions
+39 -13
View File
@@ -1,6 +1,7 @@
import os import os
import time import time
import hashlib import hashlib
from urllib.parse import urlparse # <--- 新增导入
import litellm import litellm
from litellm.integrations.custom_logger import CustomLogger from litellm.integrations.custom_logger import CustomLogger
from litellm.exceptions import ServiceUnavailableError, ContextWindowExceededError from litellm.exceptions import ServiceUnavailableError, ContextWindowExceededError
@@ -36,7 +37,7 @@ def dprint(msg):
log(msg, level="INFO") log(msg, level="INFO")
dprint("Loading daily_limit.py module v19 (Specific Quotas & Docker Track)...") dprint("Loading daily_limit.py module v20 (Robust Hash Fix)...")
# ========================================== # ==========================================
# Redis 与 限额配置 # Redis 与 限额配置
@@ -46,10 +47,10 @@ REDIS_PORT = os.getenv("REDIS_PORT", "6379")
REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", None) REDIS_PASSWORD = os.getenv("REDIS_PASSWORD", None)
MODEL_QUOTAS = { MODEL_QUOTAS = {
"deepseek-v3-2-251201:38430740": 1500000, "deepseek-v3-2-251201:ba0383d3": 1600000,
"doubao-seed-1-8-251228:38430740": 14000, # 测试限额 "doubao-seed-1-8-251228:ba0383d3": 2000, # 测试限额
"glm-4-7-251222:38430740": 1500000, "glm-4-7-251222:ba0383d3": 1800000,
"doubao-seed-1-8-251228:9fbb42b8": 1500000, # 测试重名 "doubao-seed-1-8-251228:d57edef4": 1500000, # 测试重名
} }
@@ -70,20 +71,44 @@ def clean_model_name(name):
def generate_api_base_hash(api_base): def generate_api_base_hash(api_base):
"""
生成 api_base 的 Hash,强制忽略 URL 的路径部分。
例如:
'https://api.com/v1/' -> 'https://api.com'
'https://api.com/v3' -> 'https://api.com'
两者生成的 Hash 将完全一致。
"""
if not api_base: if not api_base:
return "default" return "default"
try:
# 1. 预处理:去空格
s = api_base.strip()
# === 新增标准化代码 === # 2. 解析 URL
# 1. 去除首尾空格 (strip) parsed = urlparse(s)
# 2. 去除末尾的斜杠 (rstrip('/'))
# 这样 '.../v3/' 和 '.../v3' 会生成相同的 Hash
normalized_base = api_base.strip().rstrip('/')
# ====================
h = hashlib.md5(api_base.encode()).hexdigest()[:8] # 3. 提取 Scheme 和 Netloc (域名+端口)
# 如果解析成功且包含 scheme 和 netloc,则重组
if parsed.scheme and parsed.netloc:
clean_base = f"{parsed.scheme}://{parsed.netloc}".lower()
else:
# 兜底:如果不是标准 URL,或者解析失败,尝试简单的去斜杠和小写化
# 这种情况比较少见,通常 litellm 会校验 URL 格式
clean_base = s.rstrip('/').lower()
except Exception:
# 极端情况下的兜底
clean_base = api_base.strip().rstrip('/').lower()
# 4. 计算 Hash
h = hashlib.md5(clean_base.encode()).hexdigest()[:8]
if DEBUG_MODE: if DEBUG_MODE:
# Debugging hash mismatch # Debugging hash mismatch
print(f"🔍 [Hash Debug] Base='{api_base}' -> Hash='{h}'", flush=True) # 打印原始值和清洗后的值,方便确认
print(f"🔍 [Hash Debug] Base='{api_base}' -> Clean='{clean_base}' -> Hash='{h}'", flush=True)
return h return h
@@ -158,6 +183,7 @@ def soft_evict_from_router(target_upstream_model, target_api_base=None):
continue continue
# Strict api_base matching if provided # Strict api_base matching if provided
# ⚠️ 注意:这里比较的是原始字符串,为了确保精准匹配当前运行的实例
if target_api_base and current_api_base != target_api_base: if target_api_base and current_api_base != target_api_base:
continue continue
+30 -11
View File
@@ -1,6 +1,7 @@
import os import os
import yaml import yaml
import hashlib import hashlib
from urllib.parse import urlparse # ✅ 必须导入
import re import re
from typing import Dict, Any from typing import Dict, Any
@@ -63,23 +64,38 @@ def clean_model_name(name):
def generate_api_base_hash(api_base): def generate_api_base_hash(api_base):
"""
[同步更新] 生成 api_base 的 Hash,强制忽略 URL 的路径部分。
保持与 daily_limit.py v20 逻辑完全一致。
"""
if not api_base: if not api_base:
return "default" return "default"
# Logic matches daily_limit.py v18
# === 新增标准化代码 ===
# 1. 去除首尾空格 (strip)
# 2. 去除末尾的斜杠 (rstrip('/'))
# 这样 '.../v3/' 和 '.../v3' 会生成相同的 Hash
normalized_base = api_base.strip().rstrip('/')
# ====================
try:
return hashlib.md5(api_base.encode()).hexdigest()[:8] # 1. 预处理:去空格
s = api_base.strip()
# 2. 解析 URL
parsed = urlparse(s)
# 3. 提取 Scheme 和 Netloc (域名+端口)
# 如果解析成功且包含 scheme 和 netloc,则重组
if parsed.scheme and parsed.netloc:
clean_base = f"{parsed.scheme}://{parsed.netloc}".lower()
else:
# 兜底:如果不是标准 URL,或者解析失败,尝试简单的去斜杠和小写化
clean_base = s.rstrip('/').lower()
except Exception:
# 极端情况下的兜底
clean_base = api_base.strip().rstrip('/').lower()
# 4. 计算 Hash
return hashlib.md5(clean_base.encode()).hexdigest()[:8]
def main(): def main():
print("🔍 Generating Daily Limit Keys from config.yaml...\n") print("🔍 Generating Daily Limit Keys from config.yaml (Robust Mode)...\n")
# 1. Load Env # 1. Load Env
env_vars = load_env(ENV_FILE) env_vars = load_env(ENV_FILE)
@@ -119,10 +135,13 @@ def main():
api_base_raw = litellm_params.get("api_base", "") api_base_raw = litellm_params.get("api_base", "")
# Resolve env vars for hash generation # Resolve env vars for hash generation
# ⚠️ 这里非常重要:必须先解析出真实的 URL,再进行 Hash
api_base_resolved = resolve_env_var(api_base_raw, env_vars) api_base_resolved = resolve_env_var(api_base_raw, env_vars)
# Generate components # Generate components
clean_upstream = clean_model_name(upstream_model) clean_upstream = clean_model_name(upstream_model)
# 使用同步后的 Hash 逻辑
base_hash = generate_api_base_hash(api_base_resolved) base_hash = generate_api_base_hash(api_base_resolved)
# Generate final key # Generate final key