Open AI call function
In this exercise, you'll build a project management assistant using OpenAI API Function Calling A .csv file is used to simulate reading and writing from a database or project management tool API. Follow the directions in the starter code below, and try to build the functions and function calling logic before you look at the solution on the next page!
Import necessary libraries
# Importing the library for OpenAI API
from openai import OpenAI
import os
# Define OpenAI API key
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
First, define the Python functions that will read and write from the project_management.csv file using Pandas dataframes. This code uses Pandas dataframes to read and write from the .csv file.
We define 3 tasks our project management assistant can perform.
Each function returns a JSON string as output
import pandas as pd
import json
data_dict = {
"Task ID": {0: 1, 1: 2, 2: 3},
"Task Name": {
0: "Design Database Schema",
1: "Implement Login Page",
2: "Prepare Project Report",
},
"Project ID": {0: 101, 1: 101, 2: 102},
"Assigned To": {0: "Jane Doe", 1: "John Smith", 2: "Alice Johnson"},
"Status": {0: "In Progress", 1: "completed", 2: "Completed"},
"Priority": {0: "High", 1: "Medium", 2: "Low"},
"Due Date": {0: "2023-08-01", 1: "2023-08-15", 2: "2023-07-15"},
"Date Created": {0: "2023-07-01", 1: "2023-07-01", 2: "2023-06-01"},
"Last Updated": {0: "2023-07-10", 1: "2022-01-05", 2: "2023-07-05"},
"Time Estimate": {0: "10", 1: "5", 2: "2"},
"Time Spent": {0: 4, 1: None, 2: 2.0},
"Description": {
0: "Create initial database schema for customer data",
1: "Develop the login page UI and backend",
2: "Compile the weekly project status report",
},
"Project Phase": {0: "Design", 1: "Implementation", 2: "Reporting"},
"Dependencies": {0: None, 1: 1.0, 2: None},
}
df = pd.DataFrame.from_dict(data_dict)
df
Task ID | Task Name | Project ID | Assigned To | Status | Priority | Due Date | Date Created | Last Updated | Time Estimate | Time Spent | Description | Project Phase | Dependencies | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | Design Database Schema | 101 | Jane Doe | In Progress | High | 2023-08-01 | 2023-07-01 | 2023-07-10 | 10 | 4.0 | Create initial database schema for customer data | Design | NaN |
1 | 2 | Implement Login Page | 101 | John Smith | completed | Medium | 2023-08-15 | 2023-07-01 | 2022-01-05 | 5 | NaN | Develop the login page UI and backend | Implementation | 1.0 |
2 | 3 | Prepare Project Report | 102 | Alice Johnson | Completed | Low | 2023-07-15 | 2023-06-01 | 2023-07-05 | 2 | 2.0 | Compile the weekly project status report | Reporting | NaN |
def task_retrieval_and_status_updates(task_id, status, last_updated):
"""Retrieve and update task status"""
df.loc[df["Task ID"] == task_id, "Status"] = status
df.loc[df["Task ID"] == task_id, "Last Updated"] = last_updated
df.to_csv("project_management.csv", index=False) # save changes to file
task = df.loc[df["Task ID"] == task_id]
return json.dumps(task.to_dict())
def project_reporting_and_analytics(project_id):
"""Generate reports on project progress and team performance"""
project = df.loc[df["Project ID"] == project_id]
return json.dumps(project.to_dict())
def resource_allocation_and_scheduling(
task_id, assigned_to, time_estimate, due_date, status
):
"""Allocate tasks based on current workloads and schedules"""
df.loc[df["Task ID"] == task_id, "Assigned To"] = assigned_to
df.loc[df["Task ID"] == task_id, "Time Estimate"] = time_estimate
df.loc[df["Task ID"] == task_id, "Due Date"] = due_date
df.loc[df["Task ID"] == task_id, "Status"] = status
df.to_csv("project_management.csv", index=False) # save changes to file
task = df.loc[df["Task ID"] == task_id]
return json.dumps(task.to_dict())
Next, we'll build the project management assistant conversation.
We'll define the messages to send to the model, including a tools dictionary that defines a list of tools, which are the functions that are available to the model to identify and parse parameters for.
def run_conversation(user_promt):
# messages is a list of initial conversation messages. The system message describes the role of the assistant. The second message is from the user, the user prompt
messages = [
{
"role": "system",
"content": "You are a project management assistant with knowledge of project statuses, task assignments, and scheduling. You can provide updates on projects, assign tasks to team members, and schedule meetings. You understand project management terminology and are capable of parsing detailed project data. Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous.",
},
{
"role": "user",
"content": user_promt,
}, # this prompt should call the function
]
# tools is a list of functions that the assistant can use. Each function is described by its name, description, and parameters.
tools = [
{
"type": "function",
"function": {
"name": "task_retrieval_and_status_updates",
"description": "Retrieve and update task status",
"parameters": {
"type": "object",
"properties": {
"task_id": {
"type": "integer",
"description": "The unique identifier for the task",
},
"status": {
"type": "string",
"description": "The new status of the task",
},
"last_updated": {
"type": "string",
"description": "The date of the last status update or change to the task",
},
},
"required": ["task_id", "status", "last_updated"],
},
},
},
{
"type": "function",
"function": {
"name": "project_reporting_and_analytics",
"description": "Generate reports on project progress and team performance",
"parameters": {
"type": "object",
"properties": {
"project_id": {
"type": "integer",
"description": "The unique identifier for the project",
}
},
"required": ["project_id"],
},
},
},
{
"type": "function",
"function": {
"name": "resource_allocation_and_scheduling",
"description": "Allocate tasks based on current workloads and schedules",
"parameters": {
"type": "object",
"properties": {
"task_id": {
"type": "integer",
"description": "The unique identifier for the task",
},
"assigned_to": {
"type": "string",
"description": "The user ID or name of the person to whom the task is assigned",
},
"time_estimate": {
"type": "integer",
"description": "An estimate of the time required to complete the task",
},
"due_date": {
"type": "string",
"description": "The deadline for the task completion",
},
"status": {
"type": "string",
"description": "The current status of the task",
},
},
"required": [
"task_id",
"assigned_to",
"time_estimate",
"due_date",
"status",
],
},
},
},
]
# `openai.chat.completions.create()` is called to generate a response from the GPT-3 model. The model, messages, and tools are passed as arguments. The `tool_choice` is set to "auto", allowing the model to choose which tool (function) to use.
# Use openai.ChatCompletion.create for openai < 1.0
# openai.chat.completions.create for openai > 1.0
response = client.chat.completions.create(
model="gpt-3.5-turbo-1106",
messages=messages,
tools=tools,
tool_choice="auto", # let the model decide which tool (function) to use
)
# response_message and tool_calls extract the first response message and any tool calls from the response.
response_message = response.choices[0].message
tool_calls = (
response_message.tool_calls
) # get the tool calls from the first response
print(tool_calls)
# end of first response, now we parse the response and call the functions the model identified from our tool list
# check if the model wanted to call a function
if tool_calls:
# list the available functions and their corresponding python functions
available_functions = {
"task_retrieval_and_status_updates": task_retrieval_and_status_updates,
"project_reporting_and_analytics": project_reporting_and_analytics,
"resource_allocation_and_scheduling": resource_allocation_and_scheduling,
}
messages.append(
response_message
) # extend the conversation with the first response
# send the info for each function call and function response to the model
for tool_call in tool_calls: # iterate through the tool calls in the response
function_name = (
tool_call.function.name
) # get the name of the function to call
function_to_call = available_functions[function_name]
function_args = json.loads(
tool_call.function.arguments
) # converting the arguments of the function call from a JSON formatted string into a Python dictionary.
if function_name == "task_retrieval_and_status_updates":
function_response = function_to_call( # call the function with the arguments. The result of the function call is stored in function_response
task_id=function_args.get("task_id"),
status=function_args.get("status"),
last_updated=function_args.get("last_updated"),
)
elif function_name == "project_reporting_and_analytics":
function_response = function_to_call(
project_id=function_args.get("project_id")
)
elif function_name == "resource_allocation_and_scheduling":
function_response = function_to_call(
task_id=function_args.get("task_id"),
assigned_to=function_args.get("assigned_to"),
time_estimate=function_args.get("time_estimate"),
due_date=function_args.get("due_date"),
status=function_args.get("status"),
)
message_to_append = {
"tool_call_id": tool_call.id,
"role": "tool",
"name": function_name,
"content": function_response, # send the function response to the model, it's the JSON string of the function response
}
messages.append(
message_to_append
) # extend conversation with function response
# See https://gist.github.com/gaborcselle/2dc076eae23bd219ff707b954c890cd7
# messages[1].content = "" # clear the first message (parsing bug)
# messages[1]["content"] = "" # clear the first message (parsing bug)
print("\n: Mesagges")
print(messages)
second_response = client.chat.completions.create(
model="gpt-3.5-turbo-1106",
messages=messages,
) # get a new response from the model where it can see the function response
return second_response
user_promt = (
"Update the status of the task with id: 1, to: completed. Today is 29-02-2024"
)
response = run_conversation(user_promt=user_promt)
[ChatCompletionMessageToolCall(id='call_hn3NiNUMnFIAbV0yGUdA5dgS', function=Function(arguments='{"task_id":1,"status":"completed","last_updated":"29-02-2024"}', name='task_retrieval_and_status_updates'), type='function')] : Mesagges [{'role': 'system', 'content': "You are a project management assistant with knowledge of project statuses, task assignments, and scheduling. You can provide updates on projects, assign tasks to team members, and schedule meetings. You understand project management terminology and are capable of parsing detailed project data. Don't make assumptions about what values to plug into functions. Ask for clarification if a user request is ambiguous."}, {'role': 'user', 'content': 'Update the status of the task with id: 1, to: completed. Today is 29-02-2024'}, ChatCompletionMessage(content=None, role='assistant', function_call=None, tool_calls=[ChatCompletionMessageToolCall(id='call_hn3NiNUMnFIAbV0yGUdA5dgS', function=Function(arguments='{"task_id":1,"status":"completed","last_updated":"29-02-2024"}', name='task_retrieval_and_status_updates'), type='function')]), {'tool_call_id': 'call_hn3NiNUMnFIAbV0yGUdA5dgS', 'role': 'tool', 'name': 'task_retrieval_and_status_updates', 'content': '{"Task ID": {"0": 1}, "Task Name": {"0": "Design Database Schema"}, "Project ID": {"0": 101}, "Assigned To": {"0": "Jane Doe"}, "Status": {"0": "completed"}, "Priority": {"0": "High"}, "Due Date": {"0": "2023-08-01"}, "Date Created": {"0": "2023-07-01"}, "Last Updated": {"0": "29-02-2024"}, "Time Estimate": {"0": "10"}, "Time Spent": {"0": 4.0}, "Description": {"0": "Create initial database schema for customer data"}, "Project Phase": {"0": "Design"}, "Dependencies": {"0": NaN}}'}]
response
ChatCompletion(id='chatcmpl-8xZETXppBTKNbbE90OVKI7f0CXAMb', choices=[Choice(finish_reason='stop', index=0, logprobs=None, message=ChatCompletionMessage(content='Task with ID 1, "Design Database Schema," has been updated to status: completed, as of today, 29-02-2024.', role='assistant', function_call=None, tool_calls=None))], created=1709207477, model='gpt-3.5-turbo-1106', object='chat.completion', system_fingerprint='fp_b3e55cb931', usage=CompletionUsage(completion_tokens=31, prompt_tokens=316, total_tokens=347))
df
Task ID | Task Name | Project ID | Assigned To | Status | Priority | Due Date | Date Created | Last Updated | Time Estimate | Time Spent | Description | Project Phase | Dependencies | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | 1 | Design Database Schema | 101 | Jane Doe | completed | High | 2023-08-01 | 2023-07-01 | 29-02-2024 | 10 | 4.0 | Create initial database schema for customer data | Design | NaN |
1 | 2 | Implement Login Page | 101 | John Smith | completed | Medium | 2023-08-15 | 2023-07-01 | 2022-01-05 | 5 | NaN | Develop the login page UI and backend | Implementation | 1.0 |
2 | 3 | Prepare Project Report | 102 | Alice Johnson | Completed | Low | 2023-07-15 | 2023-06-01 | 2023-07-05 | 2 | 2.0 | Compile the weekly project status report | Reporting | NaN |
Created: 2024-10-23