Skip to content

Commit 901bca5

Browse files
committed
basic cost calculator
1 parent 97337c8 commit 901bca5

File tree

2 files changed

+81
-22
lines changed

2 files changed

+81
-22
lines changed

dashboard/ai-analytics/src/app/api/extract-cost-parameters/route.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,11 +68,21 @@ export async function POST(req: Request) {
6868
If a parameter is not specified in the query, omit it from your response.
6969
Always include start_date and end_date based on the timeframe (default to "last month" if not specified).
7070
71+
Context-based filter extraction rules:
72+
1. When a model name is mentioned (e.g., "gpt-4", "claude-3-opus"), set model filter to that value
73+
2. When a provider name is mentioned (e.g., "OpenAI", "Anthropic"), set provider filter to that value.
74+
3. When an environment is mentioned (e.g., "production", "staging", "development"), set environment filter
75+
4. When a project or organization name is mentioned, set the appropriate filter
76+
5. When a username is mentioned, set the user filter
77+
6. Never use a model name as a provider name and vice-versa, model=anthropic is invalid, provider=anthropic is valid.
78+
7179
Look for phrases like "filter by", "for", "in", "with", etc. to identify filter parameters.
7280
Examples:
7381
- "Show costs for organization quantum_systems" → organization: "quantum_systems"
7482
- "Predict costs for OpenAI models in production" → provider: "OpenAI", environment: "production"
7583
- "What if we switch to Claude with a 10% discount for the chatbot project" → model: "Claude", discount: 10, project: "chatbot"
84+
- "How much would GPT-4 cost us next month?" → model: "gpt-4"
85+
- "Compare Anthropic models with OpenAI" → provider: "Anthropic" (for the primary analysis)
7686
`;
7787

7888
const result = await generateObject({

dashboard/ai-analytics/src/app/components/CostPredictionModal.tsx

Lines changed: 71 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,11 @@ export default function CostPredictionModal({
9292

9393
// Example queries that users can select
9494
const exampleQueries = [
95-
"What if we switch to Claude 3 Sonnet with a 10% volume increase?",
96-
"Predict costs if we get a 15% discount on GPT-4 for the next month",
97-
"How would costs change if we use Claude 3 Opus at $0.00003 per prompt token and $0.00015 per completion token?",
98-
"What if our usage increases by 25% next month?",
99-
"Compare current costs with GPT-4 for the last week",
100-
"Show me cost predictions grouped by provider for last month",
101-
"What would be our costs grouped by project if we switch to GPT-4?",
95+
"Show me cost predictions for Anthropic models grouped by project",
96+
"What would be our costs in production environment if we switch to GPT-4?",
10297
"Filter by organization quantum_systems and show costs for last 3 months",
103-
"Predict costs for provider OpenAI in production environment",
104-
"What if we increase usage by 20% for the chatbot project?"
98+
"Cost for OpenAI models in production environment in last month",
99+
"How would costs change if we use Claude 3 Opus at $0.00003 per prompt token and $0.00015 per completion token?"
105100
];
106101

107102
// Add debugging for token
@@ -175,9 +170,19 @@ export default function CostPredictionModal({
175170
filters.model = normalizeModelName(parameters.model);
176171
}
177172

173+
// Add provider filter if specified
174+
if (parameters.provider) {
175+
filters.provider = normalizeProviderName(parameters.provider);
176+
}
177+
178+
// Add environment filter if specified
179+
if (parameters.environment) {
180+
filters.environment = normalizeEnvironmentName(parameters.environment);
181+
}
182+
178183
// Add other filter parameters if specified
179-
const filterParams = ['organization', 'project', 'environment', 'provider', 'user'];
180-
filterParams.forEach(param => {
184+
const otherFilterParams = ['organization', 'project', 'user'];
185+
otherFilterParams.forEach(param => {
181186
const value = parameters[param as keyof CostParameters];
182187
if (value) {
183188
filters[param] = value as string;
@@ -312,8 +317,8 @@ export default function CostPredictionModal({
312317
console.log("Generated sample data:", processedData);
313318
}
314319

315-
// Check if we're grouping by a dimension
316-
const isGrouped = !!params.group_by && params.group_by !== 'model';
320+
// Check if we're grouping by any dimension (including model)
321+
const isGrouped = !!params.group_by;
317322

318323
if (isGrouped) {
319324
// Handle grouped data visualization
@@ -425,6 +430,12 @@ export default function CostPredictionModal({
425430
// Group data by date
426431
const dateMap = new Map<string, DateAggregatedData>();
427432

433+
// Get cost parameters
434+
const promptCost = params.promptTokenCost ?? getDefaultPromptCost(params.model);
435+
const completionCost = params.completionTokenCost ?? getDefaultCompletionCost(params.model);
436+
const discount = params.discount / 100; // Convert percentage to decimal
437+
const volumeMultiplier = 1 + (params.volumeChange / 100); // Define volumeMultiplier here
438+
428439
// Log the structure of the first item to understand the data format
429440
if (data.length > 0) {
430441
console.log("Sample data item:", data[0]);
@@ -634,6 +645,40 @@ export default function CostPredictionModal({
634645
return normalized;
635646
};
636647

648+
// Add a function to normalize provider names
649+
const normalizeProviderName = (providerName: string | null): string | null => {
650+
if (!providerName) return null;
651+
652+
// Convert to lowercase
653+
const normalized = providerName.toLowerCase();
654+
655+
// Map common variations to standard names
656+
if (normalized.includes('openai')) return 'openai';
657+
if (normalized.includes('anthropic')) return 'anthropic';
658+
if (normalized.includes('cohere')) return 'cohere';
659+
if (normalized.includes('mistral')) return 'mistral';
660+
if (normalized.includes('google')) return 'google';
661+
if (normalized.includes('meta')) return 'meta';
662+
663+
return normalized;
664+
};
665+
666+
// Add a function to normalize environment names
667+
const normalizeEnvironmentName = (envName: string | null): string | null => {
668+
if (!envName) return null;
669+
670+
// Convert to lowercase
671+
const normalized = envName.toLowerCase();
672+
673+
// Map common variations to standard names
674+
if (normalized.includes('prod')) return 'production';
675+
if (normalized.includes('dev')) return 'development';
676+
if (normalized.includes('stag')) return 'staging';
677+
if (normalized.includes('test')) return 'testing';
678+
679+
return normalized;
680+
};
681+
637682
return (
638683
<>
639684
{isOpen && (
@@ -651,7 +696,7 @@ export default function CostPredictionModal({
651696
<div className="flex items-center justify-between p-4 border-b border-gray-800">
652697
<div className="flex items-center space-x-2">
653698
<Calculator className="h-5 w-5 text-blue-400" />
654-
<h2 className="text-lg font-medium text-white">Cost Prediction</h2>
699+
<h2 className="text-lg font-medium text-white">Cost Calculator</h2>
655700
</div>
656701
<button
657702
onClick={onClose}
@@ -731,7 +776,7 @@ export default function CostPredictionModal({
731776
: 'bg-blue-600 text-white hover:bg-blue-700'
732777
}`}
733778
>
734-
{isLoading ? 'Calculating...' : 'Calculate Prediction'}
779+
{isLoading ? 'Calculating...' : 'Calculate Cost'}
735780
</button>
736781
</form>
737782

