Build a Team of AI Agents for Your Website for Free Using Agno & Groq
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
-
📋 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
-
🎓 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
🛠️ 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
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.
📄 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:
- A Groq Cloud account (free) — Create Account
🔐 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:
- Go to the Groq Cloud signup page
- Sign in using your Google or GitHub account, or create a new account
- After signing in, navigate to the "API Keys" page from the sidebar
- Click on "Create API Key"
-
Give your key a memorable name (e.g.,
ai-agents-portfolio) - 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
- ❌ Never share your API key with anyone
- ❌ Never commit it to public repositories on GitHub
- ✅ Always use
.envfiles to store secret keys - ✅ Add
.envto your.gitignorefile
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
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
🗂️ 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
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)
- 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.
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"
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)
)
| 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"}'
- 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
.envfile
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
- Make sure all files are saved in their correct locations
- Open two Terminal windows — one for Backend and one for Frontend
- Start the backend server first then the frontend
- 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
.envfile exists in thebackendfolder - 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 ofmain.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__.pyfile exists in theagentsfolder - Make sure you're running
main.pyfrom inside thebackendfolder - 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_modulesand 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
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
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:
📝 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:
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.
We'd love to hear your thoughts! Leave a comment below
and share your experience or questions.