Build a Professional AI Agent Team for Free | Complete Project with Python + React + Agno + Groq

Build a Team of AI Agents for Your Website for Free

Build a Team of AI Agents for Your Website for Free Using Agno & Groq

🎯 Quick Answer:

AI Agents are intelligent programs that automatically interact with your website visitors. Using the Agno library as an orchestration layer and Groq Cloud as an ultra-fast inference engine with the LLaMA 3.3 70B model, you can build five specialized agents:

  • 🎭 Welcome Agent — Greets visitors and guides them
  • 💼 Project Agent — Showcases your technical work
  • 📋 Career Agent — Summarizes your experience and skills
  • 🤝 Client Agent — Presents services and pricing
  • 🔬 Research Agent — Searches for the latest technologies

With a Python backend via Flask and a React frontend via Vite — completely free.

🚀 Introduction

The world of web development is undergoing a radical transformation thanks to Artificial Intelligence. Companies and developers are increasingly relying on AI agents to deliver interactive experiences to their website visitors.

Imagine having a complete team of intelligent assistants working on your website around the clock:

  • ✨ Greeting visitors personally based on their profile
  • 💬 Answering their technical and practical questions
  • 🖥️ Showcasing your projects in detail
  • 💰 Providing consultations and quotes to potential clients
  • 🔍 Researching the latest technologies and trends

And all of this completely free!

In this comprehensive guide, I'll walk you through building this team step by step using free and open-source tools. I'll show you the complete code for every file in the project so you can implement it directly.

🤖 What Are AI Agents?

AI Agents are intelligent software systems designed to use artificial intelligence techniques to interact with their environment and achieve specific goals. They can perceive their surroundings — through user inputs or data — and take actions to achieve objectives with a certain degree of autonomy.

Unlike traditional chatbots that rely on pre-programmed responses, AI agents can:

  • 🧠 Understand Context — They grasp what the user means even when it's not explicit
  • 🎯 Deliver Personalized Responses — They generate unique answers for each question
  • 📚 Learn from Interactions — They improve over time
  • 🔗 Integrate with Other Systems — They can search, analyze, and take actions

🆚 Traditional Chatbot vs. AI Agent

💬
Traditional Chatbot
  • 📋 Pre-defined Responses
    Relies on fixed scenarios
  • 🔄 Limited Interaction
    Rigid conversation paths
  • ❌ Surface-Level Understanding
    Relies on keywords only
  • ⚙️ Complex Maintenance
    Requires constant manual updates
🧠
AI Agent
  • 🎓 Continuous Learning
    Improves automatically with each interaction
  • 💡 Contextual Intelligence
    Understands intent and context
  • ✨ Dynamic Responses
    Generates unique, tailored answers
  • 🔗 Advanced Integration
    Connects with multiple systems and tools
95%
Context Understanding Accuracy
3x
Faster Problem Resolution
24/7
Always Available to Evolve

🛠️ What Are Agno & Groq Cloud?

Before diving into the practical implementation, it's essential to understand the main tools we'll be using.

🔷 Agno: The Intelligent Orchestration Layer

Agno is a lightweight Python library that enables you to build multimodal AI agents. It serves as an orchestration layer that:

  • Manages conversations between multiple agents
  • Delegates tasks to the appropriate agent
  • Handles memory and context management
  • Provides a unified interface for working with different LLM models

⚡ Groq Cloud: The Ultra-Fast Inference Engine

Groq Cloud is a cloud-based AI inference platform powered by Groq LPU (Language Processing Unit) chips, optimized for ultra-low latency workloads.

Important Note: Groq Cloud is not a large language model itself; rather, it's a high-performance inference engine that hosts and serves LLM models from multiple providers:

  • 🦙 Meta LLaMA — The model we'll use: llama-3.3-70b-versatile
  • 🔮 DeepSeek R1
  • 💎 Google Gemma 2
  • 🌬️ Mistral AI
  • 🏮 Qwen
💡 Why Did We Choose LLaMA 3.3 70B?

This model offers an excellent balance between performance and speed, supports multiple languages well, and is available for free on Groq Cloud. You can switch to a different model later if needed.

🏗️ What Will You Build in This Project?

You'll build a personal portfolio website featuring a team of five specialized AI agents. These agents function as intelligent customer service representatives — anyone can ask them about your skills, projects, and experience.

Agent Class Name Function
🎭 Welcome Agent WelcomeAgent Greets visitors and guides them based on their type (employer, client, developer)
💼 Project Agent ProjectAgent Showcases project details and answers technical questions
📋 Career Agent CareerAgent Summarizes skills and experience, assesses job fit
🤝 Client Agent ClientAgent Provides service information, pricing, and generates quotes
🔬 Research Agent ResearchAgent Searches the web for technologies and trends, compares them

📄 Website Pages:

🏠

Home

💻

Projects

📋

Career

🛠️

Services

🔬

Research

📧

Contact

📦 Prerequisites

Before getting started, make sure you have the following requirements on your machine:

✅ Required Knowledge:

  • Basic knowledge of Python
  • Basic knowledge of JavaScript and React
  • Understanding of REST APIs principles
  • Familiarity with Terminal/Command Line commands

💻 Required Software:

  • Python 3.8+ — Download Python
  • Node.js 18+ and npm — Download Node.js
  • Code Editor — VS Code, Cursor, or PyCharm
  • Git (optional) — For version control

🔑 Required Accounts:

🔐 Creating a Groq Cloud Account and Getting Your API Key

The first step is creating a free account on Groq Cloud to obtain the API key that will enable our agents to communicate with AI models.

📝 Account Creation Steps:

  1. Go to the Groq Cloud signup page
  2. Sign in using your Google or GitHub account, or create a new account
  3. After signing in, navigate to the "API Keys" page from the sidebar
  4. Click on "Create API Key"
  5. Give your key a memorable name (e.g., ai-agents-portfolio)
  6. Very Important: Copy the key and save it somewhere secure — you won't be able to see it again!
Creating an API Key on Groq Cloud

Creating an API Key on Groq Cloud

⚠️ Important Security Warnings:
  • ❌ Never share your API key with anyone
  • ❌ Never commit it to public repositories on GitHub
  • ✅ Always use .env files to store secret keys
  • ✅ Add .env to your .gitignore file
💡 Free Tier Limits:

The service is free but has usage limits. You can review them in the Rate Limits documentation. The free tier is more than sufficient for personal and educational projects.

🐍 Setting Up the Python Project (Backend)

Now we'll begin building the Backend using Python and Flask. We'll create a clean virtual environment and install all the required packages.

📁 Step 1: Create the Project Folder and Virtual Environment

Open your Terminal or Command Prompt and run the following commands:

# Create the main project folder
mkdir ai-agents-portfolio
cd ai-agents-portfolio

# Create the backend folder
mkdir backend
cd backend

# Create a Python virtual environment
python -m venv venv

# Activate the environment on Windows
venv\Scripts\activate

# Activate the environment on macOS/Linux
# source venv/bin/activate
💡 What is a Virtual Environment?

A virtual environment is an isolated space that contains an independent copy of Python and installed packages. This prevents conflicts between different projects and ensures your project works the same way on any machine.

📦 Step 2: Install Required Packages

After activating the virtual environment, install the following packages:

# Install all required packages
pip install agno groq flask flask-cors requests python-dotenv
Package Purpose
agno AI agent orchestration library
groq Official SDK for connecting to Groq Cloud
flask Lightweight web framework for building APIs
flask-cors Enable cross-origin requests (for the frontend)
requests Send HTTP requests (for web searching)
python-dotenv Load environment variables from .env file

🗂️ Step 3: Create the File Structure

Now we'll create the folder and file structure for the project:

# Create the agents folder
mkdir agents

# Create the files (Windows - PowerShell)
New-Item -ItemType File -Name ".env"
New-Item -ItemType File -Name "main.py"
New-Item -ItemType File -Name "agents/__init__.py"
New-Item -ItemType File -Name "agents/base_agent.py"
New-Item -ItemType File -Name "agents/welcome_agent.py"
New-Item -ItemType File -Name "agents/project_agent.py"
New-Item -ItemType File -Name "agents/career_agent.py"
New-Item -ItemType File -Name "agents/client_agent.py"
New-Item -ItemType File -Name "agents/research_agent.py"

# On macOS/Linux use touch instead of New-Item
# touch .env main.py
# touch agents/__init__.py agents/base_agent.py ...

📂 backend/ folder structure

backend/
├── 📄 .env                      # Environment variables (API key)
├── 📄 .gitignore               # Files ignored by Git
├── 📄 main.py                  # Main file (Flask Server)
├── 📄 requirements.txt         # Package list
└── 📁 agents/                  # Agents folder
    ├── 📄 __init__.py          # Export file
    ├── 📄 base_agent.py        # Base agent
    ├── 📄 welcome_agent.py     # Welcome agent
    ├── 📄 project_agent.py     # Project agent
    ├── 📄 career_agent.py      # Career agent
    ├── 📄 client_agent.py      # Client agent
    └── 📄 research_agent.py    # Research agent

🔑 Step 4: Set Up the Environment Variables File (.env)

Open the .env file and add the API key you obtained from Groq Cloud:

📄 File: .env

# Groq Cloud API Key
GROQ_API_KEY=gsk_your_actual_api_key_here

# You can add other variables later
# FLASK_ENV=development
# FLASK_DEBUG=1
🚨 Important Reminder:

Replace gsk_your_actual_api_key_here with the actual API key you copied from Groq Cloud. The key typically starts with gsk_.

📄 Step 5: Create the .gitignore File

If you'll be using Git, create a .gitignore file to protect your sensitive files:

📄 File: .gitignore

# Environment variables
.env
.env.local
.env.*.local

# Python
venv/
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
dist/
*.egg-info/

# IDE
.vscode/
.idea/
*.swp
*.swo

# OS
.DS_Store
Thumbs.db

📋 Step 6: Create the requirements.txt File

This file makes it easy to install packages on any other machine:

📄 File: requirements.txt

agno>=1.0.0
groq>=0.4.0
flask>=3.0.0
flask-cors>=4.0.0
requests>=2.31.0
python-dotenv>=1.0.0

🤖 Agent Files (Complete Code)

Now we move on to writing the actual code for the agents. We'll start with the base agent that all agents inherit from, then create each specialized agent. I'll explain every line in the code.

1️⃣ Base Agent — base_agent.py

This file defines the BaseAgent class that all agents inherit from. It contains shared settings and the connection to Groq Cloud.

📄 File: agents/base_agent.py

# Import required libraries
from agno.agent import Agent
from agno.models.groq import Groq
from dotenv import load_dotenv
import os

# Load environment variables from .env file
load_dotenv()


class BaseAgent:
    """
    The base agent that all specialized agents inherit from.
    Provides shared settings and connection to the LLaMA model via Groq.
    """
    
    def __init__(self, name, description, avatar="default_avatar.png"):
        """
        Initialize the base agent.
        
        Args:
            name: Agent name (for display)
            description: Brief description of the agent's function
            avatar: Agent image (optional)
        """
        self.name = name
        self.description = description
        self.avatar = avatar
        
        # Set up LLaMA 3.3 70B model via Groq
        # This model offers an excellent balance between quality and speed
        self.model = Groq(id="llama-3.3-70b-versatile")
        
        # Create Agno agent with Markdown support enabled
        self.agent = Agent(
            model=self.model,
            markdown=True  # Enable Markdown formatting in responses
        )

    def get_response(self, query, stream=False):
        """
        Get a response from the agent.
        
        Args:
            query: The question or request from the user
            stream: Whether to stream the response (default: False)
            
        Returns:
            Agent response as text or RunResponse object
        """
        try:
            response = self.agent.run(query, stream=stream)
            return response
        except Exception as e:
            return f"Error getting response: {str(e)}"

    def print_response(self, query, stream=True):
        """
        Print the agent's response directly to the console.
        Useful for testing and development.
        """
        return self.agent.print_response(query, stream=stream)
🔍 Code Explanation:
  • load_dotenv() — Loads environment variables from the .env file (including GROQ_API_KEY)
  • Groq(id="llama-3.3-70b-versatile") — Creates a connection to the LLaMA model via Groq Cloud
  • Agent(model, markdown=True) — Creates an Agno agent with Markdown support
  • agent.run(query) — Sends the query to the model and gets the response

2️⃣ Welcome Agent — welcome_agent.py

This agent is the first point of contact for visitors. It provides personalized greetings based on the visitor type and guides them to the appropriate sections of the website.

📄 File: agents/welcome_agent.py

from agents.base_agent import BaseAgent