@@ -740,17 +785,17 @@ export default function CostPredictionModal({
740785
<div className="mt-6 space-y-4">
741786
{/* Summary cards */}
742787
<div className="grid grid-cols-3 gap-4">
743-
<div className="bg-gray-800 rounded-lg p-4">
788+
{/* <div className="bg-gray-800 rounded-lg p-4">
744789
<div className="text-sm text-gray-400 mb-1">Current Cost</div>
745790
<div className="text-xl font-semibold text-white">${summary.actualTotal.toFixed(2)}</div>
746-
</div>
791+
</div> */}
747792

748-
<div className="bg-gray-800 rounded-lg p-4">
793+
{/* <div className="bg-gray-800 rounded-lg p-4">
749794
<div className="text-sm text-gray-400 mb-1">Predicted Cost</div>
750795
<div className="text-xl font-semibold text-white">${summary.predictedTotal.toFixed(2)}</div>
751-
</div>
796+
</div> */}
752797

753-
<div className={`rounded-lg p-4 ${
798+
{/* <div className={`rounded-lg p-4 ${
754799
summary.difference > 0 ? 'bg-red-900/50' : 'bg-green-900/50'
755800
}`}>
756801
<div className="text-sm text-gray-300 mb-1">Difference</div>
@@ -761,15 +806,19 @@ export default function CostPredictionModal({
761806
{summary.difference > 0 ? '+' : ''}
762807
{summary.percentChange.toFixed(1)}%
763808
</div>
764-
</div>
809+
</div> */}
765810
</div>
766811

767812
{/* Parameters and chart */}
768813
<div className="space-y-4">
769814
{/* Parameters */}
770815
{parameters && (
771816
<div className="bg-gray-800 rounded-lg p-4">
772-
<h4 className="text-sm font-medium text-gray-300 mb-2">Prediction Parameters</h4>
817+
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
818+
<h2 className="text-lg font-medium text-gray-300 mb-2">Cost</h2>
819+
<div className="text-xl font-semibold text-white">${summary.actualTotal.toFixed(2)}</div>
820+
</div>
821+
<h4 className="text-sm font-medium text-gray-300 mb-2">Parameters</h4>
773822
<div className="grid grid-cols-2 gap-x-4 gap-y-2 text-sm">
774823
<div className="text-gray-400">Model</div>
775824
<div className="text-white">{parameters.model || 'Current models'}</div>

0 commit comments

Comments
 (0)