זיהוי לחץ ותוקפנות בקול באמצעות בינה מלאכותית
מנתחי מוקדים טלפוניים קלאסיים מסתמכים על מילות עצירה וסנטימנט—וזה נכשל כשהמתקשר כבר נסער. אנו בונים מערכות בינה מלאכותית שמזהות לחץ ותוקפנות מהאקוסטיקה של הקול תוך 2–3 שניות, לפני שאיום נאמר או שהשיחה נותקת. עם למעלה מ-15 פרויקטים סוהריים לקמעונאות, בנקאות ולוגיסטיקה, אנו מכסים הכל מאיסוף נתונים ועד אינטגרציית API. החיסכון בהסלמות מגיע ל-15–20% מתקציב התמיכה.
למה זה חשוב? כל שיחה תוקפנית שהוחמצה יכולה משמעותה אובדן לקוח ונזק מוניטיני. סטטיסטיקות מראות ש-30% מההסלמות במוקדים טלפוניים נובעות מתגובה מאוחרת למתח רגשי. המודל שלנו תופס רגעים כאלה מוקדם, ומעביר התראה למפעיל או למפקח תוך שבריר שנייה.
בעיות שאנו פותרים
- פיגור בתגובת המפעיל. בני אדם צריכים 5–10 שניות לזהות טון תוקפני. המערכת מפעילה התראה מיידית, ומאפשרת התערבות מפקח.
- הערכה סובייקטיבית. מפעילים שונים מפרשים רגשות בצורה שונה. המודל שלנו מספק ציון אובייקטיבי (0–1) לכל קטגוריה.
- עומס ניטור ידני גבוה. האזנה לכל השיחות היא בלתי אפשרית. הבינה המלאכותית סורקת 100% מההקלטות בזמן אמת או במצב אצווה.
סממנים אקוסטיים של לחץ ותוקפנות
import librosa
import numpy as np
from dataclasses import dataclass
@dataclass
class EmotionalAcoustics:
f0_mean: float # средняя частота (агрессия: рост >20%)
f0_range: float # диапазон тона (стресс: сужение)
f0_std: float # вариабельность
speaking_rate: float # темп (стресс: ускорение или замедление)
energy_mean: float # громкость (агрессия: значительный рост)
jitter: float # тремор голоса (стресс: рост)
shimmer: float # неравномерность амплитуды
hnr: float # гармоническое отношение (стресс: снижение)
def extract_stress_features(audio: np.ndarray, sr: int = 16000) -> EmotionalAcoustics:
# Основной тон
f0, voiced_flag, _ = librosa.pyin(audio, fmin=75, fmax=500, sr=sr)
f0_voiced = f0[voiced_flag & ~np.isnan(f0)]
# Энергия
rms = librosa.feature.rms(y=audio, frame_length=2048, hop_length=512)[0]
# Spectral features для HNR proxy
zcr = librosa.feature.zero_crossing_rate(audio)[0]
return EmotionalAcoustics(
f0_mean=float(np.mean(f0_voiced)) if len(f0_voiced) > 0 else 0,
f0_range=float(np.ptp(f0_voiced)) if len(f0_voiced) > 0 else 0,
f0_std=float(np.std(f0_voiced)) if len(f0_voiced) > 0 else 0,
speaking_rate=estimate_speaking_rate(audio, sr),
energy_mean=float(np.mean(rms)),
jitter=estimate_jitter(f0_voiced),
shimmer=estimate_shimmer(rms),
hnr=float(1.0 / (np.mean(zcr) + 1e-8))
)המערכת מנתחת מאפיינים אקוסטיים של הקול: תדר יסוד (F0), קצב דיבור, אנרגיה, jitter, shimmer. מאפיינים אלה משתנים תחת לחץ ותוקפנות, ללא תלות בתוכן הדיבור. הניתוח רץ כל 3 שניות, ומבטיח תגובה מיידית.
איך מסווג ה-ML שלנו עובד
כללים היוריסטיים (למשל, "אם עוצמה > סף → תוקפנות") נותנים דיוק של כ-60%. מסווג ה-ML שלנו—המבוסס על Gradient Boosting או רשתות נוירונים (PyTorch)—מעלה את הדיוק ל-85% ומעלה. היתרון המרכזי: התחשבות בקו הבסיס הקולי האישי של המתקשר. המערכת לומדת את ה"נורמה" במהלך 10 השניות הראשונות של שיחה ומסמנת סטיות ממנה.
from sklearn.ensemble import GradientBoostingClassifier
import joblib
class StressAggressionClassifier:
LABELS = {0: "neutral", 1: "stressed", 2: "aggressive"}
def __init__(self, model_path: str):
self.model = joblib.load(model_path)
self.baseline = {} # персональный baseline первых 10 секунд
def classify(
self, features: EmotionalAcoustics, baseline: EmotionalAcoustics = None
) -> dict:
feat_vector = self._to_vector(features)
if baseline:
# Нормализуем относительно персонального baseline
base_vector = self._to_vector(baseline)
feat_vector = (feat_vector - base_vector) / (base_vector + 1e-8)
proba = self.model.predict_proba([feat_vector])[0]
label_id = np.argmax(proba)
return {
"label": self.LABELS[label_id],
"confidence": float(proba[label_id]),
"probabilities": {self.LABELS[i]: float(p) for i, p in enumerate(proba)},
}
קו בסיס אישי: המפתח לדיוק
עבור כל מתקשר, אנו מחשבים קו בסיס—ממוצע מאפיינים אקוסטיים במהלך 10 השניות הראשונות של השיחה. כל המאפיינים הבאים מנורמלים לקו בסיס זה. זה מבחין בין אדם שקט באופן טבעי לבין מי שמשתתק פתאום תחת לחץ. ללא נורמליזציית קו בסיס, המודל לעיתים קרובות מבלבל בין תוקפנות רגועה למצב נייטרלי.
אימון על מערכי נתוני רגשות
אנו משתמשים ב-RAVDESS (אנגלית), EMOVO, והקלטות מסווגות מותאמות אישית. לרוסית, אנו מסתמכים על מערך הנתונים הרוסי לדיבור רגשי (RESD) או על סיווג עצמי.
ביצועים לאחר אימון: דיוק ~78–85% על שלוש קטגוריות (נייטרלי / לחוץ / תוקפני). כללים היוריסטיים נותנים ~60% דיוק—המודל שלנו טוב פי 1.4.
השוואת גישות
| שיטה | דיוק | קו בסיס | זמן תגובה |
|---|---|---|---|
| כללים היוריסטיים | ~60% | לא | מיידי |
| מסווג ML (Gradient Boosting) | 78–85% | כן | 3 שניות |
| רשת נוירונים (PyTorch) | עד 90%+ | כן | 3–5 שניות |
התהליך שלנו: מנתונים לפריסה
- גילוי – ביקורת תהליכים, איסוף דרישות, הערכת נפח נתונים.
- איסוף וסיווג נתונים – אם אין מערך נתונים קיים, אנו מקליטים שיחות ומסווגים רגשות ידנית (2–4 שבועות).
- פיתוח צינור ML – חילוץ מאפיינים, אימון מודל (Gradient Boosting או PyTorch), ולידציה.
- אינטגרציה – שירות REST API או gRPC, עיבוד זרם שמע, התראות CRM.
- בדיקות – מבחן A/B על 10% מהשיחות, השוואה למערכת הנוכחית.
- פריסה ותחזוקה – קונטיינריזציה (Docker + Kubernetes), ניטור סטיית מודל.
מה כלול בתוצר הסופי
- מערך נתונים (איסוף, ניקוי, סיווג) אם נדרש.
- מודל מאומן בפורמט ONNX או TorchScript.
- REST API להסקה עם תיעוד.
- אינטגרציה עם תשתית ה-SIP או ה-CRM שלך.
- לוח מחוונים סטטיסטי (התפלגות רגשות, מגמות, SLA).
- הדרכה למפעילים ומפקחים.
- אחריות לאיכות המודל: דיוק לא נמוך מ-80% על מערך הבדיקה.
לוחות זמנים והשקעה
| שלב | משך | הערות |
|---|---|---|
| מודל על מערך נתונים קיים (2–3 קטגוריות) | 2–3 שבועות | עובד אם מערך פתוח מתאים לצרכים שלך |
| איסוף וסיווג נתונים מותאם אישית | 2–3 חודשים | היקף מורחב |
| אינטגרציה ופריסה | 1–2 שבועות | סוהרי, תיעוד מלא |
העלות נקבעת באופן אישי לאחר ניתוח הנתונים והדרישות שלך.
מלכודות נפוצות שיש להימנע מהן
- שימוש באותו מודל למבטאים ושפות שונים ללא התאמה.
- העדר נורמליזציית קו בסיס—גורם לתוצאות חיוביות שגויות על מתקשרים רגשיים באופן טבעי.
- ניסיון לזהות יותר מ-3–4 קטגוריות—הדיוק יורד ל-60%.
- התעלמות מסחיפת נתונים: אימון מחדש תקופתי על הקלטות חדשות הוא חיוני.
בקש פרויקט פיילוט או ביקורת טכנית—נעריך דיוק על הנתונים שלך ונציע את הפתרון האופטימלי. קבל ייעוץ על אינטגרציה ללא התחייבות.
CLASSIFICATION_WINDOW_SEC = 3.0 # анализируем каждые 3 секунды
async def continuous_emotion_monitoring(call_id: str, audio_stream):
classifier = StressAggressionClassifier("models/stress_model.pkl")
baseline = None
buffer = bytearray()
async for chunk in audio_stream:
buffer.extend(chunk)
if len(buffer) >= 16000 * CLASSIFICATION_WINDOW_SEC * 2:
audio = np.frombuffer(buffer, dtype=np.int16).astype(np.float32) / 32768.0
features = extract_stress_features(audio)
# Первые 10 сек — устанавливаем baseline
if baseline is None and len(buffer) < 160000:
baseline = features
buffer = bytearray()
continue
result = classifier.classify(features, baseline)
if result["label"] == "aggressive" and result["confidence"] > 0.75:
await trigger_aggression_alert(call_id, result)
buffer = bytearray()
לוחות זמנים: מסווג על מערך נתונים קיים לוקח 2–3 שבועות. מערך נתונים מותאם אישית מלא ואימון לוקח 2–3 חודשים. צור קשר כדי לדון בפרויקט שלך.







