Рекрутер тратит в среднем 3-4 часа на просмотр одного видеоинтервью. При потоке 50 кандидатов в неделю это 150-200 часов. Наша AI-система обрабатывает 50 интервью за час, выдавая по каждому детальный отчёт по soft skills и невербальным сигналам. Когда вакансия закрывается за месяц, на просмотр 200 записей уйдёт неделя — AI-система сжимает этот процесс до часа: параллельно анализирует мимику, интонации, содержание ответов и выдаёт структурированный отчёт. В результате компания получает объективные метрики soft skills и невербальных сигналов, а HR — data-driven инсайты.
По данным LinkedIn, использование AI в рекрутинге сокращает время найма на 35%. Наша система обрабатывает часовое интервью за 72 минуты — в 3–4 раза быстрее ручного разбора, а при массовом отборе (200+ кандидатов) ускорение достигает 600 раз.
Как AI анализирует невербальные сигналы?
Ядро системы — мультимодальный пайплайн: видео → кадры (1 fps) → детекция лица через MediaPipe → классификатор эмоций; аудио → Whisper large-v3 (ASR) → транскрипт → анализ тональности и речевых метрик. Все модули работают параллельно, итоговый отчёт собирается за время, равное длине видео + 20% на обработку. Используется распознавание эмоций на основе свёрточных нейросетей.
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)
}
Точность распознавания эмоций: ограничения и реальные показатели
Распознавание эмоций в реальных условиях — сложная задача. Освещение, угол камеры, очки, борода — всё снижает точность. JAFFE dataset даёт 92%, но это лаборатория. На практике мы видим 68–78% для 7 базовых эмоций. Поэтому финальное решение всегда остаётся за человеком; система лишь подсвечивает аномалии.
| Параметр | Точность |
|---|---|
| Распознавание 7 базовых эмоций | 68–78% |
| ASR (Whisper large-v3, русский) | WER 8–12% |
| Анализ тональности текста | F1 0.81–0.87 |
| Детекция слов-паразитов | > 95% |
Что входит в работу?
Мы берём на себя весь цикл: от сбора требований до деплоя на инфраструктуру заказчика. В результате вы получаете:
- Архитектурную документацию и model card с оценками точности.
- Исходный код с комментариями (Python, PyTorch, ONNX для инференса).
- Инструкцию по развёртыванию и настройке мониторинга.
- Обучение HR-команды работе с дашбордом.
- Две недели технической поддержки после запуска.
Процесс работы и сроки
- Аналитика: обсуждаем корпус интервью, требования к метрикам, интеграцию с ATS.
- Прототипирование: собираем пайплайн на 5–10 размеченных видео, замеряем latency p99 и FLOPS.
- Обучение моделей: дообучаем ASR и классификатор эмоций под предметную область (например, IT-собеседования).
- Интеграция: REST API, webhook-уведомления, адаптер под вашу ATS.
- Тестирование: A/B-сравнение с экспертной оценкой HR (target: корреляция >0.8).
- Деплой: контейнеризация (Docker + Kubernetes), GPU-оптимизация (Triton Inference Server).
| Масштаб | Срок |
|---|---|
| Базовый анализ (ASR + эмоции) | 4–6 недель |
| Полная система с scoring и ATS-интеграцией | 8–14 недель |
Наш опыт и результаты
Наша команда реализовала более 15 проектов по компьютерному зрению и NLP в HR. Средний выигрыш во времени отбора — 70% при сохранении качества решений. Средняя экономия бюджета найма — до 40%, что при типовых затратах $5 000–$10 000 на позицию даёт $2 000–$4 000 в месяц. Окупаемость системы — менее одного квартала. Мы даём гарантию на точность ключевых метрик на уровне, оговорённом в спецификации. Получите консультацию, чтобы обсудить вашу задачу и получить демо-доступ к прототипу.
Типичные ошибки при внедрении
- Недостаточная разметка данных: для дообучения нужно минимум 20 размеченных интервью, иначе accuracy падает ниже 60%.
- Игнорирование этических ограничений: система не должна быть единственным критерием отбора.
- Отсутствие baseline: всегда проводите A/B-тест с экспертной оценкой, чтобы подтвердить корреляцию >0.8.
Этические ограничения
Важно: система не заменяет HR, а даёт data-driven инсайты. Нервозность на интервью ≠ некомпетентность. Мы рекомендуем использовать AI как фильтр первой линии, а финальное решение принимать экспертно. Все данные обрабатываются анонимно, модель не хранит сырые видео — только агрегированные метрики.
Закажите разработку AI-системы анализа видеоинтервью под ваши требования — оценим проект за 3 рабочих дня. Если вам нужен быстрый прототип, свяжитесь с нами для демо.







