Skip to content

Commit bae9417

Browse files
committed
customer chatbot
1 parent 3cc4739 commit bae9417

File tree

2 files changed

+194
-0
lines changed

2 files changed

+194
-0
lines changed
Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
"""
2+
Customer chatbot.
3+
4+
Input:
5+
Users can submit queries that describe the type of books they are looking for, e.g., suggest fiction novels.
6+
Users can also ask the chat assistant for books by specific author, e.g., recommend books by Dan Brown.
7+
Answers to user's queries will be based on the Goodreads dataset:
8+
https://www.kaggle.com/datasets/cristaliss/ultimate-book-collection-top-100-books-up-to-2023
9+
10+
Application logic:
11+
The app determines the closest matches by comparing user query's embedding to the available
12+
book embeddings. Embeddings of books are pre-computed on the description column of every book
13+
and stored in the assets/ folder.
14+
15+
Response:
16+
The chat assistant then determines the top relevant answers shortlisted by comparing embeddings and
17+
provides the top 5 recommendations.
18+
"""
19+
20+
import json
21+
22+
import panel as pn
23+
from openai import OpenAI
24+
from scipy.spatial import KDTree
25+
import numpy as np
26+
import pandas as pd
27+
from pathlib import Path
28+
from _wandb import WeightsBiasesTracking
29+
import datetime
30+
31+
from util import get_embedding_from_text
32+
33+
ORDER_CANCEL = False
34+
35+
WEIGHTS_AND_BIASES_TRACKING = False
36+
37+
if WEIGHTS_AND_BIASES_TRACKING:
38+
wandb_client = WeightsBiasesTracking()
39+
40+
41+
client = OpenAI()
42+
43+
df = pd.read_csv("orders.csv")
44+
45+
46+
def detect_order_number(user_query):
47+
system_prompt = f"""
48+
You're a system that determines the invoice number or the order number in the user query.
49+
50+
You need to return only the order number.If no invoice number or order number is found
51+
return the string None.
52+
"""
53+
response = client.chat.completions.create(
54+
model="gpt-3.5-turbo",
55+
messages=[
56+
{"role": "system", "content": system_prompt},
57+
{"role": "user", "content": "What were the items in order 536365?"},
58+
{"role": "system", "content": "536365"},
59+
{"role": "user", "content": user_query},
60+
],
61+
seed=42,
62+
n=1,
63+
)
64+
invoice_number = response.choices[0].message.content
65+
print(f"invoice_number: {invoice_number}")
66+
return invoice_number if invoice_number != "None" else ""
67+
68+
69+
def detect_intent(user_query):
70+
system_prompt = f"""
71+
You're a system that determines the intent of the user query.
72+
73+
You need to return only the intent and no additional sentences.
74+
If relevant intent is not found then return the string None.
75+
76+
Valid intents = ["TOTAL_ORDER_COST", "CANCEL", "NUMBER_OF_ITEMS", "ORDER_ITEM_DETAILS", "CUSTOMER_ORDERS"]
77+
"""
78+
response = client.chat.completions.create(
79+
model="gpt-3.5-turbo",
80+
messages=[
81+
{"role": "system", "content": system_prompt},
82+
{"role": "user", "content": "What is the total cost of the order 536365"},
83+
{"role": "system", "content": "TOTAL_ORDER_COST"},
84+
{"role": "user", "content": "total cost of all items in the order 536365"},
85+
{"role": "system", "content": "TOTAL_ORDER_COST"},
86+
{"role": "user", "content": "Which items were ordered in 536364"},
87+
{"role": "system", "content": "ORDER_ITEM_DETAILS"},
88+
{"role": "user", "content": "Can i cancel the order 458891"},
89+
{"role": "system", "content": "CANCEL"},
90+
{"role": "user", "content": "How many items were ordered in Invoice 558420"},
91+
{"role": "system", "content": "NUMBER_OF_ITEMS"},
92+
{"role": "user", "content": "Purchases made by Customer ID 17850"},
93+
{"role": "system", "content": "CUSTOMER_ORDERS"},
94+
{"role": "user", "content": user_query},
95+
],
96+
seed=42,
97+
n=1,
98+
)
99+
intent = response.choices[0].message.content
100+
return intent if intent != None else ""
101+
102+
103+
def cancel_order(invoice_number):
104+
cancel = {}
105+
print(df.head())
106+
invoice_details = df.loc[df['InvoiceNo'] == invoice_number]
107+
print(len(invoice_details))
108+
if len(invoice_details) == 0:
109+
cancel['eligible'] = False
110+
cancel['reason'] = f"Order not found: {invoice_number}"
111+
ORDER_CANCEL = False
112+
return cancel
113+
114+
invoice_date = invoice_details.iloc[0]['InvoiceDate']
115+
print(f"invoice_date: {invoice_date}")
116+
date_object = datetime.datetime.strptime(invoice_date.split()[0], "%d/%m/%y")
117+
print(date_object)
118+
start_date = datetime.datetime(2010, 11, 1)
119+
end_date = datetime.datetime(2010, 12, 2)
120+
if start_date < date_object < end_date:
121+
cancel['eligible'] = True
122+
ORDER_CANCEL = True
123+
return cancel
124+
else:
125+
cancel['eligible'] = False
126+
cancel['reason'] = f"Order {invoice_number} not eligible for cancellation."
127+
ORDER_CANCEL = False
128+
return cancel
129+
130+
131+
def customer_chatbot_agent(user_query, verbose=False, tracking=False):
132+
"""An agent that can respond to customer's queries regarding orders"""
133+
134+
if ORDER_CANCEL and "yes" in user_query:
135+
ORDER_CANCEL = False
136+
return f"Order successfully cancelled"
137+
138+
invoice_number = detect_order_number(user_query)
139+
if not invoice_number:
140+
return "Please provide an Order ID"
141+
intent = detect_intent(user_query)
142+
print(intent)
143+
if not intent:
144+
return "Please provide more details regarding the action you want to take on the order."
145+
146+
if intent != "CANCEL":
147+
return "We only support order cancellation requests. "
148+
149+
return cancel_order(invoice_number)
150+
151+
return "Sorry, we couldn't understand your query!"
152+
153+
# start_time_ms = datetime.datetime.now().timestamp() * 1000
154+
#
155+
# response = client.chat.completions.create(
156+
# model="gpt-3.5-turbo",
157+
# messages=[
158+
# {"role": "system", "content": system_prompt},
159+
# {"role": "user", "content": user_query},
160+
# ],
161+
# seed=42,
162+
# n=1,
163+
# )
164+
#
165+
# end_time_ms = round(datetime.datetime.now().timestamp() * 1000)
166+
#
167+
# if tracking:
168+
# wandb_client.create_trace(system_prompt, response, user_query, start_time_ms, end_time_ms)
169+
170+
# return response.choices[0].message.content
171+
172+
173+
def callback(contents: str, user: str, instance: pn.chat.ChatInterface):
174+
return customer_chatbot_agent(contents, tracking=WEIGHTS_AND_BIASES_TRACKING)
175+
176+
177+
chat_interface = pn.chat.ChatInterface(callback=callback, callback_exception='verbose')
178+
chat_interface.send(
179+
"I am a customer chat assistant! "
180+
"Currently we support only order cancellations. Please mention Order ID in your request."
181+
"You can deploy your own by signing up at https://ploomber.io",
182+
user="System",
183+
respond=False,
184+
)
185+
186+
pn.template.MaterialTemplate(
187+
title="Customer Chatbot",
188+
main=[chat_interface],
189+
).servable()
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
panel
2+
openai
3+
scipy
4+
numpy
5+
wandb

0 commit comments

Comments
 (0)