class WelcomeAgent(BaseAgent):
    """
    Welcome Agent - Greets visitors and guides them to the appropriate sections.
    """
    
    def __init__(self):
        # Call the base agent constructor
        super().__init__(
            name="Greeter",
            description="I'm the welcome agent for this portfolio. I help guide visitors to the right section.",
            avatar="welcome_avatar.png"
        )

    def greet(self, visitor_type=None):
        """
        Generate a personalized greeting based on visitor type.
        
        Args:
            visitor_type: Type of visitor (employer/client/fellow_programmer/None)
            
        Returns:
            Personalized greeting from the agent
        """
        
        if visitor_type == "employer":
            prompt = """
            Generate a friendly, professional greeting for a potential employer 
            visiting a programmer's portfolio website.
            
            Guidelines:
            - Be warm but professional
            - Mention they can explore the Projects section for technical skills
            - Mention the Career section for professional experience
            - Keep it concise (2-3 sentences)
            - Use a welcoming tone
            """
            
        elif visitor_type == "client":
            prompt = """
            Generate a friendly, business-oriented greeting for a potential client 
            visiting a programmer's portfolio website.
            
            Guidelines:
            - Be warm and service-oriented
            - Mention the Projects section for examples of past work
            - Mention the Services section for available services and pricing
            - Emphasize quality and reliability
            - Keep it concise (2-3 sentences)
            """
            
        elif visitor_type == "fellow_programmer":
            prompt = """
            Generate a friendly, casual greeting for a fellow programmer 
            visiting a portfolio website.
            
            Guidelines:
            - Be friendly and collegial
            - Mention the Projects section for technical details and code samples
            - Mention the Research section for tech insights
            - Use a more casual, developer-to-developer tone
            - Keep it concise (2-3 sentences)
            """
            
        else:
            # General greeting for unspecified visitors
            prompt = """
            Generate a friendly, general greeting for a visitor to a programmer's 
            portfolio website.
            
            Guidelines:
            - Be warm and welcoming
            - Ask if they are an employer, client, or fellow programmer
            - Offer to help them find what they're looking for
            - Keep it concise (2-3 sentences)
            """
        
        return self.get_response(prompt)

    def suggest_section(self, interest):
        """
        Suggest an appropriate section based on visitor interest.
        
        Args:
            interest: Visitor's interest (e.g., "machine learning", "web development")
            
        Returns:
            Suggestion with a brief explanation
        """
        prompt = f"""
        A visitor expressed interest in '{interest}'.
        
        Based on this interest, suggest which section of a programmer's portfolio 
        they should visit.
        
        Available sections:
        - Projects: Technical projects with code samples
        - Career: Professional experience and skills
        - Services: Available services for clients
        - Research: Latest tech trends and insights
        - Contact: Get in touch
        
        Provide a brief recommendation (1-2 sentences) explaining why that section 
        would be most relevant for their interest.
        """
        
        return self.get_response(prompt)

    def answer_question(self, question):
        """
        Answer general questions from visitors.
        
        Args:
            question: Visitor's question
            
        Returns:
            Helpful, directed answer
        """
        prompt = f"""
        A visitor to a programmer's portfolio website asked: "{question}"
        
        Provide a helpful, friendly response. If the question is about:
        - Technical skills → Suggest visiting the Projects or Career section
        - Services/Pricing → Suggest visiting the Services section
        - Getting in touch → Suggest visiting the Contact section
        - Tech trends → Suggest visiting the Research section
        
        Keep your response concise and helpful (2-4 sentences).
        """
        
        return self.get_response(prompt)

3️⃣ Project Agent — project_agent.py

This agent specializes in showcasing technical projects and answering questions related to implementation details and technologies used.

📄 File: agents/project_agent.py

from agents.base_agent import BaseAgent


class ProjectAgent(BaseAgent):
    """
    Project Agent - Showcases technical projects and answers related questions.
    """
    
    def __init__(self):
        super().__init__(
            name="TechExpert",
            description="I'm the project specialist. I provide detailed information about technical projects.",
            avatar="project_avatar.png"
        )
        
        # Projects database (in a real project, this would come from an actual database)
        self.projects = {
            "ecommerce": {
                "name": "E-commerce Platform",
                "tech_stack": ["React", "Node.js", "MongoDB", "Express", "Stripe"],
                "description": "A full-stack e-commerce platform with user authentication, product catalog, shopping cart, and payment processing.",
                "highlights": [
                    "Responsive design for all devices",
                    "RESTful API architecture",
                    "Stripe payment integration",
                    "JWT authentication",
                    "Admin dashboard"
                ],
                "github_link": "https://github.com/username/ecommerce-platform",
                "demo_link": "https://ecommerce-demo.example.com",
                "status": "Completed",
                "year": "2024"
            },
            "taskmanager": {
                "name": "Task Management App",
                "tech_stack": ["Vue.js", "Firebase", "Tailwind CSS", "Vuex"],
                "description": "A real-time task management application with collaborative features, notifications, and progress tracking.",
                "highlights": [
                    "Real-time synchronization",
                    "Team collaboration features",
                    "Drag-and-drop interface",
                    "Progressive Web App (PWA)",
                    "Push notifications"
                ],
                "github_link": "https://github.com/username/task-manager",
                "demo_link": "https://taskmanager-demo.example.com",
                "status": "Completed",
                "year": "2024"
            },
            "dashboard": {
                "name": "Data Visualization Dashboard",
                "tech_stack": ["Python", "Django", "D3.js", "PostgreSQL", "Redis"],
                "description": "An interactive dashboard for visualizing complex datasets with filtering, sorting, and export capabilities.",
                "highlights": [
                    "Interactive charts and graphs",
                    "Advanced data filtering",
                    "CSV/PDF export",
                    "Caching with Redis",
                    "Responsive design"
                ],
                "github_link": "https://github.com/username/data-dashboard",
                "demo_link": "https://dataviz-demo.example.com",
                "status": "Completed",
                "year": "2023"
            },
            "aiagents": {
                "name": "AI Agents Portfolio",
                "tech_stack": ["Python", "Flask", "React", "Agno", "Groq"],
                "description": "This very portfolio website featuring a team of AI agents powered by LLaMA 3.3.",
                "highlights": [
                    "5 specialized AI agents",
                    "Real-time chat interface",
                    "Web search capabilities",
                    "Markdown rendering",
                    "Responsive design"
                ],
                "github_link": "https://github.com/username/ai-agents-portfolio",
                "demo_link": "https://ai-portfolio.example.com",
                "status": "In Progress",
                "year": "2025"
            }
        }

    def get_project_list(self):
        """
        Get a list of all projects with a summary for each.
        """
        projects_summary = []
        for project_id, project in self.projects.items():
            projects_summary.append(
                f"- **{project['name']}** ({project['year']}): {project['description'][:100]}..."
            )
        
        projects_text = "\n".join(projects_summary)
        
        prompt = f"""
        Present the following projects in an engaging way for a portfolio website:
        
        {projects_text}
        
        Format as a numbered list with brief descriptions. 
        Add emojis for visual appeal.
        Mention that visitors can ask for more details about any specific project.
        """
        
        return self.get_response(prompt)

    def get_project_details(self, project_id):
        """
        Get details for a specific project.
        
        Args:
            project_id: Project identifier (ecommerce, taskmanager, dashboard, aiagents)
        """
        # Search for project by ID or name
        project = self.projects.get(project_id.lower())
        
        if not project:
            # Search by partial name
            for pid, p in self.projects.items():
                if project_id.lower() in p['name'].lower():
                    project = p
                    break
        
        if not project:
            return self.get_response(
                f"I couldn't find a project matching '{project_id}'. "
                f"Available projects are: {', '.join([p['name'] for p in self.projects.values()])}"
            )
        
        prompt = f"""
        Generate a detailed, engaging description for this project:
        
        **Project Name:** {project['name']}
        **Tech Stack:** {', '.join(project['tech_stack'])}
        **Description:** {project['description']}
        **Key Features:** {', '.join(project['highlights'])}
        **GitHub:** {project['github_link']}
        **Live Demo:** {project['demo_link']}
        **Status:** {project['status']}
        **Year:** {project['year']}
        
        Include:
        1. A brief overview
        2. Technical details about implementation
        3. Key features and what makes it special
        4. Links to GitHub and demo
        
        Format the response in markdown with appropriate headers and bullet points.
        """
        
        return self.get_response(prompt)

    def answer_technical_question(self, project_id, question):
        """
        Answer a technical question about a specific project.
        
        Args:
            project_id: Project identifier
            question: The technical question
        """
        project = self.projects.get(project_id.lower())
        
        if not project:
            # Search by partial name
            for pid, p in self.projects.items():
                if project_id.lower() in p['name'].lower():
                    project = p
                    break
        
        if not project:
            return self.get_response(
                f"Project not found. Available projects: {', '.join([p['name'] for p in self.projects.values()])}"
            )
        
        prompt = f"""
        Answer this technical question about the project:
        
        **Project:** {project['name']}
        **Tech Stack:** {', '.join(project['tech_stack'])}
        **Description:** {project['description']}
        **Features:** {', '.join(project['highlights'])}
        
        **Question:** {question}
        
        Provide a detailed technical answer. If relevant, include:
        - Code examples or snippets
        - Architecture decisions
        - Best practices used
        - Challenges faced and solutions
        
        Format the response in markdown.
        """
        
        return self.get_response(prompt)

    def search_projects(self, technology):
        """
        Search for projects using a specific technology.
        
        Args:
            technology: Technology name (e.g., React, Python, MongoDB)
        """
        matching_projects = []
        
        for project_id, project in self.projects.items():
            for tech in project['tech_stack']:
                if technology.lower() in tech.lower():
                    matching_projects.append(project)
                    break
        
        if not matching_projects:
            return self.get_response(
                f"No projects found using '{technology}'. "
                f"Technologies used in my projects include: React, Vue.js, Node.js, Python, Django, Flask, MongoDB, PostgreSQL, Firebase."
            )
        
        projects_text = "\n".join([
            f"- {p['name']}: {p['description'][:80]}..."
            for p in matching_projects
        ])
        
        prompt = f"""
        The visitor is looking for projects that use {technology}.
        
        Here are the matching projects:
        {projects_text}
        
        Present these projects in an engaging way, highlighting how {technology} 
        is used in each one. Offer to provide more details about any specific project.
        """
        
        return self.get_response(prompt)

4️⃣ Career Agent — career_agent.py

This agent is designed to help potential employers learn about professional skills and experience, and assess how well the candidate fits different job positions.

📄 File: agents/career_agent.py

from agents.base_agent import BaseAgent


