@warriorteam/redai-zalo-sdk 1.26.1 → 1.27.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.
@@ -1,390 +0,0 @@
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
- };
@@ -1,171 +0,0 @@
1
- /**
2
- * Example: How to use the enhanced getAllArticles and getAllArticlesCombined methods
3
- *
4
- * This example demonstrates the new custom API methods that can fetch all articles
5
- * automatically by handling pagination internally.
6
- */
7
-
8
- import { ArticleService } from "../src/services/article.service";
9
- import { ZaloClient } from "../src/clients/zalo-client";
10
-
11
- // Initialize the services
12
- const zaloClient = new ZaloClient();
13
- const articleService = new ArticleService(zaloClient);
14
-
15
- // Your access token
16
- const ACCESS_TOKEN = "your-access-token-here";
17
-
18
- /**
19
- * Example 1: Get all normal articles with progress tracking
20
- */
21
- async function getAllNormalArticlesExample() {
22
- console.log("=== Getting All Normal Articles ===");
23
-
24
- try {
25
- const result = await articleService.getAllArticles(ACCESS_TOKEN, "normal", {
26
- batchSize: 50, // Fetch 50 articles per API call
27
- maxArticles: 1000, // Stop after 1000 articles (0 = no limit)
28
- onProgress: (progress) => {
29
- console.log(`📄 Batch ${progress.currentBatch}: ${progress.totalFetched} articles fetched, hasMore: ${progress.hasMore}`);
30
- }
31
- });
32
-
33
- console.log(`✅ Completed! Total: ${result.totalFetched} normal articles in ${result.totalBatches} batches`);
34
- console.log(`📊 Has more articles available: ${result.hasMore}`);
35
-
36
- // Access the articles
37
- result.articles.forEach((article, index) => {
38
- console.log(`${index + 1}. ${article.title} (ID: ${article.id})`);
39
- });
40
-
41
- return result;
42
- } catch (error) {
43
- console.error("❌ Error getting normal articles:", error);
44
- throw error;
45
- }
46
- }
47
-
48
- /**
49
- * Example 2: Get all video articles
50
- */
51
- async function getAllVideoArticlesExample() {
52
- console.log("\n=== Getting All Video Articles ===");
53
-
54
- try {
55
- const result = await articleService.getAllArticles(ACCESS_TOKEN, "video", {
56
- batchSize: 30, // Smaller batch size for videos
57
- maxArticles: 500, // Limit to 500 videos
58
- onProgress: (progress) => {
59
- console.log(`🎥 Video Batch ${progress.currentBatch}: ${progress.totalFetched} videos fetched`);
60
- }
61
- });
62
-
63
- console.log(`✅ Completed! Total: ${result.totalFetched} video articles in ${result.totalBatches} batches`);
64
-
65
- return result;
66
- } catch (error) {
67
- console.error("❌ Error getting video articles:", error);
68
- throw error;
69
- }
70
- }
71
-
72
- /**
73
- * Example 3: Get all articles (both normal and video) combined
74
- */
75
- async function getAllArticlesCombinedExample() {
76
- console.log("\n=== Getting All Articles Combined ===");
77
-
78
- try {
79
- const result = await articleService.getAllArticlesCombined(ACCESS_TOKEN, {
80
- batchSize: 50,
81
- maxArticlesPerType: 500, // Max 500 per type (normal + video)
82
- onProgress: (progress) => {
83
- console.log(`📱 ${progress.type.toUpperCase()}: Batch ${progress.currentBatch}, Total: ${progress.totalFetched}`);
84
- }
85
- });
86
-
87
- console.log(`✅ All articles fetched!`);
88
- console.log(`📊 Total articles: ${result.totalFetched}`);
89
- console.log(`📄 Normal articles: ${result.breakdown.normal.totalFetched}`);
90
- console.log(`🎥 Video articles: ${result.breakdown.video.totalFetched}`);
91
- console.log(`🔄 Total API calls: ${result.totalBatches}`);
92
-
93
- // You can access all articles combined
94
- console.log(`\n📋 All Articles (${result.articles.length}):`);
95
- result.articles.slice(0, 5).forEach((article, index) => {
96
- console.log(`${index + 1}. [${article.type?.toUpperCase()}] ${article.title}`);
97
- });
98
-
99
- if (result.articles.length > 5) {
100
- console.log(`... and ${result.articles.length - 5} more articles`);
101
- }
102
-
103
- return result;
104
- } catch (error) {
105
- console.error("❌ Error getting combined articles:", error);
106
- throw error;
107
- }
108
- }
109
-
110
- /**
111
- * Example 4: Get unlimited articles (fetch everything)
112
- */
113
- async function getAllArticlesUnlimitedExample() {
114
- console.log("\n=== Getting ALL Articles (No Limit) ===");
115
-
116
- try {
117
- const result = await articleService.getAllArticles(ACCESS_TOKEN, "normal", {
118
- batchSize: 100, // Max batch size
119
- maxArticles: 0, // 0 = no limit, fetch everything
120
- onProgress: (progress) => {
121
- console.log(`🔄 Batch ${progress.currentBatch}: ${progress.totalFetched} articles...`);
122
- }
123
- });
124
-
125
- console.log(`✅ Fetched EVERYTHING! Total: ${result.totalFetched} articles`);
126
- console.log(`⚠️ Warning: This fetched all articles without limit!`);
127
-
128
- return result;
129
- } catch (error) {
130
- console.error("❌ Error getting unlimited articles:", error);
131
- throw error;
132
- }
133
- }
134
-
135
- /**
136
- * Main function to run all examples
137
- */
138
- async function runExamples() {
139
- try {
140
- // Example 1: Normal articles
141
- await getAllNormalArticlesExample();
142
-
143
- // Example 2: Video articles
144
- await getAllVideoArticlesExample();
145
-
146
- // Example 3: Combined articles
147
- await getAllArticlesCombinedExample();
148
-
149
- // Example 4: Unlimited (commented out for safety)
150
- // await getAllArticlesUnlimitedExample();
151
-
152
- console.log("\n🎉 All examples completed successfully!");
153
-
154
- } catch (error) {
155
- console.error("💥 Example failed:", error);
156
- }
157
- }
158
-
159
- // Export for use in other files
160
- export {
161
- getAllNormalArticlesExample,
162
- getAllVideoArticlesExample,
163
- getAllArticlesCombinedExample,
164
- getAllArticlesUnlimitedExample,
165
- runExamples
166
- };
167
-
168
- // Run examples if this file is executed directly
169
- if (require.main === module) {
170
- runExamples();
171
- }