Nicolas852 commited on
Commit
a96a8ea
1 Parent(s): eef9635
Files changed (2) hide show
  1. Shop_chatbot.ipynb +0 -0
  2. app.py +910 -48
Shop_chatbot.ipynb DELETED
The diff for this file is too large to render. See raw diff
 
app.py CHANGED
@@ -1,63 +1,925 @@
1
- import gradio as gr
2
- from huggingface_hub import InferenceClient
 
 
3
 
 
 
4
  """
5
- For more information on `huggingface_hub` Inference API support, please check the docs: https://huggingface.co/docs/huggingface_hub/v0.22.2/en/guides/inference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  """
7
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
8
 
9
 
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
 
19
 
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
 
26
- messages.append({"role": "user", "content": message})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
 
28
- response = ""
29
 
30
- for message in client.chat_completion(
31
- messages,
32
- max_tokens=max_tokens,
33
- stream=True,
34
- temperature=temperature,
35
- top_p=top_p,
36
- ):
37
- token = message.choices[0].delta.content
38
 
39
- response += token
40
- yield response
41
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  """
43
- For information on how to customize the ChatInterface, peruse the gradio docs: https://www.gradio.app/docs/chatinterface
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  """
45
- demo = gr.ChatInterface(
46
- respond,
47
- additional_inputs=[
48
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
49
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
50
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
51
- gr.Slider(
52
- minimum=0.1,
53
- maximum=1.0,
54
- value=0.95,
55
- step=0.05,
56
- label="Top-p (nucleus sampling)",
57
- ),
58
- ],
59
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
 
61
 
62
- if __name__ == "__main__":
63
- demo.launch()
 
1
+ # -*- coding: utf-8 -*-
2
+ """Shop_chatbot.ipynb
3
+
4
+ Automatically generated by Colab.
5
 
6
+ Original file is located at
7
+ https://colab.research.google.com/drive/1ZOEdR8x7T0Qkj5Nn5FeI8hKIHyTfqsFU
8
  """
9
+
10
+ import pandas as pd
11
+
12
+ data = [
13
+ {
14
+ "Model Number": "Honeywell VC10 Aeromax Elite Cordless Vacuum Cleaner",
15
+ "Product Design": "Off-the-shelf",
16
+ "Price": 379.95,
17
+ "Power": 400,
18
+ "Filter": "HEPA+Sponge",
19
+ "Air Watts Suction": 125,
20
+ "Charging Time": 4.5,
21
+ "Noise Level": 85,
22
+ "Weight": 2.7,
23
+ "Dimensions": {
24
+ "width": 230,
25
+ "depth": 257,
26
+ "height": 1170
27
+ },
28
+ "Accessories and Tools": [
29
+ "Cleaner head with Tangle Resistant Hair Design and LED with Natural Brite-White for better clarity",
30
+ "2-in-1 Crevice Tool",
31
+ "Wall Mount Docking Station",
32
+ "Flexible Crevice Tube",
33
+ "2-in-1 Sofa Brush",
34
+ ],
35
+ "Running Time": 60,
36
+ "Description": """The Honeywell VC10 AEROMAX ELITE is a lightweight cordless vacuum offering powerful 125 air-watt suction
37
+ with its advanced digital motor. This vacuum includes eight tools, a tangle-resistant design,
38
+ and LED lights on the roller for clear and enjoyable cleaning. Its dual-cyclonic filtration ensures consistent suction,
39
+ while the ergonomic design promotes wrist comfort. With up to 55 minutes of runtime from the high-capacity battery,
40
+ Easy One-Touch Control for settings, a quick dustbin emptying mechanism, a wall mount dock, and a deluxe pet hair brush,
41
+ it's an ideal choice, especially for pet owners. Upgrade your cleaning with the VC10 AEROMAX ELITE.
42
+ """,
43
+ "URL": "https://honeywellvac.com/products/vc10-aeromax-elite"
44
+ },
45
+ {
46
+ "Model Number": "Honeywell VC14 Aeromax Elite Cordless Vacuum Cleaner",
47
+ "Product Design": "Off-the-shelf",
48
+ "Price": 649.95,
49
+ "Power": 630,
50
+ "Filter": "HEPA 13",
51
+ "Air Watts Suction": 220,
52
+ "Charging Time": 2.0,
53
+ "Noise Level": 81,
54
+ "Weight": 2.92,
55
+ "Dimensions": {
56
+ "width": 255,
57
+ "depth": 278,
58
+ "height": 1190
59
+ },
60
+ "Accessories and Tools": [
61
+ "Tangle-Resistant Motorized Carpet Roller with Carpet Friendly Softer Bristles & Composite Strip (No LED)",
62
+ "Mini Electric Brush for Mattress, Sofa, Stairs",
63
+ "Rotatory Brush",
64
+ "Flexible Hose",
65
+ "Exchangeable Wide Brush",
66
+ ],
67
+ "Running Time": 90,
68
+ "Description": """The Honeywell VC14 AEROMAX ELITE Cordless Vacuum offers superior 220 air-watt suction with its 630W digital motor.
69
+ This lightweight handheld vacuum includes ten tools for comprehensive cleaning.
70
+ Features include a tangle-resistant design, LED lights on the roller,
71
+ and a dual pro high-efficiency filter system for effective dust separation.
72
+ It's ergonomically designed for wrist comfort and boasts a high-capacity battery with 70 minutes of run time.
73
+ A fast-charging premium charger, advanced LED display for settings adjustments, smart auto clean mode,
74
+ easy one-press disposal, and washable dust tank enhance usability.
75
+ The package also includes a wall mount docking station and a deluxe pet hair removal brush.
76
+ """,
77
+ "URL": "https://honeywellvac.com/products/vc14"
78
+ },
79
+ {
80
+ "Model Number": "Honeywell VC16 Cordless Vacuum Cleaner",
81
+ "Product Design": "New Design",
82
+ "Price": 599.95,
83
+ "Power": 600,
84
+ "Filter": "HEPA",
85
+ "Air Watts Suction": 185,
86
+ "Charging Time": 4.5,
87
+ "Noise Level": 83,
88
+ "Weight": 3.0,
89
+ "Dimensions": {
90
+ "width": 250,
91
+ "depth": 251,
92
+ "height": 1120
93
+ },
94
+ "Accessories and Tools": [
95
+ "Carpet Floor Nozzle",
96
+ "EZ-Change Soft Roller",
97
+ "Deluxe 2-in-1 Sofa Brush",
98
+ "Deluxe 2-in-1 Crevice Tool",
99
+ "Additional HEPA filter H13",
100
+ "Flexible/Stretch Hose",
101
+ "Scented Bead Connector",
102
+ "Bendable connector",
103
+ "Pet Hair removal brush",
104
+ "Deluxe Soft Hairbrush",
105
+ "Electric Mattress/Stairs/Sofa Brush",
106
+ "Deluxe Pet Hair Removal Brush",
107
+ "Small Brush with Cutter",
108
+ "Long Cleaning Brush with Bristles",
109
+ "Accessory Storage Bag",
110
+ ],
111
+ "Running Time": 60,
112
+ "Description":
113
+ """The Honeywell VC16 AEROMAX PRO is a lightweight, cordless vacuum with powerful 185 air-watt suction,
114
+ thanks to its advanced 600W digital motor. Boasting eight cleaning tools,
115
+ this handheld device offers tangle-resistant design and a full-length Brite White LED light strip on the rollers,
116
+ plus an extra spotlight on the body. Its cyclonic tank, paired with a HEPA filter,
117
+ ensures 99.9% dust separation, while the ISC technology keeps the filter efficient.
118
+ Its ergonomic design ensures wrist comfort, and a high-capacity battery offers up to 60 minutes of use.
119
+ The vacuum also features an intuitive LCD display for power and speed control, easy dustbin disposal,
120
+ a motorized rotary brush, scented beads, and a bendable flex hose for hard-to-reach areas.
121
+ """,
122
+ "URL": "https://honeywellvac.com/products/vc16-aeromax-pro-cordless-vac"
123
+ },
124
+ ]
125
+
126
+
127
+ # Create the DataFrame
128
+ df = pd.DataFrame(data)
129
+
130
+ # Display the DataFrame
131
+ df
132
+
133
+ # Import the libraries
134
+ import os, json, ast
135
+ import openai
136
+ from tenacity import retry, wait_random_exponential, stop_after_attempt
137
+
138
+ from openai import OpenAI
139
+ import os
140
+
141
+ api_key = os.getenv('OPENAI_API_KEY')
142
+ client = OpenAI(
143
+ # This is the default and can be omitted
144
+ api_key= api_key,
145
+ base_url="https://api.rcouyi.com/v1"
146
+ )
147
+
148
+ """## Initalize the Conversation"""
149
+
150
+ def initialize_conversation():
151
+ '''
152
+ Returns a list [{"role": "system", "content": system_message}]
153
+ '''
154
+
155
+ delimiter = "####"
156
+
157
+ example_user_dict = {'Product Design': 'low',
158
+ 'Price': '400',
159
+ 'Air Watts Suction': 'high',
160
+ 'Charging Time': 'low',
161
+ 'Filter': 'low',
162
+ 'Noise Level': 'low',
163
+ 'Weight': 'low',
164
+ 'Dimensions': 'low',
165
+ 'Accessories and Tools': 'low',
166
+ 'Running Time': 'low'}
167
+
168
+ example_user_req = {'Product Design': '_',
169
+ 'Price': '_',
170
+ 'Air Watts Suction': '_',
171
+ 'Charging Time': '_',
172
+ 'Filter': '_',
173
+ 'Noise Level': '_',
174
+ 'Weight': '_',
175
+ 'Dimensions': '_',
176
+ 'Accessories and Tools': '_',
177
+ 'Running Time': '_'}
178
+
179
+ system_message = f"""
180
+ You are a Honeywell vacuum sales expert, keen on making a connection with your customers. Your task is to engage in friendly chit-chat with users
181
+ to understand their lifestyle and analystic of which our Honeywell vacuum can fits into their need. By casually talking about their day-to-day activities,
182
+ preferences, and home environment, you'll gain insights into the perfect vacuum cleaner for their needs:
183
+ {{
184
+ 'Product Design': 'value',
185
+ 'Price': 'number', # Ensure this is a number (integer or float without quotes)
186
+ 'Air Watts Suction': 'value',
187
+ 'Charging Time': 'value',
188
+ 'Filter': 'value'
189
+ 'Noise Level': 'value',
190
+ 'Weight': 'value',
191
+ 'Dimensions': 'value',
192
+ 'Accessories and Tools': 'value',
193
+ 'Running Time': 'value'
194
+ }}
195
+ The value for 'Price' should be a numerical value extracted from the user's response.
196
+ The values for all keys, except 'Price', should be 'low', 'medium', or 'high' based on the importance of the corresponding keys, as stated by user.
197
+ All the values in the example dictionary are only representative values.
198
+
199
+ {delimiter}
200
+ Here are some instructions around the values for the different keys. If you do not follow this, you'll be heavily penalised:
201
+ - The values for all keys, except, should strictly be either 'low', 'medium', or 'high' based on the importance of the corresponding keys, as stated by user.
202
+ - The value for ‘Price’ should be a numerical value extracted from the user's response.
203
+ - ' Price' value needs to be greater than or equal to 379.95. If the user says less than that, please mention that there are no vacuums in that range.
204
+ - Do not randomly assign values to any of the keys.
205
+ - The values need to be inferred from the user's response.
206
+
207
+ {delimiter}
208
+ To fill the dictionary, you need to have the following chain of thoughts:
209
+ Follow the chain-of-thoughts below and only output the final updated python dictionary for the keys as described in {example_user_req}. \n
210
+ {delimiter}
211
+
212
+ Thought 1: Engage the user to quickly understand their primary needs for a vacuum cleaner.
213
+ If the primary purpose or key features of the vacuum are unclear, use brief interactions to clarify their main preferences. Your goal is to populate the values of all keys in the Python dictionary based on the user's statements, focusing on efficiency and relevancy. These keys include:
214
+ - 'Product Design'
215
+ - 'Price'
216
+ - 'Air Watts Suction'
217
+ - 'Charging Time'
218
+ - 'Filter'
219
+ - 'Noise Level'
220
+ - 'Weight'
221
+ - 'Dimensions'
222
+ - 'Accessories and Tools'
223
+ - 'Running Time'
224
+
225
+ During your interaction, swiftly identify the user's primary concern:
226
+ - If the user specifically mentions a need like sticking to a budget, prioritize 'Price' and ask for their budget range.
227
+ - Set all other attributes to 'low' immediately if the user confirms the budget is their only concern, indicating that other features are secondary.
228
+
229
+ For example, if the user states, 'I’m looking for the best vacuum within a $400 budget,' structure the conversation to finalize their needs in just a few exchanges:
230
+ 1. Assistant: Great, focusing on a $300 budget. Are there specific features you need besides being cost-effective?
231
+ 2. User: Not really, I just need something simple and cheap.
232
+
233
+ Based on this, immediately set all keys to 'low' as preferred but not crucial, and confirm:
234
+ Assistant: Got it! I’ll look for something affordable. I'll set your budget as the main priority and other features to basic settings. This way, I can find the best option for you quickly.
235
+
236
+ This approach ensures you gather all necessary information within four interactions, making the process efficient and user-focused, with minimal back-and-forth while covering all essential aspects.
237
+
238
+ {delimiter}
239
+ Thought 2: After identifying key preferences of the user, assume that all keys should be set.
240
+ This approach ensures that the vacuum cleaner configuration is tailored to the user's primary concerns while maintaining simplicity in less critical areas.
241
+ Continue to probe for details on any keys you are still unsure about.
242
+ It is best to frame your questions logically, focusing on user needs rather than directly asking for specific key values.
243
+
244
+ {delimiter}
245
+ Thought 3: Review the updated values for all keys in the Python dictionary to ensure they accurately reflect the user's preferences and requirements.
246
+ If you find any values that you're unsure about, don't hesitate to ask clarifying questions.
247
+ This final check is crucial to ensure that all entries are correct and meet the user's expectations.
248
+
249
+ {delimiter}
250
+ Please follow these thoughts systematically to provide a recommendation that
251
+ best fits the user's needs based on the profile you've developed through your questions.
252
+
253
+
254
+ {delimiter}
255
+ Here is a sample conversation between the user and assistant:
256
+
257
+ User: Hi, I'm looking for a budget-friendly vacuum cleaner that's effective on hardwood floors.
258
+
259
+ Assistant: Fantastic! I'd be thrilled to help you find the perfect vacuum. Could you share your budget and how you plan to use it?
260
+
261
+ User: My budget is up to $400, and I need something that can handle pet hair and dirt on hardwood floors effectively.
262
+
263
+ Assistant: Got it! With pet hair, strong suction is a must. Keep other features basic to stay within your budget. Sound good?
264
+
265
+ User: Yes, that sounds perfect.
266
+
267
+ Assistant: {example_user_dict}
268
+ {delimiter}
269
+
270
+ Start with a short welcome message mention 'Honeywell vacuum Store' and encourage the user to share their preferences.
271
+ """
272
+ conversation = [{"role": "system", "content": system_message}]
273
+ # conversation = system_message
274
+ return conversation
275
+
276
+
277
+ # print(debug_conversation[0]['content'])
278
+
279
+ def iterate_llm_response(funct, debug_response, num = 5):
280
+ """
281
+ Calls a specified function repeatedly and prints the results.
282
+ This function is designed to test the consistency of a response from a given function.
283
+ It calls the function multiple times (default is 10) and prints out the iteration count,
284
+ the function's response(s).
285
+ Args:
286
+ funct (function): The function to be tested. This function should accept a single argument
287
+ and return the response value(s).
288
+ debug_response (dict): The input argument to be passed to 'funct' on each call.
289
+ num (int, optional): The number of times 'funct' will be called. Defaults to 10.
290
+ Returns:
291
+ This function only returns the results to the console.
292
+ """
293
+ i = 0 # Initialize counter
294
+
295
+ while i < num: # Loop to call the function 'num' times
296
+
297
+ response = funct(debug_response) # Call the function with the debug response
298
+
299
+ # Print the iteration number, result, and reason from the response
300
+ print("Iteration: {0}".format(i))
301
+ print(response)
302
+ print('-' * 50) # Print a separator line for readability
303
+ i += 1 # Increment the counter
304
+
305
+ # Example usage: test the consistency of responses from 'intent_confirmation_layer'
306
+ # iterate_llm_response(get_chat_completions, messages)
307
+
308
+ debug_user_input = "Hi,I need a best budget of vacuum under $400"
309
+
310
+
311
+ """## Get Chat completion"""
312
+
313
+ # Define a Chat Completions API call
314
+ # Retry up to 6 times with exponential backoff, starting at 1 second and maxing out at 20 seconds delay
315
+ @retry(wait=wait_random_exponential(min=1, max=20), stop=stop_after_attempt(6))
316
+
317
+ def get_chat_completions(input, json_format = False):
318
+ MODEL = 'gpt-3.5-turbo'
319
+
320
+ system_message_json_output = """<<. Return output in JSON format to the key output.>>"""
321
+
322
+ # If the output is required to be in JSON format
323
+ if json_format == True:
324
+
325
+ # Append the input prompt to include JSON response as specified by OpenAI
326
+ input[0]['content'] += system_message_json_output
327
+
328
+ # JSON return type specified
329
+ chat_completion_json = client.chat.completions.create(
330
+ model = MODEL,
331
+ messages = input,
332
+ response_format = { "type": "json_object"},
333
+ seed = 42)
334
+
335
+ output = json.loads(chat_completion_json.choices[0].message.content)
336
+
337
+ # No JSON return type specified
338
+ else:
339
+ chat_completion = client.chat.completions.create(
340
+ model = MODEL,
341
+ messages = input,
342
+ seed = 42)
343
+
344
+ output = chat_completion.choices[0].message.content
345
+
346
+
347
+ return output
348
+
349
+
350
+ """## moderation checking"""
351
+
352
+ # Define a function called moderation_check that takes user_input as a parameter.
353
+
354
+ def moderation_check(user_input):
355
+
356
+ MODEL = 'text-moderation-latest'
357
+ # Call the OpenAI API to perform moderation on the user's input.
358
+ response = client.moderations.create(
359
+ input=user_input,
360
+ model=MODEL
361
+ )
362
+
363
+ # Extract the moderation result from the API response.
364
+ moderation_output = response.results[0].flagged
365
+ # Check if the input was flagged by the moderation system.
366
+ if response.results[0].flagged == True:
367
+ # If flagged, return "Flagged"
368
+ return "Flagged"
369
+ else:
370
+ # If not flagged, return "Not Flagged"
371
+ return "Not Flagged"
372
+
373
+ """## Confirm intent"""
374
+
375
+ def intent_confirmation_layer(response_assistant):
376
+
377
+ delimiter = "####"
378
+
379
+ allowed_values = {'low','medium','high'}
380
+
381
+
382
+ prompt = f"""
383
+ You are a senior evaluator with an eye for detail. You will receive input text that contains user requirements for a vacuum cleaner, captured through various keys. Evaluate if the input text includes values for the following keys:
384
+ {{
385
+ 'Product Design': 'value',
386
+ 'Price': 'number', # Ensure this is a number (integer or float without quotes)
387
+ 'Filter': 'value',
388
+ 'Air Watts Suction': 'value',
389
+ 'Charging Time': 'value',
390
+ 'Noise Level': 'value',
391
+ 'Weight': 'value',
392
+ 'Dimensions': 'value',
393
+ 'Accessories and Tools': 'value',
394
+ 'Running Time': 'value'
395
+ }}
396
+
397
+ The 'Price' key should only contain a number. For all other keys, the values must come from the set of allowed values: {allowed_values}.
398
+
399
+ Next you need to evaluate if the keys have the the values filled correctly.
400
+ Only output a one-word string in JSON format at the key 'result' - Yes/No.
401
+ Thought 1 - Output a string 'Yes' if the values are correctly filled for all keys, otherwise output 'No'.
402
+ Thought 2 - If the answer is No, mention the reason in the key 'reason'.
403
+ THought 3 - Think carefully before the answering.
404
  """
 
405
 
406
 
407
+ messages=[{"role": "system", "content":prompt },
408
+ {"role": "user", "content":f"""Here is the input: {response_assistant}""" }]
409
+
410
+ response = client.chat.completions.create(
411
+ model="gpt-3.5-turbo",
412
+ messages = messages,
413
+ response_format={ "type": "json_object" },
414
+ seed = 1234
415
+ # n = 5
416
+ )
417
 
418
+ json_output = json.loads(response.choices[0].message.content)
 
 
 
 
419
 
420
+ return json_output
421
+
422
+ # Example 3 - Let's check confirmation_layer if all the keys are present
423
+ debug_response_assistant = f"""
424
+ Great, thank you for clarifying your requirements.
425
+ Based on your inputs, here is the final profile for the vacuum you are looking for:
426
+
427
+ {{'Product Design': 'low',
428
+ 'Price': 400,
429
+ 'Filter': 'low',
430
+ 'Air Watts Suction': 'low',
431
+ 'Charging Time': 'low',
432
+ 'Noise Level': 'low',
433
+ 'Weight': 'low',
434
+ 'Dimensions': 'low',
435
+ 'Accessories and Tools': 'low',
436
+ 'Running Time': 'low'}}
437
+ """
438
+ #Note that you are using double curly braces
439
 
440
+ print(debug_response_assistant)
441
 
442
+ # debug_confirmation = intent_confirmation_layer(debug_response_assistant)
443
+ # print("Result:",debug_confirmation.get('result'),"\t", "Reason:", debug_confirmation.get('reason'), "\t", "response:", debug_confirmation.get('response'))
 
 
 
 
 
 
444
 
445
+ """## Dictionary_preset"""
 
446
 
447
+ def dictionary_present(response):
448
+ delimiter = "####"
449
+
450
+ user_req = {
451
+ 'Product Design': 'low/medium/high',
452
+ 'Price': 'numerical value',
453
+ 'Filter': 'low/medium/high',
454
+ 'Air Watts Suction': 'low/medium/high',
455
+ 'Charging Time': 'low/medium/high',
456
+ 'Noise Level': 'low/medium/high',
457
+ 'Weight': 'low/medium/high',
458
+ 'Dimensions': 'low/medium/high',
459
+ 'Accessories and Tools': 'low/medium/high',
460
+ 'Running Time': 'low/medium/high',
461
+ }
462
+
463
+ prompt = f"""
464
+ You are a Python expert. You are provided an input.
465
+ You have to check if there is a Python dictionary present in the string.
466
+ It will have the following format {user_req}.
467
+ Your task is to extract the relevant values from the input and return only the Python dictionary in JSON format.
468
+ The output should match the format as {user_req}.
469
+
470
+ {delimiter}
471
+ Make sure that the value of the budget is also present in the user input.
472
+ The output should contain the exact keys and values as present in the input.
473
+ Ensure the keys and values are in the given format:
474
+ {{
475
+ 'Product Design': 'low/medium/high',
476
+ 'Price': 'numerical value',
477
+ 'Filter': 'low/medium/high',
478
+ 'Air Watts Suction': 'low/medium/high',
479
+ 'Charging Time': 'low/medium/high',
480
+ 'Noise Level': 'low/medium/high',
481
+ 'Weight': 'low/medium/high',
482
+ 'Dimensions': 'low/medium/high',
483
+ 'Accessories and Tools': 'low/medium/high',
484
+ 'Running Time': 'low/medium/high'
485
+ }}
486
+
487
+ Here are some sample input-output pairs for better understanding:
488
+ {delimiter}
489
+
490
+ input 1: - Product Design: high - Price: 100 - Filter: high - Air Watts Suction: high - Charging Time: low - Noise Level: medium - Weight: low - Dimensions: medium - Detachable Handheld Vacuum: yes - Accessories and Tools: low - Running Time: medium
491
+ output 1: {{'Product Design': 'high', 'Price': 100, 'Filter': 'high', 'Air Watts Suction': 'high', 'Charging Time': 'low', 'Noise Level': 'medium', 'Weight': 'low', 'Dimensions': 'medium', 'Accessories and Tools': 'low', 'Running Time': 'medium'}}
492
+
493
+ input 2: {{'Product Design': 'low', 'Price': '1,000', 'Filter': 'medium', 'Air Watts Suction': 'medium', 'Charging Time': 'medium', 'Noise Level': 'high', 'Weight': 'medium', 'Dimensions': 'low', 'Accessories and Tools': 'medium', 'Running Time': 'low'}}
494
+ output 2: {{'Product Design': 'low', 'Price': 1000, 'Filter': 'medium', 'Air Watts Suction': 'medium', 'Charging Time': 'medium', 'Noise Level': 'high', 'Weight': 'medium', 'Dimensions': 'low', 'Accessories and Tools': 'medium', 'Running Time': 'low'}}
495
+
496
+ input 3: Here is your user profile 'Product Design': 'medium','Price': '600','Filter': 'medium','Air Watts Suction': 'medium','Charging Time': 'medium','Noise Level': 'low','Weight': 'medium','Dimensions': 'medium','Accessories and Tools': 'high','Running Time': 'medium'
497
+ output 3: {{'Product Design': 'medium','Price': 600,'Filter': 'medium','Air Watts Suction': 'medium','Charging Time': 'medium','Noise Level': 'low','Weight': 'medium','Dimensions': 'medium','Accessories and Tools': 'high','Running Time': 'medium'}}
498
+ {delimiter}
499
+ """
500
+
501
+ messages = [
502
+ {"role": "system", "content": prompt},
503
+ {"role": "user", "content": f"Here is the user input: {response}"}
504
+ ]
505
+
506
+ confirmation = get_chat_completions(messages, json_format=True)
507
+
508
+ return confirmation
509
+
510
+ debug_response_assistant_n_1 = """
511
+ {'Product Design': 'high',
512
+ 'Price': '500',
513
+ 'Filter': 'high',
514
+ 'Air Watts Suction': 'medium',
515
+ 'Charging Time': 'low',
516
+ 'Noise Level': 'high',
517
+ 'Weight': 'low',
518
+ 'Dimensions': 'high',
519
+ 'Accessories and Tools': 'high',
520
+ 'Running Time': 'medium'}
521
  """
522
+
523
+ debug_response_assistant_n_2 = f"""Thank you for providing your budget.
524
+ Based on your budget of 600 , I will consider this while recommending suitable vacuum options for you.
525
+ Here is the final recommendation for your vacuum:
526
+ - Product Design: medium
527
+ - Price: '600'
528
+ - Filter: medium
529
+ - Air Watts Suction': medium
530
+ - Charging Time': medium
531
+ - Noise Level: low
532
+ - Weight: medium
533
+ - Dimensions: medium
534
+ - Accessories and Tools: high
535
+ - Running Time: medium
536
+
537
+ Please note that these specifications are based on your requirements for surfing and a decent suction within your budget.
538
+ Let me know if there's anything else I can assist you with!"""
539
+
540
+ # response_dict_n = dictionary_present(debug_response_assistant_n_1)
541
+ # display(response_dict_n)
542
+
543
+ import json
544
+ import pandas as pd
545
+
546
+ def product_map_layer(row):
547
+ delimiter = "#####"
548
+
549
+ # Convert the row (Series) to a dictionary
550
+ row_dict = row.to_dict()
551
+
552
+ # Create the prompt
553
+ prompt = f"""
554
+ You are a Vacuum Specifications Classifier whose job is to extract the key features of vacuums and classify them according to their specifications.
555
+ The following is a dictionary representing a vacuum model:
556
+
557
+ {row_dict}
558
+
559
+ Follow these steps:
560
+ 1. Classify the features based on the rules below.
561
+ 2. Output the classification as a dictionary representing one row.
562
+
563
+ {delimiter}
564
+ Model Number:
565
+ - simply extract the value
566
+
567
+ Product Design:
568
+ - low: <<< if the product has an old design >>>
569
+ - medium: <<< if the product features an 'Off-the-shelf' design >>>
570
+ - high: <<< if the design boasts an innovative, premium design >>>
571
+
572
+ Power:
573
+ - low: <<< if the power is below 500 Watts >>>
574
+ - medium: <<< if the power is between 500 and 600 Watts >>>
575
+ - high: <<< if the power is above 600 Watts >>>
576
+
577
+ Filter:
578
+ - low: <<< if the filter is a basic or missing altogether >>>
579
+ - medium: <<< if the filter is of standard quality >>>
580
+ - high: <<< if the filter is a premium, high-efficiency model >>>
581
+
582
+ Air Watts Suction:
583
+ - low: <<< if the suction power is below 126 Air Watts >>>
584
+ - medium: <<< if the suction power is between 126 and 185 Air Watts >>>
585
+ - high: <<< if the suction power is above 185 Air Watts >>>
586
+
587
+ Charging Time:
588
+ - low: <<< if the charging time is above 6 hours >>>
589
+ - medium: <<< if the charging time is between 3 and 6 hours >>>
590
+ - high: <<< if the charging time is below 3 hours >>>
591
+
592
+ Noise Level:
593
+ - low: <<< if the noise level is above 80 dB >>>
594
+ - medium: <<< if the noise level is between 60 and 80 dB >>>
595
+ - high: <<< if the noise level is below 60 dB >>>
596
+
597
+ Weight:
598
+ - low: <<< if the weight is above 2.95 kg >>>
599
+ - medium: <<< if the weight is between 2.71 and 2.95 kg >>>
600
+ - high: <<< if the weight is below 2.71 kg >>>
601
+
602
+ Dimensions:
603
+ - low: <<< if the dimensions are large, taking up significant space >>>
604
+ - medium: <<< if the dimensions are average >>>
605
+ - high: <<< if the dimensions are compact and space-saving >>>
606
+
607
+ Accessories and Tools:
608
+ - low: <<< if there are few or basic accessories/tools >>>
609
+ - medium: <<< if there is a moderate number of accessories/tools >>>
610
+ - high: <<< if there is a wide range of accessories/tools included >>>
611
+
612
+ Running Time:
613
+ - low: <<< if the running time is below 60 minutes >>>
614
+ - medium: <<< if the running time is between 60 and 89 minutes >>>
615
+ - high: <<< if the running time is above 89 minutes >>>
616
+
617
+ {delimiter}
618
+
619
+ ### The output should be a dictionary representing the classification for one row. ###
620
+ """
621
+
622
+ input_text = "Please classify the vacuum model using the rules provided above."
623
+
624
+ # Create the messages for the completion
625
+ messages = [{"role": "system", "content": prompt}, {"role": "user", "content": input_text}]
626
+
627
+ # Assuming get_chat_completions() is a function you have to handle the completion request
628
+ response = get_chat_completions(messages, json_format=True)
629
+
630
+ return response
631
+
632
+
633
+ # iterate_llm_response(product_map_layer, df.iloc[0])
634
+
635
+ # display(response_dict_n)
636
+
637
+ import pandas as pd # Importing the pandas library for data manipulation
638
+ import json
639
+
640
+ def compare_with_user(response_dict_n):
641
+
642
+
643
+ user_requirements = response_dict_n
644
+
645
+ # Extracting user requirements from the input string (assuming it's a dictionary)
646
+ # Since the function parameter already seems to be a string, we'll use it directly instead of extracting from a dictionary
647
+
648
+ # Extracting the budget value from user_requirements and converting it to an float
649
+ price_value = user_requirements.get('Price', '0')
650
+
651
+ # Check the type of price_value and handle accordingly
652
+ if isinstance(price_value, int):
653
+ price = price_value # Use the integer directly
654
+ elif isinstance(price_value, str):
655
+ # It's a string, so clean it and convert it to an integer
656
+ price = int(price_value.replace(',', '').split()[0])
657
+ else:
658
+ # If it's neither an int nor a string (unexpected), set a default or handle the error
659
+ price = 0 # Default value or raise an exception
660
+
661
+ # Creating a copy of the DataFrame and filtering laptops based on the budget
662
+ filtered_df = df.copy()
663
+ # filtered_df['Price'] = filtered_df['Price'].str.replace(',', '').astype(int)
664
+ filtered_df = filtered_df[filtered_df['Price'] <= price].copy()
665
+
666
+ # # # Mapping string values 'low', 'medium', 'high' to numerical scores 0, 1, 2
667
+ mappings = {'low': 0, 'medium': 1, 'high': 2}
668
+
669
+ # # # Creating a new column 'Score' in the filtered DataFrame and initializing it to 0
670
+ filtered_df['Score'] = 0
671
+
672
+ # # # Iterating over each item in the filtered DataFrame to calculate scores based on user requirements
673
+ for index, row in filtered_df.iterrows():
674
+ user_product_match_str = row
675
+ item_values = user_product_match_str
676
+ item_values = product_map_layer(user_product_match_str)
677
+ score = 0
678
+
679
+ # # Comparing user requirements with laptop features and updating scores
680
+ for key, user_value in user_requirements.items():
681
+ # if key.lower() == 'budget':
682
+ if key == 'Price':
683
+ continue # Skipping budget comparison
684
+ item_value = item_values.get(key, None)
685
+ # print(key, item_value)
686
+ item_mapping = mappings.get(item_value, -1)
687
+ user_mapping = mappings.get(user_value, -1)
688
+ if item_mapping >= user_mapping:
689
+ score += 1 # Incrementing score if laptop value meets or exceeds user value
690
+
691
+ filtered_df.loc[index, 'Score'] = score # Updating the 'Score' column in the DataFrame
692
+
693
+ # Sorting laptops by score in descending order and selecting the top 3 products
694
+ # top_laptops = filtered_df.drop('laptop_feature', axis=1)
695
+ # top_laptops = top_laptops.sort_values('Score', ascending=False)
696
+ choices_json = filtered_df.to_json(orient='records') # Converting the top laptops DataFrame to JSON format
697
+
698
+ # top_laptops
699
+ return choices_json
700
+
701
+ # compare = compare_with_user(response_dict_n)
702
+
703
+ # display(compare)
704
+
705
+ # df2 = pd.read_json(compare, orient='records')
706
+ # df2
707
+
708
+ def recommendation_validation(compare_recommendation):
709
+ data = json.loads(compare_recommendation)
710
+ data1 = []
711
+ for i in range(len(data)):
712
+ if data[i]['Score'] > 2:
713
+ data1.append(data[i])
714
+
715
+ return data1
716
+
717
+ """## Finalize the chat"""
718
+
719
+ def initialize_conv_reco(products):
720
+
721
+ system_message = f"""
722
+ As an expert on intelligent vacuum gadgets, your task is to provide concise, informative responses to user inquiries about products from the catalogue. Keep the user’s specific needs in mind while crafting your answers.
723
+
724
+ Start each response with a brief summary of the vacuum in the following format:
725
+ <vacuum Name> : <Description>, <Price in USD>, <URL>
726
+
727
+ Ensure the description is tailored to highlight how the vacuum meets the user's needs, using a tone that enhances the recommendation’s relevance. For example, if a user is looking for a budget-friendly option for hardwood floors, your summary might look like this:
728
+
729
+ HoneyWell VC10 Vacuum: Ideal for hardwood floors with efficient suction and easy maneuverability, priced at $399. For more details or to purchase, visit: [https://honeywellvac.com/products/vc10-aeromax-elite](https://honeywellvac.com/products/vc10-aeromax-elite).
730
+
731
+ This format provides a quick overview and positions the vacuum as a solution to the user's requirements, making the recommendation both informative and directly useful. Include the URL at the end of each summary to enable users to find more information or to make a purchase directly.
732
  """
733
+ user_message = f""" These are the user's products: {products}"""
734
+ conversation = [{"role": "system", "content": system_message },
735
+ {"role":"user","content":user_message}]
736
+ # conversation_final = conversation[0]['content']
737
+
738
+ return conversation
739
+
740
+ def dialogue_mgmt_system():
741
+ """
742
+ Manages a conversational system between a user and an assistant to recommend vacuum.
743
+
744
+ This function initializes the conversation, retrieves the introduction, handles user input,
745
+ performs moderation checks, and manages the recommendation process based on user interactions.
746
+
747
+ Returns:
748
+ None
749
+ """
750
+
751
+ conversation = initialize_conversation()
752
+
753
+ introduction = get_chat_completions(conversation)
754
+
755
+ print(f"Assistant: {introduction}" + '\n')
756
+
757
+ recommend_vacuum = None
758
+
759
+ user_input = ''
760
+
761
+ while(user_input != "exit"):
762
+
763
+ user_input = input("")
764
+
765
+ moderation = moderation_check(user_input)
766
+ if moderation == 'Flagged':
767
+ break
768
+
769
+ if recommend_vacuum is None:
770
+
771
+ conversation.append({"role": "user", "content": user_input})
772
+
773
+ response_assistant = get_chat_completions(conversation)
774
+ moderation = moderation_check(response_assistant)
775
+ if moderation == 'Flagged':
776
+ break
777
+
778
+
779
+ confirmation = intent_confirmation_layer(response_assistant)
780
+
781
+ print(f"Intent Confirmation Yes/No: {confirmation.get('result')}", f"Reason: {confirmation.get('reason')}")
782
+
783
+ if "No" in confirmation.get('result'):
784
+ conversation.append({"role": "assistant", "content": str(response_assistant)})
785
+ print(f"Assistant: {response_assistant}" + "\n")
786
+ print(f"conversation: {conversation}")
787
+
788
+ else:
789
+ print(f"Assistant: {response_assistant}" + "\n")
790
+ print('\n' + "Variables extracted!" + '\n')
791
+
792
+ response = dictionary_present(response_assistant)
793
+
794
+ print("Thank you for providing all the information. Kindly wait, while I fetch the products: \n")
795
+ recommend_vacuum = compare_with_user(response)
796
+
797
+ print("Recommend vacuums are", recommend_vacuum)
798
+
799
+ validated_reco = recommendation_validation(recommend_vacuum)
800
+
801
+ conversation_reco = initialize_conv_reco(validated_reco)
802
+
803
+ print("initial_reco", conversation_reco)
804
+
805
+ conversation_reco.append({"role": "user", "content": "This is my user profile" + str(response)})
806
+
807
+ recommendation = get_chat_completions(conversation_reco)
808
+
809
+ moderation = moderation_check(recommendation)
810
+ if moderation == 'Flagged':
811
+ break
812
+
813
+ conversation_reco.append({"role": "assistant", "content": str(recommendation)})
814
+
815
+ print(f"Assistant: {recommendation}" + '\n')
816
+ break
817
+
818
+ else:
819
+ conversation_reco.append({"role": "user", "content": user_input})
820
+
821
+ response_asst_reco = get_chat_completions(conversation_reco)
822
+
823
+ moderation = moderation_check(response_asst_reco)
824
+ if moderation == 'Flagged':
825
+ print("Sorry, this message has been flagged. Please restart your conversation.")
826
+ break
827
+
828
+ print(f"Assistant:{response_asst_reco}" + '\n')
829
+ conversation.append({"role": "assistant", "content": response_asst_reco})
830
+ break
831
+
832
+ # dialogue_mgmt_system()
833
+
834
+ """## Gradio"""
835
+
836
+ # @title
837
+ import gradio as gr
838
+ import time
839
+
840
+ def welcome_msg():
841
+
842
+ conversation = initialize_conversation()
843
+ introduction = get_chat_completions(conversation)
844
+ return [(None, introduction)]
845
+ # return [(None, "Hello! How can I assist you today?")]
846
+
847
+ def gradio_chatbot(msg, history, recommend_vacuum):
848
+ # print("Function called with message:", msg)
849
+ print("before history")
850
+ # history = []
851
+
852
+ history_openai_format = []
853
+ for human, assistant in history:
854
+ if human is not None:
855
+ history_openai_format.append({"role": "user", "content": human})
856
+ history_openai_format.append({"role": "assistant", "content": assistant})
857
+
858
+ history_openai_format.append({"role": "user", "content": msg})
859
+
860
+ if recommend_vacuum is False:
861
+ response_assistant = get_chat_completions(history_openai_format)
862
+ confirmation = intent_confirmation_layer(response_assistant)
863
+
864
+ if "No" in confirmation.get('result'):
865
+ # history.append({"role": "assistant", "content": str(response_assistant)})
866
+ history.append((msg, response_assistant))
867
+ return "", history, False
868
+ else:
869
+ response = dictionary_present(response_assistant)
870
+ recommend_vacuum = compare_with_user(response)
871
+ validated_reco = recommendation_validation(recommend_vacuum)
872
+ conversation_reco = [{"role": "assistant", "content": "This is my user profile " + str(response)}]
873
+ recommendation = get_chat_completions(conversation_reco)
874
+ history.append(msg, recommendation)
875
+ return "", history, True
876
+ else:
877
+ history_openai_format.append({"role": "user", "content": msg })
878
+ response_asst_reco = get_chat_completions(history_openai_format)
879
+ history.append(msg, response_asst_reco)
880
+ return "", history, True
881
+
882
+ bot_img = 'https://cdn-icons-png.freepik.com/512/4712/4712035.png'
883
+ user_img = 'https://cdn3.iconfinder.com/data/icons/people-and-avatar-2/48/22-nerd_bot-1024.png'
884
+
885
+ def clear():
886
+ # Clear only the message input field
887
+ return ""
888
+
889
+ with gr.Blocks() as demo:
890
+
891
+ recommend_vacuum = gr.State(value = False)
892
+
893
+
894
+ with gr.Row():
895
+ chatbot = gr.Chatbot(value = welcome_msg(),
896
+ show_label=False,
897
+ avatar_images=(user_img, bot_img)
898
+ )
899
+ with gr.Row():
900
+ msg = gr.Textbox(label="Type a message...", placeholder="Type a message...", show_label=False)
901
+ with gr.Row():
902
+ restart = gr.ClearButton([msg, chatbot, recommend_vacuum],value = "Restart")
903
+ clear_button = gr.Button("Clear")
904
+ submit_button = gr.Button("Submit", variant='primary')
905
+
906
+ msg.submit(
907
+ gradio_chatbot,
908
+ inputs=[msg, chatbot, recommend_vacuum],
909
+ outputs=[msg, chatbot, recommend_vacuum]
910
+ )
911
+
912
+ submit_button.click(
913
+ gradio_chatbot,
914
+ inputs=[msg, chatbot, recommend_vacuum],
915
+ outputs=[msg, chatbot, recommend_vacuum]
916
+ )
917
+
918
+ clear_button.click(
919
+ clear,
920
+ inputs=[],
921
+ outputs=[msg]
922
+ )
923
 
924
+ demo.launch(share=True)
925