class CareerAgent(BaseAgent):
    """
    Career Agent - Provides information about skills and experience.
    """
    
    def __init__(self):
        super().__init__(
            name="CareerGuide",
            description="I'm the career specialist. I provide information about skills, experience, and job suitability.",
            avatar="career_avatar.png"
        )
        
        # Skills database
        self.skills = {
            "programming_languages": {
                "expert": ["Python", "JavaScript", "TypeScript"],
                "proficient": ["Java", "SQL", "PHP"],
                "familiar": ["Go", "Rust", "C++"]
            },
            "frameworks": {
                "frontend": ["React", "Vue.js", "Next.js", "Tailwind CSS"],
                "backend": ["Node.js", "Express", "Django", "Flask", "FastAPI"],
                "mobile": ["React Native", "Flutter"]
            },
            "databases": ["PostgreSQL", "MongoDB", "MySQL", "Redis", "Firebase"],
            "cloud_devops": ["AWS", "Google Cloud", "Docker", "Kubernetes", "CI/CD", "GitHub Actions"],
            "soft_skills": [
                "Team Leadership",
                "Project Management",
                "Agile/Scrum",
                "Technical Writing",
                "Client Communication",
                "Problem Solving"
            ]
        }
        
        # Professional experience database
        self.experience = [
            {
                "title": "Senior Full Stack Developer",
                "company": "Tech Innovations Inc.",
                "period": "2022 - Present",
                "type": "Full-time",
                "responsibilities": [
                    "Led development of cloud-based SaaS platform serving 10,000+ users",
                    "Managed and mentored team of 5 developers",
                    "Implemented CI/CD pipeline reducing deployment time by 60%",
                    "Architected microservices infrastructure on AWS",
                    "Reduced server costs by 40% through optimization"
                ],
                "technologies": ["React", "Node.js", "AWS", "PostgreSQL", "Docker"]
            },
            {
                "title": "Full Stack Developer",
                "company": "WebSolutions Co.",
                "period": "2019 - 2022",
                "type": "Full-time",
                "responsibilities": [
                    "Developed responsive web applications using React and Vue.js",
                    "Built RESTful APIs with Node.js and Django",
                    "Collaborated with UX/UI designers on user-friendly interfaces",
                    "Conducted code reviews and mentored junior developers",
                    "Implemented automated testing achieving 85% code coverage"
                ],
                "technologies": ["Vue.js", "Django", "MongoDB", "Redis"]
            },
            {
                "title": "Junior Developer",
                "company": "StartUp Labs",
                "period": "2017 - 2019",
                "type": "Full-time",
                "responsibilities": [
                    "Built and maintained client websites and web applications",
                    "Developed custom WordPress plugins and themes",
                    "Implemented responsive designs with cross-browser compatibility",
                    "Assisted in database design and query optimization"
                ],
                "technologies": ["PHP", "WordPress", "MySQL", "JavaScript"]
            }
        ]
        
        # Education and certifications
        self.education = {
            "degree": "Bachelor's in Computer Science",
            "university": "University of Technology",
            "year": "2017",
            "certifications": [
                "AWS Certified Solutions Architect",
                "Google Cloud Professional Developer",
                "MongoDB Certified Developer"
            ]
        }

    def get_skills_summary(self):
        """
        Get a comprehensive summary of technical skills.
        """
        skills_text = f"""
        **Programming Languages:**
        - Expert: {', '.join(self.skills['programming_languages']['expert'])}
        - Proficient: {', '.join(self.skills['programming_languages']['proficient'])}
        - Familiar: {', '.join(self.skills['programming_languages']['familiar'])}
        
        **Frameworks & Libraries:**
        - Frontend: {', '.join(self.skills['frameworks']['frontend'])}
        - Backend: {', '.join(self.skills['frameworks']['backend'])}
        - Mobile: {', '.join(self.skills['frameworks']['mobile'])}
        
        **Databases:** {', '.join(self.skills['databases'])}
        
        **Cloud & DevOps:** {', '.join(self.skills['cloud_devops'])}
        
        **Soft Skills:** {', '.join(self.skills['soft_skills'])}
        """
        
        prompt = f"""
        Generate a professional, engaging summary of these technical skills 
        for a portfolio website:
        
        {skills_text}
        
        Format the response with:
        - Clear sections with emojis
        - Skill levels clearly indicated
        - A brief introduction about being a full-stack developer
        - Use markdown formatting
        """
        
        return self.get_response(prompt)

    def get_experience_summary(self):
        """
        Get a summary of professional experience.
        """
        experience_text = ""
        for job in self.experience:
            experience_text += f"""
            **{job['title']}** at {job['company']}
            *{job['period']}* ({job['type']})
            
            Responsibilities:
            {chr(10).join(['- ' + r for r in job['responsibilities']])}
            
            Technologies: {', '.join(job['technologies'])}
            
            ---
            """
        
        prompt = f"""
        Generate a professional career summary based on this work experience:
        
        {experience_text}
        
        Education: {self.education['degree']} from {self.education['university']} ({self.education['year']})
        Certifications: {', '.join(self.education['certifications'])}
        
        Include:
        1. A compelling career narrative showing progression
        2. Key achievements highlighted
        3. Total years of experience
        4. Education and certifications
        
        Format in markdown with clear sections.
        """
        
        return self.get_response(prompt)

    def assess_job_fit(self, job_description):
        """
        Assess how well skills match a specific job.
        
        Args:
            job_description: Description of the desired job
        """
        # Gather all skills
        all_skills = []
        all_skills.extend(self.skills['programming_languages']['expert'])
        all_skills.extend(self.skills['programming_languages']['proficient'])
        all_skills.extend(self.skills['frameworks']['frontend'])
        all_skills.extend(self.skills['frameworks']['backend'])
        all_skills.extend(self.skills['databases'])
        all_skills.extend(self.skills['cloud_devops'])
        
        # Gather experience
        experience_summary = []
        for job in self.experience:
            experience_summary.extend(job['responsibilities'])
        
        prompt = f"""
        Assess the fit for this job based on the candidate's profile:
        
        **Job Description:**
        {job_description}
        
        **Candidate's Skills:**
        {', '.join(all_skills)}
        
        **Candidate's Experience:**
        - 7+ years of professional experience
        - {chr(10).join(['- ' + exp for exp in experience_summary[:8]])}
        
        **Certifications:**
        {', '.join(self.education['certifications'])}
        
        Provide:
        1. **Match Score**: X/10 with brief explanation
        2. **Matching Skills**: Skills that align with the job
        3. **Strengths**: Why this candidate is a good fit
        4. **Potential Gaps**: Any missing requirements (if any)
        5. **Recommendation**: Final assessment
        
        Be honest but positive. Format in markdown.
        """
        
        return self.get_response(prompt)

    def answer_career_question(self, question):
        """
        Answer general questions about the career.
        """
        prompt = f"""
        Answer this career-related question based on the following profile:
        
        **Question:** {question}
        
        **Profile Summary:**
        - 7+ years of full-stack development experience
        - Expert in Python, JavaScript, TypeScript
        - Experienced with React, Vue.js, Node.js, Django
        - Strong background in cloud services (AWS, GCP)
        - Team leadership and project management experience
        - Bachelor's in Computer Science
        - AWS and GCP certified
        
        Provide a helpful, professional answer. If the question is about 
        availability, mention that the candidate is open to opportunities.
        """
        
        return self.get_response(prompt)

5️⃣ Client Agent — client_agent.py

This agent is designed to help potential clients learn about available services, explain the engagement process, and generate custom quotes.

📄 File: agents/client_agent.py

from agents.base_agent import BaseAgent


class ClientAgent(BaseAgent):
    """
    Client Agent - Provides service information and generates quotes.
    """
    
    def __init__(self):
        super().__init__(
            name="BusinessAdvisor",
            description="I'm the client specialist. I provide information about services, pricing, and project proposals.",
            avatar="client_avatar.png"
        )
        
        # Services database
        self.services = {
            "web_development": {
                "name": "Web Application Development",
                "description": "Custom web application development using modern frameworks and best practices. From simple websites to complex SaaS platforms.",
                "features": [
                    "Responsive design for all devices",
                    "Modern UI/UX implementation",
                    "SEO optimization",
                    "Performance optimization",
                    "Security best practices"
                ],
                "pricing_model": "Project-based or hourly",
                "price_range": {
                    "simple": "\\$2,000 - \\$5,000",
                    "medium": "\\$5,000 - \\$15,000",
                    "complex": "\\$15,000 - \\$50,000+"
                },
                "timeline": "4-16 weeks depending on complexity",
                "technologies": ["React", "Vue.js", "Next.js", "Node.js", "Django"]
            },
            "mobile_development": {
                "name": "Mobile App Development",
                "description": "Native and cross-platform mobile application development for iOS and Android.",
                "features": [
                    "Cross-platform development (iOS & Android)",
                    "Native performance",
                    "Push notifications",
                    "Offline functionality",
                    "App Store submission support"
                ],
                "pricing_model": "Project-based",
                "price_range": {
                    "simple": "\\$8,000 - \\$15,000",
                    "medium": "\\$15,000 - \\$35,000",
                    "complex": "\\$35,000 - \\$80,000+"
                },
                "timeline": "8-20 weeks depending on complexity",
                "technologies": ["React Native", "Flutter", "Swift", "Kotlin"]
            },
            "api_development": {
                "name": "API Development & Integration",
                "description": "RESTful and GraphQL API development, third-party integrations, and backend services.",
                "features": [
                    "RESTful API design",
                    "GraphQL implementation",
                    "Third-party integrations",
                    "API documentation",
                    "Authentication & security"
                ],
                "pricing_model": "Project-based or hourly",
                "price_range": {
                    "simple": "\\$1,500 - \\$4,000",
                    "medium": "\\$4,000 - \\$10,000",
                    "complex": "\\$10,000 - \\$25,000+"
                },
                "timeline": "2-8 weeks depending on scope",
                "technologies": ["Node.js", "FastAPI", "Django REST", "GraphQL"]
            },
            "consulting": {
                "name": "Technical Consulting",
                "description": "Expert advice on architecture, technology stack selection, code review, and development best practices.",
                "features": [
                    "Architecture review & design",
                    "Technology stack recommendations",
                    "Code review & audit",
                    "Performance optimization",
                    "Team training & mentoring"
                ],
                "pricing_model": "Hourly",
                "price_range": {
                    "hourly": "\\$100 - \\$200 per hour",
                    "daily": "\\$700 - \\$1,400 per day"
                },
                "timeline": "Flexible - ongoing or one-time",
                "technologies": ["All major technologies"]
            }
        }
        
        # Engagement process
        self.process_steps = [
            {
                "step": 1,
                "name": "Discovery Call",
                "description": "Free 30-minute consultation to understand your needs and goals.",
                "duration": "30 minutes"
            },
            {
                "step": 2,
                "name": "Proposal & Quote",
                "description": "Detailed proposal with scope, timeline, and pricing.",
                "duration": "2-3 business days"
            },
            {
                "step": 3,
                "name": "Contract & Kickoff",
                "description": "Sign agreement and begin project with kickoff meeting.",
                "duration": "1-2 days"
            },
            {
                "step": 4,
                "name": "Design & Planning",
                "description": "UI/UX design, technical architecture, and sprint planning.",
                "duration": "1-2 weeks"
            },
            {
                "step": 5,
                "name": "Development Sprints",
                "description": "Agile development with regular demos and feedback cycles.",
                "duration": "Varies by project"
            },
            {
                "step": 6,
                "name": "Testing & QA",
                "description": "Comprehensive testing, bug fixes, and quality assurance.",
                "duration": "1-2 weeks"
            },
            {
                "step": 7,
                "name": "Launch & Deployment",
                "description": "Production deployment with monitoring setup.",
                "duration": "1-3 days"
            },
            {
                "step": 8,
                "name": "Support & Maintenance",
                "description": "30 days free support, optional ongoing maintenance plans.",
                "duration": "Ongoing"
            }
        ]

    def get_services_overview(self):
        """
        Get an overview of all services.
        """
        services_text = ""
        for service_id, service in self.services.items():
            services_text += f"""
            **{service['name']}**
            {service['description']}
            Timeline: {service['timeline']}
            Technologies: {', '.join(service['technologies'])}
            
            """
        
        prompt = f"""
        Present these services in an engaging, professional way for potential clients:
        
        {services_text}
        
        Format with:
        - Clear sections for each service
        - Emojis for visual appeal
        - Brief but compelling descriptions
        - Mention that detailed pricing is available upon request
        - Invite them to ask about any specific service
        
        Use markdown formatting.
        """
        
        return self.get_response(prompt)

    def get_service_details(self, service_name):
        """
        Get details for a specific service.
        """
        # Search for the service
        service = None
        for sid, s in self.services.items():
            if service_name.lower() in s['name'].lower() or service_name.lower() in sid:
                service = s
                break
        
        if not service:
            available = ", ".join([s['name'] for s in self.services.values()])
            return self.get_response(
                f"I couldn't find a service matching '{service_name}'. "
                f"Available services are: {available}"
            )
        
        prompt = f"""
        Provide detailed information about this service for a potential client:
        
        **Service:** {service['name']}
        **Description:** {service['description']}
        
        **Features:**
        {chr(10).join(['- ' + f for f in service['features']])}
        
        **Pricing:** {service['pricing_model']}
        - Simple projects: {service['price_range'].get('simple', 'N/A')}
        - Medium projects: {service['price_range'].get('medium', 'N/A')}
        - Complex projects: {service['price_range'].get('complex', 'N/A')}
        
        **Timeline:** {service['timeline']}
        **Technologies:** {', '.join(service['technologies'])}
        
        Format professionally with:
        - Value proposition
        - What's included
        - Pricing breakdown
        - Call to action (schedule a consultation)
        
        Use markdown formatting.
        """
        
        return self.get_response(prompt)

    def explain_process(self):
        """
        Explain the engagement and work process.
        """
        process_text = ""
        for step in self.process_steps:
            process_text += f"""
            Step {step['step']}: {step['name']}
            {step['description']}
            Duration: {step['duration']}
            
            """
        
        prompt = f"""
        Explain the client engagement process in a friendly, professional way:
        
        {process_text}
        
        Format as a clear step-by-step guide with:
        - Numbered steps with emojis
        - Brief explanation of each phase
        - What the client can expect
        - Timeline indicators
        
        Emphasize the collaborative nature and regular communication.
        Use markdown formatting.
        """
        
        return self.get_response(prompt)

    def generate_proposal(self, project_description):
        """
        Generate a preliminary quote based on project description.
        """
        prompt = f"""
        Generate a preliminary project proposal based on this description:
        
        **Client's Project Description:**
        {project_description}
        
        **Available Services:**
        - Web Development: \\$2,000 - \\$50,000+ (4-16 weeks)
        - Mobile Development: \\$8,000 - \\$80,000+ (8-20 weeks)
        - API Development: \\$1,500 - \\$25,000+ (2-8 weeks)
        - Consulting: \\$100-200/hour
        
        Create a professional proposal with:
        
        1. **Project Understanding** - Show you understand their needs
        2. **Proposed Solution** - Recommend approach and technologies
        3. **Scope of Work** - Break down the deliverables
        4. **Estimated Timeline** - Realistic phases
        5. **Budget Range** - Preliminary estimate with explanation
        6. **Next Steps** - How to proceed (schedule a call)
        
        Be professional but friendly. Include a disclaimer that this is 
        a preliminary estimate and final pricing requires a detailed discussion.
        
        Use markdown formatting with clear sections.
        """
        
        return self.get_response(prompt)

    def answer_client_question(self, question):
        """
        Answer general client questions.
        """
        prompt = f"""
        Answer this client question professionally:
        
        **Question:** {question}
        
        **Context:**
        - Services: Web Development, Mobile Apps, APIs, Consulting
        - Experience: 7+ years, 50+ projects delivered
        - Process: Agile methodology with regular updates
        - Support: 30 days free post-launch support
        - Payment: Typically 30% upfront, 70% on completion
        
        Provide a helpful, sales-oriented (but not pushy) response.
        If appropriate, suggest scheduling a consultation call.
        """
        
        return self.get_response(prompt)

