Рекрутер витрачає в середньому 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_uk = ['е', 'ну', 'це', 'коротше', 'типу', 'як би'] 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='uk', 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_uk] 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 робочих дні. Якщо вам потрібен швидкий прототип, зв'яжіться з нами для демо.







