Skip to content

Refactor tutorials #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file

version: 2
updates:
- package-ecosystem: "pip" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
16 changes: 13 additions & 3 deletions 1_phidata_finance_agent/1_simple_groq_agent.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
import os
# Add your GROQ_API_KEY and optionally GROQ_MODEL_ID to a .env file or set them as environment variables.
from phi.agent import Agent
from phi.model.groq import Groq
from dotenv import load_dotenv

load_dotenv()
if not os.getenv("GROQ_API_KEY"):
print("Warning: GROQ_API_KEY not found. Please set it in your .env file or as an environment variable.")


# Create a simple agent with a Groq model
agent = Agent(
model=Groq(id="llama-3.3-70b-versatile")
model=Groq(id=os.getenv("GROQ_MODEL_ID", "llama-3.3-70b-versatile"))
# No specific instructions or tools are provided, so it will use the model's default capabilities.
)


agent.print_response("Share a 2 sentence love story between dosa and samosa")
# Example usage of the agent
try:
agent.print_response("Share a 2 sentence love story between dosa and samosa")
except Exception as e:
print(f"An error occurred: {e}")
30 changes: 23 additions & 7 deletions 1_phidata_finance_agent/2_finance_agent_llama.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import os
# Add your GROQ_API_KEY and optionally GROQ_MODEL_ID to a .env file or set them as environment variables.
"""Run `pip install yfinance` to install dependencies."""

from phi.agent import Agent
Expand All @@ -6,6 +8,8 @@
from dotenv import load_dotenv

load_dotenv()
if not os.getenv("GROQ_API_KEY"):
print("Warning: GROQ_API_KEY not found. Please set it in your .env file or as an environment variable.")


