blackbird-app / function_orchestrator.py
dwb2023's picture
Update function_orchestrator.py
3775a55 verified
raw
history blame
7.34 kB
import anthropic
import json
import re
import requests
client = anthropic.Client()
MODEL_NAME = "claude-3-sonnet-20240229"
# Define the base URL for the FastAPI service
BASE_URL = "https://huggingface.co/spaces/dwb2023/blackbird-svc:7860"
# Define tools
tools = [
{
"name": "get_user"
"description": "Looks up a user by email, phone, or username.",
"input_schema": {
"type": "object",
"properties": {
"key": {
"type": "string",
"enum": ["email", "phone", "username"],
"description": "The attribute to search for a user by (email, phone, or username)."
},
"value": {
"type": "string",
"description": "The value to match for the specified attribute."
}
},
"required": ["key", "value"]
}
},
{
"name": "get_order_by_id",
"description": "Retrieves the details of a specific order based on the order ID.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The unique identifier for the order."
}
},
"required": ["order_id"]
}
},
{
"name": "get_customer_orders",
"description": "Retrieves the list of orders belonging to a user based on a user's customer id.",
"input_schema": {
"type": "object",
"properties": {
"customer_id": {
"type": "string",
"description": "The customer_id belonging to the user"
}
},
"required": ["customer_id"]
}
},
{
"name": "cancel_order",
"description": "Cancels an order based on a provided order_id. Only orders that are 'processing' can be cancelled.",
"input_schema": {
"type": "object",
"properties": {
"order_id": {
"type": "string",
"description": "The order_id pertaining to a particular order"
}
},
"required": ["order_id"]
}
},
{
"name": "update_user_contact",
"description": "Updates a user's email and/or phone number.",
"input_schema": {
"type": "object",
"properties": {
"user_id": {
"type": "string",
"description": "The ID of the user"
},
"email": {
"type": "string",
"description": "The new email address of the user"
},
"phone": {
"type": "string",
"description": "The new phone number of the user"
}
},
"required": ["user_id"]
}
},
{
"name": "get_user_info",
"description": "Retrieves a user's information along with their order history based on email, phone, or username.",
"input_schema": {
"type": "object",
"properties": {
"key": {
"type": "string",
"enum": ["email", "phone", "username"],
"description": "The attribute to search for a user by (email, phone, or username)."
},
"value": {
"type": "string",
"description": "The value to match for the specified attribute."
}
},
"required": ["key", "value"]
}
}
]
# Function to process tool calls
def process_tool_call(tool_name, tool_input):
if tool_name == "get_user":
response = requests.post(f"{BASE_URL}/get_user", json=tool_input)
elif tool_name == "get_order_by_id":
response = requests.post(f"{BASE_URL}/get_order_by_id", json=tool_input)
elif tool_name == "get_customer_orders":
response = requests.post(f"{BASE_URL}/get_customer_orders", json=tool_input)
elif tool_name == "cancel_order":
response = requests.post(f"{BASE_URL}/cancel_order", json=tool_input)
elif tool_name == "update_user_contact":
response = requests.post(f"{BASE_URL}/update_user", json=tool_input)
elif tool_name == "get_user_info":
response = requests.post(f"{BASE_URL}/get_user_info", json=tool_input)
else:
return {"error": "Invalid tool name"}
if response.status_code == 200:
return response.json()
else:
return {"error": response.text}
# Function to handle interactive chat session
def simple_chat():
system_prompt = """
You are a customer support chat bot for an online retailer called TechNova.
Your job is to help users look up their account, orders, and cancel orders.
Be helpful and brief in your responses.
You have access to a set of tools, but only use them when needed.
If you do not have enough information to use a tool correctly, ask a user follow up questions to get the required inputs.
Do not call any of the tools unless you have the required data from a user.
In each conversational turn, you will begin by thinking about your response.
Once you're done, you will write a user-facing response.
"""
user_message = input("\nUser: ")
messages = [{"role": "user", "content": user_message}]
while True:
#If the last message is from the assistant, get another input from the user
if messages[-1].get("role") == "assistant":
user_message = input("\nUser: ")
messages.append({"role": "user", "content": user_message})
#Send a request to Claude
response = client.messages.create(
model=MODEL_NAME,
max_tokens=4096,
tools=tools,
messages=messages
)
# Update messages to include Claude's response
messages.append(
{"role": "assistant", "content": response.content}
)
#If Claude stops because it wants to use a tool:
if response.stop_reason == "tool_use":
tool_use = response.content[-1] #Naive approach assumes only 1 tool is called at a time
tool_name = tool_use.name
tool_input = tool_use.input
print(f"======Claude wants to use the {tool_name} tool======")
#Actually run the underlying tool functionality on our db
tool_result = process_tool_call(tool_name, tool_input)
#Add our tool_result message:
messages.append(
{
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_use.id,
"content": str(tool_result),
}
],
},
)
else:
#If Claude does NOT want to use a tool, just print out the text reponse
print("\nTechNova Support: " + f"{response.content[0].text}" )
# Start the chat!!
simple_chat()