@warriorteam/redai-zalo-sdk 1.1.1 → 1.2.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/CHANGELOG.md +154 -0
- package/README.md +45 -0
- package/SERVICES_ADDED.md +38 -1
- package/docs/CONSULTATION_SERVICE.md +330 -0
- package/examples/consultation-service-example.ts +390 -0
- package/package.json +15 -5
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.2.0] - 2025-01-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
#### 🆕 ConsultationService - Customer Support Messaging
|
|
13
|
+
- **New Service**: `ConsultationService` for sending customer support messages within 48-hour interaction window
|
|
14
|
+
- **Text Messages**: Send consultation text messages with automatic validation (max 2000 characters)
|
|
15
|
+
- **Image Messages**: Send consultation images for visual support and guides
|
|
16
|
+
- **File Messages**: Send consultation file attachments (manuals, guides, documents)
|
|
17
|
+
- **Sticker Messages**: Send consultation sticker messages for friendly interactions
|
|
18
|
+
- **General Messages**: Send any type of consultation message with unified interface
|
|
19
|
+
|
|
20
|
+
#### 📚 Documentation & Examples
|
|
21
|
+
- **Comprehensive Guide**: New `docs/CONSULTATION_SERVICE.md` with detailed usage instructions
|
|
22
|
+
- **Practical Examples**: New `examples/consultation-service-example.ts` with 6 real-world scenarios
|
|
23
|
+
- **Smart Customer Support**: Example implementation of intelligent customer support bot
|
|
24
|
+
- **Webhook Integration**: Complete webhook integration examples for consultation service
|
|
25
|
+
- **Error Handling**: Detailed error handling and retry mechanism examples
|
|
26
|
+
|
|
27
|
+
#### 🔧 SDK Integration
|
|
28
|
+
- **Quick Access**: Available via `zalo.consultation` property
|
|
29
|
+
- **Quick Methods**: Added `zalo.sendConsultationText()` and `zalo.sendConsultationImage()` convenience methods
|
|
30
|
+
- **Type Safety**: Full TypeScript support with comprehensive type definitions
|
|
31
|
+
- **Error Handling**: Enhanced error handling with `ZaloSDKError` for consultation-specific errors
|
|
32
|
+
|
|
33
|
+
#### 📖 Documentation Updates
|
|
34
|
+
- **README.md**: Updated with ConsultationService examples and documentation links
|
|
35
|
+
- **SERVICES_ADDED.md**: Added detailed ConsultationService documentation
|
|
36
|
+
- **Keywords**: Enhanced package keywords for better discoverability
|
|
37
|
+
|
|
38
|
+
### Technical Details
|
|
39
|
+
|
|
40
|
+
#### Consultation Service Features
|
|
41
|
+
- **48-Hour Window**: Enforces Zalo's 48-hour interaction window for consultation messages
|
|
42
|
+
- **Content Validation**: Automatic validation of message content and format
|
|
43
|
+
- **Quota Management**: Built-in quota tracking and management
|
|
44
|
+
- **Anti-Spam**: Follows Zalo's anti-spam guidelines and best practices
|
|
45
|
+
- **Retry Logic**: Built-in retry mechanism for failed requests
|
|
46
|
+
|
|
47
|
+
#### Usage Conditions
|
|
48
|
+
- Messages must be sent within 48 hours of last user interaction
|
|
49
|
+
- Content must be consultation/support related (no direct advertising)
|
|
50
|
+
- User must have followed the OA and not blocked it
|
|
51
|
+
- No daily limit but must follow anti-spam guidelines
|
|
52
|
+
|
|
53
|
+
#### Integration Points
|
|
54
|
+
- Seamless integration with existing webhook system
|
|
55
|
+
- Compatible with all existing SDK features
|
|
56
|
+
- Follows established SDK patterns and conventions
|
|
57
|
+
- Full backward compatibility maintained
|
|
58
|
+
|
|
59
|
+
### Examples Added
|
|
60
|
+
|
|
61
|
+
1. **Basic Consultation**: Simple text message consultation
|
|
62
|
+
2. **Image Support**: Sending images for visual guidance
|
|
63
|
+
3. **File Attachments**: Sending documents and manuals
|
|
64
|
+
4. **Smart Customer Support**: AI-powered customer support bot
|
|
65
|
+
5. **Retry Mechanism**: Robust error handling and retry logic
|
|
66
|
+
6. **Webhook Integration**: Complete webhook event handling
|
|
67
|
+
|
|
68
|
+
### Files Added/Modified
|
|
69
|
+
|
|
70
|
+
#### New Files
|
|
71
|
+
- `src/services/consultation.service.ts` - Main ConsultationService implementation
|
|
72
|
+
- `docs/CONSULTATION_SERVICE.md` - Comprehensive documentation
|
|
73
|
+
- `examples/consultation-service-example.ts` - Practical examples
|
|
74
|
+
- `CHANGELOG.md` - This changelog file
|
|
75
|
+
|
|
76
|
+
#### Modified Files
|
|
77
|
+
- `README.md` - Added ConsultationService documentation and examples
|
|
78
|
+
- `SERVICES_ADDED.md` - Added ConsultationService details
|
|
79
|
+
- `package.json` - Updated version, description, keywords, and scripts
|
|
80
|
+
- `src/index.ts` - Export ConsultationService types and classes
|
|
81
|
+
- `src/zalo-sdk.ts` - Integrated ConsultationService into main SDK
|
|
82
|
+
|
|
83
|
+
### Breaking Changes
|
|
84
|
+
None. This release maintains full backward compatibility.
|
|
85
|
+
|
|
86
|
+
### Migration Guide
|
|
87
|
+
No migration required. All existing code will continue to work unchanged.
|
|
88
|
+
|
|
89
|
+
To use the new ConsultationService:
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";
|
|
93
|
+
|
|
94
|
+
const zalo = new ZaloSDK({
|
|
95
|
+
appId: "your-app-id",
|
|
96
|
+
appSecret: "your-app-secret"
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Use consultation service
|
|
100
|
+
await zalo.consultation.sendTextMessage(
|
|
101
|
+
accessToken,
|
|
102
|
+
{ user_id: "user-id" },
|
|
103
|
+
{ type: "text", text: "How can I help you?" }
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
// Or use quick methods
|
|
107
|
+
await zalo.sendConsultationText(accessToken, "user-id", "Hello!");
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## [1.1.1] - 2024-12-XX
|
|
113
|
+
|
|
114
|
+
### Fixed
|
|
115
|
+
- Bug fixes and stability improvements
|
|
116
|
+
- Enhanced error handling
|
|
117
|
+
- Documentation updates
|
|
118
|
+
|
|
119
|
+
### Added
|
|
120
|
+
- Additional webhook event types
|
|
121
|
+
- Improved TypeScript definitions
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## [1.1.0] - 2024-11-XX
|
|
126
|
+
|
|
127
|
+
### Added
|
|
128
|
+
- Group Management Service
|
|
129
|
+
- Article Management Service
|
|
130
|
+
- Video Upload Service
|
|
131
|
+
- Enhanced webhook handling
|
|
132
|
+
- Comprehensive documentation
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## [1.0.0] - 2024-10-XX
|
|
137
|
+
|
|
138
|
+
### Added
|
|
139
|
+
- Initial release
|
|
140
|
+
- Official Account API support
|
|
141
|
+
- ZNS (Zalo Notification Service) support
|
|
142
|
+
- Social API support
|
|
143
|
+
- Authentication flow
|
|
144
|
+
- Basic messaging capabilities
|
|
145
|
+
- TypeScript support
|
|
146
|
+
- Comprehensive error handling
|
|
147
|
+
|
|
148
|
+
### Features
|
|
149
|
+
- OAuth 2.0 authentication
|
|
150
|
+
- Message sending (text, image, file, sticker)
|
|
151
|
+
- User management
|
|
152
|
+
- Template management
|
|
153
|
+
- Quota monitoring
|
|
154
|
+
- Webhook event handling
|
package/README.md
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
A comprehensive TypeScript/JavaScript SDK for Zalo APIs, providing easy-to-use interfaces for:
|
|
4
4
|
|
|
5
5
|
- **Official Account (OA) API** - Manage your Zalo Official Account
|
|
6
|
+
- **Consultation Service** - Send customer support messages within 48-hour window
|
|
6
7
|
- **Zalo Notification Service (ZNS)** - Send template-based notification messages
|
|
7
8
|
- **Social API** - Access user social information and authentication
|
|
8
9
|
- **Group Message Framework (GMF)** - Send messages to Zalo groups
|
|
@@ -35,6 +36,7 @@ npm install @warriorteam/redai-zalo-sdk
|
|
|
35
36
|
- **[Services Added](./SERVICES_ADDED.md)** - Detailed breakdown of all services and features
|
|
36
37
|
- **[Group Management](./docs/GROUP_MANAGEMENT.md)** - Group messaging and management
|
|
37
38
|
- **[Article Management](./docs/ARTICLE_MANAGEMENT.md)** - Content and article management
|
|
39
|
+
- **[Consultation Service](./docs/CONSULTATION_SERVICE.md)** - Customer service messaging guide
|
|
38
40
|
|
|
39
41
|
## Development
|
|
40
42
|
|
|
@@ -319,6 +321,49 @@ For support and questions:
|
|
|
319
321
|
- Create an issue on GitHub
|
|
320
322
|
- Contact RedAI team
|
|
321
323
|
|
|
324
|
+
### Consultation Service (Customer Support)
|
|
325
|
+
|
|
326
|
+
```typescript
|
|
327
|
+
// Send consultation text message
|
|
328
|
+
await zalo.consultation.sendTextMessage(accessToken,
|
|
329
|
+
{ user_id: "user-id" },
|
|
330
|
+
{
|
|
331
|
+
type: "text",
|
|
332
|
+
text: "Xin chào! Tôi có thể hỗ trợ gì cho bạn?"
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
// Send consultation image with guide
|
|
337
|
+
await zalo.consultation.sendImageMessage(accessToken,
|
|
338
|
+
{ user_id: "user-id" },
|
|
339
|
+
{
|
|
340
|
+
type: "image",
|
|
341
|
+
attachment: {
|
|
342
|
+
type: "image",
|
|
343
|
+
payload: {
|
|
344
|
+
url: "https://example.com/support-guide.jpg"
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
);
|
|
349
|
+
|
|
350
|
+
// Send file attachment for support
|
|
351
|
+
await zalo.consultation.sendFileMessage(accessToken,
|
|
352
|
+
{ user_id: "user-id" },
|
|
353
|
+
{
|
|
354
|
+
type: "file",
|
|
355
|
+
url: "https://example.com/manual.pdf",
|
|
356
|
+
filename: "User Manual.pdf",
|
|
357
|
+
attachment: {
|
|
358
|
+
type: "file",
|
|
359
|
+
payload: {
|
|
360
|
+
url: "https://example.com/manual.pdf"
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
);
|
|
365
|
+
```
|
|
366
|
+
|
|
322
367
|
### ZNS (Zalo Notification Service)
|
|
323
368
|
|
|
324
369
|
```typescript
|
package/SERVICES_ADDED.md
CHANGED
|
@@ -4,7 +4,44 @@ This document summarizes all the services that have been added to the RedAI Zalo
|
|
|
4
4
|
|
|
5
5
|
## New Services Added
|
|
6
6
|
|
|
7
|
-
### 1.
|
|
7
|
+
### 1. ConsultationService (`src/services/consultation.service.ts`)
|
|
8
|
+
|
|
9
|
+
**Purpose**: Customer Service messaging for sending consultation messages within 48-hour window
|
|
10
|
+
|
|
11
|
+
**Key Features**:
|
|
12
|
+
|
|
13
|
+
- Send consultation text messages
|
|
14
|
+
- Send consultation image messages
|
|
15
|
+
- Send consultation file messages
|
|
16
|
+
- Send consultation sticker messages
|
|
17
|
+
- Send general consultation messages
|
|
18
|
+
- Automatic validation of message content
|
|
19
|
+
- Built-in error handling and retry logic
|
|
20
|
+
- 48-hour interaction window enforcement
|
|
21
|
+
|
|
22
|
+
**Main Methods**:
|
|
23
|
+
|
|
24
|
+
- `sendTextMessage()` - Send consultation text message (max 2000 characters)
|
|
25
|
+
- `sendImageMessage()` - Send consultation image with support content
|
|
26
|
+
- `sendFileMessage()` - Send consultation file attachments (guides, manuals)
|
|
27
|
+
- `sendStickerMessage()` - Send consultation sticker messages
|
|
28
|
+
- `sendMessage()` - Send any type of consultation message
|
|
29
|
+
|
|
30
|
+
**Usage Conditions**:
|
|
31
|
+
|
|
32
|
+
- Must be sent within 48 hours of last user interaction
|
|
33
|
+
- Content must be consultation/support related (no direct advertising)
|
|
34
|
+
- User must have followed the OA and not blocked it
|
|
35
|
+
- No daily limit but must follow anti-spam guidelines
|
|
36
|
+
|
|
37
|
+
**Integration**:
|
|
38
|
+
|
|
39
|
+
- Accessible via `zalo.consultation` property
|
|
40
|
+
- Quick methods: `zalo.sendConsultationText()`, `zalo.sendConsultationImage()`
|
|
41
|
+
- Full webhook integration support
|
|
42
|
+
- Comprehensive error handling with ZaloSDKError
|
|
43
|
+
|
|
44
|
+
### 2. ZNSService (`src/services/zns.service.ts`)
|
|
8
45
|
|
|
9
46
|
**Purpose**: Zalo Notification Service for sending template-based notifications
|
|
10
47
|
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
# Consultation Service - Hướng Dẫn Sử Dụng
|
|
2
|
+
|
|
3
|
+
## Tổng Quan
|
|
4
|
+
|
|
5
|
+
`ConsultationService` là dịch vụ chuyên dụng để gửi tin nhắn tư vấn (Customer Service) qua Zalo Official Account. Tin nhắn tư vấn cho phép OA gửi tin nhắn chủ động đến người dùng trong khung thời gian nhất định để hỗ trợ và tư vấn khách hàng.
|
|
6
|
+
|
|
7
|
+
## Điều Kiện Gửi Tin Nhắn Tư Vấn
|
|
8
|
+
|
|
9
|
+
### 1. Thời Gian Gửi
|
|
10
|
+
- **Khung thời gian**: Chỉ được gửi trong vòng **48 giờ** kể từ khi người dùng tương tác cuối cùng với OA
|
|
11
|
+
- **Tương tác bao gồm**:
|
|
12
|
+
- Gửi tin nhắn đến OA
|
|
13
|
+
- Nhấn button/quick reply
|
|
14
|
+
- Gọi điện thoại từ OA
|
|
15
|
+
- Truy cập website từ OA
|
|
16
|
+
|
|
17
|
+
### 2. Nội Dung Tin Nhắn
|
|
18
|
+
- **Mục đích**: Phải liên quan đến tư vấn, hỗ trợ khách hàng
|
|
19
|
+
- **Bao gồm**: Trả lời câu hỏi, hướng dẫn sử dụng, hỗ trợ kỹ thuật
|
|
20
|
+
- **Không được**: Chứa nội dung quảng cáo trực tiếp
|
|
21
|
+
|
|
22
|
+
### 3. Điều Kiện Người Dùng
|
|
23
|
+
- Người dùng phải đã follow OA
|
|
24
|
+
- Người dùng không được block OA
|
|
25
|
+
- Người dùng phải có tương tác gần đây với OA
|
|
26
|
+
|
|
27
|
+
### 4. Tần Suất Gửi
|
|
28
|
+
- Không giới hạn số lượng tin nhắn tư vấn trong ngày
|
|
29
|
+
- Cần tuân thủ nguyên tắc không spam
|
|
30
|
+
|
|
31
|
+
## Khởi Tạo Service
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { ZaloSDK } from "@warriorteam/redai-zalo-sdk";
|
|
35
|
+
|
|
36
|
+
const zalo = new ZaloSDK({
|
|
37
|
+
appId: "your-app-id",
|
|
38
|
+
appSecret: "your-app-secret",
|
|
39
|
+
debug: true
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Lấy consultation service
|
|
43
|
+
const consultationService = zalo.consultation;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Các Phương Thức Chính
|
|
47
|
+
|
|
48
|
+
### 1. Gửi Tin Nhắn Văn Bản
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Gửi tin nhắn văn bản tư vấn
|
|
52
|
+
const response = await consultationService.sendTextMessage(
|
|
53
|
+
accessToken,
|
|
54
|
+
{ user_id: "user-id-here" },
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: "Xin chào! Tôi có thể hỗ trợ gì cho bạn?"
|
|
58
|
+
}
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
console.log("Message ID:", response.message_id);
|
|
62
|
+
console.log("Quota remaining:", response.quota?.remain);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Giới hạn văn bản:**
|
|
66
|
+
- Nội dung không được để trống
|
|
67
|
+
- Tối đa 2000 ký tự
|
|
68
|
+
|
|
69
|
+
### 2. Gửi Tin Nhắn Hình Ảnh
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Gửi hình ảnh tư vấn
|
|
73
|
+
const response = await consultationService.sendImageMessage(
|
|
74
|
+
accessToken,
|
|
75
|
+
{ user_id: "user-id-here" },
|
|
76
|
+
{
|
|
77
|
+
type: "image",
|
|
78
|
+
attachment: {
|
|
79
|
+
type: "image",
|
|
80
|
+
payload: {
|
|
81
|
+
url: "https://example.com/support-image.jpg"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 3. Gửi File Đính Kèm
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
// Gửi file hướng dẫn
|
|
92
|
+
const response = await consultationService.sendFileMessage(
|
|
93
|
+
accessToken,
|
|
94
|
+
{ user_id: "user-id-here" },
|
|
95
|
+
{
|
|
96
|
+
type: "file",
|
|
97
|
+
url: "https://example.com/user-manual.pdf",
|
|
98
|
+
filename: "Hướng dẫn sử dụng.pdf",
|
|
99
|
+
attachment: {
|
|
100
|
+
type: "file",
|
|
101
|
+
payload: {
|
|
102
|
+
url: "https://example.com/user-manual.pdf"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### 4. Gửi Sticker
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Gửi sticker thân thiện
|
|
113
|
+
const response = await consultationService.sendStickerMessage(
|
|
114
|
+
accessToken,
|
|
115
|
+
{ user_id: "user-id-here" },
|
|
116
|
+
{
|
|
117
|
+
type: "sticker",
|
|
118
|
+
sticker_id: "sticker-id",
|
|
119
|
+
attachment: {
|
|
120
|
+
type: "sticker",
|
|
121
|
+
payload: {
|
|
122
|
+
id: "sticker-id"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### 5. Gửi Tin Nhắn Tổng Quát
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
// Gửi bất kỳ loại tin nhắn nào
|
|
133
|
+
const response = await consultationService.sendMessage(
|
|
134
|
+
accessToken,
|
|
135
|
+
{ user_id: "user-id-here" },
|
|
136
|
+
{
|
|
137
|
+
type: "text",
|
|
138
|
+
text: "Cảm ơn bạn đã liên hệ. Chúng tôi sẽ hỗ trợ bạn ngay!"
|
|
139
|
+
}
|
|
140
|
+
);
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Xử Lý Lỗi
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
import { ZaloSDKError } from "@warriorteam/redai-zalo-sdk";
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
const response = await consultationService.sendTextMessage(
|
|
150
|
+
accessToken,
|
|
151
|
+
{ user_id: "user-id" },
|
|
152
|
+
{ type: "text", text: "Hello!" }
|
|
153
|
+
);
|
|
154
|
+
} catch (error) {
|
|
155
|
+
if (error instanceof ZaloSDKError) {
|
|
156
|
+
console.error("Zalo API Error:", error.message);
|
|
157
|
+
console.error("Error Code:", error.code);
|
|
158
|
+
|
|
159
|
+
// Xử lý các lỗi phổ biến
|
|
160
|
+
switch (error.code) {
|
|
161
|
+
case -216:
|
|
162
|
+
console.log("Access token không hợp lệ");
|
|
163
|
+
break;
|
|
164
|
+
case -201:
|
|
165
|
+
console.log("Tham số không hợp lệ");
|
|
166
|
+
break;
|
|
167
|
+
case -223:
|
|
168
|
+
console.log("Đã vượt quá quota");
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
console.log("Lỗi khác:", error.message);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Ví Dụ Thực Tế
|
|
178
|
+
|
|
179
|
+
### Hệ Thống Hỗ Trợ Khách Hàng
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
class CustomerSupportBot {
|
|
183
|
+
constructor(private consultationService: ConsultationService) {}
|
|
184
|
+
|
|
185
|
+
async handleUserQuestion(accessToken: string, userId: string, question: string) {
|
|
186
|
+
try {
|
|
187
|
+
// Phân tích câu hỏi và tạo phản hồi
|
|
188
|
+
const response = this.generateResponse(question);
|
|
189
|
+
|
|
190
|
+
// Gửi tin nhắn tư vấn
|
|
191
|
+
await this.consultationService.sendTextMessage(
|
|
192
|
+
accessToken,
|
|
193
|
+
{ user_id: userId },
|
|
194
|
+
{
|
|
195
|
+
type: "text",
|
|
196
|
+
text: response
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
// Gửi thêm hình ảnh hướng dẫn nếu cần
|
|
201
|
+
if (this.needsVisualGuide(question)) {
|
|
202
|
+
await this.consultationService.sendImageMessage(
|
|
203
|
+
accessToken,
|
|
204
|
+
{ user_id: userId },
|
|
205
|
+
{
|
|
206
|
+
type: "image",
|
|
207
|
+
attachment: {
|
|
208
|
+
type: "image",
|
|
209
|
+
payload: {
|
|
210
|
+
url: "https://example.com/guide-image.jpg"
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.error("Failed to send consultation message:", error);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
private generateResponse(question: string): string {
|
|
223
|
+
// Logic tạo phản hồi dựa trên câu hỏi
|
|
224
|
+
if (question.includes("đăng nhập")) {
|
|
225
|
+
return "Để đăng nhập, bạn vui lòng làm theo các bước sau...";
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (question.includes("thanh toán")) {
|
|
229
|
+
return "Về vấn đề thanh toán, chúng tôi hỗ trợ các phương thức...";
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return "Cảm ơn bạn đã liên hệ. Chúng tôi sẽ hỗ trợ bạn ngay!";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private needsVisualGuide(question: string): boolean {
|
|
236
|
+
return question.includes("hướng dẫn") || question.includes("cách làm");
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### Tích Hợp Với Webhook
|
|
242
|
+
|
|
243
|
+
```typescript
|
|
244
|
+
// Xử lý tin nhắn từ webhook
|
|
245
|
+
app.post('/webhook', async (req, res) => {
|
|
246
|
+
const event = req.body;
|
|
247
|
+
|
|
248
|
+
if (event.event_name === 'user_send_text') {
|
|
249
|
+
const userId = event.sender.id;
|
|
250
|
+
const userMessage = event.message.text;
|
|
251
|
+
|
|
252
|
+
// Kiểm tra xem có phải câu hỏi cần hỗ trợ không
|
|
253
|
+
if (userMessage.includes('help') || userMessage.includes('hỗ trợ')) {
|
|
254
|
+
|
|
255
|
+
// Gửi tin nhắn tư vấn
|
|
256
|
+
await consultationService.sendTextMessage(
|
|
257
|
+
accessToken,
|
|
258
|
+
{ user_id: userId },
|
|
259
|
+
{
|
|
260
|
+
type: "text",
|
|
261
|
+
text: "Tôi có thể hỗ trợ bạn về các vấn đề sau:\n1. Đăng nhập\n2. Thanh toán\n3. Sử dụng sản phẩm\nBạn cần hỗ trợ về vấn đề nào?"
|
|
262
|
+
}
|
|
263
|
+
);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
res.status(200).send('OK');
|
|
268
|
+
});
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
## Best Practices
|
|
272
|
+
|
|
273
|
+
### 1. Kiểm Tra Thời Gian Tương Tác
|
|
274
|
+
```typescript
|
|
275
|
+
// Kiểm tra thời gian tương tác cuối cùng trước khi gửi
|
|
276
|
+
const lastInteraction = await getUserLastInteraction(userId);
|
|
277
|
+
const hoursSinceLastInteraction = (Date.now() - lastInteraction) / (1000 * 60 * 60);
|
|
278
|
+
|
|
279
|
+
if (hoursSinceLastInteraction > 48) {
|
|
280
|
+
console.log("Không thể gửi tin nhắn tư vấn - quá 48 giờ");
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### 2. Quản Lý Quota
|
|
286
|
+
```typescript
|
|
287
|
+
// Kiểm tra quota trước khi gửi
|
|
288
|
+
const quota = await zalo.oa.getQuotaSummary(accessToken);
|
|
289
|
+
if (quota.consultation.remaining <= 0) {
|
|
290
|
+
console.log("Đã hết quota tin nhắn tư vấn");
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 3. Retry Logic
|
|
296
|
+
```typescript
|
|
297
|
+
async function sendWithRetry(
|
|
298
|
+
consultationService: ConsultationService,
|
|
299
|
+
accessToken: string,
|
|
300
|
+
recipient: MessageRecipient,
|
|
301
|
+
message: Message,
|
|
302
|
+
maxRetries = 3
|
|
303
|
+
) {
|
|
304
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
305
|
+
try {
|
|
306
|
+
return await consultationService.sendMessage(accessToken, recipient, message);
|
|
307
|
+
} catch (error) {
|
|
308
|
+
if (i === maxRetries - 1) throw error;
|
|
309
|
+
|
|
310
|
+
// Đợi trước khi retry
|
|
311
|
+
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
## Lưu Ý Quan Trọng
|
|
318
|
+
|
|
319
|
+
1. **Tuân thủ chính sách**: Chỉ gửi tin nhắn tư vấn thực sự, không spam
|
|
320
|
+
2. **Theo dõi quota**: Kiểm tra quota thường xuyên để tránh vượt giới hạn
|
|
321
|
+
3. **Xử lý lỗi**: Luôn có cơ chế xử lý lỗi phù hợp
|
|
322
|
+
4. **Logging**: Ghi log để theo dõi và debug
|
|
323
|
+
5. **Rate limiting**: Tránh gửi quá nhiều tin nhắn trong thời gian ngắn
|
|
324
|
+
|
|
325
|
+
## Tài Liệu Liên Quan
|
|
326
|
+
|
|
327
|
+
- [Message Types](./MESSAGE_TYPES.md) - Các loại tin nhắn được hỗ trợ
|
|
328
|
+
- [Webhook Events](./WEBHOOK_EVENTS.md) - Xử lý sự kiện webhook
|
|
329
|
+
- [Error Handling](./ERROR_HANDLING.md) - Xử lý lỗi chi tiết
|
|
330
|
+
- [Quota Management](./QUOTA_MANAGEMENT.md) - Quản lý quota tin nhắn
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ví dụ sử dụng ConsultationService - Dịch vụ tin nhắn tư vấn
|
|
3
|
+
*
|
|
4
|
+
* Ví dụ này minh họa cách sử dụng ConsultationService để:
|
|
5
|
+
* - Gửi tin nhắn tư vấn văn bản
|
|
6
|
+
* - Gửi hình ảnh hỗ trợ
|
|
7
|
+
* - Gửi file hướng dẫn
|
|
8
|
+
* - Xử lý lỗi và retry
|
|
9
|
+
* - Tích hợp với webhook
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { ZaloSDK, ZaloSDKError, SendMessageResponse } from "../src/index";
|
|
13
|
+
|
|
14
|
+
// Cấu hình SDK
|
|
15
|
+
const zalo = new ZaloSDK({
|
|
16
|
+
appId: "your-app-id",
|
|
17
|
+
appSecret: "your-app-secret",
|
|
18
|
+
debug: true
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
// Access token của OA (lấy từ quá trình authentication)
|
|
22
|
+
const ACCESS_TOKEN = "your-oa-access-token";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Ví dụ 1: Gửi tin nhắn tư vấn cơ bản
|
|
26
|
+
*/
|
|
27
|
+
async function basicConsultationExample() {
|
|
28
|
+
console.log("=== Ví dụ 1: Tin nhắn tư vấn cơ bản ===");
|
|
29
|
+
|
|
30
|
+
try {
|
|
31
|
+
// Gửi tin nhắn văn bản tư vấn
|
|
32
|
+
const response = await zalo.consultation.sendTextMessage(
|
|
33
|
+
ACCESS_TOKEN,
|
|
34
|
+
{ user_id: "user-id-here" },
|
|
35
|
+
{
|
|
36
|
+
type: "text",
|
|
37
|
+
text: "Xin chào! Cảm ơn bạn đã liên hệ với chúng tôi. Tôi có thể hỗ trợ gì cho bạn hôm nay?"
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
console.log("✅ Gửi tin nhắn thành công!");
|
|
42
|
+
console.log("Message ID:", response.message_id);
|
|
43
|
+
console.log("User ID:", response.user_id);
|
|
44
|
+
|
|
45
|
+
if (response.quota) {
|
|
46
|
+
console.log("Quota còn lại:", response.quota.remain);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
} catch (error) {
|
|
50
|
+
if (error instanceof ZaloSDKError) {
|
|
51
|
+
console.error("❌ Lỗi Zalo API:", error.message);
|
|
52
|
+
console.error("Mã lỗi:", error.code);
|
|
53
|
+
} else {
|
|
54
|
+
console.error("❌ Lỗi không xác định:", error);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Ví dụ 2: Gửi hình ảnh hỗ trợ
|
|
61
|
+
*/
|
|
62
|
+
async function imageConsultationExample() {
|
|
63
|
+
console.log("\n=== Ví dụ 2: Gửi hình ảnh hỗ trợ ===");
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const response = await zalo.consultation.sendImageMessage(
|
|
67
|
+
ACCESS_TOKEN,
|
|
68
|
+
{ user_id: "user-id-here" },
|
|
69
|
+
{
|
|
70
|
+
type: "image",
|
|
71
|
+
attachment: {
|
|
72
|
+
type: "image",
|
|
73
|
+
payload: {
|
|
74
|
+
url: "https://example.com/support-guide.jpg"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
console.log("✅ Gửi hình ảnh hỗ trợ thành công!");
|
|
81
|
+
console.log("Message ID:", response.message_id);
|
|
82
|
+
|
|
83
|
+
} catch (error) {
|
|
84
|
+
console.error("❌ Lỗi gửi hình ảnh:", error);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Ví dụ 3: Gửi file hướng dẫn
|
|
90
|
+
*/
|
|
91
|
+
async function fileConsultationExample() {
|
|
92
|
+
console.log("\n=== Ví dụ 3: Gửi file hướng dẫn ===");
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const response = await zalo.consultation.sendFileMessage(
|
|
96
|
+
ACCESS_TOKEN,
|
|
97
|
+
{ user_id: "user-id-here" },
|
|
98
|
+
{
|
|
99
|
+
type: "file",
|
|
100
|
+
url: "https://example.com/user-manual.pdf",
|
|
101
|
+
filename: "Hướng dẫn sử dụng.pdf",
|
|
102
|
+
attachment: {
|
|
103
|
+
type: "file",
|
|
104
|
+
payload: {
|
|
105
|
+
url: "https://example.com/user-manual.pdf"
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
console.log("✅ Gửi file hướng dẫn thành công!");
|
|
112
|
+
console.log("Message ID:", response.message_id);
|
|
113
|
+
|
|
114
|
+
} catch (error) {
|
|
115
|
+
console.error("❌ Lỗi gửi file:", error);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Ví dụ 4: Hệ thống hỗ trợ khách hàng thông minh
|
|
121
|
+
*/
|
|
122
|
+
class SmartCustomerSupport {
|
|
123
|
+
private zalo: ZaloSDK;
|
|
124
|
+
private accessToken: string;
|
|
125
|
+
|
|
126
|
+
constructor(zalo: ZaloSDK, accessToken: string) {
|
|
127
|
+
this.zalo = zalo;
|
|
128
|
+
this.accessToken = accessToken;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Xử lý câu hỏi của khách hàng
|
|
133
|
+
*/
|
|
134
|
+
async handleCustomerQuestion(userId: string, question: string) {
|
|
135
|
+
console.log(`\n📞 Xử lý câu hỏi từ user ${userId}: "${question}"`);
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
// Phân tích câu hỏi và tạo phản hồi
|
|
139
|
+
const response = this.analyzeQuestion(question);
|
|
140
|
+
|
|
141
|
+
// Gửi tin nhắn phản hồi
|
|
142
|
+
await this.zalo.consultation.sendTextMessage(
|
|
143
|
+
this.accessToken,
|
|
144
|
+
{ user_id: userId },
|
|
145
|
+
{
|
|
146
|
+
type: "text",
|
|
147
|
+
text: response.text
|
|
148
|
+
}
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Gửi thêm tài liệu hỗ trợ nếu cần
|
|
152
|
+
if (response.needsDocument) {
|
|
153
|
+
await this.sendSupportDocument(userId, response.documentType);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
console.log("✅ Đã phản hồi khách hàng thành công!");
|
|
157
|
+
|
|
158
|
+
} catch (error) {
|
|
159
|
+
console.error("❌ Lỗi xử lý câu hỏi khách hàng:", error);
|
|
160
|
+
|
|
161
|
+
// Gửi tin nhắn lỗi cho khách hàng
|
|
162
|
+
await this.sendErrorMessage(userId);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Phân tích câu hỏi và tạo phản hồi
|
|
168
|
+
*/
|
|
169
|
+
private analyzeQuestion(question: string) {
|
|
170
|
+
const lowerQuestion = question.toLowerCase();
|
|
171
|
+
|
|
172
|
+
if (lowerQuestion.includes("đăng nhập") || lowerQuestion.includes("login")) {
|
|
173
|
+
return {
|
|
174
|
+
text: "Để đăng nhập vào hệ thống, bạn vui lòng:\n1. Truy cập trang đăng nhập\n2. Nhập email và mật khẩu\n3. Nhấn 'Đăng nhập'\n\nNếu quên mật khẩu, bạn có thể sử dụng chức năng 'Quên mật khẩu'.",
|
|
175
|
+
needsDocument: true,
|
|
176
|
+
documentType: "login_guide"
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (lowerQuestion.includes("thanh toán") || lowerQuestion.includes("payment")) {
|
|
181
|
+
return {
|
|
182
|
+
text: "Chúng tôi hỗ trợ các phương thức thanh toán sau:\n• Thẻ tín dụng/ghi nợ\n• Ví điện tử (MoMo, ZaloPay)\n• Chuyển khoản ngân hàng\n• Thanh toán khi nhận hàng (COD)\n\nBạn cần hỗ trợ về phương thức nào?",
|
|
183
|
+
needsDocument: true,
|
|
184
|
+
documentType: "payment_guide"
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (lowerQuestion.includes("giao hàng") || lowerQuestion.includes("shipping")) {
|
|
189
|
+
return {
|
|
190
|
+
text: "Thông tin về giao hàng:\n• Nội thành: 1-2 ngày\n• Ngoại thành: 2-3 ngày\n• Tỉnh khác: 3-5 ngày\n\nPhí ship được tính theo khoảng cách và trọng lượng đơn hàng.",
|
|
191
|
+
needsDocument: false,
|
|
192
|
+
documentType: null
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// Phản hồi mặc định
|
|
197
|
+
return {
|
|
198
|
+
text: "Cảm ơn bạn đã liên hệ! Tôi đã ghi nhận câu hỏi của bạn. Đội ngũ hỗ trợ sẽ phản hồi trong vòng 24 giờ.\n\nCác vấn đề phổ biến:\n• Đăng nhập\n• Thanh toán\n• Giao hàng\n• Đổi trả\n\nBạn có thể hỏi cụ thể về các vấn đề này để được hỗ trợ nhanh hơn.",
|
|
199
|
+
needsDocument: false,
|
|
200
|
+
documentType: null
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Gửi tài liệu hỗ trợ
|
|
206
|
+
*/
|
|
207
|
+
private async sendSupportDocument(userId: string, documentType: string) {
|
|
208
|
+
const documents = {
|
|
209
|
+
login_guide: {
|
|
210
|
+
url: "https://example.com/guides/login-guide.pdf",
|
|
211
|
+
filename: "Hướng dẫn đăng nhập.pdf"
|
|
212
|
+
},
|
|
213
|
+
payment_guide: {
|
|
214
|
+
url: "https://example.com/guides/payment-guide.pdf",
|
|
215
|
+
filename: "Hướng dẫn thanh toán.pdf"
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
const doc = documents[documentType as keyof typeof documents];
|
|
220
|
+
if (!doc) return;
|
|
221
|
+
|
|
222
|
+
await this.zalo.consultation.sendFileMessage(
|
|
223
|
+
this.accessToken,
|
|
224
|
+
{ user_id: userId },
|
|
225
|
+
{
|
|
226
|
+
type: "file",
|
|
227
|
+
url: doc.url,
|
|
228
|
+
filename: doc.filename,
|
|
229
|
+
attachment: {
|
|
230
|
+
type: "file",
|
|
231
|
+
payload: {
|
|
232
|
+
url: doc.url
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Gửi tin nhắn lỗi
|
|
241
|
+
*/
|
|
242
|
+
private async sendErrorMessage(userId: string) {
|
|
243
|
+
try {
|
|
244
|
+
await this.zalo.consultation.sendTextMessage(
|
|
245
|
+
this.accessToken,
|
|
246
|
+
{ user_id: userId },
|
|
247
|
+
{
|
|
248
|
+
type: "text",
|
|
249
|
+
text: "Xin lỗi, hiện tại hệ thống đang gặp sự cố. Vui lòng thử lại sau hoặc liên hệ hotline: 1900-xxxx để được hỗ trợ trực tiếp."
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
} catch (error) {
|
|
253
|
+
console.error("❌ Không thể gửi tin nhắn lỗi:", error);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/**
|
|
259
|
+
* Ví dụ 5: Retry mechanism
|
|
260
|
+
*/
|
|
261
|
+
async function sendWithRetry(
|
|
262
|
+
userId: string,
|
|
263
|
+
message: string,
|
|
264
|
+
maxRetries: number = 3
|
|
265
|
+
): Promise<SendMessageResponse | null> {
|
|
266
|
+
console.log(`\n🔄 Gửi tin nhắn với retry (tối đa ${maxRetries} lần)`);
|
|
267
|
+
|
|
268
|
+
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
269
|
+
try {
|
|
270
|
+
console.log(`Lần thử ${attempt}/${maxRetries}`);
|
|
271
|
+
|
|
272
|
+
const response = await zalo.consultation.sendTextMessage(
|
|
273
|
+
ACCESS_TOKEN,
|
|
274
|
+
{ user_id: userId },
|
|
275
|
+
{ type: "text", text: message }
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
console.log("✅ Gửi thành công!");
|
|
279
|
+
return response;
|
|
280
|
+
|
|
281
|
+
} catch (error) {
|
|
282
|
+
console.log(`❌ Lần thử ${attempt} thất bại:`, error instanceof ZaloSDKError ? error.message : error);
|
|
283
|
+
|
|
284
|
+
if (attempt === maxRetries) {
|
|
285
|
+
console.log("❌ Đã thử hết số lần cho phép");
|
|
286
|
+
return null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Đợi trước khi thử lại (exponential backoff)
|
|
290
|
+
const delay = Math.pow(2, attempt) * 1000;
|
|
291
|
+
console.log(`⏳ Đợi ${delay}ms trước khi thử lại...`);
|
|
292
|
+
await new Promise(resolve => setTimeout(resolve, delay));
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Ví dụ 6: Tích hợp với webhook
|
|
301
|
+
*/
|
|
302
|
+
function setupWebhookIntegration() {
|
|
303
|
+
console.log("\n🔗 Thiết lập tích hợp webhook");
|
|
304
|
+
|
|
305
|
+
const customerSupport = new SmartCustomerSupport(zalo, ACCESS_TOKEN);
|
|
306
|
+
|
|
307
|
+
// Giả lập xử lý webhook event
|
|
308
|
+
const handleWebhookEvent = async (event: any) => {
|
|
309
|
+
console.log("📨 Nhận webhook event:", event.event_name);
|
|
310
|
+
|
|
311
|
+
switch (event.event_name) {
|
|
312
|
+
case "user_send_text":
|
|
313
|
+
const userId = event.sender.id;
|
|
314
|
+
const userMessage = event.message.text;
|
|
315
|
+
|
|
316
|
+
// Kiểm tra xem có phải câu hỏi cần hỗ trợ không
|
|
317
|
+
if (userMessage.includes("help") ||
|
|
318
|
+
userMessage.includes("hỗ trợ") ||
|
|
319
|
+
userMessage.includes("support")) {
|
|
320
|
+
|
|
321
|
+
await customerSupport.handleCustomerQuestion(userId, userMessage);
|
|
322
|
+
}
|
|
323
|
+
break;
|
|
324
|
+
|
|
325
|
+
case "user_send_sticker":
|
|
326
|
+
// Phản hồi sticker bằng tin nhắn thân thiện
|
|
327
|
+
await zalo.consultation.sendTextMessage(
|
|
328
|
+
ACCESS_TOKEN,
|
|
329
|
+
{ user_id: event.sender.id },
|
|
330
|
+
{
|
|
331
|
+
type: "text",
|
|
332
|
+
text: "Cảm ơn bạn! 😊 Tôi có thể hỗ trợ gì cho bạn không?"
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
break;
|
|
336
|
+
|
|
337
|
+
default:
|
|
338
|
+
console.log("Event không cần xử lý:", event.event_name);
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
return handleWebhookEvent;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Chạy tất cả ví dụ
|
|
347
|
+
*/
|
|
348
|
+
async function runAllExamples() {
|
|
349
|
+
console.log("🚀 Bắt đầu chạy các ví dụ ConsultationService\n");
|
|
350
|
+
|
|
351
|
+
// Ví dụ cơ bản
|
|
352
|
+
await basicConsultationExample();
|
|
353
|
+
await imageConsultationExample();
|
|
354
|
+
await fileConsultationExample();
|
|
355
|
+
|
|
356
|
+
// Ví dụ hệ thống hỗ trợ thông minh
|
|
357
|
+
const customerSupport = new SmartCustomerSupport(zalo, ACCESS_TOKEN);
|
|
358
|
+
await customerSupport.handleCustomerQuestion("user123", "Tôi không đăng nhập được");
|
|
359
|
+
await customerSupport.handleCustomerQuestion("user456", "Làm sao để thanh toán?");
|
|
360
|
+
|
|
361
|
+
// Ví dụ retry
|
|
362
|
+
await sendWithRetry("user789", "Tin nhắn test retry");
|
|
363
|
+
|
|
364
|
+
// Thiết lập webhook
|
|
365
|
+
const webhookHandler = setupWebhookIntegration();
|
|
366
|
+
|
|
367
|
+
// Giả lập một số webhook events
|
|
368
|
+
await webhookHandler({
|
|
369
|
+
event_name: "user_send_text",
|
|
370
|
+
sender: { id: "user123" },
|
|
371
|
+
message: { text: "Tôi cần hỗ trợ về đăng nhập" }
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
console.log("\n✅ Hoàn thành tất cả ví dụ!");
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Chạy ví dụ nếu file được execute trực tiếp
|
|
378
|
+
if (require.main === module) {
|
|
379
|
+
runAllExamples().catch(console.error);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export {
|
|
383
|
+
basicConsultationExample,
|
|
384
|
+
imageConsultationExample,
|
|
385
|
+
fileConsultationExample,
|
|
386
|
+
SmartCustomerSupport,
|
|
387
|
+
sendWithRetry,
|
|
388
|
+
setupWebhookIntegration,
|
|
389
|
+
runAllExamples
|
|
390
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@warriorteam/redai-zalo-sdk",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Comprehensive TypeScript/JavaScript SDK for Zalo APIs - Official Account, ZNS, Consultation Service, Group Messaging, and Social APIs",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"scripts": {
|
|
@@ -9,6 +9,11 @@
|
|
|
9
9
|
"dev": "tsc --watch",
|
|
10
10
|
"clean": "rimraf dist",
|
|
11
11
|
"prepublishOnly": "npm run clean && npm run build",
|
|
12
|
+
"publish:npm": "npm publish --access public",
|
|
13
|
+
"publish:beta": "npm publish --tag beta --access public",
|
|
14
|
+
"version:patch": "npm version patch",
|
|
15
|
+
"version:minor": "npm version minor",
|
|
16
|
+
"version:major": "npm version major",
|
|
12
17
|
"test": "jest",
|
|
13
18
|
"lint": "eslint src/**/*.ts",
|
|
14
19
|
"lint:fix": "eslint src/**/*.ts --fix"
|
|
@@ -21,13 +26,16 @@
|
|
|
21
26
|
"zalo-sdk",
|
|
22
27
|
"typescript",
|
|
23
28
|
"official-account",
|
|
24
|
-
"notification-service"
|
|
29
|
+
"notification-service",
|
|
30
|
+
"consultation-service",
|
|
31
|
+
"customer-support",
|
|
32
|
+
"messaging"
|
|
25
33
|
],
|
|
26
34
|
"author": "RedAI Team",
|
|
27
35
|
"license": "MIT",
|
|
28
36
|
"repository": {
|
|
29
37
|
"type": "git",
|
|
30
|
-
"url": "https://github.com/
|
|
38
|
+
"url": "https://github.com/warriorteam/redai-zalo-sdk.git"
|
|
31
39
|
},
|
|
32
40
|
"bugs": {
|
|
33
41
|
"url": "https://github.com/redai/redai-zalo-sdk/issues"
|
|
@@ -53,8 +61,10 @@
|
|
|
53
61
|
"README.md",
|
|
54
62
|
"LICENSE",
|
|
55
63
|
"docs/**/*",
|
|
64
|
+
"examples/**/*",
|
|
56
65
|
"ARCHITECTURE.md",
|
|
57
|
-
"SERVICES_ADDED.md"
|
|
66
|
+
"SERVICES_ADDED.md",
|
|
67
|
+
"CHANGELOG.md"
|
|
58
68
|
],
|
|
59
69
|
"engines": {
|
|
60
70
|
"node": ">=16.0.0"
|