chat now gets briefing as context, improved readme

This commit is contained in:
Drew Peifer 2026-02-21 01:38:18 -05:00
parent 11d510d81d
commit b2cc853535
4 changed files with 183 additions and 204 deletions

356
README.md
View file

@ -1,217 +1,183 @@
# Personal Dashboard (ClauDash) # ClauDash - Personal Dashboard
A React-based personal dashboard application that generates AI-powered daily briefings using Claude (Anthropic). The app aggregates data from multiple configurable sources—including weather, news APIs, Reddit, and RSS feeds—and uses Claude to create personalized, conversational briefings that highlight what's interesting and track changes over time. Includes an interactive chat interface and intelligent caching to minimize API usage. ## Description
## Quick Setup ClauDash is a personal dashboard application that aggregates data from multiple sources and uses Claude AI to generate contextualized daily briefings. The application fetches data from configurable sources including Reddit APIs, RSS feeds, web pages, and weather services, then leverages Claude to create personalized summaries that track changes and follow up on stories over time. Features include intelligent caching to minimize API costs, an interactive chat interface, and customizable widget layouts.
After cloning the repository, follow these steps to get started: ## Tech Stack
1. **Install dependencies** **Frontend**
```bash - React 19
cd claudash - Material-UI 7 (MUI)
npm install - Emotion (CSS-in-JS)
``` - Vite 4
2. **Configure environment variables** **Backend**
```bash - Express 5 (proxy server)
cp .env.example .env.local - Node.js
```
Edit `.env.local` and add your Anthropic API key:
```
REACT_APP_ANTHROPIC_API_KEY=sk-ant-your-actual-key-here
```
3. **Configure your data sources and location** (optional) **APIs & Services**
- Anthropic Claude API (claude-sonnet-4-5-20250929)
- Open-Meteo API (weather data)
- RSS2JSON API (RSS feed parsing)
In `.env.local`, customize these settings: **Storage**
- `REACT_APP_LOCATION` - Your location for weather (e.g., "harrisburg, pa, usa") - localStorage (client-side caching)
- `REACT_APP_DATA_SOURCES` - Comma-separated URLs to fetch from
- `REACT_APP_CLAUDE_INSTRUCTIONS` - Custom instructions for briefing tone/focus
4. **Start the application**
```bash
npm start
```
This command runs both the Vite dev server (port 5173) and the proxy server (port 3001) concurrently.
5. **Access the dashboard**
Open your browser to `http://localhost:5173`
## How It Works
### Architecture
The application consists of three main layers:
1. **Data Fetching Layer** (`src/services/dataFetcher.js`)
- Fetches data from configured sources (Reddit JSON APIs, RSS feeds, etc.)
- Retrieves weather information using Open-Meteo API
- Implements intelligent caching with configurable TTL to minimize API calls
- Handles multiple data sources in parallel with graceful error handling
2. **AI Processing Layer** (`src/services/claudeService.js`)
- Sends aggregated data to Claude via a local Express proxy server
- Builds context-aware prompts that include yesterday's briefing for comparison
- Generates personalized briefings (300-400 words) with personality and insights
- Tracks token usage and estimated API costs
- Provides a chat interface for follow-up questions
3. **Presentation Layer** (`src/components/`)
- Material-UI widgets display briefing, weather, and news data
- Drag-and-drop capable widget layout (via MUI flex grid)
- Dark/light theme toggle
- Chat interface for conversational interaction with Claude
- Debug panel for development (toggleable via env variable)
### Data Flow
1. **On Load**: Dashboard checks localStorage for today's cached briefing
2. **If Not Cached**: Fetches data from all configured sources in parallel
3. **Data Aggregation**: Combines weather and news data with standardized schema
4. **AI Generation**: Sends data + yesterday's briefing to Claude for context-aware briefing
5. **Caching**: Stores briefing and raw data in localStorage with timestamps
6. **Display**: Renders briefing and individual source widgets
7. **Refresh**: Manual refresh button forces fresh data fetch and new briefing generation
### Proxy Server
The application uses a local Express proxy server (`proxy-server.js`) to communicate with the Anthropic API. This is necessary because:
- Browser CORS restrictions prevent direct API calls from the frontend
- Keeps the API key secure from browser developer tools
- Provides a single point for API request/response logging
**The proxy server is automatically started when you run `npm start`** and runs on port 3001 alongside the Vite dev server (port 5173).
#### Troubleshooting the Proxy Server
If you encounter errors like "Failed to fetch" or "Network request failed" when generating briefings:
1. **Check if the proxy server is running**: Look for console output showing `Proxy server listening on port 3001`
2. **Restart the application**: The easiest way to restart both servers is to:
- Stop the current process (Ctrl+C in terminal)
- Run `npm start` again
If you need to run the servers separately for debugging:
```bash
# Terminal 1: Run proxy server only
npm run proxy
# Terminal 2: Run Vite dev server only
npm run dev
```
### Source Parser
The `sourceParser.js` service intelligently handles various data formats:
- **JSON APIs**: Reddit, custom JSON endpoints
- **RSS/XML Feeds**: Parses RSS feeds with full article content
- **HTML Pages**: Uses Claude to extract and summarize web page content
- **Weather**: Standardizes Open-Meteo weather data into a consistent format
All sources are normalized into a common schema before being sent to Claude.
### Storage & Caching
The app uses localStorage for two types of caching:
1. **Briefing History**: Stores daily briefings with dates for historical context
2. **Source Data Cache**: Short-term cache (default 15 min) for API responses to avoid redundant fetches
The `storageService.js` handles all persistence with automatic cleanup of old data based on `REACT_APP_HISTORY_DAYS`.
## Features ## Features
- **AI-Powered Briefings**: Claude generates conversational, personalized summaries - AI-generated daily briefings with conversational tone and contextual awareness
- **Historical Context**: Compares today's news with yesterday's to highlight changes and follow-ups - Historical context tracking that compares current news with previous briefings
- **Multiple Data Sources**: Configure any combination of JSON APIs, RSS feeds, or web pages - Multi-source data aggregation from Reddit, RSS feeds, and web pages
- **Smart Caching**: Reduces API calls and costs through intelligent data caching - Intelligent caching system with configurable TTL to minimize API usage
- **Interactive Chat**: Ask Claude follow-up questions about your briefing - Interactive chat interface for follow-up questions about briefing content
- **Token Tracking**: Real-time display of API usage and estimated costs - Location-based weather integration with forecast display
- **Theme Support**: Toggle between light and dark themes - Row-based widget layout system for organizing content sources
- **Responsive Layout**: Flexible widget grid adapts to screen size - Quick links bar for frequently accessed URLs
- **Weather Integration**: Location-based weather from Open-Meteo API (supports zip codes and city names) - Token usage tracking with cost estimation
- **Row-based Layout**: Configure widgets in multiple rows using JSON object format - Dark and light theme support
- **Enhanced Reddit Display**: Shows post age, upvotes, comments, and optimized images - Responsive widget grid layout
- **Debug Mode**: Developer tools for testing and troubleshooting - Enhanced Reddit post display with images, upvotes, and comment counts
- Webpage content summarization using Claude
- Debug mode for development and testing
## Configuration Options ## Configuration
All configuration is done via environment variables in `.env.local`: All configuration is managed through environment variables in `.env.local`. Copy `.env.example` to `.env.local` and configure the following:
| Variable | Description | Default | ### Required Configuration
|----------|-------------|---------|
| `REACT_APP_ANTHROPIC_API_KEY` | Your Anthropic API key (required) | - | | Variable | Description |
| `REACT_APP_LOCATION` | Location for weather (zip code or city name) | - | |----------|-------------|
| `REACT_APP_DATA_SOURCES` | JSON object for rows or comma-separated URLs | Reddit URLs | | `REACT_APP_ANTHROPIC_API_KEY` | Anthropic API key for Claude access |
| `REACT_APP_CLAUDE_MODEL` | Claude model to use | claude-sonnet-4-5-20250929 |
| `REACT_APP_CLAUDE_INSTRUCTIONS` | Custom briefing instructions | - | ### Optional Configuration
| `REACT_APP_REFRESH_INTERVAL` | Cache TTL in minutes | 15 |
| `REACT_APP_HISTORY_DAYS` | Days of history to keep | 7 | | Variable | Default | Description |
| `REACT_APP_CORS_PROXY` | Custom CORS proxy URL | allorigins.win | |----------|---------|-------------|
| `REACT_APP_DEBUG_MODE` | Enable debug features | false | | `REACT_APP_LOCATION` | None | Location for weather (city, state, country or zip code) |
| `REACT_APP_DATA_SOURCES` | Reddit tech/worldnews/science | JSON object for row-based layout or comma-separated URLs |
| `REACT_APP_CLAUDE_MODEL` | claude-sonnet-4-5-20250929 | Claude model identifier |
| `REACT_APP_CLAUDE_INSTRUCTIONS` | None | Custom instructions for briefing generation |
| `REACT_APP_REFRESH_INTERVAL` | 15 | Cache TTL in minutes |
| `REACT_APP_HISTORY_DAYS` | 7 | Days of briefing history to retain |
| `REACT_APP_CORS_PROXY` | allorigins.win | CORS proxy service URL |
| `REACT_APP_DEBUG_MODE` | false | Enable debug panel and logging |
| `REACT_APP_TEMPERATURE_UNIT` | F | Temperature unit (F or C) |
| `REACT_APP_CHART_DATE_FORMAT` | MM/DD/YYYY | Date format for charts |
| `REACT_APP_TEXT_VOICE` | Google UK English Female | Text-to-speech voice name |
| `REACT_APP_QUICK_LINKS` | None | Comma-separated URLs for quick link buttons |
### Data Source Configuration
The `REACT_APP_DATA_SOURCES` variable accepts two formats:
**Row-based layout (JSON object):**
```json
{"row1":["https://www.reddit.com/r/technology.json","https://www.reddit.com/r/worldnews.json"],"row2":["https://www.reddit.com/r/science.json"],"Games":["https://example.com/updates"]}
```
**Legacy format (comma-separated):**
```
https://www.reddit.com/r/technology.json,https://www.reddit.com/r/worldnews.json
```
Supported source types:
- JSON APIs (Reddit endpoints with `.json` suffix)
- RSS/XML feeds
- Web pages (automatically summarized using Claude)
## Installation and Setup
### Prerequisites
- Node.js (version 14 or higher)
- npm or yarn package manager
- Anthropic API key (obtain from https://console.anthropic.com/)
### Installation Steps
1. Clone the repository:
```bash
git clone <repository-url>
cd personal-dash-cl
```
2. Install dependencies:
```bash
cd claudash
npm install
```
3. Configure environment variables:
```bash
cp .env.example .env.local
```
4. Edit `.env.local` and add your Anthropic API key:
```
REACT_APP_ANTHROPIC_API_KEY=sk-ant-your-actual-key-here
```
5. Configure optional settings in `.env.local` (location, data sources, etc.)
6. Start the application:
```bash
npm start
```
This command launches both the Vite development server (port 5173) and the Express proxy server (port 3001) concurrently.
7. Access the application at `http://localhost:5173`
### Development Commands
```bash
npm start # Start both dev server and proxy server
npm run dev # Start only Vite dev server
npm run proxy # Start only Express proxy server
npm run build # Create production build
npm run preview # Preview production build
npm run lint # Run ESLint
```
### Troubleshooting
If briefing generation fails with network errors, verify that both servers are running. The proxy server must be active on port 3001 to communicate with the Anthropic API. Stop the process with Ctrl+C and restart with `npm start` if needed.
To debug specific issues, set `REACT_APP_DEBUG_MODE=true` in `.env.local` to enable the debug panel and detailed console logging.
To clear all cached data, click the trash icon in the top-right corner of the application interface.
## Project Structure ## Project Structure
``` ```
claudash/ claudash/
├── proxy-server.js # Express proxy for Anthropic API ├── proxy-server.js # Express server for API proxying
├── src/ ├── package.json # Dependencies and scripts
│ ├── components/ ├── vite.config.js # Vite configuration
│ │ ├── Dashboard.jsx # Main dashboard container ├── index.html # HTML entry point
│ │ ├── ChatInterface.jsx # Floating chat widget ├── public/ # Static assets
│ │ └── widgets/ # Individual data display widgets └── src/
│ ├── services/ ├── App.jsx # Root component
│ │ ├── claudeService.js # Claude API integration ├── main.jsx # Application entry point
│ │ ├── dataFetcher.js # Multi-source data fetching ├── theme.js # MUI theme configuration
│ │ ├── sourceParser.js # Parse various data formats ├── components/ # React components
│ │ └── storageService.js # localStorage management │ ├── Dashboard.jsx # Main dashboard container
│ └── utils/ │ ├── ChatInterface.jsx # Chat interface component
│ ├── constants.js # App-wide constants │ ├── QuickLinksBar.jsx # Quick links bar
│ └── corsProxy.js # CORS proxy utilities │ └── widgets/ # Widget components
├── services/ # Business logic and API integration
│ ├── claudeService.js # Claude API integration
│ ├── dataFetcher.js # Multi-source data fetching
│ ├── sourceParser.js # Data parsing and standardization
│ ├── storageService.js # localStorage management
│ └── openMeteoService.js # Weather API integration
└── utils/ # Utility functions and constants
├── constants.js # Application constants
└── corsProxy.js # CORS proxy utilities
``` ```
## Major Dependencies
- **[React](https://react.dev/)** (v19) - UI framework
- **[Material-UI](https://mui.com/)** (v7) - Component library and design system
- **[Emotion](https://emotion.sh/)** - CSS-in-JS styling for MUI
- **[Vite](https://vitejs.dev/)** (v4) - Build tool and dev server
- **[Express](https://expressjs.com/)** (v5) - Proxy server for API communication
- **[Anthropic Claude API](https://www.anthropic.com/)** - AI-powered text generation
## Development
### Running in Development Mode
```bash
npm start # Runs both dev server and proxy
npm run dev # Run only Vite dev server
npm run proxy # Run only proxy server
```
### Building for Production
```bash
npm run build # Creates optimized production build
npm run preview # Preview production build locally
```
### Debugging
Set `REACT_APP_DEBUG_MODE=true` in `.env.local` to enable:
- Debug panel with raw data inspection
- Console logging for API calls
- Dummy data generation for testing
## Tips & Best Practices
- **API Costs**: The app displays token usage and estimated costs after each briefing generation. Typical briefings cost $0.02-0.05 depending on data source complexity.
- **Caching**: Briefings are cached per day; use the refresh button to force a new generation.
- **Custom Instructions**: Use `REACT_APP_CLAUDE_INSTRUCTIONS` to tailor briefing style (e.g., "Focus on tech news, be concise").
- **Data Sources**: Reddit JSON endpoints (`/r/subreddit.json`) work well. RSS feeds are also supported. Use JSON object format for row-based layouts: `{"row1":["url1","url2"],"row2":["url3","url4"]}`
- **Clear Cache**: Use the trash icon button to clear all cached data and reset the app.
## License ## License
MIT License - see [LICENSE](LICENSE) file for details. MIT License - see LICENSE file for details.

View file

@ -3,7 +3,7 @@ import { Box, TextField, IconButton, Paper, CircularProgress } from '@mui/materi
import { Send, ExpandLess, ExpandMore } from '@mui/icons-material'; import { Send, ExpandLess, ExpandMore } from '@mui/icons-material';
import { sendChatMessage } from '../services/claudeService'; import { sendChatMessage } from '../services/claudeService';
function ChatInterface() { function ChatInterface({ briefing, sourceData }) {
const [messages, setMessages] = useState([]); const [messages, setMessages] = useState([]);
const [input, setInput] = useState(''); const [input, setInput] = useState('');
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
@ -20,7 +20,7 @@ function ChatInterface() {
setIsExpanded(true); // Expand chat when sending a message setIsExpanded(true); // Expand chat when sending a message
try { try {
const response = await sendChatMessage(input, messages); const response = await sendChatMessage(input, messages, briefing, sourceData);
setMessages(prev => [...prev, { role: 'assistant', content: response }]); setMessages(prev => [...prev, { role: 'assistant', content: response }]);
} catch (error) { } catch (error) {
console.error('Chat error:', error); console.error('Chat error:', error);

View file

@ -304,7 +304,7 @@ function Dashboard({ themeToggle, isDark }) {
</Container> </Container>
{/* Fixed chat at bottom */} {/* Fixed chat at bottom */}
<ChatInterface /> <ChatInterface briefing={briefing} sourceData={sourceData} />
</Box> </Box>
); );
} }

View file

@ -240,9 +240,11 @@ export async function generateBriefing(currentData, previousBriefing) {
* Send a chat message to Claude * Send a chat message to Claude
* @param {string} message - User's message * @param {string} message - User's message
* @param {Array} conversationHistory - Previous messages * @param {Array} conversationHistory - Previous messages
* @param {string} briefing - Current briefing content
* @param {Object} sourceData - Source data from dashboard
* @returns {Promise<string>} Claude's response * @returns {Promise<string>} Claude's response
*/ */
export async function sendChatMessage(message, conversationHistory = []) { export async function sendChatMessage(message, conversationHistory = [], briefing = '', sourceData = {}) {
if (!message || !message.trim()) { if (!message || !message.trim()) {
throw new Error('Message cannot be empty'); throw new Error('Message cannot be empty');
} }
@ -253,12 +255,23 @@ export async function sendChatMessage(message, conversationHistory = []) {
content: msg.content content: msg.content
})); }));
// Add context about the dashboard // Build context with briefing and source data
const contextPrompt = `You are a helpful assistant embedded in a personal dashboard application. let contextPrompt = `You are a helpful assistant embedded in a personal dashboard application.
You have access to the user's daily briefing data and can help answer questions about news, weather, You have access to the user's daily briefing and source data, and can help answer questions about news, weather,
and other information sources configured in their dashboard. Be conversational and helpful. and other information displayed in their dashboard. Be conversational and helpful.`;
User's message: ${message}`; // Add briefing context if available
if (briefing && briefing.trim()) {
contextPrompt += `\n\nCURRENT BRIEFING:\n${briefing}`;
}
// Add condensed source data context if available
if (sourceData && Object.keys(sourceData).length > 0) {
const condensedData = condenseSourcesForClaude(sourceData);
contextPrompt += `\n\nSOURCE DATA SUMMARY:\n${JSON.stringify(condensedData, null, 2)}`;
}
contextPrompt += `\n\nUser's message: ${message}`;
try { try {
const result = await callClaude(contextPrompt, messages); const result = await callClaude(contextPrompt, messages);