# Project export: BetterLyfe

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: UC Berkeley AI Hackathon 2025
- Tagline: Navigating social services is confusing, especially in times of crisis. We're building an AI-powered assistant that acts as a digital safety net.
- Devpost: https://devpost.com/software/betterlyf
- GitHub: https://github.com/1300Sarthak/Helper
- Team: 2 GitHub contributor(s) — Sarthak Sethi (17 commits), tanzilahmed0 (6 commits)

## Devpost submission (written by the team)

### Inspiration

We've all seen how difficult it can be for people facing serious hardships—like homelessness, addiction, or food insecurity—to find the help they need. The systems in place are often fragmented, confusing, and overwhelming to navigate. We were inspired to build something that could act as a compassionate first point of contact. We imagined a tool that could instantly provide clear, empathetic guidance, 24/7, to someone in crisis, bridging the gap between needing help and getting it. We wanted to create a digital safety net that wasn't just a directory, but a genuine companion on the path to stability.

### What it does

BetterLyf is an AI-powered life assistant designed to provide immediate, personalized support to vulnerable individuals. Through a simple, voice-enabled chat interface, users can: Get Connected to Local Resources: Tell the app their situation (e.g., "I'm homeless in Oakland"), and it instantly provides a formatted list of nearby shelters, food banks, or clinics, complete with contact information and access instructions. Receive Empathetic Coaching: The AI has a "Life Coach" mode that offers motivational support and practical advice, helping users break down overwhelming problems into manageable steps. Experience a Judgment-Free Conversation: The platform is built on a foundation of empathy and trauma-informed principles, ensuring users feel safe and understood, not judged. View and Manage Resources: A comprehensive admin dashboard allows case workers or administrators to monitor conversations, view user needs, and see how the system is being used in real-time.

### How we built it

BetterLyf is built on a modern, robust tech stack designed for scalability and real-time interaction: Backend: We used Python with the Flask framework to create a lightweight and powerful API. This handles all the core logic, from user management to AI orchestration. AI & Language Models: The "brains" of our operation is Google's Gemini, which we use for all conversational AI. We spent significant time on prompt engineering to create our distinct "coach" and "resource assistant" personalities. Database: We used SQLite for its simplicity and ease of use in storing user data and conversation histories, all managed through SQLAlchemy. Frontend: The user interface is built with standard HTML, CSS, and JavaScript, ensuring it's accessible and responsive. The chat interface is designed to be clean, intuitive, and easy to use, even for non-technical users.

### Challenges we ran into

One of our biggest challenges was balancing empathy with efficiency in the AI's responses. Initially, the AI was either too direct and robotic, or too verbose and not actionable enough. It took many iterations of prompt engineering to find the right voice—one that is compassionate but also provides clear, direct help. Another hurdle was maintaining conversational context. Early versions of the bot would "forget" what the user said just a few messages ago. We had to implement a robust system for storing and retrieving conversation history with every API call, which made the AI significantly smarter and the conversations feel much more natural. Finally, we learned that user experience is paramount. We started with an optional user information form, but quickly realized that making it mandatory was essential for the AI to provide truly personalized and effective guidance right from the start.

### Accomplishments we're proud of

We are incredibly proud of creating an AI that feels genuinely human and helpful. The ability of the "Life Coach" to provide empathetic, non-judgmental support is something we believe can make a real difference. Building the dual-mode personality—switching between a resourceful assistant and a motivational coach—was a complex undertaking, and we're thrilled with how it turned out. It allows the user to get exactly the kind of help they need at any given moment. Finally, getting the full-featured admin dashboard up and running was a major accomplishment. It provides a powerful tool for monitoring the system and understanding user needs on a broader scale, which is essential for any organization that would implement this.

### What we learned

This project was a deep dive into the practical application of large language models for social good. We learned that the "magic" of AI is really in the details—the careful crafting of prompts, the thoughtful management of conversation history, and the relentless focus on the end user's emotional state. We also learned that building a tool for people in crisis comes with a heavy responsibility. Every design choice, from the color of a button to the wording of a prompt, has to be made with empathy and a trauma-informed perspective.

### What's next

for BetterLyf The journey for BetterLyf is just beginning. Our next steps are focused on expanding its impact and capabilities: Maps Integration: We plan to integrate Google Maps to visually show users where resources are located and provide real-time directions. Proactive Email Support: We want to build a system that can automatically email users a summary of the resources they discussed, so they have a permanent record. Guided Journaling: We envision a feature where users can journal their thoughts and feelings, and the AI can provide supportive analysis and track their emotional progress over time. Expanding the Resource Database: We aim to continuously expand and verify our database of local services to ensure our users are always getting the most accurate and up-to-date information.

## README (from the GitHub repository)

# CAG Chatbot Flask API

A Flask-based REST API for a CAG (Context-Aware Generation) chatbot system.

