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 ADDED
@@ -0,0 +1,94 @@
1
+ # nepali-messenger-nlp
2
+
3
+ [![NPM Version](https://img.shields.io/npm/v/nepali-messenger-nlp.svg)](https://www.npmjs.com/package/nepali-messenger-nlp)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](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)
@@ -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
+ }