# Project export: Culturo

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: Cal Hacks 12.0
- Tagline: Cultural Immersion on Steroids
- Devpost: https://devpost.com/software/culturo-r9yg0p
- GitHub: https://github.com/VibhorN/Culturo
- Video: https://www.youtube.com/embed/0ZGMvzPsD5w?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Dan Chizik (29 commits), Vibhor Narang (5 commits), Tarun Shah (3 commits)

## Devpost submission (written by the team)

### Inspiration

One of the ways that people going about learning about culture is by learning language. This is partially because that is probably the most streamlined way to do so and there are a plethora of resources for language learning. What we wanted to do is different. We want to give users an opportunity to learn to be a local whether that's by exploring the history, music, food, and landmarks from a country or by engaging in conversation with an agent to learn what its like to be a local.

### What it does

WorldWise is an AI cultural immersion companion that delivers personalized snapshots via voice, visual content, and trivia. Voice-first interface — Engage in conversation with a Vapi Voice Agent to learn what it's like to be a local Cultural content feed — movies, news, music, restaurants, and attractions that make a country what it is Real-time trivia — dynamic questions from fetched content; stores memory about their user Agentic orchestration — Spotify, NewsAPI, Reddit, TripAdvisor, Wikipedia, Google Maps etc

### How we built it

Frontend (React), Backend (Python/Flask), Multi-agent framework for coordinated workflows Asynchronous API integration with aiohttp, Health, orchestration, content feed, trivia, and voice endpoints Orchestrator routes user queries, ContentFeed agent gathers real-time data, TriviaAgent generates questions from content; Parallel API calls to reduce latency API integrations: Spotify (local music), NewsAPI (current events), Reddit (slang/community trends), TripAdvisor (restaurants, attractions), Deepgram (multilingual STT), Anthropic Claude Haiku (reasoning), Vapi (Voice AI)

### Challenges we ran into

Integrating the sheer amount of APIs was difficult because each had different types of documentation + different hurdles to cross deepgram + Vapi was difficult because we were trying to include language support beyond just English; this required implementing a language detection script through deepgram and accordingly prompting vapi to respond in that language to come off as more personable ##

### Accomplishments we're proud of

a working MVP for 3 cultures (Japan, Spanish, France) a solid intuitive front end with a content feed, trivia, and voice-first chatbot support for english, spanish, french, and japanese + scalable for other languages Letta Integration that remembers user progress; creates personalized experience for users; key for cultural immersion ##

### What we learned

Technologies: Letta, Vapi, Deepgram, Claude While agentic workflows are always subjected to latency, there are ways to perform simultaneous processing to cut it down A voice first engagement approach makes it more accessible and personable for the user ##

### What's next

Coming out with support for more cultures; our system is designed to be scalable (just have to fully build out the integrations) reducing latency with processing content and setting up the voice agent gathering feedback from users to see if there are other ways to deliver the culturally immersive experience we are passionate about

## README (from the GitHub repository)

# Cultura: Your Cultural Immersion Platformura

Cultura is a comprehensive cultural immersion application that provides rich, **real-time** content about countries including movies, news, music, food, attractions, and interactive trivia. All data is aggregated from multiple APIs and presented in an immersive UI

## Features

### Voice Interface (Vapi + Deepgram)
- Speech recognition using Deepgram for voice input
- Natural voice synthesis for responses
- Real-time voice conversation about cultures and countries

### Content Feed (News API, TripAdvisor API, Spotify API)
- Movie cards with embedded YouTube trailers
- News cards with current events and articles
- Music cards with popular songs and Spotify integration
- Food cards with local cuisine and restaurants
- Attraction cards with landmarks and cultural sites

### Interactive Trivia
- Daily cultural quizzes for selected countries
- Multiple choice questions with immediate feedback
- Adaptive learning system that re-queues incorrect answers
- Completion tracking and progress monitoring

## Architecture

```
[User Selects Country]
   ↓
[Loading Screen with Country Facts]
   ↓
[Backend Orchestration] → [Multi-API Data Aggregation]
   ├── TMDB (Movie Trailers)
   ├── NewsAPI (Current Events)
   ├── Spotify (Music Playlists)
   ├── TripAdvisor (Food & Attractions)
   └── LLM Agents (Trivia Generation)
   ↓
[Country-Themed Snapshot Page]
   ├── Content Feed (Movies, News, Food, Attractions)
   ├── Interactive Trivia Panel
   └── Voice Assistant Interface
```

## Tech Stack

### Backend
- Flask - Python web framework
- Python 3.8+ - Async/await support
- Deepgram - Speech-to-text transcription
- Vapi - Voice assistant and TTS synthesis
- Anthropic Claude - AI reasoning and content generation
- TMDB - Movie trailer data
- Spotify API - Music playlists and trending songs
- NewsAPI - Current events and news
- TripAdvisor API - Food and restaurant data
- Agent-based architecture for content aggregation

