เมนูคู่มือ

Flutter

แพ็กเกจ kavchat_flutter เพิ่มแชทบริการลูกค้าตามสคริปต์ให้แอป Flutter พร้อมปุ่ม การจับคู่ข้อความที่พิมพ์เอง แบบฟอร์มเปิดคำร้อง สำเนาบอตที่ทำงานได้แม้ไม่มีอินเทอร์เน็ต และการแสดงผลจากขวาไปซ้ายสำหรับภาษาฮีบรูและอาหรับ

การติดตั้ง

pubspec.yaml
dependencies:
  kavchat_flutter: ^0.0.11

แพ็กเกจนี้มาพร้อม http, shared_preferences (สำหรับแคชเวอร์ชันและบทสนทนาที่บันทึกไว้) และ url_launcher (สำหรับลิงก์ในสคริปต์) หากต้องการเปิดลิงก์ tel: บน Android 11 ขึ้นไป ให้เพิ่มรายการ <queries> สำหรับสคีม tel ใน AndroidManifest.xml และเพิ่มอีกรายการสำหรับ https เพื่อเปิดลิงก์เว็บไซต์ (ดู README ของ url_launcher) ส่วน iOS ต้องใช้ LSApplicationQueriesSchemes เฉพาะเมื่อเรียก canLaunchUrl เองเท่านั้น

การใช้งาน

Dart
final kavchat = KavchatController(
  publicKey: 'pk_live_...',
  // apiBase: 'https://api.kavchat.com', // default
  // locale: 'he',                        // default: device language if translated, else the bot language
  onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);

Scaffold(
  floatingActionButton: KavchatLauncher(controller: kavchat), // hidden while the bot is off
);

// or open it yourself
showKavchat(context, kavchat);

// or embed the screen in your own route
KavchatChat(controller: kavchat, onClose: () => Navigator.pop(context));

สร้างคอนโทรลเลอร์เพียงครั้งเดียว (เช่น ใน State หรือ provider) และเรียก dispose() เมื่อออบเจ็กต์ที่เก็บคอนโทรลเลอร์นั้นสิ้นสุดการใช้งาน

KavchatLauncher เป็น FloatingActionButton โดยกำหนดตำแหน่งด้วย Scaffold.floatingActionButtonLocation ค่า kavchat.settings?.position (start หรือ end) ระบุด้านที่เลือกไว้ในแดชบอร์ด

เมื่อตั้งค่าข้อความข้างปุ่มแชทในหน้าจัดการ (เป็นกล่องคำพูด ข้อความโค้งเหนือปุ่ม ปุ่มที่ขยายเป็นรูปแคปซูลเพื่อแสดงข้อความ หรือเส้นที่ยื่นขึ้นจากปุ่มพร้อมตัวเลือกแรกของบอต) KavchatLauncher จะแสดงข้อความหลังพ้นระยะหน่วงที่ตั้งไว้ ไม่เกินวันละครั้ง การแตะตัวเลือกบนเส้นจะเปิดแชทพร้อมเลือกตัวเลือกนั้น เหมือนกับเลือกจากในแชท การปิดข้อความหรือเปิดแชทจะซ่อนข้อความจนถึงวันถัดไป ข้อความจะไม่แสดงขณะแชทเปิดอยู่ หากอุปกรณ์ตั้งค่าให้ลดการเคลื่อนไหว ข้อความจะแสดงโดยไม่มีการเคลื่อนไหว เมื่อเปิดตัวเลือก "ไม่แสดงบนโทรศัพท์" ข้อความจะแสดงเฉพาะบนแท็บเล็ต (หน้าจอด้านสั้นมีขนาดตั้งแต่ 600 จุดขึ้นไป) บนโทรศัพท์ เส้นจะแสดงได้ไม่เกินสองตัวเลือก ใช้ KavchatLauncher(controller: kavchat, attention: false) เพื่อปิดการแสดงข้อความนี้

หากไอคอนปุ่มในธีมเป็นรูปใบหน้า ใบหน้าจะกะพริบตาเป็นระยะเมื่อปุ่มอยู่นิ่ง โดยจะไม่กะพริบตาขณะแชทเปิดอยู่ แอปทำงานอยู่เบื้องหลัง หรืออุปกรณ์ตั้งค่าให้ลดการเคลื่อนไหว

