การนำไปใช้
คู่มือนี้ใช้ Flutter SDK 0.4.0 ดูขั้นตอนการติดตั้งและอัปเดต
สร้าง instance ของ AudioRecognition
สร้าง SORIAudioRecognizer ด้วย credentials ของแอปพลิเคชัน SORI อย่า hardcode credentials จริงใน source code สาธารณะ ให้โหลดผ่านการกำหนดค่า release, secure storage หรือกระบวนการ build เฉพาะ environment
ตัวอย่างด้านล่างใช้ค่า --dart-define เพื่อไม่ให้ source code มีค่าที่เป็นข้อมูลลับ:
import 'package:sorisdk_flutter/sorisdk_flutter.dart';
const applicationId = String.fromEnvironment('SORI_APP_ID');
const secretKey = String.fromEnvironment('SORI_SECRET_KEY');
final recognizer = SORIAudioRecognizer(
applicationId: applicationId,
secretKey: secretKey,
);
await recognizer.configure();เรียกใช้แอปด้วยค่าที่จัดเตรียมไว้ใน local หรือ CI environment:
flutter run \
--dart-define=SORI_APP_ID=your-application-id \
--dart-define=SORI_SECRET_KEY=your-secret-keyWARNING
app_id และ secret_key ใช้ยืนยันตัวตนของแอปกับ SORI API Server ห้าม commit ค่าจริงลงใน repository แอปตัวอย่าง issue ภาพหน้าจอ หรือเอกสารสาธารณะ
Web recognizer
browser build ต้องไม่มี SORI secret_key ที่มีอายุยาวนาน หลังจากเตรียม Web bridge ในขั้นตอน การติดตั้ง แล้ว ให้สร้าง recognizer ด้วย endpoint สำหรับ ephemeral key บน application server:
final recognizer = SORIAudioRecognizer.web(
applicationId: applicationId,
webAuth: SORIWebAuthOptions.ephemeralKeyEndpoint(
Uri.parse('/api/sori/ephemeral-key'),
requestCredentials: SORIWebRequestCredentials.sameOrigin,
),
);
await recognizer.configure();ป้องกัน endpoint ด้วยการควบคุม session, origin, CSRF และ rate limit แบบเดียวกับ application APIs อื่น โดยเก็บ secret_key ที่มีอายุยาวนานไว้บนเซิร์ฟเวอร์ ส่วน applicationId จะถูก compile ลงในแอปพลิเคชันเบราว์เซอร์และไม่ถือเป็น secret endpoint จะส่งคืนเฉพาะ ephemeral key อายุสั้นให้เบราว์เซอร์ ดู คีย์ชั่วคราว
รับฟังเหตุการณ์การรู้จำ
subscribe recognizer.events ก่อนเริ่มการรู้จำ ข้อมูลแคมเปญอยู่ใน event.campaign หรือ event payload ทั้งนี้ขึ้นอยู่กับ event ของ native platform
import 'dart:async';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:sorisdk_flutter/sorisdk_flutter.dart';
late final SORIAudioRecognizer recognizer;
StreamSubscription<SORIRecognitionEvent>? subscription;
subscription = recognizer.events.listen((event) {
if (event.type == SORIRecognitionEventType.stateChanged) {
final state = event.payload['state'];
// Update your UI for STARTING, STARTED, or stopped states.
}
final campaign = event.campaign;
if (campaign != null) {
// Render campaign.name, campaign.imageUrl, and campaign.actionUrl.
}
if (event.type == SORIRecognitionEventType.audioMarkerStateChanged) {
final state = event.audioMarkerState;
// Update marker-specific UI or state.
}
if (kIsWeb && event.type == SORIRecognitionEventType.audioMarkerFound) {
final marker = event.audioMarkerIdentity;
// Render the Console-resolved marker ID and name on Web.
// Native current-marker UI uses audioMarkerStateChanged above.
}
if (event.type == SORIRecognitionEventType.error ||
event.type == SORIRecognitionEventType.networkError) {
// Show event.message in your app's error UI.
}
});ปรับสถานะ segment ของกิจกรรมปัจจุบัน
คำแนะนำต่อไปนี้ใช้กับ callback แคมเปญเดิม สำหรับผลลัพธ์กิจกรรมใหม่ที่ SDK ยืนยันแล้ว ให้ใช้กฎอัปเดตด้วย ID ที่ตรงกันใน สถานะ Audio Marker และผลลัพธ์กิจกรรม ซึ่งสามารถอัปเดตกิจกรรมย้อนหลังที่ตรงกันได้
campaign events และ recognition events มี event.activityId แบบไม่บังคับ ส่วนแคมเปญ อาจมี event.campaign?.materialId และ event.campaign?.trait?.marker ให้แสดง campaign event แรกทันที และเก็บ segment ปัจจุบันไว้อย่างชัดเจนใน state ของแอปพลิเคชัน
- event ในภายหลังที่มี
event.activityIdไม่ว่างตรงกันจะปรับละเอียดได้เฉพาะแถวปัจจุบัน อย่าค้นหาแถวเก่า และอย่าสร้าง identity ของกิจกรรมจาก ID ของแคมเปญหรือสื่อ - เซิร์ฟเวอร์รุ่นเก่าอาจส่ง activity ID เป็น null การใช้สื่อเป็น fallback จะปลอดภัยเฉพาะเมื่อ แถวปัจจุบันมี
event.campaign?.materialIdที่ไม่ว่างตรงกัน - คงเวลา ตำแหน่ง และ UI metadata อื่นของการตรวจพบครั้งแรกในแถวปัจจุบัน native และ Web reporters จะยึด transport metadata ไว้กับการตรวจพบครั้งแรก แอปพลิเคชันจึงไม่ควรแทนที่ ด้วยเวลาของ callback ที่ปรับละเอียด
- คง marker แรกและฟิลด์แคมเปญที่ปรับละเอียดแล้วไว้ เมื่อ event ถัดมาไม่มี marker หรือมีข้อมูล แคมเปญไม่ครบกว่า
- event
campaignFoundหรือrecognitionResultของสื่ออื่น หรือการหยุด recognition อย่างชัดเจนจะปิด segment ให้ละเว้นการปรับละเอียดที่ล่าช้าของกิจกรรมเก่าหลังจากจุดนั้นaudioMarkerFoundจะไม่ปิด segment SORIRecognitionEventType.audioMarkerFoundแจ้งการค้นพบมาร์กเกอร์อย่างอิสระ เหตุการณ์นี้เพียงอย่างเดียวไม่สร้างหรือเสริมข้อมูลแถวกิจกรรม อ่าน ID และชื่อที่ SORI Console ยืนยันจากevent.audioMarkerIdentity
A(activity-1) -> A'(activity-1, marker) -> A(activity-1, marker miss) เป็น หนึ่งแถวที่คง marker ไว้ ส่วน A(activity-1) -> B(activity-2) -> delayed A'(activity-1) จะคง B เป็นรายการปัจจุบันและไม่เปลี่ยน A ในประวัติ
ยกเลิก subscription เมื่อ widget หรือ scope ของแอปพลิเคชันถูก dispose:
await subscription?.cancel();เริ่มและหยุดการรู้จำ
เรียก startRecognition() หลังจากกำหนดค่า recognizer และ UI พร้อมรับ events แล้ว
await recognizer.startRecognition(
notification: const SORIAndroidNotificationOptions(
title: 'SORI recognition',
body: 'Listening for SORI audio signals',
),
);ตัวเลือก notification ใช้กับการแจ้งเตือนของ Android foreground service และจะถูกละเว้นบน iOS และ Web สำหรับ Web ให้เรียก startRecognition() จากการกระทำของผู้ใช้เพื่อให้เบราว์เซอร์ขอสิทธิ์ใช้ไมโครโฟนได้
หากต้องการหยุดการรู้จำ:
await recognizer.stopRecognition();คุณยังสามารถตรวจสอบสถานะ recorder ปัจจุบันได้:
final isRunning = await recognizer.isRecorderRunning();เปิดใช้งานการรู้จำ Audio Marker
การรู้จำ Audio Marker ถูกปิดไว้โดยค่าเริ่มต้น ให้เปิดใช้งานเฉพาะเมื่อการตั้งค่า SORI Console ใช้ Audio Markers
await recognizer.configure(
config: const SORIRecognitionConfig(audiomarker: true),
);สำหรับ UI มาร์กเกอร์ปัจจุบันและการเสริมข้อมูลกิจกรรมภายหลัง ให้ใช้ API สถานะและผลลัพธ์กิจกรรมที่ SDK จัดการ SDK จัดการการหมดอายุ trait ของมาร์กเกอร์ และการอัปเดตกิจกรรมเดิม โดยยังรองรับ callback ของแคมเปญและการค้นพบเดิม
Flutter Web ยังคงพฤติกรรมการรู้จำและเหตุการณ์เดิม สถานะปัจจุบัน การหมดอายุ และการอัปเดตมาร์กเกอร์ที่มาภายหลังอย่างอิสระแบบใหม่นี้ใช้กับ Android/iOS บน Web เมธอด getCurrentAudioMarkerState() จะคืนค่า null จึงไม่ควรตีความว่าไม่มีการตรวจพบมาร์กเกอร์
จัดการการดำเนินการของแคมเปญ
เมื่อแคมเปญมี action URL ให้แอปตัดสินใจว่าควรเปิด URL หรือไม่ หลังจากแอปยอมรับ URL แล้ว ให้เรียก handleActionUrl() เพื่อรายงานและจัดการ interaction ผ่าน SDK
final actionUrl = campaign.actionUrl;
if (actionUrl != null && actionUrl.isNotEmpty) {
await recognizer.handleActionUrl(actionUrl);
}อัปเดตฐานข้อมูลการรู้จำ
SDK สามารถสั่งให้ native recognizer อัปเดตฐานข้อมูลการรู้จำในเครื่องได้โดยไม่ขัดจังหวะการรู้จำ Android จะส่งคืนผลการรีเฟรช ส่วน iOS จะส่งคำขอรีเฟรช แต่ native API ไม่เปิดเผยผลเมื่อดำเนินการเสร็จ ดังนั้น success: false พร้อมข้อความอธิบายจึงหมายถึงไม่สามารถทราบผลลัพธ์ได้ ไม่ได้หมายความว่าการรีเฟรชล้มเหลว
API SORIUpdateResult แบบสี่ฟิลด์ยังคงเดิม ปัจจุบัน Web ไม่รองรับ updateDatabase()
final result = await recognizer.updateDatabase();
if (!result.success) {
// Android: จัดการความล้มเหลวจริงที่รายงานใน result.errorMessage
// iOS: ข้อความอธิบายว่าไม่สามารถทราบผลลัพธ์ของการรีเฟรชได้
}