Files
ALwrity/frontend/src/components/ImageStudio/CreateStudioCostAlerts.tsx
ajaysi 45bd1eada9 fix(01-code-splitting): convert ImageStudio, Landing, LinkedIn, MainDashboard, OnboardingWizard MUI icons
- Converted barrel imports to individual imports across 14 files
- Most complex: VoiceAvatarPlaceholder (22 icons), FeatureShowcase (8), TestPersonaModal (9)
2026-05-14 09:11:51 +05:30

313 lines
10 KiB
TypeScript

/**
* Image Studio Cost Alerts Integration
*
* Example integration of Priority 2 alerts (cost estimation, OSS recommendations)
* into the Image Studio Create Studio component.
*/
import React, { useEffect, useState } from 'react';
import { Box, Alert, AlertTitle, Button, Collapse, Chip, Stack, Typography } from '@mui/material';
import { usePriority2Alerts, useCostEstimationAlert } from '../../hooks/usePriority2Alerts';
import Priority2AlertBanner from '../shared/Priority2AlertBanner';
import { useSubscription } from '../../contexts/SubscriptionContext';
import { checkPreflight, PreflightOperation } from '../../services/billingService';
import { showToastNotification } from '../../utils/toastNotifications';
import AttachMoney from '@mui/icons-material/AttachMoney';
import Lightbulb from '@mui/icons-material/Lightbulb';
import TrendingUp from '@mui/icons-material/TrendingUp';
interface CreateStudioCostAlertsProps {
userId?: string;
provider?: string;
model?: string;
numVariations?: number;
onGenerate?: () => void;
}
/**
* Image Studio Cost Alerts Component
*
* Displays Priority 2 alerts and provides cost estimation before image generation.
* Shows OSS model recommendations and cost comparisons.
*/
export const CreateStudioCostAlerts: React.FC<CreateStudioCostAlertsProps> = ({
userId,
provider = 'auto',
model,
numVariations = 1,
onGenerate,
}) => {
const { subscription } = useSubscription();
const { alerts, refreshAlerts, dismissAlert } = usePriority2Alerts({
userId,
enabled: !!userId && subscription?.active,
checkInterval: 120000,
});
const { showEstimationAlert } = useCostEstimationAlert();
const [estimatedCost, setEstimatedCost] = useState<number | null>(null);
const [ossRecommendation, setOssRecommendation] = useState<{
model: string;
savings: number;
currentCost: number;
} | null>(null);
// Estimate cost for image generation
useEffect(() => {
const estimateCost = async () => {
if (!userId || provider === 'auto') return;
try {
// Determine actual provider (default to wavespeed for OSS)
const actualProvider = provider === 'wavespeed' ? 'stability' : provider;
const actualModel = model || (provider === 'wavespeed' ? 'qwen-image' : 'stable-diffusion');
const operations: PreflightOperation[] = Array(numVariations).fill(null).map(() => ({
provider: actualProvider,
model: actualModel,
operation_type: 'image_generation',
tokens_requested: 0,
}));
if (operations.length > 0) {
const preflightResult = await checkPreflight(operations[0]);
const cost = (preflightResult.estimated_cost || 0) * numVariations;
setEstimatedCost(cost);
// Check if OSS alternative would be cheaper
if (provider !== 'wavespeed' && actualProvider === 'stability') {
// Compare with OSS model
const ossOperation: PreflightOperation = {
provider: 'stability',
model: 'qwen-image',
operation_type: 'image_generation',
tokens_requested: 0,
};
const ossResult = await checkPreflight(ossOperation);
const ossCost = (ossResult.estimated_cost || 0) * numVariations;
if (ossCost < cost) {
setOssRecommendation({
model: 'Qwen Image (OSS)',
savings: cost - ossCost,
currentCost: cost,
});
}
}
}
} catch (error) {
console.error('[CreateStudioCostAlerts] Error estimating cost:', error);
}
};
estimateCost();
}, [userId, provider, model, numVariations]);
const handleGenerateWithEstimation = async () => {
if (!estimatedCost || estimatedCost < 0.01) {
// Low cost - proceed directly
if (onGenerate) onGenerate();
return;
}
showEstimationAlert(
estimatedCost,
`image generation (${numVariations} image${numVariations > 1 ? 's' : ''})`,
() => {
if (onGenerate) onGenerate();
},
() => {
showToastNotification('Image generation cancelled', 'info');
}
);
};
// Filter alerts relevant to Image Studio
const imageStudioAlerts = alerts.filter(alert =>
alert.type === 'oss_recommendation' ||
alert.type === 'cost_trend' ||
(alert.type === 'cost_estimation' && alert.message.includes('image'))
);
// Get OSS model cost info
const getModelCost = (modelName: string): number => {
const costs: Record<string, number> = {
'qwen-image': 0.03,
'ideogram-v3-turbo': 0.05,
'stable-diffusion': 0.04,
'stability-ultra': 0.08,
'stability-core': 0.03,
};
return costs[modelName] || 0.04;
};
const currentModelCost = model ? getModelCost(model) : 0.03; // Default to OSS
const totalEstimatedCost = currentModelCost * numVariations;
return (
<Box sx={{ mb: 2 }}>
{/* Priority 2 Alert Banner */}
{imageStudioAlerts.length > 0 && (
<Priority2AlertBanner
alerts={imageStudioAlerts}
onDismiss={dismissAlert}
maxAlerts={2}
/>
)}
{/* Cost Estimation Display */}
<Collapse in={true}>
<Alert
severity="info"
icon={<AttachMoney />}
sx={{
mb: 2,
backgroundColor: 'rgba(59, 130, 246, 0.1)',
border: '1px solid rgba(59, 130, 246, 0.2)',
}}
>
<AlertTitle sx={{ fontWeight: 'bold', mb: 0.5, display: 'flex', alignItems: 'center', gap: 1 }}>
<AttachMoney sx={{ fontSize: 18 }} />
Estimated Cost
</AlertTitle>
<Stack spacing={1}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' }}>
<Typography variant="body2">
<strong>{numVariations} image{numVariations > 1 ? 's' : ''}</strong> using{' '}
<strong>{model || (provider === 'wavespeed' ? 'Qwen Image (OSS)' : 'Default')}</strong>:
</Typography>
<Chip
label={`$${totalEstimatedCost.toFixed(4)}`}
color="primary"
size="small"
sx={{ fontWeight: 'bold' }}
/>
</Box>
{/* OSS Recommendation */}
{ossRecommendation && (
<Box sx={{
mt: 1,
p: 1.5,
backgroundColor: 'rgba(251, 191, 36, 0.1)',
borderRadius: 1,
border: '1px solid rgba(251, 191, 36, 0.3)',
}}>
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1, mb: 0.5 }}>
<Lightbulb sx={{ fontSize: 18, color: '#f59e0b' }} />
<Typography variant="body2" sx={{ fontWeight: 'bold' }}>
💡 Cost Savings Opportunity
</Typography>
</Box>
<Typography variant="body2" sx={{ mb: 1 }}>
Switch to <strong>{ossRecommendation.model}</strong> to save{' '}
<strong>${ossRecommendation.savings.toFixed(4)}</strong> per generation
({((ossRecommendation.savings / ossRecommendation.currentCost) * 100).toFixed(0)}% savings).
</Typography>
<Button
size="small"
variant="outlined"
onClick={() => {
showToastNotification(
'OSS models are automatically used as defaults in Basic tier',
'info'
);
}}
sx={{ textTransform: 'none' }}
>
Learn More About OSS Models
</Button>
</Box>
)}
{/* Cost Breakdown */}
<Box sx={{ mt: 1, fontSize: '0.75rem', color: 'text.secondary' }}>
<Typography variant="caption">
Cost per image: ${currentModelCost.toFixed(4)} Total: ${totalEstimatedCost.toFixed(4)}
{subscription?.tier === 'basic' && ' (Basic tier uses OSS models by default)'}
</Typography>
</Box>
</Stack>
</Alert>
</Collapse>
{/* Generate Button with Cost Awareness */}
{onGenerate && (
<Button
variant="contained"
color="primary"
fullWidth
onClick={handleGenerateWithEstimation}
startIcon={<AttachMoney />}
sx={{ mt: 1 }}
>
Generate {numVariations} Image{numVariations > 1 ? 's' : ''}
{estimatedCost && estimatedCost > 0 && (
<Chip
label={`$${estimatedCost.toFixed(4)}`}
size="small"
sx={{ ml: 1, height: 20, fontSize: '0.7rem' }}
/>
)}
</Button>
)}
</Box>
);
};
/**
* Hook for Image Studio cost estimation
* Use this in Image Studio components before triggering image generation
*/
export const useImageStudioCostEstimation = () => {
const { showEstimationAlert } = useCostEstimationAlert();
const estimateAndGenerate = async (
provider: string,
model: string,
numVariations: number,
onGenerate: () => void,
userId?: string
) => {
if (!userId) {
onGenerate();
return;
}
try {
const actualProvider = provider === 'wavespeed' ? 'stability' : provider;
const operations: PreflightOperation[] = Array(numVariations).fill(null).map(() => ({
provider: actualProvider,
model: model || (provider === 'wavespeed' ? 'qwen-image' : 'stable-diffusion'),
operation_type: 'image_generation',
tokens_requested: 0,
}));
if (operations.length > 0) {
const preflightResult = await checkPreflight(operations[0]);
const estimatedCost = (preflightResult.estimated_cost || 0) * numVariations;
if (estimatedCost > 0.01) {
showEstimationAlert(
estimatedCost,
`image generation (${numVariations} image${numVariations > 1 ? 's' : ''})`,
onGenerate,
() => showToastNotification('Image generation cancelled', 'info')
);
} else {
onGenerate();
}
} else {
onGenerate();
}
} catch (error) {
console.error('[ImageStudioCostEstimation] Error:', error);
onGenerate();
}
};
return { estimateAndGenerate };
};
export default CreateStudioCostAlerts;