6️⃣ Research Agent — research_agent.py

What sets this agent apart from the others is that it searches the web to get up-to-date information about technologies and trends, rather than relying solely on pre-defined data.

💡 Important Note:

This agent uses the web search feature from the Groq API (if available). If this feature isn't available in your account, the agent will rely on the model's built-in knowledge.

📄 File: agents/research_agent.py (Complete Code)

from agents.base_agent import BaseAgent
import requests
import os


class ResearchAgent(BaseAgent):
    """
    Research Agent - Searches for the latest technologies and trends.
    """
    
    def __init__(self):
        super().__init__(
            name="ResearchAssistant",
            description="I research latest technologies and industry trends.",
            avatar="research_avatar.png"
        )
        self.api_key = os.getenv("GROQ_API_KEY")
        self.api_url = "https://api.groq.com/openai/v1/chat/completions"

    def _make_api_request(self, messages, use_search=False):
        """Send request to Groq API."""
        headers = {
            "Authorization": f"Bearer {self.api_key}",
            "Content-Type": "application/json"
        }
        
        payload = {
            "model": "llama-3.3-70b-versatile",
            "messages": messages,
            "temperature": 0.7,
            "max_tokens": 2048
        }
        
        if use_search:
            payload["tools"] = [{"type": "web_search"}]
        
        try:
            response = requests.post(self.api_url, headers=headers, json=payload, timeout=60)
            if response.status_code == 200:
                return response.json()["choices"][0]["message"]["content"]
            return None
        except Exception as e:
            print(f"API error: {e}")
            return None

    def research_technology(self, technology):
        """Research a specific technology."""
        prompt = f"""
        Provide a comprehensive overview of **{technology}**:
        
        ## 1. What is {technology}?
        Brief introduction and core concept.
        
        ## 2. Key Features
        Main features and capabilities (bullet points).
        
        ## 3. Use Cases
        Common applications and when to use it.
        
        ## 4. Pros and Cons
        | Pros | Cons |
        |------|------|
        | ... | ... |
        
        ## 5. Getting Started
        Basic steps to start using it.
        
        ## 6. Current State (2025)
        Popularity, community support, latest developments.
        
        ## 7. Learning Resources
        Top 3-5 recommended resources.
        
        Format in clean markdown with emojis. Be accurate and practical.
        """
        
        return self.get_response(prompt)

    def compare_technologies(self, tech1, tech2):
        """Compare two technologies."""
        prompt = f"""
        Compare **{tech1}** vs **{tech2}** for developers:
        
        ## Overview
        Brief intro to both technologies.
        
        ## Comparison Table
        | Aspect | {tech1} | {tech2} |
        |--------|---------|---------|
        | Type | ... | ... |
        | Learning Curve | ... | ... |
        | Performance | ... | ... |
        | Community Size | ... | ... |
        | Job Market | ... | ... |
        | Best For | ... | ... |
        
        ## When to Choose {tech1}
        - Scenario 1
        - Scenario 2
        
        ## When to Choose {tech2}
        - Scenario 1
        - Scenario 2
        
        ## Verdict
        Final recommendation based on different use cases.
        
        Be objective and practical. Use markdown formatting.
        """
        
        return self.get_response(prompt)

    def get_industry_trends(self):
        """Get the latest software industry trends."""
        prompt = """
        Provide an overview of the latest software development trends for 2025:
        
        ## 🚀 Emerging Technologies
        Top 5 emerging technologies developers should watch.
        
        ## 💼 In-Demand Skills
        Most sought-after skills in the job market.
        
        ## 🔄 Industry Shifts
        Major changes in how software is built and deployed.
        
        ## 🤖 AI & Automation
        How AI is changing development workflows.
        
        ## ☁️ Cloud & Infrastructure
        Latest trends in cloud services and DevOps.
        
        ## 📱 Frontend Trends
        What's new in frontend development.
        
        ## 🔮 Predictions
        What to expect in the next 1-2 years.
        
        Be specific with examples. Format in markdown with emojis.
        """
        
        return self.get_response(prompt)

    def get_learning_path(self, goal):
        """Create a custom learning path."""
        prompt = f"""
        Create a learning roadmap for someone who wants to: **{goal}**
        
        ## 🎯 Goal Analysis
        Break down what skills are needed.
        
        ## 📚 Learning Path
        ### Phase 1: Fundamentals (Weeks 1-4)
        - Topic 1
        - Topic 2
        
        ### Phase 2: Core Skills (Weeks 5-12)
        - Topic 1
        - Topic 2
        
        ### Phase 3: Advanced Topics (Weeks 13-20)
        - Topic 1
        - Topic 2
        
        ### Phase 4: Projects & Portfolio (Weeks 21-24)
        - Project ideas
        
        ## 🛠️ Recommended Tools
        Essential tools and software.
        
        ## 📖 Resources
        - Free resources
        - Paid courses (worth the investment)
        
        ## ⏱️ Time Estimate
        Realistic timeline with daily commitment.
        
        Be practical and specific. Format in markdown.
        """
        
        return self.get_response(prompt)

    def answer_research_question(self, question):
        """Answer general research questions."""
        prompt = f"""
        Answer this technology/research question:
        
        **Question:** {question}
        
        Provide a well-researched, accurate answer with:
        - Clear explanation
        - Practical examples if applicable
        - Links to concepts (not actual URLs)
        - Your recommendation if relevant
        
        Format in markdown. Be concise but comprehensive.
        """
        
        return self.get_response(prompt)

7️⃣ Export File — __init__.py

This file collects all agents and exports them to be available for use in the main file main.py.

📄 File: agents/__init__.py

"""
AI Agents Package
================
This package contains all specialized AI agents for the portfolio website.

Available Agents:
- WelcomeAgent: Greets visitors and guides them
- ProjectAgent: Showcases technical projects
- CareerAgent: Provides career and skills information
- ClientAgent: Handles service inquiries and proposals
- ResearchAgent: Researches technologies and trends
"""

# Import all agents
from agents.base_agent import BaseAgent
from agents.welcome_agent import WelcomeAgent
from agents.project_agent import ProjectAgent
from agents.career_agent import CareerAgent
from agents.client_agent import ClientAgent
from agents.research_agent import ResearchAgent

# Define what gets exported when using from agents import *
__all__ = [
    'BaseAgent',
    'WelcomeAgent',
    'ProjectAgent',
    'CareerAgent',
    'ClientAgent',
    'ResearchAgent'
]

# Version information
__version__ = "1.0.0"
__author__ = "Your Name"
🔍 Why Do We Use __init__.py?

This file converts the agents folder into a Python Package, which allows us to:

  • Import agents easily: from agents import WelcomeAgent
  • Import all agents at once: from agents import *
  • Organize code and make it more maintainable

🚀 Main File — main.py

This is the heart of the backend. It creates a Flask server and connects all agents to API endpoints that the frontend will communicate with.

📄 File: main.py (Complete Code)

"""
AI Agents Portfolio - Backend Server
====================================
Flask server that provides API endpoints for AI agents.
"""

from flask import Flask, request, jsonify
from flask_cors import CORS
from dotenv import load_dotenv
import os

# Load environment variables
load_dotenv()

# Import agents
from agents import (
    WelcomeAgent,
    ProjectAgent,
    CareerAgent,
    ClientAgent,
    ResearchAgent
)

# Create Flask application
app = Flask(__name__)

# Enable CORS to allow access from frontend
CORS(app, resources={
    r"/api/*": {
        "origins": ["http://localhost:5173", "http://127.0.0.1:5173"],
        "methods": ["GET", "POST", "OPTIONS"],
        "allow_headers": ["Content-Type"]
    }
})

# ═══════════════════════════════════════════════════════════
# Initialize Agents
# ═══════════════════════════════════════════════════════════

print("🤖 Initializing AI Agents...")

welcome_agent = WelcomeAgent()
project_agent = ProjectAgent()
career_agent = CareerAgent()
client_agent = ClientAgent()
research_agent = ResearchAgent()

print("✅ All agents initialized successfully!")


# ═══════════════════════════════════════════════════════════
# Helper Functions
# ═══════════════════════════════════════════════════════════

def extract_response_content(response):
    """
    Extract text from agent response.
    Handles different types of responses.
    """
    if response is None:
        return "I apologize, but I couldn't generate a response. Please try again."
    
    # If response is a RunResponse object from Agno
    if hasattr(response, 'content'):
        return response.content
    
    # If response has a run() method
    if hasattr(response, 'run'):
        result = response.run()
        if hasattr(result, 'content'):
            return result.content
        return str(result)
    
    # If it's plain text
    return str(response)


def create_error_response(message, status_code=500):
    """Create a unified error response."""
    return jsonify({
        "error": True,
        "message": message,
        "response": f"I apologize, but an error occurred: {message}"
    }), status_code


# ═══════════════════════════════════════════════════════════
# API Endpoints
# ═══════════════════════════════════════════════════════════

# --- Status Check Endpoint ---
@app.route('/api/status', methods=['GET'])
def status():
    """Check server and agents status."""
    return jsonify({
        "status": "online",
        "message": "AI Agents Team is Ready! 🤖",
        "agents": {
            "welcome": "✅ Active",
            "project": "✅ Active",
            "career": "✅ Active",
            "client": "✅ Active",
            "research": "✅ Active"
        },
        "version": "1.0.0"
    })


# --- Welcome Agent ---
@app.route('/api/welcome', methods=['POST'])
def welcome_endpoint():
    """Welcome Agent endpoint."""
    try:
        data = request.get_json() or {}
        message = data.get('message', '').lower()
        visitor_type = data.get('visitor_type', None)
        
        # Determine visitor type from message if not specified
        if not visitor_type:
            if any(word in message for word in ['employer', 'hiring', 'recruit', 'job']):
                visitor_type = 'employer'
            elif any(word in message for word in ['client', 'project', 'hire', 'service']):
                visitor_type = 'client'
            elif any(word in message for word in ['developer', 'programmer', 'coding', 'tech']):
                visitor_type = 'fellow_programmer'
        
        # Choose appropriate function
        if 'section' in message or 'where' in message or 'suggest' in message:
            response = welcome_agent.suggest_section(message)
        elif message and len(message) > 20:
            response = welcome_agent.answer_question(message)
        else:
            response = welcome_agent.greet(visitor_type)
        
        return jsonify({
            "response": extract_response_content(response),
            "agent": "welcome",
            "visitor_type": visitor_type
        })
        
    except Exception as e:
        print(f"Welcome endpoint error: {e}")
        return create_error_response(str(e))


# --- Project Agent ---
@app.route('/api/project', methods=['POST'])
def project_endpoint():
    """Project Agent endpoint."""
    try:
        data = request.get_json() or {}
        message = data.get('message', '').lower()
        project_id = data.get('project_id', None)
        
        # Determine request type
        if project_id:
            response = project_agent.get_project_details(project_id)
        elif any(word in message for word in ['list', 'all', 'show', 'projects']):
            response = project_agent.get_project_list()
        elif any(word in message for word in ['ecommerce', 'e-commerce', 'shop']):
            response = project_agent.get_project_details('ecommerce')
        elif any(word in message for word in ['task', 'todo', 'management']):
            response = project_agent.get_project_details('taskmanager')
        elif any(word in message for word in ['dashboard', 'data', 'visualization']):
            response = project_agent.get_project_details('dashboard')
        elif any(word in message for word in ['ai', 'agent', 'portfolio']):
            response = project_agent.get_project_details('aiagents')
        elif any(tech in message for tech in ['react', 'vue', 'python', 'node', 'django']):
            # Extract technology name
            for tech in ['react', 'vue', 'python', 'node', 'django', 'mongodb']:
                if tech in message:
                    response = project_agent.search_projects(tech)
                    break
            else:
                response = project_agent.get_project_list()
        else:
            # General technical question
            response = project_agent.answer_technical_question('ecommerce', message)
        
        return jsonify({
            "response": extract_response_content(response),
            "agent": "project"
        })
        
    except Exception as e:
        print(f"Project endpoint error: {e}")
        return create_error_response(str(e))


# --- Career Agent ---
@app.route('/api/career', methods=['POST'])
def career_endpoint():
    """Career Agent endpoint."""
    try:
        data = request.get_json() or {}
        message = data.get('message', '').lower()
        
        if any(word in message for word in ['skill', 'know', 'technology', 'tech']):
            response = career_agent.get_skills_summary()
        elif any(word in message for word in ['experience', 'work', 'history', 'career', 'job']):
            response = career_agent.get_experience_summary()
        elif any(word in message for word in ['fit', 'suitable', 'qualify', 'position']):
            response = career_agent.assess_job_fit(message)
        else:
            response = career_agent.answer_career_question(message)
        
        return jsonify({
            "response": extract_response_content(response),
            "agent": "career"
        })
        
    except Exception as e:
        print(f"Career endpoint error: {e}")
        return create_error_response(str(e))