## Features

- RESTful API endpoints for chat interactions
- Chat history management
- User session handling
- Configurable CAG integration
- CORS support for frontend integration
- Comprehensive error handling and logging

## Project Structure

```
.
├── app.py              # Main Flask application
├── config.py           # Configuration management
├── cag_service.py      # CAG chatbot service layer
├── requirements.txt    # Python dependencies
└── README.md          # This file
```

## Setup Instructions

### 1. Install Dependencies

```bash
pip install -r requirements.txt
```

### 2. Environment Configuration

Create a `.env` file in the root directory with the following variables:

```env
# Flask Configuration
SECRET_KEY=your-secret-key-here
DEBUG=True
PORT=5000

# CAG Chatbot Configuration
CAG_API_KEY=your-cag-api-key
CAG_MODEL_NAME=your-model-name
CAG_API_URL=https://api.cag.example.com

# Logging Configuration
LOG_LEVEL=INFO
```

### 3. Run the Application

#### Development Mode

```bash
python app.py
```

#### Production Mode

```bash
gunicorn -w 4 -b 0.0.0.0:5000 app:app
```

The application will be available at `http://localhost:5000`

## API Endpoints

### Health Check

- **GET** `/`
- Returns application status

### Chat Endpoints

#### Send Message

- **POST** `/api/chat`
- **Body:**
  ```json
  {
    "message": "Hello, how are you?",
    "user_id": "user123"
  }
  ```
- **Response:**
  ```json
  {
    "response": "Hello! I'm doing well, thank you for asking.",
    "user_id": "user123",
    "timestamp": "2024-01-01T12:00:00"
  }
  ```

#### Get Chat History

- **GET** `/api/chat/history?user_id=user123`
- **Response:**
  ```json
  {
    "chat_history": [
      {
        "user_id": "user123",
        "message": "Hello",
        "timestamp": "2024-01-01T12:00:00",
        "type": "user"
      },
      {
        "user_id": "bot",
        "message": "Hello! How can I help you?",
        "timestamp": "2024-01-01T12:00:01",
        "type": "bot"
      }
    ],
    "total_messages": 2
  }
  ```

#### Clear Chat History

- **POST** `/api/chat/clear`
- **Body:**
  ```json
  {
    "user_id": "user123"
  }
  ```
- **Response:**
  ```json
  {
    "message": "Chat history cleared for user user123",
    "remaining_messages": 0
  }
  ```

## CAG Integration

The application includes a placeholder CAG service in `cag_service.py`. To integrate with your actual CAG system:

1. Update the `CAGService.generate_response()` method in `cag_service.py`
2. Configure your CAG API credentials in the environment variables
3. Implement the actual API calls to your CAG system

### Example CAG Integration

```python
def generate_response(self, message: str, user_id: str, context: Optional[Dict[str, Any]] = None) -> str:
    payload = {
        'message': message,
        'user_id': user_id,
        'model': self.model_name,
        'context': context or {}
    }

    headers = {
        'Authorization': f'Bearer {self.api_key}',
        'Content-Type': 'application/json'
    }

    response = requests.post(
        f"{self.api_url}/generate",
        json=payload,
        headers=headers,
        timeout=30
    )
    response.raise_for_status()
    return response.json()['response']
```

## Development

### Adding New Endpoints

1. Add your route in `app.py`
2. Implement proper error handling
3. Add logging for debugging
4. Update this README with endpoint documentation

### Testing

You can test the API using curl or any HTTP client:

```bash
# Health check
curl http://localhost:5000/

# Send a message
curl -X POST http://localhost:5000/api/chat \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello", "user_id": "test_user"}'

# Get chat history
curl http://localhost:5000/api/chat/history?user_id=test_user
```

## Deployment

### Docker (Optional)

Create a `Dockerfile`:

```dockerfile
FROM python:3.9-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]
```

### Environment Variables for Production

- Set `DEBUG=False`
- Use a strong `SECRET_KEY`
- Configure your CAG API credentials
- Set appropriate `LOG_LEVEL`

## Error Handling

The application includes comprehensive error handling:

- 400: Bad Request (missing required fields)
- 404: Not Found (invalid endpoints)
- 500: Internal Server Error (server-side issues)

All errors return JSON responses with descriptive messages.

## Logging

The application uses Python's logging module with configurable log levels. Logs include:

- Incoming requests
- CAG API interactions
- Error conditions
- Application startup/shutdown

## Security Considerations

- CORS is enabled for frontend integration
- Input validation on all endpoints
- Environment variable configuration for sensitive data
- Error messages don't expose internal system details

## Contributing

1. Follow the existing code structure
2. Add proper error handling and logging
3. Update documentation for new features
4. Test your changes thoroughly


## Detected evidence (automated analysis)

