import React, { useState, useEffect } from 'react';
import {
Card,
CardContent,
Typography,
Box,
Grid,
Chip,
Tooltip,
Accordion,
AccordionSummary,
AccordionDetails,
CircularProgress,
} from '@mui/material';
import { ExpandMore } from '@mui/icons-material';
import { motion } from 'framer-motion';
import {
Info,
Search,
Image,
Code,
Database,
FileText,
BarChart3,
RefreshCw
} from 'lucide-react';
// Types
import { ProviderBreakdown, APIPricing } from '../../types/billing';
// Services
import { billingService } from '../../services/billingService';
interface ComprehensiveAPIBreakdownProps {
providerBreakdown: ProviderBreakdown;
totalCost: number;
}
// Comprehensive API categories and their descriptions
const API_CATEGORIES = {
llm_models: {
title: 'Large Language Models',
description: 'AI models for text generation, analysis, and processing',
icon: ,
apis: [
{
name: 'Gemini',
description: 'Google\'s advanced AI model for complex reasoning and coding',
models: ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-1.5-pro', 'gemini-1.5-flash'],
pricing: 'From $0.10/1M tokens (Flash-Lite) to $15.00/1M tokens (Pro)',
use_cases: ['Content generation', 'Code analysis', 'Complex reasoning']
},
{
name: 'OpenAI',
description: 'GPT models for natural language processing and generation',
models: ['gpt-4o', 'gpt-4o-mini', 'gpt-3.5-turbo'],
pricing: 'From $0.15/1M tokens (GPT-4o Mini) to $10.00/1M tokens (GPT-4o)',
use_cases: ['Chat completion', 'Text analysis', 'Creative writing']
},
{
name: 'Anthropic',
description: 'Claude models for safe and helpful AI assistance',
models: ['claude-3.5-sonnet', 'claude-3-haiku', 'claude-3-opus'],
pricing: 'From $3.00/1M tokens (Sonnet) to $15.00/1M tokens (Opus)',
use_cases: ['Safe AI assistance', 'Long-form content', 'Analysis tasks']
},
{
name: 'Mistral',
description: 'European AI models for efficient text processing',
models: ['mistral-large', 'mistral-medium', 'mistral-small'],
pricing: 'From $2.00/1M tokens (Small) to $8.00/1M tokens (Large)',
use_cases: ['Multilingual support', 'Efficient processing', 'European compliance']
}
]
},
search_apis: {
title: 'Search & Research APIs',
description: 'APIs for web search, content discovery, and research',
icon: ,
apis: [
{
name: 'Tavily',
description: 'AI-powered search for real-time information',
models: ['tavily-search'],
pricing: '$0.001 per search request',
use_cases: ['Real-time search', 'Fact checking', 'Research assistance']
},
{
name: 'Serper',
description: 'Google Search API for web results',
models: ['serper-search'],
pricing: '$0.001 per search request',
use_cases: ['Web search', 'SEO analysis', 'Content research']
},
{
name: 'Metaphor',
description: 'Advanced search and content discovery',
models: ['metaphor-search'],
pricing: '$0.003 per search request',
use_cases: ['Content discovery', 'Link analysis', 'Research automation']
}
]
},
content_processing: {
title: 'Content Processing APIs',
description: 'APIs for web scraping, content extraction, and processing',
icon: ,
apis: [
{
name: 'Firecrawl',
description: 'Web scraping and content extraction service',
models: ['firecrawl-extract', 'firecrawl-scrape'],
pricing: '$0.002 per page crawled',
use_cases: ['Web scraping', 'Content extraction', 'Data collection']
}
]
},
image_generation: {
title: 'Image Generation APIs',
description: 'APIs for creating and processing images',
icon: ,
apis: [
{
name: 'Stability AI',
description: 'AI-powered image generation and editing',
models: ['stable-diffusion-xl', 'stable-diffusion-3'],
pricing: '$0.04 per image generated',
use_cases: ['Image generation', 'Art creation', 'Visual content']
},
{
name: 'Image Editing',
description: 'AI-powered image editing using natural language prompts',
models: ['Qwen/Qwen-Image-Edit', 'FLUX.1-Kontext-dev'],
pricing: '$0.04 per image edited',
use_cases: ['Image editing', 'Photo manipulation', 'Natural language editing']
}
]
},
embeddings: {
title: 'Embeddings & Vector APIs',
description: 'APIs for text embeddings and vector operations',
icon: ,
apis: [
{
name: 'Gemini Embeddings',
description: 'Text embeddings for semantic search and analysis',
models: ['gemini-embedding'],
pricing: '$0.15 per 1M input tokens',
use_cases: ['Semantic search', 'Text similarity', 'Vector databases']
}
]
}
};
const ComprehensiveAPIBreakdown: React.FC = ({
providerBreakdown,
totalCost
}) => {
const [pricing, setPricing] = useState([]);
const [loadingPricing, setLoadingPricing] = useState(true);
const [pricingError, setPricingError] = useState(null);
// Fetch dynamic pricing on mount
useEffect(() => {
const fetchPricing = async () => {
try {
setLoadingPricing(true);
setPricingError(null);
const pricingData = await billingService.getAPIPricing();
setPricing(pricingData);
} catch (err) {
console.error('[ComprehensiveAPIBreakdown] Error fetching pricing:', err);
setPricingError(err instanceof Error ? err.message : 'Failed to fetch pricing');
} finally {
setLoadingPricing(false);
}
};
fetchPricing();
}, []);
// Get active providers from breakdown
const activeProviders = Object.entries(providerBreakdown)
.filter(([_, data]) => data && data.cost > 0)
.map(([provider, data]) => ({
provider,
cost: data?.cost ?? 0,
calls: data?.calls ?? 0,
tokens: data?.tokens ?? 0
}));
// Helper function to format pricing from API or fallback to static
const getPricingDisplay = (apiName: string, fallbackPricing: string): string => {
if (loadingPricing) {
return 'Loading pricing...';
}
if (pricingError) {
return fallbackPricing; // Fallback to static pricing on error
}
// Find matching pricing by provider name
const apiPricing = pricing.find(p =>
p.provider.toLowerCase() === apiName.toLowerCase() ||
p.model_name.toLowerCase().includes(apiName.toLowerCase())
);
if (apiPricing) {
// Format pricing based on what's available
const parts: string[] = [];
if (apiPricing.cost_per_input_token > 0 || apiPricing.cost_per_output_token > 0) {
const inputCost = apiPricing.cost_per_input_token > 0
? `$${(apiPricing.cost_per_input_token * 1000000).toFixed(2)}/1M input`
: '';
const outputCost = apiPricing.cost_per_output_token > 0
? `$${(apiPricing.cost_per_output_token * 1000000).toFixed(2)}/1M output`
: '';
if (inputCost && outputCost) {
parts.push(`${inputCost}, ${outputCost}`);
} else if (inputCost) {
parts.push(inputCost);
} else if (outputCost) {
parts.push(outputCost);
}
}
if (apiPricing.cost_per_request > 0) {
parts.push(`$${apiPricing.cost_per_request.toFixed(4)} per request`);
}
if (apiPricing.cost_per_search > 0) {
parts.push(`$${apiPricing.cost_per_search.toFixed(4)} per search`);
}
if (apiPricing.cost_per_image > 0) {
parts.push(`$${apiPricing.cost_per_image.toFixed(2)} per image`);
}
if (apiPricing.cost_per_page > 0) {
parts.push(`$${apiPricing.cost_per_page.toFixed(4)} per page`);
}
return parts.length > 0 ? parts.join(', ') : fallbackPricing;
}
return fallbackPricing; // Fallback to static pricing if not found
};
const getProviderCategory = (providerName: string) => {
const provider = providerName.toLowerCase();
if (['gemini', 'openai', 'anthropic', 'mistral'].includes(provider)) {
return 'llm_models';
}
if (['tavily', 'serper', 'metaphor'].includes(provider)) {
return 'search_apis';
}
if (['firecrawl'].includes(provider)) {
return 'content_processing';
}
if (['stability', 'image_edit'].includes(provider)) {
return 'image_generation';
}
return 'llm_models'; // default
};
const getCategoryStats = (categoryKey: string) => {
const categoryProviders = activeProviders.filter(p =>
getProviderCategory(p.provider) === categoryKey
);
return {
count: categoryProviders.length,
totalCost: categoryProviders.reduce((sum, p) => sum + (p.cost ?? 0), 0),
totalCalls: categoryProviders.reduce((sum, p) => sum + (p.calls ?? 0), 0),
totalTokens: categoryProviders.reduce((sum, p) => sum + (p.tokens ?? 0), 0)
};
};
return (
{/* Header */}
Comprehensive API Breakdown
{loadingPricing && (
)}
{!loadingPricing && !pricingError && (
{
try {
setLoadingPricing(true);
const pricingData = await billingService.getAPIPricing();
setPricing(pricingData);
setPricingError(null);
} catch (err) {
setPricingError(err instanceof Error ? err.message : 'Failed to refresh pricing');
} finally {
setLoadingPricing(false);
}
}}
/>
)}
{/* Summary Stats */}
{Object.keys(API_CATEGORIES).length}
API Categories
{activeProviders.length}
Active Providers
${totalCost.toFixed(4)}
Total Cost
{activeProviders.reduce((sum, p) => sum + (p.calls ?? 0), 0)}
Total Calls
{/* API Categories */}
{Object.entries(API_CATEGORIES).map(([categoryKey, category]) => {
const stats = getCategoryStats(categoryKey);
const hasUsage = stats.count > 0;
return (
}
sx={{
minHeight: 48,
'&.Mui-expanded': { minHeight: 48 }
}}
>
{category.icon}
{category.title}
{category.description}
{hasUsage && (
${stats.totalCost.toFixed(4)}
)}
{category.apis.map((api) => {
const providerData = activeProviders.find(p =>
p.provider.toLowerCase() === api.name.toLowerCase()
);
return (
{api.name}
{providerData && (
)}
{api.description}
Current Pricing
{loadingPricing
? 'Loading...'
: pricingError
? `Using fallback pricing. Error: ${pricingError}`
: 'Real-time pricing from API'
}
{!loadingPricing && !pricingError && (
Last updated: {pricing.find(p =>
p.provider.toLowerCase() === api.name.toLowerCase()
)?.effective_date || 'N/A'}
)}
}
arrow
placement="top"
>
Pricing: {getPricingDisplay(api.name, api.pricing)}
{!loadingPricing && !pricingError && ' ✓'}
{pricingError && ' (static)'}
{providerData && (
Cost
${(providerData.cost ?? 0).toFixed(4)}
Calls
{providerData.calls ?? 0}
Tokens
{(providerData.tokens ?? 0).toLocaleString()}
)}
Use cases: {api.use_cases.join(', ')}
);
})}
);
})}
);
};
export default ComprehensiveAPIBreakdown;