### Frontend
- React 
- Styled Components - CSS-in-JS styling
- Framer Motion - Smooth animations and transitions
- Axios

### Infrastructure
- Agent Orchestrator - Coordinates multiple specialized agents
- Deepgram Integration - Real-time speech recognition
- Vapi Integration - Voice assistant capabilities
- TMDB Integration - Movie and trailer data
- Spotify Integration - Music discovery
- NewsAPI Integration - Current events

## Quick Start

### Prerequisites
- Python 3.8+
- Node.js 16+
- API keys for all services (see Configuration)

### Backend Setup

1. **Clone and navigate to backend:**
```bash
cd backend
```

2. **Install dependencies:**
```bash
pip install -r requirements.txt
```

3. **Configure environment variables:**
```bash
cp env.example .env
# Edit .env with your API keys
```

4. **Run the Flask server:**
```bash
python app.py
```

### Frontend Setup

1. **Navigate to frontend:**
```bash
cd frontend
```

2. **Install dependencies:**
```bash
npm install
```

3. **Start the development server:**
```bash
npm start
```

4. **Open your browser:**
```
http://localhost:3000
```

## Configuration

### Required API Keys

Create a `.env` file in the backend directory with the following keys:

```env
# Voice & AI
DEEPGRAM_API_KEY=your_deepgram_api_key
VAPI_API_KEY=your_vapi_api_key
ANTHROPIC_API_KEY=your_anthropic_api_key

# Music & Media
SPOTIFY_CLIENT_ID=your_spotify_client_id
SPOTIFY_CLIENT_SECRET=your_spotify_client_secret
NEWS_API_KEY=your_news_api_key
TMDB_API_KEY=your_tmdb_api_key

# Social & Cultural Data
REDDIT_CLIENT_ID=your_reddit_client_id
REDDIT_CLIENT_SECRET=your_reddit_client_secret

# Tourism & Attractions
TRIPADVISOR_API_KEY=your_tripadvisor_api_key

# Memory & Analytics
LETTA_API_KEY=your_letta_api_key
```

### Getting API Keys

1. Deepgram - Sign up at https://deepgram.com/ for speech-to-text
2. Vapi - Get API key at https://vapi.ai/ for voice synthesis
3. Anthropic - Claude API at https://console.anthropic.com/ for AI reasoning
4. Spotify - Developer Dashboard at https://developer.spotify.com/ for music data
5. NewsAPI - Free tier at https://newsapi.org/ for news data
6. TMDB - Get API key at https://www.themoviedb.org/settings/api for movie trailers
7. Reddit - Reddit API at https://www.reddit.com/prefs/apps for cultural insights
8. TripAdvisor - Developer portal for food and attraction data

## Example Usage

### Voice Interaction
```
User: "Hey, I'm flying to Tokyo next week. Can you teach me the basics?"

Cultura: "Sure! In Japan, a polite greeting is 'Hajimemashite' — it means 'Nice to meet you.'
🇯🇵 The current government is a constitutional monarchy led by Prime Minister Fumio Kishida.
🍣 For food, locals love ramen alleys in Shinjuku and okonomiyaki in Osaka.
🎵 Here's what's trending on Spotify Japan: Fujii Kaze's 'Workin' Hard'.
🗣️ Slang tip: saying 'Yabai!' means 'That's crazy!' — good or bad.
Want to hear about festivals or how to behave at dinner?"
```

## Key Features Explained

### 1. Voice-First Interface
- **Natural Conversation**: Speak naturally, get cultural insights
- **Multilingual Support**: Works in multiple languages
- **Real-time Processing**: Instant cultural data aggregation

### 2. Cultural Intelligence
- **Comprehensive Data**: Government, history, music, food, slang
- **Real-time Updates**: Current news and trending topics
- **Authentic Sources**: Reddit, Wikipedia, official APIs

### 3. Personalized Learning
- **Memory System**: Remembers your interests and progress
- **Adaptive Content**: Adjusts to your learning style
- **Cultural Quizzes**: Interactive learning experiences

### 4. Observability
- **AI Tracing**: Track AI reasoning and decision-making
- **Performance Metrics**: Monitor accuracy and user engagement
- **Continuous Improvement**: Data-driven enhancements

## Development

### Project Structure
```
lingua-cal-hacks/
├── backend/
│   ├── app.py              # Main Flask application
│   ├── integrations.py     # API integration classes
│   ├── requirements.txt    # Python dependencies
│   └── env.example        # Environment configuration
├── frontend/
│   ├── src/
│   │   ├── App.js         # Main React component
│   │   ├── App.css        # Styling
│   │   └── index.js       # Entry point
│   ├── package.json       # Node dependencies
│   └── public/            # Static assets
└── README.md              # This file
```

