Hugo Guarin commited on
Commit
c169262
1 Parent(s): 23b2a3d

Update space

Browse files
.DS_Store ADDED
Binary file (6.15 kB). View file
 
README.md CHANGED
@@ -1,13 +1,37 @@
1
- ---
2
- title: Fastlane
3
- emoji: 📈
4
- colorFrom: gray
5
- colorTo: red
6
- sdk: gradio
7
- sdk_version: 4.36.1
8
- app_file: app.py
9
- pinned: false
10
- license: mit
11
- ---
12
-
13
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ## FastLane E-commerce Chatbot
2
+
3
+ This project provides a Retrieval-Augmented Generation (RAG) system that involves Elastisearch, OpenAI, FastAPI and Gradio components. The system is about an e-commerce chatbot for product and orders searches and leverages Natural Language Processing (NLP) for understanding user intent.
4
+
5
+ **Modular Structure for Maintainability:**
6
+
7
+ The system was designed with a focus on maintainability and scalability. Here's a breakdown of the core components:
8
+
9
+ * **main.py:** The entry point for the application, where the FastAPI app is defined and run.
10
+ * **models/ (Directory):** Contains Pydantic models for data validation and defining data structures used throughout the application.
11
+ - `query.py`: Defines models for user queries.
12
+ - `product.py`: Defines models for representing product data.
13
+ - `customer.py`: Defines models for representing customer data.
14
+ - `order.py`: Defines models for representing order data.
15
+ * **services/ (Directory):** Encapsulates the core business logic of the application.
16
+ - `elasticsearch.py`: Handles interactions with the Elasticsearch instance for product searches.
17
+ - `nlp.py`: Provides functionalities for Natural Language Processing (NLP) to understand user intent.
18
+ - `utils.py`: Provides functions that are used by several components of the system.
19
+ * **routes/ (Directory):** Defines API endpoints for interacting with the chatbot functionalities. Each feature has its dedicated module:
20
+ - `search_products.py`: Handles routes related to product search functionalities.
21
+ - `query_handler`: Handles routes related to the processing of the query introduced by users.
22
+ - `purchase.py`: Handles routes related to purchase functionalities (add to cart, checkout, etc.).
23
+ - `order_management.py`: Handles routes related to managing orders (tracking, history).
24
+ - `account_management.py`: Handles routes related to account management (sign-in, update information).
25
+ - `customer_support.py`: Handles routes related to customer support functionalities (returns, payments, etc.).
26
+
27
+ This modular structure promotes separation of concerns, making the code easier to understand, maintain, and extend in the future.
28
+
29
+ **Getting Started:**
30
+
31
+ (Provide instructions on how to set up and run the application, including any dependencies or environment variables required.)
32
+
33
+ **Further Development:**
34
+
35
+ * Generating more comprehensive responses based on intent, entities, and search results.
36
+ * Enhance security features for handling sensitive user data.
37
+ * Implement user authentication and authorization mechanisms.
gradio_app.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import requests
3
+
4
+
5
+ def fastlane_agent(message, history):
6
+
7
+ history_openai_format = [
8
+ {"role": "system", "content": "You are an assistant for an eCommerce store."}]
9
+ for human, assistant in history:
10
+ history_openai_format.append({"role": "user", "content": human})
11
+ history_openai_format.append(
12
+ {"role": "assistant", "content": assistant})
13
+ history_openai_format.append({"role": "user", "content": message})
14
+
15
+ response = requests.post(
16
+ "http://localhost:8000/query-handler/", json={"text": message, "history": history_openai_format})
17
+ if response.status_code == 200:
18
+ return response.json().get("generative response")
19
+ else:
20
+ return "Error: Could not fetch response."
21
+
22
+
23
+ iface = gr.ChatInterface(
24
+ fn=fastlane_agent,
25
+ chatbot=gr.Chatbot(height=400),
26
+ textbox=gr.Textbox(
27
+ placeholder="How can I help you?", container=False, scale=7
28
+ ),
29
+ title="Fastlane Chat GPT",
30
+ description="AI sales assistance for e-commmerce",
31
+ theme="soft",
32
+ examples=["Hello", "What is the status of my order?",
33
+ "Recommend me products"],
34
+ cache_examples=True,
35
+ retry_btn=None,
36
+ undo_btn="Delete Previous",
37
+ clear_btn="Clear"
38
+ )
39
+
40
+ if __name__ == "__main__":
41
+ iface.launch()
gradio_cached_examples/15/log.csv ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ component 0,flag,username,timestamp
2
+ "[[""Hello"", ""Hello! How can I assist you today?""]]",,,2024-06-11 20:45:46.202912
3
+ "[[""What is the status of my order?"", ""Could you please provide me with your order number so I can check the status for you?""]]",,,2024-06-11 20:45:50.095791
4
+ "[[""Recommend me products"", ""Error: Could not fetch response.""]]",,,2024-06-11 20:46:01.780475
img/fastlane.jpg ADDED
main.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from routes import query_handler, purchase, order_management, account_management, customer_support, search_products
3
+
4
+ app = FastAPI()
5
+
6
+ app.include_router(purchase.router, prefix="/purchase", tags=["purchase"])
7
+ app.include_router(order_management.router,
8
+ prefix="/order-management", tags=["order-management"])
9
+ app.include_router(account_management.router,
10
+ prefix="/account-management", tags=["account-management"])
11
+ app.include_router(customer_support.router,
12
+ prefix="/customer-support", tags=["customer-support"])
13
+ app.include_router(search_products.router,
14
+ prefix="/search-products", tags=["search-products"])
15
+ app.include_router(query_handler.router,
16
+ prefix="/query-handler", tags=["query-handler"])
17
+
18
+ if __name__ == "__main__":
19
+ import uvicorn
20
+ uvicorn.run(app, host="0.0.0.0", port=8000)
models/.DS_Store ADDED
Binary file (6.15 kB). View file
 
