nepali-messenger-nlp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +94 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +157 -0
- package/package.json +32 -0
- package/src/index.ts +214 -0
- package/tsconfig.json +14 -0
package/README.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# nepali-messenger-nlp
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/nepali-messenger-nlp)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
> Lightweight, zero-dependency Romanized Nepali NLP parser and entity extraction engine built specifically for **[Facebook Messenger AI Chatbots in Nepal](https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal)**.
|
|
7
|
+
|
|
8
|
+
Developed and maintained by the engineering team at **[Sajedar](https://www.sajedar.com)**, powering automated 24/7 conversational sales for Nepali e-commerce pages on Meta Messenger.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 🌟 Why nepali-messenger-nlp?
|
|
13
|
+
|
|
14
|
+
Nepali e-commerce on Facebook Messenger operates predominantly in Romanized colloquial Nepali mixed with English (*"Kathmandu ma delivery kati parcha?", "cod huncha ki advance halna parcha?", "mero size L ho"*). Traditional NLP pipelines fail on these phrases because of informal spelling variations, lack of standard orthography, and regional slang.
|
|
15
|
+
|
|
16
|
+
This library provides deterministic, ultra-fast (<2ms) parsing for:
|
|
17
|
+
- 💰 **Pricing & Rate queries** (*"kati parcha"*, *"rate k ho"*, *"price plx"*)
|
|
18
|
+
- 📍 **Kathmandu Valley Delivery Locations** (Classifying Inside Ring Road vs. Outside Ring Road vs. Out of Valley)
|
|
19
|
+
- 📱 **Nepali Mobile Number Sanitization** (Detecting NTC `984/985/986`, Ncell `980/981/982`, SmartCell `988/961`, stripping `+977`, spaces, hyphens)
|
|
20
|
+
- 👕 **Apparel Size & Color Extraction** (S, M, L, XL, XXL, Free Size, Rato, Kalo, Seto, etc.)
|
|
21
|
+
- 💳 **Cash on Delivery & Advance Payment Intent** (Detecting Rs. 100 advance deposit intent to slash COD cancellations from 35% to <10%)
|
|
22
|
+
- 📸 **Payment Screenshot Detection Intent** (Flagging when a buyer announces they sent an eSewa/Fonepay screenshot)
|
|
23
|
+
|
|
24
|
+
For enterprise-grade conversational AI with 2-second live latency, human supervisor handoff, and direct order catalog sync, check out the full **[Facebook Messenger AI Chatbot Nepal Solution by Sajedar](https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal)**.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 📦 Installation
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install nepali-messenger-nlp
|
|
32
|
+
# or
|
|
33
|
+
yarn add nepali-messenger-nlp
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 🚀 Quick Start
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import {
|
|
42
|
+
parseNepaliIntent,
|
|
43
|
+
classifyNepalLocation,
|
|
44
|
+
extractNepalPhoneNumber,
|
|
45
|
+
detectAdvancePaymentIntent
|
|
46
|
+
} from 'nepali-messenger-nlp';
|
|
47
|
+
|
|
48
|
+
// 1. Parse Romanized Nepali customer intent
|
|
49
|
+
const intent = parseNepaliIntent("Dai yo jacket ko price kati ho? New Road ma delivery huncha?");
|
|
50
|
+
console.log(intent);
|
|
51
|
+
// Output:
|
|
52
|
+
// {
|
|
53
|
+
// category: 'PRICE_INQUIRY',
|
|
54
|
+
// confidence: 0.98,
|
|
55
|
+
// extractedEntities: {
|
|
56
|
+
// item: 'jacket',
|
|
57
|
+
// location: 'New Road'
|
|
58
|
+
// }
|
|
59
|
+
// }
|
|
60
|
+
|
|
61
|
+
// 2. Classify Delivery Logistics (Inside vs Outside Ring Road)
|
|
62
|
+
const locationInfo = classifyNepalLocation("Mero ghar Baneshwor Shankhamul tira ho");
|
|
63
|
+
console.log(locationInfo);
|
|
64
|
+
// Output:
|
|
65
|
+
// {
|
|
66
|
+
// isInsideRingRoad: true,
|
|
67
|
+
// hub: 'Kathmandu Central',
|
|
68
|
+
// suggestedCourierRate: 100
|
|
69
|
+
// }
|
|
70
|
+
|
|
71
|
+
// 3. Clean and validate Nepali phone numbers
|
|
72
|
+
const phone = extractNepalPhoneNumber("Contact no: 984-1234567 call me");
|
|
73
|
+
console.log(phone);
|
|
74
|
+
// Output: "9841234567" (Carrier: NTC Mobile, Valid: true)
|
|
75
|
+
|
|
76
|
+
// 4. Advance COD confirmation intent
|
|
77
|
+
const isAdvance = detectAdvancePaymentIntent("Maile 100 advance pathaye screenshot hernus ta");
|
|
78
|
+
console.log(isAdvance);
|
|
79
|
+
// Output: { hasAdvanceIntent: true, hasScreenshotProof: true }
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 🏛️ Official Commercial Solution
|
|
85
|
+
|
|
86
|
+
Looking for a fully managed, turn-key AI chatbot with a dedicated human technical supervisor for your Nepali Facebook store?
|
|
87
|
+
|
|
88
|
+
Visit **[https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal](https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal)** to test the interactive live simulator and get onboarded in under 48 hours.
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## 📄 License
|
|
93
|
+
|
|
94
|
+
MIT © [Sajedar](https://www.sajedar.com)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nepali-messenger-nlp
|
|
3
|
+
* Lightweight, zero-dependency Romanized Nepali intent and entity parser
|
|
4
|
+
* for Facebook Messenger E-Commerce chatbots in Nepal.
|
|
5
|
+
*
|
|
6
|
+
* Maintained by Sajedar: https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal
|
|
7
|
+
*/
|
|
8
|
+
export interface IntentResult {
|
|
9
|
+
intent: 'PRICE_INQUIRY' | 'DELIVERY_INQUIRY' | 'ORDER_PLACEMENT' | 'ADVANCE_PAYMENT' | 'SIZE_COLOR_INQUIRY' | 'HUMAN_SUPPORT' | 'GREETING' | 'UNKNOWN';
|
|
10
|
+
confidence: number;
|
|
11
|
+
extractedKeywords: string[];
|
|
12
|
+
}
|
|
13
|
+
export interface LocationClassification {
|
|
14
|
+
locationDetected: string | null;
|
|
15
|
+
zone: 'INSIDE_RING_ROAD' | 'OUTSIDE_RING_ROAD' | 'OUT_OF_VALLEY' | 'UNKNOWN';
|
|
16
|
+
suggestedCourierCharge: number;
|
|
17
|
+
deliveryDaysEstimate: string;
|
|
18
|
+
}
|
|
19
|
+
export interface PhoneNumberResult {
|
|
20
|
+
raw: string;
|
|
21
|
+
cleaned: string | null;
|
|
22
|
+
isValid: boolean;
|
|
23
|
+
carrier: 'NTC' | 'NCELL' | 'SMART_CELL' | 'UNKNOWN';
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse Romanized Nepali customer text and determine intent.
|
|
27
|
+
*/
|
|
28
|
+
export declare function parseNepaliIntent(text: string): IntentResult;
|
|
29
|
+
/**
|
|
30
|
+
* Classify Nepali delivery locations into shipping zones with courier rate guidance.
|
|
31
|
+
*/
|
|
32
|
+
export declare function classifyNepalLocation(text: string): LocationClassification;
|
|
33
|
+
/**
|
|
34
|
+
* Extract and validate 10-digit Nepali mobile numbers from customer messages.
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractNepalPhoneNumber(text: string): PhoneNumberResult;
|
|
37
|
+
/**
|
|
38
|
+
* Detect Advance Payment & Screenshot proof intents to slash COD cancellation rates.
|
|
39
|
+
*/
|
|
40
|
+
export declare function detectAdvancePaymentIntent(text: string): {
|
|
41
|
+
hasAdvanceIntent: boolean;
|
|
42
|
+
hasScreenshotProof: boolean;
|
|
43
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* nepali-messenger-nlp
|
|
4
|
+
* Lightweight, zero-dependency Romanized Nepali intent and entity parser
|
|
5
|
+
* for Facebook Messenger E-Commerce chatbots in Nepal.
|
|
6
|
+
*
|
|
7
|
+
* Maintained by Sajedar: https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.detectAdvancePaymentIntent = exports.extractNepalPhoneNumber = exports.classifyNepalLocation = exports.parseNepaliIntent = void 0;
|
|
11
|
+
const INSIDE_RING_ROAD_AREAS = [
|
|
12
|
+
'new road', 'newroad', 'putalisadak', 'baneshwor', 'thamel', 'dillibazar',
|
|
13
|
+
'maitighar', 'tripureshwor', 'kupondole', 'pulchowk', 'jawalakhel', 'lagankhel',
|
|
14
|
+
'lazimpat', 'baluwatar', 'panipokhari', 'maharajgunj', 'chabahil', 'gaushala',
|
|
15
|
+
'battisputali', 'sankhamul', 'teku', 'kalimati', 'kuleshwor', 'balkhu',
|
|
16
|
+
'sanepa', 'jhamsikhel', 'kumaripati', 'minbhawan', 'anamnagar', 'ghattaghar'
|
|
17
|
+
];
|
|
18
|
+
const OUTSIDE_RING_ROAD_VALLEY_AREAS = [
|
|
19
|
+
'kapan', 'budhanilkantha', 'tokha', 'gongabu', 'samakhusi', 'machhapokhari',
|
|
20
|
+
'balaju', 'sitapaila', 'kalanki', 'chobhar', 'dhapakhel', 'sunakothi',
|
|
21
|
+
'lubhu', 'imadol', 'tikathali', 'thimi', 'sallaghari', 'bhaktapur',
|
|
22
|
+
'suryabinayak', 'sankhu', 'boudha', 'jorpati', 'dakshinkali', 'godawari'
|
|
23
|
+
];
|
|
24
|
+
const MAJOR_OUT_OF_VALLEY_CITIES = [
|
|
25
|
+
'pokhara', 'butwal', 'chitwan', 'narayangarh', 'biratnagar', 'dharan',
|
|
26
|
+
'nepalgunj', 'hetauda', 'damak', 'birtamod', 'itahari', 'dhangadhi',
|
|
27
|
+
'surkhet', 'janakpur', 'birgunj', 'bhairahawa'
|
|
28
|
+
];
|
|
29
|
+
/**
|
|
30
|
+
* Parse Romanized Nepali customer text and determine intent.
|
|
31
|
+
*/
|
|
32
|
+
function parseNepaliIntent(text) {
|
|
33
|
+
const normalized = text.toLowerCase().trim();
|
|
34
|
+
const keywords = [];
|
|
35
|
+
// Advance Payment / Screenshot Proof intent
|
|
36
|
+
if (/screenshot|esewa|fonepay|advance|screen shot|qr code|pay garisake|haldiye|pathaidie/.test(normalized)) {
|
|
37
|
+
keywords.push('payment_proof');
|
|
38
|
+
return { intent: 'ADVANCE_PAYMENT', confidence: 0.96, extractedKeywords: keywords };
|
|
39
|
+
}
|
|
40
|
+
// Price Inquiry
|
|
41
|
+
if (/kati parcha|kati ho|price|rate|cost|mulyo|prc|dam kati|kati ma|discount/.test(normalized)) {
|
|
42
|
+
keywords.push('pricing');
|
|
43
|
+
return { intent: 'PRICE_INQUIRY', confidence: 0.94, extractedKeywords: keywords };
|
|
44
|
+
}
|
|
45
|
+
// Delivery & Courier Inquiry
|
|
46
|
+
if (/delivery|courier|pathao|ncm|nepal can move|ring road|charge kati|gharma pathaune/.test(normalized)) {
|
|
47
|
+
keywords.push('delivery');
|
|
48
|
+
return { intent: 'DELIVERY_INQUIRY', confidence: 0.91, extractedKeywords: keywords };
|
|
49
|
+
}
|
|
50
|
+
// Order Placement
|
|
51
|
+
if (/order|kinna|chaiyo|pathaideu|pathaidinus|confirm|cash on delivery|cod|book garidinu/.test(normalized)) {
|
|
52
|
+
keywords.push('order_initiation');
|
|
53
|
+
return { intent: 'ORDER_PLACEMENT', confidence: 0.93, extractedKeywords: keywords };
|
|
54
|
+
}
|
|
55
|
+
// Size / Color
|
|
56
|
+
if (/\b(size|color|colour|xl|xxl|small|medium|large|kalo|rato|seto|blue|black)\b/.test(normalized)) {
|
|
57
|
+
keywords.push('variant');
|
|
58
|
+
return { intent: 'SIZE_COLOR_INQUIRY', confidence: 0.88, extractedKeywords: keywords };
|
|
59
|
+
}
|
|
60
|
+
// Human Supervisor Handoff
|
|
61
|
+
if (/human|manche|admin|owner|supervisor|call gar|phone gar|kura garna/.test(normalized)) {
|
|
62
|
+
keywords.push('human_handoff');
|
|
63
|
+
return { intent: 'HUMAN_SUPPORT', confidence: 0.95, extractedKeywords: keywords };
|
|
64
|
+
}
|
|
65
|
+
// Greeting
|
|
66
|
+
if (/^(hi|hello|namaste|namaskar|hey|salam|k cha|k chha)\b/.test(normalized)) {
|
|
67
|
+
keywords.push('greeting');
|
|
68
|
+
return { intent: 'GREETING', confidence: 0.99, extractedKeywords: keywords };
|
|
69
|
+
}
|
|
70
|
+
return { intent: 'UNKNOWN', confidence: 0.3, extractedKeywords: [] };
|
|
71
|
+
}
|
|
72
|
+
exports.parseNepaliIntent = parseNepaliIntent;
|
|
73
|
+
/**
|
|
74
|
+
* Classify Nepali delivery locations into shipping zones with courier rate guidance.
|
|
75
|
+
*/
|
|
76
|
+
function classifyNepalLocation(text) {
|
|
77
|
+
const normalized = text.toLowerCase();
|
|
78
|
+
for (const area of INSIDE_RING_ROAD_AREAS) {
|
|
79
|
+
if (normalized.includes(area)) {
|
|
80
|
+
return {
|
|
81
|
+
locationDetected: area,
|
|
82
|
+
zone: 'INSIDE_RING_ROAD',
|
|
83
|
+
suggestedCourierCharge: 100,
|
|
84
|
+
deliveryDaysEstimate: 'Same day / 24 hours'
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const area of OUTSIDE_RING_ROAD_VALLEY_AREAS) {
|
|
89
|
+
if (normalized.includes(area)) {
|
|
90
|
+
return {
|
|
91
|
+
locationDetected: area,
|
|
92
|
+
zone: 'OUTSIDE_RING_ROAD',
|
|
93
|
+
suggestedCourierCharge: 150,
|
|
94
|
+
deliveryDaysEstimate: '24 - 48 hours'
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const city of MAJOR_OUT_OF_VALLEY_CITIES) {
|
|
99
|
+
if (normalized.includes(city)) {
|
|
100
|
+
return {
|
|
101
|
+
locationDetected: city,
|
|
102
|
+
zone: 'OUT_OF_VALLEY',
|
|
103
|
+
suggestedCourierCharge: 200,
|
|
104
|
+
deliveryDaysEstimate: '2 - 4 business days'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return {
|
|
109
|
+
locationDetected: null,
|
|
110
|
+
zone: 'UNKNOWN',
|
|
111
|
+
suggestedCourierCharge: 150,
|
|
112
|
+
deliveryDaysEstimate: 'Contact store'
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
exports.classifyNepalLocation = classifyNepalLocation;
|
|
116
|
+
/**
|
|
117
|
+
* Extract and validate 10-digit Nepali mobile numbers from customer messages.
|
|
118
|
+
*/
|
|
119
|
+
function extractNepalPhoneNumber(text) {
|
|
120
|
+
// Strips +977 or 00977 prefix and searches for 98xxxxxxxx or 97xxxxxxxx
|
|
121
|
+
const regex = /(?:\+?977[-.\s]?)?(9[78]\d{8})\b/;
|
|
122
|
+
const match = text.match(regex);
|
|
123
|
+
if (!match) {
|
|
124
|
+
return { raw: text, cleaned: null, isValid: false, carrier: 'UNKNOWN' };
|
|
125
|
+
}
|
|
126
|
+
const phone = match[1];
|
|
127
|
+
let carrier = 'UNKNOWN';
|
|
128
|
+
if (/^98[456]/.test(phone)) {
|
|
129
|
+
carrier = 'NTC';
|
|
130
|
+
}
|
|
131
|
+
else if (/^98[012]/.test(phone)) {
|
|
132
|
+
carrier = 'NCELL';
|
|
133
|
+
}
|
|
134
|
+
else if (/^988|^961/.test(phone)) {
|
|
135
|
+
carrier = 'SMART_CELL';
|
|
136
|
+
}
|
|
137
|
+
return {
|
|
138
|
+
raw: match[0],
|
|
139
|
+
cleaned: phone,
|
|
140
|
+
isValid: true,
|
|
141
|
+
carrier
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
exports.extractNepalPhoneNumber = extractNepalPhoneNumber;
|
|
145
|
+
/**
|
|
146
|
+
* Detect Advance Payment & Screenshot proof intents to slash COD cancellation rates.
|
|
147
|
+
*/
|
|
148
|
+
function detectAdvancePaymentIntent(text) {
|
|
149
|
+
const norm = text.toLowerCase();
|
|
150
|
+
const hasAdvance = /advance|rs\.?\s*100|peski|bayana|deposit/.test(norm);
|
|
151
|
+
const hasScreenshot = /screenshot|screen shot|photo|slip|receipt|pathaideko|send gareko/.test(norm);
|
|
152
|
+
return {
|
|
153
|
+
hasAdvanceIntent: hasAdvance || (hasScreenshot && /esewa|fonepay|payment/.test(norm)),
|
|
154
|
+
hasScreenshotProof: hasScreenshot
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
exports.detectAdvancePaymentIntent = detectAdvancePaymentIntent;
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "nepali-messenger-nlp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Zero-dependency NLP parser for Nepali E-Commerce Facebook Messenger chatbots. Detects Romanized Nepali intents, sizes, Kathmandu Ring Road boundaries, phone numbers, and advance COD payment commitments.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc",
|
|
9
|
+
"test": "node -e \"const nlp = require('./dist'); console.log(nlp.parseNepaliIntent('kati parcha delivery charge?'));\""
|
|
10
|
+
},
|
|
11
|
+
"keywords": [
|
|
12
|
+
"nepal",
|
|
13
|
+
"messenger",
|
|
14
|
+
"chatbot",
|
|
15
|
+
"nepali-chatbot",
|
|
16
|
+
"nepali-nlp",
|
|
17
|
+
"ecommerce-nepal",
|
|
18
|
+
"facebook-messenger-ai-chatbot-nepal",
|
|
19
|
+
"sajedar"
|
|
20
|
+
],
|
|
21
|
+
"author": "Sajedar AI <contact@sajedar.com> (https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal)",
|
|
22
|
+
"homepage": "https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/dimanjan/sjdrreimagine.git",
|
|
26
|
+
"directory": "packages/nepali-messenger-nlp"
|
|
27
|
+
},
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal"
|
|
30
|
+
},
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* nepali-messenger-nlp
|
|
3
|
+
* Lightweight, zero-dependency Romanized Nepali intent and entity parser
|
|
4
|
+
* for Facebook Messenger E-Commerce chatbots in Nepal.
|
|
5
|
+
*
|
|
6
|
+
* Maintained by Sajedar: https://www.sajedar.com/facebook-messenger-ai-chatbot-nepal
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export interface IntentResult {
|
|
10
|
+
intent:
|
|
11
|
+
| 'PRICE_INQUIRY'
|
|
12
|
+
| 'DELIVERY_INQUIRY'
|
|
13
|
+
| 'ORDER_PLACEMENT'
|
|
14
|
+
| 'ADVANCE_PAYMENT'
|
|
15
|
+
| 'SIZE_COLOR_INQUIRY'
|
|
16
|
+
| 'HUMAN_SUPPORT'
|
|
17
|
+
| 'GREETING'
|
|
18
|
+
| 'UNKNOWN';
|
|
19
|
+
confidence: number;
|
|
20
|
+
extractedKeywords: string[];
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface LocationClassification {
|
|
24
|
+
locationDetected: string | null;
|
|
25
|
+
zone: 'INSIDE_RING_ROAD' | 'OUTSIDE_RING_ROAD' | 'OUT_OF_VALLEY' | 'UNKNOWN';
|
|
26
|
+
suggestedCourierCharge: number;
|
|
27
|
+
deliveryDaysEstimate: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface PhoneNumberResult {
|
|
31
|
+
raw: string;
|
|
32
|
+
cleaned: string | null;
|
|
33
|
+
isValid: boolean;
|
|
34
|
+
carrier: 'NTC' | 'NCELL' | 'SMART_CELL' | 'UNKNOWN';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const INSIDE_RING_ROAD_AREAS = [
|
|
38
|
+
'new road', 'newroad', 'putalisadak', 'baneshwor', 'thamel', 'dillibazar',
|
|
39
|
+
'maitighar', 'tripureshwor', 'kupondole', 'pulchowk', 'jawalakhel', 'lagankhel',
|
|
40
|
+
'lazimpat', 'baluwatar', 'panipokhari', 'maharajgunj', 'chabahil', 'gaushala',
|
|
41
|
+
'battisputali', 'sankhamul', 'teku', 'kalimati', 'kuleshwor', 'balkhu',
|
|
42
|
+
'sanepa', 'jhamsikhel', 'kumaripati', 'minbhawan', 'anamnagar', 'ghattaghar'
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
const OUTSIDE_RING_ROAD_VALLEY_AREAS = [
|
|
46
|
+
'kapan', 'budhanilkantha', 'tokha', 'gongabu', 'samakhusi', 'machhapokhari',
|
|
47
|
+
'balaju', 'sitapaila', 'kalanki', 'chobhar', 'dhapakhel', 'sunakothi',
|
|
48
|
+
'lubhu', 'imadol', 'tikathali', 'thimi', 'sallaghari', 'bhaktapur',
|
|
49
|
+
'suryabinayak', 'sankhu', 'boudha', 'jorpati', 'dakshinkali', 'godawari'
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
const MAJOR_OUT_OF_VALLEY_CITIES = [
|
|
53
|
+
'pokhara', 'butwal', 'chitwan', 'narayangarh', 'biratnagar', 'dharan',
|
|
54
|
+
'nepalgunj', 'hetauda', 'damak', 'birtamod', 'itahari', 'dhangadhi',
|
|
55
|
+
'surkhet', 'janakpur', 'birgunj', 'bhairahawa'
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Parse Romanized Nepali customer text and determine intent.
|
|
60
|
+
*/
|
|
61
|
+
export function parseNepaliIntent(text: string): IntentResult {
|
|
62
|
+
const normalized = text.toLowerCase().trim();
|
|
63
|
+
const keywords: string[] = [];
|
|
64
|
+
|
|
65
|
+
// Advance Payment / Screenshot Proof intent
|
|
66
|
+
if (
|
|
67
|
+
/screenshot|esewa|fonepay|advance|screen shot|qr code|pay garisake|haldiye|pathaidie/.test(normalized)
|
|
68
|
+
) {
|
|
69
|
+
keywords.push('payment_proof');
|
|
70
|
+
return { intent: 'ADVANCE_PAYMENT', confidence: 0.96, extractedKeywords: keywords };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Price Inquiry
|
|
74
|
+
if (
|
|
75
|
+
/kati parcha|kati ho|price|rate|cost|mulyo|prc|dam kati|kati ma|discount/.test(normalized)
|
|
76
|
+
) {
|
|
77
|
+
keywords.push('pricing');
|
|
78
|
+
return { intent: 'PRICE_INQUIRY', confidence: 0.94, extractedKeywords: keywords };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Delivery & Courier Inquiry
|
|
82
|
+
if (
|
|
83
|
+
/delivery|courier|pathao|ncm|nepal can move|ring road|charge kati|gharma pathaune/.test(normalized)
|
|
84
|
+
) {
|
|
85
|
+
keywords.push('delivery');
|
|
86
|
+
return { intent: 'DELIVERY_INQUIRY', confidence: 0.91, extractedKeywords: keywords };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Order Placement
|
|
90
|
+
if (
|
|
91
|
+
/order|kinna|chaiyo|pathaideu|pathaidinus|confirm|cash on delivery|cod|book garidinu/.test(normalized)
|
|
92
|
+
) {
|
|
93
|
+
keywords.push('order_initiation');
|
|
94
|
+
return { intent: 'ORDER_PLACEMENT', confidence: 0.93, extractedKeywords: keywords };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Size / Color
|
|
98
|
+
if (
|
|
99
|
+
/\b(size|color|colour|xl|xxl|small|medium|large|kalo|rato|seto|blue|black)\b/.test(normalized)
|
|
100
|
+
) {
|
|
101
|
+
keywords.push('variant');
|
|
102
|
+
return { intent: 'SIZE_COLOR_INQUIRY', confidence: 0.88, extractedKeywords: keywords };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Human Supervisor Handoff
|
|
106
|
+
if (
|
|
107
|
+
/human|manche|admin|owner|supervisor|call gar|phone gar|kura garna/.test(normalized)
|
|
108
|
+
) {
|
|
109
|
+
keywords.push('human_handoff');
|
|
110
|
+
return { intent: 'HUMAN_SUPPORT', confidence: 0.95, extractedKeywords: keywords };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Greeting
|
|
114
|
+
if (
|
|
115
|
+
/^(hi|hello|namaste|namaskar|hey|salam|k cha|k chha)\b/.test(normalized)
|
|
116
|
+
) {
|
|
117
|
+
keywords.push('greeting');
|
|
118
|
+
return { intent: 'GREETING', confidence: 0.99, extractedKeywords: keywords };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return { intent: 'UNKNOWN', confidence: 0.3, extractedKeywords: [] };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Classify Nepali delivery locations into shipping zones with courier rate guidance.
|
|
126
|
+
*/
|
|
127
|
+
export function classifyNepalLocation(text: string): LocationClassification {
|
|
128
|
+
const normalized = text.toLowerCase();
|
|
129
|
+
|
|
130
|
+
for (const area of INSIDE_RING_ROAD_AREAS) {
|
|
131
|
+
if (normalized.includes(area)) {
|
|
132
|
+
return {
|
|
133
|
+
locationDetected: area,
|
|
134
|
+
zone: 'INSIDE_RING_ROAD',
|
|
135
|
+
suggestedCourierCharge: 100,
|
|
136
|
+
deliveryDaysEstimate: 'Same day / 24 hours'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
for (const area of OUTSIDE_RING_ROAD_VALLEY_AREAS) {
|
|
142
|
+
if (normalized.includes(area)) {
|
|
143
|
+
return {
|
|
144
|
+
locationDetected: area,
|
|
145
|
+
zone: 'OUTSIDE_RING_ROAD',
|
|
146
|
+
suggestedCourierCharge: 150,
|
|
147
|
+
deliveryDaysEstimate: '24 - 48 hours'
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
for (const city of MAJOR_OUT_OF_VALLEY_CITIES) {
|
|
153
|
+
if (normalized.includes(city)) {
|
|
154
|
+
return {
|
|
155
|
+
locationDetected: city,
|
|
156
|
+
zone: 'OUT_OF_VALLEY',
|
|
157
|
+
suggestedCourierCharge: 200,
|
|
158
|
+
deliveryDaysEstimate: '2 - 4 business days'
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return {
|
|
164
|
+
locationDetected: null,
|
|
165
|
+
zone: 'UNKNOWN',
|
|
166
|
+
suggestedCourierCharge: 150,
|
|
167
|
+
deliveryDaysEstimate: 'Contact store'
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Extract and validate 10-digit Nepali mobile numbers from customer messages.
|
|
173
|
+
*/
|
|
174
|
+
export function extractNepalPhoneNumber(text: string): PhoneNumberResult {
|
|
175
|
+
// Strips +977 or 00977 prefix and searches for 98xxxxxxxx or 97xxxxxxxx
|
|
176
|
+
const regex = /(?:\+?977[-.\s]?)?(9[78]\d{8})\b/;
|
|
177
|
+
const match = text.match(regex);
|
|
178
|
+
|
|
179
|
+
if (!match) {
|
|
180
|
+
return { raw: text, cleaned: null, isValid: false, carrier: 'UNKNOWN' };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const phone = match[1];
|
|
184
|
+
let carrier: PhoneNumberResult['carrier'] = 'UNKNOWN';
|
|
185
|
+
|
|
186
|
+
if (/^98[456]/.test(phone)) {
|
|
187
|
+
carrier = 'NTC';
|
|
188
|
+
} else if (/^98[012]/.test(phone)) {
|
|
189
|
+
carrier = 'NCELL';
|
|
190
|
+
} else if (/^988|^961/.test(phone)) {
|
|
191
|
+
carrier = 'SMART_CELL';
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
raw: match[0],
|
|
196
|
+
cleaned: phone,
|
|
197
|
+
isValid: true,
|
|
198
|
+
carrier
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Detect Advance Payment & Screenshot proof intents to slash COD cancellation rates.
|
|
204
|
+
*/
|
|
205
|
+
export function detectAdvancePaymentIntent(text: string): { hasAdvanceIntent: boolean; hasScreenshotProof: boolean } {
|
|
206
|
+
const norm = text.toLowerCase();
|
|
207
|
+
const hasAdvance = /advance|rs\.?\s*100|peski|bayana|deposit/.test(norm);
|
|
208
|
+
const hasScreenshot = /screenshot|screen shot|photo|slip|receipt|pathaideko|send gareko/.test(norm);
|
|
209
|
+
|
|
210
|
+
return {
|
|
211
|
+
hasAdvanceIntent: hasAdvance || (hasScreenshot && /esewa|fonepay|payment/.test(norm)),
|
|
212
|
+
hasScreenshotProof: hasScreenshot
|
|
213
|
+
};
|
|
214
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"module": "commonjs",
|
|
5
|
+
"declaration": true,
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"rootDir": "./src",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"forceConsistentCasingInFileNames": true
|
|
12
|
+
},
|
|
13
|
+
"include": ["src/**/*"]
|
|
14
|
+
}
|