# --- Client Agent ---
@app.route('/api/client', methods=['POST'])
def client_endpoint():
    """Client Agent endpoint."""
    try:
        data = request.get_json() or {}
        message = data.get('message', '').lower()
        
        if any(word in message for word in ['service', 'offer', 'provide', 'do you']):
            response = client_agent.get_services_overview()
        elif any(word in message for word in ['web', 'website', 'webapp']):
            response = client_agent.get_service_details('web development')
        elif any(word in message for word in ['mobile', 'app', 'ios', 'android']):
            response = client_agent.get_service_details('mobile')
        elif any(word in message for word in ['api', 'backend', 'integration']):
            response = client_agent.get_service_details('api')
        elif any(word in message for word in ['consult', 'advice', 'review']):
            response = client_agent.get_service_details('consulting')
        elif any(word in message for word in ['process', 'work with', 'how do', 'steps']):
            response = client_agent.explain_process()
        elif any(word in message for word in ['quote', 'proposal', 'estimate', 'price', 'cost', 'budget']):
            response = client_agent.generate_proposal(message)
        else:
            response = client_agent.answer_client_question(message)
        
        return jsonify({
            "response": extract_response_content(response),
            "agent": "client"
        })
        
    except Exception as e:
        print(f"Client endpoint error: {e}")
        return create_error_response(str(e))


# --- Research Agent ---
@app.route('/api/research', methods=['POST'])
def research_endpoint():
    """Research Agent endpoint."""
    try:
        data = request.get_json() or {}
        message = data.get('message', '').lower()
        
        if any(word in message for word in ['compare', 'vs', 'versus', 'or', 'difference']):
            # Try to extract two technologies for comparison
            techs = ['react', 'vue', 'angular', 'svelte', 'python', 'javascript', 
                     'typescript', 'node', 'django', 'flask', 'fastapi',
                     'mongodb', 'postgresql', 'mysql', 'docker', 'kubernetes']
            found_techs = [t for t in techs if t in message]
            
            if len(found_techs) >= 2:
                response = research_agent.compare_technologies(found_techs[0], found_techs[1])
            else:
                response = research_agent.compare_technologies('React', 'Vue')
        elif any(word in message for word in ['trend', 'latest', 'new', '2025', 'future']):
            response = research_agent.get_industry_trends()
        elif any(word in message for word in ['learn', 'roadmap', 'path', 'become']):
            response = research_agent.get_learning_path(message)
        else:
            # Search for specific technology or general question
            techs = ['react', 'vue', 'angular', 'python', 'javascript', 'docker',
                     'kubernetes', 'aws', 'node', 'django', 'graphql', 'ai']
            found_tech = None
            for tech in techs:
                if tech in message:
                    found_tech = tech
                    break
            
            if found_tech:
                response = research_agent.research_technology(found_tech)
            else:
                response = research_agent.answer_research_question(message)
        
        return jsonify({
            "response": extract_response_content(response),
            "agent": "research"
        })
        
    except Exception as e:
        print(f"Research endpoint error: {e}")
        return create_error_response(str(e))


# ═══════════════════════════════════════════════════════════
# Run Server
# ═══════════════════════════════════════════════════════════

if __name__ == '__main__':
    print("""
    ╔══════════════════════════════════════════════════════════╗
    ║         🤖 AI Agents Portfolio - Backend Server          ║
    ╠══════════════════════════════════════════════════════════╣
    ║  Server running at: http://127.0.0.1:5001                ║
    ║                                                          ║
    ║  Available Endpoints:                                    ║
    ║  ├── GET  /api/status   - Check server status            ║
    ║  ├── POST /api/welcome  - Welcome Agent                  ║
    ║  ├── POST /api/project  - Project Agent                  ║
    ║  ├── POST /api/career   - Career Agent                   ║
    ║  ├── POST /api/client   - Client Agent                   ║
    ║  └── POST /api/research - Research Agent                 ║
    ║                                                          ║
    ║  Press Ctrl+C to stop the server                         ║
    ╚══════════════════════════════════════════════════════════╝
    """)
    
    # Run the server
    app.run(
        host='0.0.0.0',      # Allow access from any address
        port=5001,            # Port
        debug=True            # Development mode (auto-reload)
    )
📋 API Endpoints Summary:
Endpoint Method Function
/api/status GET Check server status
/api/welcome POST Welcome Agent
/api/project POST Project Agent
/api/career POST Career Agent
/api/client POST Client Agent
/api/research POST Research Agent

🧪 Running and Testing the Backend

Now that we've completed all the backend files, it's time to run the server and test it to make sure everything is working correctly.

🚀 Running the Server

Make sure you're inside the backend folder and the virtual environment is activated:

# Make sure you're in the correct directory
cd ai-agents-portfolio/backend

# Activate the virtual environment (if not already activated)
# Windows:
venv\Scripts\activate

# macOS/Linux:
# source venv/bin/activate

# Run the server
python main.py

If everything goes well, you'll see a message like this:

🤖 Initializing AI Agents...
✅ All agents initialized successfully!

    ╔══════════════════════════════════════════════════════════╗
    ║         🤖 AI Agents Portfolio - Backend Server          ║
    ╠══════════════════════════════════════════════════════════╣
    ║  Server running at: http://127.0.0.1:5001                ║
    ╚══════════════════════════════════════════════════════════╝

 * Running on http://127.0.0.1:5001
 * Debug mode: on

🔍 Testing Endpoints Using curl

Open a new Terminal window (keep the server running) and test each endpoint:

🧪 Test 1: Check Server Status

curl http://localhost:5001/api/status

Expected Result:

{
  "status": "online",
  "message": "AI Agents Team is Ready! 🤖",
  "agents": {
    "welcome": "✅ Active",
    "project": "✅ Active",
    "career": "✅ Active",
    "client": "✅ Active",
    "research": "✅ Active"
  }
}

🧪 Test 2: Welcome Agent

curl -X POST http://localhost:5001/api/welcome \
  -H "Content-Type: application/json" \
  -d '{"message": "Hello, I am an employer looking for developers"}'

🧪 Test 3: Project Agent

curl -X POST http://localhost:5001/api/project \
  -H "Content-Type: application/json" \
  -d '{"message": "Show me all your projects"}'

🧪 Test 4: Career Agent

curl -X POST http://localhost:5001/api/career \
  -H "Content-Type: application/json" \
  -d '{"message": "What skills do you have?"}'

🧪 Test 5: Client Agent

curl -X POST http://localhost:5001/api/client \
  -H "Content-Type: application/json" \
  -d '{"message": "What services do you offer and what are the prices?"}'

🧪 Test 6: Research Agent

curl -X POST http://localhost:5001/api/research \
  -H "Content-Type: application/json" \
  -d '{"message": "Compare React vs Vue for frontend development"}'
⚠️ Important Notes:
  • Each POST request consumes one API call from your Groq Cloud quota
  • Responses may take 2-5 seconds depending on the response length
  • You can monitor your usage on the Groq Dashboard
  • If errors appear, verify that GROQ_API_KEY is correct in your .env file
✅ If All Tests Pass:

Congratulations! 🎉 The backend is working correctly. Keep the server running and move on to building the frontend.

⚛️ Building the Frontend with React and Vite

We've reached the second half of the project! 🎯 Now we'll build a beautiful, interactive frontend using React, Vite, and Tailwind CSS.

📦 Step 1: Create the React Project

Open a new Terminal window (keep the Flask server running) and navigate to the main directory:

# Navigate to the main project directory
cd ai-agents-portfolio

# Create React project with Vite
npm create vite@latest frontend -- --template react

# Enter the frontend directory
cd frontend

# Install base packages
npm install

# Install additional required packages
npm install react-router-dom axios

# Install Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

🗂️ Step 2: Create the File Structure

# Create directories
mkdir -p src/components src/pages

# Create component files
touch src/components/Chat.jsx
touch src/components/Layout.jsx
touch src/components/Navbar.jsx
touch src/components/Footer.jsx

# Create page files
touch src/pages/Home.jsx
touch src/pages/Projects.jsx
touch src/pages/Career.jsx
touch src/pages/Services.jsx
touch src/pages/Research.jsx
touch src/pages/Contact.jsx

📂 frontend/ folder structure

frontend/
├── 📄 index.html
├── 📄 package.json
├── 📄 vite.config.js
├── 📄 tailwind.config.js
├── 📄 postcss.config.js
└── 📁 src/
    ├── 📄 main.jsx
    ├── 📄 App.jsx
    ├── 📄 App.css
    ├── 📄 index.css
    ├── 📁 components/
    │   ├── 📄 Chat.jsx        # Main chat component
    │   ├── 📄 Layout.jsx      # Page layout
    │   ├── 📄 Navbar.jsx      # Navigation bar
    │   └── 📄 Footer.jsx      # Footer
    └── 📁 pages/
        ├── 📄 Home.jsx        # Home page
        ├── 📄 Projects.jsx    # Projects page
        ├── 📄 Career.jsx      # Career page
        ├── 📄 Services.jsx    # Services page
        ├── 📄 Research.jsx    # Research page
        └── 📄 Contact.jsx     # Contact page

⚙️ Step 3: Configuration Files

📄 File: tailwind.config.js

/** @type {import('tailwindcss').Config} */
export default {
  content: [
    "./index.html",
    "./src/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {
      colors: {
        // Custom colors for the project
        primary: {
          50: '#f0fdf4',
          100: '#dcfce7',
          500: '#22c55e',
          600: '#16a34a',
          700: '#15803d',
        }
      },
      fontFamily: {
        sans: ['Inter', 'system-ui', 'sans-serif'],
      },
    },
  },
  plugins: [],
}

📄 File: vite.config.js

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'

export default defineConfig({
  plugins: [react()],
  server: {
    port: 5173,
    proxy: {
      // Proxy API requests to Flask server
      '/api': {
        target: 'http://127.0.0.1:5001',
        changeOrigin: true,
      }
    }
  }
})

📄 File: src/index.css

/* Tailwind CSS Directives */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* Google Fonts */
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap');

/* Base Styles */
body {
  font-family: 'Inter', sans-serif;
  background-color: #f9fafb;
  min-height: 100vh;
}

/* Custom Scrollbar */
::-webkit-scrollbar {
  width: 8px;
}

::-webkit-scrollbar-track {
  background: #f1f1f1;
  border-radius: 10px;
}

::-webkit-scrollbar-thumb {
  background: #22c55e;
  border-radius: 10px;
}

::-webkit-scrollbar-thumb:hover {
  background: #16a34a;
}

/* Chat Animation */
@keyframes bounce {
  0%, 60%, 100% { transform: translateY(0); }
  30% { transform: translateY(-8px); }
}

.typing-dot {
  animation: bounce 1.4s infinite ease-in-out;
}

.typing-dot:nth-child(1) { animation-delay: 0s; }
.typing-dot:nth-child(2) { animation-delay: 0.2s; }
.typing-dot:nth-child(3) { animation-delay: 0.4s; }

/* Message Fade In */
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(10px); }
  to { opacity: 1; transform: translateY(0); }
}

.message-fade-in {
  animation: fadeIn 0.3s ease-out;
}

📄 File: src/main.jsx

import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
import './index.css'

createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
)

📄 File: src/App.jsx

import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
import Layout from './components/Layout'
import Home from './pages/Home'
import Projects from './pages/Projects'
import Career from './pages/Career'
import Services from './pages/Services'
import Research from './pages/Research'
import Contact from './pages/Contact'

function App() {
  return (
    <Router>
      <Layout>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/projects" element={<Projects />} />
          <Route path="/career" element={<Career />} />
          <Route path="/services" element={<Services />} />
          <Route path="/research" element={<Research />} />
          <Route path="/contact" element={<Contact />} />
        </Routes>
      </Layout>
    </Router>
  )
}

export default App

🧩 React Components

1️⃣ Layout Component — Layout.jsx

📄 File: src/components/Layout.jsx

import Navbar from './Navbar'
import Footer from './Footer'

function Layout({ children }) {
  return (
    <div className="min-h-screen flex flex-col bg-gray-50">
      <Navbar />
      
      <main className="flex-1 container mx-auto px-4 py-8">
        {children}
      </main>
      
      <Footer />
    </div>
  )
}

export default Layout

2️⃣ Navigation Bar — Navbar.jsx

📄 File: src/components/Navbar.jsx

import { Link, useLocation } from 'react-router-dom'
import { useState } from 'react'