models/customer.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from typing import List, Optional
3
+
4
+
5
+ class Customer(BaseModel):
6
+ customer_id: str
7
+ name: str
8
+ email: str
9
+ address: str
10
+ phone: Optional[str] = None
11
+ orders: Optional[List[str]] = None
models/order.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class Order(BaseModel):
5
+ order_id: str
6
+ product_ids: list
7
+ quantities: list
8
+ status: str
models/product.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+ from typing import List, Optional
3
+
4
+
5
+ class Product(BaseModel):
6
+ product_id: str
7
+ title: str
8
+ description: str
9
+ price: float
10
+ category: str
11
+ tags: Optional[List[str]] = None
models/query.py ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional, List, Dict
2
+ from pydantic import BaseModel
3
+
4
+
5
+ class Query(BaseModel):
6
+ text: str
7
+ intent: Optional[str] = None
8
+ entities: Optional[Dict] = None
9
+ keywords: Optional[List] = None
10
+ history: Optional[List[Dict[str, str]]] = None
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ elasticsearch
2
+ en-core-web-lg @ https://github.com/explosion/spacy-models/releases/download/en_core_web_lg-3.0.0/en_core_web_lg-3.0.0.tar.gz
3
+ fastapi
4
+ gradio
5
+ nltk
6
+ openai
7
+ pydantic
8
+ spacy
9
+ torch
10
+ transformers
11
+ uvicorn[standard]
routes/.DS_Store ADDED
Binary file (6.15 kB). View file
 
