# Project export: Acey The Interviewer

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: Acey - our AI mock interviewer! Practice anytime, get real-time feedback, and "ace" your next big interview!
- Devpost: https://devpost.com/software/acey-the-interviewer
- GitHub: https://github.com/samoohleester/Acey-The-Interviewer
- Video: https://www.youtube.com/embed/1PQ16cEAteM?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 3 GitHub contributor(s) — Chelsea Zhang (24 commits), RaghavG17 (8 commits), GweeLiao (2 commits)

## Devpost submission (written by the team)

### Inspiration

Interviewing is hard, and practice makes perfect. But many people don’t have someone to practice with—friends are busy, and professional coaching is expensive. Acey solves this by giving everyone an AI interview coach to practice with anytime.

### What it does

Acey is like a real interview, but with AI. You talk to it, and it gives feedback to help you improve. Key Features: Talk naturally – Acey listens and responds like a real person. Instant feedback – Get tips on your answers, body language (eye contact, posture), and how well you use the STAR method. Adjustable difficulty – Choose Easy, Medium, or Hard mode. Score & feedback report – See your strengths, weaknesses, and how to improve. Save your progress – Log in to track your past interviews. How We Built It Frontend: Made with React + Firebase (for login). Backend: Built with Python & Flask. APIs: Vapi – Handles the voice conversation + turns text into speech. Deepgram (Vapi) – Turns speech into text. Gemini AI – Generates questions & feedback. Gemini Vision - Checks your body language and returns feedback. Gemini AI – Generates questions & feedback. Fetch.ai - Utilizes mutiple ai agents to customize and give real time feedback Challenges We Faced Getting Flask and all the AI tools to work together smoothly was tricky. For example, at the start, the chatbot was very sensitive to noise, so it get getting interrupted while asking / giving a question. Another challenge we faced was picking the best Gemini model for vision and posture-recognition, which required lot of experimenting. We ended up picking Gemini 2.0 Flash that satisfied our specifications. We were also having difficulty to customize multiple agents for varying difficulties. Our solution was to combine Gemini and uagents together to make each agent. We also had to figure out a proper scoring system so that the AI gave fair, useful feedback took a lot of testing. What We’re Proud Of We're proud to have created a realistic, helpful interview practice tool that analyzes both body language and responses, which are observed in real interviews. For the most part, the conversations feel smooth and questions asked are plausible in real interviews. Also, some of our UI designs, like Acey the Cat, were hand-drawn, and the design fits well with the overall website. What We Learned We all gained significant experience in: Full-Stack Development: **Connecting a React frontend to a Python/Flask backend. **System Architecture: Designing a complex system that orchestrates multiple third-party APIs. Prompt Engineering: Writing detailed prompts to control the behavior and output format of large language models. Real-time Data Processing: Managing and synchronizing multiple real-time data streams. What’s Next? Progress tracking: See how you improve over time. Pinpoint feedback: See exactly where you said "um" or lost eye contact. Improve scoring: Create more comprehensive and accurate scoring.

## README (from the GitHub repository)

# Acey-The-Interviewer
Building an AI bot that actively improves users' interviewing skills!


## Detected evidence (automated analysis)