บอตจะไม่แสดง (ปุ่มลอยไม่ปรากฏ และ KavchatChat แสดงว่า "ไม่พร้อมใช้งาน") เมื่อเวอร์ชันมีค่า enabled: false ซึ่งหมายถึงบอตถูกปิด เปิดให้เฉพาะผู้ใช้ทดสอบแต่ผู้ใช้รายนี้ไม่ได้อยู่ในกลุ่มทดสอบ หรือใช้โควตาหมดแล้ว (reason: 'quota')

โทเค็นระบุตัวตน

สำหรับผู้ใช้ที่เข้าสู่ระบบ ให้ลงนาม JWT แบบสั้นด้วยคีย์ลับบนเซิร์ฟเวอร์ของคุณ (ห้ามทำในแอป ดู การระบุตัวตนผู้ใช้) แล้วส่งโทเค็นดังนี้:

Dart
KavchatController(publicKey: 'pk_live_...', userToken: jwt, userName: 'Dana');
await kavchat.setUser(token: newJwt, name: 'Dana'); // after login
await kavchat.setUser(token: null);                 // after logout

โทเค็นจะถูกส่งในส่วนหัว Authorization: Bearer <token> ทุกครั้งที่เรียก เมื่อมีโทเค็น แบบฟอร์มคำร้องจะไม่บังคับกรอกอีเมลหรือเบอร์โทร และระบบจะระบุได้ว่าผู้ใช้อยู่ในกลุ่มผู้ใช้ทดสอบหรือไม่ setUser จะโหลดเวอร์ชันใหม่ และเมื่อเปลี่ยนผู้ใช้จะเริ่มบทสนทนาใหม่ บทสนทนาที่บันทึกในอุปกรณ์จึงไม่ถูกนำไปใช้กับบัญชีอื่น

ลิงก์ หน้าจอ และแบบฟอร์มคำร้อง

  • ปุ่มประเภท link เปิดด้วย url_launcher โดยรองรับเฉพาะที่อยู่ https: และ tel: ส่วนลิงก์ในข้อความของบอตรองรับเฉพาะ https:
  • ปุ่มประเภท screen จะเรียก onScreen(screen, targetId) หากไม่มีฟังก์ชันนี้ ปุ่มจะไม่ทำอะไร
  • ปุ่ม "ติดต่อทีมงาน" เปิดแบบฟอร์มในตัว (ชื่อ อีเมล เบอร์โทร หัวข้อ และข้อความ พร้อมแนบบทสนทนา) และแสดงหมายเลขคำร้องหลังส่ง

รายการหน้าจอในตัวแก้ไข

ประกาศหน้าจอที่แอปเปิดได้เพียงครั้งเดียวใน KavchatController(screens: ...) SDK จะส่งรายการไปยัง Kavchat เอง จากนั้นตัวแก้ไขสคริปต์จะแสดงชื่อหน้าจอเหล่านี้ในรายการแบบเลื่อนลงแทนช่องกรอกข้อความ นอกจากนี้ ตัวแก้ไขจะขอรหัสรายการเมื่อหน้าจอนั้นต้องใช้ และแจ้งเตือนเมื่อปุ่มนำไปยังหน้าจอที่ไม่ได้ประกาศไว้ ไม่ต้องพิมพ์รายการหน้าจอเองในแดชบอร์ด

Dart
final kavchat = KavchatController(
  publicKey: 'pk_live_...',
  screens: const [
    KavchatScreen(id: 'orders', label: 'My orders'),
    KavchatScreen(id: 'product', label: 'Product page', needsTarget: true), // the button carries a targetId
  ],
  onScreen: (screen, targetId) => navigatorKey.currentState?.pushNamed('/$screen', arguments: targetId),
);
// later, to replace the list: await kavchat.registerScreens([...]);
  • id คือค่าที่ส่งไปยัง onScreen ใช้ตัวอักษรละติน ตัวเลข _, . และ - ได้ไม่เกิน 40 ตัวอักษร ส่วน label คือชื่อที่ผู้ดูแลเห็น ยาวได้ไม่เกิน 60 ตัวอักษร รองรับสูงสุด 100 หน้าจอ รายการที่ไม่ถูกต้องและรหัสที่ซ้ำกันจะถูกตัดออก
  • needsTarget: ปุ่มจะมีรหัสรายการด้วย (เช่น รหัสสินค้า) และส่งไปยัง onScreen ในค่า targetId
  • รายการจะถูกส่งในเบื้องหลังหลังโหลดเวอร์ชันเสร็จ เฉพาะเมื่อรายการเปลี่ยนแปลงหรือสัปดาห์ละครั้ง หากส่งไม่สำเร็จจะไม่มีการแจ้งเตือน และจะลองส่งอีกครั้งเมื่อเปิดแอปครั้งถัดไป ผู้ใช้จะไม่เห็นอะไร
  • หน้าจอที่ลงทะเบียนไว้จะแสดงในแดชบอร์ดที่ บอต, การตั้งค่า, "หน้าจอแอป" พร้อมแพลตฟอร์มที่รายงานแต่ละหน้าจอ หากนำหน้าจอออกจากแอปแล้ว สามารถลบออกจากรายการนี้ได้

