Spaces:
Sleeping
Sleeping
Richard Zhang
commited on
Commit
·
0e8b82d
1
Parent(s):
35bf4aa
Your commit message
Browse files
app.py
CHANGED
@@ -1,64 +1,122 @@
|
|
1 |
import gradio as gr
|
2 |
-
from
|
|
|
|
|
|
|
3 |
|
4 |
-
|
5 |
-
|
6 |
-
""
|
7 |
-
client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
|
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 |
-
demo = gr.ChatInterface(
|
47 |
-
respond,
|
48 |
-
additional_inputs=[
|
49 |
-
gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
|
50 |
-
gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
|
51 |
-
gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
|
52 |
-
gr.Slider(
|
53 |
-
minimum=0.1,
|
54 |
-
maximum=1.0,
|
55 |
-
value=0.95,
|
56 |
-
step=0.05,
|
57 |
-
label="Top-p (nucleus sampling)",
|
58 |
-
),
|
59 |
-
],
|
60 |
-
)
|
61 |
|
|
|
|
|
|
|
|
|
62 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
if __name__ == "__main__":
|
64 |
-
|
|
|
1 |
import gradio as gr
|
2 |
+
from datetime import datetime
|
3 |
+
import json
|
4 |
+
import difflib # For better product name matching
|
5 |
+
from utils import get_product_by_name, get_products_by_category, get_products_and_category
|
6 |
|
7 |
+
# Dummy moderation function (replace with actual API)
|
8 |
+
def openai_moderation_check(text):
|
9 |
+
return {"flagged": False} # Assume no flagging for now
|
|
|
10 |
|
11 |
+
# Dummy AI response function (replace with actual API call to generate responses)
|
12 |
+
def get_completion_from_messages(messages):
|
13 |
+
return "This is a placeholder response from the model." # Mock response for now
|
14 |
|
15 |
+
# Function to log conversation to a JSON file
|
16 |
+
def log_conversation(user_input, ai_response, metadata=None, history=None):
|
17 |
+
log_entry = {
|
18 |
+
"timestamp": str(datetime.now()),
|
19 |
+
"user_input": user_input,
|
20 |
+
"ai_response": ai_response,
|
21 |
+
"metadata": metadata,
|
22 |
+
"history": history
|
23 |
+
}
|
24 |
+
with open("conversation_log.json", "a") as log_file:
|
25 |
+
log_file.write(json.dumps(log_entry) + "\n")
|
26 |
|
27 |
+
# Function to handle user queries using utils.py functions
|
28 |
+
def handle_user_query(user_input, all_messages=[], debug=False):
|
29 |
+
# Step 1: Moderation check on user input
|
30 |
+
moderation_result = openai_moderation_check(user_input)
|
31 |
+
if moderation_result["flagged"]:
|
32 |
+
return "Sorry, your request is non-compliant.", all_messages
|
33 |
+
|
34 |
+
# Step 2: Extract products and categories from user input
|
35 |
+
products_and_category = get_products_and_category()
|
36 |
+
|
37 |
+
# Debugging: Print the structure of products_and_category
|
38 |
+
if debug:
|
39 |
+
print("Products and Categories Structure:", products_and_category)
|
40 |
+
|
41 |
+
product_name = None
|
42 |
+
category_name = None
|
43 |
|
44 |
+
# Flatten the product list to check for partial matches
|
45 |
+
all_products = []
|
46 |
+
for category, products in products_and_category.items():
|
47 |
+
all_products.extend(products)
|
48 |
|
49 |
+
# Use difflib to find the closest match to the user input
|
50 |
+
product_matches = difflib.get_close_matches(user_input, all_products, n=1, cutoff=0.4)
|
51 |
+
if product_matches:
|
52 |
+
product_name = product_matches[0]
|
53 |
+
|
54 |
+
# Check for category match if no product match is found
|
55 |
+
if not product_name:
|
56 |
+
category_matches = difflib.get_close_matches(user_input, products_and_category.keys(), n=1, cutoff=0.4)
|
57 |
+
if category_matches:
|
58 |
+
category_name = category_matches[0]
|
59 |
|
60 |
+
# Step 3: Generate a response
|
61 |
+
if product_name:
|
62 |
+
product_info = get_product_by_name(product_name)
|
63 |
+
if product_info:
|
64 |
+
response = f"Product: {product_info['name']}\n" \
|
65 |
+
f"Category: {product_info['category']}\n" \
|
66 |
+
f"Price: ${product_info['price']}\n" \
|
67 |
+
f"Rating: {product_info['rating']} stars\n" \
|
68 |
+
f"Features: {', '.join(product_info['features'])}\n" \
|
69 |
+
f"Description: {product_info['description']}"
|
70 |
+
return response, all_messages
|
71 |
+
else:
|
72 |
+
return "Sorry, I couldn't find the product you're asking about.", all_messages
|
73 |
+
|
74 |
+
elif category_name:
|
75 |
+
products_in_category = get_products_by_category(category_name)
|
76 |
+
if products_in_category:
|
77 |
+
response = f"Category: {category_name}\n"
|
78 |
+
for product in products_in_category:
|
79 |
+
response += f"Product: {product['name']}\nPrice: ${product['price']}\n\n"
|
80 |
+
return response.strip(), all_messages
|
81 |
+
else:
|
82 |
+
return "Sorry, I couldn't find products in that category.", all_messages
|
83 |
+
|
84 |
+
else:
|
85 |
+
return "Please provide the name of a product or category you'd like to know about.", all_messages
|
86 |
|
87 |
+
# Chatbot logic to handle conversation
|
88 |
+
def handle_chat(user_input, history):
|
89 |
+
response, updated_history = handle_user_query(user_input, history)
|
90 |
+
history.append((user_input, response)) # Append the latest user input and response to the history
|
91 |
+
log_conversation(user_input, response) # Log the interaction
|
92 |
+
return response, history
|
93 |
|
94 |
+
# Gradio chatbot UI setup
|
95 |
+
def chatbot_ui():
|
96 |
+
with gr.Blocks() as app:
|
97 |
+
gr.Markdown("# Store Assistant Chatbot")
|
98 |
+
chatbot = gr.Chatbot(label="Chat with Store Assistant")
|
99 |
+
message_input = gr.Textbox(label="Ask about products!")
|
100 |
+
clear_btn = gr.Button("Clear Chat")
|
101 |
|
102 |
+
# Initialize conversation history as a stateful variable
|
103 |
+
conversation_history = gr.State([])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
|
105 |
+
# Process user input and update the conversation
|
106 |
+
def on_user_message(user_message, history):
|
107 |
+
response, updated_history = handle_chat(user_message, history)
|
108 |
+
return "", updated_history # Removed the extra append
|
109 |
|
110 |
+
# Clear chat history
|
111 |
+
def clear_chat():
|
112 |
+
return [], []
|
113 |
+
|
114 |
+
# Link input to chatbot
|
115 |
+
message_input.submit(on_user_message, inputs=[message_input, conversation_history], outputs=[message_input, chatbot])
|
116 |
+
clear_btn.click(clear_chat, inputs=[], outputs=[chatbot, conversation_history])
|
117 |
+
|
118 |
+
app.launch()
|
119 |
+
|
120 |
+
# Run the chatbot interface
|
121 |
if __name__ == "__main__":
|
122 |
+
chatbot_ui()
|
utils.py
ADDED
@@ -0,0 +1,815 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
|
2 |
+
import json
|
3 |
+
from collections import defaultdict
|
4 |
+
# Configure OpenAI KEY
|
5 |
+
import os
|
6 |
+
|
7 |
+
from dotenv import load_dotenv
|
8 |
+
from openai import OpenAI
|
9 |
+
|
10 |
+
|
11 |
+
# Load environment variables from .env file
|
12 |
+
load_dotenv()
|
13 |
+
|
14 |
+
|
15 |
+
api_key = os.getenv("OPENAI_API_KEY") # 'ollama'
|
16 |
+
model = "gpt-4o-mini" # "gpt-4o-mini"
|
17 |
+
base_url = None
|
18 |
+
|
19 |
+
|
20 |
+
products_file = 'products.json'
|
21 |
+
categories_file = 'categories.json'
|
22 |
+
|
23 |
+
|
24 |
+
delimiter = "####"
|
25 |
+
|
26 |
+
step_2_system_message_content = f"""
|
27 |
+
You will be provided with customer service a conversation. \
|
28 |
+
The most recent user query will be delimited with \
|
29 |
+
{delimiter} characters.
|
30 |
+
Output a python list of objects, where each object has \
|
31 |
+
the following format:
|
32 |
+
'category': <one of Computers and Laptops, \
|
33 |
+
Smartphones and Accessories, \
|
34 |
+
Televisions and Home Theater Systems, \
|
35 |
+
Gaming Consoles and Accessories,
|
36 |
+
Audio Equipment, Cameras and Camcorders>,
|
37 |
+
OR
|
38 |
+
'products': <a list of products that must \
|
39 |
+
be found in the allowed products below>
|
40 |
+
|
41 |
+
Where the categories and products must be found in \
|
42 |
+
the customer service query.
|
43 |
+
If a product is mentioned, it must be associated with \
|
44 |
+
the correct category in the allowed products list below.
|
45 |
+
If no products or categories are found, output an \
|
46 |
+
empty list.
|
47 |
+
Only list products and categories that have not already \
|
48 |
+
been mentioned and discussed in the earlier parts of \
|
49 |
+
the conversation.
|
50 |
+
|
51 |
+
Allowed products:
|
52 |
+
|
53 |
+
Computers and Laptops category:
|
54 |
+
TechPro Ultrabook
|
55 |
+
BlueWave Gaming Laptop
|
56 |
+
PowerLite Convertible
|
57 |
+
TechPro Desktop
|
58 |
+
BlueWave Chromebook
|
59 |
+
|
60 |
+
Smartphones and Accessories category:
|
61 |
+
SmartX ProPhone
|
62 |
+
MobiTech PowerCase
|
63 |
+
SmartX MiniPhone
|
64 |
+
MobiTech Wireless Charger
|
65 |
+
SmartX EarBuds
|
66 |
+
|
67 |
+
Televisions and Home Theater Systems category:
|
68 |
+
CineView 4K TV
|
69 |
+
SoundMax Home Theater
|
70 |
+
CineView 8K TV
|
71 |
+
SoundMax Soundbar
|
72 |
+
CineView OLED TV
|
73 |
+
|
74 |
+
Gaming Consoles and Accessories category:
|
75 |
+
GameSphere X
|
76 |
+
ProGamer Controller
|
77 |
+
GameSphere Y
|
78 |
+
ProGamer Racing Wheel
|
79 |
+
GameSphere VR Headset
|
80 |
+
|
81 |
+
Audio Equipment category:
|
82 |
+
AudioPhonic Noise-Canceling Headphones
|
83 |
+
WaveSound Bluetooth Speaker
|
84 |
+
AudioPhonic True Wireless Earbuds
|
85 |
+
WaveSound Soundbar
|
86 |
+
AudioPhonic Turntable
|
87 |
+
|
88 |
+
Cameras and Camcorders category:
|
89 |
+
FotoSnap DSLR Camera
|
90 |
+
ActionCam 4K
|
91 |
+
FotoSnap Mirrorless Camera
|
92 |
+
ZoomMaster Camcorder
|
93 |
+
FotoSnap Instant Camera
|
94 |
+
|
95 |
+
Only output the list of objects, with nothing else.
|
96 |
+
"""
|
97 |
+
|
98 |
+
step_2_system_message = {'role':'system', 'content': step_2_system_message_content}
|
99 |
+
|
100 |
+
# sys message for response to user
|
101 |
+
step_4_system_message_content = f"""
|
102 |
+
You are a customer service assistant for a large electronic store. \
|
103 |
+
Respond in a friendly and helpful tone, with VERY concise answers. \
|
104 |
+
Make sure to ask the user relevant follow-up questions.
|
105 |
+
"""
|
106 |
+
|
107 |
+
step_4_system_message = {'role':'system', 'content': step_4_system_message_content}
|
108 |
+
|
109 |
+
# sys message for evaluation
|
110 |
+
step_6_system_message_content = f"""
|
111 |
+
You are an assistant that evaluates whether \
|
112 |
+
customer service agent responses sufficiently \
|
113 |
+
answer customer questions, and also validates that \
|
114 |
+
all the facts the assistant cites from the product \
|
115 |
+
information are correct.
|
116 |
+
The conversation history, product information, user and customer \
|
117 |
+
service agent messages will be delimited by \
|
118 |
+
3 backticks, i.e. ```.
|
119 |
+
Respond with a Y or N character, with no punctuation:
|
120 |
+
Y - if the output sufficiently answers the question \
|
121 |
+
AND the response correctly uses product information
|
122 |
+
N - otherwise
|
123 |
+
|
124 |
+
Output a single letter only.
|
125 |
+
"""
|
126 |
+
|
127 |
+
step_6_system_message = {'role':'system', 'content': step_6_system_message_content}
|
128 |
+
|
129 |
+
|
130 |
+
|
131 |
+
# Set your OpenAI API key from the environment variable
|
132 |
+
#api_key = os.getenv("HYPERBOLIC_API_KEY") # 'ollama'
|
133 |
+
#model = "meta-llama/Llama-3.2-90B-Vision-Instruct" # "gpt-4o-mini"
|
134 |
+
#base_url = "https://api.hyperbolic.xyz/v1/" # ollama 'http://localhost:11434/v1/'
|
135 |
+
|
136 |
+
|
137 |
+
client = OpenAI(
|
138 |
+
base_url=base_url,
|
139 |
+
api_key=api_key
|
140 |
+
)
|
141 |
+
|
142 |
+
|
143 |
+
def get_completion_from_messages(messages,
|
144 |
+
model="gpt-4o-mini",
|
145 |
+
temperature=0,
|
146 |
+
max_tokens=500):
|
147 |
+
'''
|
148 |
+
Encapsulate a function to access LLM
|
149 |
+
|
150 |
+
Parameters:
|
151 |
+
messages: This is a list of messages, each message is a dictionary containing role and content. The role can be 'system', 'user' or 'assistant', and the content is the message of the role.
|
152 |
+
model: The model to be called, default is gpt-4o-mini (ChatGPT)
|
153 |
+
temperature: This determines the randomness of the model output, default is 0, meaning the output will be very deterministic. Increasing temperature will make the output more random.
|
154 |
+
max_tokens: This determines the maximum number of tokens in the model output.
|
155 |
+
'''
|
156 |
+
response = client.chat.completions.create(
|
157 |
+
messages=messages,
|
158 |
+
model = model,
|
159 |
+
temperature=temperature, # This determines the randomness of the model's output
|
160 |
+
max_tokens=max_tokens, # This determines the maximum number of tokens in the model's output
|
161 |
+
)
|
162 |
+
|
163 |
+
return response.choices[0].message.content
|
164 |
+
|
165 |
+
|
166 |
+
def create_categories():
|
167 |
+
categories_dict = {
|
168 |
+
'Billing': [
|
169 |
+
'Unsubscribe or upgrade',
|
170 |
+
'Add a payment method',
|
171 |
+
'Explanation for charge',
|
172 |
+
'Dispute a charge'],
|
173 |
+
'Technical Support':[
|
174 |
+
'General troubleshooting'
|
175 |
+
'Device compatibility',
|
176 |
+
'Software updates'],
|
177 |
+
'Account Management':[
|
178 |
+
'Password reset'
|
179 |
+
'Update personal information',
|
180 |
+
'Close account',
|
181 |
+
'Account security'],
|
182 |
+
'General Inquiry':[
|
183 |
+
'Product information'
|
184 |
+
'Pricing',
|
185 |
+
'Feedback',
|
186 |
+
'Speak to a human']
|
187 |
+
}
|
188 |
+
|
189 |
+
with open(categories_file, 'w') as file:
|
190 |
+
json.dump(categories_dict, file)
|
191 |
+
|
192 |
+
return categories_dict
|
193 |
+
|
194 |
+
|
195 |
+
def get_categories():
|
196 |
+
with open(categories_file, 'r') as file:
|
197 |
+
categories = json.load(file)
|
198 |
+
return categories
|
199 |
+
|
200 |
+
|
201 |
+
def get_product_list():
|
202 |
+
"""
|
203 |
+
具体原理参见第四节课
|
204 |
+
"""
|
205 |
+
products = get_products()
|
206 |
+
product_list = []
|
207 |
+
for product in products.keys():
|
208 |
+
product_list.append(product)
|
209 |
+
|
210 |
+
return product_list
|
211 |
+
|
212 |
+
|
213 |
+
def get_products_and_category():
|
214 |
+
"""
|
215 |
+
具体原理参见第五节课
|
216 |
+
"""
|
217 |
+
products = get_products()
|
218 |
+
products_by_category = defaultdict(list)
|
219 |
+
for product_name, product_info in products.items():
|
220 |
+
category = product_info.get('category')
|
221 |
+
if category:
|
222 |
+
products_by_category[category].append(product_info.get('name'))
|
223 |
+
|
224 |
+
return dict(products_by_category)
|
225 |
+
|
226 |
+
|
227 |
+
def get_products():
|
228 |
+
with open(products_file, 'r') as file:
|
229 |
+
products = json.load(file)
|
230 |
+
return products
|
231 |
+
|
232 |
+
# Get cate and products from user
|
233 |
+
def find_category_and_product(user_input,products_and_category):
|
234 |
+
delimiter = "####"
|
235 |
+
system_message = f"""
|
236 |
+
You will be provided with customer service queries. \
|
237 |
+
The customer service query will be delimited with {delimiter} characters.
|
238 |
+
Output a python list of json objects, where each object has the following format:
|
239 |
+
'category': <one of Computers and Laptops, Smartphones and Accessories, Televisions and Home Theater Systems, \
|
240 |
+
Gaming Consoles and Accessories, Audio Equipment, Cameras and Camcorders>,
|
241 |
+
OR
|
242 |
+
'products': <a list of products that must be found in the allowed products below>
|
243 |
+
|
244 |
+
Where the categories and products must be found in the customer service query.
|
245 |
+
If a product is mentioned, it must be associated with the correct category in the allowed products list below.
|
246 |
+
If no products or categories are found, output an empty list.
|
247 |
+
|
248 |
+
The allowed products are provided in JSON format.
|
249 |
+
The keys of each item represent the category.
|
250 |
+
The values of each item is a list of products that are within that category.
|
251 |
+
Allowed products: {products_and_category}
|
252 |
+
|
253 |
+
"""
|
254 |
+
messages = [
|
255 |
+
{'role':'system', 'content': system_message},
|
256 |
+
{'role':'user', 'content': f"{delimiter}{user_input}{delimiter}"},
|
257 |
+
]
|
258 |
+
return get_completion_from_messages(messages)
|
259 |
+
|
260 |
+
# Add allowed products
|
261 |
+
def find_category_and_product_only(user_input,products_and_category):
|
262 |
+
delimiter = "####"
|
263 |
+
system_message = f"""
|
264 |
+
You will be provided with customer service queries. \
|
265 |
+
The customer service query will be delimited with {delimiter} characters.
|
266 |
+
Output a python list of objects, where each object has the following format:
|
267 |
+
'category': <one of Computers and Laptops, Smartphones and Accessories, Televisions and Home Theater Systems, \
|
268 |
+
Gaming Consoles and Accessories, Audio Equipment, Cameras and Camcorders>,
|
269 |
+
OR
|
270 |
+
'products': <a list of products that must be found in the allowed products below>
|
271 |
+
|
272 |
+
Where the categories and products must be found in the customer service query.
|
273 |
+
If a product is mentioned, it must be associated with the correct category in the allowed products list below.
|
274 |
+
If no products or categories are found, output an empty list.
|
275 |
+
|
276 |
+
Allowed products:
|
277 |
+
Computers and Laptops category:
|
278 |
+
TechPro Ultrabook
|
279 |
+
BlueWave Gaming Laptop
|
280 |
+
PowerLite Convertible
|
281 |
+
TechPro Desktop
|
282 |
+
BlueWave Chromebook
|
283 |
+
|
284 |
+
Smartphones and Accessories category:
|
285 |
+
SmartX ProPhone
|
286 |
+
MobiTech PowerCase
|
287 |
+
SmartX MiniPhone
|
288 |
+
MobiTech Wireless Charger
|
289 |
+
SmartX EarBuds
|
290 |
+
|
291 |
+
Televisions and Home Theater Systems category:
|
292 |
+
CineView 4K TV
|
293 |
+
SoundMax Home Theater
|
294 |
+
CineView 8K TV
|
295 |
+
SoundMax Soundbar
|
296 |
+
CineView OLED TV
|
297 |
+
|
298 |
+
Gaming Consoles and Accessories category:
|
299 |
+
GameSphere X
|
300 |
+
ProGamer Controller
|
301 |
+
GameSphere Y
|
302 |
+
ProGamer Racing Wheel
|
303 |
+
GameSphere VR Headset
|
304 |
+
|
305 |
+
Audio Equipment category:
|
306 |
+
AudioPhonic Noise-Canceling Headphones
|
307 |
+
WaveSound Bluetooth Speaker
|
308 |
+
AudioPhonic True Wireless Earbuds
|
309 |
+
WaveSound Soundbar
|
310 |
+
AudioPhonic Turntable
|
311 |
+
|
312 |
+
Cameras and Camcorders category:
|
313 |
+
FotoSnap DSLR Camera
|
314 |
+
ActionCam 4K
|
315 |
+
FotoSnap Mirrorless Camera
|
316 |
+
ZoomMaster Camcorder
|
317 |
+
FotoSnap Instant Camera
|
318 |
+
|
319 |
+
Only output the list of objects, nothing else.
|
320 |
+
"""
|
321 |
+
messages = [
|
322 |
+
{'role':'system', 'content': system_message},
|
323 |
+
{'role':'user', 'content': f"{delimiter}{user_input}{delimiter}"},
|
324 |
+
]
|
325 |
+
return get_completion_from_messages(messages)
|
326 |
+
|
327 |
+
# Get product from user query
|
328 |
+
def get_products_from_query(user_msg):
|
329 |
+
|
330 |
+
products_and_category = get_products_and_category()
|
331 |
+
delimiter = "####"
|
332 |
+
system_message = f"""
|
333 |
+
You will be provided with customer service queries. \
|
334 |
+
The customer service query will be delimited with {delimiter} characters.
|
335 |
+
Output a python list of json objects, where each object has the following format:
|
336 |
+
'category': <one of Computers and Laptops, Smartphones and Accessories, Televisions and Home Theater Systems, \
|
337 |
+
Gaming Consoles and Accessories, Audio Equipment, Cameras and Camcorders>,
|
338 |
+
OR
|
339 |
+
'products': <a list of products that must be found in the allowed products below>
|
340 |
+
|
341 |
+
Where the categories and products must be found in the customer service query.
|
342 |
+
If a product is mentioned, it must be associated with the correct category in the allowed products list below.
|
343 |
+
If no products or categories are found, output an empty list.
|
344 |
+
|
345 |
+
The allowed products are provided in JSON format.
|
346 |
+
The keys of each item represent the category.
|
347 |
+
The values of each item is a list of products that are within that category.
|
348 |
+
Allowed products: {products_and_category}
|
349 |
+
|
350 |
+
"""
|
351 |
+
|
352 |
+
messages = [
|
353 |
+
{'role':'system', 'content': system_message},
|
354 |
+
{'role':'user', 'content': f"{delimiter}{user_msg}{delimiter}"},
|
355 |
+
]
|
356 |
+
category_and_product_response = get_completion_from_messages(messages)
|
357 |
+
|
358 |
+
return category_and_product_response
|
359 |
+
|
360 |
+
|
361 |
+
|
362 |
+
def get_product_by_name(name):
|
363 |
+
products = get_products()
|
364 |
+
return products.get(name, None)
|
365 |
+
|
366 |
+
def get_products_by_category(category):
|
367 |
+
products = get_products()
|
368 |
+
return [product for product in products.values() if product["category"] == category]
|
369 |
+
|
370 |
+
def get_mentioned_product_info(data_list):
|
371 |
+
"""
|
372 |
+
具体原理参见第五、六节课
|
373 |
+
"""
|
374 |
+
product_info_l = []
|
375 |
+
|
376 |
+
if data_list is None:
|
377 |
+
return product_info_l
|
378 |
+
|
379 |
+
for data in data_list:
|
380 |
+
try:
|
381 |
+
if "products" in data:
|
382 |
+
products_list = data["products"]
|
383 |
+
for product_name in products_list:
|
384 |
+
product = get_product_by_name(product_name)
|
385 |
+
if product:
|
386 |
+
product_info_l.append(product)
|
387 |
+
else:
|
388 |
+
print(f"Error: Product '{product_name}' not found")
|
389 |
+
elif "category" in data:
|
390 |
+
category_name = data["category"]
|
391 |
+
category_products = get_products_by_category(category_name)
|
392 |
+
for product in category_products:
|
393 |
+
product_info_l.append(product)
|
394 |
+
else:
|
395 |
+
print("Error: Invalid object format")
|
396 |
+
except Exception as e:
|
397 |
+
print(f"Error: {e}")
|
398 |
+
|
399 |
+
return product_info_l
|
400 |
+
|
401 |
+
|
402 |
+
|
403 |
+
def read_string_to_list(input_string):
|
404 |
+
if input_string is None:
|
405 |
+
return None
|
406 |
+
|
407 |
+
try:
|
408 |
+
input_string = input_string.replace("'", "\"") # Replace single quotes with double quotes for valid JSON
|
409 |
+
data = json.loads(input_string)
|
410 |
+
return data
|
411 |
+
except json.JSONDecodeError:
|
412 |
+
print("Error: Invalid JSON string")
|
413 |
+
return None
|
414 |
+
|
415 |
+
def generate_output_string(data_list):
|
416 |
+
output_string = ""
|
417 |
+
|
418 |
+
if data_list is None:
|
419 |
+
return output_string
|
420 |
+
|
421 |
+
for data in data_list:
|
422 |
+
try:
|
423 |
+
if "products" in data:
|
424 |
+
products_list = data["products"]
|
425 |
+
for product_name in products_list:
|
426 |
+
product = get_product_by_name(product_name)
|
427 |
+
if product:
|
428 |
+
output_string += json.dumps(product, indent=4) + "\n"
|
429 |
+
else:
|
430 |
+
print(f"Error: Product '{product_name}' not found")
|
431 |
+
elif "category" in data:
|
432 |
+
category_name = data["category"]
|
433 |
+
category_products = get_products_by_category(category_name)
|
434 |
+
for product in category_products:
|
435 |
+
output_string += json.dumps(product, indent=4) + "\n"
|
436 |
+
else:
|
437 |
+
print("Error: Invalid object format")
|
438 |
+
except Exception as e:
|
439 |
+
print(f"Error: {e}")
|
440 |
+
|
441 |
+
return output_string
|
442 |
+
|
443 |
+
# Example usage:
|
444 |
+
#product_information_for_user_message_1 = generate_output_string(category_and_product_list)
|
445 |
+
#print(product_information_for_user_message_1)
|
446 |
+
# Answer questions from customers
|
447 |
+
def answer_user_msg(user_msg,product_info):
|
448 |
+
"""
|
449 |
+
代码参见第五节课
|
450 |
+
"""
|
451 |
+
delimiter = "####"
|
452 |
+
system_message = f"""
|
453 |
+
You are a customer service assistant for a large electronic store. \
|
454 |
+
Respond in a friendly and helpful tone, with concise answers. \
|
455 |
+
Make sure to ask the user relevant follow up questions.
|
456 |
+
"""
|
457 |
+
# user_msg = f"""
|
458 |
+
# tell me about the smartx pro phone and the fotosnap camera, the dslr one. Also what tell me about your tvs"""
|
459 |
+
messages = [
|
460 |
+
{'role':'system', 'content': system_message},
|
461 |
+
{'role':'user', 'content': f"{delimiter}{user_msg}{delimiter}"},
|
462 |
+
{'role':'assistant', 'content': f"Relevant product information:\n{product_info}"},
|
463 |
+
]
|
464 |
+
response = get_completion_from_messages(messages)
|
465 |
+
return response
|
466 |
+
|
467 |
+
# 创建并存入商品数据
|
468 |
+
def create_products():
|
469 |
+
"""
|
470 |
+
Create products dictionary and save it to a file named products.json
|
471 |
+
"""
|
472 |
+
# product information
|
473 |
+
# fun fact: all these products are fake and were generated by a language model
|
474 |
+
products = {
|
475 |
+
"TechPro Ultrabook": {
|
476 |
+
"name": "TechPro Ultrabook",
|
477 |
+
"category": "Computers and Laptops",
|
478 |
+
"brand": "TechPro",
|
479 |
+
"model_number": "TP-UB100",
|
480 |
+
"warranty": "1 year",
|
481 |
+
"rating": 4.5,
|
482 |
+
"features": ["13.3-inch display", "8GB RAM", "256GB SSD", "Intel Core i5 processor"],
|
483 |
+
"description": "A sleek and lightweight ultrabook for everyday use.",
|
484 |
+
"price": 799.99
|
485 |
+
},
|
486 |
+
"BlueWave Gaming Laptop": {
|
487 |
+
"name": "BlueWave Gaming Laptop",
|
488 |
+
"category": "Computers and Laptops",
|
489 |
+
"brand": "BlueWave",
|
490 |
+
"model_number": "BW-GL200",
|
491 |
+
"warranty": "2 years",
|
492 |
+
"rating": 4.7,
|
493 |
+
"features": ["15.6-inch display", "16GB RAM", "512GB SSD", "NVIDIA GeForce RTX 3060"],
|
494 |
+
"description": "A high-performance gaming laptop for an immersive experience.",
|
495 |
+
"price": 1199.99
|
496 |
+
},
|
497 |
+
"PowerLite Convertible": {
|
498 |
+
"name": "PowerLite Convertible",
|
499 |
+
"category": "Computers and Laptops",
|
500 |
+
"brand": "PowerLite",
|
501 |
+
"model_number": "PL-CV300",
|
502 |
+
"warranty": "1 year",
|
503 |
+
"rating": 4.3,
|
504 |
+
"features": ["14-inch touchscreen", "8GB RAM", "256GB SSD", "360-degree hinge"],
|
505 |
+
"description": "A versatile convertible laptop with a responsive touchscreen.",
|
506 |
+
"price": 699.99
|
507 |
+
},
|
508 |
+
"TechPro Desktop": {
|
509 |
+
"name": "TechPro Desktop",
|
510 |
+
"category": "Computers and Laptops",
|
511 |
+
"brand": "TechPro",
|
512 |
+
"model_number": "TP-DT500",
|
513 |
+
"warranty": "1 year",
|
514 |
+
"rating": 4.4,
|
515 |
+
"features": ["Intel Core i7 processor", "16GB RAM", "1TB HDD", "NVIDIA GeForce GTX 1660"],
|
516 |
+
"description": "A powerful desktop computer for work and play.",
|
517 |
+
"price": 999.99
|
518 |
+
},
|
519 |
+
"BlueWave Chromebook": {
|
520 |
+
"name": "BlueWave Chromebook",
|
521 |
+
"category": "Computers and Laptops",
|
522 |
+
"brand": "BlueWave",
|
523 |
+
"model_number": "BW-CB100",
|
524 |
+
"warranty": "1 year",
|
525 |
+
"rating": 4.1,
|
526 |
+
"features": ["11.6-inch display", "4GB RAM", "32GB eMMC", "Chrome OS"],
|
527 |
+
"description": "A compact and affordable Chromebook for everyday tasks.",
|
528 |
+
"price": 249.99
|
529 |
+
},
|
530 |
+
"SmartX ProPhone": {
|
531 |
+
"name": "SmartX ProPhone",
|
532 |
+
"category": "Smartphones and Accessories",
|
533 |
+
"brand": "SmartX",
|
534 |
+
"model_number": "SX-PP10",
|
535 |
+
"warranty": "1 year",
|
536 |
+
"rating": 4.6,
|
537 |
+
"features": ["6.1-inch display", "128GB storage", "12MP dual camera", "5G"],
|
538 |
+
"description": "A powerful smartphone with advanced camera features.",
|
539 |
+
"price": 899.99
|
540 |
+
},
|
541 |
+
"MobiTech PowerCase": {
|
542 |
+
"name": "MobiTech PowerCase",
|
543 |
+
"category": "Smartphones and Accessories",
|
544 |
+
"brand": "MobiTech",
|
545 |
+
"model_number": "MT-PC20",
|
546 |
+
"warranty": "1 year",
|
547 |
+
"rating": 4.3,
|
548 |
+
"features": ["5000mAh battery", "Wireless charging", "Compatible with SmartX ProPhone"],
|
549 |
+
"description": "A protective case with built-in battery for extended usage.",
|
550 |
+
"price": 59.99
|
551 |
+
},
|
552 |
+
"SmartX MiniPhone": {
|
553 |
+
"name": "SmartX MiniPhone",
|
554 |
+
"category": "Smartphones and Accessories",
|
555 |
+
"brand": "SmartX",
|
556 |
+
"model_number": "SX-MP5",
|
557 |
+
"warranty": "1 year",
|
558 |
+
"rating": 4.2,
|
559 |
+
"features": ["4.7-inch display", "64GB storage", "8MP camera", "4G"],
|
560 |
+
"description": "A compact and affordable smartphone for basic tasks.",
|
561 |
+
"price": 399.99
|
562 |
+
},
|
563 |
+
"MobiTech Wireless Charger": {
|
564 |
+
"name": "MobiTech Wireless Charger",
|
565 |
+
"category": "Smartphones and Accessories",
|
566 |
+
"brand": "MobiTech",
|
567 |
+
"model_number": "MT-WC10",
|
568 |
+
"warranty": "1 year",
|
569 |
+
"rating": 4.5,
|
570 |
+
"features": ["10W fast charging", "Qi-compatible", "LED indicator", "Compact design"],
|
571 |
+
"description": "A convenient wireless charger for a clutter-free workspace.",
|
572 |
+
"price": 29.99
|
573 |
+
},
|
574 |
+
"SmartX EarBuds": {
|
575 |
+
"name": "SmartX EarBuds",
|
576 |
+
"category": "Smartphones and Accessories",
|
577 |
+
"brand": "SmartX",
|
578 |
+
"model_number": "SX-EB20",
|
579 |
+
"warranty": "1 year",
|
580 |
+
"rating": 4.4,
|
581 |
+
"features": ["True wireless", "Bluetooth 5.0", "Touch controls", "24-hour battery life"],
|
582 |
+
"description": "Experience true wireless freedom with these comfortable earbuds.",
|
583 |
+
"price": 99.99
|
584 |
+
},
|
585 |
+
|
586 |
+
"CineView 4K TV": {
|
587 |
+
"name": "CineView 4K TV",
|
588 |
+
"category": "Televisions and Home Theater Systems",
|
589 |
+
"brand": "CineView",
|
590 |
+
"model_number": "CV-4K55",
|
591 |
+
"warranty": "2 years",
|
592 |
+
"rating": 4.8,
|
593 |
+
"features": ["55-inch display", "4K resolution", "HDR", "Smart TV"],
|
594 |
+
"description": "A stunning 4K TV with vibrant colors and smart features.",
|
595 |
+
"price": 599.99
|
596 |
+
},
|
597 |
+
"SoundMax Home Theater": {
|
598 |
+
"name": "SoundMax Home Theater",
|
599 |
+
"category": "Televisions and Home Theater Systems",
|
600 |
+
"brand": "SoundMax",
|
601 |
+
"model_number": "SM-HT100",
|
602 |
+
"warranty": "1 year",
|
603 |
+
"rating": 4.4,
|
604 |
+
"features": ["5.1 channel", "1000W output", "Wireless subwoofer", "Bluetooth"],
|
605 |
+
"description": "A powerful home theater system for an immersive audio experience.",
|
606 |
+
"price": 399.99
|
607 |
+
},
|
608 |
+
"CineView 8K TV": {
|
609 |
+
"name": "CineView 8K TV",
|
610 |
+
"category": "Televisions and Home Theater Systems",
|
611 |
+
"brand": "CineView",
|
612 |
+
"model_number": "CV-8K65",
|
613 |
+
"warranty": "2 years",
|
614 |
+
"rating": 4.9,
|
615 |
+
"features": ["65-inch display", "8K resolution", "HDR", "Smart TV"],
|
616 |
+
"description": "Experience the future of television with this stunning 8K TV.",
|
617 |
+
"price": 2999.99
|
618 |
+
},
|
619 |
+
"SoundMax Soundbar": {
|
620 |
+
"name": "SoundMax Soundbar",
|
621 |
+
"category": "Televisions and Home Theater Systems",
|
622 |
+
"brand": "SoundMax",
|
623 |
+
"model_number": "SM-SB50",
|
624 |
+
"warranty": "1 year",
|
625 |
+
"rating": 4.3,
|
626 |
+
"features": ["2.1 channel", "300W output", "Wireless subwoofer", "Bluetooth"],
|
627 |
+
"description": "Upgrade your TV's audio with this sleek and powerful soundbar.",
|
628 |
+
"price": 199.99
|
629 |
+
},
|
630 |
+
"CineView OLED TV": {
|
631 |
+
"name": "CineView OLED TV",
|
632 |
+
"category": "Televisions and Home Theater Systems",
|
633 |
+
"brand": "CineView",
|
634 |
+
"model_number": "CV-OLED55",
|
635 |
+
"warranty": "2 years",
|
636 |
+
"rating": 4.7,
|
637 |
+
"features": ["55-inch display", "4K resolution", "HDR", "Smart TV"],
|
638 |
+
"description": "Experience true blacks and vibrant colors with this OLED TV.",
|
639 |
+
"price": 1499.99
|
640 |
+
},
|
641 |
+
|
642 |
+
"GameSphere X": {
|
643 |
+
"name": "GameSphere X",
|
644 |
+
"category": "Gaming Consoles and Accessories",
|
645 |
+
"brand": "GameSphere",
|
646 |
+
"model_number": "GS-X",
|
647 |
+
"warranty": "1 year",
|
648 |
+
"rating": 4.9,
|
649 |
+
"features": ["4K gaming", "1TB storage", "Backward compatibility", "Online multiplayer"],
|
650 |
+
"description": "A next-generation gaming console for the ultimate gaming experience.",
|
651 |
+
"price": 499.99
|
652 |
+
},
|
653 |
+
"ProGamer Controller": {
|
654 |
+
"name": "ProGamer Controller",
|
655 |
+
"category": "Gaming Consoles and Accessories",
|
656 |
+
"brand": "ProGamer",
|
657 |
+
"model_number": "PG-C100",
|
658 |
+
"warranty": "1 year",
|
659 |
+
"rating": 4.2,
|
660 |
+
"features": ["Ergonomic design", "Customizable buttons", "Wireless", "Rechargeable battery"],
|
661 |
+
"description": "A high-quality gaming controller for precision and comfort.",
|
662 |
+
"price": 59.99
|
663 |
+
},
|
664 |
+
"GameSphere Y": {
|
665 |
+
"name": "GameSphere Y",
|
666 |
+
"category": "Gaming Consoles and Accessories",
|
667 |
+
"brand": "GameSphere",
|
668 |
+
"model_number": "GS-Y",
|
669 |
+
"warranty": "1 year",
|
670 |
+
"rating": 4.8,
|
671 |
+
"features": ["4K gaming", "500GB storage", "Backward compatibility", "Online multiplayer"],
|
672 |
+
"description": "A compact gaming console with powerful performance.",
|
673 |
+
"price": 399.99
|
674 |
+
},
|
675 |
+
"ProGamer Racing Wheel": {
|
676 |
+
"name": "ProGamer Racing Wheel",
|
677 |
+
"category": "Gaming Consoles and Accessories",
|
678 |
+
"brand": "ProGamer",
|
679 |
+
"model_number": "PG-RW200",
|
680 |
+
"warranty": "1 year",
|
681 |
+
"rating": 4.5,
|
682 |
+
"features": ["Force feedback", "Adjustable pedals", "Paddle shifters", "Compatible with GameSphere X"],
|
683 |
+
"description": "Enhance your racing games with this realistic racing wheel.",
|
684 |
+
"price": 249.99
|
685 |
+
},
|
686 |
+
"GameSphere VR Headset": {
|
687 |
+
"name": "GameSphere VR Headset",
|
688 |
+
"category": "Gaming Consoles and Accessories",
|
689 |
+
"brand": "GameSphere",
|
690 |
+
"model_number": "GS-VR",
|
691 |
+
"warranty": "1 year",
|
692 |
+
"rating": 4.6,
|
693 |
+
"features": ["Immersive VR experience", "Built-in headphones", "Adjustable headband", "Compatible with GameSphere X"],
|
694 |
+
"description": "Step into the world of virtual reality with this comfortable VR headset.",
|
695 |
+
"price": 299.99
|
696 |
+
},
|
697 |
+
|
698 |
+
"AudioPhonic Noise-Canceling Headphones": {
|
699 |
+
"name": "AudioPhonic Noise-Canceling Headphones",
|
700 |
+
"category": "Audio Equipment",
|
701 |
+
"brand": "AudioPhonic",
|
702 |
+
"model_number": "AP-NC100",
|
703 |
+
"warranty": "1 year",
|
704 |
+
"rating": 4.6,
|
705 |
+
"features": ["Active noise-canceling", "Bluetooth", "20-hour battery life", "Comfortable fit"],
|
706 |
+
"description": "Experience immersive sound with these noise-canceling headphones.",
|
707 |
+
"price": 199.99
|
708 |
+
},
|
709 |
+
"WaveSound Bluetooth Speaker": {
|
710 |
+
"name": "WaveSound Bluetooth Speaker",
|
711 |
+
"category": "Audio Equipment",
|
712 |
+
"brand": "WaveSound",
|
713 |
+
"model_number": "WS-BS50",
|
714 |
+
"warranty": "1 year",
|
715 |
+
"rating": 4.5,
|
716 |
+
"features": ["Portable", "10-hour battery life", "Water-resistant", "Built-in microphone"],
|
717 |
+
"description": "A compact and versatile Bluetooth speaker for music on the go.",
|
718 |
+
"price": 49.99
|
719 |
+
},
|
720 |
+
"AudioPhonic True Wireless Earbuds": {
|
721 |
+
"name": "AudioPhonic True Wireless Earbuds",
|
722 |
+
"category": "Audio Equipment",
|
723 |
+
"brand": "AudioPhonic",
|
724 |
+
"model_number": "AP-TW20",
|
725 |
+
"warranty": "1 year",
|
726 |
+
"rating": 4.4,
|
727 |
+
"features": ["True wireless", "Bluetooth 5.0", "Touch controls", "18-hour battery life"],
|
728 |
+
"description": "Enjoy music without wires with these comfortable true wireless earbuds.",
|
729 |
+
"price": 79.99
|
730 |
+
},
|
731 |
+
"WaveSound Soundbar": {
|
732 |
+
"name": "WaveSound Soundbar",
|
733 |
+
"category": "Audio Equipment",
|
734 |
+
"brand": "WaveSound",
|
735 |
+
"model_number": "WS-SB40",
|
736 |
+
"warranty": "1 year",
|
737 |
+
"rating": 4.3,
|
738 |
+
"features": ["2.0 channel", "80W output", "Bluetooth", "Wall-mountable"],
|
739 |
+
"description": "Upgrade your TV's audio with this slim and powerful soundbar.",
|
740 |
+
"price": 99.99
|
741 |
+
},
|
742 |
+
"AudioPhonic Turntable": {
|
743 |
+
"name": "AudioPhonic Turntable",
|
744 |
+
"category": "Audio Equipment",
|
745 |
+
"brand": "AudioPhonic",
|
746 |
+
"model_number": "AP-TT10",
|
747 |
+
"warranty": "1 year",
|
748 |
+
"rating": 4.2,
|
749 |
+
"features": ["3-speed", "Built-in speakers", "Bluetooth", "USB recording"],
|
750 |
+
"description": "Rediscover your vinyl collection with this modern turntable.",
|
751 |
+
"price": 149.99
|
752 |
+
},
|
753 |
+
|
754 |
+
"FotoSnap DSLR Camera": {
|
755 |
+
"name": "FotoSnap DSLR Camera",
|
756 |
+
"category": "Cameras and Camcorders",
|
757 |
+
"brand": "FotoSnap",
|
758 |
+
"model_number": "FS-DSLR200",
|
759 |
+
"warranty": "1 year",
|
760 |
+
"rating": 4.7,
|
761 |
+
"features": ["24.2MP sensor", "1080p video", "3-inch LCD", "Interchangeable lenses"],
|
762 |
+
"description": "Capture stunning photos and videos with this versatile DSLR camera.",
|
763 |
+
"price": 599.99
|
764 |
+
},
|
765 |
+
"ActionCam 4K": {
|
766 |
+
"name": "ActionCam 4K",
|
767 |
+
"category": "Cameras and Camcorders",
|
768 |
+
"brand": "ActionCam",
|
769 |
+
"model_number": "AC-4K",
|
770 |
+
"warranty": "1 year",
|
771 |
+
"rating": 4.4,
|
772 |
+
"features": ["4K video", "Waterproof", "Image stabilization", "Wi-Fi"],
|
773 |
+
"description": "Record your adventures with this rugged and compact 4K action camera.",
|
774 |
+
"price": 299.99
|
775 |
+
},
|
776 |
+
"FotoSnap Mirrorless Camera": {
|
777 |
+
"name": "FotoSnap Mirrorless Camera",
|
778 |
+
"category": "Cameras and Camcorders",
|
779 |
+
"brand": "FotoSnap",
|
780 |
+
"model_number": "FS-ML100",
|
781 |
+
"warranty": "1 year",
|
782 |
+
"rating": 4.6,
|
783 |
+
"features": ["20.1MP sensor", "4K video", "3-inch touchscreen", "Interchangeable lenses"],
|
784 |
+
"description": "A compact and lightweight mirrorless camera with advanced features.",
|
785 |
+
"price": 799.99
|
786 |
+
},
|
787 |
+
"ZoomMaster Camcorder": {
|
788 |
+
"name": "ZoomMaster Camcorder",
|
789 |
+
"category": "Cameras and Camcorders",
|
790 |
+
"brand": "ZoomMaster",
|
791 |
+
"model_number": "ZM-CM50",
|
792 |
+
"warranty": "1 year",
|
793 |
+
"rating": 4.3,
|
794 |
+
"features": ["1080p video", "30x optical zoom", "3-inch LCD", "Image stabilization"],
|
795 |
+
"description": "Capture life's moments with this easy-to-use camcorder.",
|
796 |
+
"price": 249.99
|
797 |
+
},
|
798 |
+
"FotoSnap Instant Camera": {
|
799 |
+
"name": "FotoSnap Instant Camera",
|
800 |
+
"category": "Cameras and Camcorders",
|
801 |
+
"brand": "FotoSnap",
|
802 |
+
"model_number": "FS-IC10",
|
803 |
+
"warranty": "1 year",
|
804 |
+
"rating": 4.1,
|
805 |
+
"features": ["Instant prints", "Built-in flash", "Selfie mirror", "Battery-powered"],
|
806 |
+
"description": "Create instant memories with this fun and portable instant camera.",
|
807 |
+
"price": 69.99
|
808 |
+
}
|
809 |
+
}
|
810 |
+
|
811 |
+
products_file = 'products.json'
|
812 |
+
with open(products_file, 'w') as file:
|
813 |
+
json.dump(products, file)
|
814 |
+
|
815 |
+
return products
|