## Deployment

### Production Setup

1. **Environment Configuration**
```bash
export FLASK_ENV=production
export DATABASE_URL=postgresql://...
export REDIS_URL=redis://...
```

## Acknowledgments

- **Anthropic** - Claude AI for cultural reasoning
- **Deepgram** - Multilingual speech recognition
- **Vapi** - Voice interface platform
- **Spotify** - Music data API
- **NewsAPI** - News aggregation
- **Reddit** - Cultural insights
- **Wikipedia** - Historical data
- **Arize** - AI observability platform

## Contributors

- danchizik@berkeley.edu
- tarunshah@berkeley.edu
- vibhornarang@berkeley.edu
- Cal Hacks for hosting!!

---

## Detected evidence (automated analysis)

Indexed codebase: 68 recognized source files, 508 KB.
- Anthropic (technology) — detected in the code
- CSS (language) — detected in the code
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- JavaScript (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- Redis (technology) — detected in the code

## Codebase structure (from repository index)

### Files (83 of 83)

```
.gitignore
backend/agent_data/MotivationCoach_test_user_123.json
backend/agent_data/MotivationCoach_test_user_comprehensive.json
backend/agent_data/MotivationCoach_test_user_fixed.json
backend/agent_data/MotivationCoach_test_user_offline.json
backend/agent_data/MotivationCoach_test.json
backend/agents/__init__.py
backend/agents/advanced/__init__.py
backend/agents/analysis/__init__.py
backend/agents/analysis/progress_analytics.py
backend/agents/base.py
backend/agents/cognitive/__init__.py
backend/agents/cognitive/motivation_coach.py
backend/agents/content_feed.py
backend/agents/conversation.py
backend/agents/creative/__init__.py
backend/agents/cultural_agents/__init__.py
backend/agents/cultural_agents/cultural_etiquette.py
backend/agents/cultural_context.py
backend/agents/cultural.py
backend/agents/data_retrieval.py
backend/agents/evaluation.py
backend/agents/language_correction.py
backend/agents/language.py
backend/agents/learning/__init__.py
backend/agents/learning/pronunciation_coach.py
backend/agents/learning/vocabulary_builder.py
backend/agents/orchestrator.py
backend/agents/personalization.py
backend/agents/specialized/__init__.py
backend/agents/translation.py
backend/agents/trivia.py
backend/app.py
backend/arize_config.json
backend/arize_dashboard_config.json
backend/configure_keys.sh
backend/core/__init__.py
backend/core/base.py
backend/core/orchestrator.py
backend/env.template
backend/evaluation_tasks.json
backend/integrations.py
backend/integrations/__init__.py
backend/integrations/anthropic.py
backend/integrations/arize_phoenix_tracing.py
backend/integrations/deepgram.py
backend/integrations/letta_trivia.py
backend/integrations/news.py
backend/integrations/reddit.py
backend/integrations/spotify.py
backend/integrations/tmdb.py
backend/integrations/tripadvisor.py
backend/integrations/vapi.py
backend/requirements.txt
backend/utils/__init__.py
backend/utils/log_viewer.py
backend/utils/logging.py
backend/utils/persistence.py
frontend/.gitignore
frontend/package.json
frontend/public/index.html
frontend/public/manifest.json
frontend/public/robots.txt
frontend/src/App.css
frontend/src/App.js
frontend/src/App.test.js
frontend/src/components/cards/AttractionCard.js
frontend/src/components/cards/FoodCard.js
frontend/src/components/cards/MovieCard.js
frontend/src/components/cards/MusicCard.js
frontend/src/components/cards/NewsCard.js
frontend/src/components/CulturalSnapshot.js
frontend/src/components/CulturalSnapshotComplete.js
frontend/src/components/TriviaPanel.js
frontend/src/components/VoiceBoxPlaceholder.js
frontend/src/CulturalSnapshotPage.js
frontend/src/index.css
frontend/src/index.js
frontend/src/reportWebVitals.js
frontend/src/setupTests.js
README.md
setup.sh
start.sh
```

### Dependencies

- backend/requirements.txt: aiohttp@==3.9.1, alembic@==1.13.1, anthropic@==0.7.8, arize-phoenix-otel, asyncio@==3.4.3, celery@==5.3.4, deepgram-sdk@==3.2.7, feedparser@==6.0.10, flask@==3.0.0, flask-cors@==4.0.0, googlemaps@==4.10.0, gunicorn@==21.2.0, httpx@==0.25.2, letta-client@==0.1.324, opentelemetry-api@==1.21.0, opentelemetry-exporter-otlp@==1.21.0, opentelemetry-instrumentation@==0.42b0, opentelemetry-instrumentation-aiohttp-client@==0.42b0, opentelemetry-instrumentation-requests@==0.42b0, opentelemetry-sdk@==1.21.0, praw@==7.7.1, psycopg2-binary@==2.9.9, pydantic@==2.5.0, python-dotenv@==1.0.0, redis@==5.0.1, requests@==2.31.0, spotipy@==2.23.0, sqlalchemy@==2.0.23, vapi-python@==1.0.0, wikipedia@==1.4.0
- frontend/package.json: @testing-library/dom@^10.4.1, @testing-library/jest-dom@^6.9.1, @testing-library/react@^16.3.0, @testing-library/user-event@^13.5.0, @vapi-ai/web@^2.5.0, axios@^1.6.2, framer-motion@^10.16.5, lucide-react@^0.294.0, react@^19.2.0, react-dom@^19.2.0, react-hot-toast@^2.4.1, react-intersection-observer@^9.5.3, react-router-dom@^6.20.1, react-scripts@5.0.1, react-use@^17.4.0, styled-components@^6.1.1, web-vitals@^2.1.4

### Recent commits (newest first)

- Fix trivia generation: Add validation and error handling
- frontend pretty
- tmdb fix
- migrate to phoenix logging
- trivia integrated w voice
- Implemented frontend with backend integration
- Merge branch 'main' of https://github.com/VibhorN/Culturo
- update
- fix spotify import
- update
- spotify and movies
- arize tracing
- vapi + deepgram work somehow
- Complete Deepgram integration with agentic flow - Spanish speech recognition improvements
- spanish works
- pull data correctly
- Merge main and finishing-sources branches with cleanup
- before deleting irrelevant files
- update gitignore
- new agents

## Key source files (fetched from GitHub, selected and truncated for size)

### backend/requirements.txt

```
flask==3.0.0
flask-cors==4.0.0
requests==2.31.0
anthropic==0.7.8
deepgram-sdk==3.2.7
vapi-python==1.0.0
letta-client==0.1.324
python-dotenv==1.0.0
pydantic==2.5.0
httpx==0.25.2
spotipy==2.23.0
wikipedia==1.4.0
praw==7.7.1
feedparser==6.0.10
googlemaps==4.10.0
aiohttp==3.9.1
asyncio==3.4.3
redis==5.0.1
sqlalchemy==2.0.23
alembic==1.13.1
psycopg2-binary==2.9.9
celery==5.3.4
gunicorn==21.2.0
arize-phoenix-otel
opentelemetry-api==1.21.0
opentelemetry-sdk==1.21.0
opentelemetry-instrumentation==0.42b0
opentelemetry-instrumentation-aiohttp-client==0.42b0
opentelemetry-instrumentation-requests==0.42b0
opentelemetry-exporter-otlp==1.21.0

```

### frontend/package.json

```
{
  "name": "lingua",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/dom": "^10.4.1",
    "@testing-library/jest-dom": "^6.9.1",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^13.5.0",
    "@vapi-ai/web": "^2.5.0",
    "axios": "^1.6.2",
    "framer-motion": "^10.16.5",
    "lucide-react": "^0.294.0",
    "react": "^19.2.0",
    "react-dom": "^19.2.0",
    "react-hot-toast": "^2.4.1",
    "react-intersection-observer": "^9.5.3",
    "react-router-dom": "^6.20.1",
    "react-scripts": "5.0.1",
    "react-use": "^17.4.0",
    "styled-components": "^6.1.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

```

### frontend/src/index.js

```javascript
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import CulturalSnapshotPage from './CulturalSnapshotPage';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    {/* Switch between App and CulturalSnapshotPage to test */}
    <CulturalSnapshotPage />
    {/* <App /> */}
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

```

### backend/app.py

```python
# Phoenix tracing MUST be imported FIRST, before any LLM calls
from integrations.arize_phoenix_tracing import tracer_provider, log_agent_evaluation as log_to_phoenix

import os
from flask import Flask, request, jsonify
from flask_cors import CORS
from dotenv import load_dotenv
import requests
import json
import asyncio
from datetime import datetime
import logging
from integrations import (
    DeepgramIntegration, VapiIntegration, SpotifyIntegration,
    NewsAPIIntegration, RedditIntegration, AnthropicIntegration
)
from core.orchestrator import AgentOrchestrator

# Load environment variables
load_dotenv()

app = Flask(__name__)
CORS(app)

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# API Keys and Configuration
DEEPGRAM_API_KEY = os.getenv('DEEPGRAM_API_KEY')
VAPI_API_KEY = os.getenv('VAPI_API_KEY')
ANTHROPIC_API_KEY = os.getenv('ANTHROPIC_API_KEY')
SPOTIFY_CLIENT_ID = os.getenv('SPOTIFY_CLIENT_ID')
SPOTIFY_CLIENT_SECRET = os.getenv('SPOTIFY_CLIENT_SECRET')
NEWS_API_KEY = os.getenv('NEWS_API_KEY')
REDDIT_CLIENT_ID = os.getenv('REDDIT_CLIENT_ID')
REDDIT_CLIENT_SECRET = os.getenv('REDDIT_CLIENT_SECRET')
GOOGLE_MAPS_API_KEY = os.getenv('GOOGLE_MAPS_API_KEY')
LETTA_API_KEY = os.getenv('LETTA_API_KEY')
ARIZE_API_KEY = os.getenv('ARIZE_API_KEY')
TRIPADVISOR_API_KEY = os.getenv('TRIPADVISOR_API_KEY')

# Initialize API integrations
deepgram = DeepgramIntegration(DEEPGRAM_API_KEY) if DEEPGRAM_API_KEY else None
vapi = VapiIntegration(VAPI_API_KEY) if VAPI_API_KEY else None
spotify = SpotifyIntegration(SPOTIFY_CLIENT_ID, SPOTIFY_CLIENT_SECRET) if SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET else None
news_api = NewsAPIIntegration(NEWS_API_KEY) if NEWS_API_KEY else None
reddit = RedditIntegration(REDDIT_CLIENT_ID, REDDIT_CLIENT_SECRET, "WorldWise-CulturalBot/1.0") if REDDIT_CLIENT_ID and REDDIT_CLIENT_SECRET else None
claude = AnthropicIntegration(ANTHROPIC_API_KEY) if ANTHROPIC_API_KEY else None

# Make Anthropic client available globally for Arize evaluations
try:
    import anthropic
    anthropic_client = anthropic.Anthropic(api_key=ANTHROPIC_API_KEY) if ANTHROPIC_API_KEY else None
except ImportError:
    anthropic_client = None

# Phoenix tracing is initialized via import at top of this file
logger.info("✅ Phoenix tracing available for LLM observability")

# Initialize Agent Orchestrator with Anthropic API
try:
    agent_orchestrator = AgentOrchestrator(
        ANTHROPIC_API_KEY,
        NEWS_API_KEY,
        SPOTIFY_CLIENT_ID,
        SPOTIFY_CLIENT_SECRET,
        TRIPADVISOR_API_KEY
    )
    # Pass the Anthropic client to the orchestrator for evaluations
    if agent_orchestrator and anthropic_client:
        agent_orchestrator.anthropic_client = anthropic_client
    logger.info("Agent orchestrator initialized with Anthropic API and all integrations")
except Exception as e:
    logger.warning(f"Failed to initialize agent orchestrator: {str(e)}")
    agent_orchestrator = None

class CulturalDataAggregator:
    """Main class for aggregating cultural data from multiple APIs"""
    
    def __init__(self):
        self.session = requests.Session()
        self.session.headers.update({
            'User-Agent': 'WorldWise-CulturalBot/1.0'
        })
    
    async def get_cultural_data(self, country, language="en"):
        """Main method to gather comprehensive cultural data"""
        try:
            # Parallel API calls for efficiency
            tasks = [
                self.get_government_info(country),
                self.get_news_data(country),
                self.get_music_data(country),
                self.get_food_data(country),
                self.get_slang_data(country),
                self.get_festivals_data(country)
            ]
            
            results = await asyncio.gather(*tasks, return_exceptions=True)
            
            # Process results
            cultural_data = {
                "country": country,
                "language": language,
                "timestamp": datetime.now().isoformat(),
                "government": results[0] if not isinstance(results[0], Exception) else None,
                "news": results[1] if not isinstance(results[1], Exception) else None,
                "music": results[2] if not isinstance(results[2], Exception) else None,
                "food": results[3] if not isinstance(results[3], Exception) else None,
                "slang": results[4] if not isinstance(results[4], Exception) else None,
                "festivals": results[5] if not isinstance(results[5], Exception) else None
            }
            
            return cultural_data
            
        except Exception as e:
            logger.error(f"Error in get_cultural_data: {str(e)}")
            return {"error": str(e)}
    
    async def get_government_info(self, country):
        """Get government and historical information from Wikipedia"""
        try:
            import wikipedia
            wikipedia.set_lang("en")
            
            # Search for country information
            search_results = wikipedia.search(f"{country} government")
            if search_results:
                page = wikipedia.page(search_results[0])
                
                return {
                    "title": page.title,
                    "summary": page.summary[:500] + "..." if len(page.summary) > 500 else page.summary,
                    "url": page.url,
                    "categories": page.categories[:10]  # Limit categories
                }
        except Exception as e:
            logger.error(f"Error getting government info: {str(e)}")
            return None
    
    async def get_news_data(self, country):
        """Get current news from NewsAPI"""
        try:
            if news_api:
                articles = await news_api.get_cultural_news(country)
                if articles:
                    return {
                        "articles": articles,
                        "total_resul
[truncated — 27804 more characters]
```

### frontend/src/App.js

```javascript
import React, { useState, useEffect, useRef } from 'react';
import styled from 'styled-components';
import { motion, AnimatePresence } from 'framer-motion';
import { Mic, MicOff, Volume2, VolumeX, Globe, Music, Utensils, BookOpen, MessageCircle, Calendar } from 'lucide-react';
import toast, { Toaster } from 'react-hot-toast';
import axios from 'axios';
import './App.css';

const AppContainer = styled.div`
  min-height: 100vh;
  background: 
    radial-gradient(circle at 20% 80%, rgba(139, 69, 19, 0.4) 0%, transparent 50%),
    radial-gradient(circle at 80% 20%, rgba(85, 107, 47, 0.3) 0%, transparent 50%),
    radial-gradient(circle at 40% 40%, rgba(101, 67, 33, 0.3) 0%, transparent 50%),
    radial-gradient(circle at 60% 70%, rgba(34, 139, 34, 0.2) 0%, transparent 50%),
    linear-gradient(135deg, #2d5016 0%, #3e6b1e 25%, #4a7c29 50%, #5c8f35 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 2rem;
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
  position: relative;
  overflow-x: hidden;

  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: 
      radial-gradient(circle at 10% 20%, rgba(255, 255, 255, 0.1) 0%, transparent 20%),
      radial-gradient(circle at 90% 80%, rgba(255, 255, 255, 0.05) 0%, transparent 20%),
      radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.03) 0%, transparent 30%),
      url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><defs><pattern id="earth" patternUnits="userSpaceOnUse" width="100" height="100"><circle cx="50" cy="50" r="45" fill="none" stroke="rgba(255,255,255,0.1)" stroke-width="0.5"/><circle cx="30" cy="30" r="8" fill="rgba(34,139,34,0.2)"/><circle cx="70" cy="40" r="6" fill="rgba(0,100,0,0.2)"/><circle cx="20" cy="70" r="10" fill="rgba(70,130,180,0.2)"/><circle cx="80" cy="80" r="7" fill="rgba(32,178,170,0.2)"/></pattern></defs><rect width="100" height="100" fill="url(%23earth)"/></svg>');
    pointer-events: none;
    opacity: 0.3;
  }

  @media (max-width: 768px) {
    padding: 1rem;
  }

  @media (max-width: 480px) {
    padding: 0.5rem;
  }
