कंटेंट पर जाएँ
charmotion

onModeChange के साथ ElevenLabs एजेंट अवतार

Charmotion टीम द्वारा · अपडेट:

AI assistant अवतार गाइड का कवर इलस्ट्रेशन: onModeChange के साथ ElevenLabs Agent अवतार, Charmotion के डेमो कैरेक्टर के साथ

ElevenLabs React SDK में useConversation agent का mode 'speaking' या 'listening' के रूप में बताता है और बदलने पर onModeChange को कॉल करता है। speaking को talking लूप से और listening को listening लूप से जोड़ें, जब status connecting हो तब loading स्टेट दिखाएँ, और connect व disconnect पर enter और exit रिएक्शन चलाएँ।

मुख्य बातें

  • mode 'speaking' या 'listening' होता है; isSpeaking और isListening इसके boolean shortcut हैं।
  • Connection का status disconnected, connecting और connected से होकर गुज़रता है।
  • अवतार को callbacks से ref के ज़रिए अपडेट करें, React state से नहीं, ताकि streaming audio से अतिरिक्त renders न हों।
  • getOutputByteFrequencyData() और getInputVolume() audio-reactive visuals के लिए हैं।

पहले से कोई कैरेक्टर या लोगो है? अपने कैरेक्टर को असली ऐप स्क्रीन में देखें: स्प्लैश, ऑनबोर्डिंग, लोडिंग और एम्प्टी स्टेट स्क्रीन। यह फ़्री है, आपके ब्राउज़र में चलता है और कुछ भी अपलोड नहीं होता।

कौन से ElevenLabs events बताते हैं कि agent बोल रहा है?

ElevenLabs Agents React SDK का केंद्र useConversation hook है। इसका documentation वे fields और callbacks बताता है जिनकी अवतार को ज़रूरत होती है (ElevenLabs React SDK):

Field या callbackValuesअवतार में उपयोग
mode'speaking' | 'listening'Talking बनाम listening लूप
isSpeaking, isListeningBooleansवही, flags के रूप में
onModeChangemode बदलने पर कॉल होता हैmood को सीधे सेट करें
statusdisconnected | connecting | connectedConnect होते समय loading
onConnect, onDisconnectSession की शुरुआत और अंतEnter और exit रिएक्शन
onStatusChangestatus बदलने पर कॉल होता हैऊपर के दोनों का विकल्प
onErrorError की जानकारीError रिएक्शन
getInputVolume(), getOutputByteFrequencyData()Audio डेटाऑडियो पर रिएक्ट करने वाले विज़ुअल

OpenAI Realtime API के उलट, यहाँ आपको raw audio events से speaking phase का अंदाज़ा नहीं लगाना पड़ता। SDK playback संभालता है और बताता है कि agent कब speaking और listening के बीच बदलता है।

उस सूची में अलग से कोई "thinking" mode नहीं है। Agent या तो बोल रहा होता है या सुन रहा होता है; यूज़र के बोलना खत्म करने के बाद का अंतराल listening का ही हिस्सा है। अगर आप thinking स्टेट दिखाना चाहते हैं, तो अंदाज़े के बिना इसे जोड़ने का तरीका नीचे connection states वाले सेक्शन में देखें।

mode और status को अवतार के मूड से कैसे जोड़ें?

मूड को सीधे callbacks के अंदर सेट करें। Rive view model तक ref के ज़रिए पहुँचें, ताकि callbacks हमेशा मौजूदा instance देखें, भले ही वे पहले render पर define हुए हों। यह एक client component है, इसलिए Next.js में यह "use client" से शुरू होता है।

"use client";

import { useRef } from "react";
import { useConversation } from "@elevenlabs/react";
import { useRive } from "@rive-app/react-webgl2";
import type { ViewModelInstance } from "@rive-app/react-webgl2";

const MOOD = { idle: 0, sad: 4, loading: 5, listening: 6, talking: 7 } as const;