RTL

แชทกำหนด Directionality ของตัวเองตามภาษาอินเทอร์เฟซ โดย he และ ar ใช้ทิศทางจากขวาไปซ้าย ส่วนภาษาอื่นใช้จากซ้ายไปขวา โดยไม่เปลี่ยนทิศทางของแอป แต่ละกล่องข้อความยังเลือกทิศทางตามอักขระตัวแรกที่มีทิศทางชัดเจน เพื่อให้อ่านเนื้อหาที่มีหลายภาษาปะปนกันได้ถูกต้อง ภาษาอินเทอร์เฟซแยกจากภาษาสคริปต์ บอตภาษาอังกฤษจึงแสดงปุ่มภาษาอาหรับ เช่น "ย้อนกลับ" ได้เมื่อตั้งค่า locale: 'ar'

สีและแบรนด์

สีมาจากการตั้งค่าบอต primaryColor ข้อความบนสีนั้นจะเป็นสีดำหรือสีขาวตามความต่างระดับสีของ WCAG และหากสีนั้นอ่อนเกินไป จะเปลี่ยนเป็นสีเข้มในจุดที่ใช้เป็นสีข้อความ เปลี่ยนสีได้ดังนี้:

Dart
KavchatLauncher(controller: kavchat, theme: KavchatThemeData.fromColor(const Color(0xFF0F766E)));
KavchatChat(controller: kavchat, theme: KavchatThemeData.fromHex('#0f766e').copyWith(background: Colors.white));

ป้าย "ขับเคลื่อนโดย Kavchat by maxsave" แสดงในทุกแพ็กเกจ พร้อมลิงก์ไปยัง kavchat.com สำหรับ Premium สามารถซ่อนป้ายได้ในการตั้งค่าบอต

แชทกับเจ้าหน้าที่

