Android XR

Membangun pengalaman berbasis audio untuk kacamata AI dengan Gemini Nano 4

Speaker

Tentang

Tentang konferensi

Temukan cara membangun pengalaman audio handsfree yang andal dan didukung oleh AI di perangkat. Kami akan membahas semua yang Anda butuhkan: menyiapkan aktivitas kacamata, merekam feed mikrofon dan feed kamera, serta menggunakan suara bersama dengan isyarat audio lainnya sebagai UI utama Anda. Melalui showcase dunia nyata yang menarik dari XR Language Teacher open source yang dibangun di aplikasi Google AI Edge Gallery, pelajari cara mengorkestrasi Gemini Nano 4 (yang dibangun di Gemma 4 dan dioptimalkan untuk perangkat Android), dan ML Kit, serta memanfaatkan runtime LiteRT untuk membangun pengalaman XR cepat yang mendengar, melihat, dan berbicara secara alami.

Ringkasan

  • Library Jetpack Projected (alfa) menghubungkan ponsel Android ke kacamata AI. Menambahkan aktivitas yang diproyeksikan ke aplikasi yang sudah ada akan memproyeksikan konten ke kacamata layar atau kacamata khusus audio.
  • ML Kit memperkenalkan library ucapan di perangkat versi alfa untuk interaksi berbasis audio di perangkat tertentu. Fitur ini menawarkan Text to Speech dengan 8 suara di 21 lokalitas dan Pengenalan Ucapan dengan mode lanjutan Gemini Nano di Pixel 10.
  • Gemini Nano 4 memproses frame kamera dan pertanyaan yang ditranskripsikan bersama-sama dalam satu proses. Fitur ini mendukung pengalaman offline dengan merangkai model ucapan di perangkat secara lokal di ponsel unggulan yang didukung.
  • Desain dua tahap memprioritaskan latensi audio real-time di kacamata pintar. Pass 1 men-streaming teks lisan menggunakan tag XML inline untuk peralihan lokalitas di tengah kalimat, sedangkan Pass 2 mengekstrak data terstruktur di latar belakang.
  • Implementasi XR Language Teacher open source tersedia di aplikasi Google AI Edge Gallery. Developer dapat menyesuaikan kodenya untuk kasus penggunaan asisten multimodal lainnya.

Resource

Gemini Notebook

Topik

  • intelligent-eyewear
  • android-xr
  • gemini-nano
  • on-device-ai
  • ml-kit
  • speech-recognition
  • text-to-speech

Transkrip

Pengantar

  • Halo, selamat datang semuanya.

  • Senang sekali bertemu kalian semua hari ini.

  • Terima kasih sudah datang.

  • Saya Amy.

  • Hari ini, saya akan ditemani oleh rekan saya, Alice, dan kami akan membahas cara Anda dapat membangun pengalaman luar biasa yang mengutamakan audio untuk kacamata AI menggunakan Gemini Nano 4.

  • Jadi, mari kita mulai.

  • Jadi, saat kita membahas kacamata AI, yang kita maksud adalah kacamata portabel dan ringan yang dimaksudkan untuk, misalnya, dipakai sepanjang hari.

  • Kategori ini akan mencakup kacamata layar dan kacamata khusus audio, dan dengan perangkat ini, Anda akan melihat beberapa hardware yang bervariasi di sini.

  • Jadi, hal pertama yang akan Anda perhatikan adalah bahwa perangkat tersebut akan memiliki panel sentuh, yang dapat digunakan untuk input pengguna, seperti ketukan dan geser.

  • Perangkat ini juga akan memiliki speaker, kamera, dan mikrofon.

  • Kemudian, perangkat tersebut juga dapat memiliki layar atau tidak, atau mungkin kombinasi dari keduanya.

  • Hari ini, kita akan membahas audio-first dan cara membangun pengalaman yang menarik, cerdas, dan praktis.

  • Dan salah satu hal yang menarik dari audio saja adalah suara menjadi UI Anda di sini.

  • Selain itu, AI di perangkat sangat cocok untuk developer yang mencari pengalaman offline dan saat bepergian.

