Spaces:
Runtime error
Runtime error
Demo finsihed
Browse files- app.py +201 -0
- requirements.txt +4 -0
app.py
ADDED
@@ -0,0 +1,201 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import openai
|
2 |
+
import gradio as gr
|
3 |
+
import pandas as pd
|
4 |
+
import tiktoken
|
5 |
+
from openai.error import AuthenticationError
|
6 |
+
|
7 |
+
encoding = tiktoken.encoding_for_model("gpt-3.5-turbo")
|
8 |
+
|
9 |
+
class Bot():
|
10 |
+
def __init__(self):
|
11 |
+
self.car_data = None
|
12 |
+
self.api_key = None
|
13 |
+
self.system_prompt = """You are a salesman in a car dealership. You try to give a detailed answer to the
|
14 |
+
questions so that the customer is well advised. Note: If you recommend vehicles, they can only
|
15 |
+
be from the csv file provided by the customer. Customer cannot access the csv file himself."""
|
16 |
+
self.lang = "English"
|
17 |
+
|
18 |
+
def process_file(self, file, history):
|
19 |
+
print(file)
|
20 |
+
# throw error if file is not csv
|
21 |
+
if file.name.split(".")[-1] != "csv":
|
22 |
+
if lang == "English":
|
23 |
+
history.append((None, "Please upload a csv file"))
|
24 |
+
else:
|
25 |
+
history.append((None, "Bitte laden Sie eine csv-Datei hoch"))
|
26 |
+
return history
|
27 |
+
|
28 |
+
df = pd.read_csv(file.name)
|
29 |
+
# drop all rows with at least one NaN value
|
30 |
+
df = df.dropna()
|
31 |
+
df = df.drop(columns=["interne_nummer", "ez.1", "kilometer.1", "leistung.1", "leistung", "ez"])
|
32 |
+
# rename column leistung to leistung (kW)
|
33 |
+
# df = df.rename(columns={"leistung": "leistung (kW)"})
|
34 |
+
# df = df.rename(columns={"ez": "Erstzulassung"})
|
35 |
+
df = df.loc[:, ~df.columns.duplicated()]
|
36 |
+
|
37 |
+
# convert csv to text
|
38 |
+
self.car_data = df.to_string(index=False)
|
39 |
+
self.car_data = self.car_data.replace("Car.", "")
|
40 |
+
print(self.car_data)
|
41 |
+
print("Car data token count: ", len(encoding.encode(self.car_data)))
|
42 |
+
if self.api_key:
|
43 |
+
history = []
|
44 |
+
return history
|
45 |
+
|
46 |
+
def run_text(self, history, query):
|
47 |
+
# check api key
|
48 |
+
if not self.api_key:
|
49 |
+
# key must start from "sk-"
|
50 |
+
if not query.startswith("sk-"):
|
51 |
+
if lang == "English":
|
52 |
+
history.append((None, "Please enter your OpenAI API KEY"))
|
53 |
+
else:
|
54 |
+
history.append((None, "Bitte geben Sie Ihren OpenAI API-Schlüssel ein"))
|
55 |
+
return history
|
56 |
+
self.api_key = query
|
57 |
+
openai.api_key = query
|
58 |
+
if self.car_data:
|
59 |
+
history = []
|
60 |
+
else:
|
61 |
+
history.append((query, None))
|
62 |
+
if self.lang == "English":
|
63 |
+
history.append((None, "Please upload a csv file"))
|
64 |
+
else:
|
65 |
+
history.append((None, "Bitte laden Sie eine csv-Datei hoch"))
|
66 |
+
return history
|
67 |
+
|
68 |
+
if not self.car_data:
|
69 |
+
if self.lang == "English":
|
70 |
+
history.append((None, "Please upload a csv file"))
|
71 |
+
else:
|
72 |
+
history.append((None, "Bitte laden Sie eine csv-Datei hoch"))
|
73 |
+
return history
|
74 |
+
|
75 |
+
# add system message to the front
|
76 |
+
messages = [{"role": "system", "content": self.system_prompt}]
|
77 |
+
|
78 |
+
# add messages from history
|
79 |
+
for q, response in history:
|
80 |
+
if q:
|
81 |
+
messages.append({"role": "user", "content": q})
|
82 |
+
if response:
|
83 |
+
messages.append({"role": "system", "content": response})
|
84 |
+
|
85 |
+
# remove all messages in front of for the first one
|
86 |
+
# if the total number of tokens is greater than 3000
|
87 |
+
total_tokens = self._count_tokens(messages)
|
88 |
+
|
89 |
+
while total_tokens > 1200:
|
90 |
+
messages.pop(1)
|
91 |
+
total_tokens = self._count_tokens(messages)
|
92 |
+
|
93 |
+
# construct prompt from search results
|
94 |
+
if self.lang == "English":
|
95 |
+
prompt = f"""Use the cars in stock below if you need to recommend any vehicles. Only include cars that are in stock
|
96 |
+
and include links to your recommendations.
|
97 |
+
\n\n Cars in stock: \n {self.car_data} \n\n Query: {query} \n\n Response:"""
|
98 |
+
else:
|
99 |
+
prompt = f"""Verwenden Sie die unten aufgeführten Fahrzeuge, wenn Sie Fahrzeuge empfehlen müssen.
|
100 |
+
Berücksichtigen Sie nur Fahrzeuge, die auf Lager sind und geben Sie Links zu Ihren Empfehlungen an.
|
101 |
+
\n\n Fahrzeuge auf Lager: \n {self.car_data} \n\n Anfrage: {query} \n\n Antwort:"""
|
102 |
+
|
103 |
+
messages.append({"role": "user", "content": prompt})
|
104 |
+
# print(prompt)
|
105 |
+
|
106 |
+
# generate response
|
107 |
+
response = openai.ChatCompletion.create(
|
108 |
+
model="gpt-3.5-turbo", # change to gpt-3.5-turbo if don't have access
|
109 |
+
messages=messages,
|
110 |
+
temperature=0.3,
|
111 |
+
)['choices'][0]['message']['content']
|
112 |
+
|
113 |
+
# only add query and response to history
|
114 |
+
# the context is not needed
|
115 |
+
history.append((query, response))
|
116 |
+
|
117 |
+
return history
|
118 |
+
|
119 |
+
def generate_welcome_message(self):
|
120 |
+
messages = [{"role": "system", "content": self.system_prompt}]
|
121 |
+
try:
|
122 |
+
response = openai.ChatCompletion.create(
|
123 |
+
model="gpt-3.5-turbo", # change to gpt-3.5-turbo if don't have access
|
124 |
+
messages=messages,
|
125 |
+
temperature=0.3,
|
126 |
+
)['choices'][0]['message']['content']
|
127 |
+
except AuthenticationError:
|
128 |
+
if self.lang == "English":
|
129 |
+
response = "Wrong API key. Please enter your OpenAI API KEY"
|
130 |
+
else:
|
131 |
+
response = "Falscher API-Schlüssel. Bitte geben Sie Ihren OpenAI API-Schlüssel ein"
|
132 |
+
self.api_key = None
|
133 |
+
return response
|
134 |
+
|
135 |
+
def _count_tokens(self, messages):
|
136 |
+
total_tokens = 0
|
137 |
+
for message in messages:
|
138 |
+
total_tokens += len(encoding.encode(message['content']))
|
139 |
+
return total_tokens
|
140 |
+
|
141 |
+
def change_language(self, lang, history):
|
142 |
+
self.lang = lang
|
143 |
+
if lang == "English":
|
144 |
+
self.system_prompt = """You are a salesman in a car dealership. You try to give a detailed answer to the
|
145 |
+
questions so that the customer is well advised. Note: If you recommend vehicles, they can only
|
146 |
+
be from the csv file provided by the customer. Customer cannot access the csv file himself."""
|
147 |
+
if not self.api_key:
|
148 |
+
history = [(None, "Please enter your OpenAI API KEY")]
|
149 |
+
return history
|
150 |
+
if not self.car_data:
|
151 |
+
history = [(None, "Please upload a csv file")]
|
152 |
+
return history
|
153 |
+
else:
|
154 |
+
self.system_prompt = """Sie sind ein Verkäufer in einem Autohaus. Sie versuchen, eine detaillierte Antwort auf die
|
155 |
+
Fragen zu geben, damit der Kunde gut beraten wird. Hinweis: Wenn Sie Fahrzeuge empfehlen, können sie nur
|
156 |
+
aus der vom Kunden bereitgestellten CSV-Datei stammen. Der Kunde kann die CSV-Datei nicht selbst aufrufen."""
|
157 |
+
if not self.api_key:
|
158 |
+
history = [(None, "Bitte geben Sie Ihren OpenAI API-Schlüssel ein")]
|
159 |
+
return history
|
160 |
+
if not self.car_data:
|
161 |
+
history = [(None, "Bitte laden Sie eine csv-Datei hoch")]
|
162 |
+
return history
|
163 |
+
return []
|
164 |
+
|
165 |
+
|
166 |
+
|
167 |
+
|
168 |
+
|
169 |
+
if __name__ == '__main__':
|
170 |
+
bot = Bot()
|
171 |
+
# ui
|
172 |
+
with gr.Blocks(css="#chatbot .overflow-y-auto{height:500px}") as demo:
|
173 |
+
chatbot = gr.Chatbot([(None, "Please enter your OpenAI API KEY")], elem_id="chatbot", label="HUGO PFOHE - AI Car Salesman").style(height=500)
|
174 |
+
with gr.Row():
|
175 |
+
with gr.Column(scale=1):
|
176 |
+
txt = gr.Textbox(show_label=False, placeholder="What car would you like to buy?").style(
|
177 |
+
container=False)
|
178 |
+
# with gr.Column(scale=0.15):
|
179 |
+
# submit = gr.Button("Submit")
|
180 |
+
with gr.Row():
|
181 |
+
with gr.Column(scale=0.34, min_width=0):
|
182 |
+
lang = gr.inputs.Dropdown(choices=['English', 'German'], label="Language", default="English")
|
183 |
+
# with gr.Column(scale=0.33, min_width=0):
|
184 |
+
# clear = gr.Button("Clear")
|
185 |
+
# with gr.Column(scale=0.33, min_width=0):
|
186 |
+
# btn = gr.UploadButton("Upload CSV", file_types=["csv"])
|
187 |
+
with gr.Column(scale=0.66, min_width=0):
|
188 |
+
with gr.Row():
|
189 |
+
clear = gr.Button("Clear")
|
190 |
+
with gr.Row():
|
191 |
+
btn = gr.UploadButton("Upload CSV", file_types=["csv"])
|
192 |
+
|
193 |
+
|
194 |
+
txt.submit(bot.run_text, [chatbot, txt], chatbot)
|
195 |
+
txt.submit(lambda: "", None, txt)
|
196 |
+
lang.change(bot.change_language, [lang, chatbot], chatbot)
|
197 |
+
# submit.click(txt.submit, [chatbot, txt], chatbot)
|
198 |
+
# submit.click(lambda: "", None, txt)
|
199 |
+
clear.click(lambda: [], None, chatbot)
|
200 |
+
btn.upload(bot.process_file, [btn, chatbot], chatbot)
|
201 |
+
demo.launch()
|
requirements.txt
ADDED
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
openai
|
3 |
+
pandas
|
4 |
+
tiktoken
|