เริ่มใช้งานได้โดยไม่ต้องตั้งค่าเพิ่มเติม เมื่อเปิดแชทกับเจ้าหน้าที่ในหน้าจัดการ ตัวเลือกนี้จะปรากฏในแชทของแอปเหมือนกับวิดเจ็ตบนเว็บไซต์

  • ตัวเลือก: "คุยกับเจ้าหน้าที่" จะแสดงก่อน "ติดต่อทีมงาน" และแสดงเฉพาะเมื่อเซิร์ฟเวอร์ยืนยันว่ามีเจ้าหน้าที่ว่าง ระบบจะตรวจสอบอีกครั้งเมื่อแตะปุ่ม นอกเวลาทำการหรือเมื่อเจ้าหน้าที่ทุกคนไม่ว่าง จะแสดงเฉพาะแบบฟอร์มคำร้องพร้อมคำอธิบายสั้น ๆ และเวลาที่ทีมงานจะกลับมา หากทราบ เมื่อใช้โควตารายเดือนหมดแล้ว แบบฟอร์มจะแสดงโดยไม่มีคำอธิบาย
  • การขอแชท: ผู้ใช้ที่ไม่ได้เข้าสู่ระบบจะฝากอีเมลหรือเบอร์โทรไว้ เผื่อไม่มีเจ้าหน้าที่ว่างภายในเวลารอ โดยเพิ่มชื่อและข้อความแรกได้ด้วย หากมีแผนกเปิดอยู่มากกว่าหนึ่งแผนก ให้เลือกแผนก ผู้ใช้ที่ระบุตัวตนแล้ว (userToken) ไม่ต้องกรอกข้อมูลติดต่อ หากไม่มีเจ้าหน้าที่รับแชทได้ ระบบจะเปิดแบบฟอร์มคำร้องพร้อมข้อมูลที่กรอกไว้แล้ว
  • ระหว่างรอ: แสดงข้อความ "กำลังรอเจ้าหน้าที่" พร้อมนับถอยหลังตามเวลารอที่ตั้งไว้ และปุ่ม "ฝากข้อความแทน" กับ "จบการสนทนา" ผู้ใช้พิมพ์ข้อความระหว่างรอได้ เมื่อหมดเวลา บทสนทนาจะเปลี่ยนเป็นคำร้องโดยอัตโนมัติ พร้อมแสดงหมายเลขคำร้องและคำอธิบายว่าไม่มีเจ้าหน้าที่ว่างภายในเวลารอ
  • การสนทนา: แสดงชื่อเจ้าหน้าที่ ข้อความ สถานะกำลังพิมพ์ การโอนไปยังเจ้าหน้าที่คนอื่น และการจบการสนทนา ทุกอย่างที่มาจากเซิร์ฟเวอร์จะแสดงเป็นข้อความธรรมดา ไม่มีลิงก์
  • แบบเรียลไทม์: เชื่อมต่อด้วย Server-Sent Events ผ่านการตอบกลับแบบสตรีมของ http หากการเชื่อมต่อหลุด แชทจะเชื่อมต่อใหม่โดยค่อย ๆ เพิ่มระยะห่างระหว่างการลอง และดึงข้อมูลที่พลาดไปทั้งหมด จึงไม่มีข้อความสูญหายหรือแสดงซ้ำ บนเครือข่ายที่บล็อกการเชื่อมต่อประเภทนี้และบน Flutter Web แชทจะใช้การตรวจสอบซ้ำ (long-poll) ทุกข้อความมีรหัสกำกับ การลองส่งใหม่จึงไม่สร้างข้อความซ้ำ ข้อความที่ส่งไม่สำเร็จจะมีเครื่องหมายระบุ และแตะเพื่อส่งใหม่ได้
  • การทำงานเบื้องหลังและการเปิดแอปใหม่: เมื่อแอปเข้าสู่เบื้องหลัง (paused, hidden) การเชื่อมต่อจะปิด เมื่อกลับมาใช้งาน (resumed) แชทจะดึงข้อมูลที่พลาดไป ข้อมูลรับรองการเข้าถึงแชทมีอายุสูงสุด 12 ชั่วโมงหรือจนกว่าการสนทนาจะจบ และเก็บไว้ในพื้นที่จัดเก็บที่เลือกไว้ เมื่อเปิดแอปใหม่ บทสนทนาที่ยังไม่จบจึงกลับมาแสดงบนหน้าจอ ข้อมูลรับรองนี้จะไม่ถูกเก็บใน URL หรือเขียนลงล็อก
  • เวอร์ชันนี้ไม่มีการแจ้งเตือนแบบพุช: ข้อความจากเจ้าหน้าที่จะมาถึงเฉพาะขณะที่แอปเปิดอยู่

แนะนำให้เก็บข้อมูลรับรองการเข้าถึงไว้ในพื้นที่จัดเก็บที่ปลอดภัย (Keychain บน iOS, Keystore บน Android) เช่น ใช้ flutter_secure_storage หากไม่ได้กำหนด secureStorage ข้อมูลรับรองจะถูกเก็บในพื้นที่เดียวกับบทสนทนา ปุ่มคุยกับเจ้าหน้าที่ที่สร้างเองจะเปิดแบบฟอร์มขอแชทเมื่อมีเจ้าหน้าที่ว่าง หากไม่มีเจ้าหน้าที่ว่าง จะเปิดแบบฟอร์มคำร้องพร้อมคำอธิบาย:

Dart
import 'package:flutter_secure_storage/flutter_secure_storage.dart';

class SecureKavchatStorage implements KavchatStorage {
  final _s = const FlutterSecureStorage();
  @override
  Future<String?> read(String key) => _s.read(key: key);
  @override
  Future<void> write(String key, String value) => _s.write(key: key, value: value);
  @override
  Future<void> remove(String key) => _s.delete(key: key);
}

final kavchat = KavchatController(
  publicKey: 'pk_live_...',
  secureStorage: SecureKavchatStorage(),
  livePage: 'checkout',
  onLivePhase: (phase) => debugPrint('live chat: $phase'),
);

// your own button
FilledButton(onPressed: kavchat.openLive, child: const Text('Chat with us'));

ตรรกะเดียวกันที่ไม่ใช้ Flutter อยู่ใน kavchat_engine (KavchatClient, LiveSession และเครื่องสถานะที่ใช้ร่วมกัน liveApplyEvent, liveLines และ liveStatus ซึ่งผ่านชุดข้อมูลทดสอบเดียวกับวิดเจ็ตบนเว็บไซต์)