Indexed codebase: 40 recognized source files, 750 KB.
- Flask (technology) — detected in the code
- HTML (language) — detected in the code
- Python (language) — detected in the code

## Codebase structure (from repository index)

### Files (44 of 44)

```
.gitignore
ADMIN_PORTAL_GUIDE.md
app.py
architecture.md
ask.md 
codebase.md
config.py
ENHANCED_FORMATTING_GUIDE.md
GEMINI_MIGRATION.md
index.html
lol.txt
MICROPHONE_GUIDE.md
MODE_SWITCHING_GUIDE.md
models/__init__.py
models/conversation.py
models/journal.py
models/resource.py
models/session.py
models/user.py
README.md
requirements.txt
routes/__init__.py
routes/admin.py
routes/chat.py
routes/resources.py
routes/voice.py
services/__init__.py
services/claude_service_backup.py
services/claude_service_old.py
services/claude_service.py
services/email_service.py
services/gemini_service.py
services/rag_pipeline.py
templates/admin_dashboard.html
test_api.py
test_cag_rag.py
test_chat_endpoint.py
test_claude.py
test_formatting.html
test_gemini.py
test_microphone.html
test_models.py
utils/__init__.py
utils/formatters.py
```

### Dependencies

- requirements.txt: Flask@==2.3.3, Flask-CORS@==4.0.0, Flask-SQLAlchemy@==3.0.5, python-dotenv@==1.0.0, requests@==2.31.0

### Recent commits (newest first)

- bro
- Merge partner's changes with conversation deletion feature
- Fixed bugs
- Merge branch 'new' of https://github.com/1300Sarthak/Helper into new
- full commit 3;14 am
- Added Delete Functionality to Conversations
- Added real time user management to admin portal
- Merge branch 'new' of https://github.com/1300Sarthak/Helper into new
- added speaker ts
- Complete Admin Portal Created
- admin portal added
- Fixed null error
- micophone wokrs
- lol
- gemini now
- claude
- 7:23 pm (claude)
- Implemented CAG and RAG
- Created User and Conversation model
- Implemented Claude API

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

### GEMINI_MIGRATION.md

```markdown
# Claude to Gemini Migration

## Overview

Successfully migrated all API functionality from Claude to Gemini API. The system now uses Google's Gemini as the primary AI assistant for all operations.

## Changes Made

### 1. Services Updated

- **`services/gemini_service.py`**: Enhanced to include complete AI assistant functionality
  - Added `get_support_response()` function (previously Claude-only)
  - Added system prompts for "empathetic_coach" and "direct_assistant" modes
  - Integrated RAG pipeline support
  - Enhanced with user context handling
  - Maintained existing journal analysis and emotion scoring capabilities

### 2. Routes Updated

- **`routes/chat.py`**: Changed imports from `claude_service` to `gemini_service`
- Updated all function calls and comments to reference Gemini instead of Claude

### 3. Configuration Updated

- **`config.py`**: Added `GEMINI_API_KEY` configuration
- Maintained legacy CAG configuration for compatibility

### 4. Documentation Updated

- **`architecture.md`**: Updated AI orchestration section to reflect Gemini as primary AI
- Updated service descriptions and flow diagrams
- Removed Claude-specific references

### 5. RAG Pipeline Enhanced

- **`services/rag_pipeline.py`**: Added `format_resources_for_gemini()` method

### 6. Testing

- **`test_gemini.py`**: Created new comprehensive test file for Gemini integration
- **`test_chat_endpoint.py`**: Updated references to Gemini
- **`test_claude.py`**: Kept for legacy compatibility

## New Functionality

### Dual Prompt Types

The Gemini service now supports two interaction modes:

1. **empathetic_coach** (default): Warm, supportive, counselor-like responses
2. **direct_assistant**: Clear, step-by-step, no-nonsense guidance

### Enhanced Context Integration

- User location, situation, and needs are now fully integrated into prompts
- RAG pipeline results are formatted and provided as context to Gemini
- Greeting detection for natural conversation flow

## Environment Variables Required

```bash
# Required for Gemini functionality
GEMINI_API_KEY=your_gemini_api_key_here

# Optional legacy
CAG_API_KEY=your_cag_api_key_here
```

## API Endpoints

All existing endpoints remain the same but now use Gemini:

- `POST /api/chat/message` - Main chat interface
- `POST /api/chat/analyze-journal` - Journal analysis
- `GET /api/chat/summarize/<user_id>` - Conversation summarization
- `POST /api/chat/resources` - Resource retrieval

## Testing

Run the new Gemini tests:

```bash
python test_gemini.py
```

## Benefits of Migration

1. **Cost Efficiency**: Gemini typically offers better pricing than Claude
2. **Unified Service**: All AI functionality now handled by single service
3. **Enhanced Capabilities**: Gemini's multimodal capabilities ready for future features
4. **Better Integration**: Designed specifically for Google's ecosystem

## Backward Compatibility

- All existing API endpoints work identically
- Function signatures unchanged
- Database schema unchanged
- Fronten
[truncated — 22 more characters]
```

