ai & tokens

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-19 17:06:01 +00:00
parent 98e68f6bd8
commit e041cb8e65
4 changed files with 962 additions and 66 deletions

View File

@@ -251,3 +251,325 @@ def data_quality_report(request):
context.update(admin_context)
return render(request, 'admin/reports/data_quality.html', context)
@staff_member_required
def token_usage_report(request):
"""Comprehensive token usage analytics with multi-dimensional insights"""
from igny8_core.business.billing.models import CreditUsageLog
from igny8_core.auth.models import Account
from decimal import Decimal
# Date filter setup
days_filter = request.GET.get('days', '30')
try:
days = int(days_filter)
except ValueError:
days = 30
start_date = timezone.now() - timedelta(days=days)
# Base queryset - filter for records with token data
logs = CreditUsageLog.objects.filter(
created_at__gte=start_date,
tokens_input__isnull=False,
tokens_output__isnull=False
)
# Total statistics
total_tokens_input = logs.aggregate(total=Sum('tokens_input'))['total'] or 0
total_tokens_output = logs.aggregate(total=Sum('tokens_output'))['total'] or 0
total_tokens = total_tokens_input + total_tokens_output
total_calls = logs.count()
avg_tokens_per_call = total_tokens / total_calls if total_calls > 0 else 0
# Token usage by model
token_by_model = logs.values('model_used').annotate(
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
).order_by('-total_tokens_input')[:10]
# Add total_tokens to each model and sort by total
for model in token_by_model:
model['total_tokens'] = (model['total_tokens_input'] or 0) + (model['total_tokens_output'] or 0)
model['avg_tokens'] = model['total_tokens'] / model['call_count'] if model['call_count'] > 0 else 0
model['model'] = model['model_used'] # Add alias for template
token_by_model = sorted(token_by_model, key=lambda x: x['total_tokens'], reverse=True)
# Token usage by function/operation
token_by_function = logs.values('operation_type').annotate(
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
).order_by('-total_tokens_input')[:10]
# Add total_tokens to each function and sort by total
for func in token_by_function:
func['total_tokens'] = (func['total_tokens_input'] or 0) + (func['total_tokens_output'] or 0)
func['avg_tokens'] = func['total_tokens'] / func['call_count'] if func['call_count'] > 0 else 0
func['function'] = func['operation_type'] # Add alias for template
token_by_function = sorted(token_by_function, key=lambda x: x['total_tokens'], reverse=True)
# Token usage by account (top consumers)
token_by_account = logs.values('account__name', 'account_id').annotate(
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
).order_by('-total_tokens_input')[:15]
# Add total_tokens to each account and sort by total
for account in token_by_account:
account['total_tokens'] = (account['total_tokens_input'] or 0) + (account['total_tokens_output'] or 0)
token_by_account = sorted(token_by_account, key=lambda x: x['total_tokens'], reverse=True)[:15]
# Daily token trends (time series)
daily_data = []
daily_labels = []
for i in range(days):
day = timezone.now().date() - timedelta(days=days-i-1)
day_logs = logs.filter(created_at__date=day)
day_tokens_input = day_logs.aggregate(total=Sum('tokens_input'))['total'] or 0
day_tokens_output = day_logs.aggregate(total=Sum('tokens_output'))['total'] or 0
day_tokens = day_tokens_input + day_tokens_output
daily_labels.append(day.strftime('%m/%d'))
daily_data.append(int(day_tokens))
# Token efficiency metrics (CreditUsageLog doesn't have error field, so assume all successful)
success_rate = 100.0
successful_tokens = total_tokens
wasted_tokens = 0
# Create tokens_by_status for template compatibility
tokens_by_status = [{
'error': None,
'total_tokens': total_tokens,
'call_count': total_calls,
'avg_tokens': avg_tokens_per_call
}]
# Peak usage times (hour of day)
hourly_usage = logs.extra(
select={'hour': "EXTRACT(hour FROM created_at)"}
).values('hour').annotate(
token_input=Sum('tokens_input'),
token_output=Sum('tokens_output'),
call_count=Count('id')
).order_by('hour')
# Add total token_count for each hour
for hour_data in hourly_usage:
hour_data['token_count'] = (hour_data['token_input'] or 0) + (hour_data['token_output'] or 0)
# Cost efficiency
total_cost = logs.aggregate(total=Sum('cost_usd'))['total'] or Decimal('0.00')
cost_per_1k_tokens = (total_cost / (total_tokens / 1000)) if total_tokens > 0 else Decimal('0.00')
context = {
'title': 'Token Usage Report',
'days_filter': days,
'total_tokens': int(total_tokens),
'total_calls': total_calls,
'avg_tokens_per_call': round(avg_tokens_per_call, 2),
'token_by_model': list(token_by_model),
'token_by_function': list(token_by_function),
'token_by_account': list(token_by_account),
'daily_labels': json.dumps(daily_labels),
'daily_data': json.dumps(daily_data),
'tokens_by_status': list(tokens_by_status),
'success_rate': round(success_rate, 2),
'successful_tokens': int(successful_tokens),
'wasted_tokens': int(wasted_tokens),
'hourly_usage': list(hourly_usage),
'total_cost': float(total_cost),
'cost_per_1k_tokens': float(cost_per_1k_tokens),
'current_app': '_reports', # For active menu state
}
# Merge with admin context
from igny8_core.admin.site import admin_site
admin_context = admin_site.each_context(request)
context.update(admin_context)
return render(request, 'admin/reports/token_usage.html', context)
@staff_member_required
def ai_cost_analysis(request):
"""Multi-dimensional AI cost analysis with model pricing, trends, and predictions"""
from igny8_core.business.billing.models import CreditUsageLog
from igny8_core.auth.models import Account
from decimal import Decimal
# Date filter setup
days_filter = request.GET.get('days', '30')
try:
days = int(days_filter)
except ValueError:
days = 30
start_date = timezone.now() - timedelta(days=days)
# Base queryset - filter for records with cost data
logs = CreditUsageLog.objects.filter(
created_at__gte=start_date,
cost_usd__isnull=False
)
# Overall cost metrics
total_cost = logs.aggregate(total=Sum('cost_usd'))['total'] or Decimal('0.00')
total_calls = logs.count()
avg_cost_per_call = logs.aggregate(avg=Avg('cost_usd'))['avg'] or Decimal('0.00')
total_tokens_input = logs.aggregate(total=Sum('tokens_input'))['total'] or 0
total_tokens_output = logs.aggregate(total=Sum('tokens_output'))['total'] or 0
total_tokens = total_tokens_input + total_tokens_output
# Cost by model with efficiency metrics
cost_by_model = logs.values('model_used').annotate(
total_cost=Sum('cost_usd'),
call_count=Count('id'),
avg_cost=Avg('cost_usd'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output')
).order_by('-total_cost')
# Add cost efficiency (cost per 1K tokens) for each model
for model in cost_by_model:
model['total_tokens'] = (model['total_tokens_input'] or 0) + (model['total_tokens_output'] or 0)
model['avg_tokens'] = model['total_tokens'] / model['call_count'] if model['call_count'] > 0 else 0
model['model'] = model['model_used'] # Add alias for template
if model['total_tokens'] and model['total_tokens'] > 0:
model['cost_per_1k_tokens'] = float(model['total_cost']) / (model['total_tokens'] / 1000)
else:
model['cost_per_1k_tokens'] = 0
# Cost by account (top spenders)
cost_by_account = logs.values('account__name', 'account_id').annotate(
total_cost=Sum('cost_usd'),
call_count=Count('id'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
avg_cost=Avg('cost_usd')
).order_by('-total_cost')[:15]
# Add total_tokens to each account
for account in cost_by_account:
account['total_tokens'] = (account['total_tokens_input'] or 0) + (account['total_tokens_output'] or 0)
# Cost by function/operation
cost_by_function = logs.values('operation_type').annotate(
total_cost=Sum('cost_usd'),
call_count=Count('id'),
avg_cost=Avg('cost_usd'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output')
).order_by('-total_cost')[:10]
# Add total_tokens and function alias
for func in cost_by_function:
func['total_tokens'] = (func['total_tokens_input'] or 0) + (func['total_tokens_output'] or 0)
func['function'] = func['operation_type'] # Add alias for template
# Daily cost trends (time series)
daily_cost_data = []
daily_cost_labels = []
daily_call_data = []
for i in range(days):
day = timezone.now().date() - timedelta(days=days-i-1)
day_logs = logs.filter(created_at__date=day)
day_cost = day_logs.aggregate(total=Sum('cost_usd'))['total'] or Decimal('0.00')
day_calls = day_logs.count()
daily_cost_labels.append(day.strftime('%m/%d'))
daily_cost_data.append(float(day_cost))
daily_call_data.append(day_calls)
# Cost prediction (simple linear extrapolation)
if len(daily_cost_data) > 7:
recent_avg_daily = sum(daily_cost_data[-7:]) / 7
projected_monthly = recent_avg_daily * 30
else:
projected_monthly = 0
# Failed requests cost (CreditUsageLog doesn't track errors, so no failed cost)
failed_cost = Decimal('0.00')
# Cost anomalies (calls costing > 3x average)
if avg_cost_per_call > 0:
anomaly_threshold = float(avg_cost_per_call) * 3
anomalies = logs.filter(cost_usd__gt=anomaly_threshold).values(
'model_used', 'operation_type', 'account__name', 'cost_usd', 'tokens_input', 'tokens_output', 'created_at'
).order_by('-cost_usd')[:10]
# Add aliases and calculate total tokens for each anomaly
for anomaly in anomalies:
anomaly['model'] = anomaly['model_used']
anomaly['function'] = anomaly['operation_type']
anomaly['cost'] = anomaly['cost_usd']
anomaly['tokens'] = (anomaly['tokens_input'] or 0) + (anomaly['tokens_output'] or 0)
else:
anomalies = []
# Model comparison matrix
model_comparison = []
for model_data in cost_by_model:
model_name = model_data['model']
model_comparison.append({
'model': model_name,
'total_cost': float(model_data['total_cost']),
'calls': model_data['call_count'],
'avg_cost': float(model_data['avg_cost']),
'total_tokens': model_data['total_tokens'],
'cost_per_1k': model_data['cost_per_1k_tokens'],
})
# Cost distribution percentages
if total_cost > 0:
for item in cost_by_model:
item['cost_percentage'] = float((item['total_cost'] / total_cost) * 100)
# Peak cost hours
hourly_cost = logs.extra(
select={'hour': "EXTRACT(hour FROM created_at)"}
).values('hour').annotate(
total_cost=Sum('cost_usd'),
call_count=Count('id')
).order_by('hour')
# Cost efficiency score (CreditUsageLog doesn't track errors, assume all successful)
successful_cost = total_cost
efficiency_score = 100.0
context = {
'title': 'AI Cost Analysis',
'days_filter': days,
'total_cost': float(total_cost),
'total_calls': total_calls,
'avg_cost_per_call': float(avg_cost_per_call),
'total_tokens': int(total_tokens),
'cost_by_model': list(cost_by_model),
'cost_by_account': list(cost_by_account),
'cost_by_function': list(cost_by_function),
'daily_cost_labels': json.dumps(daily_cost_labels),
'daily_cost_data': json.dumps(daily_cost_data),
'daily_call_data': json.dumps(daily_call_data),
'projected_monthly': round(projected_monthly, 2),
'failed_cost': float(failed_cost),
'wasted_percentage': float((failed_cost / total_cost * 100) if total_cost > 0 else 0),
'anomalies': list(anomalies),
'model_comparison': model_comparison,
'hourly_cost': list(hourly_cost),
'efficiency_score': round(efficiency_score, 2),
'successful_cost': float(successful_cost),
'current_app': '_reports', # For active menu state
}
# Merge with admin context
from igny8_core.admin.site import admin_site
admin_context = admin_site.each_context(request)
context.update(admin_context)
return render(request, 'admin/reports/ai_cost_analysis.html', context)