Membangun untuk Android XR

  • Dan ada kabar baik.

  • Jadi, jika Anda sudah membangun aplikasi untuk Android, Anda juga sudah membangun aplikasi untuk Android XR.

  • Aplikasi Android yang ada dirancang untuk diperluas dengan baik ke kacamata pintar audio, sehingga memberikan notifikasi lisan dan audio lainnya melalui Bluetooth.

  • Jika Anda ingin melangkah lebih jauh dan membedakan aplikasi Anda untuk XR, ada banyak cara untuk melakukannya.

  • Jadi, dalam pembahasan ini, kita akan membahas model di perangkat, tetapi ini bukanlah daftar yang lengkap.

  • Kami-- ada juga model cloud.

  • Ada hal-hal seperti Gemini Live API.

  • Ada agen sistem yang dapat Anda integrasikan, seperti Gemini, dan semua ini dapat membantu Anda membangun pengalaman yang terbaik untuk Anda.

  • Jadi, bagaimana cara membangun pengalaman yang mendengar, melihat, dan berbicara secara alami?

  • Hari ini, kami akan memandu Anda membangun pengalaman handsfree yang andal dan didukung oleh AI di perangkat.

  • Saya akan memandu Anda mempelajari dasar-dasarnya: cara membangun untuk kacamata, cara menyiapkan aktivitas, mendapatkan izin yang diperlukan, lalu cara menggunakan ML Kit untuk UI percakapan.

  • Kemudian, saya akan menyerahkannya kepada Alice, dan dia akan menjelaskan beberapa contoh nyata yang menggunakan Gemini Nano 4.

  • Jadi, mari kita pelajari kodenya lebih lanjut.

  • Jadi, dengan kacamata, ponsel adalah perangkat yang melakukan pekerjaan berat, dan konten kacamata akan diproyeksikan dari ponsel ke kacamata.

  • Jadi, ada dua hal yang Anda perlukan untuk menjembatani perangkat ini saat pertama kali menyiapkan.

  • Yang Anda perlukan terlebih dahulu adalah library Jetpack Projected.

  • Anda harus menambahkan dependensi ini, dan dependensi ini akan berisi API untuk mendukung pengalaman yang diproyeksikan tersebut.

    dependencies {
       implementation("androidx.xr.projected:projected:1.0.0-alpha13")
    }
  • Kemudian, Anda juga perlu membuat aktivitas baru khusus untuk kacamata.

    class ProjectedMainActivity : ComponentActivity() {
       override fun onCreate(savedInstanceState: Bundle?) {
           super.onCreate(savedInstanceState)
           setContent {
               // Glasses content
           }
       }
    }
  • Kemudian, Anda akan memanfaatkan library Jetpack Projected tersebut di dalam aplikasi yang ada dan di dalam aktivitas baru ini sehingga kedua perangkat dapat berkomunikasi dengan lancar kapan pun diperlukan.

  • Jadi, seperti aktivitas normal yang pernah Anda lihat, Anda akan mendeklarasikannya dalam manifes.

    <activity
       android:name=".ProjectedMainActivity"
       android:exported="false"
       android:requiredDisplayCategory="android.hardware.display.category.XR_PROJECTED"
       android:label="Example activity for audio glasses">
       <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
       </intent-filter>
    </activity>
  • Perbedaan utamanya adalah Anda harus menggunakan XR_PROJECTED sebagai requiredDisplayCategory.

  • Hal ini agar sistem mengetahui bahwa aktivitas ini adalah untuk kacamata.

  • Kemudian, Anda juga perlu menggunakan kategori intent ini di sini, yaitu XR_PROJECTED_LAUNCHER.

  • Hal ini memungkinkan Gemini menemukan aplikasi Anda sehingga pengguna dapat meluncurkannya secara handsfree saat dalam perjalanan.

  • Oke.

  • Jadi, setelah menyiapkan aktivitas tersebut, seperti yang saya sebutkan, Anda akan menggunakan library yang Diproyeksikan untuk mendukung pengalaman aplikasi tersebut.

  • Library ini berisi semua alat yang Anda perlukan untuk membangun pengalaman kacamata yang lengkap.

  • Mari kita bahas beberapa API utama yang akan Anda gunakan di sini.

  • Jadi, yang pertama ingin kami sebutkan adalah metode isProjectedDeviceConnected.

    // Continuously monitor whether the glasses are connected
    val isGlassesConnected by ProjectedContext.isProjectedDeviceConnected(
       context,
       scope.coroutineContext
    ).collectAsStateWithLifecycle(initialValue = false)
    
    // Launch the activity
    val options = ProjectedContext.createProjectedActivityOptions(context)
    val intent = Intent(context, ProjectedMainActivity::class.java)
    context.startActivity(intent, options.toBundle())
    
    // Check if the device is audio only or has a display
    val projectedDeviceController = ProjectedDeviceController.create(this@ProjectedMainActivity)
    isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI)
  • Dengan cara ini, Anda akan terus memantau koneksi kacamata pintar.

  • Anda menggunakannya bersama dengan siklus proses perangkat untuk mengetahui kapan kacamata benar-benar tersedia, jadi tidak hanya saat dipasangkan atau dinyalakan, tetapi juga, misalnya, saat dipakai dan siap digunakan.

  • Dan inilah yang, jadi, ya.

  • Jadi, ini akan memberi tahu Anda kapan tepatnya Anda siap meluncurkan aktivitas tersebut.

  • Jadi, untuk melakukannya, saat Anda siap meluncurkan aktivitas, ada beberapa opsi spesifik yang perlu Anda tetapkan saat memulai aktivitas.

  • Untuk itu, Anda akan menggunakan createProjectedActivityOptions di ProjectedContext.

  • Dan sekali lagi, Anda akan menggunakannya dengan konteks pada intent di sana.

  • Lalu, satu lagi alat yang perlu Anda gunakan adalah ProjectedDeviceController.

  • Dengan cara ini, Anda akan memeriksa jenis kacamata yang digunakan pengguna.

  • Jadi, seperti yang saya katakan sebelumnya bahwa kacamata AI mencakup kacamata khusus layar dan audio, Anda-- Anda perlu melihat apakah kemampuannya berisi CAPABILITY_VISUAL_UI ini, dan itu akan memungkinkan Anda menyesuaikan aplikasi dengan baik untuk berbagai perangkat dan menyesuaikan pengalaman yang dioptimalkan untuk perangkat tersebut.

  • Jadi, saat Anda membangun pengalaman yang berbeda ini, Anda mungkin ingin mengakses hardware perangkat, misalnya, memanfaatkan kamera kacamata.

  • Jadi, untuk melakukannya dari aktivitas yang diproyeksikan, Anda harus meminta izin yang sesuai menggunakan ProjectedActivityCompat.

    // In a projected activity
    private fun requestProjectedPermissions() {
       lifecycleScope.launch {
           try {
               ProjectedActivityCompat.requestPermissions(
                   this@PermissionsFromProjectedActivity,
                   arrayOf(Manifest.permission.CAMERA),
                   // CAMERA_PERMISSION_REQUEST_CODE is a developer defined constant
                   requestCode = CAMERA_PERMISSION_REQUEST_CODE,
               )
           } catch (e: IllegalStateException) {
               // Thrown when the projected system service can't be bound.
               Log.e(TAG, "Request failed: projected service unavailable.", e)
           }
       }
    }
  • Meskipun aplikasi Anda sudah memiliki izin yang diperlukan untuk ponsel, Anda tetap perlu meminta izin khusus untuk hardware kacamata.

  • Setiap kali menggunakan izin, ingatlah untuk mengikuti praktik terbaik untuk Android secara umum.

  • Nyatakan izin yang diperlukan dalam manifes, minta izin dalam konteks yang diperlukan, dan hanya minta izin yang benar-benar Anda perlukan agar aplikasi berfungsi.

  • Tentu saja, kami telah mendokumentasikan hal ini di situs kami di developer.android.com.

  • Namun, kami juga memiliki keterampilan baru, yaitu keterampilan hardware yang diproyeksikan.

  • Anda dapat menggunakannya dengan Android CLI di Android Studio untuk menyiapkan alur kerja izin, dan Anda bisa mendapatkan akses ke keterampilan ini, lalu semua keterampilan Android lainnya juga.

    android skills add projected-hardware
    android skills add --all