### architecture.md

```markdown
File and Folder Structure
social_change_app/
│
├── frontend/ # Mobile + Web app (React + Tailwind + Glass UI style)
│ ├── public/ # Static assets
│ ├── src/
│ │ ├── assets/ # Fonts, icons, images
│ │ ├── components/ # Shared UI: buttons, input fields, modals
│ │ ├── pages/ # Screens: Home, VoiceChat, ResourcesMap, Journal, Coach
│ │ ├── features/
│ │ │ ├── voiceAssistant/ # Browser-based voice input (Web Speech API)
│ │ │ ├── mapView/ # Google Maps resource overlay
│ │ │ ├── mentorChat/ # AI chat w/ motivational interviewing
│ │ │ └── journalLog/ # Guided journaling + emotion scoring
│ │ ├── services/ # Axios-based API calls to backend
│ │ ├── state/ # Zustand or Redux store (user, session, map state)
│ │ └── App.tsx # Main app layout
│ └── tailwind.config.js
│
├── backend/ # Python Flask backend with AI orchestration
│ ├── app.py # Main Flask entry point
│ ├── config.py # ENV configs, DB URIs, API keys
│ ├── requirements.txt
│ ├── .env # Claude, Gemini, Gmail, DB creds
│ ├── models/
│ │ ├── user.py # User info schema
│ │ ├── journal.py # Daily logs from journaling/chat
│ │ ├── resource.py # Food banks, shelters, clinics
│ │ └── session.py # LLM session + conversation memory
│ ├── routes/
│ │ ├── chat.py # /api/chat – AI chat endpoints
│ │ ├── resources.py # /api/resources – Location-based service listings
│ │ └── voice.py # /api/voice – basic speech-to-text handler (if needed)
│ ├── services/
│ │ ├── gemini_service.py # Gemini AI calls, complete assistant functionality
│ │ ├── email_service.py # Gmail API – sends support emails to users
│ │ └── rag_pipeline.py # Custom RAG pipeline for nearby resources
│ └── utils/
│ ├── formatters.py # Clean display text, time helpers
│

How Services Connect
graph TD
MobileUser -->|Mic Input (Web Speech API)| VoiceAssistant
VoiceAssistant -->|Transcript| FrontendChat
FrontendChat -->|API Call| FlaskBackend
FlaskBackend -->|Gemini Prompt| GeminiService
FlaskBackend -->|Resource Info| RAGPipeline
FlaskBackend -->|Gmail API| EmailService
FlaskBackend -->|Sends Back| MobileUI

State Management
Frontend:
User State: Anonymous or persistent (name, location, preferences)

Session State: Current AI chat memory (stored in local/session + backend)

Resource Data: Live location-based service listings

Emotion State: For personalized content in journal and coaching

Backend:
MongoDB: Journaling data, conversation logs

PostgreSQL: Resource locations, availability (e.g., # beds/meals)

In-Memory (Redis optional): AI chat memory, temp context for speech input

🤖 AI Orchestration
Gemini
Primary AI assistant for:

Personalized assistant interactions

Warm info delivery

Motivational interviewing-style coaching

Email-ready summaries of resources

Summarizes journal entries

Scores tone (distress, motivation, positivity)

Adds feedback suggestions for user support

RAG Pipeline
Pulls best-fit local services based on:

Geolocation

Past resource usage

Confidence scoring

Can generate smart outputs like:

“There’s a women’s she
[truncated — 810 more characters]
```

### requirements.txt

```
Flask==2.3.3
Flask-CORS==4.0.0
Flask-SQLAlchemy==3.0.5
python-dotenv==1.0.0
requests==2.31.0 
```

### app.py

```python
from flask import Flask, jsonify, redirect, send_from_directory
from flask_cors import CORS
import os
from datetime import datetime
import logging
from config import config
from models.user import db, User
from models.conversation import Conversation
from routes.chat import chat_bp
from routes.admin import admin_bp

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

app = Flask(__name__)

# Enable CORS for frontend connection
CORS(app, origins=["http://localhost:8000", "http://127.0.0.1:8000",
     "http://localhost:5001", "http://127.0.0.1:5001"])

# Load configuration
config_name = os.environ.get('FLASK_ENV', 'default')
app_config = config[config_name]
app.config.from_object(app_config)

# Configure SQLite database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///social_change_app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

# Initialize database
db.init_app(app)

# Register blueprints
app.register_blueprint(chat_bp)
app.register_blueprint(admin_bp)

# Create tables
with app.app_context():
    db.create_all()


@app.route('/')
def home():
    """Serve the frontend HTML file"""
    return send_from_directory('.', 'index.html')


@app.route('/ping')
def ping():
    """Ping endpoint for Task 1"""
    return jsonify({'status': 'ok'})


@app.route('/admin')
def admin_redirect():
    """Redirect /admin to /admin/"""
    return redirect('/admin/')


@app.errorhandler(404)
def not_found(error):
    return jsonify({
        'error': 'Endpoint not found'
    }), 404


@app.errorhandler(500)
def internal_error(error):
    return jsonify({
        'error': 'Internal server error'
    }), 500


if __name__ == '__main__':
    port = app_config.PORT
    logger.info(f"Starting Social Change Helper API on port {port}")
    app.run(host='0.0.0.0', port=port, debug=app_config.DEBUG)

```

