chat now gets briefing as context, improved readme
This commit is contained in:
parent
11d510d81d
commit
b2cc853535
4 changed files with 183 additions and 204 deletions
356
README.md
356
README.md
|
|
@ -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**
|
||||
```bash
|
||||
cd claudash
|
||||
npm install
|
||||
```
|
||||
**Frontend**
|
||||
- React 19
|
||||
- Material-UI 7 (MUI)
|
||||
- Emotion (CSS-in-JS)
|
||||
- Vite 4
|
||||
|
||||
2. **Configure environment variables**
|
||||
```bash
|
||||
cp .env.example .env.local
|
||||
```
|
||||
Edit `.env.local` and add your Anthropic API key:
|
||||
```
|
||||
REACT_APP_ANTHROPIC_API_KEY=sk-ant-your-actual-key-here
|
||||
```
|
||||
**Backend**
|
||||
- Express 5 (proxy server)
|
||||
- Node.js
|
||||
|
||||
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:
|
||||
- `REACT_APP_LOCATION` - Your location for weather (e.g., "harrisburg, pa, usa")
|
||||
- `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`.
|
||||
**Storage**
|
||||
- localStorage (client-side caching)
|
||||
|
||||
## Features
|
||||
|
||||
- **AI-Powered Briefings**: Claude generates conversational, personalized summaries
|
||||
- **Historical Context**: Compares today's news with yesterday's to highlight changes and follow-ups
|
||||
- **Multiple Data Sources**: Configure any combination of JSON APIs, RSS feeds, or web pages
|
||||
- **Smart Caching**: Reduces API calls and costs through intelligent data caching
|
||||
- **Interactive Chat**: Ask Claude follow-up questions about your briefing
|
||||
- **Token Tracking**: Real-time display of API usage and estimated costs
|
||||
- **Theme Support**: Toggle between light and dark themes
|
||||
- **Responsive Layout**: Flexible widget grid adapts to screen size
|
||||
- **Weather Integration**: Location-based weather from Open-Meteo API (supports zip codes and city names)
|
||||
- **Row-based Layout**: Configure widgets in multiple rows using JSON object format
|
||||
- **Enhanced Reddit Display**: Shows post age, upvotes, comments, and optimized images
|
||||
- **Debug Mode**: Developer tools for testing and troubleshooting
|
||||
- AI-generated daily briefings with conversational tone and contextual awareness
|
||||
- Historical context tracking that compares current news with previous briefings
|
||||
- Multi-source data aggregation from Reddit, RSS feeds, and web pages
|
||||
- Intelligent caching system with configurable TTL to minimize API usage
|
||||
- Interactive chat interface for follow-up questions about briefing content
|
||||
- Location-based weather integration with forecast display
|
||||
- Row-based widget layout system for organizing content sources
|
||||
- Quick links bar for frequently accessed URLs
|
||||
- Token usage tracking with cost estimation
|
||||
- Dark and light theme support
|
||||
- Responsive widget grid layout
|
||||
- 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 |
|
||||
|----------|-------------|---------|
|
||||
| `REACT_APP_ANTHROPIC_API_KEY` | Your Anthropic API key (required) | - |
|
||||
| `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_CLAUDE_MODEL` | Claude model to use | claude-sonnet-4-5-20250929 |
|
||||
| `REACT_APP_CLAUDE_INSTRUCTIONS` | Custom briefing instructions | - |
|
||||
| `REACT_APP_REFRESH_INTERVAL` | Cache TTL in minutes | 15 |
|
||||
| `REACT_APP_HISTORY_DAYS` | Days of history to keep | 7 |
|
||||
| `REACT_APP_CORS_PROXY` | Custom CORS proxy URL | allorigins.win |
|
||||
| `REACT_APP_DEBUG_MODE` | Enable debug features | false |
|
||||
### Required Configuration
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `REACT_APP_ANTHROPIC_API_KEY` | Anthropic API key for Claude access |
|
||||
|
||||
### Optional Configuration
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `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
|
||||
|
||||
```
|
||||
claudash/
|
||||
├── proxy-server.js # Express proxy for Anthropic API
|
||||
├── src/
|
||||
│ ├── components/
|
||||
│ │ ├── Dashboard.jsx # Main dashboard container
|
||||
│ │ ├── ChatInterface.jsx # Floating chat widget
|
||||
│ │ └── widgets/ # Individual data display widgets
|
||||
│ ├── services/
|
||||
│ │ ├── claudeService.js # Claude API integration
|
||||
│ │ ├── dataFetcher.js # Multi-source data fetching
|
||||
│ │ ├── sourceParser.js # Parse various data formats
|
||||
│ │ └── storageService.js # localStorage management
|
||||
│ └── utils/
|
||||
│ ├── constants.js # App-wide constants
|
||||
│ └── corsProxy.js # CORS proxy utilities
|
||||
├── proxy-server.js # Express server for API proxying
|
||||
├── package.json # Dependencies and scripts
|
||||
├── vite.config.js # Vite configuration
|
||||
├── index.html # HTML entry point
|
||||
├── public/ # Static assets
|
||||
└── src/
|
||||
├── App.jsx # Root component
|
||||
├── main.jsx # Application entry point
|
||||
├── theme.js # MUI theme configuration
|
||||
├── components/ # React components
|
||||
│ ├── Dashboard.jsx # Main dashboard container
|
||||
│ ├── ChatInterface.jsx # Chat interface component
|
||||
│ ├── QuickLinksBar.jsx # Quick links bar
|
||||
│ └── 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
|
||||
|
||||
MIT License - see [LICENSE](LICENSE) file for details.
|
||||
MIT License - see LICENSE file for details.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { Box, TextField, IconButton, Paper, CircularProgress } from '@mui/materi
|
|||
import { Send, ExpandLess, ExpandMore } from '@mui/icons-material';
|
||||
import { sendChatMessage } from '../services/claudeService';
|
||||
|
||||
function ChatInterface() {
|
||||
function ChatInterface({ briefing, sourceData }) {
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [input, setInput] = useState('');
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
|
@ -20,7 +20,7 @@ function ChatInterface() {
|
|||
setIsExpanded(true); // Expand chat when sending a message
|
||||
|
||||
try {
|
||||
const response = await sendChatMessage(input, messages);
|
||||
const response = await sendChatMessage(input, messages, briefing, sourceData);
|
||||
setMessages(prev => [...prev, { role: 'assistant', content: response }]);
|
||||
} catch (error) {
|
||||
console.error('Chat error:', error);
|
||||
|
|
|
|||
|
|
@ -304,7 +304,7 @@ function Dashboard({ themeToggle, isDark }) {
|
|||
</Container>
|
||||
|
||||
{/* Fixed chat at bottom */}
|
||||
<ChatInterface />
|
||||
<ChatInterface briefing={briefing} sourceData={sourceData} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -240,9 +240,11 @@ export async function generateBriefing(currentData, previousBriefing) {
|
|||
* Send a chat message to Claude
|
||||
* @param {string} message - User's message
|
||||
* @param {Array} conversationHistory - Previous messages
|
||||
* @param {string} briefing - Current briefing content
|
||||
* @param {Object} sourceData - Source data from dashboard
|
||||
* @returns {Promise<string>} Claude's response
|
||||
*/
|
||||
export async function sendChatMessage(message, conversationHistory = []) {
|
||||
export async function sendChatMessage(message, conversationHistory = [], briefing = '', sourceData = {}) {
|
||||
if (!message || !message.trim()) {
|
||||
throw new Error('Message cannot be empty');
|
||||
}
|
||||
|
|
@ -253,12 +255,23 @@ export async function sendChatMessage(message, conversationHistory = []) {
|
|||
content: msg.content
|
||||
}));
|
||||
|
||||
// Add context about the dashboard
|
||||
const 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,
|
||||
and other information sources configured in their dashboard. Be conversational and helpful.
|
||||
// Build context with briefing and source data
|
||||
let contextPrompt = `You are a helpful assistant embedded in a personal dashboard application.
|
||||
You have access to the user's daily briefing and source data, and can help answer questions about news, weather,
|
||||
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 {
|
||||
const result = await callClaude(contextPrompt, messages);
|
||||
|
|
|
|||
Loading…
Reference in a new issue