LLM prompt — add the Flutter SDK
Use this prompt when you have an existing Flutter app and want to add a 2wai avatar screen with Transport 0 (LiveKit).
The prompt
Section titled “The prompt”Copy, paste, fill {PLACEHOLDERS}:
I'm adding a 2wai talking avatar to an existing Flutter app.
CONTEXT
2wai is a lip-synced talking-avatar platform. Transport 0 (LiveKit) is the only live transport. Integration pattern is MINT-PROXY: a backend holds `sk_...` and mints short-lived LiveKit participant tokens.
The Flutter SDK ships inside `2waiorg/2wai-toolkit-public`:- `twai_avatar_sdk` — UI widgets + Transcriber- `twai_avatar_sdk_core` — pure-Dart core (REST + types + errors)- `twai_avatar_sdk_livekit` — Transport 0 engine (`TwaiTransport0Player` widget)- `twai_speech_to_text_patched` — vendored speech_to_text fork with iOS LiveKit audio-session fix (MANDATORY on iOS)
MY INPUTS
- avatar_id: {AVATAR_ID}- voice_id (optional): {VOICE_ID}- target platforms: {IOS / ANDROID / WEB / DESKTOP / ANY_SUBSET}- mint-proxy URL: {URL — e.g. https://my-app.com/api/mint, OR "I need help setting one up"}- where I want the avatar screen: {ROUTE_NAME or FILE_PATH}
WHAT I NEED YOU TO DO
1. **Add dependencies** to my `pubspec.yaml`: ```yaml dependencies: twai_avatar_sdk: git: url: https://github.com/2waiorg/2wai-toolkit-public path: packages/twai_avatar_sdk ref: main twai_avatar_sdk_core: git: url: https://github.com/2waiorg/2wai-toolkit-public path: packages/twai_avatar_sdk_core ref: main twai_avatar_sdk_livekit: git: url: https://github.com/2waiorg/2wai-toolkit-public path: packages/twai_avatar_sdk_livekit ref: main ```
2. **Add dependency_overrides** (MANDATORY for iOS to work — this is non-negotiable): ```yaml dependency_overrides: livekit_client: 2.8.1 flutter_webrtc: 1.4.0 speech_to_text: git: url: https://github.com/2waiorg/2wai-toolkit-public path: packages/twai_speech_to_text_patched ref: main ``` Without these pins: - Newer `livekit_client` breaks iOS receive-only audio. - Upstream `speech_to_text` unconditionally deactivates AVAudioSession on stop, killing the avatar audio after mic turn 1.
3. **Run** `flutter pub get`.
4. **Create the avatar screen** at the file path I specified: ```dart import 'package:flutter/material.dart'; import 'package:twai_avatar_sdk/twai_avatar_sdk.dart'; import 'package:twai_avatar_sdk_core/twai_avatar_sdk_core.dart'; import 'package:twai_avatar_sdk_livekit/transport0.dart' as t0;
class AvatarScreen extends StatefulWidget { const AvatarScreen({super.key}); @override State<AvatarScreen> createState() => _AvatarScreenState(); }
class _AvatarScreenState extends State<AvatarScreen> { late final TwaiApiRestClient _rest; t0.Engine? _engine; t0.EngineState _state = t0.EngineState.idle; bool _speaking = false;
@override void initState() { super.initState(); _rest = TwaiApiRestClient( baseUrl: Uri.parse('{MINT_PROXY_URL}'), credentials: const AnonymousCredentials(), ); }
Future<t0.MintResult> _mint() async { try { final r = await _rest.createLiveKitSession( TwaiApiLiveKitSessionRequest(avatarId: '{AVATAR_ID}'), ); return t0.MintResultEnabled( url: r.livekitUrl.toString(), token: r.participantToken, room: r.roomName, ); } on TwaiApiRateLimitedException catch (e) { return t0.MintRateLimited(e.retryAfterSeconds ?? 60); } catch (e) { return t0.MintUnavailable('mint failed: $e', cause: e); } }
@override Widget build(BuildContext ctx) => Scaffold( body: Column(children: [ Expanded( child: t0.TwaiTransport0Player( mint: _mint, idleBuilder: (ctx) => Container(color: Colors.black), onEngine: (e) => setState(() => _engine = e), onState: (s) => setState(() => _state = s), onSpeaking: (e) => setState(() => _speaking = e.active), ), ), ElevatedButton( onPressed: _state == t0.EngineState.ready && !_speaking ? () => _engine?.send('Hello!') : null, child: const Text('Say hi'), ), ]), ); } ``` Mount it under my app's existing router at the route I specified.
5. **Verify**: - `flutter run` on {chrome / my iPhone / my Android / Windows / macOS} - Avatar video appears within ~5s. - Tap "Say hi" — avatar speaks. - No red screens, no console errors beyond the usual Flutter noise.
GOTCHAS TO HONOR (iOS especially)
- The vendored `speech_to_text` pin is NOT optional on iOS. Without it, the avatar audio dies after the user's first mic turn.- `livekit_client` pin 2.8.1 is NOT optional on iOS. Newer versions break receive-only audio.- Don't configure AVAudioSession yourself in `ios/Runner/AppDelegate.swift` — the SDK owns it.- On Android, `android/app/build.gradle` needs minSdk 21+ for LiveKit. If my app is older, bump it.- Web target needs the LiveKit JS SDK but the Flutter SDK handles that transitively. Just `flutter build web`.
DELIVERABLE
- Updated `pubspec.yaml` (deps + dependency_overrides).- New `avatar_screen.dart`.- Router wiring to mount it.- One-line README note on which platforms I've tested and which are TBD.
If you need anything (my package manager, my router setup, my iOS minimum version, whether I have a mint proxy running yet), ASK.
Reference docs: https://developers.2wai.ai/sdks/flutter/Reference app: https://github.com/2waiorg/2wai-toolkit-public/tree/main/apps/avatar_only_flutteriOS integration traps (read if you hit a weird mic/audio issue):https://github.com/2waiorg/2wai-toolkit-public/blob/main/docs/flutter_consumer_integration_gotchas.md