### config.py

```python
import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()


class Config:
    """Base configuration class"""
    SECRET_KEY = os.environ.get('SECRET_KEY', None)  # Optional for basic API
    DEBUG = os.environ.get('DEBUG', 'True').lower() == 'true'
    PORT = int(os.environ.get('PORT', 5001))

    # Gemini API Configuration
    GEMINI_API_KEY = os.environ.get('GEMINI_API_KEY', None)

    # Legacy CAG Configuration (if needed)
    CAG_API_KEY = os.environ.get('CAG_API_KEY', None)
    CAG_MODEL_NAME = os.environ.get('CAG_MODEL_NAME', 'default-model')
    CAG_API_URL = os.environ.get('CAG_API_URL', 'https://api.cag.example.com')

    # Database Configuration (if needed)
    DATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///chatbot.db')
    REDIS_URL = os.environ.get('REDIS_URL', 'redis://localhost:6379')

    # Logging Configuration
    LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO')


class DevelopmentConfig(Config):
    """Development configuration"""
    DEBUG = True


class ProductionConfig(Config):
    """Production configuration"""
    DEBUG = False


class TestingConfig(Config):
    """Testing configuration"""
    TESTING = True
    DEBUG = True


# Configuration dictionary
config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'testing': TestingConfig,
    'default': DevelopmentConfig
}

```

### test_claude.py

```python
#!/usr/bin/env python3
"""
Test script for Claude API integration (Task 3)
"""

from services.claude_service import get_support_response
import os
import sys
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()


def test_claude_integration():
    """Test the get_support_response function"""
    print("🧪 Testing Claude API Integration (Task 3)")
    print("=" * 50)

    # Test message
    test_message = "I'm having trouble finding food today and don't know where to turn for help."

    # Test context
    test_context = {
        'location': 'San Francisco, CA',
        'situation': 'experiencing food insecurity',
        'needs': 'food assistance'
    }

    print(f"📝 Test Message: {test_message}")
    print(f"📍 Test Context: {test_context}")
    print("\n🤖 Claude Response:")
    print("-" * 30)

    try:
        # Call the get_support_response function
        response = get_support_response(test_message, test_context)
        print(response)
        print("-" * 30)
        print("✅ Claude integration test completed successfully!")

        # Check if we got a fallback response (indicating no API key)
        if "trouble connecting to my full capabilities" in response:
            print("\n⚠️  Note: Using fallback response (CLAUDE_API_KEY not configured)")
            print("To test with actual Claude API:")
            print("1. Set CLAUDE_API_KEY environment variable")
            print("2. Run: export CLAUDE_API_KEY=your_api_key")
            print("3. Run this test again")
        else:
            print("\n🎉 Successfully connected to Claude API!")

    except Exception as e:
        print(f"❌ Error testing Claude integration: {str(e)}")
        return False

    return True


def test_without_context():
    """Test the function without context"""
    print("\n🧪 Testing without context...")
    test_message = "Hello, I need some help."

    try:
        response = get_support_response(test_message)
        print(f"Response: {response[:100]}...")
        print("✅ Test without context passed!")
    except Exception as e:
        print(f"❌ Error: {str(e)}")


if __name__ == "__main__":
    print("Starting Claude API Integration Tests...\n")

    # Test with context
    success = test_claude_integration()

    # Test without context
    test_without_context()

    print(f"\n{'='*50}")
    if success:
        print("🎯 Task 3 Requirements Met:")
        print("✅ Created claude_service.py in services/")
        print("✅ Function get_support_response(message, context) implemented")
        print("✅ Test message processed and Claude response returned")
        print("\n🚀 Ready for Task 4!")
    else:
        print("❌ Some tests failed. Please check the implementation.")

```

### test_gemini.py

