mirror of
https://github.com/dartdavros/chatballs.git
synced 2026-10-05 01:14:58 +03:00
- каталог code/custocrm → code/chatballs; CLI custocrm → chatballs; пакеты hub_platform → chatballs, hub_backend → chatballs_backend (app labels прежние) - переменные CUS_* и CUSTOCRM_* → CHATBALLS_*; образы chatballs-*; compose-проект и база chatballs (были edevs_hub); роли Postgres chatballs_* (были custocrm_*); схема RLS chatballs и GUC chatballs.organization_id; cookie chatballs_* - CI: APP_DIR code/chatballs, DEPLOY_ROOT /opt/chatballs - deploy/migrate/rename-to-chatballs.sh — миграция существующей установки без потери данных: остановка старого проекта, .env (с резервной копией), переименование суперпользователя initdb через временную роль, остальных ролей, базы, схемы и функции RLS; проверено на локальном стеке - dev-стек хранит Postgres в bind-mount data/postgres, как prod (именованный том compose.dev был устаревшим снимком и вводил в заблуждение) - снятие демо удаляет объекты, созданные поверх демо-данных тестировавшим (звонки по демо-диалогу), вместо падения на PROTECT - реальные домены *.custocrm.ru и идентификаторы документов не тронуты Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
33 lines
1.3 KiB
Python
33 lines
1.3 KiB
Python
from django.conf import settings
|
|
|
|
from django.db.models import Sum
|
|
|
|
from django.utils import timezone
|
|
|
|
|
|
|
|
from chatballs.ai.models import LlmInvocation, LlmInvocationStatus
|
|
|
|
|
|
|
|
|
|
|
|
class LimitExceeded(Exception):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
|
def _day_start():
|
|
|
|
now = timezone.localtime()
|
|
|
|
return now.replace(hour=0, minute=0, second=0, microsecond=0)
|
|
|
|
|
|
|
|
|
|
|
|
def daily_cost_micros(channel=None) -> int:
|
|
|
|
queryset = LlmInvocation.objects.filter(created_at__gte=_day_start(), status=LlmInvocationStatus.SUCCESS)
|
|
|
|
if channel is not None:
|
|
|
|
queryset = queryset.filter(channel=channel)
|
|
|
|
return queryset.aggregate(total=Sum("cost_micros"))["total"] or 0
|
|
|
|
|
|
|
|
|
|
|
|
def assert_within_limits(channel, agent) -> None:
|
|
|
|
global_limit = settings.CHATBALLS_AI_GLOBAL_DAILY_COST_LIMIT_MICROS
|
|
|
|
if global_limit and daily_cost_micros() >= global_limit:
|
|
|
|
raise LimitExceeded("Global daily AI cost limit reached")
|
|
|
|
# Канальный лимит хранится в целых центах USD (dailyCostUsd); расход учитывается
|
|
|
|
# в micro-USD. 1 цент = 10 000 micro-USD.
|
|
|
|
channel_limit = (agent.limits or {}).get("dailyCostUsd")
|
|
|
|
if channel_limit and daily_cost_micros(channel) >= int(channel_limit) * 10_000:
|
|
|
|
raise LimitExceeded("Channel daily AI cost limit reached")
|
|
|