function Navbar() {
  const location = useLocation()
  const [isMenuOpen, setIsMenuOpen] = useState(false)

  const navLinks = [
    { path: '/', label: 'Home', icon: '🏠' },
    { path: '/projects', label: 'Projects', icon: '💻' },
    { path: '/career', label: 'Career', icon: '📋' },
    { path: '/services', label: 'Services', icon: '🛠️' },
    { path: '/research', label: 'Research', icon: '🔬' },
    { path: '/contact', label: 'Contact', icon: '📧' },
  ]

  return (
    <nav className="bg-gradient-to-r from-green-600 to-teal-600 text-white shadow-lg sticky top-0 z-50">
      <div className="container mx-auto px-4">
        <div className="flex items-center justify-between h-16">
          
          {/* Logo */}
          <Link to="/" className="flex items-center space-x-2 text-xl font-bold hover:opacity-90 transition-opacity">
            <span className="text-2xl">🤖</span>
            <span>AI Agents Portfolio</span>
          </Link>

          {/* Desktop Navigation */}
          <div className="hidden md:flex items-center space-x-1">
            {navLinks.map((link) => (
              <Link
                key={link.path}
                to={link.path}
                className={`px-4 py-2 rounded-lg transition-all duration-200 flex items-center space-x-1
                  ${location.pathname === link.path 
                    ? 'bg-white/20 font-semibold' 
                    : 'hover:bg-white/10'
                  }`}
              >
                <span>{link.icon}</span>
                <span>{link.label}</span>
              </Link>
            ))}
          </div>

          {/* Mobile Menu Button */}
          <button
            onClick={() => setIsMenuOpen(!isMenuOpen)}
            className="md:hidden p-2 rounded-lg hover:bg-white/10 transition-colors"
          >
            <svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              {isMenuOpen ? (
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
              ) : (
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 6h16M4 12h16M4 18h16" />
              )}
            </svg>
          </button>
        </div>

        {/* Mobile Navigation */}
        {isMenuOpen && (
          <div className="md:hidden py-4 border-t border-white/20">
            {navLinks.map((link) => (
              <Link
                key={link.path}
                to={link.path}
                onClick={() => setIsMenuOpen(false)}
                className={`block px-4 py-3 rounded-lg transition-colors flex items-center space-x-2
                  ${location.pathname === link.path 
                    ? 'bg-white/20 font-semibold' 
                    : 'hover:bg-white/10'
                  }`}
              >
                <span>{link.icon}</span>
                <span>{link.label}</span>
              </Link>
            ))}
          </div>
        )}
      </div>
    </nav>
  )
}

export default Navbar

3️⃣ Footer — Footer.jsx

📄 File: src/components/Footer.jsx (Complete Code)

function Footer() {
  const currentYear = new Date().getFullYear()

  return (
    <footer className="bg-gray-800 text-white">
      <div className="container mx-auto px-4 py-8">
        <div className="grid grid-cols-1 md:grid-cols-3 gap-8">
          
          {/* About Section */}
          <div>
            <h3 className="text-lg font-semibold mb-4 flex items-center gap-2">
              <span>🤖</span> AI Agents Portfolio
            </h3>
            <p className="text-gray-400 text-sm leading-relaxed">
              A portfolio website powered by a team of AI agents. 
              Built with React, Flask, and Groq Cloud using LLaMA 3.3 70B.
            </p>
          </div>

          {/* Quick Links */}
          <div>
            <h3 className="text-lg font-semibold mb-4">Quick Links</h3>
            <ul className="space-y-2 text-sm">
              <li>
                <a href="/projects" className="text-gray-400 hover:text-green-400 transition-colors">
                  💻 Projects
                </a>
              </li>
              <li>
                <a href="/career" className="text-gray-400 hover:text-green-400 transition-colors">
                  📋 Career
                </a>
              </li>
              <li>
                <a href="/services" className="text-gray-400 hover:text-green-400 transition-colors">
                  🛠️ Services
                </a>
              </li>
              <li>
                <a href="/contact" className="text-gray-400 hover:text-green-400 transition-colors">
                  📧 Contact
                </a>
              </li>
            </ul>
          </div>

          {/* Tech Stack */}
          <div>
            <h3 className="text-lg font-semibold mb-4">Built With</h3>
            <div className="flex flex-wrap gap-2">
              {['React', 'Flask', 'Agno', 'Groq', 'LLaMA', 'Tailwind'].map((tech) => (
                <span
                  key={tech}
                  className="px-3 py-1 bg-gray-700 rounded-full text-xs text-gray-300"
                >
                  {tech}
                </span>
              ))}
            </div>
          </div>
        </div>

        {/* Copyright */}
        <div className="border-t border-gray-700 mt-8 pt-6 text-center">
          <p className="text-gray-400 text-sm">
            © {currentYear} AI Agents Portfolio. Powered by 
            <span className="text-green-400"> Groq Cloud </span> 
            & 
            <span className="text-green-400"> LLaMA 3.3 70B</span>
          </p>
        </div>
      </div>
    </footer>
  )
}

export default Footer

4️⃣ Chat Component — Chat.jsx ⭐ (Most Important)

This is the most important component in the project. It manages sending messages to agents and displaying their responses with Markdown to HTML conversion and typing indicator display.

📄 File: src/components/Chat.jsx (Complete Code)

import { useState, useEffect, useRef, useCallback } from 'react'
import axios from 'axios'

function Chat({ agentType, initialMessage, agentName, agentIcon }) {
  // Component state
  const [messages, setMessages] = useState([])
  const [input, setInput] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [isOnline, setIsOnline] = useState(true)
  const messagesEndRef = useRef(null)
  
  // API URL
  const API_BASE_URL = 'http://127.0.0.1:5001'

  // Scroll to last message
  const scrollToBottom = () => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' })
  }

  // Convert Markdown to HTML
  const renderMarkdown = (text) => {
    if (!text) return ''
    
    let html = text
      // Headers
      .replace(/^### (.*$)/gim, '<h3 class="text-lg font-bold mt-4 mb-2 text-gray-800">\\$1</h3>')
      .replace(/^## (.*$)/gim, '<h2 class="text-xl font-bold mt-4 mb-2 text-gray-800">\\$1</h2>')
      .replace(/^# (.*$)/gim, '<h1 class="text-2xl font-bold mt-4 mb-2 text-gray-800">\\$1</h1>')
      // Bold & Italic
      .replace(/\*\*\*(.*?)\*\*\*/g, '<strong><em>\\$1</em></strong>')
      .replace(/\*\*(.*?)\*\*/g, '<strong class="font-semibold">\\$1</strong>')
      .replace(/\*(.*?)\*/g, '<em>\\$1</em>')
      // Code blocks
      .replace(/```(\w+)?\n([\s\S]*?)```/g, '<pre class="bg-gray-800 text-green-400 p-4 rounded-lg my-3 overflow-x-auto text-sm"><code>\\$2</code></pre>')
      .replace(/`(.*?)`/g, '<code class="bg-gray-200 text-red-600 px-1.5 py-0.5 rounded text-sm">\\$1</code>')
      // Lists
      .replace(/^\s*[-*]\s+(.*$)/gim, '<li class="ml-4 mb-1">\\$1</li>')
      .replace(/^\s*(\d+)\.\s+(.*$)/gim, '<li class="ml-4 mb-1">\\$2</li>')
      // Links
      .replace(/
$$
([^
$$
]+)\]\(([^)]+)\)/g, '<a href="\\$2" class="text-green-600 hover:underline" target="_blank">\\$1</a>')
      // Tables (basic support)
      .replace(/\|(.+)\|/g, '<div class="table-row">\\$1</div>')
      // Line breaks
      .replace(/\n\n/g, '</p><p class="mb-3">')
      .replace(/\n/g, '<br>')
    
    return `<p class="mb-3">${html}</p>`
  }

  // Send message
  const sendMessage = useCallback(async (messageText = null) => {
    const textToSend = messageText || input.trim()
    if (!textToSend) return

    // Add user message
    const userMessage = { 
      id: Date.now(), 
      content: textToSend, 
      isUser: true,
      timestamp: new Date().toLocaleTimeString()
    }
    setMessages(prev => [...prev, userMessage])
    setInput('')
    setIsLoading(true)

    try {
      const response = await axios.post(
        `${API_BASE_URL}/api/${agentType}`,
        { message: textToSend },
        { 
          headers: { 'Content-Type': 'application/json' },
          timeout: 60000 // 60 seconds timeout
        }
      )

      if (response.data?.response) {
        const botMessage = {
          id: Date.now() + 1,
          content: response.data.response,
          isUser: false,
          timestamp: new Date().toLocaleTimeString()
        }
        setMessages(prev => [...prev, botMessage])
        setIsOnline(true)
      }
    } catch (error) {
      console.error('Error sending message:', error)
      setIsOnline(false)
      
      const errorMessage = {
        id: Date.now() + 1,
        content: error.code === 'ECONNABORTED'
          ? '⏱️ Request timed out. The AI is taking longer than expected. Please try again.'
          : '❌ Unable to connect to the AI agent. Please make sure the Flask server is running on http://127.0.0.1:5001',
        isUser: false,
        isError: true,
        timestamp: new Date().toLocaleTimeString()
      }
      setMessages(prev => [...prev, errorMessage])
    } finally {
      setIsLoading(false)
    }
  }, [input, agentType, API_BASE_URL])

  // Handle Enter key press
  const handleKeyPress = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault()
      sendMessage()
    }
  }

  // Add initial message on load
  useEffect(() => {
    if (initialMessage) {
      setMessages([{
        id: 0,
        content: initialMessage,
        isUser: false,
        timestamp: new Date().toLocaleTimeString()
      }])
    }
  }, [initialMessage])

  // Scroll when new messages are added
  useEffect(() => {
    scrollToBottom()
  }, [messages])

  // Suggested quick questions
  const quickQuestions = {
    welcome: ['I am an employer', 'I am a client', 'I am a developer'],
    project: ['Show all projects', 'React projects', 'E-commerce details'],
    career: ['What are your skills?', 'Work experience', 'Certifications'],
    client: ['What services do you offer?', 'Pricing info', 'Get a quote'],
    research: ['Latest tech trends', 'Compare React vs Vue', 'Learn Python path']
  }

  return (
    <div className="flex flex-col h-[600px] bg-white rounded-2xl shadow-xl overflow-hidden border border-gray-200">
      
      {/* Header */}
      <div className="bg-gradient-to-r from-green-500 to-teal-500 text-white p-4">
        <div className="flex items-center gap-3">
          <div className="w-12 h-12 bg-white/20 rounded-full flex items-center justify-center text-2xl">
            {agentIcon || '🤖'}
          </div>
          <div>
            <h3 className="font-semibold text-lg">{agentName || 'AI Agent'}</h3>
            <div className="flex items-center gap-2 text-sm">
              <span className={`w-2 h-2 rounded-full ${isOnline ? 'bg-green-300' : 'bg-red-400'}`}></span>
              <span className="opacity-90">{isOnline ? 'Online' : 'Offline'}</span>
            </div>
          </div>
        </div>
      </div>

      {/* Messages Area */}
      <div className="flex-1 overflow-y-auto p-4 space-y-4 bg-gray-50">
        {messages.map((msg) => (
          <div
            key={msg.id}
            className={`flex ${msg.isUser ? 'justify-end' : 'justify-start'} message-fade-in`}
          >
            <div
              className={`max-w-[85%] rounded-2xl px-4 py-3 ${
                msg.isUser
                  ? 'bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-br-md'
                  : msg.isError
                    ? 'bg-red-50 text-red-700 border border-red-200 rounded-bl-md'
                    : 'bg-white text-gray-800 shadow-md rounded-bl-md'
              }`}
            >
              {msg.isUser ? (
                <p>{msg.content}</p>
              ) : (
                <div
                  className="prose prose-sm max-w-none"
                  dangerouslySetInnerHTML={{ __html: renderMarkdown(msg.content) }}
                />
              )}
              <span className={`text-xs mt-2 block ${msg.isUser ? 'text-white/70' : 'text-gray-400'}`}>
                {msg.timestamp}
              </span>
            </div>
          </div>
        ))}

        {/* Typing Indicator */}
        {isLoading && (
          <div className="flex justify-start">
            <div className="bg-white rounded-2xl rounded-bl-md px-4 py-3 shadow-md">
              <div className="flex items-center gap-1">
                <span className="w-2 h-2 bg-gray-400 rounded-full typing-dot"></span>
                <span className="w-2 h-2 bg-gray-400 rounded-full typing-dot"></span>
                <span className="w-2 h-2 bg-gray-400 rounded-full typing-dot"></span>
                <span className="text-sm text-gray-500 ml-2">AI is thinking...</span>
              </div>
            </div>
          </div>
        )}

        <div ref={messagesEndRef} />
      </div>

      {/* Quick Questions */}
      {messages.length <= 1 && quickQuestions[agentType] && (
        <div className="px-4 py-2 bg-gray-50 border-t border-gray-100">
          <p className="text-xs text-gray-500 mb-2">Quick questions:</p>
          <div className="flex flex-wrap gap-2">
            {quickQuestions[agentType].map((q, i) => (
              <button
                key={i}
                onClick={() => sendMessage(q)}
                className="text-xs px-3 py-1.5 bg-white border border-gray-200 rounded-full hover:bg-green-50 hover:border-green-300 transition-colors"
              >
                {q}
              </button>
            ))}
          </div>
        </div>
      )}

      {/* Input Area */}
      <div className="p-4 bg-white border-t border-gray-200">
        <div className="flex gap-3">
          <input
            type="text"
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyPress={handleKeyPress}
            placeholder="Type your message..."
            disabled={isLoading}
            className="flex-1 px-4 py-3 border border-gray-200 rounded-xl focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent disabled:bg-gray-100 disabled:cursor-not-allowed transition-all"
          />
          <button
            onClick={() => sendMessage()}
            disabled={isLoading || !input.trim()}
            className="px-6 py-3 bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-xl font-medium hover:opacity-90 disabled:opacity-50 disabled:cursor-not-allowed transition-all flex items-center gap-2"
          >
            {isLoading ? (
              <>
                <svg className="animate-spin h-5 w-5" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4" fill="none" />
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z" />
                </svg>
              </>
            ) : (
              <>
                Send
                <svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                  <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 19l9 2-9-18-9 18 9-2zm0 0v-8" />
                </svg>
              </>
            )}
          </button>
        </div>
      </div>
    </div>
  )
}