```python
#!/usr/bin/env python3
"""
Test script for Gemini API integration (Task 3)
"""

from services.gemini_service import get_support_response
import os
import sys
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()


def test_gemini_integration():
    """Test the get_support_response function"""
    print("🧪 Testing Gemini API Integration (Task 3)")
    print("=" * 50)

    # Test message
    test_message = "I'm having trouble finding food today and don't know where to turn for help."

    # Test context
    test_context = {
        'location': 'San Francisco, CA',
        'situation': 'experiencing food insecurity',
        'needs': 'food assistance'
    }

    print(f"📝 Test Message: {test_message}")
    print(f"📍 Test Context: {test_context}")
    print("\n🤖 Gemini Response:")
    print("-" * 30)

    try:
        # Call the get_support_response function
        response = get_support_response(test_message, test_context)
        print(response)
        print("-" * 30)
        print("✅ Gemini integration test completed successfully!")

        # Check if we got a fallback response (indicating no API key)
        if "unable to access my full capabilities" in response:
            print("\n⚠️  Note: Using fallback response (GEMINI_API_KEY not configured)")
            print("To test with actual Gemini API:")
            print("1. Set GEMINI_API_KEY environment variable")
            print("2. Run: export GEMINI_API_KEY=your_api_key")
            print("3. Run this test again")
        else:
            print("\n🎉 Successfully connected to Gemini API!")

    except Exception as e:
        print(f"❌ Error testing Gemini integration: {str(e)}")
        return False

    return True


def test_without_context():
    """Test the function without context"""
    print("\n🧪 Testing without context...")
    test_message = "Hello, I need some help."

    try:
        response = get_support_response(test_message)
        print(f"Response: {response[:100]}...")
        print("✅ Test without context passed!")
    except Exception as e:
        print(f"❌ Error: {str(e)}")


def test_prompt_types():
    """Test different prompt types"""
    print("\n🧪 Testing different prompt types...")
    test_message = "I need help with housing."
    test_context = {'location': 'Oakland, CA', 'situation': 'homeless'}

    # Test empathetic coach
    print("\n🤗 Testing empathetic_coach prompt:")
    response = get_support_response(
        test_message, test_context, "empathetic_coach")
    print(f"Response: {response[:150]}...")

    # Test direct assistant
    print("\n📋 Testing direct_assistant prompt:")
    response = get_support_response(
        test_message, test_context, "direct_assistant")
    print(f"Response: {response[:150]}...")

    print("✅ Prompt type tests completed!")


if __name__ == "__main__":
    print("Starting Gemini API Integration Tests...\n")

    # Test with context
    success = test_gemini_integration()

    # Test without context
    test_without_context()

    # Test prompt types
    test_prompt_types()

    print(f"\n{'='*50}")
    if success:
        print("🎯 Task 3 Requirements Met:")
        print("✅ Created gemini_service.py in services/")
        print("✅ Function get_support_response(message, context) implemented")
        print("✅ Test message processed and Gemini response returned")
        print("\n🚀 Ready for Task 4!")
    else:
        print("❌ Some tests failed. Please check the implementation.")

```

### test_api.py

```python
#!/usr/bin/env python3
"""
Simple test script for the CAG Chatbot Flask API
"""

import requests
import json
import time

BASE_URL = "http://localhost:5000"


def test_health_check():
    """Test the health check endpoint"""
    print("Testing health check...")
    try:
        response = requests.get(f"{BASE_URL}/")
        if response.status_code == 200:
            data = response.json()
            print(f"✅ Health check passed: {data['message']}")
            return True
        else:
            print(f"❌ Health check failed: {response.status_code}")
            return False
    except requests.exceptions.ConnectionError:
        print("❌ Could not connect to the API. Make sure the Flask app is running.")
        return False


def test_chat_endpoint():
    """Test the chat endpoint"""
    print("\nTesting chat endpoint...")
    try:
        payload = {
            "message": "Hello, this is a test message",
            "user_id": "test_user_123"
        }

        response = requests.post(
            f"{BASE_URL}/api/chat",
            json=payload,
            headers={"Content-Type": "application/json"}
        )

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Chat endpoint passed")
            print(f"   Response: {data['response']}")
            print(f"   User ID: {data['user_id']}")
            return True
        else:
            print(f"❌ Chat endpoint failed: {response.status_code}")
            print(f"   Error: {response.text}")
            return False
    except Exception as e:
        print(f"❌ Chat endpoint error: {str(e)}")
        return False


def test_chat_history():
    """Test the chat history endpoint"""
    print("\nTesting chat history endpoint...")
    try:
        response = requests.get(
            f"{BASE_URL}/api/chat/history?user_id=test_user_123")

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Chat history endpoint passed")
            print(f"   Total messages: {data['total_messages']}")
            return True
        else:
            print(f"❌ Chat history endpoint failed: {response.status_code}")
            return False
    except Exception as e:
        print(f"❌ Chat history endpoint error: {str(e)}")
        return False


def test_status_endpoint():
    """Test the status endpoint"""
    print("\nTesting status endpoint...")
    try:
        response = requests.get(f"{BASE_URL}/api/status")

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Status endpoint passed")
            print(f"   Status: {data['status']}")
            print(
                f"   CAG API configured: {data['config']['cag_api_configured']}")
            print(
                f"   Total chat entries: {data['stats']['total_chat_entries']}")
            return True
        else:
            print(f"❌ Status endpoint failed: {response.status_code}")
            return False
    except Exception as e:
        print(f"❌ Status endpoint error: {str(e)}")
        return False


def main():
    """Run all tests"""
    print("🧪 Testing CAG Chatbot Flask API")
    print("=" * 40)

    tests = [
        test_health_check,
        test_chat_endpoint,
        test_chat_history,
        test_status_endpoint
    ]

    passed = 0
    total = len(tests)

    for test in tests:
        if test():
            passed += 1
        time.sleep(0.5)  # Small delay between tests

    print("\n" + "=" * 40)
    print(f"📊 Test Results: {passed}/{total} tests passed")

    if passed == total:
        print("🎉 All tests passed! The API is working correctly.")
    else:
        print("⚠️  Some tests failed. Check the Flask app logs for more details.")


if __name__ == "__main__":
    main()

```