Mendesain pengalaman yang mengutamakan audio

  • Oke, setelah kita terhubung, mengetahui kemampuan hardware, dan memiliki izin yang tepat, mari kita bahas alat yang Anda miliki untuk membangun pengalaman audio tersebut.

  • Jadi, saat mendesain pengalaman audio, kami ingin memastikan bahwa kami menciptakan pengalaman berkualitas tinggi bagi pengguna.

  • Dan ini dapat mencakup beberapa interaksi utama.

  • Jadi, yang pertama adalah menggunakan suara sebagai output, sehingga memungkinkan suara Anda berbicara secara alami kepada pengguna.

  • Selanjutnya, gunakan earcon untuk mengirim sinyal audio tertentu kepada pengguna.

  • Dan juga menangani input dari pengguna, baik melalui touchpad menggunakan ketukan dan geser, atau juga jika Anda ingin mengizinkan pengguna berbicara ke aplikasi Anda.

  • Jadi, hal pertama yang akan kita bahas adalah penggunaan suara sebagai output.

  • Untuk itu, kami ingin memperkenalkan library Text To Speech GenAI baru dari ML Kit.

  • Fitur ini kini tersedia dalam versi alfa, dan tersedia di perangkat Pixel dan Samsung tertentu.

  • Kami sangat antusias dengan hal ini, terutama untuk pengalaman berbasis audio ini.

  • Jika pernah menggunakan Text To Speech, Anda mungkin tahu bahwa salah satu poin masalahnya adalah Suara Sistem tidak selalu terdengar sealami yang Anda inginkan.

  • Selain itu, menghubungkan ke model cloud untuk suara lain dapat menyebabkan potensi latensi atau biaya tambahan.

  • Jadi, ML Kit memberi Anda ucapan yang terdengar jauh lebih alami dibandingkan dengan TTS sistem tersebut.

  • ML Kit menawarkan delapan suara unik yang dapat Anda pilih dengan karakteristik berbeda untuk memenuhi kebutuhan aplikasi Anda.

  • Selain itu, ML Kit menawarkan dukungan bahasa yang andal dengan 21 lokalitas berbeda yang dapat Anda pilih.

  • Selain itu, salah satu manfaat besar di sini adalah setelah download awal, fitur ini akan berfungsi sepenuhnya di perangkat.

  • Jadi, model ini akan didownload ke sistem dan akan dibagikan ke seluruh aplikasi, sehingga tidak akan meningkatkan ukuran APK Anda.

  • Selain tersedia secara offline, yang sangat penting bagi pengguna kacamata yang sedang bepergian, mereka mungkin tidak memiliki Wi-Fi atau mungkin berada di area dengan jangkauan yang buruk, tetapi Anda juga kemungkinan akan melihat performa yang lebih baik, karena Anda tidak perlu melakukan panggilan bolak-balik ke server.

  • Oke.

  • Jadi, mari kita lihat detail library, dan cara membangunnya.

  • Jadi, pertama-tama, tentu saja, Anda hanya perlu menambahkan dependensi.

    dependencies {
       // ML Kit GenAI TTS SDK
       implementation("com.google.mlkit:genai-text-to-speech:1.0.0-alpha1")
    }
  • Jadi, di sini Anda hanya memerlukan SDK Text To Speech ML Kit.

  • Kemudian, Anda dapat mulai menulis kode.

  • Jadi, library GenAI ML Kit menyertakan Speech Synthesizer API.

    // 1. Initializing the SpeechSynthesizer client.
    val options = SpeechSynthesizerOptions.Builder(Locale.US).build()
    val client = SpeechSynthesis.getClient(options)
    
    // 2. Check and download the voice model.
    val voiceInfo = client.getSupportedVoices().firstOrNull()
    
    if (voiceInfo != null && client.checkStatus(voiceInfo) == FeatureStatus.DOWNLOADABLE) {
       client.download(voiceInfo).collect { status -> println("Download status: $status") }
    } else if (voiceInfo == null) {
       // Tip: Fallback to system TTS if ML Kit voice is unavailable
    }
  • Dengan demikian, Anda dapat menerapkan suara pilihan Anda dengan mudah.

  • Langkah pertama yang akan Anda lakukan di sini adalah melakukan inisialisasi klien menggunakan speech synthesizer lagi, dengan menetapkan lokalitas yang Anda pilih.

  • Kemudian, Anda akan memeriksa status download dan melihat apakah suara sudah didownload, lalu memilihnya.

  • Dalam contoh ini, kita memilih suara pertama, tetapi kami juga ingin menunjukkan bahwa kita menggunakan firstOrNull.

  • Seperti yang saya sebutkan, ML Kit memerlukan ponsel tertentu yang mumpuni, yaitu perangkat Samsung atau Pixel.

  • Jadi, jika Anda mendapatkan nilai null, itu bisa berarti bahwa pengguna mungkin tidak menggunakan ponsel yang kompatibel.

  • Kemudian, Anda hanya perlu memastikan bahwa Anda memiliki penggantian, baik itu kembali ke Text To Speech Sistem atau seperti memutar pesan yang direkam atau semacamnya.

  • Oke, lalu Anda akan menggunakan speech synthe- SpeechSynthesizerRequest untuk membuat permintaan, memberikan teks input, lalu menetapkan penggunaan dan jenis konten.

    // 3. Construct the SpeechSynthesizerRequest
    val request = SpeechSynthesizerRequest(
       input = SpeechSynthesizerRequest.Input.Text("Hello world", voiceInfo),
       audioAttributes = AudioAttributes.Builder()
           .setUsage(AudioAttributes.USAGE_MEDIA)
           .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
           .build()
    )
    
    // 4. Speak and collect status
    client.synthesize(request).collect { response ->
       when (response) {
           is SpeechSynthesizerResponse.StatusUpdate -> println("Playback status: ${response.status}")
       }
    }
  • Putar ucapan, pantau statusnya, dan ketahui kapan ucapan selesai, lalu kumpulkan error yang mungkin terjadi.

  • Lalu, tutup resource apa pun jika diperlukan.

    // 4. Speak and collect status
    client.synthesize(request).collect { response ->
       when (response) {
           is SpeechSynthesizerResponse.StatusUpdate -> println("Playback status: ${response.status}")
       }
    }
    
    // 5. Release resources when finished (e.g., on Activity destroy)
    override fun onDestroy() {
       super.onDestroy()
       client.close()
    }
  • Jadi, cukup mudah, bukan?

  • Dengan langkah-langkah ini, Anda dapat mengubah suara aplikasi dari yang terdengar seperti ini…

  • Halo, developer Android.

  • Senang bertemu Anda semua hari ini.

  • Kami harap Anda semua menikmati presentasi kami tentang pengalaman yang mengutamakan audio.

  • Menjadi sesuatu yang terdengar lebih seperti ini.

  • Halo developer Android.

  • Senang bertemu Anda semua hari ini.

  • Kami harap Anda semua menikmati presentasi kami tentang pengalaman yang mengutamakan audio.

  • Jauh lebih baik, bukan?

  • Oke.

  • Jadi, library Text to Speech ML Kit adalah alat yang sangat canggih, tetapi Anda tidak hanya terbatas pada penggunaan suara ini, Anda juga dapat memutar earcon dengan library ini.

    // 1. Register Earcon resource with Builder
    SpeechSynthesizerOptions.Builder(Locale.US)
       .addEarcon(
           name = "shutter_sound",
           Uri = "path/to/earcon.file".toUri()
       )
       .build()
    
    // 2. Request Earcon playback
    val request = SpeechSynthesizerRequest(
       input = SpeechSynthesizerRequest.Input.Earcon(
           name = "shutter_sound"
       ),
       audioAttributes = AudioAttributes.Builder()
           .setUsage(AudioAttributes
               .USAGE_ASSISTANCE_SONIFICATION)
           .setContentType(AudioAttributes
               .CONTENT_TYPE_SONIFICATION)
           .build()
    )
  • Jadi, earcon, seperti namanya, pada dasarnya adalah ikon yang setara dengan audio.

  • Dengan begitu, Anda dapat memutar suara singkat untuk berkomunikasi dengan pengguna.

  • Dan seperti ikon visual dengan earcon, pengguna perlu mengetahui apa itu dan apa artinya.

  • Jadi, pada awalnya Anda mungkin ingin menyandingkannya dengan notifikasi suara untuk memperjelasnya.

  • Kami juga telah membuat beberapa suara standar yang tersedia di Android Design Hub. Anda dapat menggunakannya, mendownloadnya langsung dari sana, dan menggunakannya untuk hal-hal seperti membuka aplikasi, menutup aplikasi, notifikasi error, dan membisukan atau membunyikan audio.

  • Namun, Anda juga memiliki opsi untuk membuat earcon kustom Anda sendiri.

  • Jadi, untuk earcon, ada beberapa praktik terbaik yang sebaiknya Anda ikuti, baik Anda menggunakan earcon yang didownload dari Design Hub maupun membuat earcon sendiri.

  • Jadi, Anda harus mempertimbangkan cara menggunakan earcon dan cara menggunakannya.

  • Jadi, ada beberapa hal yang perlu diingat, misalnya, untuk pemula, cobalah untuk tidak menggunakan earcon secara berlebihan.

  • Jangan memutar ulang suara yang sama berulang kali, karena dapat menyebabkan kelelahan telinga.

  • Ingatlah bahwa earcon Anda harus sangat intuitif, serta gunakan nada dan ritme yang sudah dikenal saat Anda menerapkannya.

  • Kemudian, cobalah untuk menghindari earcon yang terlalu rumit dan memerlukan penjelasan, earcon ini mungkin lebih cocok sebagai notifikasi suara.

  • Lalu, selalu ingat bahwa apa yang mungkin terdengar halus di studio atau di sistem Anda, di speaker komputer Anda, dapat menjadi mengganggu setelah diputar berulang kali oleh pengguna Anda.

  • Jadi, usahakan untuk tidak membebani pengguna dengan suara yang mungkin membingungkan mereka atau membuat mereka mengabaikan peringatan penting.

  • Oke.

  • Jadi, sekarang kami memiliki kemampuan untuk memberikan isyarat dan masukan audio, baik melalui ucapan alami maupun menggunakan earcon.

  • Namun, bagaimana dengan input?

  • Jadi, tentu saja ada touchpad, atau tombol khusus juga di perangkat, yang dapat Anda gunakan untuk membuat interaksi ketuk dan geser.

  • Namun, Anda mungkin juga ingin mengizinkan UI percakapan ini, dan untuk itu, Anda dapat menggunakan API Pengenalan Ucapan GenAI ML Kit.

  • Saat ini dalam versi alfa dan tersedia di perangkat tertentu, tetapi pada dasarnya fitur ini berjalan dalam dua mode yang berbeda.

  • Jadi, ada mode dasar yang menggunakan pengenalan ucapan di perangkat tradisional, dan tersedia di perangkat Android dengan API level 31 dan yang lebih tinggi.

  • Lalu, ada juga mode lanjutan yang menggunakan Gemini Nano, yang ditawarkan di perangkat Pixel 10 ke atas dan dengan mode ini, Anda akan melihat kualitas dan cakupan bahasa yang lebih baik.

  • Jadi, SpeechRecognizer mengikuti pola kode yang sangat mirip dengan SpeechSynthesizer.

  • Anda membuat klien, memeriksa apakah model tersedia, mendownload jika diperlukan, membuat permintaan, dan merilis resource Anda.

  • Jadi, mari kita fokus pada perbedaan utama saat Anda membuat permintaan, merekam audio mikrofon, lalu memproses hasilnya.

  • Sekali lagi, Anda perlu menambahkan dependensi yang diperlukan.

    dependencies {
       // ML Kit Speech Recognition
       implementation("com.google.mlkit:genai-speech-recognition:1.0.0-alpha1")
    }
  • Yang Anda perlukan di sini hanyalah Speech Recognition API.

  • Kemudian, Anda dapat mulai membuat permintaan.

  • Jadi, Anda akan menggunakan fungsi penangguhan saat menentukan logika pengenalan.

    suspend fun startMyRecognition() {
       // choose locale and mode
       val options: SpeechRecognizerOptions =
           speechRecognizerOptions {
               locale = Locale.US
               preferredMode = SpeechRecognizerOptions.Mode.MODE_ADVANCED
           }
    
       val speechRecognizer: SpeechRecognizer = SpeechRecognition.getClient(options)
    
       val request: SpeechRecognizerRequest =
           speechRecognizerRequest { audioSource = AudioSource.fromMic() }
    ...
  • Lalu, tentukan opsi pengenalan ucapan Anda, dengan menetapkan lokalitas dan preferredMode.

  • Di sini, Anda juga akan memilih audioSource dan menentukan permintaan itu sendiri.

  • Kemudian, Anda akan memulai pengenalan dan mengumpulkan respons.

    speechRecognizer.startRecognition(request).collect { response ->
       when (response) {
           is SpeechRecognizerResponse.PartialTextResponse -> {
               // Real-time: Act immediately if trigger phrase is heard
               handleResponse(response.text, speechRecognizer)
           }
           is SpeechRecognizerResponse.FinalTextResponse -> {
               // Final result and recognition
               handleResponse(response.text, speechRecognizer)
           }
           is SpeechRecognizerResponse.CompletedResponse -> {
               resetListeningUi()
           }
           is SpeechRecognizerResponse.ErrorResponse -> {
               Log.e("SpeechRec", "Error: ${response.e.errorCode}", response.e)
               resetListeningUi()
           }
    ...
  • Jadi, dengan SpeechRecognizer, Anda memiliki empat potensi respons: parsial, final, error, dan lengkap.

  • Partial akan melihat streaming real-time, sehingga digunakan untuk hal-hal seperti hotword atau kata kunci.

  • Final mengambil streaming audio akhir setelah menganalisis dan memperbaruinya sepenuhnya, lalu completed adalah setelah ucapan selesai, dan error mengumpulkan error yang mungkin terjadi.

  • Berikut cara kami menggabungkan semuanya.

    // Helper function to check for multiple phrases and trigger the right action
    private suspend fun handleResponse(text: String, recognizer: SpeechRecognizer) {
       val savePhrases = listOf("save", "bookmark", "remember")
       if (savePhrases.any { text.contains(it) }) {
    
           // 1. Update app state immediately
           saveItemForLater()
    
           // 2. Stop the recognizer to enforce the action and prevent TTS echo
           recognizer.stopRecognition()
    
           // 3. Play the mute earcon for immediate, non-verbal confirmation
           playEarcon()
    
           // 4. Provide voice feedback
           playAudioFeedback("Saved")
       }
    }
  • Misalnya, kita ingin pengguna dapat menggunakan perintah suara untuk memberi tahu aplikasi agar menyimpan beberapa jenis konten untuk nanti.

  • Kita dapat menggunakan satu perintah suara eksplisit yang telah kita beri tahukan kepada mereka untuk digunakan atau Anda dapat mengizinkan mereka menggunakan sejumlah kata kunci dan frasa.

  • Jadi, di sini kita mengizinkan mereka menggunakan: simpan, bookmark, atau ingat.

  • Segera setelah SpeechRecognizer mendeteksi bahwa pengguna telah menggunakan salah satu frasa tersebut, aplikasi akan menghentikan pengenalan ucapan, menyimpan konten, memutar earcon kustom, dan menggunakan Text to Speech GenAI ML Kit untuk memberi tahu pengguna bahwa konten telah disimpan.

Studi kasus Pengajar Bahasa XR

  • Oke.

  • Jadi, kita telah membahas banyak hal.

  • Mungkin terasa agak abstrak.

  • Jika Anda seperti saya, Anda ingin melihat beberapa contoh nyata.

  • Saya dan Alice ingin memandu Anda melakukan hal itu.

  • Dia akan memandu Anda menggunakan XR Language Teacher di aplikasi Google AI Edge Gallery.

  • Tim Alice yang membuatnya, dan dia akan menunjukkan kepada Anda cara kerjanya.

  • Silakan.

  • Terima kasih, Amy.

  • Ya.

  • Jadi, saya ingin memulai dengan sesuatu yang mungkin sudah Anda kenal.

  • Saya sedang belajar bahasa Jepang, dan saya telah menghabiskan waktu berjam-jam di aplikasi pembelajaran bahasa, kartu flash, streak, semuanya.

  • Kemudian, saya mendarat di Tokyo, saya berjalan ke aula pasar dan menyadari bahwa hampir tidak ada kosakata yang saya pelajari di depan saya.

  • Ada mainan kayu cup-and-ball di kios pasar yang saya kenali, tetapi saya tidak tahu cara mengucapkannya dalam bahasa Jepang.

  • Ada hiasan di jendela toko yang ingin saya beli dan tidak dapat saya sebutkan namanya.

  • Saat itulah saya paling termotivasi untuk mempelajari sebuah kata.

  • Bukan di sofa sambil melihat aplikasi bahasa.

  • Pada saat itulah, saya melihat hal yang ingin saya pelajari.

  • Jadi, inilah yang saya inginkan.

  • Saya ingin memakai kacamata pintar saya sepanjang hari, cukup berjalan-jalan.

  • Dan setiap kali ada sesuatu yang menarik perhatian saya, saya cukup menanyakannya secara lisan.

  • Kemudian, pada malam hari, saat saya kembali ke hotel, semua yang saya tanyakan akan menunggu saya seperti kartu kosakata di ponsel saya.

  • Dan inilah yang kami bangun.

  • Mari kita tonton klip singkat.

  • Jadi, kami menyebutnya Pengajar Bahasa XR.

  • Halo.

  • Apa yang ingin Anda pelajari hari ini?

  • Anda juga dapat menyesuaikan pengalaman belajar di setelan pengajar.

  • Misalnya, pilih bahasa yang ingin Anda pelajari dan pilih persona pengajar tertentu yang sesuai untuk Anda.

  • Serius.

  • Anda juga dapat beralih antara mode kacamata dan ponsel.

  • Bagaimana cara mengatakan anggur ini dalam bahasa Spanyol?

  • Berdasarkan ini, anggur yang lezat itu disebut uvas.

  • Dalam bahasa Spanyol, Anda dapat mengatakan, "Estas uvas son deliciosas", untuk mendeskripsikannya.

  • Saya ingin mengatakan anggur hijau, khususnya.

  • Izinkan kami memeriksanya.

  • Untuk menentukan anggur hijau, Anda dapat mengatakan, "Uvas verdes.

  • Me gustan las uvas verdes," adalah cara yang bagus untuk memberi tahu seseorang bahwa Anda menyukainya.

  • Bagaimana cara mengatakannya dalam bahasa Prancis, dan bagaimana cara meminta tiga buah?

  • Mari kita lihat.

  • Kue yang terlihat lezat itu disebut des madeleines.

  • Dalam bahasa Prancis, untuk meminta tiga, Anda dapat mengatakan, "Je voudrais trois madeleines, s'il vous plaît."

  • Bagaimana cara meminta perubahan dengan ini?

  • Mari kita lihat apa yang kita miliki di sini.

  • Untuk meminta uang kembalian, Anda dapat mengucapkan, "Otsuri wa arimasu ka?"

  • Yang berarti, "Apakah Anda punya uang kembalian?"

  • Anda juga dapat menggunakan, "Otsuri o onegaishimasu", untuk meminta kembalian dengan sopan.

  • Kemudian, semua yang Anda pelajari akan otomatis disimpan sebagai kartu kosakata untuk Anda.

  • La botella de agua.

  • Esta es una botella de agua.

  • Ya, dan Anda dapat menguji ingatan serta berlatih di tab belajar.

  • Oke.

  • Ya.

  • Jadi, semua yang baru saja Anda lihat berjalan di perangkat, tanpa jaringan sama sekali.

  • Saya bepergian dengan paket data internasional, yang biasanya baik-baik saja sampai saya berada di dalam aula pasar atau mungkin di bawah tanah atau di balik beton tebal.

  • Saat Anda sangat menginginkan fitur ini, sering kali sinyalnya justru paling buruk.

  • Dan menurut saya, pengalaman yang hilang saat sinyal turun bukanlah teman perjalanan yang sesungguhnya. Itulah sebabnya kami membuat XR Language Teacher berfungsi sepenuhnya secara offline dan di perangkat.

Merangkai model di perangkat

  • Jadi, bagaimana cara membuatnya?

  • Secara arsitektur, Amy telah menunjukkan kepada Anda cara menggunakan frame kamera yang diproyeksikan dari kacamata ke ponsel.

  • Dia menunjukkan cara menggunakan ML Kit, pengenalan ucapan, untuk mengubah teks menjadi ucapan, dan juga Text to Speech ML Kit yang mengubah teks kembali menjadi ucapan.

  • Yang masih kita butuhkan adalah otak di tengah, sesuatu yang dapat melihat frame kamera dan pertanyaan secara bersamaan, dan mencari tahu apa yang sebenarnya ditanyakan pengguna.

  • Kecerdasan tersebut adalah Gemini Nano 4, yang dibangun di atas Gemma 4, model open source Google yang berjalan secara lokal di ponsel.

  • Jadi, di perangkat Android unggulan yang didukung, Anda bisa mendapatkan performa yang dioptimalkan dengan menggunakan API ML Kit secara langsung.

  • Sistem Android akan menangani pengiriman model untuk Anda, sehingga Anda tidak perlu memaketkan apa pun di aplikasi.

  • Jadi, untuk menggabungkan semuanya, mikrofon masuk ke pengenalan ucapan, dan frame kamera serta transkrip bersama-sama masuk ke Gemini Nano 4, dan Gemini Nano 4 menulis ke sintesis ucapan, lalu keluar dari speaker.

  • Tiga model, yang saling terhubung, semuanya berjalan secara lokal di ponsel Anda.

  • Berikut beberapa alasan mengapa Gemini Nano 4 sangat cocok untuk masalah ini.

  • Pertama, model ini melihat dan membaca dalam satu proses.

  • Melalui ML Kit, Gemini Nano 4 menangani teks dan gambar secara native, sehingga Anda tidak perlu menggunakan detektor, lalu pengklasifikasi, lalu penerjemah.

  • Model ini adalah satu model yang melihat frame kamera dan pertanyaan secara bersamaan.

  • Kedua, dukungan bahasanya yang luas.

  • Gemini Nano 4 dilatih menggunakan lebih dari 140 bahasa.

  • Selain itu, untuk tutor bahasa, terjemahan saja tidak cukup.

  • Anda ingin idiom, Anda ingin register formal versus kasual, Anda juga ingin contoh kalimat yang akan diucapkan oleh orang sungguhan.

  • Dan terakhir, model ini cukup dapat dikontrol untuk memiliki kepribadian.

  • Berlatih pengucapan dengan suara keras bisa jadi menakutkan.

  • Model ini juga mengikuti perintah sistem dengan baik, sehingga pengguna dapat memilih persona pengajar mereka sendiri.

  • Dan mungkin, asisten yang sabar dan menyemangati bisa membuat orang lebih mau mencoba.

  • Dan berikut satu hal lagi yang ingin saya soroti tentang desain ini.

  • Saat percakapan berlangsung dalam mode kacamata, aplikasi diam-diam menulis kartu kosakata di latar belakang.

  • Kata, terjemahan, contoh kalimat, dan foto dari momen Anda mengajukan pertanyaan.

  • Pengguna tidak perlu mengetuk apa pun secara manual.

  • Mereka hanya berjalan dan berbicara.

  • Kemudian, pada hari yang sama, semuanya sudah tersedia di ponsel mereka, persis seperti yang saya inginkan saat berada di Tokyo.

  • Jadi, mengutamakan audio tidak berarti hanya audio.

  • Kacamata adalah platform yang tepat untuk rasa ingin tahu, dan ponsel Anda adalah platform yang tepat untuk refleksi setelahnya.

  • Biarkan momen handsfree meninggalkan sesuatu.

  • Sekarang, mari kita bahas beberapa tips praktis untuk membangun pengalaman real-time dengan Gemini Nano 4 dan ML Kit yang kami pelajari dari pembuatan demo ini.

Memprioritaskan latensi real-time dengan desain dua penerusan

  • Tips 1, prioritaskan latensi real-time dengan desain dua tahap.

  • Di kacamata pintar audio, saat Anda bertanya, "Apa itu?"

  • Setiap momen hening akan terlihat.

  • Dalam contoh Pengajar Bahasa XR, kita memerlukan dua hal untuk setiap giliran interaksi pengguna dari model: jawaban lisan langsung, dan juga kartu kosakata terstruktur untuk disimpan ke aplikasi.

  • Jika kita meminta model untuk melakukan dua hal sekaligus dalam satu proses, setiap token yang digunakan untuk pembuatan data latar belakang tersebut akan menunda kalimat lisan pertama.

  • Jadi, kita memisahkan apa yang dibutuhkan pengguna saat ini dari apa yang dibutuhkan aplikasi beberapa detik kemudian.

  • Jadi, kami membagi setiap giliran menjadi dua tahap.

  • Pada Pass 1, kami melakukan streaming frame kamera dan pertanyaan untuk balasan lisan saja, sehingga memicu text-to-speech segera setelah kalimat pertama selesai.

  • Dan karena TPU atau NPU tersebut selesai menghasilkan balasan singkat jauh sebelum text-to-speech selesai membacakan dengan keras, kita sebenarnya mendapatkan jendela beberapa detik saat pengguna masih mendengarkan, dan chip sudah tidak aktif.

  • Dan karena Pass 1 telah mengidentifikasi objek dalam balasan teksnya, Pass 2 bahkan tidak memerlukan input gambar.

  • Kita cukup meneruskan balasan Pass 1 kembali ke chip yang tidak aktif tersebut untuk mengekstrak dan menyimpan kartu terstruktur bahkan sebelum pengajar selesai berbicara.

  • Sekarang, mari kita perbesar ke Tahap 1, yang akan-- membawa kita ke tips kedua.

  • Gunakan tag XML ringan saat melakukan streaming.

  • Karena Pass 1 melakukan streaming langsung ke text-to-speech, Anda tidak ingin objek JSON yang berat menghambat kata pertama yang diucapkan.

  • Sebagai gantinya, Anda memerlukan teks biasa yang dapat langsung diucapkan dengan tag inline yang ringan dan aktif setiap kali aplikasi perlu mengambil tindakan di tengah streaming.

  • Jadi, mari kita lihat masalah yang membawa kita ke situasi saat ini.

  • Ingat mainan kayu cup-and-ball di kios pasar yang saya sebutkan?

  • Dalam bahasa Jepang, mainan ini disebut "kendama".

  • Sejak awal, model mengenalinya dari frame kamera dan memberikan jawaban yang benar, "Itu kendama, mainan kayu".

  • Jadi, kami memasukkan kalimat lengkap tersebut ke dalam sesi text-to-speech bahasa Inggris, dan inilah hasilnya.

  • Itu ken-mi, mainan kayu.

  • Sepertinya ada yang salah.

  • Sebaliknya, kalimat itu seharusnya terdengar…

  • Itu kendama, mainan kayu.

  • Jadi, mengapa hal itu terjadi?

  • Kendama ditulis dengan hiragana, "ken", dan karakter kanji, "dama".

  • Mesin text-to-speech bahasa Inggris menangani hiragana fonetik seperti "ken" dengan baik, tetapi benar-benar gagal saat mencapai bagian kanji dan mengubah dama menjadi sesuatu yang terdengar seperti me.

  • Hal ini sebenarnya terjadi di berbagai bahasa dengan cara yang berbeda jika Anda tidak beralih lokalitas.

  • Misalnya, dalam bahasa Spanyol, Anda mungkin mendengar…

  • Suh-BOH-luh…

  • Saat Anda benar-benar mengharapkan…

  • Cebolla.

  • Demikian pula, dalam bahasa Prancis, Anda mungkin mendengar…

  • PAIN oh chock-uh-lat…

  • Padahal, Anda sebenarnya mengharapkan…

  • Pain au chocolat.

  • Ya, sesi TTS biasanya dirancang untuk satu lokalitas pada satu waktu, tetapi pengajar bahasa perlu beralih kode dalam setiap kalimat.

  • Jadi, di tahap 1, kita meminta model untuk menggabungkan setiap kata atau frasa bahasa target di dalam tag XML target saat melakukan streaming.

  • Saat potongan tiba, klien kami membaginya sesuai target, mengarahkan setiap rentang ke lokalitas Text To Speech yang cocok, yang bisa berupa bahasa Jepang, Spanyol, Prancis, atau bahasa apa pun yang Anda pelajari, lalu memutarnya kembali dengan lancar, mengubah aksen di tengah kalimat, sehingga kata seperti kendama diucapkan dengan benar.

  • Jadi, kesimpulannya adalah model sudah mengetahui kosakata dan kata mana yang termasuk dalam bahasa mana, dan dengan menandai rentang target secara inline saat streaming, prosesnya jauh lebih rapi daripada melakukan pascapemrosesan sendiri setelahnya.

  • Berikut adalah penerusan 1 dalam kode.

    // 1. Pass 1 System + Turn Prompt (XrLanguageTeacherPersona.kt)
    // System: "Always start immediately with <reply>...</reply> (strictly 1 to 3 sentences total).
    //   Inside <reply>, wrap every Japanese word AND every complete Japanese example sentence
    //   inside <target>...</target> tags (never output <card>)."
    val pass1TurnPrompt = """
      The student is looking at the camera view and asked: "$question". Answer in English
      teaching Japanese inside <reply>...</reply>: if they refer to 'this'/'that' or point to
      an object, ground it to the focal item in the camera frame; if they ask for a phrase or
      greeting, teach that phrase.
    """.trimIndent()
    
    // 2. Stream multimodal dialogue (ImagePart + TextPart) and split <target> tags to TTS
    val generativeModel = Generation.getClient()
    val pass1Request = generateContentRequest(ImagePart(frame), TextPart(pass1TurnPrompt)) {
      temperature = 1.0f; topK = 1; maxOutputTokens = 1024
    }
    generativeModel.generateContentStream(pass1Request).collect { chunk ->
      val delta = chunk.candidates.firstOrNull()?.text.orEmpty()
      streamReplyAndSplitTargetTagsToTts(delta) // Speaks 1st complete sentence immediately
    }
    // Streams: "<reply>That's <target>けん玉</target> — a wooden toy. <target>けん玉をください。</target></reply>"
  • Di bagian atas, kita menggunakan perintah untuk menginstruksikan model agar membalas dalam satu hingga tiga kalimat di dalam tag balasan, lalu menggabungkan setiap kata atau contoh kalimat bahasa Jepang di dalam tag target.

  • Kemudian, kita meneruskan kamera ImagePart dan perintah TextPart ke generateContentStream ML Kit, memisahkan rentang target menjadi Text To Speech saat setiap kalimat tiba.

  • Hal ini membawa kita ke tahap 2 dan tips ketiga.

  • Meskipun penggunaan tag XML ringan sangat bagus untuk streaming audio live, gunakan output terstruktur, yang dibuat untuk menampilkan objek yang diketik dan bersih saat menyimpan data ke aplikasi Anda.

  • Karena Pengajar Bahasa XR kami bersifat percakapan, pengguna juga dapat mengajukan pertanyaan lanjutan tanpa perlu mempelajari kata baru.

  • Dan saat sebuah kata diajarkan, database memerlukan kolom kamus yang bersih untuk membuat kartu kosakata.

  • Jadi, daripada menulis ekspresi reguler yang rentan untuk mengurai transkrip tahap satu, kita membiarkan tahap 2 mengekstrak objek yang aman dari jenis di latar belakang.

  • Dan untuk menerapkan skema di tahap 2, kita menggunakan API output terstruktur ML Kit, yang di balik layar menggunakan decoding terbatas.

    import com.google.mlkit.genai.prompt.Generation
    import com.google.mlkit.genai.prompt.generateTypedContentRequest
    import com.google.mlkit.genai.schema.annotations.Generable
    import com.google.mlkit.genai.schema.annotations.Guide
    
    // Pass 2 schema (XrLanguageTeacherGenerableSchemas.kt):
    @Generable(description = "Vocabulary flashcard for the taught word or short phrase")
    data class GenerableVocabCard(
      @Guide(description = TeacherResponseSchema.WORD_FIELD_DESCRIPTION) val word: String,
      @Guide(description = "Native-language meaning or translation") val meaning: String,
      @Guide(description = "Target-language example sentence") val example: String,
      @Guide(description = "Native-language translation of the example sentence") val example_translation: String,
    )
    
    @Generable(description = "Optional vocabulary card extracted from a teacher reply")
    data class GenerableOptionalVocabCardWrapper(
      @Guide(description = "Vocabulary flashcard if a vocabulary term was taught, or null otherwise")
      val card: GenerableVocabCard?
    )
  • Anda cukup menganotasi class data dengan @Generable dan setiap kolom dengan @Guide, seperti contoh class kartu kosakata di sini.

  • Dengan menggabungkan kolom kartu nullable, penerusan 2 akan menampilkan kartu yang terisi saat kata baru diajarkan, atau null pada giliran percakapan murni.

  • Berikut adalah kode untuk tahap 2.

    // 1. Pass 1 Streamed Output -> Pass 2 Extraction Prompt (no image needed!)
    val replyWithTargetTags =
      "<reply>That's <target>けん玉</target> — a wooden toy. <target>けん玉をください。</target></reply>"
    
    val pass2Prompt = """
      If the teacher reply below teaches or introduces a specific Japanese vocabulary item, extract
      only its core focal dictionary term into "card" with keys "word", "meaning", "example", and
      "example_translation". If purely conversational with no focal term taught, set "card" to null:
      $replyWithTargetTags
    """.trimIndent()
    
    // 2. Extract @Generable card on idle NPU while TTS audio plays
    val pass2Request = generateContentRequest(TextPart(pass2Prompt)) {
      temperature = 1.0f; topK = 1; maxOutputTokens = 256
    }
    val typedRequest =
      generateTypedContentRequest(pass2Request, GenerableOptionalVocabCardWrapper::class)
    val card: GenerableVocabCard? =
      generativeModel.generateContent(typedRequest).candidates.firstOrNull()?.response?.card
    // Extracts: {"word": "けん玉", "meaning": "a wooden toy", "example": "けん玉をください。", ...}
  • Di bagian atas, kita mengambil teks balasan yang di-streaming dari tahap 1, tanpa memerlukan gambar, dan membuat perintah ekstraksi.

  • Kemudian, saat pengguna masih mendengarkan Text To Speech, kita meneruskan perintah dan class wrapper ke generateTypedContentRequest dan mengekstrak kartu kosakata yang bersih dan bebas tag, atau null jika tidak ada kata yang diajarkan.

  • Oke.

  • Kita telah membahas banyak hal.

  • Mungkin Anda berpikir, "Bagus, satu lagi hal yang terlihat menarik di panggung, tetapi tidak akan pernah saya gunakan."

  • Bukan yang ini.

  • XR Language Teacher tersedia di aplikasi Google AI Edge Gallery bersama dengan pengalaman AI di perangkat lainnya.

  • Anda dapat mendownloadnya sekarang, menginstalnya di ponsel, dan mengarahkan kamera ke objek apa pun yang ingin Anda pelajari cara pengucapannya dalam bahasa lain.

  • Dan jika Anda ingin mengetahui cara pembuatannya, seluruh implementasi ini bersifat open source di GitHub.

  • Jangan khawatir jika tidak semua pengguna Anda memiliki kacamata audio atau kacamata pintar dengan layar, atau perangkat Android unggulan yang didukung.

  • Code base kami juga menunjukkan contoh cara pengalaman yang sama ini dapat disesuaikan untuk pengalaman khusus seluler.

  • Jika Anda juga ingin menjangkau platform lain, kode aplikasi Google AI Edge Gallery juga menunjukkan cara membuat fitur ini menggunakan runtime Google LiteRT dan MediaPipe Tasks API.

  • Atau, jika Anda ingin menggunakan model bahasa atau audio di perangkat open source lainnya, Anda juga dapat melihat cara melakukannya dari kode.

Beradaptasi dengan kasus penggunaan lain menggunakan agen AI

  • Jadi, kami menjadikan XR Language Teacher sebagai open source untuk mempermudah pembuatan prototipe Anda.

  • Arahkan agen pilihan Anda ke repo GitHub kami untuk mengubah pengalaman berbasis AI di perangkat yang aktif ini menjadi sesuatu yang lain.

  • Bisa jadi panduan museum, mungkin asisten memasak yang melihat meja dapur Anda, panduan perbaikan, narator aksesibilitas, alat inspeksi lapangan.

  • Model, runtime, implementasi open source, dan alatnya kini tersedia sehingga Anda dapat bersiap untuk peluncuran kacamata AI mendatang pada musim gugur ini.

  • Kami ingin melihat hasil kreasi Anda dengan fitur ini.

  • Sebagai penutup, hari ini, kami menunjukkan contoh-contoh luar biasa dari apa yang dapat dilakukan dengan model AI yang berjalan lancar di perangkat.

  • Berikut beberapa cara untuk memulai.

  • Pertama, ambil resource di layar.

  • Download aplikasi AI Edge Gallery untuk mencoba demo dan lihat kode referensi di GitHub.

  • Dan pindai kode QR untuk mengakses Android XR SDK, ML Kit API, dan penawaran Google AI Edge.

  • Kedua, mulai bereksperimen langsung di ponsel sekarang.

  • Ada banyak hal yang telah kita bahas yang sudah dapat dibuat dengan pengalaman yang mengutamakan perangkat seluler.

  • Ketiga, lihat aplikasi seluler yang sudah Anda kirim dan tanyakan pada diri sendiri, fitur inti apa yang akan lebih baik jika digunakan secara handsfree?

  • Menambahkan Aktivitas yang Diproyeksikan ke APK yang ada sudah cukup untuk menghadirkan pengalaman tersebut ke kacamata pintar.

  • Terima kasih banyak sudah bergabung bersama kami hari ini.

  • Kami tidak sabar melihat pengalaman luar biasa yang mengutamakan audio yang Anda bangun di Android dan untuk kacamata AI.

  • Terima kasih.

Kode

Cuplikan kode

Cuplikan Kotlin pada menit 02.39 di "Mem-build untuk Android XR"
dependencies {
   implementation("androidx.xr.projected:projected:1.0.0-alpha13")
}
Cuplikan Kotlin pada menit 02:45 di "Membangun untuk Android XR"
class ProjectedMainActivity : ComponentActivity() {
   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContent {
           // Glasses content
       }
   }
}
Cuplikan XML pada menit 03:02 di "Membangun untuk Android XR"
<activity
   android:name=".ProjectedMainActivity"
   android:exported="false"
   android:requiredDisplayCategory="android.hardware.display.category.XR_PROJECTED"
   android:label="Example activity for audio glasses">
   <intent-filter>
       <action android:name="android.intent.action.MAIN" />
       <category android:name="android.intent.category.XR_PROJECTED_LAUNCHER"/>
   </intent-filter>
</activity>
Cuplikan Kotlin pada menit 03:44 di "Menciptakan aplikasi untuk Android XR"
// Continuously monitor whether the glasses are connected
val isGlassesConnected by ProjectedContext.isProjectedDeviceConnected(
   context,
   scope.coroutineContext
).collectAsStateWithLifecycle(initialValue = false)

// Launch the activity
val options = ProjectedContext.createProjectedActivityOptions(context)
val intent = Intent(context, ProjectedMainActivity::class.java)
context.startActivity(intent, options.toBundle())

// Check if the device is audio only or has a display
val projectedDeviceController = ProjectedDeviceController.create(this@ProjectedMainActivity)
isVisualUiSupported = projectedDeviceController.capabilities.contains(CAPABILITY_VISUAL_UI)
Cuplikan Kotlin pada menit 05:05 di "Membangun untuk Android XR"
// In a projected activity
private fun requestProjectedPermissions() {
   lifecycleScope.launch {
       try {
           ProjectedActivityCompat.requestPermissions(
               this@PermissionsFromProjectedActivity,
               arrayOf(Manifest.permission.CAMERA),
               // CAMERA_PERMISSION_REQUEST_CODE is a developer defined constant
               requestCode = CAMERA_PERMISSION_REQUEST_CODE,
           )
       } catch (e: IllegalStateException) {
           // Thrown when the projected system service can't be bound.
           Log.e(TAG, "Request failed: projected service unavailable.", e)
       }
   }
}
Cuplikan shell pada menit 05:46 di "Membangun untuk Android XR"
android skills add projected-hardware
android skills add --all
Cuplikan Kotlin pada 08:14 di "Mendesain pengalaman yang mengutamakan audio"
dependencies {
   // ML Kit GenAI TTS SDK
   implementation("com.google.mlkit:genai-text-to-speech:1.0.0-alpha1")
}
Cuplikan Kotlin pada 08:26 di "Mendesain pengalaman yang mengutamakan audio"
// 1. Initializing the SpeechSynthesizer client.
val options = SpeechSynthesizerOptions.Builder(Locale.US).build()
val client = SpeechSynthesis.getClient(options)

// 2. Check and download the voice model.
val voiceInfo = client.getSupportedVoices().firstOrNull()

if (voiceInfo != null && client.checkStatus(voiceInfo) == FeatureStatus.DOWNLOADABLE) {
   client.download(voiceInfo).collect { status -> println("Download status: $status") }
} else if (voiceInfo == null) {
   // Tip: Fallback to system TTS if ML Kit voice is unavailable
}
Cuplikan Kotlin pada 09:26 di "Mendesain pengalaman yang mengutamakan audio"
// 3. Construct the SpeechSynthesizerRequest
val request = SpeechSynthesizerRequest(
   input = SpeechSynthesizerRequest.Input.Text("Hello world", voiceInfo),
   audioAttributes = AudioAttributes.Builder()
       .setUsage(AudioAttributes.USAGE_MEDIA)
       .setContentType(AudioAttributes.CONTENT_TYPE_SPEECH)
       .build()
)

// 4. Speak and collect status
client.synthesize(request).collect { response ->
   when (response) {
       is SpeechSynthesizerResponse.StatusUpdate -> println("Playback status: ${response.status}")
   }
}
Cuplikan Kotlin pada 09:47 di "Mendesain pengalaman yang mengutamakan audio"
// 4. Speak and collect status
client.synthesize(request).collect { response ->
   when (response) {
       is SpeechSynthesizerResponse.StatusUpdate -> println("Playback status: ${response.status}")
   }
}

// 5. Release resources when finished (e.g., on Activity destroy)
override fun onDestroy() {
   super.onDestroy()
   client.close()
}
Cuplikan Kotlin pada menit 10:29 di "Mendesain pengalaman yang mengutamakan audio"
// 1. Register Earcon resource with Builder
SpeechSynthesizerOptions.Builder(Locale.US)
   .addEarcon(
       name = "shutter_sound",
       Uri = "path/to/earcon.file".toUri()
   )
   .build()

// 2. Request Earcon playback
val request = SpeechSynthesizerRequest(
   input = SpeechSynthesizerRequest.Input.Earcon(
       name = "shutter_sound"
   ),
   audioAttributes = AudioAttributes.Builder()
       .setUsage(AudioAttributes
           .USAGE_ASSISTANCE_SONIFICATION)
       .setContentType(AudioAttributes
           .CONTENT_TYPE_SONIFICATION)
       .build()
)
Cuplikan Kotlin pada menit 13:42 di "Mendesain pengalaman yang mengutamakan audio"
dependencies {
   // ML Kit Speech Recognition
   implementation("com.google.mlkit:genai-speech-recognition:1.0.0-alpha1")
}
Cuplikan Kotlin pada menit 13:52 di "Mendesain pengalaman yang mengutamakan audio"
suspend fun startMyRecognition() {
   // choose locale and mode
   val options: SpeechRecognizerOptions =
       speechRecognizerOptions {
           locale = Locale.US
           preferredMode = SpeechRecognizerOptions.Mode.MODE_ADVANCED
       }

   val speechRecognizer: SpeechRecognizer = SpeechRecognition.getClient(options)

   val request: SpeechRecognizerRequest =
       speechRecognizerRequest { audioSource = AudioSource.fromMic() }
...
Cuplikan Kotlin pada menit 14:12 di "Mendesain pengalaman yang mengutamakan audio"
speechRecognizer.startRecognition(request).collect { response ->
   when (response) {
       is SpeechRecognizerResponse.PartialTextResponse -> {
           // Real-time: Act immediately if trigger phrase is heard
           handleResponse(response.text, speechRecognizer)
       }
       is SpeechRecognizerResponse.FinalTextResponse -> {
           // Final result and recognition
           handleResponse(response.text, speechRecognizer)
       }
       is SpeechRecognizerResponse.CompletedResponse -> {
           resetListeningUi()
       }
       is SpeechRecognizerResponse.ErrorResponse -> {
           Log.e("SpeechRec", "Error: ${response.e.errorCode}", response.e)
           resetListeningUi()
       }
...
Cuplikan Kotlin pada menit 14:41 di "Mendesain pengalaman yang mengutamakan audio"
// Helper function to check for multiple phrases and trigger the right action
private suspend fun handleResponse(text: String, recognizer: SpeechRecognizer) {
   val savePhrases = listOf("save", "bookmark", "remember")
   if (savePhrases.any { text.contains(it) }) {

       // 1. Update app state immediately
       saveItemForLater()

       // 2. Stop the recognizer to enforce the action and prevent TTS echo
       recognizer.stopRecognition()

       // 3. Play the mute earcon for immediate, non-verbal confirmation
       playEarcon()

       // 4. Provide voice feedback
       playAudioFeedback("Saved")
   }
}
Cuplikan Kotlin pada 26:27 di "Memprioritaskan latensi real-time dengan desain dua penerusan"
// 1. Pass 1 System + Turn Prompt (XrLanguageTeacherPersona.kt)
// System: "Always start immediately with <reply>...</reply> (strictly 1 to 3 sentences total).
//   Inside <reply>, wrap every Japanese word AND every complete Japanese example sentence
//   inside <target>...</target> tags (never output <card>)."
val pass1TurnPrompt = """
  The student is looking at the camera view and asked: "$question". Answer in English
  teaching Japanese inside <reply>...</reply>: if they refer to 'this'/'that' or point to
  an object, ground it to the focal item in the camera frame; if they ask for a phrase or
  greeting, teach that phrase.
""".trimIndent()

// 2. Stream multimodal dialogue (ImagePart + TextPart) and split <target> tags to TTS
val generativeModel = Generation.getClient()
val pass1Request = generateContentRequest(ImagePart(frame), TextPart(pass1TurnPrompt)) {
  temperature = 1.0f; topK = 1; maxOutputTokens = 1024
}
generativeModel.generateContentStream(pass1Request).collect { chunk ->
  val delta = chunk.candidates.firstOrNull()?.text.orEmpty()
  streamReplyAndSplitTargetTagsToTts(delta) // Speaks 1st complete sentence immediately
}
// Streams: "<reply>That's <target>けん玉</target> — a wooden toy. <target>けん玉をください。</target></reply>"
Cuplikan Kotlin pada menit 27:33 di "Memprioritaskan latensi real-time dengan desain dua penerusan"
import com.google.mlkit.genai.prompt.Generation
import com.google.mlkit.genai.prompt.generateTypedContentRequest
import com.google.mlkit.genai.schema.annotations.Generable
import com.google.mlkit.genai.schema.annotations.Guide

// Pass 2 schema (XrLanguageTeacherGenerableSchemas.kt):
@Generable(description = "Vocabulary flashcard for the taught word or short phrase")
data class GenerableVocabCard(
  @Guide(description = TeacherResponseSchema.WORD_FIELD_DESCRIPTION) val word: String,
  @Guide(description = "Native-language meaning or translation") val meaning: String,
  @Guide(description = "Target-language example sentence") val example: String,
  @Guide(description = "Native-language translation of the example sentence") val example_translation: String,
)

@Generable(description = "Optional vocabulary card extracted from a teacher reply")
data class GenerableOptionalVocabCardWrapper(
  @Guide(description = "Vocabulary flashcard if a vocabulary term was taught, or null otherwise")
  val card: GenerableVocabCard?
)
Cuplikan Kotlin pada 28:00 di "Memprioritaskan latensi real-time dengan desain dua penerusan"
// 1. Pass 1 Streamed Output -> Pass 2 Extraction Prompt (no image needed!)
val replyWithTargetTags =
  "<reply>That's <target>けん玉</target> — a wooden toy. <target>けん玉をください。</target></reply>"

val pass2Prompt = """
  If the teacher reply below teaches or introduces a specific Japanese vocabulary item, extract
  only its core focal dictionary term into "card" with keys "word", "meaning", "example", and
  "example_translation". If purely conversational with no focal term taught, set "card" to null:
  $replyWithTargetTags
""".trimIndent()

// 2. Extract @Generable card on idle NPU while TTS audio plays
val pass2Request = generateContentRequest(TextPart(pass2Prompt)) {
  temperature = 1.0f; topK = 1; maxOutputTokens = 256
}
val typedRequest =
  generateTypedContentRequest(pass2Request, GenerableOptionalVocabCardWrapper::class)
val card: GenerableVocabCard? =
  generativeModel.generateContent(typedRequest).candidates.firstOrNull()?.response?.card
// Extracts: {"word": "けん玉", "meaning": "a wooden toy", "example": "けん玉をください。", ...}