@@ -0,0 +1,34 @@
|
||||
"""Простой in-process rate limit для POST /api/admin/llm/* по логину сессии."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from typing import MutableMapping
|
||||
|
||||
_LAST: MutableMapping[str, float] = {}
|
||||
|
||||
|
||||
def reset_llm_rate_limit_for_tests() -> None:
|
||||
_LAST.clear()
|
||||
|
||||
|
||||
def llm_post_rate_allow(
|
||||
login: str, interval_sec: float, *, bucket: str = "default"
|
||||
) -> tuple[bool, float]:
|
||||
"""
|
||||
Возвращает (разрешено, сек_до_следующего_слота).
|
||||
При interval_sec <= 0 ограничения нет.
|
||||
|
||||
bucket — отдельный счётчик на пользователя (например «chat» и «heavy» не мешают друг другу).
|
||||
"""
|
||||
login_k = (login or "").strip()
|
||||
if interval_sec <= 0 or not login_k:
|
||||
return True, 0.0
|
||||
key = f"{login_k}\x00{bucket}"
|
||||
now = time.monotonic()
|
||||
last = _LAST.get(key, 0.0)
|
||||
wait = interval_sec - (now - last)
|
||||
if wait > 0:
|
||||
return False, wait
|
||||
_LAST[key] = now
|
||||
return True, 0.0
|
||||
Reference in New Issue
Block a user