Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
| # Database-Driven Homepage - Complete Setup Guide | |
| ## π What You Now Have | |
| **β Fully database-driven homepage with automated cause/topic management:** | |
| 1. **API Endpoint** - `/api/trending` serves causes from database | |
| 2. **Frontend Integration** - Homepage fetches causes dynamically | |
| 3. **Image Generator** - Creates images for ALL 235 causes automatically | |
| 4. **Three Data Sources:** | |
| - **EveryOrg** (39 popular causes like "Climate", "Education", "Health") | |
| - **NTEE Codes** (196 IRS nonprofit categories like "E32: School-Based Health Care") | |
| - **Mixed** (automatically combines both) | |
| --- | |
| ## π Quick Start | |
| ### Step 1: Generate Images for ALL Causes | |
| ```bash | |
| cd /home/developer/projects/open-navigator | |
| source .venv/bin/activate | |
| # First, add Gemini API key to .env: | |
| # echo "GEMINI_API_KEY=your_key_here" >> .env | |
| # Get key from: https://makersuite.google.com/app/apikey | |
| # Generate ALL 235 cause images (takes ~10-15 minutes) | |
| python scripts/media/generate_all_cause_images.py | |
| # OR test with just 10 causes first | |
| python scripts/media/generate_all_cause_images.py --limit 10 | |
| # OR generate only EveryOrg causes (39 causes) | |
| python scripts/media/generate_all_cause_images.py --type everyorg | |
| # OR generate only NTEE codes (196 causes) | |
| python scripts/media/generate_all_cause_images.py --type ntee | |
| ``` | |
| **Output:** | |
| ``` | |
| data/media/causes/ | |
| βββ everyorg_animals_banner.png (1200x600) | |
| βββ everyorg_animals_square.png (400x400) | |
| βββ everyorg_climate_banner.png | |
| βββ everyorg_climate_square.png | |
| βββ ntee_E_banner.png | |
| βββ ntee_E_square.png | |
| βββ ntee_E32_banner.png | |
| βββ ntee_E32_square.png | |
| βββ all_causes_metadata.json | |
| ``` | |
| ### Step 2: Copy Images to Frontend | |
| ```bash | |
| # Make images accessible to frontend | |
| mkdir -p frontend/public/images/causes | |
| cp data/media/causes/*.png frontend/public/images/causes/ | |
| # OR use symlink | |
| ln -s ../../../data/media/causes frontend/public/images/causes | |
| ``` | |
| ### Step 3: Test the API | |
| ```bash | |
| # Start the API | |
| ./start-all.sh | |
| # Or just API: | |
| cd /home/developer/projects/open-navigator | |
| source .venv/bin/activate | |
| uvicorn api.main:app --reload --port 8001 | |
| # Test endpoints: | |
| curl http://localhost:8001/api/trending?source=everyorg&limit=12 | |
| curl http://localhost:8001/api/trending?source=ntee&level=1 | |
| curl http://localhost:8001/api/trending?source=mixed&limit=12 | |
| curl http://localhost:8001/api/trending/stats | |
| ``` | |
| ### Step 4: See It Live | |
| ```bash | |
| # Visit homepage | |
| http://localhost:5173 | |
| # You should see: | |
| # - Trending causes loaded from database (not hardcoded!) | |
| # - Count showing: "(12 from database)" | |
| # - Causes change based on what's in parquet files | |
| ``` | |
| --- | |
| ## π How It Works | |
| ### Data Flow | |
| ``` | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β 1. CAUSES DATA (Parquet Files) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β data/gold/causes_everyorg_causes.parquet (39 rows) β | |
| β data/gold/causes_ntee_codes (196 rows) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β 2. IMAGE GENERATOR (Python Script) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β scripts/media/generate_all_cause_images.py β | |
| β - Reads parquet files β | |
| β - Uses Gemini AI for color schemes β | |
| β - Generates banner (1200x600) + square (400x400) β | |
| β - Saves to data/media/causes/ β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β 3. API ENDPOINT (FastAPI) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β GET /api/trending?source=mixed&limit=12 β | |
| β - Reads parquet files β | |
| β - Returns causes with metadata β | |
| β - Includes image URLs β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| β 4. FRONTEND (React) β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€ | |
| β Home.tsx - useQuery('trending-causes') β | |
| β - Fetches from API on page load β | |
| β - Renders trending topics bar β | |
| β - Shows cause icons, names, + buttons β | |
| β - Clickable β search that cause β | |
| βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ``` | |
| ### API Endpoints | |
| #### `GET /api/trending` | |
| **Parameters:** | |
| - `source`: "everyorg" | "ntee" | "mixed" (default: "everyorg") | |
| - `limit`: Number of causes to return (default: 12, max: 100) | |
| - `level`: NTEE level filter (1=major groups, 2=subcategories) - only for ntee source | |
| **Response:** | |
| ```json | |
| { | |
| "causes": [ | |
| { | |
| "name": "Climate", | |
| "icon": "π", | |
| "category": "primary", | |
| "description": "Climate change mitigation...", | |
| "image_url": "/images/causes/everyorg_climate_square.png", | |
| "popularity_rank": 4 | |
| }, | |
| { | |
| "name": "Health", | |
| "icon": "βοΈ", | |
| "category": "major_group", | |
| "description": "NTEE Code E", | |
| "image_url": "/images/causes/ntee_E_square.png", | |
| "popularity_rank": null | |
| } | |
| ], | |
| "total": 12 | |
| } | |
| ``` | |
| #### `GET /api/trending/stats` | |
| **Response:** | |
| ```json | |
| { | |
| "everyorg_causes": 39, | |
| "ntee_causes": 196, | |
| "total_causes": 235, | |
| "generated_images": 470 | |
| } | |
| ``` | |
| --- | |
| ## π¨ Image Generation Details | |
| ### What Gets Generated | |
| **For each cause** (e.g., "Climate"): | |
| 1. **Banner image** (1200x600px) | |
| - Filename: `everyorg_climate_banner.png` | |
| - Use: Hero banners, featured stories | |
| - Has: Gradient background, large text overlay | |
| 2. **Square thumbnail** (400x400px) | |
| - Filename: `everyorg_climate_square.png` | |
| - Use: Topic cards, trending bar | |
| - Has: Circular gradient, compact text | |
| 3. **Color scheme** (in metadata.json) | |
| - AI-generated thematic colors | |
| - Example: Climate β greens and blues | |
| - Example: Health β calming medical blues | |
| ### Filename Patterns | |
| - **EveryOrg**: `everyorg_{cause_id}_{type}.png` | |
| - `everyorg_climate_banner.png` | |
| - `everyorg_education_square.png` | |
| - **NTEE**: `ntee_{code}_{type}.png` | |
| - `ntee_E_banner.png` (Health - major group) | |
| - `ntee_E32_square.png` (School-Based Health Care - specific) | |
| ### Generation Progress | |
| The script shows: | |
| ``` | |
| [1/235] Processing: Climate | |
| Category: everyorg | ID: climate | |
| ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| π¨ Generated color scheme: Calming greens and blues for environmental focus | |
| πΌοΈ Creating banner image (1200x600)... | |
| β Saved: data/media/causes/everyorg_climate_banner.png | |
| π² Creating square image (400x400)... | |
| β Saved: data/media/causes/everyorg_climate_square.png | |
| β Success! (1/235 = 0.4% complete) | |
| ``` | |
| --- | |
| ## π§ Customization | |
| ### Change Source Mix | |
| **Homepage** (`frontend/src/pages/Home.tsx`): | |
| ```typescript | |
| // Current: Mixed (6 everyorg + 6 ntee) | |
| source: 'mixed', | |
| limit: 12 | |
| // Only popular causes: | |
| source: 'everyorg', | |
| limit: 12 | |
| // Only IRS categories: | |
| source: 'ntee', | |
| limit: 12, | |
| level: 1 // Only major groups (Arts, Health, Education, etc.) | |
| ``` | |
| ### Add Custom Causes | |
| **Option 1: Add to EveryOrg causes** | |
| ```python | |
| import polars as pl | |
| # Load existing | |
| df = pl.read_parquet('data/gold/causes_everyorg_causes.parquet') | |
| # Add new cause | |
| new_cause = pl.DataFrame({ | |
| 'cause_id': ['oral-health'], | |
| 'cause_name': ['Oral Health'], | |
| 'description': ['Dental care access and fluoride policy'], | |
| 'category': ['primary'], | |
| 'parent_id': [None], | |
| 'icon': ['π¦·'], | |
| 'popularity_rank': [40], | |
| 'data_source': ['Manual'], | |
| 'download_date': [pl.datetime('now')], | |
| 'version': ['2026.1'] | |
| }) | |
| # Combine | |
| df = pl.concat([df, new_cause]) | |
| # Save | |
| df.write_parquet('data/gold/causes_everyorg_causes.parquet') | |
| ``` | |
| **Option 2: Add to NTEE codes** | |
| (Similar process with causes_ntee_codes) | |
| ### Skip Existing Images | |
| If you've already generated some images: | |
| ```bash | |
| python scripts/media/generate_all_cause_images.py --skip-existing | |
| ``` | |
| This will only generate images for causes that don't have them yet. | |
| --- | |
| ## π What Changed | |
| ### Files Modified | |
| 1. **API:** | |
| - β `api/routes/trending.py` - New trending causes endpoint | |
| - β `api/main.py` - Registered trending router | |
| 2. **Frontend:** | |
| - β `frontend/src/pages/Home.tsx` - Database-driven causes | |
| - Added `useQuery` to fetch from `/api/trending` | |
| - Shows count "(X from database)" | |
| 3. **Scripts:** | |
| - β `scripts/media/generate_all_cause_images.py` - Batch generator | |
| - β `scripts/media/generate_topic_images.py` - Base generator (already existed) | |
| ### Before vs After | |
| **Before (Hardcoded):** | |
| ```typescript | |
| const TRENDING_TOPICS = [ | |
| { name: 'World Press Freedom Day', icon: 'π°', category: 'Global' }, | |
| { name: 'Business & Markets', icon: 'πΌ', category: 'Economics' }, | |
| // ... hardcoded list | |
| ] | |
| ``` | |
| **After (Database-Driven):** | |
| ```typescript | |
| const { data: trendingData } = useQuery({ | |
| queryKey: ['trending-causes'], | |
| queryFn: async () => { | |
| const response = await api.get('/trending', { | |
| params: { source: 'mixed', limit: 12 } | |
| }) | |
| return response.data | |
| } | |
| }) | |
| const trendingTopics = trendingData?.causes || [] | |
| ``` | |
| --- | |
| ## π― Next Steps | |
| ### Phase 1: Generate All Images (Do This First!) | |
| ```bash | |
| # Get Gemini API key | |
| https://makersuite.google.com/app/apikey | |
| # Add to .env | |
| echo "GEMINI_API_KEY=your_key" >> .env | |
| # Generate all 235 cause images (~10-15 minutes) | |
| python scripts/media/generate_all_cause_images.py | |
| # Copy to frontend | |
| cp data/media/causes/*.png frontend/public/images/causes/ | |
| ``` | |
| ### Phase 2: Test Locally | |
| ```bash | |
| ./start-all.sh | |
| # Visit http://localhost:5173 | |
| # Check that trending causes load from database | |
| # Inspect network tab: should see /api/trending request | |
| ``` | |
| ### Phase 3: Deploy | |
| ```bash | |
| # Standard deployment | |
| ./packages/hosting/scripts/huggingface/safe-deploy.sh | |
| # Make sure to include generated images! | |
| # Either: | |
| # 1. Copy to frontend/public/images/causes before deploy | |
| # 2. Or upload to CDN and update image_url in API | |
| ``` | |
| ### Phase 4: Track Popularity (Future) | |
| Add analytics to track which causes users click: | |
| ```sql | |
| CREATE TABLE cause_interactions ( | |
| cause_id VARCHAR, | |
| interaction_type VARCHAR, -- click, follow, search | |
| user_id VARCHAR, | |
| timestamp TIMESTAMP | |
| ); | |
| ``` | |
| Then use this data to dynamically rank causes by popularity! | |
| --- | |
| ## π Troubleshooting | |
| ### "GEMINI_API_KEY not found" | |
| ```bash | |
| # Get key from Google | |
| https://makersuite.google.com/app/apikey | |
| # Add to .env | |
| echo "GEMINI_API_KEY=your_actual_key_here" >> .env | |
| # Verify | |
| grep GEMINI_API_KEY .env | |
| ``` | |
| ### Images Don't Show on Homepage | |
| 1. **Check API response:** | |
| ```bash | |
| curl http://localhost:8001/api/trending?source=mixed&limit=1 | |
| # Look for "image_url" field | |
| ``` | |
| 2. **Check images exist:** | |
| ```bash | |
| ls frontend/public/images/causes/ | head -10 | |
| ``` | |
| 3. **Check browser console:** | |
| - Should see no 404 errors for images | |
| - Network tab shows images loading | |
| ### "No causes found" Error | |
| Verify parquet files exist: | |
| ```bash | |
| ls -lh data/gold/causes*.parquet | |
| # Should show: | |
| # causes_everyorg_causes.parquet (39 rows) | |
| # causes_ntee_codes (196 rows) | |
| ``` | |
| ### Frontend Shows "(0 from database)" | |
| 1. Check API is running: | |
| ```bash | |
| curl http://localhost:8001/api/trending | |
| ``` | |
| 2. Check for CORS errors in browser console | |
| 3. Verify .env has correct API URL | |
| --- | |
| ## π Summary | |
| **You now have:** | |
| β **235 causes** ready to generate images for | |
| - 39 EveryOrg popular causes (Climate, Education, etc.) | |
| - 196 NTEE codes (official IRS categories) | |
| β **Automated image generation** script | |
| - Reads causes from parquet files | |
| - Uses Gemini AI for color schemes | |
| - Generates banner + square for each | |
| β **Database-driven API** endpoint | |
| - `/api/trending` serves causes dynamically | |
| - Supports filtering by source, limit, level | |
| - Includes image URLs and metadata | |
| β **Frontend integration** | |
| - Homepage fetches causes from API | |
| - Shows "(X from database)" count | |
| - Automatically updates when data changes | |
| **Your homepage is now 100% database-driven! π** | |
| No more hardcoded causes - everything comes from your parquet files! | |