### test_models.py

```python
#!/usr/bin/env python3
"""
Test script for User and Conversation models (Task 4)
"""

from app import app, db, User, Conversation
from datetime import datetime


def test_models():
    """Test the User and Conversation models"""
    print("🧪 Testing User and Conversation Models (Task 4)")
    print("=" * 60)

    with app.app_context():
        try:
            # Test 1: Create a new user
            print("📝 Test 1: Creating a new user...")
            user = User(
                name="John Doe",
                location="San Francisco, CA",
                situation="Looking for food assistance",
                needs="Food, temporary shelter"
            )

            db.session.add(user)
            db.session.commit()
            print(f"✅ User created: {user}")
            print(f"   User ID: {user.id}")
            print(f"   User dict: {user.to_dict()}")

            # Test 2: Create a conversation for the user
            print("\n📝 Test 2: Creating a conversation...")
            conversation = Conversation(
                user_id=user.id,
                message="I need help finding food today",
                response="I understand you're looking for food assistance. Let me help you find local resources.",
                message_type="user",
                context={
                    "location": user.location,
                    "situation": user.situation,
                    "needs": user.needs
                }
            )

            db.session.add(conversation)
            db.session.commit()
            print(f"✅ Conversation created: {conversation}")
            print(f"   Conversation ID: {conversation.id}")
            print(f"   Conversation dict: {conversation.to_dict()}")

            # Test 3: Query the user with conversations
            print("\n📝 Test 3: Querying user with conversations...")
            user_with_conversations = User.query.get(user.id)
            print(f"✅ User found: {user_with_conversations}")
            print(
                f"   Number of conversations: {len(user_with_conversations.conversations)}")

            for conv in user_with_conversations.conversations:
                print(f"   - Conversation: {conv.message[:50]}...")

            # Test 4: Query all users
            print("\n📝 Test 4: Querying all users...")
            all_users = User.query.all()
            print(f"✅ Total users in database: {len(all_users)}")

            # Test 5: Query all conversations
            print("\n📝 Test 5: Querying all conversations...")
            all_conversations = Conversation.query.all()
            print(
                f"✅ Total conversations in database: {len(all_conversations)}")

            print("\n" + "=" * 60)
            print("🎯 Task 4 Requirements Met:")
            print("✅ Created user.py in models/")
            print("✅ Created conversation.py in models/")
            print("✅ SQLAlchemy models created and linked to SQLite")
            print("✅ Test data inserted into tables successfully")
            print("\n🚀 Ready for Task 5!")

            return True

        except Exception as e:
            print(f"❌ Error testing models: {str(e)}")
            return False


def test_flask_shell_commands():
    """Test commands that would be run in Flask shell"""
    print("\n🧪 Testing Flask Shell Commands...")

    with app.app_context():
        try:
            # Commands you could run in Flask shell
            print("📝 Flask shell equivalent commands:")
            print("   from models.user import User")
            print("   from models.conversation import Conversation")
            print("   from app import db")

            # Create another test user
            user2 = User(name="Jane Smith", location="Oakland, CA")
            db.session.add(user2)
            db.session.commit()

            print(f"✅ Created user via Flask shell simulation: {user2}")

        except Exception as e:
            print(f"❌ Error in Flask shell test: {str(e)}")


if __name__ == "__main__":
    print("Starting Model Tests...\n")

    success = test_models()
    test_flask_shell_commands()

    if success:
        print("\n🎉 All tests passed! Database models are working correctly.")
    else:
        print("\n❌ Some tests failed. Please check the implementation.")

```

### test_chat_endpoint.py