คำถาม เงื่อนไข และลีด

ไม่ต้องตั้งค่าในแอป สคริปต์สามารถขอข้อมูล (ชื่อ เบอร์โทร อีเมล ตัวเลข หรือข้อความ) เลือกขั้นตอนถัดไปตามเงื่อนไข (Premium) และส่งข้อมูลลีดได้ ทั้งหมดทำงานบนอุปกรณ์

  • คีย์บอร์ดที่เหมาะกับข้อมูล: เมื่อบอตรอคำตอบ ช่องข้อความจะแสดงคีย์บอร์ดสำหรับเบอร์โทร อีเมล หรือตัวเลข พร้อมการเติมข้อความอัตโนมัติ หากคำตอบไม่ถูกต้อง บอตจะอธิบายว่าขาดอะไรและทำเครื่องหมายที่ช่องนั้น คำถามที่ข้ามได้จะแสดงปุ่ม "ข้าม"
  • ลีด: เมื่อมีข้อความขอความยินยอม จะแสดงปุ่ม "ส่ง" และ "ไม่ ขอบคุณ" หากไม่มีการเชื่อมต่อเครือข่าย ข้อมูลลีดจะถูกบันทึกในอุปกรณ์และส่งเมื่อกลับมาเชื่อมต่อ โดยไม่ส่งซ้ำ
  • การกรอกข้อมูลล่วงหน้า: คำตอบที่ผู้ใช้ให้ไว้แล้วจะถูกนำไปกรอกในแบบฟอร์มคำร้องและแบบฟอร์มขอแชทกับเจ้าหน้าที่ พร้อมแนบไปกับคำร้องและบทสนทนากับเจ้าหน้าที่ ชื่อ อีเมล และเบอร์โทรจากโทเค็นระบุตัวตนถือเป็นคำตอบที่ทราบแล้ว บอตจึงไม่ถามซ้ำ
  • หน้าจอปัจจุบัน: livePage ยังระบุหน้าจอที่ใช้ตรวจสอบเงื่อนไขและส่งไปพร้อมข้อมูลลีด เมื่อผู้ใช้เปลี่ยนไปหน้าจออื่น ให้เรียก setPage('checkout')

คำตอบจาก AI (Premium)

ไม่ต้องตั้งค่าในแอป เมื่อเปิดคำตอบจาก AI ในหน้าจัดการ (โดยใช้คีย์จากผู้ให้บริการ AI ของคุณเอง) คำถามที่ไม่มีสคริปต์ใดตอบได้จะถูกส่งไปยัง Kavchat ระหว่างรอสูงสุด 20 วินาที แชทจะแสดงว่าบอตกำลังพิมพ์ คำตอบจะแสดงเป็นข้อความธรรมดาพร้อมป้ายเล็ก ๆ ว่า "คำตอบจาก AI" ตามภาษาอินเทอร์เฟซ ด้านล่างมีปุ่มหัวข้อที่เกี่ยวข้องหากมี และปุ่ม "ติดต่อทีมงาน"

หากไม่มีคำตอบ หรือคำขอล้มเหลว ใช้เวลานานเกินไป หรือเกินขีดจำกัด (10 คำตอบต่อบทสนทนาในทุก 15 นาที) แชทจะแสดงข้อความ "ไม่พบคำตอบ" ตามปกติ คำถามจะยังปรากฏในรายงานคำถามที่ไม่มีคำตอบ และคำตอบจาก AI จะถูกเก็บในบทสนทนาที่บันทึกไว้เหมือนข้อความอื่น

การใช้งานออฟไลน์และแคช

เวอร์ชันจะถูกเก็บในแคชพร้อม ETag (If-None-Match, 304) เมื่อไม่มีเครือข่ายหรือเซิร์ฟเวอร์เกิดข้อผิดพลาด ระบบจะใช้สำเนาที่บันทึกไว้และแสดงข้อความแจ้ง บทสนทนาจะถูกบันทึกแยกตามบอตและกู้คืนได้ภายใน 24 ชั่วโมง ตราบใดที่เวอร์ชันไม่เปลี่ยน ลำดับการสนทนาจะถูกรายงานไปยังเซิร์ฟเวอร์หลังการกระทำล่าสุด 2 วินาที และเมื่อแอปเข้าสู่เบื้องหลัง