added token usage and cost to UI, cleanup
This commit is contained in:
parent
a85e96aad8
commit
bffb11e5b0
15 changed files with 285 additions and 254 deletions
|
|
@ -46,6 +46,7 @@ app.post('/api/claude', async (req, res) => {
|
|||
|
||||
const data = await response.json();
|
||||
console.log('Claude API success, response content length:', data.content?.[0]?.text?.length);
|
||||
console.log('Token usage:', data.usage);
|
||||
res.json(data);
|
||||
} catch (error) {
|
||||
console.error('Proxy error:', error);
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
const [sourceData, setSourceData] = useState({});
|
||||
const [error, setError] = useState(null);
|
||||
const [refreshing, setRefreshing] = useState(false);
|
||||
const [tokenUsage, setTokenUsage] = useState(null);
|
||||
|
||||
useEffect(() => {
|
||||
loadDashboard();
|
||||
|
|
@ -75,14 +76,24 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
|
||||
try {
|
||||
// Generate today's briefing with Claude
|
||||
const newBriefing = await generateBriefing(data, previousBriefing);
|
||||
console.log('Briefing generated, length:', newBriefing?.length);
|
||||
setBriefing(newBriefing);
|
||||
const result = await generateBriefing(data, previousBriefing);
|
||||
console.log('Briefing generated');
|
||||
|
||||
// Handle result object with text and usage
|
||||
if (result && typeof result === 'object' && result.text) {
|
||||
setBriefing(result.text);
|
||||
setTokenUsage(result.usage);
|
||||
console.log('Token usage:', result.usage);
|
||||
} else if (typeof result === 'string') {
|
||||
// Fallback for string responses
|
||||
setBriefing(result);
|
||||
}
|
||||
|
||||
// Save to localStorage
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
console.log('Saving briefing for:', today);
|
||||
saveBriefing(today, newBriefing, data.sources);
|
||||
const briefingText = result?.text || result;
|
||||
saveBriefing(today, briefingText, data.sources);
|
||||
} catch (briefingError) {
|
||||
console.error('Failed to generate briefing:', briefingError);
|
||||
setBriefing(`Unable to generate AI briefing: ${briefingError.message}\n\nYou can still view the data widgets below.`);
|
||||
|
|
@ -161,6 +172,20 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
</Alert>
|
||||
)}
|
||||
|
||||
{tokenUsage && (
|
||||
<Box sx={{ mb: 2, p: 2, bgcolor: 'background.paper', borderRadius: 1, border: '1px solid', borderColor: 'divider' }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
<strong>API Usage:</strong> {tokenUsage.input_tokens?.toLocaleString()} input + {tokenUsage.output_tokens?.toLocaleString()} output = {(tokenUsage.input_tokens + tokenUsage.output_tokens).toLocaleString()} total tokens
|
||||
{' • '}
|
||||
<strong>Cost:</strong> ${((tokenUsage.input_tokens * 0.003 / 1000) + (tokenUsage.output_tokens * 0.015 / 1000)).toFixed(4)}
|
||||
{' '}
|
||||
<Typography component="span" variant="caption" color="text.disabled">
|
||||
(Claude Sonnet 4 pricing: $0.003/1K input, $0.015/1K output)
|
||||
</Typography>
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
|
||||
{/* Widget Grid - easily rearrangeable */}
|
||||
<Box sx={{
|
||||
display: 'flex',
|
||||
|
|
|
|||
|
|
@ -62,7 +62,12 @@ async function callClaude(prompt, messages = []) {
|
|||
const data = await response.json();
|
||||
console.log('Response data structure:', Object.keys(data));
|
||||
console.log('Response content:', data.content?.[0]?.text?.substring(0, 200) + '...');
|
||||
return data.content[0].text;
|
||||
console.log('Usage data:', data.usage);
|
||||
|
||||
return {
|
||||
text: data.content[0].text,
|
||||
usage: data.usage // { input_tokens, output_tokens }
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Error calling Claude:', error);
|
||||
throw error;
|
||||
|
|
@ -129,8 +134,8 @@ export async function generateBriefing(currentData, previousBriefing) {
|
|||
|
||||
try {
|
||||
const prompt = buildBriefingPrompt(currentData, previousBriefing);
|
||||
const briefing = await callClaude(prompt);
|
||||
return briefing;
|
||||
const result = await callClaude(prompt);
|
||||
return result; // Returns { text, usage }
|
||||
} catch (error) {
|
||||
console.error('Error generating briefing:', error);
|
||||
|
||||
|
|
@ -168,8 +173,8 @@ export async function sendChatMessage(message, conversationHistory = []) {
|
|||
User's message: ${message}`;
|
||||
|
||||
try {
|
||||
const response = await callClaude(contextPrompt, messages);
|
||||
return response;
|
||||
const result = await callClaude(contextPrompt, messages);
|
||||
return result.text; // For chat, just return text for now
|
||||
} catch (error) {
|
||||
console.error('Error in chat:', error);
|
||||
return `I apologize, but I encountered an error: ${error.message}. Please try again.`;
|
||||
|
|
|
|||
Loading…
Reference in a new issue