def get_company_symbol(company: str) -> str:
Expand All @@ -17,6 +21,8 @@ def get_company_symbol(company: str) -> str:
Returns:
str: The symbol for the company.
"""
# This is a simplified lookup for tutorial purposes.
# A real application should use a dedicated API or a more comprehensive database for symbol lookups.
symbols = {
"Phidata": "MSFT",
"Infosys": "INFY",
Expand All @@ -25,22 +31,32 @@ def get_company_symbol(company: str) -> str:
"Microsoft": "MSFT",
"Amazon": "AMZN",
"Google": "GOOGL",
"Netflix": "NFLX",
"Nvidia": "NVDA",
}
return symbols.get(company, "Unknown")


# YFinanceTools provides the agent with capabilities to fetch stock prices, analyst recommendations, and company fundamentals.
agent = Agent(
model=Groq(id="llama-3.3-70b-versatile"),
model=Groq(id=os.getenv("GROQ_MODEL_ID", "llama-3.3-70b-versatile")),
tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, stock_fundamentals=True), get_company_symbol],
# Instructions guide the agent on how to behave and use its tools.
instructions=[
"Use tables to display data.",
"If you need to find the symbol for a company, use the get_company_symbol tool.",
],
show_tool_calls=True,
markdown=True,
debug_mode=True,
show_tool_calls=True, # Displays tool calls and their responses.
markdown=True, # Outputs responses in Markdown format.
debug_mode=True, # Enables detailed logging for debugging.
)

agent.print_response(
"Summarize and compare analyst recommendations and fundamentals for TSLA and MSFT. Show in tables.", stream=True
)
# Example usage of the finance agent
# The agent will use YFinanceTools to get financial data and get_company_symbol to find stock symbols.
# It will then use the Groq model to process this information and generate a response.
try:
agent.print_response(
"Summarize and compare analyst recommendations and fundamentals for TSLA and MSFT. Show in tables.", stream=True
)
except Exception as e:
print(f"An error occurred: {e}")
53 changes: 40 additions & 13 deletions 1_phidata_finance_agent/3_agent_teams_openai.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import os
# Add your OPENAI_API_KEY (and optionally OPENAI_MODEL_ID) and/or GROQ_API_KEY (and optionally GROQ_MODEL_ID)
# to a .env file or set them as environment variables, depending on the model used.
from phi.agent import Agent
from phi.model.openai import OpenAIChat
from phi.model.groq import Groq
Expand All @@ -6,35 +9,59 @@
from dotenv import load_dotenv

load_dotenv()
# Default model is OpenAI, so check for OPENAI_API_KEY first.
if not os.getenv("OPENAI_API_KEY"):
print("Warning: OPENAI_API_KEY not found. Please set it in your .env file or as an environment variable if you plan to use OpenAI models.")
if not os.getenv("GROQ_API_KEY"):
print("Warning: GROQ_API_KEY not found. Please set it in your .env file or as an environment variable if you plan to use Groq models.")

# --- Choosing between OpenAI and Groq Models ---
# This script defaults to using OpenAI models (gpt-4o specified by OPENAI_MODEL_ID).
# To use Groq models (e.g., llama-3.3-70b-versatile specified by GROQ_MODEL_ID):
# 1. Comment out the `model=OpenAIChat(...)` line for each agent definition below.
# 2. Uncomment the `model=Groq(...)` line for each agent definition.
#
# Ensure the relevant API keys (OPENAI_API_KEY, GROQ_API_KEY) and any chosen
# model IDs (OPENAI_MODEL_ID, GROQ_MODEL_ID) are set in your environment,
# typically in a .env file at the root of your project.

# Web Agent: Specialist agent with web search capabilities using DuckDuckGo.
web_agent = Agent(
name="Web Agent",
# model=Groq(id="llama-3.3-70b-versatile"),
model=OpenAIChat(id="gpt-4o"),
# model=Groq(id=os.getenv("GROQ_MODEL_ID", "llama-3.3-70b-versatile")),
model=OpenAIChat(id=os.getenv("OPENAI_MODEL_ID", "gpt-4o")),
tools=[DuckDuckGo()],
instructions=["Always include sources"],
show_tool_calls=True,
markdown=True
show_tool_calls=True, # Displays tool calls and their responses.
markdown=True # Outputs responses in Markdown format.
)

# Finance Agent: Specialist agent with financial data fetching capabilities using YFinanceTools.
finance_agent = Agent(
name="Finance Agent",
role="Get financial data",
# model=Groq(id="llama-3.3-70b-versatile"),
model=OpenAIChat(id="gpt-4o"),
# model=Groq(id=os.getenv("GROQ_MODEL_ID", "llama-3.3-70b-versatile")),
model=OpenAIChat(id=os.getenv("OPENAI_MODEL_ID", "gpt-4o")),
tools=[YFinanceTools(stock_price=True, analyst_recommendations=True, company_info=True)],
instructions=["Use tables to display data"],
show_tool_calls=True,
markdown=True,
show_tool_calls=True, # Displays tool calls and their responses.
markdown=True, # Outputs responses in Markdown format.
)

# Agent Team: Supervisor agent that delegates tasks to specialist agents (Web Agent, Finance Agent)
# based on the nature of the prompt. It coordinates the work of the team.
agent_team = Agent(
# model=Groq(id="llama-3.3-70b-versatile"),
model=OpenAIChat(id="gpt-4o"),
# model=Groq(id=os.getenv("GROQ_MODEL_ID", "llama-3.3-70b-versatile")),
model=OpenAIChat(id=os.getenv("OPENAI_MODEL_ID", "gpt-4o")),
team=[web_agent, finance_agent],
instructions=["Always include sources", "Use tables to display data"],
show_tool_calls=True,
markdown=True,
show_tool_calls=True, # Displays tool calls and their responses for the team.
markdown=True, # Outputs the final response in Markdown format.
)

agent_team.print_response("Summarize analyst recommendations and share the latest news for NVDA", stream=True)
# Example usage of the agent team
# The team will delegate tasks to the Web Agent for news and Finance Agent for financial data.
try:
agent_team.print_response("Summarize analyst recommendations and share the latest news for NVDA", stream=True)
except Exception as e:
print(f"An error occurred: {e}")
6 changes: 6 additions & 0 deletions 1_phidata_finance_agent/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
phi-ai
python-dotenv
groq
openai
yfinance
duckduckgo-search
5 changes: 5 additions & 0 deletions 2_mcp_leave_management/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,9 @@ is for MCP server that interacts with mock leave database and responds to MCP cl
8. Kill any running instance of Claude from Task Manager. Restart Claude Desktop
9. In Claude desktop, now you will see tools from this server

# Database Information
- This server uses an SQLite database named `leave_management.db`.
- When you run the server (e.g., using `python main.py` or via the MCP client interaction if it's started by the client environment), this database file will be automatically created in the `2_mcp_leave_management/` directory if it doesn't already exist.
- The database is also automatically initialized with sample employee data and leave history upon its first creation, allowing you to test the tools immediately.

@All rights reserved. Codebasics Inc. LearnerX Pvt Ltd.
150 changes: 150 additions & 0 deletions 2_mcp_leave_management/database.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
"""
Handles SQLite database operations for the Leave Management System.

This module includes functions for:
- Establishing database connections.
- Creating necessary tables (`employees`, `leave_history`) if they don't exist.
- Initializing the database with sample employee data and leave history.
- Retrieving employee leave balance and history.
- Updating employee leave balances and adding new leave entries.