export default Chat

📄 Application Pages

1️⃣ Home Page — Home.jsx

📄 File: src/pages/Home.jsx

import Chat from '../components/Chat'

function Home() {
  return (
    <div className="max-w-4xl mx-auto">
      {/* Hero Section */}
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">👋</div>
        <h1 className="text-4xl md:text-5xl font-bold text-gray-800 mb-4">
          Welcome to My Portfolio
        </h1>
        <p className="text-xl text-gray-600 max-w-2xl mx-auto leading-relaxed">
          I'm a Full-Stack Developer with 7+ years of experience. 
          Meet my AI assistant team — they're here to help you explore my work 
          and answer any questions you might have!
        </p>
      </div>

      {/* Features Grid */}
      <div className="grid grid-cols-2 md:grid-cols-5 gap-4 mb-10">
        {[
          { icon: '🎭', label: 'Welcome Agent', color: 'bg-yellow-100' },
          { icon: '💻', label: 'Projects Agent', color: 'bg-blue-100' },
          { icon: '📋', label: 'Career Agent', color: 'bg-pink-100' },
          { icon: '🤝', label: 'Client Agent', color: 'bg-purple-100' },
          { icon: '🔬', label: 'Research Agent', color: 'bg-red-100' },
        ].map((agent, i) => (
          <div key={i} className={`${agent.color} rounded-xl p-4 text-center`}>
            <div className="text-3xl mb-2">{agent.icon}</div>
            <div className="text-sm font-medium text-gray-700">{agent.label}</div>
          </div>
        ))}
      </div>

      {/* Chat Component */}
      <Chat
        agentType="welcome"
        agentName="Welcome Agent"
        agentIcon="🎭"
        initialMessage="Hello! 👋 I'm the Welcome Agent for this portfolio. I can help guide you to the right section based on your interests. Are you an employer looking for talent, a potential client, or a fellow programmer? Let me know how I can help!"
      />
    </div>
  )
}

export default Home

2️⃣ Projects Page — Projects.jsx

📄 File: src/pages/Projects.jsx

import Chat from '../components/Chat'

function Projects() {
  return (
    <div className="max-w-4xl mx-auto">
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">💻</div>
        <h1 className="text-4xl font-bold text-gray-800 mb-4">My Projects</h1>
        <p className="text-xl text-gray-600">
          Explore my technical projects and ask about implementation details
        </p>
      </div>

      {/* Project Cards Preview */}
      <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
        {[
          { name: 'E-commerce Platform', tech: 'React, Node.js, MongoDB', icon: '🛒' },
          { name: 'Task Manager', tech: 'Vue.js, Firebase', icon: '✅' },
          { name: 'Data Dashboard', tech: 'Python, Django, D3.js', icon: '📊' },
          { name: 'AI Agents Portfolio', tech: 'React, Flask, Groq', icon: '🤖' },
        ].map((project, i) => (
          <div key={i} className="bg-white p-4 rounded-xl shadow-md hover:shadow-lg transition-shadow">
            <div className="flex items-center gap-3">
              <span className="text-2xl">{project.icon}</span>
              <div>
                <h3 className="font-semibold text-gray-800">{project.name}</h3>
                <p className="text-sm text-gray-500">{project.tech}</p>
              </div>
            </div>
          </div>
        ))}
      </div>

      <Chat
        agentType="project"
        agentName="Project Agent"
        agentIcon="💻"
        initialMessage="Hi! 👋 I'm the Project Agent. I can tell you all about the technical projects in this portfolio. Would you like to see a list of all projects, or ask about a specific one? You can also ask technical questions about implementation details!"
      />
    </div>
  )
}

export default Projects

3️⃣ Career Page — Career.jsx

📄 File: src/pages/Career.jsx (Complete Code)

import Chat from '../components/Chat'

function Career() {
  return (
    <div className="max-w-4xl mx-auto">
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">📋</div>
        <h1 className="text-4xl font-bold text-gray-800 mb-4">Career & Skills</h1>
        <p className="text-xl text-gray-600">
          Learn about my professional experience and technical expertise
        </p>
      </div>

      {/* Stats Overview */}
      <div className="bg-white rounded-xl shadow-md p-6 mb-8">
        <h3 className="font-semibold text-lg mb-4 text-gray-800">🚀 Quick Overview</h3>
        <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
          <div className="text-center p-3 bg-green-50 rounded-lg">
            <div className="text-2xl font-bold text-green-600">7+</div>
            <div className="text-sm text-gray-600">Years Experience</div>
          </div>
          <div className="text-center p-3 bg-blue-50 rounded-lg">
            <div className="text-2xl font-bold text-blue-600">50+</div>
            <div className="text-sm text-gray-600">Projects</div>
          </div>
          <div className="text-center p-3 bg-purple-50 rounded-lg">
            <div className="text-2xl font-bold text-purple-600">15+</div>
            <div className="text-sm text-gray-600">Technologies</div>
          </div>
          <div className="text-center p-3 bg-yellow-50 rounded-lg">
            <div className="text-2xl font-bold text-yellow-600">3</div>
            <div className="text-sm text-gray-600">Certifications</div>
          </div>
        </div>
      </div>

      {/* Skills Tags */}
      <div className="bg-white rounded-xl shadow-md p-6 mb-8">
        <h3 className="font-semibold text-lg mb-4 text-gray-800">🛠️ Tech Stack</h3>
        <div className="flex flex-wrap gap-2">
          {['Python', 'JavaScript', 'TypeScript', 'React', 'Vue.js', 'Node.js', 
           'Django', 'Flask', 'PostgreSQL', 'MongoDB', 'AWS', 'Docker'].map((skill) => (
            <span
              key={skill}
              className="px-3 py-1 bg-gradient-to-r from-green-100 to-teal-100 text-green-700 rounded-full text-sm font-medium"
            >
              {skill}
            </span>
          ))}
        </div>
      </div>

      <Chat
        agentType="career"
        agentName="Career Agent"
        agentIcon="📋"
        initialMessage="Hello! 👋 I'm the Career Agent. I can provide detailed information about skills, work experience, and professional background. I can also assess job fit if you share a job description. What would you like to know?"
      />
    </div>
  )
}

export default Career

4️⃣ Services Page — Services.jsx

📄 File: src/pages/Services.jsx

import Chat from '../components/Chat'

function Services() {
  const services = [
    {
      icon: '🌐',
      title: 'Web Development',
      desc: 'Custom web applications',
      price: 'From \\$2,000',
      color: 'bg-blue-50 border-blue-200'
    },
    {
      icon: '📱',
      title: 'Mobile Apps',
      desc: 'iOS & Android development',
      price: 'From \\$8,000',
      color: 'bg-green-50 border-green-200'
    },
    {
      icon: '🔗',
      title: 'API Development',
      desc: 'RESTful & GraphQL APIs',
      price: 'From \\$1,500',
      color: 'bg-purple-50 border-purple-200'
    },
    {
      icon: '💡',
      title: 'Consulting',
      desc: 'Technical advice & reviews',
      price: '\\$100-200/hr',
      color: 'bg-yellow-50 border-yellow-200'
    }
  ]

  return (
    <div className="max-w-4xl mx-auto">
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">🛠️</div>
        <h1 className="text-4xl font-bold text-gray-800 mb-4">Services</h1>
        <p className="text-xl text-gray-600">
          Professional development services tailored to your needs
        </p>
      </div>

      {/* Services Grid */}
      <div className="grid grid-cols-1 md:grid-cols-2 gap-4 mb-8">
        {services.map((service, i) => (
          <div
            key={i}
            className={`p-5 rounded-xl border-2 ${service.color} hover:shadow-md transition-shadow`}
          >
            <div className="flex items-start gap-4">
              <span className="text-3xl">{service.icon}</span>
              <div>
                <h3 className="font-semibold text-gray-800 text-lg">{service.title}</h3>
                <p className="text-gray-600 text-sm mb-2">{service.desc}</p>
                <span className="text-green-600 font-semibold">{service.price}</span>
              </div>
            </div>
          </div>
        ))}
      </div>

      {/* CTA */}
      <div className="bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-xl p-6 mb-8 text-center">
        <h3 className="text-xl font-semibold mb-2">💬 Need a Custom Quote?</h3>
        <p className="opacity-90">
          Describe your project below and the AI agent will generate a preliminary proposal!
        </p>
      </div>

      <Chat
        agentType="client"
        agentName="Business Advisor"
        agentIcon="🤝"
        initialMessage="Welcome! 👋 I'm the Business Advisor. I can help you understand our services, explain the engagement process, and even generate a preliminary proposal for your project. What would you like to know? Feel free to describe your project for a custom quote!"
      />
    </div>
  )
}

export default Services

5️⃣ Research Page — Research.jsx

📄 File: src/pages/Research.jsx

import Chat from '../components/Chat'

function Research() {
  const topics = [
    { icon: '⚛️', name: 'React' },
    { icon: '💚', name: 'Vue.js' },
    { icon: '🐍', name: 'Python' },
    { icon: '🐳', name: 'Docker' },
    { icon: '☸️', name: 'Kubernetes' },
    { icon: '🤖', name: 'AI/ML' },
  ]

  return (
    <div className="max-w-4xl mx-auto">
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">🔬</div>
        <h1 className="text-4xl font-bold text-gray-800 mb-4">Tech Research</h1>
        <p className="text-xl text-gray-600">
          Explore latest technologies, compare tools, and discover industry trends
        </p>
      </div>

      {/* Popular Topics */}
      <div className="bg-white rounded-xl shadow-md p-6 mb-8">
        <h3 className="font-semibold text-lg mb-4 text-gray-800">🔥 Popular Topics</h3>
        <div className="flex flex-wrap gap-3">
          {topics.map((topic, i) => (
            <span
              key={i}
              className="px-4 py-2 bg-gray-100 rounded-lg text-gray-700 hover:bg-green-100 hover:text-green-700 cursor-pointer transition-colors flex items-center gap-2"
            >
              <span>{topic.icon}</span>
              <span>{topic.name}</span>
            </span>
          ))}
        </div>
      </div>

      {/* Research Ideas */}
      <div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-8">
        <div className="bg-blue-50 p-4 rounded-xl text-center">
          <div className="text-2xl mb-2">📖</div>
          <h4 className="font-medium text-gray-800">Learn a Technology</h4>
          <p className="text-sm text-gray-600">Get comprehensive overviews</p>
        </div>
        <div className="bg-green-50 p-4 rounded-xl text-center">
          <div className="text-2xl mb-2">⚖️</div>
          <h4 className="font-medium text-gray-800">Compare Tools</h4>
          <p className="text-sm text-gray-600">React vs Vue, etc.</p>
        </div>
        <div className="bg-purple-50 p-4 rounded-xl text-center">
          <div className="text-2xl mb-2">🚀</div>
          <h4 className="font-medium text-gray-800">Latest Trends</h4>
          <p className="text-sm text-gray-600">2025 industry insights</p>
        </div>
      </div>

      <Chat
        agentType="research"
        agentName="Research Assistant"
        agentIcon="🔬"
        initialMessage="Hi! 👋 I'm the Research Assistant. I can help you explore technologies, compare different tools and frameworks, or provide insights on industry trends. What would you like to research today? Try asking me to compare React vs Vue, or about the latest trends in AI!"
      />
    </div>
  )
}

export default Research

6️⃣ Contact Page — Contact.jsx

📄 File: src/pages/Contact.jsx

import { useState } from 'react'

