Разработка AI-системы анализа видеоинтервью soft skills невербальные сигналы

Проектируем и внедряем системы искусственного интеллекта: от прототипа до production-ready решения. Наша команда объединяет экспертизу в машинном обучении, дата-инжиниринге и MLOps, чтобы AI работал не в лаборатории, а в реальном бизнесе.
Показано 1 из 1 услугВсе 1566 услуг
Разработка AI-системы анализа видеоинтервью soft skills невербальные сигналы
Сложная
~2-4 недели
Часто задаваемые вопросы
Направления AI-разработки
Этапы разработки AI-решения
Последние работы
  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1218
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    854
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1047
  • image_logo-advance_0.png
    Разработка логотипа компании B2B Advance
    561
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    825

AI-система анализа видеоинтервью

Задача — автоматический анализ записанных или онлайн видеоинтервью с кандидатами: распознавание эмоций, анализ вербальных ответов, выявление признаков стресса или неуверенности. Система не заменяет HR-специалиста, но помогает приоритизировать 200 кандидатов за час.

Компоненты системы

import cv2
import numpy as np
import torch
import whisper
from transformers import pipeline
import mediapipe as mp

class VideoInterviewAnalyzer:
    def __init__(self, config: dict):
        # Речь → текст: Whisper large-v3
        self.asr = whisper.load_model('large-v3')

        # Анализ тональности текста
        self.sentiment_analyzer = pipeline(
            'text-classification',
            model='blanchefort/rubert-base-cased-sentiment',
            device=0 if torch.cuda.is_available() else -1
        )

        # Эмоции на лице: MediaPipe + классификатор
        self.face_mesh = mp.solutions.face_mesh.FaceMesh(
            max_num_faces=1, refine_landmarks=True
        )
        self.emotion_model = self._load_emotion_model(config['emotion_model'])

        # Анализ речи: темп, паузы, слова-паразиты
        self.filler_words_ru = ['э', 'ну', 'это', 'короче', 'типа', 'как бы']

    def analyze_video(self, video_path: str) -> dict:
        cap = cv2.VideoCapture(video_path)
        fps = cap.get(cv2.CAP_PROP_FPS)

        frames = []
        audio_data = []

        # Извлечение кадров (1 в секунду для эмоций)
        frame_idx = 0
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            if frame_idx % int(fps) == 0:  # 1 fps
                frames.append(frame)
            frame_idx += 1
        cap.release()

        # Параллельный анализ
        emotion_timeline = self._analyze_emotions(frames)
        transcript = self._transcribe_audio(video_path)
        speech_features = self._analyze_speech(transcript, fps * frame_idx)
        text_analysis = self._analyze_text(transcript['text'])

        return self._compile_report(emotion_timeline, transcript,
                                     speech_features, text_analysis)

    def _analyze_emotions(self, frames: list) -> list:
        timeline = []
        for t, frame in enumerate(frames):
            rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            results = self.face_mesh.process(rgb)

            if results.multi_face_landmarks:
                emotion = self.emotion_model.predict(frame)
                timeline.append({'second': t, 'emotion': emotion})
            else:
                timeline.append({'second': t, 'emotion': 'no_face'})

        return timeline

    def _transcribe_audio(self, video_path: str) -> dict:
        result = self.asr.transcribe(video_path, language='ru',
                                      word_timestamps=True)
        return result

    def _analyze_speech(self, transcript: dict,
                          total_frames: int) -> dict:
        words = [w for seg in transcript.get('segments', [])
                  for w in seg.get('words', [])]

        if not words:
            return {}

        total_duration = words[-1]['end'] if words else 1.0
        words_per_minute = len(words) / (total_duration / 60)

        # Паузы > 2 сек
        long_pauses = []
        for i in range(1, len(words)):
            pause = words[i]['start'] - words[i-1]['end']
            if pause > 2.0:
                long_pauses.append({'start': words[i-1]['end'],
                                     'duration': pause})

        # Слова-паразиты
        fillers = [w for w in words
                    if w['word'].strip().lower() in self.filler_words_ru]
        filler_rate = len(fillers) / max(len(words), 1)

        return {
            'words_per_minute': words_per_minute,
            'long_pauses': long_pauses,
            'filler_rate': filler_rate,
            'total_words': len(words)
        }

    def _compile_report(self, emotions: list, transcript: dict,
                          speech: dict, text: dict) -> dict:
        # Распределение эмоций
        emotion_counts = {}
        for e in emotions:
            em = e.get('emotion', 'unknown')
            emotion_counts[em] = emotion_counts.get(em, 0) + 1

        dominant_emotion = max(emotion_counts,
                                key=emotion_counts.get) if emotion_counts else None

        # Скоринг (упрощённый)
        score = 50.0
        if speech.get('words_per_minute', 0) > 100:
            score += 10  # хороший темп речи
        if speech.get('filler_rate', 1) < 0.05:
            score += 10  # мало слов-паразитов
        if dominant_emotion in ['happy', 'neutral']:
            score += 10
        if dominant_emotion in ['fear', 'disgust']:
            score -= 10
        if len(speech.get('long_pauses', [])) > 5:
            score -= 10

        return {
            'overall_score': min(100, max(0, score)),
            'emotion_distribution': emotion_counts,
            'dominant_emotion': dominant_emotion,
            'speech_metrics': speech,
            'transcript': transcript.get('text', ''),
            'text_sentiment': text,
            'recommendations': self._generate_recommendations(emotions,
                                                               speech, text)
        }

Этические ограничения и точность

Важно понимать: системы анализа эмоций имеют точность 65–75% в реальных условиях (JAFFE dataset: до 92%, но это лабораторные условия). Нервозность на интервью ≠ некомпетентность. Система даёт сигналы, не решения.

Параметр Точность
Распознавание 7 базовых эмоций 68–78%
ASR (Whisper large-v3, русский) WER 8–12%
Анализ тональности текста F1 0.81–0.87
Детекция слов-паразитов > 95%

Интеграция с ATS/HRM

Система отдаёт структурированный JSON: оценка, транскрипт, эмоциональный профиль, метрики речи. Интегрируется через REST API в любую ATS: Huntflow, Potok, SAP SuccessFactors.

Масштаб Срок
Базовый анализ (ASR + эмоции) 4–6 недель
Полная система с scoring и ATS-интеграцией 8–14 недель