Repository navigation
Expand file tree
/
Copy pathchatbot_engine.py
More file actions
359 lines (341 loc) · 14.7 KB
/
Copy pathchatbot_engine.py
File metadata and controls
359 lines (341 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
from __future__ import annotations
from dataclasses import dataclass
from difflib import SequenceMatcher
import re
from typing import Dict, List, Optional
@dataclass(frozen=True)
class Intent:
name: str
patterns: List[str]
response: str
suggestions: List[str]
class CustomerServiceChatbot:
def __init__(self) -> None:
self.intents = self._build_intents()
def _build_intents(self) -> List[Intent]:
return [
Intent(
name="greeting",
patterns=[
"hello",
"hi",
"hey",
"good morning",
"good evening",
"is anyone there",
"can you help me",
],
response=(
"Hello and welcome to Astera support. I can help with order tracking, delivery delays, "
"returns, payments, address updates, account issues, promo code problems, and support contact details."
),
suggestions=["Track my order", "Refund policy", "Change delivery address"],
),
Intent(
name="order_tracking",
patterns=[
"where is my order",
"track my order",
"track order",
"order status",
"delivery status",
"when will my order arrive",
"my order has not arrived",
],
response=(
"You can check the latest status from the Orders section using your order ID and registered email. "
"If tracking has not updated for more than 48 hours, support can raise a courier check."
),
suggestions=["Delivery is delayed", "Talk to support", "Change delivery address"],
),
Intent(
name="shipping",
patterns=[
"shipping time",
"delivery time",
"how long does shipping take",
"how many days for delivery",
"shipping charges",
"express delivery",
"international shipping",
],
response=(
"Standard delivery usually takes 3 to 5 business days. Express shipping takes 1 to 2 business days in eligible areas. "
"Final delivery charges are shown during checkout."
),
suggestions=["Track my order", "Payment methods", "Product availability"],
),
Intent(
name="delivery_delay",
patterns=[
"delivery is delayed",
"my order is delayed",
"package is late",
"why is my order late",
"order delayed",
"delivery delay",
],
response=(
"Delays can happen because of courier backlog, weather conditions, address verification, or failed delivery attempts. "
"If the order has been stuck for more than 48 hours, please contact support with your order reference."
),
suggestions=["Track my order", "Talk to support", "Change delivery address"],
),
Intent(
name="refund",
patterns=[
"refund policy",
"i want a refund",
"how do i get a refund",
"money back",
"refund status",
"can i return my order",
"return item",
],
response=(
"Eligible items can usually be returned within 7 days of delivery if they are unused and in original condition. "
"Once a return is approved, refunds are typically completed within 5 to 7 business days."
),
suggestions=["Start a return", "Cancel my order", "Talk to support"],
),
Intent(
name="return_process",
patterns=[
"start a return",
"return process",
"how to return item",
"schedule return pickup",
"pickup for return",
"return request",
],
response=(
"To start a return, open your order details, select Return Item, choose the reason, and confirm the pickup address. "
"You will receive an update as soon as the return request is approved."
),
suggestions=["Refund policy", "Track my order", "Talk to support"],
),
Intent(
name="cancel_order",
patterns=[
"cancel order",
"i want to cancel my order",
"order cancellation",
"stop my purchase",
"cancel before shipping",
"can i cancel after placing order",
],
response=(
"Orders can usually be cancelled before they move to packing or shipping. "
"Open the order details page and choose Cancel Order. If the option is unavailable, the order may already be in process."
),
suggestions=["Refund policy", "Track my order", "Talk to support"],
),
Intent(
name="payment",
patterns=[
"payment methods",
"how can i pay",
"can i pay with upi",
"credit card accepted",
"cash on delivery",
"wallet payment",
],
response=(
"We support UPI, debit cards, credit cards, net banking, and selected digital wallets. "
"Cash on delivery may be available depending on location and order value."
),
suggestions=["Payment failed", "Refund policy", "Promo code issue"],
),
Intent(
name="payment_failed",
patterns=[
"payment failed",
"transaction failed",
"money deducted but order not confirmed",
"billing failed",
"card declined",
"payment problem",
],
response=(
"If payment failed but money was deducted, please wait up to 30 minutes for an automatic reversal. "
"If the amount is not reversed, contact support with the transaction ID for manual review."
),
suggestions=["Talk to support", "Payment methods", "Refund policy"],
),
Intent(
name="account_help",
patterns=[
"login problem",
"forgot password",
"reset my password",
"cannot sign in",
"unable to login",
"account locked",
"account help",
],
response=(
"Use the Forgot Password option on the sign-in page to reset access. "
"If your account is locked or still inaccessible, support can verify your identity and help restore it."
),
suggestions=["Talk to support", "Store hours", "Payment methods"],
),
Intent(
name="address_change",
patterns=[
"change delivery address",
"change shipping address",
"update address",
"wrong address",
"modify delivery location",
"address change",
],
response=(
"You can update the delivery address before the order is shipped. "
"Open your order details and choose Edit Address. If the order is already packed, please contact support right away."
),
suggestions=["Track my order", "Cancel my order", "Talk to support"],
),
Intent(
name="product_availability",
patterns=[
"is this product in stock",
"product availability",
"when will it be back",
"out of stock",
"restock date",
"available size",
],
response=(
"Product availability is updated live on the product page. "
"If an item is out of stock, you can use the notify option to get an alert when it returns."
),
suggestions=["Notify me when available", "Shipping time", "Talk to support"],
),
Intent(
name="promo_code",
patterns=[
"promo code issue",
"coupon not working",
"discount code invalid",
"offer not applying",
"promo code",
"coupon failed",
],
response=(
"Please check whether the coupon has expired, whether the minimum order value is met, and whether the selected items are eligible. "
"Some offers are limited to one use per account."
),
suggestions=["Payment methods", "Talk to support", "Shipping time"],
),
Intent(
name="store_hours",
patterns=[
"store hours",
"working hours",
"support timings",
"when are you open",
"business hours",
"what time support available",
],
response=(
"Our customer support team is available Monday to Saturday from 9:00 AM to 7:00 PM. "
"Messages sent after hours are handled in the next working window."
),
suggestions=["Talk to support", "Track my order", "Refund policy"],
),
Intent(
name="contact_support",
patterns=[
"contact support",
"talk to agent",
"speak to human",
"customer care number",
"email support",
"help center",
"representative",
],
response=(
"You can contact the care team at support@asterahelp.com or call +91-90000-12345 during support hours. "
"Sharing your order ID and issue summary helps the team resolve the case faster."
),
suggestions=["Store hours", "Track my order", "Payment failed"],
),
Intent(
name="goodbye",
patterns=[
"bye",
"goodbye",
"thanks",
"thank you",
"see you",
"ok thanks",
],
response="Happy to help. If you need anything else, just send another message.",
suggestions=["Track my order", "Refund policy", "Talk to support"],
),
]
def _normalize(self, text: str) -> str:
text = text.lower()
text = re.sub(r"[^a-z0-9\s]", " ", text)
return re.sub(r"\s+", " ", text).strip()
def _keyword_score(self, message: str, pattern: str) -> float:
message_words = set(message.split())
pattern_words = set(pattern.split())
if not pattern_words:
return 0.0
overlap = len(message_words & pattern_words)
return overlap / len(pattern_words)
def _pattern_score(self, message: str, pattern: str) -> float:
similarity = SequenceMatcher(None, message, pattern).ratio()
keyword_score = self._keyword_score(message, pattern)
contains_bonus = 0.15 if pattern in message else 0.0
return max(similarity, keyword_score + contains_bonus)
def _extract_order_id(self, message: str) -> Optional[str]:
match = re.search(r"\b(?:ord|order)[-\s:]?(\d{4,10})\b", message, re.IGNORECASE)
if match:
return f"ORD-{match.group(1)}"
return None
def _fallback_response(self, message: str) -> Dict[str, object]:
order_id = self._extract_order_id(message)
if order_id:
reply = (
f"I noticed the reference {order_id}. I cannot fetch live order data in this build, "
"but I can still guide you on tracking, cancellation, returns, address changes, and support escalation."
)
suggestions = ["Track my order", "Change delivery address", "Talk to support"]
else:
reply = (
"I do not have a precise answer for that yet, but I can help with tracking, delivery delays, returns, "
"payments, coupon issues, account access, store hours, and support contact details."
)
suggestions = ["Track my order", "Payment failed", "Refund policy"]
return {
"reply": reply,
"intent": "fallback",
"confidence": 0.0,
"suggestions": suggestions,
}
def get_response(self, message: str) -> Dict[str, object]:
normalized_message = self._normalize(message)
best_intent = None
best_score = 0.0
for intent in self.intents:
intent_score = max(
self._pattern_score(normalized_message, self._normalize(pattern))
for pattern in intent.patterns
)
if intent_score > best_score:
best_score = intent_score
best_intent = intent
if best_intent is None or best_score < 0.45:
return self._fallback_response(message)
reply = best_intent.response
order_id = self._extract_order_id(message)
if order_id and best_intent.name in {"order_tracking", "delivery_delay", "cancel_order"}:
reply = f"For {order_id}, {reply}"
return {
"reply": reply,
"intent": best_intent.name,
"confidence": round(best_score, 2),
"suggestions": best_intent.suggestions,
}