- Fix text selection menu not showing: wire contentRef via inputRef on multiline TextField - Fix blog title not truncating: add min-w-0 for flex item overflow - Fix outline generation 500: escape curly braces in f-string prompt template - Fix content generation 'NoneType not callable': replace SessionLocal() with get_session_for_user(), add db param to MediumBlogGenerator, fix signature mismatch in database_task_manager - Fix writing assistant suggest 500: add auth + user_id to API endpoint and service, replace sync requests with httpx.AsyncClient - Fix hallucination detector 404: explicitly include router in main.py and app.py - Fix missing error_data in task failure responses - Hide CopilotKit web inspector button - Remove hardcoded fallback suggestions from SmartTypingAssist - Fix stale closure refs in SmartTypingAssist handleTypingChange - Add two-column editor layout, stats bar, section hover menu - Various subscription, billing, and research module improvements
158 lines
6.2 KiB
Python
158 lines
6.2 KiB
Python
#!/usr/bin/env python
|
|
# Add _get_all_historical_usage method to usage_tracking_service.py
|
|
|
|
with open('services/subscription/usage_tracking_service.py', 'r', encoding='utf-8') as f:
|
|
lines = f.readlines()
|
|
|
|
# Find where to insert (before get_usage_trends)
|
|
insert_idx = None
|
|
for i, line in enumerate(lines):
|
|
if ' def get_usage_trends(' in line:
|
|
insert_idx = i
|
|
break
|
|
|
|
if insert_idx is None:
|
|
print("Error: Could not find insertion point")
|
|
exit(1)
|
|
|
|
print(f"Inserting at line {insert_idx + 1}")
|
|
|
|
# Method to insert
|
|
new_method = ''' def _get_all_historical_usage(self, user_id: str) -> Dict[str, Any]:
|
|
"""Get ALL historical usage data aggregated across all billing periods."""
|
|
|
|
# Get all usage summaries for the user
|
|
all_summaries = self.db.query(UsageSummary).filter(
|
|
UsageSummary.user_id == user_id
|
|
).order_by(UsageSummary.billing_period.desc()).all()
|
|
|
|
if not all_summaries:
|
|
return {
|
|
'billing_period': 'all',
|
|
'usage_status': 'active',
|
|
'total_calls': 0,
|
|
'total_tokens': 0,
|
|
'total_cost': 0.0,
|
|
'avg_response_time': 0.0,
|
|
'error_rate': 0.0,
|
|
'limits': self.pricing_service.get_user_limits(user_id),
|
|
'provider_breakdown': {},
|
|
'usage_percentages': {},
|
|
'historical_breakdown': [],
|
|
'last_updated': datetime.now().isoformat()
|
|
}
|
|
|
|
# Aggregate all data from UsageSummary
|
|
total_calls = sum(s.total_calls or 0 for s in all_summaries)
|
|
total_tokens = sum(s.total_tokens or 0 for s in all_summaries)
|
|
total_cost = sum(float(s.total_cost or 0) for s in all_summaries)
|
|
|
|
# Calculate weighted average response time
|
|
total_weighted_time = sum((s.avg_response_time or 0) * (s.total_calls or 0) for s in all_summaries)
|
|
avg_response_time = total_weighted_time / total_calls if total_calls > 0 else 0.0
|
|
|
|
# Calculate overall error rate
|
|
total_errors = sum((s.total_calls or 0) * (s.error_rate or 0) / 100 for s in all_summaries)
|
|
error_rate = (total_errors / total_calls * 100) if total_calls > 0 else 0.0
|
|
|
|
# Get user limits
|
|
limits = self.pricing_service.get_user_limits(user_id)
|
|
|
|
# Map database columns to frontend keys
|
|
provider_mapping = {
|
|
'gemini_calls': 'gemini',
|
|
'openai_calls': 'openai',
|
|
'anthropic_calls': 'anthropic',
|
|
'mistral_calls': 'huggingface',
|
|
'wavespeed_calls': 'wavespeed',
|
|
'exa_calls': 'exa',
|
|
'video_calls': 'video',
|
|
'image_edit_calls': 'image_edit',
|
|
'audio_calls': 'audio',
|
|
}
|
|
|
|
# Build provider_breakdown for frontend
|
|
provider_breakdown = {}
|
|
for db_col, frontend_key in provider_mapping.items():
|
|
total_provider_calls = sum(getattr(s, db_col, 0) or 0 for s in all_summaries)
|
|
provider_breakdown[frontend_key] = {
|
|
'calls': total_provider_calls,
|
|
'cost': 0,
|
|
'tokens': 0
|
|
}
|
|
|
|
# Calculate usage_percentages based on limits
|
|
usage_percentages = {}
|
|
if limits and limits.get('limits'):
|
|
# Gemini calls percentage
|
|
gemini_calls = provider_breakdown.get('gemini', {}).get('calls', 0)
|
|
gemini_limit = limits.get('limits', {}).get('gemini_calls', 0) or 0
|
|
if gemini_limit > 0:
|
|
usage_percentages['gemini_calls'] = (gemini_calls / gemini_limit) * 100
|
|
|
|
# HuggingFace calls percentage (from mistral_calls)
|
|
huggingface_calls = provider_breakdown.get('huggingface', {}).get('calls', 0)
|
|
huggingface_limit = limits.get('limits', {}).get('mistral_calls', 0) or 0
|
|
if huggingface_limit > 0:
|
|
usage_percentages['huggingface_calls'] = (huggingface_calls / huggingface_limit) * 100
|
|
|
|
# Cost percentage
|
|
cost_limit = limits.get('limits', {}).get('monthly_cost', 0) or 0
|
|
if cost_limit > 0:
|
|
usage_percentages['cost'] = (total_cost / cost_limit) * 100
|
|
|
|
# Build historical breakdown
|
|
historical_breakdown = []
|
|
for s in all_summaries:
|
|
try:
|
|
status_val = s.usage_status.value
|
|
except:
|
|
status_val = str(s.usage_status)
|
|
historical_breakdown.append({
|
|
'billing_period': s.billing_period,
|
|
'total_calls': s.total_calls or 0,
|
|
'total_tokens': s.total_tokens or 0,
|
|
'total_cost': float(s.total_cost or 0),
|
|
'usage_status': status_val,
|
|
'updated_at': s.updated_at.isoformat() if s.updated_at else None
|
|
})
|
|
|
|
# Determine overall status
|
|
usage_status = 'active'
|
|
for s in all_summaries:
|
|
try:
|
|
status = s.usage_status.value
|
|
except:
|
|
status = str(s.usage_status)
|
|
if status == 'limit_reached':
|
|
usage_status = 'limit_reached'
|
|
break
|
|
elif status == 'warning' and usage_status != 'limit_reached':
|
|
usage_status = 'warning'
|
|
|
|
return {
|
|
'billing_period': 'all',
|
|
'usage_status': usage_status,
|
|
'total_calls': total_calls,
|
|
'total_tokens': total_tokens,
|
|
'total_cost': round(total_cost, 2),
|
|
'avg_response_time': round(avg_response_time, 2),
|
|
'error_rate': round(error_rate, 2),
|
|
'limits': limits,
|
|
'provider_breakdown': provider_breakdown,
|
|
'usage_percentages': usage_percentages,
|
|
'historical_breakdown': historical_breakdown,
|
|
'last_updated': datetime.now().isoformat()
|
|
}
|
|
|
|
'''
|
|
|
|
# Insert the new method
|
|
new_lines = lines[:insert_idx] + [new_method] + lines[insert_idx:]
|
|
|
|
# Write back
|
|
with open('services/subscription/usage_tracking_service.py', 'w', encoding='utf-8') as f:
|
|
f.writelines(new_lines)
|
|
|
|
print("Successfully added _get_all_historical_usage method")
|