AIAvatarKit Documentation

repository·main·Indexed 20 days ago

https://github.com/uezo/aiavatarkit

A modular Speech-to-Speech framework for building real-time conversational AI avatars. It supports various LLMs (ChatGPT, Gemini, Claude, Dify), STT, and TTS engines (VOICEVOX, OpenAI, SpeechGateway), and is compatible with metaverse platforms, standalone apps, and edge devices. Features include a FastAPI-embedded Admin Panel for runtime configuration, WebSocket support for low-latency interaction and avatar motion control, and integration with VAD and multimodal I/O.

Tokens
55K
Snippets
138
Records
191
Agent score
71%

What's inside AIAvatarKit

  1. Dynamically switch voice style or emotion

    main

    You can change the avatar's voice style (speaker or emotion) dynamically based on keywords found in the LLM output using a style_mapper. This is useful for making an avatar sound "angry" when specific keywords or tags (e.g., [face:angry]) are detected in the text stream.

    For VOICEVOX, the mapper can convert style names to integer speaker IDs.

    # Style mapper example: Switch to angry voice if "angry" is in LLM output
    style_mapper = {
        "angry": "3",  # VOICEVOX: Zundamon (angry)
        "happy": "1",  # VOICEVOX: Zundamon (happy)
    }
    
    # Implementation logic: extract style info in @process_llm_chunk and pass to TTS
  2. AIAvatarKit Architecture Overview

    main

    AIAvatarKit is a modular Speech-to-Speech framework designed for low-latency real-time interaction. It abstracts the differences between various LLMs and supports multimodal input/output.

    Core Modular Components:

    • VAD (Voice Activity Detection): Supports standard silence-based detection and SileroVAD.
    • STT (Speech-to-Text): Integrates with Google, Azure, OpenAI, and AmiVoice.
    • LLM (Large Language Model): Supports ChatGPT, OpenAI Responses API, Gemini, Claude, and any model compatible with LiteLLM or Dify.
    • TTS (Text-to-Speech): Supports VOICEVOX / AivisSpeech, OpenAI, and SpeechGateway (including Style-Bert-VITS2).

    Deployment Targets:

    • Metaverse: Compatible with VRChat, cluster, Vket Cloud, etc.
    • Standalone Apps: Via WebSocket or HTTP (SSE).
    • Edge/Telephony: Supports Raspberry Pi and Twilio.
  3. Enable background tool execution with on_completed

    main

    For long-running tasks, use background execution to prevent blocking the conversation. The avatar will immediately acknowledge the request and notify the user when finished via a callback.

    To enable this, register an @tool.on_completed callback. The Tool class handles task_id generation and metadata tracking automatically.

    Note: Background execution and AsyncGenerator (streaming progress) are mutually exclusive.

    from aiavatar.sts.llm import Tool
    
    # ... tool spec and function definition ...
    
    tool = Tool("run_heavy_task", heavy_task_spec, run_heavy_task)
    
    # Enable background execution
    @tool.on_completed
    async def on_completed(result, metadata):
        # result: return value of tool
        # metadata: contains task_id, user_id, context_id, session_id, etc.
        answer = result["answer"]
        
        # Use STS invoke to push the result back to the user
        async for resp in aiavatar_app.sts.invoke(
            STSRequest(
                session_id=metadata["session_id"],
                user_id=metadata["user_id"],
                context_id=metadata["context_id"],
                text=f"Here is the result: {answer}",
                wait_in_queue=True,
                skip_quick_response=True,
            )
        ):
            await aiavatar_app.handle_response(resp)
    
    llm.add_tool(tool)
  4. Use CharacterLoader for lightweight, file-based characters

    main

    If you do not need a database or complex schedule/diary generation, use CharacterLoader. It loads character settings from local files and is ideal for lightweight setups.

    Key Features:

    • Modes: Supports Single file mode (one markdown file for prompt) or Directory mode (multiple files like character.md, attribute.md, etc.).
    • Hot Reload: Uses mtime-based invalidation to reflect file changes without restarting.
    • Customization: Use @loader.get_user_name for dynamic user resolution and @loader.format_messages for post-processing initial messages.
    • Comparison with CharacterService:
      • Uses local files instead of a database.
      • No built-in schedule/diary generation or long-term memory.
      • Supports hot reloading.
    from aiavatar.character.loader import CharacterLoader
    
    loader = CharacterLoader("my_character", split_initial_messages=True, lang="ja")
    loader.bind(adapter.sts.llm)
  5. Understand VAD (Voice Activity Detection) implementations

    main

    AIAvatarKit uses VAD components to detect the start and end of speech, which is critical for natural turn-taking. Depending on your environment and latency requirements, you can choose from several implementations:

    • StandardSpeechDetector: Volume threshold-based. Fast and lightweight; best for quiet environments.
    • SileroSpeechDetector: Deep learning model. High accuracy and noise resistant; ideal for noisy environments.
    • SileroStreamSpeechDetector: Deep learning + Streaming STT. Provides real-time segment recognition to eliminate STT latency after VAD completes.
    • AzureStreamSpeechDetector: Cloud API (Azure). Supports real-time recognition text retrieval.
    • AmazonTranscribeStreamSpeechDetector: Cloud API (AWS). Uses silence-based accumulation of multiple recognition results.
  6. Use CharacterLoader for lightweight character management

    main

    If you want to avoid database dependencies (PostgreSQL/SQLite), use CharacterLoader. It loads character definitions directly from local .md and .json files.

    Modes:

    • Single file mode: Point to a single markdown file containing the system prompt.
    • Directory mode: Use a directory with structured files (character.md, response_instructions.md, message_templates.json, etc.). Using split_initial_messages=True allows you to inject character knowledge as pseudo-conversation turns.

    Features:

    • Hot reload: Files are reloaded automatically on change (mtime-based).
    • Customization: Use @loader.get_user_name for dynamic user resolution and @loader.format_messages to post-process messages.
    from aiavatar.character.loader import CharacterLoader
    
    # Directory mode example
    loader = CharacterLoader(
        "my_character",
        split_initial_messages=True,
        lang="ja",
        user_names={"user_001": "Alice"},
        default_user_name="You"
    )
    
    loader.bind(adapter.sts.llm)
  7. Manage Request Queuing Modes

    main

    Control how the pipeline handles multiple simultaneous requests using the following modes:

    1. Direct (Default): Set use_invoke_queue=False. New requests immediately interrupt the current response.
    2. Queued (Interrupt): Set use_invoke_queue=True and wait_in_queue=False. Requests are queued, but they clear pending requests; the current response is interrupted.
    3. Queued (Wait): Set use_invoke_queue=True and wait_in_queue=True. Requests wait until the previous ones complete; no interruption occurs.

    Additional settings:

    • invoke_queue_idle_timeout: Time before the worker is released.
    • invoke_timeout: Maximum processing time for a request.
  8. Manage AI character lifecycles with CharacterService

    main

    The CharacterService manages the 'soul' and behavior of an AI character. It handles the Character Model which includes id (UUID), name, prompt (personality/behavior), and metadata (appearance, hobbies, etc.).

    It supports:

    • OpenAI/Azure OpenAI: Standard API support for generating schedules and diaries. Azure is auto-detected if the model name contains 'azure'.
    • Schedule Management: Manages weekly and daily schedules to provide context (e.g., "I'm in class now"). Supports AI-driven generation and CRUD operations.
    • Diary System: Records daily events, extracts topics, and integrates news to provide continuity and emotional expression.
    • Memory System: Enables semantic search of past conversations and integration with diaries so the character can recall past interactions.
  9. Use Avatar Control and Vision tags

    main

    AIAvatarKit supports several common features across all adapters for controlling the avatar and interacting with the environment via LLM output:

    • Avatar control tags: Parse tags like [face:name] or [animation:name] (or XML equivalents) to extract animation commands from the LLM.
    • Language detection: Parse [language:code] tags to trigger multi-language TTS switching.
    • Vision requests: Parse [vision:source] tags to trigger camera image retrieval requests.
    • Base64 encoding: Audio data is automatically converted to/from Base64 for JSON transmission.
  10. Optimize OpenClaw for Voice and Facial Expressions

    main

    To enable the avatar to switch facial expressions and optimize responses for voice interaction, add specific instructions to your SOUL.md file. The system uses a [channel:voice] prefix to distinguish between voice and text modes.

    Voice Mode Instructions

    When the [channel:voice] prefix is present, instruct the model to:

    • Keep responses short: 1-2 sentences (~100 characters).
    • Prohibit emojis: Emojis are strictly forbidden in voice mode.
    • Use Face Tags: Use tags to express emotion. Available tags: neutral, joy, angry, sorrow, fun, surprised.
      • Example: [face:joy]I found the file for you! [face:neutral]Here it is.
    • Use Language Tags: Use [language:en-US] (or other primary-secondary combinations) to signal language switches.

    Text Mode Instructions

    When the [channel:voice] prefix is NOT present:

    • No Tags: Do NOT output any [face:...] or [language:...] tags.
    • Natural Text: Use emojis and normal response lengths.

    System Logic

    • Instructions regarding agentic behavior or meta-information are prefixed with $. The model should not respond to these directly but should act upon them naturally.
    ## Communication Modes & Voice Constraints
    
    **1. Channel Detection**
    - Requests from the voice channel are prefixed with `[channel:voice]`.
    - You MUST change your output format depending on whether this prefix is present.
    
    **2. Voice Mode (Apply ONLY IF `[channel:voice]` is present)**
    - **Length & Emojis:** Keep your response short (1-2 sentences, ~100 characters). Emojis are strictly prohibited.
    - **Face Tags:** Express your emotions using face tags. Available tags: `neutral`, `joy`, `angry`, `sorrow`, `fun`, `surprised`. (Default is `neutral`).
      - Example: `[face:joy]I found the file for you! [face:neutral]Here it is.`
    - **Multilingual Tags:** If you determine that you should switch to a different language, insert a language code tag like `[language:en-US]` (primary-secondary combination separated by a hyphen).
    - **Speech Errors:** Infer the intended meaning if the user's input contains speech recognition errors.
    
    **3. Text Mode (Apply IF `[channel:voice]` is NOT present)**
    - **NO Tags:** You MUST NOT output any face tags or language tags (e.g., NEVER write `[face:joy]` or `[language:en-US]`).
    - You may use emojis naturally and respond at a normal length.
    
    ## System Logic & Agentic Behavior
    
    - Instructions regarding agentic behavior (such as tool execution) or the provision of meta-information are prefixed with a `$`.
    - Do NOT respond directly to this instruction (e.g., do not say "I will execute the tool"); instead, reply to the user naturally in accordance with the instruction's content.
  11. Use PostgreSQLPoolProvider for centralized connection management

    main

    To prevent connection exhaustion, use the PostgreSQLPoolProvider to manage a single shared connection pool across all database-dependent components.

    Key Features:

    • Shared pool: Multiple components share one connection pool.
    • Lazy initialization: The pool is created on first access, not at startup.
    • Configurable size: Use min_size (default: 5) and max_size (default: 20).
    • Thread-safe: Safe for concurrent access from multiple coroutines.
    • Monitoring: Use get_stats() to retrieve pool utilization metrics.

    Best Practices:

    • Instantiate PostgreSQLPoolProvider once at application startup.
    • Pass the get_pool method to components.
    • Set max_size based on your database's max_connections setting.
    from aiavatar.database.postgres import PostgreSQLPoolProvider
    
    # Create shared pool provider
    pool_provider = PostgreSQLPoolProvider(
        connection_str="postgresql://user:pass@host:5432/db",
        min_size=5,
        max_size=30
    )
    
    # Pass to components - all share the same pool
    from aiavatar.sts.context.postgres import PostgreSQLContextManager
    from aiavatar.sts.session.postgres import PostgreSQLSessionStateManager
    from aiavatar.sts.performance.postgres import PostgreSQLPerformanceRecorder
    from aiavatar.character import CharacterService
    
    context_manager = PostgreSQLContextManager(get_pool=pool_provider.get_pool)
    session_manager = PostgreSQLSessionStateManager(get_pool=pool_provider.get_pool)
    performance_recorder = PostgreSQLPerformanceRecorder(get_pool=pool_provider.get_pool)
    character_service = CharacterService(db_pool_provider=pool_provider)
  12. Implement Chain-of-Thought using voice_text_tag

    main

    You can implement a 'think before answering' pattern by using the voice_text_tag parameter. This allows the LLM to generate reasoning (Chain-of-Thought) inside specific tags, while the system only vocalizes the content within the designated tags.

    # Single tag: vocalize only <answer> content
    llm = ChatGPTService(
        system_prompt="Think within <think> tags. Write your answer within <answer> tags.",
        voice_text_tag="answer"
    )
    
    # Multiple tags: vocalize both <ack> and <answer>, skip <think>
    llm = ChatGPTService(
        system_prompt="Output <ack>first reaction</ack><think>reasoning</think><answer>full response</answer>",
        voice_text_tag=["ack", "answer"]
    )