chore: 从汽车AI客服项目拷贝骨架并清理(blog页/redis)

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-09-29 14:15:12 +08:00
parent 90860b8bfd
commit 49c0e5559c
97 changed files with 19131 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
"""Minimal in-memory rate limiter (per (ip, device_id), rolling 1h window).
Mirrors hesu's rate_limit.py shape. Only the chat message route uses this;
session/history endpoints are cheap and not throttled. State is process-local
and resets on restart, which is acceptable for a single-worker ai-kefu deploy.
Caveats:
- Single-process, in-memory. Under `uvicorn --workers >1` each worker keeps
its own `_buckets`, so the effective cap is `max_requests * workers`.
- Keyed on (ip, device_id); a client rotating the `X-Device-Id` header per
request bypasses it. This is a light safeguard against accidental GLM-cost
burn, NOT abuse-proof.
"""
import time
from collections import defaultdict
_buckets: dict[tuple[str, str], list[float]] = defaultdict(list)
WINDOW = 3600
DEFAULT_MAX = 30
def check(
ip: str | None,
device_id: str | None,
*,
max_requests: int = DEFAULT_MAX,
) -> bool:
"""Return True if the request is under the cap (and record it), else False."""
key = (ip or "", device_id or "")
now = time.time()
_buckets[key] = [t for t in _buckets[key] if t > now - WINDOW]
if len(_buckets[key]) >= max_requests:
return False
_buckets[key].append(now)
return True
def _reset_for_test() -> None:
_buckets.clear()