v0.0.38: живой таймер обработки + индикация ИИ (live-блок, heartbeat llm в SSE)
Deploy drhider / validate (push) Canceled after 0s

This commit is contained in:
“Naeel”
2026-08-19 09:25:01 +04:00
parent defbc10004
commit e548c89880
5 changed files with 165 additions and 26 deletions
+42 -23
View File
@@ -10,6 +10,7 @@ LLM-клиент для DrHider.
"""
import os
import time
import httpx
@@ -29,16 +30,28 @@ class LLMClient:
tokens_prompt — суммарные входные токены
tokens_completion — суммарные выходные токены
llm_sec — суммарное время LLM-запросов (сек)
Плюс флаг текущей активности (для live-таймера в UI):
llm_active — True пока идёт LLM-вызов
llm_started — time.time() начала текущего LLM-вызова
"""
self._httpx = httpx
self.tokens_prompt = 0
self.tokens_completion = 0
self.llm_sec = 0.0
self.llm_active = False
self.llm_started = 0.0
@property
def tokens_total(self) -> int:
return self.tokens_prompt + self.tokens_completion
def llm_elapsed_now(self) -> float:
"""Секунд с начала текущего LLM-вызова (0, если LLM не активен)."""
if self.llm_active:
return time.time() - self.llm_started
return 0.0
def complete(self, prompt: str) -> str:
"""Отправить промпт в LLM и вернуть текст ответа.
@@ -59,29 +72,35 @@ class LLMClient:
url = os.environ.get("LLM_URL", "https://api.aillm.ru/v1/chat/completions")
model = os.environ.get("LLM_MODEL", "gpt-oss-120b")
r = self._httpx.post(
url,
json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 8000,
"temperature": 0.1,
},
headers={
"Authorization": f"Bearer {key}",
"Content-Type": "application/json",
},
timeout=120,
)
r.raise_for_status()
# Пометим LLM-вызов как активный (для live-таймера в UI)
self.llm_active = True
self.llm_started = time.time()
try:
r = self._httpx.post(
url,
json={
"model": model,
"messages": [{"role": "user", "content": prompt}],
"max_tokens": 8000,
"temperature": 0.1,
},
headers={
"Authorization": f"Bearer {key}",
"Content-Type": "application/json",
},
timeout=120,
)
r.raise_for_status()
# Время запроса (реальное время HTTP-вызова LLM)
self.llm_sec += r.elapsed.total_seconds()
# Время запроса (реальное время HTTP-вызова LLM)
self.llm_sec += r.elapsed.total_seconds()
data = r.json()
# Счётчики токенов из usage (могут отсутствовать у некоторых прокси)
usage = data.get("usage", {}) or {}
self.tokens_prompt += int(usage.get("prompt_tokens", 0) or 0)
self.tokens_completion += int(usage.get("completion_tokens", 0) or 0)
data = r.json()
# Счётчики токенов из usage (могут отсутствовать у некоторых прокси)
usage = data.get("usage", {}) or {}
self.tokens_prompt += int(usage.get("prompt_tokens", 0) or 0)
self.tokens_completion += int(usage.get("completion_tokens", 0) or 0)
return data["choices"][0]["message"]["content"]
return data["choices"][0]["message"]["content"]
finally:
self.llm_active = False