Skip to content

구현

AudioRecognition instance 생성

SORI 애플리케이션 인증 정보로 SORIAudioRecognizer를 생성합니다. 실제 인증 정보를 공개 소스 코드에 하드코딩하지 마세요. 릴리즈 설정, 보안 저장소, 환경별 빌드 프로세스를 통해 로드하세요.

아래 예시는 소스 코드에 민감한 값이 남지 않도록 --dart-define 값을 사용합니다.

dart
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();

로컬 또는 CI 환경에서 값을 전달해 앱을 실행합니다.

bash
flutter run \
  --dart-define=SORI_APP_ID=your-application-id \
  --dart-define=SORI_SECRET_KEY=your-secret-key

WARNING

app_idsecret_key는 앱을 SORI API Server에 인증하는 값입니다. 실제 값을 저장소, 샘플 앱, 이슈, 스크린샷, 공개 문서에 커밋하지 마세요.

Web recognizer

브라우저 빌드에는 장기 SORI secret_key를 포함하면 안 됩니다. 설치에서 Web bridge를 준비한 뒤 애플리케이션 서버의 ephemeral key endpoint로 recognizer를 생성하세요.

dart
final recognizer = SORIAudioRecognizer.web(
  applicationId: applicationId,
  webAuth: SORIWebAuthOptions.ephemeralKeyEndpoint(
    Uri.parse('/api/sori/ephemeral-key'),
    requestCredentials: SORIWebRequestCredentials.sameOrigin,
  ),
);

await recognizer.configure();

endpoint를 다른 애플리케이션 API와 동일한 session, origin, CSRF, rate limit 제어로 보호하세요. 장기 secret_key는 서버에 보관하지만 applicationId는 브라우저 애플리케이션에 컴파일되므로 secret이 아닙니다. endpoint는 브라우저에 단기 ephemeral key만 반환합니다. Ephemeral Key를 참고하세요.

인식 이벤트 수신

인식을 시작하기 전에 recognizer.events를 구독하세요. 캠페인 정보는 네이티브 플랫폼 이벤트에 따라 event.campaign 또는 이벤트 payload에서 확인할 수 있습니다.

dart
import 'dart:async';

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'];
    // STARTING, STARTED, stopped 상태에 맞춰 UI를 업데이트합니다.
  }

  final campaign = event.campaign;
  if (campaign != null) {
    // campaign.name, campaign.imageUrl, campaign.actionUrl을 표시합니다.
    final marker = campaign.trait?.marker;
    if (marker != null) {
      // 이 캠페인에 첨부된 오디오마커 code를 필요에 따라 사용합니다.
    }
  }

  if (event.type == SORIRecognitionEventType.audioMarkerChanged) {
    final marker = event.audioMarker;
    // marker 전용 UI나 상태를 업데이트합니다.
  }

  if (event.type == SORIRecognitionEventType.error ||
      event.type == SORIRecognitionEventType.networkError) {
    // 앱의 오류 UI에 event.message를 표시합니다.
  }
});

현재 활동 세그먼트 조정

캠페인 및 인식 이벤트는 선택적 event.activityId를 제공하며, 캠페인에는 event.campaign?.materialIdevent.campaign?.trait?.marker가 포함될 수 있습니다. 최초 캠페인 이벤트는 즉시 표시하고 애플리케이션 상태에 명시적인 현재 세그먼트를 유지하세요.

  • 비어 있지 않은 event.activityId가 같은 후속 이벤트는 현재 행만 정제할 수 있습니다. 과거 행을 검색하거나 캠페인 또는 소재 ID에서 활동 식별자를 유추하지 마세요.
  • 이전 서버는 null 활동 ID를 반환할 수 있습니다. 소재 fallback은 현재 행의 비어 있지 않은 event.campaign?.materialId가 같을 때만 안전합니다.
  • 현재 행의 최초 관측 시각, 위치 및 기타 UI 메타데이터를 유지하세요. native 및 Web reporter는 전송 메타데이터를 최초 관측에 고정하므로 애플리케이션도 정제 콜백 시각으로 교체하면 안 됩니다.
  • 후속 이벤트에 marker가 없거나 캠페인 데이터가 덜 완전해도 최초 marker와 정제된 캠페인 필드를 유지하세요.
  • 다른 소재의 campaignFound 또는 recognitionResult 이벤트나 명시적인 인식 중지가 있으면 세그먼트를 닫습니다. 그 이후에 도착한 이전 활동의 지연된 정제는 무시하세요. audioMarkerChanged는 세그먼트를 닫지 않습니다.
  • SORIRecognitionEventType.audioMarkerChanged는 독립적으로 관측할 수 있는 marker 상태이며, 이 이벤트만으로 캠페인 행을 생성하거나 정제하지 않습니다.

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는 변경되지 않습니다.

위젯 또는 애플리케이션 scope가 종료될 때 subscription을 해제합니다.

dart
await subscription?.cancel();

인식 시작과 중지

recognizer 구성이 끝나고 UI가 이벤트를 받을 준비가 되면 startRecognition()을 호출합니다.

dart
await recognizer.startRecognition(
  notification: const SORIAndroidNotificationOptions(
    title: 'SORI recognition',
    body: 'Listening for SORI audio signals',
  ),
);

notification 옵션은 Android foreground-service 알림에 사용됩니다. iOS와 Web에서는 무시됩니다. Web에서는 브라우저가 마이크 권한을 요청할 수 있도록 사용자 동작에서 startRecognition()을 호출하세요.

인식을 중지하려면 다음을 호출합니다.

dart
await recognizer.stopRecognition();

현재 recorder 상태도 확인할 수 있습니다.

dart
final isRunning = await recognizer.isRecorderRunning();

오디오마커 인식 활성화

오디오마커 인식은 기본적으로 비활성화되어 있습니다. SORI Console 설정에서 오디오마커를 사용하는 경우에만 활성화하세요.

dart
await recognizer.configure(
  config: const SORIRecognitionConfig(audiomarker: true),
);

활성화하면 marker-only 상태 변경이 SORIRecognitionEventType.audioMarkerChanged로 전달되며, 최신 marker는 event.audioMarker에서 읽을 수 있습니다. marker가 포함된 캠페인이 발견되면 같은 marker를 event.campaign?.trait?.marker에서도 확인할 수 있습니다.

캠페인 액션 처리

캠페인에 action URL이 있으면, 앱에서 해당 URL을 열지 먼저 결정하세요. 앱이 URL을 허용한 뒤 handleActionUrl()을 호출하면 SDK를 통해 상호작용이 보고되고 처리됩니다.

dart
final actionUrl = campaign.actionUrl;
if (actionUrl != null && actionUrl.isNotEmpty) {
  await recognizer.handleActionUrl(actionUrl);
}

인식 데이터베이스 업데이트

SDK는 네이티브 recognizer에 로컬 인식 데이터베이스 업데이트를 요청할 수 있습니다.

updateDatabase()는 현재 Web에서 지원되지 않습니다.

dart
final result = await recognizer.updateDatabase();

if (!result.success) {
  // result.errorMessage를 확인하고 필요하면 재시도 옵션을 표시합니다.
}