The database file is named `leave_management.db` and is located in the
`2_mcp_leave_management` directory.
"""
import sqlite3
from typing import List, Dict, Any, Tuple


DATABASE_NAME = "2_mcp_leave_management/leave_management.db"


def get_db_connection() -> sqlite3.Connection:
"""Establishes a connection to the SQLite database."""
conn = sqlite3.connect(DATABASE_NAME)
conn.row_factory = sqlite3.Row # Access columns by name
return conn

def create_tables_if_not_exist():
"""Creates the necessary tables if they don't already exist."""
# Ensures that the employees and leave_history tables are created before any operations.
conn = get_db_connection()
cursor = conn.cursor()

# Employee table: stores employee ID and their current leave balance
cursor.execute('''
CREATE TABLE IF NOT EXISTS employees (
employee_id TEXT PRIMARY KEY,
balance INTEGER NOT NULL
)
''')

# Leave history table: stores individual leave dates for each employee
cursor.execute('''
CREATE TABLE IF NOT EXISTS leave_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
employee_id TEXT NOT NULL,
leave_date TEXT NOT NULL,
FOREIGN KEY (employee_id) REFERENCES employees (employee_id)
)
''')
conn.commit()
conn.close()

def initialize_database_with_sample_data():
"""Populates the database with initial sample data if it's empty."""
# Idempotent function: only adds data if the 'employees' table is currently empty.
conn = get_db_connection()
cursor = conn.cursor()

# Check if employees table is empty
cursor.execute("SELECT COUNT(*) FROM employees")
if cursor.fetchone()[0] == 0:
sample_employees: List[Tuple[str, int]] = [
("E001", 18),
("E002", 20)
]
cursor.executemany("INSERT INTO employees (employee_id, balance) VALUES (?, ?)", sample_employees)

sample_leave_history: List[Tuple[str, str]] = [
("E001", "2024-12-25"),
("E001", "2025-01-01")
]
cursor.executemany("INSERT INTO leave_history (employee_id, leave_date) VALUES (?, ?)", sample_leave_history)

conn.commit()
conn.close()

def get_employee_data(employee_id: str) -> Dict[str, Any]:
"""Retrieves employee balance and history. Returns None if employee_id is not found."""
conn = get_db_connection()
cursor = conn.cursor()

cursor.execute("SELECT balance FROM employees WHERE employee_id = ?", (employee_id,))
employee_row = cursor.fetchone()

if not employee_row:
conn.close()
return None

balance = employee_row["balance"]

cursor.execute("SELECT leave_date FROM leave_history WHERE employee_id = ? ORDER BY leave_date", (employee_id,))
history_rows = cursor.fetchall()
history = [row["leave_date"] for row in history_rows]

conn.close()
return {"balance": balance, "history": history}

def update_employee_leave(employee_id: str, new_balance: int, leave_dates_to_add: List[str]) -> bool:
"""
Updates an employee's leave balance and adds new leave dates to their history.
This operation is transactional: either all changes are committed or none are.
Returns True if successful, False otherwise.
"""
conn = get_db_connection()
cursor = conn.cursor()

try:
# Update employee's balance
cursor.execute("UPDATE employees SET balance = ? WHERE employee_id = ?", (new_balance, employee_id))
if cursor.rowcount == 0: # No rows updated means employee_id was not found
conn.close()
return False # Employee not found, or no update was needed (though balance change implies it was)

# Add new leave dates to history
if leave_dates_to_add:
history_data: List[Tuple[str, str]] = [(employee_id, date_str) for date_str in leave_dates_to_add]
cursor.executemany("INSERT INTO leave_history (employee_id, leave_date) VALUES (?, ?)", history_data)

conn.commit() # Commit transaction
return True
except sqlite3.Error as e: # Catch any SQLite-related errors
conn.rollback() # Rollback transaction in case of any error during DB operations
# Optionally, log the error e here
return False
finally:
conn.close()

# Initialize tables and data when this module is loaded
create_tables_if_not_exist()
initialize_database_with_sample_data()

if __name__ == '__main__':
# Example usage for testing the database module directly
print("Database module initialized.")
print("Data for E001:", get_employee_data("E001"))
print("Data for E002:", get_employee_data("E002"))
print("Data for E003 (non-existent):", get_employee_data("E003"))

# Example apply leave
# print("\nAttempting to apply leave for E002...")
# if get_employee_data("E002")['balance'] >= 2:
# new_dates = ["2025-03-10", "2025-03-11"]
# current_balance = get_employee_data("E002")['balance']
# if update_employee_leave("E002", current_balance - len(new_dates), new_dates):
# print("Leave applied successfully for E002.")
# print("Updated data for E002:", get_employee_data("E002"))
# else:
# print("Failed to apply leave for E002.")
# else:
# print("E002 has insufficient balance for this example.")
Loading