@hhoangphuoc/escape-room-cli
Version:
A CLI for playing AI-generated escape room games. Install globally with: npm install -g @hhoangphuoc/escape-room-cli
267 lines (266 loc) • 10.4 kB
JavaScript
"use strict";
// // escape-room-cli/source/components/UsageDashboard.tsx
Object.defineProperty(exports, "__esModule", { value: true });
// import React, { useState, useEffect } from 'react';
// import { Box, Text, Spacer } from 'ink';
// import { useAuth } from '../context/AuthContext.js';
// interface UserUsageMetrics {
// userId: string;
// totalRequests: number;
// totalInputTokens: number;
// totalOutputTokens: number;
// totalTokens: number;
// totalCost: number;
// costByModel: Record<string, {
// requests: number;
// inputTokens: number;
// outputTokens: number;
// totalCost: number;
// }>;
// firstRequest: string;
// lastRequest: string;
// }
// interface GameSessionMetrics {
// gameId: string;
// userId: string;
// gameMode: string;
// totalRequests: number;
// totalInputTokens: number;
// totalOutputTokens: number;
// totalTokens: number;
// totalCost: number;
// startTime: string;
// endTime?: string;
// }
// interface PricingInfo {
// models: Record<string, { input: number; output: number; }>;
// lastUpdated: string;
// currency: string;
// unit: string;
// }
// export const UsageDashboard: React.FC = () => {
// const { apiCall } = useAuth();
// const [userMetrics, setUserMetrics] = useState<UserUsageMetrics | null>(null);
// const [pricingInfo, setPricingInfo] = useState<PricingInfo | null>(null);
// const [loading, setLoading] = useState(true);
// const [error, setError] = useState<string | null>(null);
// const [activeTab, setActiveTab] = useState<'overview' | 'models' | 'pricing'>('overview');
// useEffect(() => {
// const fetchData = async () => {
// try {
// setLoading(true);
// // Fetch user metrics
// const userResponse = await apiCall('/api/usage/user');
// if (userResponse.success) {
// setUserMetrics(userResponse.data);
// }
// // Fetch pricing info
// const pricingResponse = await apiCall('/api/usage/pricing');
// if (pricingResponse.success) {
// setPricingInfo(pricingResponse.data);
// }
// setError(null);
// } catch (err) {
// setError(err instanceof Error ? err.message : 'Failed to load usage data');
// } finally {
// setLoading(false);
// }
// };
// fetchData();
// }, []);
// const formatCost = (cost: number): string => {
// return cost < 0.01 ? `$${cost.toFixed(5)}` : `$${cost.toFixed(3)}`;
// };
// const formatTokens = (tokens: number): string => {
// return tokens.toLocaleString();
// };
// const formatDate = (dateString: string): string => {
// return new Date(dateString).toLocaleDateString();
// };
// if (loading) {
// return (
// <Box justifyContent="center">
// <Text color="blue">Loading usage dashboard...</Text>
// </Box>
// );
// }
// if (error) {
// return (
// <Box justifyContent="center">
// <Text color="red">Error: {error}</Text>
// </Box>
// );
// }
// return (
// <Box flexDirection="column" padding={1}>
// {/* Header */}
// <Box borderStyle="double" borderColor="cyan" padding={1}>
// <Text color="cyan" bold>AI Usage Dashboard</Text>
// <Spacer />
// <Text color="gray">User ID: {userMetrics?.userId || 'Unknown'}</Text>
// </Box>
// {/* Tab Navigation */}
// <Box marginTop={1}>
// <Box marginRight={2}>
// <Text color={activeTab === 'overview' ? 'cyan' : 'gray'} bold={activeTab === 'overview'}>
// [1] Overview
// </Text>
// </Box>
// <Box marginRight={2}>
// <Text color={activeTab === 'models' ? 'cyan' : 'gray'} bold={activeTab === 'models'}>
// [2] Models
// </Text>
// </Box>
// <Box>
// <Text color={activeTab === 'pricing' ? 'cyan' : 'gray'} bold={activeTab === 'pricing'}>
// [3] Pricing
// </Text>
// </Box>
// </Box>
// {/* Content */}
// <Box marginTop={1} flexDirection="column">
// {activeTab === 'overview' && userMetrics && (
// <OverviewTab userMetrics={userMetrics} formatCost={formatCost} formatTokens={formatTokens} formatDate={formatDate} />
// )}
// {activeTab === 'models' && userMetrics && (
// <ModelsTab userMetrics={userMetrics} formatCost={formatCost} formatTokens={formatTokens} />
// )}
// {activeTab === 'pricing' && pricingInfo && (
// <PricingTab pricingInfo={pricingInfo} formatCost={formatCost} />
// )}
// </Box>
// {/* Footer */}
// <Box marginTop={2} borderStyle="single" borderColor="gray" padding={1}>
// <Text color="gray">
// Use number keys (1-3) to switch tabs. Press 'q' to return to game.
// </Text>
// </Box>
// </Box>
// );
// };
// const OverviewTab: React.FC<{
// userMetrics: UserUsageMetrics;
// formatCost: (cost: number) => string;
// formatTokens: (tokens: number) => string;
// formatDate: (date: string) => string;
// }> = ({ userMetrics, formatCost, formatTokens, formatDate }) => (
// <Box flexDirection="column">
// {/* Summary Stats */}
// <Box borderStyle="single" borderColor="green" padding={1}>
// <Box flexDirection="column" width="50%">
// <Text color="green" bold>Total Usage</Text>
// <Text>Requests: {userMetrics.totalRequests}</Text>
// <Text>Cost: {formatCost(userMetrics.totalCost)}</Text>
// <Text>Tokens: {formatTokens(userMetrics.totalTokens)}</Text>
// </Box>
// <Box flexDirection="column" width="50%">
// <Text color="yellow" bold>Token Breakdown</Text>
// <Text>Input: {formatTokens(userMetrics.totalInputTokens)}</Text>
// <Text>Output: {formatTokens(userMetrics.totalOutputTokens)}</Text>
// <Text>Avg/Request: {Math.round(userMetrics.totalTokens / Math.max(userMetrics.totalRequests, 1))}</Text>
// </Box>
// </Box>
// {/* Date Range */}
// <Box marginTop={1} borderStyle="single" borderColor="blue" padding={1}>
// <Text color="blue" bold>Activity Period</Text>
// <Spacer />
// <Text>First: {formatDate(userMetrics.firstRequest)}</Text>
// <Text> → </Text>
// <Text>Last: {formatDate(userMetrics.lastRequest)}</Text>
// </Box>
// {/* Cost Analysis */}
// <Box marginTop={1} borderStyle="single" borderColor="magenta" padding={1}>
// <Text color="magenta" bold>Cost Analysis</Text>
// <Spacer />
// <Text>Avg/Request: {formatCost(userMetrics.totalCost / Math.max(userMetrics.totalRequests, 1))}</Text>
// </Box>
// </Box>
// );
// const ModelsTab: React.FC<{
// userMetrics: UserUsageMetrics;
// formatCost: (cost: number) => string;
// formatTokens: (tokens: number) => string;
// }> = ({ userMetrics, formatCost, formatTokens }) => (
// <Box flexDirection="column">
// <Text color="cyan" bold>Model Usage Breakdown</Text>
// {Object.keys(userMetrics.costByModel).length === 0 ? (
// <Box marginTop={1}>
// <Text color="gray">No model usage data available</Text>
// </Box>
// ) : (
// <Box marginTop={1} flexDirection="column">
// {Object.entries(userMetrics.costByModel)
// .sort(([,a], [,b]) => b.totalCost - a.totalCost)
// .map(([model, data]) => (
// <Box key={model} borderStyle="single" borderColor="yellow" padding={1} marginTop={1}>
// <Box flexDirection="column" width="100%">
// <Text color="yellow" bold>{model}</Text>
// <Box>
// <Box width="33%">
// <Text>Requests: {data.requests}</Text>
// </Box>
// <Box width="33%">
// <Text>Cost: {formatCost(data.totalCost)}</Text>
// </Box>
// <Box width="34%">
// <Text>Tokens: {formatTokens(data.inputTokens + data.outputTokens)}</Text>
// </Box>
// </Box>
// <Box>
// <Box width="50%">
// <Text color="green">Input: {formatTokens(data.inputTokens)}</Text>
// </Box>
// <Box width="50%">
// <Text color="blue">Output: {formatTokens(data.outputTokens)}</Text>
// </Box>
// </Box>
// <Text color="gray">
// Avg: {formatCost(data.totalCost / Math.max(data.requests, 1))}/req
// </Text>
// </Box>
// </Box>
// ))}
// </Box>
// )}
// </Box>
// );
// const PricingTab: React.FC<{
// pricingInfo: PricingInfo;
// formatCost: (cost: number) => string;
// }> = ({ pricingInfo, formatCost }) => (
// <Box flexDirection="column">
// <Box>
// <Text color="cyan" bold>Current OpenAI Pricing</Text>
// <Spacer />
// <Text color="gray">{pricingInfo.unit} in {pricingInfo.currency}</Text>
// </Box>
// <Box marginTop={1} flexDirection="column">
// {Object.entries(pricingInfo.models)
// .sort(([,a], [,b]) => b.input - a.input)
// .map(([model, pricing]) => (
// <Box key={model} borderStyle="single" borderColor="green" padding={1} marginTop={1}>
// <Box flexDirection="column" width="100%">
// <Text color="green" bold>{model}</Text>
// <Box>
// <Box width="50%">
// <Text color="yellow">Input: {formatCost(pricing.input)}/1K</Text>
// </Box>
// <Box width="50%">
// <Text color="blue">Output: {formatCost(pricing.output)}/1K</Text>
// </Box>
// </Box>
// <Text color="gray">
// Ratio: 1:{(pricing.output / pricing.input).toFixed(1)} (out:in)
// </Text>
// </Box>
// </Box>
// ))}
// </Box>
// <Box marginTop={2} borderStyle="single" borderColor="gray" padding={1}>
// <Text color="gray">
// Last updated: {pricingInfo.lastUpdated}
// </Text>
// </Box>
// </Box>
// );
// export default UsageDashboard;