export function AgentAvatar() {
  const { rive, RiveComponent } = useRive({
    src: "/character.riv",
    stateMachine: "CharacterViewModelMachine",
    autoplay: true,
    autoBind: true,
  });
  const vmi = useRef<ViewModelInstance | null>(null);
  vmi.current = rive?.viewModelInstance ?? null;

  const setMood = (m: number) => {
    const p = vmi.current?.number("mood");
    if (p) p.value = m;
  };
  const fire = (name: string) => vmi.current?.trigger(name)?.trigger();

  const conversation = useConversation({
    onConnect: () => {
      fire("enter");
      setMood(MOOD.listening);
    },
    onDisconnect: () => {
      fire("exit");
      setMood(MOOD.idle);
    },
    onModeChange: ({ mode }) => setMood(mode === "speaking" ? MOOD.talking : MOOD.listening),
    onError: () => {
      fire("error");
      setMood(MOOD.sad);
    },
  });

  const start = async () => {
    setMood(MOOD.loading);
    await navigator.mediaDevices.getUserMedia({ audio: true });
    await conversation.startSession({ agentId: "your-agent-id" });
  };

  return (
    <div>
      <div aria-hidden="true" style={{ width: 160, height: 160 }}>
        <RiveComponent />
      </div>
      <button onClick={start} disabled={conversation.status !== "disconnected"}>Talk</button>
      <button onClick={() => conversation.endSession()}>End</button>
      <p role="status">{conversation.status === "connected" ? (conversation.isSpeaking ? "Speaking" : "Listening") : conversation.status}</p>
    </div>
  );
}

आपके वर्ज़न को startSession के लिए कौन से options चाहिए (agent ID या signed URL, connection type), यह SDK reference में देखें। इनसे mapping logic नहीं बदलता।

क्या agent के output audio से मुँह की हरकत चलाई जा सकती है?

SDK agent की आवाज़ के लिए getOutputByteFrequencyData() और माइक्रोफ़ोन के लिए getInputVolume() देता है, और इसका documentation इन्हें audio visualizations बनाने का तरीका बताता है (ElevenLabs React SDK)। Frequency डेटा का ढाँचा Web Audio AnalyserNode जैसा ही है: हर frequency bin के लिए 0 से 255 तक की byte values (MDN)।

इससे आप क्या चला सकते हैं, यह कैरेक्टर पर निर्भर करता है:

  • file में mouth-open नंबर हो तो: हर एनिमेशन फ़्रेम पर bins का औसत लें, value को smooth करें और उसे उस नंबर में लिखें।
  • सिर्फ़ talking लूप हो तो: आपको audio डेटा की ज़रूरत ही नहीं, क्योंकि onModeChange पहले ही बता देता है कि कब बोलना है। अगर अतिरिक्त मोशन चाहिए तो डेटा को एक अलग visualizer ring के लिए इस्तेमाल करें।
  • Visemes: frequency spectrum में phoneme की पहचान नहीं होती, इसलिए इससे सटीक lip-sync नहीं बन सकता। viseme कब फ़ायदेमंद हैं, यह जानने के लिए lip-sync बनाम amplitude देखें।
// Optional: a 0–1 level from the agent's voice, sampled once per frame.
function outputLevel(): number {
  const bins = conversation.getOutputByteFrequencyData();
  if (!bins?.length) return 0;
  let sum = 0;
  for (let i = 0; i < bins.length; i++) sum += bins[i];
  return sum / bins.length / 255;
}

इसे requestAnimationFrame के अंदर चलाएँ, React state में नहीं। सेकंड में 60 बार setState कॉल करने से आपका component tree बिना किसी visual फ़ायदे के re-render होता है।

connecting और disconnect स्टेट कैसे दिखाएँ?

Voice session शुरू होने में थोड़ा समय लगता है: ब्राउज़र माइक्रोफ़ोन की अनुमति माँगता है, फिर SDK connection खोलता है। इस दौरान status connecting रहता है। इसे दिखाएँ, वरना यूज़र फिर से बटन टैप करेगा।

  • startSession से पहले: loading मूड सेट करें। अगर यूज़र माइक्रोफ़ोन प्रॉम्प्ट पढ़ता है तो इसमें कुछ सेकंड लग सकते हैं।
  • onConnect: enter रिएक्शन चलाएँ (या थोड़ी देर के लिए wave मूड पर जाएँ), फिर listening पर रुकें, क्योंकि agent बात सुनने के लिए तैयार है।
  • onDisconnect: exit रिएक्शन चलाएँ और idle या sleeping पर रुकें।
  • अनुमति न मिलने पर: getUserMedia reject करता है। इसे catch करें, idle पर लौटें और text में बताएँ कि माइक्रोफ़ोन की अनुमति कैसे दें।

