This commit is contained in:
alorig
2025-12-24 01:58:22 +05:00
60 changed files with 12275 additions and 1272 deletions

View File

@@ -82,10 +82,6 @@ def usage_report(request):
operation_count=Count('id')
).order_by('-total_credits')
# Format operation types as Title Case
for usage in usage_by_operation:
usage['operation_type'] = usage['operation_type'].replace('_', ' ').title() if usage['operation_type'] else 'Unknown'
# Top credit consumers
top_consumers = CreditUsageLog.objects.values(
'account__name'
@@ -260,7 +256,7 @@ def data_quality_report(request):
@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.business.billing.models import CreditUsageLog, AIModelConfig
from igny8_core.auth.models import Account
from decimal import Decimal
@@ -285,19 +281,24 @@ def token_usage_report(request):
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(
# Token usage by model (using model_config FK)
token_by_model = logs.filter(model_config__isnull=False).values(
'model_config__model_name',
'model_config__display_name'
).annotate(
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
total_cost_input=Sum('cost_usd_input'),
total_cost_output=Sum('cost_usd_output')
).order_by('-total_tokens_input')[:10]
# Add total_tokens to each model and sort by total
# Add total_tokens and total_cost to each model
for model in token_by_model:
model['total_tokens'] = (model['total_tokens_input'] or 0) + (model['total_tokens_output'] or 0)
model['total_cost'] = (model['total_cost_input'] or 0) + (model['total_cost_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
model['model'] = model['model_config__display_name'] or model['model_config__model_name']
token_by_model = sorted(token_by_model, key=lambda x: x['total_tokens'], reverse=True)
# Token usage by function/operation
@@ -305,14 +306,13 @@ def token_usage_report(request):
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
total_cost=Sum('cost_usd_total')
).order_by('-total_tokens_input')[:10]
# Add total_tokens to each function and sort by total
# Add total_tokens to each function
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
# Format operation_type as Title Case
func['function'] = func['operation_type'].replace('_', ' ').title() if func['operation_type'] else 'Unknown'
token_by_function = sorted(token_by_function, key=lambda x: x['total_tokens'], reverse=True)
@@ -321,10 +321,10 @@ def token_usage_report(request):
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
call_count=Count('id'),
total_cost=Sum('cost_usd')
total_cost=Sum('cost_usd_total')
).order_by('-total_tokens_input')[:15]
# Add total_tokens to each account and sort by total
# Add total_tokens to each account
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]
@@ -341,13 +341,12 @@ def token_usage_report(request):
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)
# Token efficiency metrics
success_rate = 100.0
successful_tokens = total_tokens
wasted_tokens = 0
# Create tokens_by_status for template compatibility
tokens_by_status = [{
tokens_by_status = [{
'error': None,
'total_tokens': total_tokens,
'call_count': total_calls,
@@ -368,7 +367,7 @@ def token_usage_report(request):
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')
total_cost = logs.aggregate(total=Sum('cost_usd_total'))['total'] or Decimal('0.00')
cost_per_1k_tokens = float(total_cost) / (total_tokens / 1000) if total_tokens > 0 else 0.0
context = {
@@ -389,7 +388,7 @@ def token_usage_report(request):
'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
'current_app': '_reports',
}
# Merge with admin context
@@ -403,7 +402,7 @@ def token_usage_report(request):
@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.business.billing.models import CreditUsageLog, AIModelConfig
from igny8_core.auth.models import Account
from decimal import Decimal
@@ -419,53 +418,55 @@ def ai_cost_analysis(request):
# Base queryset - filter for records with cost data
logs = CreditUsageLog.objects.filter(
created_at__gte=start_date,
cost_usd__isnull=False
cost_usd_total__isnull=False
)
# Overall cost metrics
total_cost = logs.aggregate(total=Sum('cost_usd'))['total'] or Decimal('0.00')
total_cost = logs.aggregate(total=Sum('cost_usd_total'))['total'] or Decimal('0.00')
total_calls = logs.count()
avg_cost_per_call = logs.aggregate(avg=Avg('cost_usd'))['avg'] or Decimal('0.00')
avg_cost_per_call = logs.aggregate(avg=Avg('cost_usd_total'))['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
# Revenue & Margin calculation
from igny8_core.business.billing.models import BillingConfiguration
billing_config = BillingConfiguration.get_config()
total_credits_charged = logs.aggregate(total=Sum('credits_used'))['total'] or 0
total_revenue = Decimal(total_credits_charged) * billing_config.default_credit_price_usd
# Average credit price (simplified - in reality would vary by plan)
avg_credit_price = Decimal('0.01') # $0.01 per credit default
total_revenue = Decimal(total_credits_charged) * avg_credit_price
total_margin = total_revenue - total_cost
margin_percentage = float((total_margin / total_revenue * 100) if total_revenue > 0 else 0)
# Per-unit margins
# Calculate per 1M tokens (margin per million tokens)
margin_per_1m_tokens = float(total_margin) / (total_tokens / 1_000_000) if total_tokens > 0 else 0
# Calculate per 1K credits (margin per thousand credits)
margin_per_1k_credits = float(total_margin) / (total_credits_charged / 1000) if total_credits_charged > 0 else 0
# Cost by model with efficiency metrics
cost_by_model = logs.values('model_used').annotate(
total_cost=Sum('cost_usd'),
# Cost by model with efficiency metrics (using model_config FK)
cost_by_model = logs.filter(model_config__isnull=False).values(
'model_config__model_name',
'model_config__display_name'
).annotate(
total_cost=Sum('cost_usd_total'),
call_count=Count('id'),
avg_cost=Avg('cost_usd'),
avg_cost=Avg('cost_usd_total'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output')
total_tokens_output=Sum('tokens_output'),
total_credits=Sum('credits_used')
).order_by('-total_cost')
# Add cost efficiency and margin 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
model['model'] = model['model_config__display_name'] or model['model_config__model_name']
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
# Calculate margin for this model
model_credits = logs.filter(model_used=model['model_used']).aggregate(total=Sum('credits_used'))['total'] or 0
model_revenue = Decimal(model_credits) * billing_config.default_credit_price_usd
model_revenue = Decimal(model['total_credits'] or 0) * avg_credit_price
model_margin = model_revenue - model['total_cost']
model['revenue'] = float(model_revenue)
model['margin'] = float(model_margin)
@@ -473,11 +474,11 @@ def ai_cost_analysis(request):
# Cost by account (top spenders)
cost_by_account = logs.values('account__name', 'account_id').annotate(
total_cost=Sum('cost_usd'),
total_cost=Sum('cost_usd_total'),
call_count=Count('id'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output'),
avg_cost=Avg('cost_usd')
avg_cost=Avg('cost_usd_total')
).order_by('-total_cost')[:15]
# Add total_tokens to each account
@@ -486,22 +487,21 @@ def ai_cost_analysis(request):
# Cost by function/operation
cost_by_function = logs.values('operation_type').annotate(
total_cost=Sum('cost_usd'),
total_cost=Sum('cost_usd_total'),
call_count=Count('id'),
avg_cost=Avg('cost_usd'),
avg_cost=Avg('cost_usd_total'),
total_tokens_input=Sum('tokens_input'),
total_tokens_output=Sum('tokens_output')
total_tokens_output=Sum('tokens_output'),
total_credits=Sum('credits_used')
).order_by('-total_cost')[:10]
# Add total_tokens, function alias, and margin
for func in cost_by_function:
func['total_tokens'] = (func['total_tokens_input'] or 0) + (func['total_tokens_output'] or 0)
# Format operation_type as Title Case
func['function'] = func['operation_type'].replace('_', ' ').title() if func['operation_type'] else 'Unknown'
# Calculate margin for this operation
func_credits = logs.filter(operation_type=func['operation_type']).aggregate(total=Sum('credits_used'))['total'] or 0
func_revenue = Decimal(func_credits) * billing_config.default_credit_price_usd
func_revenue = Decimal(func['total_credits'] or 0) * avg_credit_price
func_margin = func_revenue - func['total_cost']
func['revenue'] = float(func_revenue)
func['margin'] = float(func_margin)
@@ -515,7 +515,7 @@ def ai_cost_analysis(request):
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_cost = day_logs.aggregate(total=Sum('cost_usd_total'))['total'] or Decimal('0.00')
day_calls = day_logs.count()
daily_cost_labels.append(day.strftime('%m/%d'))
@@ -529,21 +529,26 @@ def ai_cost_analysis(request):
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)
failed_cost = Decimal('0.00')
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
anomalies = logs.filter(cost_usd_total__gt=anomaly_threshold).select_related('model_config').values(
'model_config__model_name',
'model_config__display_name',
'operation_type',
'account__name',
'cost_usd_total',
'tokens_input',
'tokens_output',
'created_at'
).order_by('-cost_usd_total')[:10]
# Add aliases for template
for anomaly in anomalies:
anomaly['model'] = anomaly['model_used']
# Format operation_type as Title Case
anomaly['model'] = anomaly['model_config__display_name'] or anomaly['model_config__model_name'] or 'Unknown'
anomaly['function'] = anomaly['operation_type'].replace('_', ' ').title() if anomaly['operation_type'] else 'Unknown'
anomaly['cost'] = anomaly['cost_usd']
anomaly['cost'] = anomaly['cost_usd_total']
anomaly['tokens'] = (anomaly['tokens_input'] or 0) + (anomaly['tokens_output'] or 0)
else:
anomalies = []
@@ -551,9 +556,8 @@ def ai_cost_analysis(request):
# Model comparison matrix
model_comparison = []
for model_data in cost_by_model:
model_name = model_data['model']
model_comparison.append({
'model': model_name,
'model': model_data['model'],
'total_cost': float(model_data['total_cost']),
'calls': model_data['call_count'],
'avg_cost': float(model_data['avg_cost']),
@@ -570,11 +574,11 @@ def ai_cost_analysis(request):
hourly_cost = logs.extra(
select={'hour': "EXTRACT(hour FROM created_at)"}
).values('hour').annotate(
total_cost=Sum('cost_usd'),
total_cost=Sum('cost_usd_total'),
call_count=Count('id')
).order_by('hour')
# Cost efficiency score (CreditUsageLog doesn't track errors, assume all successful)
# Cost efficiency score
successful_cost = total_cost
efficiency_score = 100.0
@@ -588,7 +592,7 @@ def ai_cost_analysis(request):
'margin_per_1m_tokens': round(margin_per_1m_tokens, 4),
'margin_per_1k_credits': round(margin_per_1k_credits, 4),
'total_credits_charged': total_credits_charged,
'credit_price': float(billing_config.default_credit_price_usd),
'credit_price': float(avg_credit_price),
'total_calls': total_calls,
'avg_cost_per_call': float(avg_cost_per_call),
'total_tokens': int(total_tokens),
@@ -606,7 +610,7 @@ def ai_cost_analysis(request):
'hourly_cost': list(hourly_cost),
'efficiency_score': round(efficiency_score, 2),
'successful_cost': float(successful_cost),
'current_app': '_reports', # For active menu state
'current_app': '_reports',
}
# Merge with admin context

View File

@@ -21,34 +21,23 @@ class Igny8AdminSite(UnfoldAdminSite):
index_title = 'IGNY8 Administration'
def get_urls(self):
"""Get admin URLs with dashboard, reports, and monitoring pages available"""
"""Get admin URLs with dashboard and reports available"""
from django.urls import path
from .dashboard import admin_dashboard
from .reports import (
revenue_report, usage_report, content_report, data_quality_report,
token_usage_report, ai_cost_analysis
)
from .monitoring import (
system_health_dashboard, api_monitor_dashboard, debug_console
)
urls = super().get_urls()
custom_urls = [
# Dashboard
path('dashboard/', self.admin_view(admin_dashboard), name='dashboard'),
# Reports
path('reports/revenue/', self.admin_view(revenue_report), name='report_revenue'),
path('reports/usage/', self.admin_view(usage_report), name='report_usage'),
path('reports/content/', self.admin_view(content_report), name='report_content'),
path('reports/data-quality/', self.admin_view(data_quality_report), name='report_data_quality'),
path('reports/token-usage/', self.admin_view(token_usage_report), name='report_token_usage'),
path('reports/ai-cost-analysis/', self.admin_view(ai_cost_analysis), name='report_ai_cost_analysis'),
# Monitoring (NEW)
path('monitoring/system-health/', self.admin_view(system_health_dashboard), name='monitoring_system_health'),
path('monitoring/api-monitor/', self.admin_view(api_monitor_dashboard), name='monitoring_api_monitor'),
path('monitoring/debug-console/', self.admin_view(debug_console), name='monitoring_debug_console'),
path('reports/ai-cost-analysis/', self.admin_view(ai_cost_analysis), name='report_ai_cost'),
]
return custom_urls + urls
@@ -157,15 +146,6 @@ class Igny8AdminSite(UnfoldAdminSite):
('igny8_core_auth', 'SeedKeyword'),
],
},
'Global Settings': {
'models': [
('system', 'GlobalIntegrationSettings'),
('system', 'GlobalModuleSettings'),
('system', 'GlobalAIPrompt'),
('system', 'GlobalAuthorProfile'),
('system', 'GlobalStrategy'),
],
},
'Plans and Billing': {
'models': [
('igny8_core_auth', 'Plan'),
@@ -218,7 +198,14 @@ class Igny8AdminSite(UnfoldAdminSite):
},
'AI & Automation': {
'models': [
('billing', 'AIModelConfig'),
('ai', 'IntegrationState'),
('system', 'IntegrationSettings'),
('system', 'GlobalModuleSettings'),
('system', 'GlobalIntegrationSettings'),
('system', 'GlobalAIPrompt'),
('system', 'GlobalAuthorProfile'),
('system', 'GlobalStrategy'),
('system', 'AIPrompt'),
('system', 'Strategy'),
('system', 'AuthorProfile'),