function Contact() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    subject: '',
    message: ''
  })
  const [isSubmitted, setIsSubmitted] = useState(false)

  const handleChange = (e) => {
    setFormData({ ...formData, [e.target.name]: e.target.value })
  }

  const handleSubmit = (e) => {
    e.preventDefault()
    // In a real project, you would send data to the server here
    console.log('Form submitted:', formData)
    setIsSubmitted(true)
  }

  return (
    <div className="max-w-4xl mx-auto">
      <div className="text-center mb-10">
        <div className="text-6xl mb-4">📧</div>
        <h1 className="text-4xl font-bold text-gray-800 mb-4">Get In Touch</h1>
        <p className="text-xl text-gray-600">
          Have a project in mind? Let's discuss how we can work together!
        </p>
      </div>

      <div className="grid grid-cols-1 md:grid-cols-2 gap-8">
        {/* Contact Info */}
        <div>
          <div className="bg-white rounded-xl shadow-md p-6 mb-6">
            <h3 className="font-semibold text-lg mb-4 text-gray-800">📍 Contact Information</h3>
            <div className="space-y-4">
              <div className="flex items-center gap-3">
                <span className="text-xl">📧</span>
                <span className="text-gray-600">hello@example.com</span>
              </div>
              <div className="flex items-center gap-3">
                <span className="text-xl">💼</span>
                <span className="text-gray-600">LinkedIn Profile</span>
              </div>
              <div className="flex items-center gap-3">
                <span className="text-xl">🐙</span>
                <span className="text-gray-600">GitHub Profile</span>
              </div>
              <div className="flex items-center gap-3">
                <span className="text-xl">🌍</span>
                <span className="text-gray-600">Remote - Worldwide</span>
              </div>
            </div>
          </div>

          <div className="bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-xl p-6">
            <h3 className="font-semibold text-lg mb-2">⚡ Quick Response</h3>
            <p className="opacity-90 text-sm">
              I typically respond within 24 hours. For urgent inquiries, 
              please mention "URGENT" in the subject line.
            </p>
          </div>
        </div>

        {/* Contact Form */}
        <div className="bg-white rounded-xl shadow-md p-6">
          {isSubmitted ? (
            <div className="text-center py-10">
              <div className="text-5xl mb-4">✅</div>
              <h3 className="text-xl font-semibold text-gray-800 mb-2">Message Sent!</h3>
              <p className="text-gray-600">Thank you! I'll get back to you soon.</p>
              <button
                onClick={() => setIsSubmitted(false)}
                className="mt-4 text-green-600 hover:underline"
              >
                Send another message
              </button>
            </div>
          ) : (
            <form onSubmit={handleSubmit} className="space-y-4">
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Name</label>
                <input
                  type="text"
                  name="name"
                  value={formData.name}
                  onChange={handleChange}
                  required
                  className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent"
                  placeholder="Your name"
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Email</label>
                <input
                  type="email"
                  name="email"
                  value={formData.email}
                  onChange={handleChange}
                  required
                  className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent"
                  placeholder="your@email.com"
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Subject</label>
                <input
                  type="text"
                  name="subject"
                  value={formData.subject}
                  onChange={handleChange}
                  required
                  className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent"
                  placeholder="Project inquiry"
                />
              </div>
              <div>
                <label className="block text-sm font-medium text-gray-700 mb-1">Message</label>
                <textarea
                  name="message"
                  value={formData.message}
                  onChange={handleChange}
                  required
                  rows={4}
                  className="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-green-500 focus:border-transparent resize-none"
                  placeholder="Tell me about your project..."
                />
              </div>
              <button
                type="submit"
                className="w-full py-3 bg-gradient-to-r from-green-500 to-teal-500 text-white rounded-lg font-medium hover:opacity-90 transition-opacity"
              >
                Send Message 📨
              </button>
            </form>
          )}
        </div>
      </div>
    </div>
  )
}

export default Contact

🚀 Running the Complete Project

Now that all files are complete, it's time to run the entire project and test it!

📋 Steps Summary

  1. Make sure all files are saved in their correct locations
  2. Open two Terminal windows — one for Backend and one for Frontend
  3. Start the backend server first then the frontend
  4. Open your browser and start interacting with the agents!

🖥️ First Terminal: Running the Backend

# Navigate to the backend directory
cd ai-agents-portfolio/backend

# Activate the virtual environment
# Windows:
venv\Scripts\activate
# macOS/Linux:
# source venv/bin/activate

# Start the server
python main.py

✅ You should see:

🤖 Initializing AI Agents...
✅ All agents initialized successfully!
 * Running on http://127.0.0.1:5001

🌐 Second Terminal: Running the Frontend

# Open a new Terminal window
# Navigate to the frontend directory
cd ai-agents-portfolio/frontend

# Start the development server
npm run dev

✅ You should see:

  VITE v5.x.x  ready in xxx ms

  ➜  Local:   http://localhost:5173/
  ➜  Network: use --host to expose

🎉 Opening the Application

Open your browser and navigate to: http://localhost:5173

🎊

Congratulations!

You now have a portfolio website powered by a team of 5 AI agents!

🔧 Common Challenges and Solutions

When building intelligent agent systems, you may encounter some technical challenges. Here are the most common ones with practical solutions:

❌ Issue 1: "CORS" Error When Connecting to the API

Access to XMLHttpRequest has been blocked by CORS policy

✅ Solution:

Make sure flask-cors is installed and enabled in main.py:

from flask_cors import CORS
app = Flask(__name__)
CORS(app)  # Must be right after creating the app

❌ Issue 2: "API Key Invalid" Error

Invalid API Key or Authentication failed

✅ Solution:

  • Make sure the .env file exists in the backend folder
  • Verify the key is correct (starts with gsk_)
  • Make sure there are no spaces or extra characters around the key
  • Make sure load_dotenv() is called at the top of main.py

❌ Issue 3: Slow Response or Timeout

✅ Solution:

  • LLM responses may take 3-10 seconds — this is normal
  • Make sure the axios timeout is sufficient (at least 60 seconds)
  • Use Groq Cloud as it's much faster than alternatives
  • Reduce prompt length if they're too long

❌ Issue 4: "Module not found" Error

ModuleNotFoundError: No module named 'agents'

✅ Solution:

  • Make sure the __init__.py file exists in the agents folder
  • Make sure you're running main.py from inside the backend folder
  • Make sure to activate the virtual environment before running
# Make sure the structure is correct
backend/
├── main.py
└── agents/
    ├── __init__.py  ← This file is required!
    ├── base_agent.py
    └── ...

❌ Issue 5: Blank Page or React Error

✅ Solution:

  • Open the Developer Console in the browser (F12) and check for errors
  • Make sure all packages are installed: npm install
  • Verify import paths are correct in the files
  • Try deleting node_modules and reinstalling:
rm -rf node_modules package-lock.json
npm install
npm run dev

❌ Issue 6: Rate Limit Exceeded

Error 429: Too Many Requests

✅ Solution:

  • Wait a few minutes before sending new requests
  • Review usage limits in the Groq documentation
  • Reduce the number of concurrent requests
  • Use caching for repeated responses
⚠️ Important Security Warning:

Do not grant agents dangerous execution permissions (such as deleting files, making payments, or modifying databases) without having a human confirmation layer in between. Agents can make mistakes or be misused.

⭐ Best Practices and Advanced Tips

After building the basic system, here are tips to improve your project and make it more professional:

1️⃣ Comprehensive Error Handling

Add comprehensive error handling to every API endpoint, including:

  • Groq API connection errors
  • Timeout errors
  • Invalid user data
  • Rate limit exceeded

2️⃣ Caching

Cache repeated responses to reduce API calls and improve speed:

from functools import lru_cache

@lru_cache(maxsize=100)
def get_cached_response(query_hash):
    # Cache repeated responses
    return agent.get_response(query)

3️⃣ Rate Limiting

Add rate limits for user requests to protect your free Groq quota:

from flask_limiter import Limiter

limiter = Limiter(app, default_limits=["100 per hour"])

@app.route('/api/welcome', methods=['POST'])
@limiter.limit("10 per minute")
def welcome_endpoint():
    # ...

4️⃣ Logging

Log interactions to analyze performance and track errors:

import logging

logging.basicConfig(
    filename='app.log',
    level=logging.INFO,
    format='%(asctime)s - %(levelname)s - %(message)s'
)

# In each endpoint
logging.info(f"Welcome request: {message[:50]}...")

5️⃣ Prompt Engineering

Design precise prompts for each agent to ensure consistent, high-quality responses:

  • Clearly define the agent's personality
  • State constraints and boundaries
  • Specify the desired response format (Markdown, JSON, etc.)
  • Provide examples of ideal responses
🚀 Advanced Tip — Deploy Your Project for Free:

You can deploy your project to be available to everyone on the internet — for free!

💡 Ideas for Expanding Your Team

Don't stop here! You can add specialized agents for other tasks:

🔍

SEO Agent

Keyword analysis and title suggestions

📊

Data Analyst

Analyze visitor engagement and provide reports

✍️

Proofreader

Review text and correct errors

🎨

Design Consultant

UI/UX suggestions and design improvements

📊 Comparison of Available Tools

To help you choose the right tools for your future projects, here's a comprehensive comparison:

Criteria Agno + Groq
(Our Choice ✅)
LangChain + OpenAI CrewAI
💰 Cost Free
(with limits)
Paid
(pay-as-you-go)
Free
(open source)
⚡ Speed Ultra-fast
(Groq LPU)
Good Depends on model
📚 Learning Curve Very Easy Moderate Easy
🎯 Best For Web agents
and chatbots
Large enterprise
applications
Sequential task
automation
🔧 Flexibility High Very High Moderate

📝 Conclusion

Building a team of AI agents for your website using Agno and Groq Cloud is an effective way to improve user experience and provide excellent service — at no cost.

🎯 What You Learned in This Guide:

✅ Creating 5 specialized AI agents
✅ Building a backend with Python Flask
✅ Building a frontend with React + Vite
✅ Connecting to LLaMA 3.3 70B via Groq
✅ Designing an interactive chat interface
✅ Error handling and best practices

Combining Agno's orchestration with Groq's ultra-fast inference provides a free path to explore practical AI applications. With the rapid developments in this field, the ability to experiment with these solutions will keep you ahead of the curve.

Start today and share your experience with us! If you encounter any issues or have questions, don't hesitate to leave a comment below.

📬

Did you find this article helpful?

Join hundreds of subscribers and get the latest articles and tutorials delivered directly to your inbox.

Yes, I want to subscribe! ✉️

🔒 Your privacy matters to us. We'll never send spam.

❓ Frequently Asked Questions (FAQ)

🤔 Do I need advanced AI experience?

No! Basic knowledge of Python, JavaScript, and React is sufficient. The Agno library simplifies agent creation, and Groq Cloud handles the complex inference. All you need is to follow the steps in this guide.

🤔 Is Groq Cloud really free?

Yes! Groq Cloud offers a generous free tier sufficient for educational and personal projects. For heavy commercial use, you may need to upgrade to a paid plan. Check the usage limits.

🤔 Can I use a different language model than LLaMA?

Absolutely! Groq Cloud supports multiple models like DeepSeek R1, Google Gemma 2, and Mistral AI. Just change the model identifier in base_agent.py:
self.model = Groq(id="gemma2-9b-it")

🤔 Does the project work on Windows?

Yes! It works on all operating systems (Windows, macOS, Linux). The only difference is the virtual environment activation command:
• Windows: venv\Scripts\activate
• macOS/Linux: source venv/bin/activate

🤔 How do I add multi-language support?

Add instructions in the agent prompts such as:
"Always respond in formal English"
The LLaMA 3.3 model supports multiple languages, though English performance is typically best.

🤔 What's the difference between Agno and LangChain?

Agno is lighter and simpler — ideal for quick starts and small/medium projects.
LangChain is more comprehensive — for large projects requiring multiple integrations with databases, tools, and advanced memory.

🤔 Can I add new agents?

Yes! Follow these steps:
1. Create a new file in agents/ (e.g., seo_agent.py)
2. Make the class inherit from BaseAgent
3. Add an import in __init__.py
4. Add an endpoint in main.py
5. Create a corresponding React page

🤔 Can I deploy the project for free?

Yes! Deploy the backend on Railway or Render, and the frontend on Vercel or Netlify — all offer free tiers sufficient for personal projects.

🤔 How do I protect my API key?

• Never put the key directly in code
• Use a .env file and add it to .gitignore
• When deploying, use Environment Variables in the hosting platform
• Don't send the key to the frontend — keep it on the server only

🤔 Responses are very slow, what's the solution?

• Groq is one of the fastest service providers — responses usually take 2-5 seconds
• If slower, check your internet connection
• Reduce prompt length if they're too long
• Use caching for repeated responses
• Try a smaller model like llama-3.1-8b-instant

Add Valley4Techs as a Preferred Source

Follow us on Google News for the latest updates

Add Now
Mostafa Amaan
Mostafa Amaan
Technical educational content creator on my blog and YouTube channel. My goal with this content is to eradicate information technology literacy.
Comments