Alpha Subscription Implementation Plan

This commit is contained in:
ajaysi
2025-09-24 14:44:42 +05:30
parent dee3e428bd
commit 9cd5b3a583
7 changed files with 563 additions and 151 deletions

View File

@@ -32,17 +32,22 @@ class DatabaseAPIMonitor:
'misses': 0,
'hit_rate': 0.0
}
# API provider detection patterns
# API provider detection patterns - Updated to match actual endpoints
self.provider_patterns = {
APIProvider.GEMINI: [r'/gemini', r'gemini', r'google.*ai'],
APIProvider.OPENAI: [r'/openai', r'openai', r'gpt'],
APIProvider.GEMINI: [
r'/api/blog-writer', r'/api/content-planning', r'/api/strategy-copilot',
r'/api/brainstorm', r'/api/writing-assistant', r'/api/seo-dashboard',
r'/api/onboarding', r'/api/user-data', r'/api/component-logic',
r'gemini', r'google.*ai', r'blog.*writer', r'content.*planning'
],
APIProvider.OPENAI: [r'/openai', r'openai', r'gpt', r'chatgpt'],
APIProvider.ANTHROPIC: [r'/anthropic', r'claude', r'anthropic'],
APIProvider.MISTRAL: [r'/mistral', r'mistral'],
APIProvider.TAVILY: [r'/tavily', r'tavily'],
APIProvider.SERPER: [r'/serper', r'serper', r'google.*search'],
APIProvider.TAVILY: [r'/tavily', r'tavily', r'research', r'search'],
APIProvider.SERPER: [r'/serper', r'serper', r'google.*search', r'seo'],
APIProvider.METAPHOR: [r'/metaphor', r'/exa', r'metaphor', r'exa'],
APIProvider.FIRECRAWL: [r'/firecrawl', r'firecrawl'],
APIProvider.STABILITY: [r'/stability', r'stable.*diffusion', r'stability']
APIProvider.FIRECRAWL: [r'/firecrawl', r'firecrawl', r'crawl'],
APIProvider.STABILITY: [r'/stability', r'stable.*diffusion', r'stability', r'image.*generation']
}
def detect_api_provider(self, path: str, user_agent: str = None) -> Optional[APIProvider]:
@@ -154,6 +159,7 @@ class DatabaseAPIMonitor:
# Track API usage if this is an API call to external providers
api_provider = self.detect_api_provider(path, user_agent)
if api_provider and user_id:
logger.info(f"🔍 Detected API call: {path} -> {api_provider.value} for user: {user_id}")
try:
# Extract usage metrics
usage_metrics = self.extract_usage_metrics(request_body, response_body)
@@ -178,7 +184,7 @@ class DatabaseAPIMonitor:
image_count=usage_metrics.get('image_count', 0),
page_count=usage_metrics.get('page_count', 0)
)
logger.info(f"Tracked usage for {user_id}: {api_provider.value} - {usage_metrics.get('tokens_input', 0)}+{usage_metrics.get('tokens_output', 0)} tokens")
logger.info(f"Tracked usage for {user_id}: {api_provider.value} - {usage_metrics.get('tokens_input', 0)}+{usage_metrics.get('tokens_output', 0)} tokens")
except Exception as usage_error:
logger.error(f"Error tracking API usage: {usage_error}")
# Don't fail the main request if usage tracking fails
@@ -457,33 +463,60 @@ async def monitoring_middleware(request: Request, call_next):
response = await call_next(request)
return response
# Extract request details
# Extract request details - Enhanced user identification
user_id = None
try:
# Check query parameters
if hasattr(request, 'query_params') and 'user_id' in request.query_params:
user_id = request.query_params['user_id']
elif hasattr(request, 'path_params') and 'user_id' in request.path_params:
user_id = request.path_params['user_id']
# Also check headers for user identification
# Check headers for user identification
elif 'x-user-id' in request.headers:
user_id = request.headers['x-user-id']
elif 'x-user-email' in request.headers:
user_id = request.headers['x-user-email'] # Use email as user identifier
elif 'x-session-id' in request.headers:
user_id = request.headers['x-session-id'] # Use session as fallback
# Check for authorization header with user info
elif 'authorization' in request.headers:
# This would need to be implemented based on your auth system
pass
except:
pass
auth_header = request.headers['authorization']
# Extract user info from JWT or other auth tokens if needed
# For now, use a default user for testing
user_id = "default_user"
# For alpha testing, use IP address as user identifier if no other ID found
if not user_id and request.client:
user_id = f"alpha_user_{request.client.host}"
# Final fallback for testing
if not user_id:
user_id = "anonymous_user"
except Exception as e:
logger.debug(f"Error extracting user ID: {e}")
user_id = "error_user"
# Capture request body for usage tracking (read once)
# Capture request body for usage tracking (read once, safely)
request_body = None
try:
if hasattr(request, '_body'):
request_body = request._body.decode('utf-8') if request._body else None
else:
body = await request.body()
request_body = body.decode('utf-8') if body else None
except:
pass
# Only read body for POST/PUT/PATCH requests to avoid issues
if request.method in ['POST', 'PUT', 'PATCH']:
if hasattr(request, '_body') and request._body:
request_body = request._body.decode('utf-8')
else:
# Read body only if it hasn't been read yet
try:
body = await request.body()
request_body = body.decode('utf-8') if body else None
except Exception as body_error:
logger.debug(f"Could not read request body: {body_error}")
request_body = None
except Exception as e:
logger.debug(f"Error capturing request body: {e}")
request_body = None
# Check usage limits before processing
limit_response = await check_usage_limits_middleware(request, user_id, request_body)

View File

@@ -3,7 +3,7 @@
import time
import asyncio
import os
from typing import Dict, Any, Optional
from typing import Dict, Any, Optional, List
from collections import defaultdict, deque
from fastapi import Request, HTTPException
from fastapi.responses import JSONResponse