feat(costs): $-Tagesbudget pro Nutzer (Stufe 3)
cost_daily_limit_usd (Pref > global; 0 = unbegrenzt) in quota.py (cost_within_budget, cost_limit). ws.py-Gate: Web-Such- ODER Kostenbudget aufgebraucht -> Web-Suche fuer den Turn aus + freundlicher Hinweis. Admin: Schema-Feld + list_users + UI-Eingabe ($/Tag) + globales Live-Setting. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
d87f0ce424
commit
66d6708f59
7 changed files with 57 additions and 5 deletions
|
|
@ -239,6 +239,7 @@ async def list_users():
|
|||
"location_consent": bool((u.prefs or {}).get("location_consent", False)),
|
||||
"web_search_enabled": bool((u.prefs or {}).get("web_search_enabled", runtime_settings.web_search_enabled)),
|
||||
"web_search_daily_limit": (u.prefs or {}).get("web_search_daily_limit", ""),
|
||||
"cost_daily_limit_usd": (u.prefs or {}).get("cost_daily_limit_usd", ""),
|
||||
"is_admin": is_admin_user(u),
|
||||
}
|
||||
for u in get_store().list_users()
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ from app.store import ANONYMOUS_USER_ID, SessionOwnershipError
|
|||
from app.audio.vad import EnergyVAD
|
||||
from app.core.memory_extractor import maybe_schedule_extraction
|
||||
from app.quota import (enforce_quota, record_usage, QuotaExceededError,
|
||||
web_search_within_budget, record_web_search)
|
||||
web_search_within_budget, record_web_search, cost_within_budget)
|
||||
from app.core.costs import start_meter, persist_costs
|
||||
from app.pipeline.search_backstop import should_force_search
|
||||
|
||||
|
|
@ -93,8 +93,9 @@ def _authenticate(websocket: WebSocket, token: str | None):
|
|||
async def _resolve(user, session_id, options, store=None):
|
||||
"""Loest Route + Orchestrator + Output-Endpunkt auf (kann RoutingError/Ownership werfen)."""
|
||||
overrides = {key: options.get(key) for key in _OVERRIDE_KEYS}
|
||||
# Web-Such-Tagesbudget aufgebraucht -> Web-Suche fuer diesen Turn aus.
|
||||
if store is not None and not web_search_within_budget(user, store):
|
||||
# Web-Such- oder Kosten-Tagesbudget aufgebraucht -> Web-Suche fuer den Turn aus.
|
||||
if store is not None and (not web_search_within_budget(user, store)
|
||||
or not cost_within_budget(user, store)):
|
||||
overrides["web_search_enabled"] = False
|
||||
route = resolve_route(user, session_id, overrides)
|
||||
orchestrator = build_orchestrator(route)
|
||||
|
|
@ -215,7 +216,9 @@ async def _run_turn(
|
|||
# Freundlicher Hinweis, wenn die Web-Suche bei einer offensichtlich aktuellen
|
||||
# Frage nicht verfuegbar war (abgeschaltet oder Tagesbudget aufgebraucht).
|
||||
if not route.web_search_enabled and should_force_search(text):
|
||||
kind = "budget" if not web_search_within_budget(user, store) else "off"
|
||||
over_budget = (not web_search_within_budget(user, store)
|
||||
or not cost_within_budget(user, store))
|
||||
kind = "budget" if over_budget else "off"
|
||||
await websocket.send_json({"type": "notice", "text": _ws_notice(route.language, kind)})
|
||||
# Im text_only-Modus kommt kein Audio (Gerät spricht selbst).
|
||||
if not audio_stream and not text_only:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue