15 KiB
Pre-flight Check with Cost Estimation and Button Enhancement Plan
Overview
Implement a reusable pre-flight check system that shows estimated costs on buttons and validates operations on hover. This will provide users with cost transparency and prevent unnecessary API calls by showing if operations are allowed before execution.
Goals
- Show estimated cost on buttons (e.g., "Generate HD Video $0.21")
- Perform pre-flight check on hover (debounced to avoid performance issues)
- Show detailed information (allowed/blocked, limits, remaining quota)
- Disable buttons with appropriate messaging if limits exceeded
- Common/reusable solution across all ALwrity tools (blog writer, story, linkedin, etc.)
- Performance optimized (caching, debouncing, batching)
- Foundation for billing dashboard insights about operation costs
Current State Analysis
Backend Existing Capabilities
- Pre-flight validation:
preflight_validator.pyhas functions likevalidate_video_generation_operations,validate_image_generation_operations - Limit checking:
pricing_service.pyhascheck_comprehensive_limits()andcheck_usage_limits() - Pricing lookup:
get_pricing_for_provider_model()returns cost information - Caching:
_limits_cachewith TTL to reduce DB reads - Operation validation: Supports multi-operation workflows with token estimation
Frontend Existing Capabilities
- Billing service:
billingService.tshas API client for subscription endpoints - Subscription hooks:
useSubscriptionGuard,useSubscriptionfor subscription state - Button components: Various buttons but no cost/pre-flight integration
- Usage dashboard: Shows usage but not per-operation costs
Gaps
- No lightweight endpoint for cost estimation + pre-flight check
- No reusable button component with cost/pre-flight integration
- No debouncing/throttling for hover-based checks
- No consistent UX pattern across tools
Implementation Plan
Phase 1: Backend API Endpoint
1.1 Create Pre-flight Check Endpoint
File: backend/api/subscription_api.py
Endpoint: POST /api/subscription/preflight-check
Purpose: Lightweight endpoint that:
- Accepts operation definition (provider, model, tokens_estimated, operation_type)
- Returns cost estimation, limits check result, usage info
- Uses caching to minimize DB load
- Fast response (< 100ms with cache hit)
Request Format:
{
"operations": [
{
"provider": "video",
"model": "tencent/HunyuanVideo",
"tokens_requested": 0,
"operation_type": "video_generation",
"actual_provider_name": "huggingface"
}
]
}
Response Format:
{
"success": true,
"data": {
"can_proceed": true,
"estimated_cost": 0.21,
"operations": [
{
"provider": "video",
"operation_type": "video_generation",
"cost": 0.21,
"allowed": true,
"limit_info": {
"current_usage": 5,
"limit": 100,
"remaining": 95
},
"message": null
}
],
"total_cost": 0.21,
"usage_summary": {
"current_calls": 5,
"limit": 100,
"remaining": 95
},
"cached": false
}
}
Implementation Details:
- Use
PricingService.check_comprehensive_limits()for validation - Use
PricingService.get_pricing_for_provider_model()for cost - Leverage existing
_limits_cache(5-second TTL) - Return structured error if blocked with user-friendly message
1.2 Batch Pre-flight Check Endpoint (Optional, for performance)
Endpoint: POST /api/subscription/preflight-check-batch
Purpose: Check multiple operations at once for pages with many buttons
Performance Considerations:
- Single DB query for all operations
- Batch cache lookups
- Return results in order matching request
Phase 2: Frontend Service Layer
2.1 Extend Billing Service
File: frontend/src/services/billingService.ts
New Functions:
interface PreflightOperation {
provider: string;
model?: string;
tokens_requested?: number;
operation_type: string;
actual_provider_name?: string;
}
interface PreflightCheckResponse {
can_proceed: boolean;
estimated_cost: number;
operations: Array<{
provider: string;
operation_type: string;
cost: number;
allowed: boolean;
limit_info: {
current_usage: number;
limit: number;
remaining: number;
};
message: string | null;
}>;
total_cost: number;
usage_summary: {
current_calls: number;
limit: number;
remaining: number;
};
cached: boolean;
}
// Single operation check
export const checkPreflight = async (
operation: PreflightOperation
): Promise<PreflightCheckResponse>
// Batch operations check (for pages with many buttons)
export const checkPreflightBatch = async (
operations: PreflightOperation[]
): Promise<PreflightCheckResponse>
Implementation Details:
- Use axios with request cancellation support
- Add request debouncing wrapper
- Handle errors gracefully (show cached result if available)
- Return structured error messages for UI display
2.2 Create Pre-flight Check Hook
File: frontend/src/hooks/usePreflightCheck.ts
Purpose: Reusable React hook that:
- Manages pre-flight check state (loading, error, result)
- Debounces hover events (300ms delay)
- Caches results per operation (5-second TTL)
- Provides easy-to-use API for components
API:
interface UsePreflightCheckOptions {
operation: PreflightOperation;
enabled?: boolean; // Whether to perform check on hover
debounceMs?: number; // Debounce delay (default: 300ms)
cacheTtl?: number; // Cache TTL in ms (default: 5000ms)
}
interface UsePreflightCheckResult {
canProceed: boolean;
estimatedCost: number;
limitInfo: {
current: number;
limit: number;
remaining: number;
} | null;
loading: boolean;
error: string | null;
checkOnHover: () => void;
checkNow: () => void; // Immediate check
reset: () => void;
}
export const usePreflightCheck = (
options: UsePreflightCheckOptions
): UsePreflightCheckResult
Implementation Details:
- Use
useStatefor state management - Use
useCallbackfor memoized handlers - Use
useReffor debounce timers and cache - Implement request cancellation on unmount
Phase 3: Reusable Button Component
3.1 Create Enhanced Operation Button Component
File: frontend/src/components/shared/OperationButton.tsx
Purpose: Reusable button component that:
- Shows estimated cost in button label
- Performs pre-flight check on hover
- Shows detailed tooltip with limits/remaining quota
- Disables button with messaging if blocked
- Supports all operation types (video, image, image_edit, text generation, etc.)
Props:
interface OperationButtonProps {
// Operation definition
operation: PreflightOperation;
// Button configuration
label: string; // Base label (e.g., "Generate HD Video")
variant?: 'contained' | 'outlined' | 'text';
size?: 'small' | 'medium' | 'large';
color?: 'primary' | 'secondary' | 'success' | 'error';
startIcon?: React.ReactNode;
endIcon?: React.ReactNode;
// Pre-flight check behavior
showCost?: boolean; // Show cost in label (default: true)
checkOnHover?: boolean; // Check on hover (default: true)
checkOnMount?: boolean; // Check on mount (default: false)
// Callbacks
onClick: () => void;
onPreflightResult?: (result: PreflightCheckResponse) => void;
// Customization
disabled?: boolean; // Additional disabled state
loading?: boolean; // Loading state override
tooltipPlacement?: 'top' | 'bottom' | 'left' | 'right';
// Styling
sx?: SxProps<Theme>;
fullWidth?: boolean;
}
Features:
- Cost display: "Generate HD Video $0.21" or "Generate HD Video" if cost unavailable
- Tooltip on hover shows:
- Operation allowed/blocked status
- Current usage / limit / remaining
- Estimated cost breakdown
- Message if blocked (e.g., "You've reached your video generation limit. Upgrade your plan for more videos.")
- Button disabled if:
disabledprop is trueloadingprop is true- Pre-flight check returned
can_proceed: false
- Button styling:
- Normal: standard button
- Blocked: grayed out with warning icon
- Loading: spinner with disabled state
Implementation Details:
- Use Material-UI
ButtonandTooltipcomponents - Integrate with
usePreflightCheckhook - Format cost as currency (e.g., "$0.21" or "$0.00" if free)
- Handle edge cases (no subscription, no limits, etc.)
3.2 Create Operation Type Mappings
File: frontend/src/utils/operationTypes.ts
Purpose: Centralized configuration for operation types:
- Default models per operation type
- Display names
- Icons
- Default token estimates
export const OPERATION_TYPES = {
video_generation: {
provider: 'video',
defaultModel: 'tencent/HunyuanVideo',
displayName: 'Video Generation',
icon: VideoLibraryIcon,
defaultTokens: 0,
},
image_generation: {
provider: 'stability',
defaultModel: 'stability-ai/stable-diffusion-xl',
displayName: 'Image Generation',
icon: ImageIcon,
defaultTokens: 0,
},
image_editing: {
provider: 'image_edit',
defaultModel: 'Qwen/Qwen-Image-Edit',
displayName: 'Image Editing',
icon: EditIcon,
defaultTokens: 0,
},
// ... more operation types
} as const;
Phase 4: Integration Across Tools
4.1 Story Writer Integration
Files:
frontend/src/components/StoryWriter/components/HdVideoSection.tsxfrontend/src/components/StoryWriter/components/VideoSection.tsxfrontend/src/components/StoryWriter/components/MultimediaToolbar.tsx
Changes:
- Replace existing buttons with
OperationButton - Configure with appropriate operation type
- Pass existing
onClickhandlers
Example:
<OperationButton
operation={{
provider: 'video',
model: 'tencent/HunyuanVideo',
tokens_requested: 0,
operation_type: 'video_generation',
actual_provider_name: 'huggingface',
}}
label="Generate HD Animation"
showCost={true}
checkOnHover={true}
onClick={handleGenerateHdVideo}
disabled={isGeneratingHdVideo || state.hdVideoGenerationStatus === 'awaiting_approval'}
loading={isGeneratingHdVideo}
/>
4.2 Blog Writer Integration
Files: Various blog writer components with generation buttons
Changes: Similar to Story Writer - replace buttons with OperationButton
4.3 LinkedIn Writer Integration
Files: LinkedIn writer components
Changes: Similar pattern
Phase 5: Performance Optimization
5.1 Caching Strategy
Backend:
- Use existing
_limits_cache(5-second TTL) - Cache pre-flight check results per user:operation combination
- Invalidate cache on usage updates
Frontend:
- In-memory cache per hook instance (5-second TTL)
- Share cache across components using React Context
- Clear cache on subscription changes
5.2 Debouncing/Throttling
Frontend:
- Debounce hover events (300ms delay)
- Throttle batch requests (max 1 request per 500ms)
- Cancel in-flight requests on unmount/hover exit
5.3 Request Batching
Frontend:
- For pages with many buttons (e.g., story export with multiple operations)
- Batch multiple operations into single request
- Use
checkPreflightBatchAPI
5.4 Lazy Loading
Frontend:
- Only check on hover (not on mount)
- Optional: Check on mount for primary buttons only
- Defer checks for secondary/tertiary buttons
Phase 6: Billing Dashboard Integration (Future)
6.1 Operation Cost Tracking
Backend:
- Track operation costs in
APIUsageLog(already exists) - Add operation_type field to logs (already exists)
6.2 Cost Insights
Frontend:
- Add operation cost breakdown to billing dashboard
- Show most expensive operations
- Show cost trends per operation type
- Add filters by operation type
Performance Considerations
Potential Bottlenecks
-
Many buttons on one page: Each button hovering could trigger requests
- Solution: Batch requests, debounce, cache aggressively
-
Rapid hover in/out: Multiple requests for same operation
- Solution: Debounce (300ms), cancel in-flight requests
-
Backend DB load: Each check queries subscription/usage tables
- Solution: Use existing cache (5-second TTL), optimize queries
-
Frontend render performance: Many tooltips updating
- Solution: Virtualize if needed, optimize re-renders with React.memo
Performance Targets
- Pre-flight check API: < 100ms with cache hit, < 300ms without cache
- Frontend hover response: < 50ms (debounced)
- Batch check (10 operations): < 500ms
- Tooltip render: < 16ms (60fps)
Testing Strategy
Unit Tests
usePreflightCheckhook: debouncing, caching, error handlingOperationButtoncomponent: cost display, tooltip, disabled states- Billing service: API calls, error handling
Integration Tests
- Pre-flight check endpoint: validation, cost calculation, caching
- Button hover behavior: tooltip display, disabled states
E2E Tests
- User hovers over button, sees cost and limits
- User blocked by limits, sees appropriate messaging
- User clicks button, operation executes (or fails with clear error)
Migration Strategy
Phase 1: Backend (Week 1)
- Create pre-flight check endpoint
- Add unit tests
- Deploy and monitor performance
Phase 2: Frontend Core (Week 2)
- Extend billing service
- Create
usePreflightCheckhook - Create
OperationButtoncomponent - Add unit tests
Phase 3: Integration (Week 3)
- Integrate into Story Writer (highest priority - most buttons)
- Test thoroughly
- Iterate based on feedback
Phase 4: Rollout (Week 4+)
- Integrate into Blog Writer
- Integrate into LinkedIn Writer
- Integrate into other tools
- Monitor performance and user feedback
Success Metrics
-
User Experience:
- Reduced confusion about operation costs
- Fewer failed operations due to limits
- Increased clarity about remaining quota
-
Performance:
- < 100ms API response time (with cache)
- < 1% increase in backend DB load
- No noticeable UI lag on pages with many buttons
-
Adoption:
- All major operation buttons using new component
- Consistent UX across all tools
Future Enhancements
- Cost estimation for multi-operation workflows: Estimate total cost for complex operations
- Usage predictions: Show projected usage if user continues current pattern
- Cost optimization suggestions: Suggest cheaper alternatives
- Batch operation approval: Show total cost and allow approval for multiple operations
- Cost alerts: Warn users approaching cost limits
- Operation history: Show recent operations and their costs in tooltip