`;

const Header = styled(motion.div)`
  text-align: center;
  margin-bottom: 3rem;
  color: white;
`;

const Title = styled(motion.h1)`
  font-size: 4rem;
  font-weight: 900;
  margin-bottom: 1rem;
  background: linear-gradient(45deg, #ffffff, #e0e7ff, #c7d2fe, #a5b4fc);
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  text-shadow: 0 0 30px rgba(255, 255, 255, 0.3);
  position: relative;
  
  &::after {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: linear-gradient(45deg, transparent, rgba(255, 255, 255, 0.1), transparent);
    animation: shimmer 3s infinite;
  }
  
  @keyframes shimmer {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(100%); }
  }

  @media (max-width: 768px) {
    font-size: 3rem;
  }

  @media (max-width: 480px) {
    font-size: 2.5rem;
  }
`;

const Subtitle = styled(motion.p)`
  font-size: 1.2rem;
  opacity: 0.9;
  max-width: 600px;
  margin: 0 auto;

  @media (max-width: 768px) {
    font-size: 1rem;
    max-width: 90%;
  }

  @media (max-width: 480px) {
    font-size: 0.9rem;
    max-width: 95%;
  }
`;

const VoiceInterface = styled(motion.div)`
  background: 
    linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%),
    radial-gradient(circle at 50% 50%, rgba(255, 255, 255, 0.1) 0%, transparent 70%);
  backdrop-filter: blur(20px);
  border-radius: 2rem;
  padding: 3rem;
  margin-bottom: 3rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 
    0 8px 32px rgba(0, 0, 0, 0.3),
    inset 0 1px 0 rgba(255, 255, 255, 0.2),
    0 0 0 1px rgba(255, 255, 255, 0.1);
  position: relative;
  
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 2rem;
    background: linear-gradient(135deg, transparent, rgba(255, 255, 255, 0.1), transparent);
    pointer-events: none;
  }

  @media (max-width: 768px) {
    padding: 2rem;
    margin-bottom: 2rem;
  }

  @media (max-width: 480px) {
    padding: 1.5rem;
    margin-bottom: 1.5rem;
    border-radius: 1.5rem;
  }