Charmotion फ़ाइलों में ठीक यही हिस्से होते हैं: Character व्यू मॉडल पर एक loading मूड (5), एक listening मूड (6), एक talking मूड (7), sleeping (8), और enter और exit ट्रिगर। मूड बदलने से कभी वन-शॉट नहीं कटता, इसलिए एक ही कॉलबैक में enter चलाने और listening सेट करने पर लूप शुरू होने से पहले पूरी एंट्री चलती है। Charmotion यह सेट आपके अपने कैरेक्टर या लोगो से बनाता है; .riv हर पेड प्लान ($20/माह से) के साथ मिलती है।

thinking वाले पल के लिए आप अंदाज़े की जगह agent के अपने events इस्तेमाल कर सकते हैं: अगर आपका agent client tools कॉल करता है, तो tool call शुरू होने पर thinking सेट करें और बोलना फिर शुरू होने पर mode के हिसाब से चलने वाली स्टेट पर लौटें।

listening: mood 6, जब यूज़र बोल रहा हो या टाइप कर रहा हो।

कौन सा granular hook अतिरिक्त rerenders से बचाता है?

useConversation बहुत सारी state लौटाता है, और उसे पढ़ने वाला component उसमें कोई भी बदलाव होने पर re-render होता है। इसके लिए ElevenLabs granular hooks का documentation देता है, जिनमें सिर्फ़ speaking/listening state के लिए useConversationMode() भी है, और re-renders कम करने के लिए इन्हीं की सलाह देता है (ElevenLabs React SDK)। आपके SDK वर्ज़न में hooks का सटीक सेट और उनके लिए ज़रूरी provider, यह reference में देखें।

अवतार के लिए सबसे हल्का तरीका वही है जो ऊपर के code में है: Rive को render हुई values से नहीं, बल्कि callbacks से चलाएँ। onModeChange जैसे callbacks React के render cycle के बाहर चलते हैं, और view model property में value लिखने से कुछ भी re-render नहीं होता। Rive canvas अपने आप अपडेट हो जाता है।

इससे canvas भी सुरक्षित रहता है। Rive चेतावनी देता है कि canvas को दोबारा mount करने से एनिमेशन फिर से शुरू हो सकता है या खाली हो सकता है (Rive React best practices)। useRive और RiveComponent को एक ही component में रखें जो पूरे session के दौरान mounted रहे, और सिर्फ़ छोटे status text को re-render होने दें।

अक्सर पूछे जाने वाले सवाल

ElevenLabs React SDK से speaking और listening का पता कैसे लगाएँ?

useConversation में mode मिलता है, जिसकी value 'speaking' या 'listening' होती है, साथ ही isSpeaking और isListening booleans और एक onModeChange callback भी मिलता है। अवतार का मूड सीधे सेट करने के लिए onModeChange का इस्तेमाल करें: जब agent बोल रहा हो तब talking, बाकी समय listening। Connection status अलग से disconnected, connecting या connected के रूप में बताया जाता है।

क्या ElevenLabs कोई thinking स्टेट भेजता है?

React SDK के mode की दो values हैं, speaking और listening, इसलिए कोई built-in thinking mode नहीं है। यूज़र के बोलना बंद करने के बाद का ठहराव listening में ही आता है। अगर आपका agent client tools का इस्तेमाल करता है, तो tool चलने के दौरान आप thinking दिखा सकते हैं और उसके बाद mode के हिसाब से स्टेट पर लौट सकते हैं।

क्या मैं किसी अवतार को ElevenLabs agent के साथ lip-sync कर सकता हूँ?

सिर्फ़ React SDK के audio helpers से सटीक lip-sync नहीं होता। getOutputByteFrequencyData() हर frequency पर आवाज़ की तीव्रता देता है, जिससे तेज़ आवाज़ पर मुँह ज़्यादा खोला जा सकता है, लेकिन यह phonemes की पहचान नहीं करता। talking लूप वाले कैरेक्टर के लिए talking शुरू और बंद करने को onModeChange ही काफ़ी है।

इस गाइड से झटपट जवाब

स्रोत

संबंधित गाइड