```python
#!/usr/bin/env python3
"""
Test script for /api/chat/message endpoint (Task 5)
"""

import requests
import json
import time

BASE_URL = "http://localhost:5001"


def test_chat_message_endpoint():
    """Test the /api/chat/message POST endpoint"""
    print("🧪 Testing /api/chat/message Endpoint (Task 5)")
    print("=" * 60)

    # Test 1: Basic message without user context
    print("📝 Test 1: Basic message without user context...")
    try:
        payload = {
            "message": "I need help finding food today"
        }

        response = requests.post(
            f"{BASE_URL}/api/chat/message",
            json=payload,
            headers={"Content-Type": "application/json"}
        )

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Basic message test passed")
            print(f"   Response: {data['response'][:100]}...")
            print(f"   User ID: {data['user_id']}")
            print(f"   Conversation ID: {data['conversation_id']}")

            # Save user_id for next test
            user_id = data['user_id']
        else:
            print(f"❌ Basic message test failed: {response.status_code}")
            print(f"   Error: {response.text}")
            return False

    except Exception as e:
        print(f"❌ Basic message test error: {str(e)}")
        return False

    # Test 2: Message with user context
    print("\n📝 Test 2: Message with user context...")
    try:
        payload = {
            "message": "Can you help me find a shelter for tonight?",
            "context": {
                "name": "Test User",
                "location": "San Francisco, CA",
                "situation": "Experiencing homelessness",
                "needs": "Shelter, food assistance"
            }
        }

        response = requests.post(
            f"{BASE_URL}/api/chat/message",
            json=payload,
            headers={"Content-Type": "application/json"}
        )

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Context message test passed")
            print(f"   Response: {data['response'][:100]}...")
            print(f"   Context: {data['context']}")

            # Save user_id for history test
            context_user_id = data['user_id']
        else:
            print(f"❌ Context message test failed: {response.status_code}")
            print(f"   Error: {response.text}")
            return False

    except Exception as e:
        print(f"❌ Context message test error: {str(e)}")
        return False

    # Test 3: Message with existing user_id
    print("\n📝 Test 3: Message with existing user_id...")
    try:
        payload = {
            "message": "Thank you for the help earlier. Do you have any other suggestions?",
            "user_id": user_id
        }

        response = requests.post(
            f"{BASE_URL}/api/chat/message",
            json=payload,
            headers={"Content-Type": "application/json"}
        )

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Existing user test passed")
            print(f"   Response: {data['response'][:100]}...")
            print(f"   Same User ID: {data['user_id'] == user_id}")
        else:
            print(f"❌ Existing user test failed: {response.status_code}")
            return False

    except Exception as e:
        print(f"❌ Existing user test error: {str(e)}")
        return False

    # Test 4: Get chat history
    print("\n📝 Test 4: Getting chat history...")
    try:
        response = requests.get(
            f"{BASE_URL}/api/chat/history/{context_user_id}")

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Chat history test passed")
            print(f"   User: {data['user']['name']}")
            print(f"   Total conversations: {data['total_conversations']}")
        else:
            print(f"❌ Chat history test failed: {response.status_code}")
            return False

    except Exception as e:
        print(f"❌ Chat history test error: {str(e)}")
        return False

    # Test 5: Get all users
    print("\n📝 Test 5: Getting all users...")
    try:
        response = requests.get(f"{BASE_URL}/api/chat/users")

        if response.status_code == 200:
            data = response.json()
            print(f"✅ Users list test passed")
            print(f"   Total users: {data['total_users']}")
        else:
            print(f"❌ Users list test failed: {response.status_code}")
            return False

    except Exception as e:
        print(f"❌ Users list test error: {str(e)}")
        return False

    return True


def test_error_cases():
    """Test error cases"""
    print("\n🧪 Testing Error Cases...")

    # Test missing message
    print("📝 Testing missing message...")
    try:
        payload = {}
        response = requests.post(
            f"{BASE_URL}/api/chat/message",
            json=payload,
            headers={"Content-Type": "application/json"}
        )

        if response.status_code == 400:
            print("✅ Missing message error handling works")
        else:
            print(f"❌ Expected 400, got {response.status_code}")

    except Exception as e:
        print(f"❌ Error test failed: {str(e)}")


def main():
    """Run all tests"""
    print("🧪 Testing Chat Message Endpoint")
    print("=" * 60)
    print("⚠️  Make sure the Flask app is running on port 5001!")
    print("   Run: python app.py")
    print("=" * 60)

    # Test basic connectivity
    try:
        response = requests.get(f"{BASE_URL}/ping")
        if response.status_code != 200:
            print("❌ Flask app is not running or not accessible")
            print("   Please start the app with: python app.py")
            return
    except requests.exceptions.ConnectionError:
        print("❌ Cannot connect to Flask app")
        print("   Please start the app with: python app.py")
        retur
[truncated — 538 more characters]
```

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