`;

const VoiceControls = styled.div`
  display: flex;
  gap: 2rem;
  justify-content: center;
  align-items: center;
  margin-bottom: 2rem;

  @media (max-width: 480px) {
    gap: 1rem;
    margin-bottom: 1.5rem;
  }
`;

const VoiceButton = styled(motion.button)`
  width: 90px;
  height: 90px;
  border-radius: 50%;
  border: none;
  background: ${props => props.$active 
    ? 'linear-gradient(135deg, #ff6b6b 0%, #ff5252 100%)' 
    : 'linear-gradient(135deg, rgba(255, 255, 255, 0.2) 0%, rgba(255, 255, 255, 0.1) 100%)'};
  color: white;
  font-size: 2.2rem;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.3s ease;
  backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 
    0 8px 32px rgba(0, 0, 0, 0.2),
    inset 0 1px 0 rgba(255, 255, 255, 0.2);
  position: relative;
  
  &::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    border-radius: 50%;
    background: ${props => props.$active 
      ? 'radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.3) 0%, transparent 50%)'
      : 'radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.1) 0%, transparent 50%)'};
    pointer-events: none;
  }
  
  &:hover {
    transform: scale(1.1);
    background: ${props => props.$active 
      ? 'linear-gradient(135deg, #ff5252 0%, #f44336 100%)' 
      : 'linear-gradient(135deg, rgba(255, 255, 255, 0.3) 0%, rgba(255, 255, 255, 0.2) 100%)'};
    box-shadow: 
      0 12px 40px rgba(0, 0, 0, 0.3),
      inset 0 1px 0 rgba(255, 255, 255, 0.3);
  }
  
  &:active {
    transform: scal
[truncated — 38411 more characters]
```

### start.sh

```shell
#!/bin/bash

# WorldWise Start Script
# Starts both backend and frontend servers

echo "🌍 Starting WorldWise..."

# Function to kill processes on specific ports
kill_port() {
    local port=$1
    local pids=$(lsof -ti:$port 2>/dev/null)
    if [ ! -z "$pids" ]; then
        echo "🛑 Killing processes on port $port (PIDs: $pids)"
        kill -9 $pids 2>/dev/null
        sleep 1
    else
        echo "✅ Port $port is free"
    fi
}

# Function to kill background processes on exit
cleanup() {
    echo ""
    echo "🛑 Shutting down WorldWise..."
    kill $BACKEND_PID $FRONTEND_PID 2>/dev/null
    exit 0
}

# Set up signal handlers
trap cleanup SIGINT SIGTERM

# Kill any existing processes on our ports
echo "🔍 Checking for existing processes..."
kill_port 3000  # Frontend port
kill_port 5001  # Backend port

echo ""
echo "🚀 Starting fresh servers..."

# Start backend
echo "🚀 Starting backend server..."
cd backend
python3 app.py &
BACKEND_PID=$!
cd ..

# Wait a moment for backend to start
sleep 3

# Start frontend
echo "🚀 Starting frontend server..."
cd frontend
npm start &
FRONTEND_PID=$!
cd ..

echo ""
echo "✅ WorldWise is running!"
echo ""
echo "🌐 Frontend: http://localhost:3000"
echo "🔧 Backend:  http://localhost:5001"
echo ""
echo "Press Ctrl+C to stop both servers"

# Wait for processes
wait $BACKEND_PID $FRONTEND_PID

```

### setup.sh

```shell
#!/bin/bash

# WorldWise Startup Script
# This script helps you get WorldWise up and running quickly

echo "🌍 Welcome to WorldWise - Cultural Immersion Companion!"
echo "=================================================="

# Check if Python is installed
if ! command -v python3 &> /dev/null; then
    echo "❌ Python 3 is required but not installed."
    echo "Please install Python 3.8+ and try again."
    exit 1
fi

# Check if Node.js is installed
if ! command -v node &> /dev/null; then
    echo "❌ Node.js is required but not installed."
    echo "Please install Node.js 16+ and try again."
    exit 1
fi

echo "✅ Python and Node.js are installed"

# Check if we're in the right directory
if [ ! -f "backend/app.py" ] || [ ! -f "frontend/package.json" ]; then
    echo "❌ Please run this script from the project root directory"
    echo "Expected structure:"
    echo "  backend/app.py"
    echo "  frontend/package.json"
    exit 1
fi

echo "✅ Project structure looks good"

# Setup backend
echo ""
echo "🔧 Setting up backend..."
cd backend

# Create virtual environment if it doesn't exist
if [ ! -d ".venv" ]; then
    echo "Creating Python virtual environment..."
    python3 -m venv .venv
fi

# Activate virtual environment
echo "Activating virtual environment..."
source .venv/bin/activate

# Install dependencies
echo "Installing Python dependencies..."
.venv/bin/pip install -r requirements.txt

# Check for .env file
if [ ! -f ".env" ]; then
    echo "⚠️  No .env file found. Creating from template..."
    cp env.example .env
    echo "📝 Please edit backend/.env with your API keys"
    echo "   Required keys: DEEPGRAM_API_KEY, VAPI_API_KEY, ANTHROPIC_API_KEY"
    echo "   Optional keys: SPOTIFY_CLIENT_ID, NEWS_API_KEY, REDDIT_CLIENT_ID"
fi

cd ..

# Setup frontend
echo ""
echo "🔧 Setting up frontend..."
cd frontend

# Install dependencies
echo "Installing Node.js dependencies..."
npm install --legacy-peer-deps

cd ..

echo ""
echo "🎉 Setup complete!"
echo ""
echo "To start WorldWise:"
echo "1. Edit backend/.env with your API keys"
echo "2. Run: ./start.sh"
echo ""
echo "Or start manually:"
echo "  Backend:  cd backend && .venv/bin/python3 app.py"
echo "  Frontend: cd frontend && npm start"
echo ""
echo "🌍 Happy cultural exploring!"

```

### backend/configure_keys.sh

```shell
#!/bin/bash

# WorldWise API Key Configuration Script
echo "🔑 Configuring WorldWise API Keys..."
echo "=================================="

# Backup original .env file
cp .env .env.backup
echo "✅ Backed up original .env file"

# Update API keys
sed -i '' 's/DEEPGRAM_API_KEY=your_deepgram_api_key_here/DEEPGRAM_API_KEY=7a2884444ff84cfd012c51d735c625f28ed795f9/' .env
sed -i '' 's/VAPI_API_KEY=your_vapi_api_key_here/VAPI_API_KEY=f4bad5d9-d539-4221-9a0d-7bb23f5c2714/' .env
sed -i '' 's/SPOTIFY_CLIENT_ID=your_spotify_client_id_here/SPOTIFY_CLIENT_ID=3ce9549537a143c98497d39116f394e3/' .env
sed -i '' 's/SPOTIFY_CLIENT_SECRET=your_spotify_client_secret_here/SPOTIFY_CLIENT_SECRET=c2d098d1a8904bffa30fa1a51f548c59/' .env
sed -i '' 's/NEWS_API_KEY=your_news_api_key_here/NEWS_API_KEY=f3aac734705041efb7a4c82a36fa409a/' .env
sed -i '' 's/REDDIT_CLIENT_ID=your_reddit_client_id_here/REDDIT_CLIENT_ID=8F6j9FkVdstAi4xXM0YxFg/' .env
sed -i '' 's/REDDIT_CLIENT_SECRET=your_reddit_client_secret_here/REDDIT_CLIENT_SECRET=wBqTzC0mG8fO857xyR4sm9ltSddw_A/' .env

echo "✅ API keys configured successfully!"
echo ""
echo "🔍 Verifying configuration..."
echo "============================="

# Check which keys are configured
echo "✅ Deepgram API Key: $(grep DEEPGRAM_API_KEY .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ Vapi API Key: $(grep VAPI_API_KEY .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ Spotify Client ID: $(grep SPOTIFY_CLIENT_ID .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ Spotify Client Secret: $(grep SPOTIFY_CLIENT_SECRET .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ NewsAPI Key: $(grep NEWS_API_KEY .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ Reddit Client ID: $(grep REDDIT_CLIENT_ID .env | cut -d'=' -f2 | cut -c1-10)..."
echo "✅ Reddit Client Secret: $(grep REDDIT_CLIENT_SECRET .env | cut -d'=' -f2 | cut -c1-10)..."

echo ""
echo "⚠️  Still need:"
echo "   - Anthropic Claude API Key (for AI reasoning)"
echo "   - Google Maps API Key (optional)"
echo "   - Letta API Key (optional)"
echo "   - Arize API Key (optional)"
echo ""
echo "🚀 Ready to test! Run: python3 ../test_system.py"

```

### backend/core/__init__.py

```python
"""
Core system components for WorldWise
"""

from .base import BaseAgent, AgentMessage, AgentResponse
from .orchestrator import AgentOrchestrator

__all__ = ['BaseAgent', 'AgentMessage', 'AgentResponse', 'AgentOrchestrator']

```

### frontend/src/setupTests.js

```javascript
// jest-dom adds custom jest matchers for asserting on DOM nodes.
// allows you to do things like:
// expect(element).toHaveTextContent(/react/i)
// learn more: https://github.com/testing-library/jest-dom
import '@testing-library/jest-dom';

```

[52 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]