-
Notifications
You must be signed in to change notification settings - Fork 0
/
Chatbot.py
150 lines (119 loc) · 5.1 KB
/
Chatbot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
import os
import re
import time
import openai
from dotenv import load_dotenv
from CartManager import CartManager
from ElasticsearchManager import ElasticsearchManager
# Load environment variables from .env file
load_dotenv()
class Chatbot:
"""A chatbot capable of handling user queries and managing a shopping cart."""
def __init__(self):
"""
Initialize a Chatbot object by reading the OpenAI API key from a YAML file.
"""
self.es = ElasticsearchManager()
self.cart_manager = CartManager()
openai.api_key = os.getenv("OPENAI_API_KEY")
def handle_query(self, messages, query):
"""
Handle a user query.
:param messages: List of messages exchanged in the conversation.
:type messages: list
:param query: The user's query.
:type query: str
:return: Updated list of messages, response, and shopping cart items.
:rtype: tuple
"""
query_lower = query.lower()
messages, response = self.generate_response(messages, query_lower)
action, title, author, genre, response = self.extract_action(response)
if action == "Search":
books = self.es.search_book(title=title, author=author, genre=genre)
num_books = len(books)
if num_books > 1:
# Format the book details into a string, each on a new line
books_details = "\n".join(
[f"{idx + 1}. Title: {book['title']}, Author: {book['author']}, Genre: {book['genre']}"
for idx, book in enumerate(books)])
response += f"\nI found multiple books:\n{books_details}\n\nWhich one do you mean?"
elif num_books == 1:
book = books[0] # Get the single book found
response += f"\nI found the book: Title: {book['title']}, Author: {book['author']}, Genre: {book['genre']}. Would you like to add it to the cart?"
else:
response += "\nI couldn't find any books matching your criteria."
# Ensure the response is part of the conversation history
messages.append({"role": "assistant", "content": response})
elif action == "Add_to_Cart":
self.add_to_cart(title)
elif action == "Remove_from_Cart":
self.remove_from_cart(title)
elif action == "Clear_Cart":
self.remove_all()
time.sleep(1)
carts = self.cart_manager.get_cart()
return messages, response, carts
def add_to_cart(self, title):
"""
Add an item to the shopping cart.
:param title: The title of the item to add.
:type title: str
"""
search_results = self.cart_manager.search_cart(title)
if search_results:
return f"Item {title} already in our database."
self.cart_manager.add(title)
def remove_from_cart(self, title):
"""
Remove an item from the shopping cart.
:param title: The title of the item to remove.
:type title: str
"""
search_results = self.cart_manager.search_cart(title)
if not search_results:
return f"Item {title} not found in our database."
self.cart_manager.remove(title)
def remove_all(self):
"""Remove all items from the shopping cart."""
self.cart_manager.clear()
def generate_response(self, messages, user_query, temperature=0.7):
"""
Generate a response to a user query.
:param messages: List of messages exchanged in the conversation.
:type messages: list
:param user_query: The user's query.
:type user_query: str
:param temperature: Controls the randomness of the response.
:type temperature: float
:return: Updated list of messages and the generated response.
:rtype: tuple
"""
messages.append({"role": "user", "content": user_query})
completion = openai.ChatCompletion.create(model="gpt-4",
messages=messages,
temperature=temperature)
ai_response = completion.choices[0].message.content
messages.append({"role": "assistant", "content": ai_response})
return messages, ai_response
def extract_action(self, text):
"""
Extract action and book title from text.
:param text: The text to extract information from.
:type text: str
:return: Action, book title, and updated text.
:rtype: tuple
"""
action = ""
book_title = ""
author = ""
genre = ""
pattern = r"\[ACTION: (.*?); BOOK_TITLE: (.*?); AUTHOR: (.*?); GENRE: (.*?)\]"
matches = re.findall(pattern, text)
if matches:
for match in matches:
action, book_title, author, genre = match
text = text.replace(
"[ACTION: " + action + "; BOOK_TITLE: " + book_title + "; AUTHOR: " + author + "; GENRE: " + genre + "]",
"")
return action, book_title, author, genre, text