Indexed codebase: 40 recognized source files, 233 KB.
- CSS (language) — detected in the code
- Firebase (technology) — 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
- Google Gemini (technology) — claimed on Devpost, not found in the code
- Node.js (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (48 of 48)

```
.gitignore
backend/.env
backend/agent_client.py
backend/app.py
backend/requirements.txt
frontend/.gitignore
frontend/package.json
frontend/public/index.html
frontend/public/manifest.json
frontend/public/robots.txt
frontend/README.md
frontend/src/App.css
frontend/src/App.js
frontend/src/App.test.js
frontend/src/CatAnimation.css
frontend/src/CatAnimation.js
frontend/src/ChatHistory.css
frontend/src/Conversation.css
frontend/src/Conversation.js
frontend/src/CustomDifficultyDetails.css
frontend/src/CustomDifficultyDetails.js
frontend/src/Demo.css
frontend/src/Demo.js
frontend/src/DifficultyDetails.css
frontend/src/DifficultyDetails.js
frontend/src/DifficultySelection.js
frontend/src/firebaseConfig.js
frontend/src/index.css
frontend/src/index.js
frontend/src/JobAnalysis.css
frontend/src/JobAnalysis.js
frontend/src/LandingPage.css
frontend/src/LandingPage.js
frontend/src/LoginPage.js
frontend/src/placeholders.js
frontend/src/Report.css
frontend/src/Report.js
frontend/src/reportWebVitals.js
frontend/src/setupTests.js
frontend/src/SignupPage.js
frontend/src/Trash.js
interview_agents.py
README_AGENTS.md
README_HYBRID.md
README.md
requirements_agents.txt
test_agents.py
test_integration.py
```

### Dependencies

- backend/requirements.txt: beautifulsoup4@==4.12.2, Flask@==2.3.3, Flask-Cors@==4.0.0, google-generativeai@==0.3.2, Pillow@==10.0.1, python-dotenv@==1.0.0, requests@==2.31.0, uagents@==0.10.0, vapi-server-sdk@==1.5.1
- frontend/package.json: @testing-library/dom@^10.4.0, @testing-library/jest-dom@^6.6.3, @testing-library/react@^16.3.0, @testing-library/user-event@^13.5.0, @vapi-ai/web@^2.3.6, firebase@^11.9.1, react@^19.1.0, react-dom@^19.1.0, react-draggable@^4.4.6, react-router-dom@^7.6.2, react-scripts@5.0.1, react-webcam@^7.2.0, web-vitals@^2.1.4

### Recent commits (newest first)

- changes
- new ui
- heading changed
- another one
- minor updates
- last update
- Lets Goo!!!!!
- ItWorks3am
- it finally works
- Revert "removing comments"
- small polish
- changes to api key
- hehe
- changed first question
- Merge branch 'trying-fetchai'
- hehe
- test
- changes and finishing hehe
- pushing fat cat and merged uagent
- Merge remote-tracking branch 'origin/FetchAi-Agents-merge' into trying-fetchai

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

### README_AGENTS.md

```markdown
# Interview Agents using Fetch.ai uAgents SDK

This project implements three AI interview agents using the Fetch.ai uAgents SDK to handle different interview difficulty levels: **easy**, **medium**, and **hard**.

## Overview

The agents are designed to:
- Listen for user interview answers
- Analyze responses based on difficulty level
- Generate appropriate follow-up questions
- Maintain different interview styles and expectations

## Files

- `interview_agents.py` - Main agent implementation
- `test_agents.py` - Test client for demonstrating agent interactions
- `requirements_agents.txt` - Dependencies for the agents
- `README_AGENTS.md` - This documentation

## Installation

1. Install the required dependencies:
```bash
pip install -r requirements_agents.txt
```

2. Install the uAgents SDK:
```bash
pip install uagents
```

## Agent Modes

### Easy Agent
- **Style**: Friendly and supportive
- **Focus**: Basic communication skills and comfort
- **Time Limit**: 30 seconds per answer
- **Questions**: Common, straightforward interview questions
- **Tone**: Encouraging and supportive

### Medium Agent
- **Style**: Professional and structured
- **Focus**: STAR method and structured responses
- **Time Limit**: 15 seconds per answer
- **Questions**: Behavioral and situational questions
- **Tone**: Professional and structured

### Hard Agent
- **Style**: Direct and challenging
- **Focus**: Quick thinking and leadership scenarios
- **Time Limit**: 5 seconds to begin answer
- **Questions**: Complex behavioral and high-pressure scenarios
- **Tone**: Direct and challenging

## Usage

### Running the Agents

1. Start the interview agents:
```bash
python interview_agents.py
```

This will create and start three agents:
- `easy-agent` on port 8000
- `medium-agent` on port 8001
- `hard-agent` on port 8002

### Testing the Agents

1. Run the test client:
```bash
python test_agents.py
```

This will simulate sending interview answers to each agent and receiving follow-up questions.

## Message Models

### InterviewAnswer
```python
class InterviewAnswer(BaseModel):
    answer: str                    # The user's interview response
    question_context: Optional[str] # Context of the question being answered
    user_id: Optional[str]         # Unique identifier for the user
```

### FollowUpQuestion
```python
class FollowUpQuestion(BaseModel):
    question: str                  # The follow-up question to ask
    difficulty: str                # Difficulty level: easy, medium, or hard
    reasoning: Optional[str]       # Reasoning behind the question choice
    expected_focus: Optional[str]  # What aspect the question focuses on
```

## Integration with Flask Backend

To integrate these agents with your existing Flask backend (`app.py`), you can:

1. Import the agent functions:
```python
from interview_agents import MODE_CONFIGS, generate_follow_up_question
```

2. Use the mode configurations in your VAPI assistant creation:
```python
# In your Flask route
mode = re
[truncated — 1710 more characters]
```

### README_HYBRID.md

```markdown
# 🚀 Hybrid Interview System: VAPI + uAgents

This project now uses a **hybrid approach** that combines the best of both worlds:

- **VAPI** handles voice/transcription and real-time conversation
- **uAgents** handle intelligent interview logic and follow-up questions
- **Flask** coordinates between them

## 🏗️ Architecture

```
┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│   Frontend      │    │   Flask Backend │    │   uAgents       │
│   (React)       │◄──►│   (Port 5001)   │◄──►│   (Ports 8000+) │
└─────────────────┘    └─────────────────┘    └─────────────────┘
                              │
                              ▼
                       ┌─────────────────┐
                       │   VAPI          │
                       │   (Voice/AI)    │
                       └─────────────────┘
```

## 🎯 What Each Component Does

### **VAPI (Voice AI)**
- ✅ Real-time voice conversation
- ✅ Speech-to-text transcription
- ✅ Text-to-speech responses
- ✅ Natural conversation flow

### **uAgents (Interview Logic)**
- ✅ Intelligent follow-up questions
- ✅ Mode-specific interview strategies
- ✅ Answer analysis and scoring
- ✅ Adaptive question generation

### **Flask Backend**
- ✅ Coordinates between VAPI and agents
- ✅ API endpoints for frontend
- ✅ Body language analysis
- ✅ Final review generation

## 🚀 How to Run

### 1. Start the Agents
```bash
python3 interview_agents.py
```
This starts three agents:
- `easy-agent` on port 8000
- `medium-agent` on port 8001  
- `hard-agent` on port 8002

### 2. Start the Flask Backend
```bash
cd backend
python3 app.py
```
This starts the Flask server on port 5001.

### 3. Start the Frontend
```bash
cd frontend
npm start
```
This starts the React app on port 3000.

### 4. Test the Integration
```bash
python3 test_integration.py
```

## 🔄 How It Works

### **User Flow:**
1. **User selects interview mode** (easy/medium/hard)
2. **Flask creates VAPI assistant** with agent-based prompts
3. **User speaks with VAPI** (voice conversation)
4. **When follow-up needed**, Flask calls the appropriate agent
5. **Agent analyzes answer** and returns intelligent follow-up
6. **VAPI continues conversation** with agent's question

### **API Endpoints:**

#### **Create VAPI Assistant**
```http
GET /api/vapi-assistant?mode=easy
```
- Creates VAPI assistant with agent-based prompts
- Returns assistant ID for frontend

#### **Get Agent Follow-up**
```http
POST /api/agent-followup
Content-Type: application/json

{
  "mode": "easy",
  "answer": "I have 3 years of experience...",
  "question_context": "Tell me about yourself",
  "user_id": "user123"
}
```
- Sends user's answer to appropriate agent
- Returns intelligent follow-up question

#### **Body Language Analysis**
```http
POST /api/analyze-frame
```
- Analyzes webcam frames for body language
- Uses Google Gemini AI

#### **Get Final Review**
```http
POST /api/get-review
```
- Generates comprehensive interview feedback
- Combines transcript and body langua
[truncated — 2900 more characters]
```

### backend/requirements.txt

```
Flask==2.3.3
Flask-Cors==4.0.0
vapi-server-sdk==1.5.1
google-generativeai==0.3.2
python-dotenv==1.0.0
Pillow==10.0.1
requests==2.31.0
beautifulsoup4==4.12.2
uagents==0.10.0 
```

### frontend/package.json

```
{
  "name": "frontend",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/dom": "^10.4.0",
    "@testing-library/jest-dom": "^6.6.3",
    "@testing-library/react": "^16.3.0",
    "@testing-library/user-event": "^13.5.0",
    "@vapi-ai/web": "^2.3.6",
    "firebase": "^11.9.1",
    "react": "^19.1.0",
    "react-dom": "^19.1.0",
    "react-draggable": "^4.4.6",
    "react-router-dom": "^7.6.2",
    "react-scripts": "5.0.1",
    "react-webcam": "^7.2.0",
    "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 { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <BrowserRouter>
      <App />
    </BrowserRouter>
  </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();

```

### frontend/src/App.js

```javascript
import React from 'react';
import { Routes, Route } from 'react-router-dom';
import LandingPage from './LandingPage';
import LoginPage from './LoginPage';
import SignupPage from './SignupPage';
import Demo from './Demo';
import DifficultySelection from './DifficultySelection';
import Conversation from './Conversation';
import Report from './Report';
import JobAnalysis from './JobAnalysis';
import { Trash, ChatHistory, Profile, Support } from './placeholders';
import './App.css';

function App() {
  return (
    <Routes>
      <Route path="/" element={<LandingPage />} />
      <Route path="/login" element={<LoginPage />} />
      <Route path="/signup" element={<SignupPage />} />
      <Route path="/demo" element={<Demo />}>
        <Route index element={<DifficultySelection />} />
        <Route path="conversation" element={<Conversation />} />
        <Route path="trash" element={<Trash />} />
        <Route path="history" element={<ChatHistory />} />
        <Route path="profile" element={<Profile />} />
        <Route path="support" element={<Support />} />
      </Route>
      <Route path="/job-analysis" element={<JobAnalysis />} />
      <Route path="/report" element={<Report />} />
    </Routes>
  );
}

export default App;

```

### backend/app.py

```python
import os
import sys
from io import BytesIO

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

import base64
from PIL import Image
from flask import Flask, jsonify, request
from flask_cors import CORS
from dotenv import load_dotenv
from vapi import Vapi
import google.generativeai as genai
from google.api_core import exceptions
import time
import json
import re
import requests
from bs4 import BeautifulSoup

try:
    from agent_client import get_followup_from_agent
    AGENT_AVAILABLE = True
except ImportError:
    print("Warning: agent_client not available. Agent features will be disabled.")
    AGENT_AVAILABLE = False

try:
    from interview_agents import MODE_CONFIGS
    MODE_CONFIGS_AVAILABLE = True
except ImportError:
    print("Warning: interview_agents not available. Using fallback configurations.")
    MODE_CONFIGS_AVAILABLE = False
    MODE_CONFIGS = {}

NGROK_URL = os.getenv("NGROK_URL", "YOUR_NGROK_HTTPS_URL_HERE")


load_dotenv()
#loading flask
app = Flask(__name__)

CORS(app)


current_job_analysis = None
#call the api keys
VAPI_API_KEY = os.environ.get('VAPI_API_KEY')
GOOGLE_API_KEY = os.environ.get('GOOGLE_API_KEY')

if VAPI_API_KEY:
    vapi = Vapi(token=VAPI_API_KEY)
else:
    print("Warning: VAPI_API_KEY not found. Voice features will be disabled.")
    vapi = None

if GOOGLE_API_KEY:
    genai.configure(api_key=GOOGLE_API_KEY)
    model = genai.GenerativeModel('gemini-1.5-flash')
else:
    print("Warning: GOOGLE_API_KEY not found. AI analysis features will be disabled.")
    model = None

frame_analyses = []

question_count = 0
current_assistant_id = None
rate_limit_hit = False
#testing backend
@app.route('/api/data')
def get_data():
    return {'message': 'Hello from your Flask backend!'}

@app.route('/api/vapi-assistant')
#vapi calls
def get_vapi_assistant():
 
    mode = request.args.get('mode', 'easy')
    
    # Get custom configuration parameters
    question_type = request.args.get('questionType', 'Common Questions')
    time_limit = request.args.get('timeLimit', 'No Time Limit')
    curveballs = request.args.get('curveballs', 'None')
    session_name = request.args.get('sessionName', 'Custom Interview')

    frame_analyses.clear()
    global rate_limit_hit
    rate_limit_hit = False
    
    print(f"=== CREATING NEW ASSISTANT WITH MODE: {mode} ===")
    if mode == 'custom':
        print(f"Custom settings - Question Type: {question_type}, Time Limit: {time_limit}, Curveballs: {curveballs}")
    
    try:
 
        timestamp = int(time.time())
        assistant_name = f"Direct-Interviewer-{mode}-{timestamp}"
        
        if mode == 'custom':
            system_prompt_content = f"""You are Acey The Interviewer, an AI-powered interview coach conducting a custom interview session.

SESSION CONFIGURATION:
- Question Type: {question_type}
- Time Limit: {time_limit}
- Curveballs: {curveballs}
- Session Name: {session_name}

INTERVIEW GUIDELINES:
1. Question Focus: Based on the selected question type, tailor your questions accordingly:
   - "Common Questions": Ask standard behavioral and situational questions
   - "Behavioral & Situational": Focus on past experiences and hypothetical scenarios
   - "Technical Questions": Include technical problem-solving and knowledge-based questions
   - "All Types": Mix of behavioral, situational, and technical questions
   - "Leadership & Management": Focus on leadership experiences and management scenarios
   - "Problem Solving": Present complex problems and assess analytical thinking
   - "Communication Skills": Evaluate verbal communication, clarity, and articulation
   - "Team Collaboration": Focus on teamwork, conflict resolution, and collaboration

2. Time Management: {time_limit}
   - "No Time Limit": Allow candidates to take their time
   - "30 seconds per answer": Encourage concise responses
   - "15 seconds per answer": Apply moderate time pressure
   - "10 seconds per answer": Apply significant time pressure
   - "5 seconds per answer": Apply high time pressure
   - "2 minutes per answer": Allow detailed responses
   - "1 minute per answer": Balance between detail and conciseness

3. Curveball Strategy: {curveballs}
   - "None": Stick to standard interview questions
   - "Ask to clarify": Request clarification when answers are vague
   - "In-depth clarification": Dive deeper into specific aspects of answers
   - "Follow-up questions": Ask probing follow-up questions
   - "Role-play scenarios": Present hypothetical role-play situations
   - "Stress testing": Gradually increase difficulty and pressure
   - "Hypothetical situations": Present challenging hypothetical scenarios
   - "Past experience validation": Ask for specific details to validate experiences

CONDUCT GUIDELINES:
- Be professional, encouraging, and constructive
- Ask one question at a time and wait for a complete response
- Provide gentle guidance if the candidate struggles
- Maintain a conversational tone while being professional
- Focus on the candidate's communication skills, problem-solving abilities, and experience
- Adapt your approach based on the candidate's comfort level and performance

Remember: This is a learning experience. Your goal is to help the candidate improve their interview skills while providing a realistic interview experience."""
        else:
            config = MODE_CONFIGS[mode]
            system_prompt_content = config['system_prompt']
        
        # Add job-specific context if available
        global current_job_analysis
        if current_job_analysis and not current_job_analysis.get('error'):
            job_context = f"""

ROLE-SPECIFIC CONTEXT:
- Target Role: {current_job_analysis.get('role', 'Not specified')}
- Company: {current_job_analysis.get('company', 'Not specified')}
- Key Responsibilities: {current_job_analysis.get('keyResponsibilities', 'Not specified')}
- Required Skills: {current_job_analysis.get('requiredSkills', 'Not specified')}
- Experience Level: {current_job_analysis.get(
[truncated — 27388 more characters]
```

### test_integration.py

```python
#!/usr/bin/env python3
"""
Test script to demonstrate the hybrid approach:
- VAPI handles voice/transcription
- Agents handle interview logic and follow-up questions
"""

import requests
import json

def test_agent_followup():
    """Test the new agent-followup endpoint"""
    
    # Test data for different modes
    test_cases = [
        {
            'mode': 'easy',
            'answer': 'I have 3 years of experience in software development, working mainly with Python and JavaScript.',
            'question_context': 'Tell me about yourself',
            'user_id': 'test_user_123'
        },
        {
            'mode': 'medium',
            'answer': 'I faced a challenge when our main database went down during peak hours. I had to quickly implement a backup solution.',
            'question_context': 'Tell me about a time you faced a challenge',
            'user_id': 'test_user_123'
        },
        {
            'mode': 'hard',
            'answer': 'As a team lead, I had to make the unpopular decision to let go of a team member who wasn\'t meeting expectations.',
            'question_context': 'Describe a time you had to make a difficult decision',
            'user_id': 'test_user_123'
        }
    ]
    
    print("=== Testing Agent Integration with Flask Backend ===\n")
    
    for i, test_case in enumerate(test_cases, 1):
        print(f"Test {i}: {test_case['mode'].upper()} mode")
        print(f"User Answer: {test_case['answer']}")
        print(f"Context: {test_case['question_context']}")
        
        try:
            # Send request to Flask backend
            response = requests.post(
                'http://localhost:5001/api/agent-followup',
                json=test_case,
                headers={'Content-Type': 'application/json'}
            )
            
            if response.status_code == 200:
                result = response.json()
                print(f"✅ Agent Response: {result['question']}")
                print(f"   Difficulty: {result['difficulty']}")
                print(f"   Reasoning: {result['reasoning']}")
                print(f"   Expected Focus: {result['expected_focus']}")
            else:
                print(f"❌ Error: {response.status_code} - {response.text}")
                
        except requests.exceptions.ConnectionError:
            print("❌ Error: Could not connect to Flask backend. Make sure it's running on port 5001.")
        except Exception as e:
            print(f"❌ Error: {e}")
        
        print("-" * 60 + "\n")

def test_vapi_assistant_creation():
    """Test that VAPI assistant creation still works with agent-based prompts"""
    
    print("=== Testing VAPI Assistant Creation with Agent Prompts ===\n")
    
    for mode in ['easy', 'medium', 'hard']:
        try:
            response = requests.get(f'http://localhost:5001/api/vapi-assistant?mode={mode}')
            
            if response.status_code == 200:
                result = response.json()
                print(f"✅ {mode.upper()} mode assistant created successfully")
                print(f"   Assistant ID: {result['assistantId']}")
                print(f"   Mode: {result['mode']}")
            else:
                print(f"❌ Error creating {mode} assistant: {response.status_code}")
                
        except requests.exceptions.ConnectionError:
            print("❌ Error: Could not connect to Flask backend. Make sure it's running on port 5001.")
        except Exception as e:
            print(f"❌ Error: {e}")
        
        print("-" * 40 + "\n")

if __name__ == "__main__":
    print("🚀 Testing Hybrid Approach: VAPI + Agents\n")
    
    # Test agent follow-up functionality
    test_agent_followup()
    
    # Test VAPI assistant creation
    test_vapi_assistant_creation()
    
    print("✅ Integration test completed!")
    print("\n📋 Summary:")
    print("- VAPI handles voice/transcription")
    print("- Agents handle interview logic and follow-up questions")
    print("- Flask backend coordinates between them")
    print("- Centralized prompts in interview_agents.py") 
```

### test_agents.py

```python
#!/usr/bin/env python3
"""
Test client for the Interview Agents
Demonstrates how to send interview answers to the agents and receive follow-up questions.
"""

import asyncio
from uagents import Agent
from interview_agents import InterviewAnswer, FollowUpQuestion, InterviewMode

async def test_interview_agents():
    """Test the interview agents with sample responses"""
    
    # Create a test client agent
    client = Agent(
        name="test-client",
        port=9000,
        seed="test_client_seed_123"
    )
    
    # Sample interview answers for testing
    test_answers = {
        'easy': [
            "I have 3 years of experience in software development, working mainly with Python and JavaScript.",
            "My strengths include problem-solving and working well in teams.",
            "I'm interested in this role because it offers growth opportunities and interesting challenges."
        ],
        'medium': [
            "I faced a challenge when our main database went down during peak hours. I had to quickly implement a backup solution.",
            "I worked with a difficult colleague who was resistant to new processes. I tried to understand their concerns and find common ground.",
            "I had to learn a new framework in a week for a critical project deadline."
        ],
        'hard': [
            "As a team lead, I had to make the unpopular decision to let go of a team member who wasn't meeting expectations.",
            "I resolved a major conflict between two senior developers who had different approaches to architecture.",
            "I had to innovate under pressure when our main vendor suddenly increased prices by 300%."
        ]
    }
    
    # Agent addresses (you'll need to get these from the running agents)
    agent_addresses = {
        'easy': "agent1q...",  # Replace with actual agent address
        'medium': "agent1q...",  # Replace with actual agent address  
        'hard': "agent1q..."   # Replace with actual agent address
    }
    
    print("=== Interview Agent Test Client ===\n")
    
    for mode, answers in test_answers.items():
        print(f"Testing {mode.upper()} mode:")
        print("-" * 40)
        
        for i, answer in enumerate(answers, 1):
            print(f"\nTest {i}:")
            print(f"User Answer: {answer}")
            
            # Create the interview answer message
            interview_msg = InterviewAnswer(
                answer=answer,
                question_context=f"Sample question for {mode} mode",
                user_id="test_user_123"
            )
            
            try:
                # Send message to the appropriate agent
                # Note: You'll need to replace with actual agent addresses
                # await client.send(agent_addresses[mode], interview_msg)
                
                # For now, just simulate the response
                print("Sending to agent... (simulated)")
                await asyncio.sleep(1)  # Simulate network delay
                
                # Simulate agent response
                simulated_response = FollowUpQuestion(
                    question=f"Follow-up question for {mode} mode based on your answer",
                    difficulty=mode,
                    reasoning="Simulated reasoning for question choice",
                    expected_focus="Simulated focus area"
                )
                
                print(f"Agent Response: {simulated_response.question}")
                print(f"Difficulty: {simulated_response.difficulty}")
                print(f"Reasoning: {simulated_response.reasoning}")
                print(f"Expected Focus: {simulated_response.expected_focus}")
                
            except Exception as e:
                print(f"Error communicating with agent: {e}")
            
            print("-" * 20)
        
        print("\n" + "=" * 50 + "\n")

async def main():
    """Main function to run the test"""
    print("Starting Interview Agent Test Client...")
    await test_interview_agents()
    print("Test completed!")

if __name__ == "__main__":
    asyncio.run(main()) 
```

### interview_agents.py

```python
#!/usr/bin/env python3
"""
Interview Agents using Fetch.ai uAgents SDK
Defines three agents: easy-agent, medium-agent, and hard-agent
Each agent handles interview responses with different difficulty levels and prompts.
"""

import asyncio
from typing import Optional
from uagents import Agent, Context, Protocol, Model
from uagents.setup import fund_agent_if_low
from pydantic import Field
import json
import time

# Message models using Pydantic
class InterviewAnswer(Model):
    """Model for user's interview answer"""
    answer: str  # required
    question_context: Optional[str] = None
    user_id: Optional[str] = None

class FollowUpQuestion(Model):
    """Model for agent's follow-up question"""
    question: str  # required
    difficulty: str  # required
    reasoning: Optional[str] = None
    expected_focus: Optional[str] = None

class InterviewMode(Model):
    """Model for interview mode selection"""
    mode: str  # required
    user_id: Optional[str] = None

# Define mode-specific prompts and behaviors
MODE_CONFIGS = {
    'easy': {
        'name': 'easy-agent',
        'description': 'Friendly and supportive interviewer for beginners',
        'system_prompt': """You are Acey, a friendly AI mock interviewer for EASY mode. 
        Ask common, straightforward interview questions. Begin with a warm greeting and ask 
        the candidate to introduce themselves. Speak clearly and with confidence. Keep responses 
        natural, under 10 words, and ask one question at a time. Focus on basic questions about 
        experience, skills, and background. Be encouraging and supportive.
        
        IMPORTANT: Wait 4 seconds of silence after the user finishes speaking before you respond. 
        This gives them time to think and ensures you don't interrupt them.""",
        'question_types': [
            "Tell me about yourself",
            "What are your strengths?",
            "Why are you interested in this role?",
            "Describe your work experience",
            "What are your career goals?"
        ],
        'tone': 'encouraging and supportive',
        'time_limit': 30,  # seconds
        'scoring_focus': 'basic communication and comfort'
    },
    'medium': {
        'name': 'medium-agent',
        'description': 'Professional interviewer for intermediate candidates',
        'system_prompt': """You are Acey, a professional AI mock interviewer for MEDIUM mode. 
        Ask behavioral and situational questions. Begin with a brief greeting, then dive into 
        structured behavioral questions. Give candidates 15 seconds to answer each question. 
        If they exceed 15 seconds, politely interrupt and move to the next question. Ask 
        follow-up questions to get specific examples. Focus on STAR method responses and 
        problem-solving scenarios.
        
        IMPORTANT: Wait 4 seconds of silence after the user finishes speaking before you respond. 
        This gives them time to think and ensures you don't interrupt them.""",
        'question_types': [
            "Tell me about a time you faced a challenge at work",
            "Describe a situation where you had to work with a difficult colleague",
            "Give me an example of when you had to learn something quickly",
            "Tell me about a project you're proud of",
            "How do you handle stress and pressure?"
        ],
        'tone': 'professional and structured',
        'time_limit': 15,  # seconds
        'scoring_focus': 'STAR method and structured responses'
    },
    'hard': {
        'name': 'hard-agent',
        'description': 'Challenging interviewer for advanced candidates',
        'system_prompt': """You are Acey, a challenging AI mock interviewer for HARD mode. 
        Ask complex behavioral and situational questions with strict timing. Give candidates 
        only 5 seconds to BEGIN their answer after you finish asking a question. If they don't 
        start speaking within 5 seconds of you finishing your question, politely interrupt 
        and ask for clarification on why they hesitated. Once they start speaking, let them 
        complete their answer without interruption. Be direct and professional. Focus on 
        leadership, conflict resolution, and high-pressure scenarios.
        
        IMPORTANT: Wait 4 seconds of silence after the user finishes speaking before you respond. 
        This gives them time to think and ensures you don't interrupt them.""",
        'question_types': [
            "Describe a time you had to make an unpopular decision as a leader",
            "Tell me about a situation where you had to resolve a major conflict",
            "Give me an example of when you had to innovate under pressure",
            "Describe a time you failed and what you learned from it",
            "How would you handle a team member who consistently underperforms?"
        ],
        'tone': 'direct and challenging',
        'time_limit': 10,  # seconds (but system prompt says 5 for psychological pressure)
        'scoring_focus': 'quick thinking and leadership scenarios'
    }
}

# Create the interview protocol
interview_protocol = Protocol()

@interview_protocol.on_message(model=InterviewAnswer, replies=FollowUpQuestion)
async def handle_interview_answer(ctx: Context, sender: str, msg: InterviewAnswer):
    """Handle user's interview answer and respond with appropriate follow-up question"""
    
    # Determine agent type from the agent's name
    agent_name = ctx.agent.name
    mode = None
    
    for mode_key, config in MODE_CONFIGS.items():
        if config['name'] in agent_name:
            mode = mode_key
            break
    
    if not mode:
        mode = 'easy'  # Default fallback
    
    config = MODE_CONFIGS[mode]
    
    # Analyze the answer and generate follow-up
    follow_up = await generate_follow_up_question(msg.answer, mode, config)
    
    # Send the follow-up question
    await ctx.send(sender, FollowUpQuestion(

[truncated — 4898 more characters]
```

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