AI-система віртуальних AI-персонажів для VR/AR

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1Усі 1566 послуг
AI-система віртуальних AI-персонажів для VR/AR
Складний
~2-4 тижні
Часті запитання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1284
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1196
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    901
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1119
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    586
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    853

AI-персонажі для VR/AR

Статичні NPC в VR/AR-застосунках — вузьке місце будь-якого іммерсивного досвіду. Користувач натискає триггер, персонаж вимовляє заготовлену фразу з 5 варіантів, діалог закінчується. AI-персонажі ведуть реальну розмову: розуміють контекст сцени, пам'ятають попередні взаємодії, адаптують поведінку до користувача, керують анімаціями в реальному часі.

Архітектура AI-персонажа

[STT] Голос користувача → текст (Whisper)
         ↓
[Context Manager] Історія + стан сцени + характер персонажа
         ↓
[LLM] GPT-4o / Claude 3.5 → текст відповіді + команди дій
         ↓
[TTS] ElevenLabs → аудіопотік
         ↓
[Animation Controller] Unity/Unreal → синхронізація губ + жести + емоції
import asyncio
from openai import AsyncOpenAI
from dataclasses import dataclass, field
import json

@dataclass
class CharacterState:
    character_id: str
    name: str
    personality: str       # системний промпт з характером
    scene_context: dict    # поточний стан VR-сцени
    history: list = field(default_factory=list)
    emotional_state: str = "neutral"
    relationship_score: float = 0.5  # 0=ворожий, 1=дружелюбний

class VRCharacterEngine:
    ACTION_SCHEMA = {
        "type": "json_schema",
        "json_schema": {
            "name": "character_response",
            "schema": {
                "type": "object",
                "properties": {
                    "speech": {"type": "string"},
                    "emotion": {"type": "string",
                                "enum": ["neutral", "happy", "angry", "scared",
                                         "surprised", "sad", "suspicious"]},
                    "animation": {"type": "string",
                                  "enum": ["idle", "walk_towards", "walk_away",
                                           "point", "nod", "shake_head",
                                           "hand_gesture", "look_around"]},
                    "scene_action": {"type": "string",
                                     "description": "Дія в сцені: open_door, pick_up_item, тощо"},
                    "relationship_delta": {"type": "number",
                                           "description": "Зміна relationship_score [-0.2, 0.2]"}
                },
                "required": ["speech", "emotion", "animation"]
            }
        }
    }

    def __init__(self):
        self.client = AsyncOpenAI()

    async def process_interaction(
        self,
        user_input: str,
        state: CharacterState
    ) -> dict:
        messages = [
            {"role": "system", "content": self._build_system_prompt(state)},
            *state.history[-10:],  # останні 5 обмінів
            {"role": "user", "content": user_input}
        ]

        response = await self.client.chat.completions.create(
            model="gpt-4o-mini",  # mini достатньо, затримка критична
            messages=messages,
            response_format=self.ACTION_SCHEMA,
            max_tokens=300,
            temperature=0.7
        )

        action = json.loads(response.choices[0].message.content)

        # Оновлюємо стан персонажа
        state.emotional_state = action["emotion"]
        state.relationship_score = max(0, min(1,
            state.relationship_score + action.get("relationship_delta", 0)
        ))
        state.history.append({"role": "user", "content": user_input})
        state.history.append({"role": "assistant", "content": action["speech"]})

        return action

Синхронізація губ та анімацій

// Unity: синхронізація lip sync з аудіопотоком від ElevenLabs
using OVRLipSync;
using UnityEngine;

public class AICharacterAnimator : MonoBehaviour
{
    private OVRLipSyncContext lipSyncContext;
    private Animator animator;
    private AudioSource audioSource;

    public async void PlayCharacterResponse(string speechText, string emotion, string animation)
    {
        // 1. Запитуємо аудіо від TTS
        byte[] audioData = await TTSService.Synthesize(speechText, voiceId: "character_voice");

        // 2. Встановлюємо емоцію через Blend Shapes
        SetEmotionBlendShape(emotion);

        // 3. Запускаємо анімацію тіла
        animator.SetTrigger(animation);

        // 4. Відтворюємо аудіо з синхронізацією губ
        AudioClip clip = AudioService.BytesToClip(audioData);
        audioSource.clip = clip;
        audioSource.Play();

        // OVRLipSync автоматично синхронізує губи з аудіо
        lipSyncContext.ProcessAudioSamplesRaw(audioData, 0);
    }

    private void SetEmotionBlendShape(string emotion)
    {
        var face = GetComponent<SkinnedMeshRenderer>();
        // Скидаємо всі емоції
        for (int i = 0; i < face.sharedMesh.blendShapeCount; i++)
            face.SetBlendShapeWeight(i, 0);

        // Встановлюємо потрібну емоцію
        int shapeIndex = face.sharedMesh.GetBlendShapeIndex($"emotion_{emotion}");
        if (shapeIndex >= 0)
            face.SetBlendShapeWeight(shapeIndex, 100f);
    }
}

Затримка: основна проблема VR-персонажів

У VR розрив > 800 мс між фразою користувача та відповіддю персонажа руйнує іммерсію. Оптимізація pipeline:

Крок Без оптимізації З оптимізацією
STT (Whisper large) 800–1200 мс 200–400 мс (Whisper medium + streaming)
LLM (GPT-4o) 1000–2000 мс 400–700 мс (GPT-4o-mini + короткий контекст)
TTS (ElevenLabs) 600–1000 мс 200–400 мс (streaming TTS)
Всього 2400–4200 мс 800–1500 мс

Розв'язання: паралельний запуск TTS відразу після отримання перших токенів від LLM (streaming), початок відтворення аудіо до завершення синтезу всієї фрази.

Кейс: VR-тренажер для навчання продажам. 4 персонажі з різними характерами (агресивний клієнт, лояльний клієнт, скептик, нейтральний). Середня затримка після оптимізації: 920 мс. Оцінка реалізму діалогів (опитування 50 користувачів): 4.1/5 на відміну від 2.3/5 для скриптованих NPC.

Строки: один AI-персонаж з базовими анімаціями: 3–5 тижнів; повний тренажер з кількома персонажами та аналітикою: 2–3 місяці.