routes/__init__.py ADDED
File without changes
routes/account_management.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, status, HTTPException
2
+ from models.query import Query
3
+ from services.elasticsearch import get_customer, update_customer
4
+
5
+ router = APIRouter()
6
+
7
+
8
+ @router.post("/sign-in-up")
9
+ def handle_sign_in_up(query: Query):
10
+ customer_id = next(
11
+ (entity['value'] for entity in query.entities if entity['entity'] == 'customer_id'), None)
12
+ if customer_id:
13
+ customer = get_customer(customer_id)
14
+ if not customer:
15
+ raise HTTPException(
16
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")
17
+ return customer
18
+ else:
19
+ raise HTTPException(
20
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer ID not provided.")
21
+
22
+
23
+ @router.post("/update-account")
24
+ def handle_update_account(query: Query):
25
+ customer_id = next(
26
+ (entity['value'] for entity in query.entities if entity['entity'] == 'customer_id'), None)
27
+ updates = {entity['entity']: entity['value'] for entity in query.entities}
28
+ if customer_id:
29
+ update_customer(customer_id, updates)
30
+ return {"message": "Account information updated successfully"}
31
+ else:
32
+ raise HTTPException(
33
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer ID not provided.")
routes/customer_support.py ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from models.query import Query
3
+ from services.nlp import generate_response
4
+
5
+ router = APIRouter()
6
+
7
+
8
+ @router.post("/get-help")
9
+ def handle_get_help(query: Query):
10
+ response_text = generate_response(
11
+ {"query": query.text, "intent": "Get help"})
12
+ return {"response": response_text[0]['generated_text']}
13
+
14
+
15
+ @router.get("/return-exchange-policy")
16
+ def handle_return_exchange_policy():
17
+ return {"policy": "Our return/exchange policy details go here"}
18
+
19
+
20
+ @router.get("/payment-options")
21
+ def handle_payment_options():
22
+ return {"payment_options": ["Credit Card", "PayPal", "Bank Transfer"]}
23
+
24
+
25
+ @router.get("/shipping-information")
26
+ def handle_shipping_information():
27
+ return {"shipping_info": "Shipping costs and delivery times details go here"}
routes/order_management.py ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, status, HTTPException
2
+ from services.elasticsearch import get_order_details, get_customer
3
+
4
+ router = APIRouter()
5
+
6
+
7
+ @router.get("/track-order/{order_id}")
8
+ def handle_track_order(order_id: str):
9
+ order = get_order_details(order_id)
10
+ if not order:
11
+ raise HTTPException(
12
+ status_code=status.HTTP_404_NOT_FOUND, detail="Order not found")
13
+ return order
14
+
15
+
16
+ @router.get("/order-history")
17
+ def view_order_history(customer_id: str):
18
+ customer = get_customer(customer_id)
19
+ if not customer:
20
+ raise HTTPException(
21
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer not found")
22
+ # Retrieve order history from customer data
23
+ return {"order_history": customer.get("orders", [])}
routes/purchase.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, status, HTTPException
2
+ from models.query import Query
3
+ from services.elasticsearch import add_to_cart, view_cart, remove_from_cart, checkout
4
+
5
+ router = APIRouter()
6
+
7
+
8
+ @router.post("/add-to-cart")
9
+ def handle_add_to_cart(query: Query):
10
+ customer_id = next(
11
+ (entity['value'] for entity in query.entities if entity['entity'] == 'customer_id'), None)
12
+ product_id = next(
13
+ (entity['value'] for entity in query.entities if entity['entity'] == 'product_id'), None)
14
+ quantity = next(
15
+ (entity['value'] for entity in query.entities if entity['entity'] == 'quantity'), 1)
16
+ if customer_id and product_id:
17
+ cart = add_to_cart(customer_id, product_id, int(quantity))
18
+ return cart
19
+ else:
20
+ raise HTTPException(
21
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer ID or Product ID not provided.")
22
+
23
+
24
+ @router.get("/view-cart/{customer_id}")
25
+ def handle_view_cart(customer_id: str):
26
+ cart = view_cart(customer_id)
27
+ if not cart:
28
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Cart not found")
29
+ return cart
30
+
31
+
32
+ @router.post("/remove-from-cart")
33
+ def handle_remove_from_cart(query: Query):
34
+ customer_id = next(
35
+ (entity['value'] for entity in query.entities if entity['entity'] == 'customer_id'), None)
36
+ product_id = next(
37
+ (entity['value'] for entity in query.entities if entity['entity'] == 'product_id'), None)
38
+ if customer_id and product_id:
39
+ cart = remove_from_cart(customer_id, product_id)
40
+ return cart
41
+ else:
42
+ raise HTTPException(
43
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer ID or Product ID not provided.")
44
+
45
+
46
+ @router.post("/checkout")
47
+ def handle_checkout(query: Query):
48
+ customer_id = next(
49
+ (entity['value'] for entity in query.entities if entity['entity'] == 'customer_id'), None)
50
+ if customer_id:
51
+ order = checkout(customer_id)
52
+ return order
53
+ else:
54
+ raise HTTPException(
55
+ status_code=status.HTTP_404_NOT_FOUND, detail="Customer ID not provided.")
routes/query_handler.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, status, HTTPException
2
+ from models.query import Query
3
+ from routes import search_products, purchase, order_management, account_management, customer_support
4
+ from services.nlp import recognize_intent, recognize_entities, extract_keywords, generate_response
5
+ from services.utils import clean_text, encode_and_normalize, extract_order_id_from_query
6
+
7
+
8
+ router = APIRouter()
9
+
10
+
11
+ FUNCTION_DESCRIPTIONS_FOR_PRODUCTS = {
12
+ "search_products_by_keywords": "User wants to find products based on keywords",
13
+ "search_products_by_filters": "User wants to refine search results with filters",
14
+ "get_product_details": "User wants detailed information about a specific product"
15
+ }
16
+
17
+ FUNCTION_DESCRIPTIONS_FOR_ORDERS = {
18
+ "get_order_location": "Find the location (city or state) of a specific order using an identification number order",
19
+ "get_recent_order": "Track the most recent order of a customer",
20
+ "get_order_details": "Get details about a specific order using an identification number order",
21
+ "get_order_quantity": "Calculate the total number of products in a specific order",
22
+ "get_order_amount": "Calculate the total amount spent in a specific order",
23
+ "cancel_order": "Process order cancellation requests"
24
+ }
25
+
26
+
27
+ def query_processing(query: Query):
28
+ cleaned_text = clean_text(query.text)
29
+ query.intent = recognize_intent(cleaned_text)
30
+ query.entities = recognize_entities(cleaned_text)
31
+ query.keywords = extract_keywords(cleaned_text)
32
+ encoded_query = encode_and_normalize(cleaned_text)
33
+
34
+ if query.intent == "search for products":
35
+ return {"products": search_products.handle_search_products_by_keywords(encoded_query)}
36
+
37
+ elif query.intent == "order management":
38
+ order_id = extract_order_id_from_query(query.text)
39
+ if order_id:
40
+ return order_management.handle_track_order(order_id)
41
+ else:
42
+ return "Please provide an Order Number"
43
+ else:
44
+ return None
45
+
46
+
47
+ @router.post("/")
48
+ async def handle_response(query: Query):
49
+ context_from_elasticsearch = query_processing(query)
50
+ return {"generative response": generate_response(query, context_from_elasticsearch)}
routes/search_products.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException
2
+ from services.elasticsearch import search_products_by_keywords, search_products_by_filters, get_product_details
3
+
4
+ router = APIRouter()
5
+
6
+
7
+ @router.post("/")
8
+ def handle_search_products_by_keywords(encoded_query: list):
9
+ products = search_products_by_keywords(encoded_query)
10
+ if not products:
11
+ raise HTTPException(status_code=404, detail="No products to recommend")
12
+ return products
services/.DS_Store ADDED
Binary file (6.15 kB). View file
 
services/__init__.py ADDED
File without changes
services/elasticsearch.py ADDED
@@ -0,0 +1,137 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from elasticsearch import Elasticsearch
3
+ from elasticsearch_dsl import Search
4
+ from models.product import Product
5
+ from models.customer import Customer
6
+ from models.order import Order
7
+
8
+ cloud_id = os.getenv("ELASTICSEARCH_CLOUD_ID")
9
+ api_key = os.getenv("ELASTICSEARCH_API_KEY")
10
+
11
+ try:
12
+ es = Elasticsearch(cloud_id=cloud_id, api_key=api_key)
13
+
14
+ except ConnectionError as e:
15
+ print("Error:", e)
16
+
17
+
18
+ def search_elasticsearch(index, query):
19
+ response = es.search(index=index, body={
20
+ "query": {
21
+ "multi_match": {
22
+ "query": query,
23
+ "fields": ["title", "description", "category", "tags"]
24
+ }
25
+ }
26
+ })
27
+ return response['hits']['hits']
28
+
29
+
30
+ def search_products_by_keywords(encoded_query):
31
+ body_query = {
32
+ "_source": ["ProductName", "Description", "Gender", "Price (INR)", "PrimaryColor"],
33
+ "knn": {
34
+ "field": "DescriptionVector",
35
+ "query_vector": encoded_query,
36
+ "k": 4,
37
+ "num_candidates": 500
38
+ }
39
+ }
40
+
41
+ response = es.search(index='products', body=body_query)
42
+ return response['hits']['hits']
43
+
44
+
45
+ def search_products_by_filters(filters):
46
+ response = es.search(index='products', body={
47
+ "query": {
48
+ "bool": {
49
+ "filter": filters
50
+ }
51
+ }
52
+ })
53
+ return response['hits']['hits']
54
+
55
+
56
+ def get_product_details(product_id):
57
+ response = es.get(index='products', id=product_id)
58
+ return response['_source']
59
+
60
+
61
+ def index_product(product: Product):
62
+ es.index(index="products", id=product.product_id, body=product.dict())
63
+
64
+
65
+ def index_customer(customer: Customer):
66
+ es.index(index="customers", id=customer.customer_id, body=customer.dict())
67
+
68
+
69
+ def get_customer(customer_id: str):
70
+ response = es.get(index="customers", id=customer_id)
71
+ return response['_source']
72
+
73
+
74
+ def update_customer(customer_id: str, updates: dict):
75
+ es.update(index="customers", id=customer_id, body={"doc": updates})
76
+
77
+
78
+ def index_order(order: Order):
79
+ es.index(index="orders", id=order.order_id, body=order.dict())
80
+
81
+
82
+ def track_order(order_id: str):
83
+ response = es.get(index="orders", id=order_id)
84
+ return response['_source']
85
+
86
+
87
+ def get_order_details(order_id):
88
+ s_order = Search(using=es, index='orders').query(
89
+ 'match', **{'Order ID': order_id})
90
+ s_details = Search(using=es, index='order_details').query(
91
+ 'match', **{'Order ID': order_id})
92
+ order_response = s_order.execute()
93
+ details_response = s_details.execute()
94
+
95
+ if order_response.hits.total.value > 0 and details_response.hits.total.value > 0:
96
+ order = order_response.hits[0].to_dict()
97
+ details = [detail.to_dict() for detail in details_response.hits]
98
+ return {
99
+ "order": order,
100
+ "details": details
101
+ }
102
+ else:
103
+ return "Order not found"
104
+
105
+
106
+ def add_to_cart(customer_id: str, product_id: str, quantity: int):
107
+ cart = es.get(index="carts", id=customer_id)['_source']
108
+ if 'items' not in cart:
109
+ cart['items'] = []
110
+ cart['items'].append({"product_id": product_id, "quantity": quantity})
111
+ es.index(index="carts", id=customer_id, body=cart)
112
+ return cart
113
+
114
+
115
+ def view_cart(customer_id: str):
116
+ response = es.get(index="carts", id=customer_id)
117
+ return response['_source']
118
+
119
+
120
+ def remove_from_cart(customer_id: str, product_id: str):
121
+ cart = es.get(index="carts", id=customer_id)['_source']
122
+ cart['items'] = [item for item in cart['items']
123
+ if item['product_id'] != product_id]
124
+ es.index(index="carts", id=customer_id, body=cart)
125
+ return cart
126
+
127
+
128
+ def checkout(customer_id: str):
129
+ cart = es.get(index="carts", id=customer_id)['_source']
130
+ order = {
131
+ "customer_id": customer_id,
132
+ "items": cart['items'],
133
+ "status": "processing"
134
+ }
135
+ es.index(index="orders", body=order)
136
+ es.delete(index="carts", id=customer_id)
137
+ return order
services/nlp.py ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from openai import OpenAI
3
+ from models.query import Query
4
+ import re
5
+ from transformers import pipeline
6
+ from services.utils import clean_text, encode_and_normalize
7
+
8
+ intent_recognizer = pipeline(
9
+ "zero-shot-classification", model="facebook/bart-large-mnli")
10
+
11
+ ner_recognizer = pipeline(
12
+ 'ner', model='dbmdz/bert-large-cased-finetuned-conll03-english')
13
+
14
+ openai_key = os.environ.get("OPENAI_KEY")
15
+ openai_client = OpenAI(api_key=openai_key)
16
+
17
+ # Define regex patterns for entities
18
+ patterns = {
19
+ 'Product': r'\b(iphone|samsung|macbook|ps5|galaxy|pixel|shoes|shampoo|cellphone|smartphone|tablet|laptop|headphones|console|tv|camera)\b',
20
+ 'Brand': r'\b(apple|samsung|google|sony|microsoft|dell|hp|lenovo|asus|nintendo|canon|nikon)\b',
21
+ 'Category': r'\b(laptops|dresses|phones|electronics|clothing|footwear|accessories|home appliances|furniture)\b',
22
+ 'Color': r'\b(red|black|yellow|blue|green|white|grey|pink|purple|orange|brown)\b',
23
+ 'Price Range': r'\b(under \$?\d+|below \$?\d+|less than \$?\d+|more than \$?\d+|above \$?\d+|between \$?\d+ and \$?\d+)\b',
24
+ 'Quantity': r'\b(\d+ bottles|\d+ items|\d+ pieces|\d+ units|\d+)\b',
25
+ 'Order Number': r'\bB-\d+\b',
26
+ 'Issue': r'\b(account help|payment issue|order problem|shipping delay|return request|product complaint|technical support)\b'
27
+ }
28
+
29
+ INTENTS = [
30
+ "search for products",
31
+ "order management",
32
+ "checkout",
33
+ "customer support",
34
+ "account management"
35
+ ]
36
+
37
+
38
+ def recognize_intent(text):
39
+ cleaned_text = clean_text(text)
40
+ intent = intent_recognizer(cleaned_text, INTENTS)
41
+ return intent['labels'][0]
42
+
43
+
44
+ def recognize_entities(text):
45
+ cleaned_text = clean_text(text)
46
+ entities_from_ner = ner_recognizer(cleaned_text)
47
+ entities_from_re = {entity: re.findall(pattern, text.lower(
48
+ )) for entity, pattern in patterns.items() if re.findall(pattern, text.lower())}
49
+
50
+ return entities_from_re
51
+
52
+
53
+ def extract_keywords(text):
54
+ cleaned_text = clean_text(text)
55
+ return cleaned_text.split()
56
+
57
+
58
+ def generate_response(query: Query, context_from_elasticsearch):
59
+ prompt = query.history
60
+ prompt.append({"role": "assistant", "content": str(context_from_elasticsearch)})
61
+
62
+ print(prompt)
63
+
64
+ response = openai_client.chat.completions.create(
65
+ model="gpt-3.5-turbo",
66
+ messages=prompt
67
+ )
68
+
69
+ return response.choices[0].message.content
70
+
71
+
services/utils.py ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+ import numpy as np
3
+ from nltk.tokenize import word_tokenize
4
+ from nltk.corpus import stopwords
5
+ from nltk.stem import WordNetLemmatizer
6
+ from sentence_transformers import SentenceTransformer
7
+
8
+ stop_words = set(stopwords.words('english'))
9
+ lemmatizer = WordNetLemmatizer()
10
+ model = SentenceTransformer('all-mpnet-base-v2')
11
+
12
+
13
+ def clean_text(text):
14
+ # Lowercase
15
+ text = text.lower()
16
+ # Remove special characters and digits
17
+ text = re.sub(r'[^a-z\s]', '', text)
18
+ # Tokenize
19
+ words = word_tokenize(text)
20
+ # Remove stopwords and lemmatize
21
+ words = [lemmatizer.lemmatize(word)
22
+ for word in words if word not in stop_words]
23
+ # Join words back to a single string
24
+ cleaned_text = ' '.join(words)
25
+ return cleaned_text
26
+
27
+
28
+ def encode_and_normalize(text):
29
+ vector = model.encode(text)
30
+ normalized_vector = vector / np.linalg.norm(vector)
31
+ return normalized_vector
32
+
33
+ def extract_order_id_from_query(text):
34
+ match = re.search(r'\bB-\d+\b', text)
35
+ if match:
36
+ return match.group(0)
37
+ return None