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();
|
const data = await response.json();
|
||||||
console.log('Claude API success, response content length:', data.content?.[0]?.text?.length);
|
console.log('Claude API success, response content length:', data.content?.[0]?.text?.length);
|
||||||
|
console.log('Token usage:', data.usage);
|
||||||
res.json(data);
|
res.json(data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Proxy error:', error);
|
console.error('Proxy error:', error);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ function Dashboard({ themeToggle, isDark }) {
|
||||||
const [sourceData, setSourceData] = useState({});
|
const [sourceData, setSourceData] = useState({});
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
|
const [tokenUsage, setTokenUsage] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadDashboard();
|
loadDashboard();
|
||||||
|
|
@ -75,14 +76,24 @@ function Dashboard({ themeToggle, isDark }) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Generate today's briefing with Claude
|
// Generate today's briefing with Claude
|
||||||
const newBriefing = await generateBriefing(data, previousBriefing);
|
const result = await generateBriefing(data, previousBriefing);
|
||||||
console.log('Briefing generated, length:', newBriefing?.length);
|
console.log('Briefing generated');
|
||||||
setBriefing(newBriefing);
|
|
||||||
|
// 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
|
// Save to localStorage
|
||||||
const today = new Date().toISOString().split('T')[0];
|
const today = new Date().toISOString().split('T')[0];
|
||||||
console.log('Saving briefing for:', today);
|
console.log('Saving briefing for:', today);
|
||||||
saveBriefing(today, newBriefing, data.sources);
|
const briefingText = result?.text || result;
|
||||||
|
saveBriefing(today, briefingText, data.sources);
|
||||||
} catch (briefingError) {
|
} catch (briefingError) {
|
||||||
console.error('Failed to generate briefing:', 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.`);
|
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>
|
</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 */}
|
{/* Widget Grid - easily rearrangeable */}
|
||||||
<Box sx={{
|
<Box sx={{
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,12 @@ async function callClaude(prompt, messages = []) {
|
||||||
const data = await response.json();
|
const data = await response.json();
|
||||||
console.log('Response data structure:', Object.keys(data));
|
console.log('Response data structure:', Object.keys(data));
|
||||||
console.log('Response content:', data.content?.[0]?.text?.substring(0, 200) + '...');
|
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) {
|
} catch (error) {
|
||||||
console.error('Error calling Claude:', error);
|
console.error('Error calling Claude:', error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -129,8 +134,8 @@ export async function generateBriefing(currentData, previousBriefing) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const prompt = buildBriefingPrompt(currentData, previousBriefing);
|
const prompt = buildBriefingPrompt(currentData, previousBriefing);
|
||||||
const briefing = await callClaude(prompt);
|
const result = await callClaude(prompt);
|
||||||
return briefing;
|
return result; // Returns { text, usage }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error generating briefing:', error);
|
console.error('Error generating briefing:', error);
|
||||||
|
|
||||||
|
|
@ -168,8 +173,8 @@ export async function sendChatMessage(message, conversationHistory = []) {
|
||||||
User's message: ${message}`;
|
User's message: ${message}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const response = await callClaude(contextPrompt, messages);
|
const result = await callClaude(contextPrompt, messages);
|
||||||
return response;
|
return result.text; // For chat, just return text for now
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error in chat:', error);
|
console.error('Error in chat:', error);
|
||||||
return `I apologize, but I encountered an error: ${error.message}. Please try again.`;
|
return `I apologize, but I encountered an error: ${error.message}. Please try again.`;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue