Asterisk'da qo'ng'iroqlarni yozib olish oson. Lekin o'sha yozuvlardan amaliy foyda olish — aksariyat jamoalar aynan shu joyda qoqiladi.
Agar siz dialplan'da MixMonitor yoki Monitor'ni allaqachon sozlagan bo'lsangiz, qo'lingizda ma'lumotlar oltin koni turibdi. Muammo shundaki, ko'pchilik Asterisk o'rnatmalarida yozuvlar compliance uchun qo'yiladigan belgi sifatida qaraladi: fayllar /var/spool/asterisk/monitor/ ichida yotadi va nizoli holat chiqmaguncha ularga hech kim tegmaydi.
Bu qo'llanmada xom qo'ng'iroq yozuvlarini tuzilgan analitika tizimiga qanday aylantirish ko'rsatiladi. Siz yozuvlarni tez qidiruv uchun qanday tashkil qilishni, ularni CDR metama'lumotlari bilan bog'lashni, sifat muammolarini o'zi ko'rsatib beradigan dashboard'lar qurishni va hatto open-source vositalar yordamida AI nutq analitikasini qo'shishni o'rganasiz.
Nega qo'ng'iroq yozuvlari analitikasi kerak
Analitikasiz qo'ng'iroq yozuvi — bu videokuzatuv kameralarini o'rnatib, yozuvlarni hech qachon ko'rmaslik bilan barobar.
Yozuvlar analitikasi nima beradi:
| Stsenariy | Analitikasiz | Analitika bilan |
|---|---|---|
| Sifat nazorati | Tasodifiy tekshiruvlar (2-5% qamrov) | Qo'ng'iroqlarning 100% bo'yicha tizimli baholash |
| Operatorlarni o'qitish | Xotiraga tayangan subyektiv fikr | Aniq misollar bilan ma'lumotga asoslangan o'qitish |
| Compliance tekshiruvi | Shikoyat kelganda qo'lda ko'rib chiqish | Qoidabuzarliklarni avtomatik belgilash |
| Mijozlarni tushunish | Tarqoq kuzatuvlar | Minglab murojaat bo'yicha trend tahlili |
| Nizolarni hal qilish | Fayl tizimi bo'ylab qo'lda qidirish | Qo'ng'iroq metama'lumotlari orqali bir zumda topish |
Qo'ng'iroq yozuvlari analitikasidan foydalanayotgan kompaniyalar joriy etishning birinchi choragidayoq birinchi qo'ng'iroqda hal qilish ko'rsatkichi 23% ga yaxshilanganini va o'rtacha ishlov berish vaqti 18% ga qisqarganini qayd etadi (ICMI Contact Center Research, 2024).
1-qadam. Poydevor: yozib olishni sozlash
Analitika qurishdan oldin yozib olishning mustahkam poydevori kerak. Asterisk ikkita asosiy ilova taklif qiladi:
MixMonitor va Monitor solishtiruvi
| Xususiyat | MixMonitor | Monitor |
|---|---|---|
| Audio miksi | Ikkala tomonni bitta faylga yozadi | Yo'nalishlar bo'yicha alohida fayllar (yoki miksangan) |
| Unumdorlikka ta'siri | Yengil (tavsiya etiladi) | Og'irroq, ovoz muammolari bo'lishi mumkin |
| Qo'ng'iroq davomida boshqaruv | Dinamik start/stop/pauza | Cheklangan boshqaruv |
| Yozuv formatlari | WAV, WAV49, GSM, SLN, SLIN | WAV, WAV49, GSM |
| Kanal talabi | Javob berilgan kanallarda ishlaydi | Javob berilgan kanallarda ishlaydi |
| Kimga tavsiya etiladi | Ishlab chiqarishdagi call-markazlarga | Legacy o'rnatmalarga |
MixMonitor'dan foydalaning. Bu zamonaviy va production'ga tayyor variant.
MixMonitor bilan oddiy dialplan
; extensions.conf — Recording with structured filenames
[macro-record-call]
exten => s,1,NoOp(Starting call recording)
same => n,Set(RECORD_DIR=/var/spool/asterisk/monitor/${STRFTIME(${EPOCH},,%Y/%m/%d)})
same => n,System(mkdir -p ${RECORD_DIR})
same => n,Set(RECORD_FILE=${RECORD_DIR}/${STRFTIME(${EPOCH},,%Y%m%d-%H%M%S)}-${UNIQUEID}-${CALLERID(num)}-${EXTEN})
same => n,Set(CDR(recordingfile)=${RECORD_FILE}.wav)
same => n,MixMonitor(${RECORD_FILE}.wav,b)
same => n,MacroExit()Bu dialplan'dagi asosiy nuqtalar:
- —Sana bo'yicha kataloglar (
YYYY/MM/DD) bitta papkada juda ko'p fayl to'planib, fayl tizimi sekinlashib qolishining oldini oladi - —Tuzilgan fayl nomlari vaqt belgisi, unikal ID, qo'ng'iroq qiluvchi raqami va ichki raqamni o'z ichiga oladi — bu analitika uchun juda muhim
- —CDR bilan bog'lanish
CDR(recordingfile)orqali yozuvni qo'ng'iroq tafsilotlari yozuviga ulaydi
FreePBX'da yozib olishni sozlash
Agar siz FreePBX'dan foydalansangiz, yozib olish har bir ichki raqam, ring group yoki navbat uchun alohida sozlanadi:
- —Admin → Extensions → [Extension] → Recording bo'limiga o'ting
- —Yozib olish siyosatini tanlang: Force, Don't Care, Yes yoki No
- —Inbound External, Outbound External, Inbound Internal, Outbound Internal variantlaridan birini tanlang
FreePBX yozuvlarni /var/spool/asterisk/monitor/ ichida quyidagi formatda saqlaydi:
{year}/{month}/{day}/{type}-{date}-{time}-{source}-{destination}-{uniqueid}.wav
2-qadam. Analitika uchun saqlash arxitekturasi
Production'dagi call-markaz yozuv tizimi uchun saqlashni puxta rejalashtirish kerak. 64 kbit/s (G.711 WAV) tezlikda bir soatlik yozilgan suhbat taxminan 28,8 MB joy egallaydi. Har bir operatorga kuniga o'rtacha 6 soat suhbat vaqti to'g'ri keladigan 50 operatorli call-markaz kuniga 8,6 GB, oyiga esa 260 GB hosil qiladi.
Saqlash hajmi kalkulyatori
| Operatorlar | Kuniga o'rt. suhbat soati | Kunlik hajm | Oylik hajm | Yillik hajm |
|---|---|---|---|---|
| 10 | 5 | 1,4 GB | 43 GB | 516 GB |
| 25 | 5 | 3,6 GB | 108 GB | 1,3 TB |
| 50 | 6 | 8,6 GB | 260 GB | 3,1 TB |
| 100 | 6 | 17,3 GB | 518 GB | 6,2 TB |
| 200 | 6 | 34,6 GB | 1 TB | 12,4 TB |
Tavsiya etilgan saqlash tuzilmasi
/var/spool/asterisk/
└── monitor/
├── 2026/
│ ├── 01/
│ │ ├── 15/
│ │ │ ├── 20260115-093042-1705312242.1-2125551234-100.wav
│ │ │ └── ...
│ │ └── 16/
│ └── 02/
├── compressed/ # Archived recordings (MP3/Opus)
│ ├── 2025/
│ └── ...
└── transcripts/ # AI-generated transcripts
├── 2026/
└── ...Siqish strategiyasi
Arxiv uchun WAV fayllar keraksiz darajada katta. Avtomatik siqishni yo'lga qo'ying:
#!/bin/bash
# compress-recordings.sh — Run daily via cron
# Compresses WAV recordings older than 7 days to Opus format
# Opus achieves 10:1 compression vs WAV with excellent quality
MONITOR_DIR="/var/spool/asterisk/monitor"
COMPRESS_DIR="$MONITOR_DIR/compressed"
DAYS_OLD=7
find "$MONITOR_DIR" -name "*.wav" -mtime +$DAYS_OLD \
-not -path "*/compressed/*" | while read wavfile; do
# Preserve directory structure
relative_path="${wavfile#$MONITOR_DIR/}"
opus_path="$COMPRESS_DIR/${relative_path%.wav}.opus"
mkdir -p "$(dirname "$opus_path")"
# Convert to Opus (high quality, ~1/10 the size)
ffmpeg -i "$wavfile" -c:a libopus -b:a 24k \
-application voip "$opus_path" 2>/dev/null
if [ $? -eq 0 ] && [ -f "$opus_path" ]; then
rm "$wavfile"
echo "Compressed: $relative_path"
fi
donecrontab'ga qo'shing:
# Run compression daily at 2 AM
0 2 * * * /usr/local/bin/compress-recordings.sh >> /var/log/recording-compression.log 2>&13-qadam. Yozuvlarni CDR metama'lumotlari bilan bog'lash
Xom yozuvlar CDR (qo'ng'iroq tafsilotlari yozuvi) ma'lumotlari bilan bog'langanda haqiqiy kuchga ega bo'ladi. Bu bog'lanish "kutish vaqti 60 soniyadan oshgan barcha yozuvlarni ko'rsat" yoki "shu mijoz raqamidan oxirgi 30 kundagi qo'ng'iroqlarni top" kabi so'rovlar qilish imkonini beradi.
Yozuvlar analitikasi uchun ma'lumotlar bazasi sxemasi
-- Create a recordings metadata table that extends CDR
CREATE TABLE recording_metadata (
id SERIAL PRIMARY KEY,
uniqueid VARCHAR(64) NOT NULL,
linkedid VARCHAR(64),
recording_path TEXT NOT NULL,
recording_format VARCHAR(10) DEFAULT 'wav',
file_size_bytes BIGINT,
duration_seconds INTEGER,
silence_percentage DECIMAL(5,2),
caller_id VARCHAR(80),
destination VARCHAR(80),
queue_name VARCHAR(64),
agent VARCHAR(64),
direction VARCHAR(10), -- 'inbound', 'outbound', 'internal'
disposition VARCHAR(20),
recorded_at TIMESTAMP NOT NULL,
compressed BOOLEAN DEFAULT FALSE,
transcribed BOOLEAN DEFAULT FALSE,
transcript_path TEXT,
quality_score DECIMAL(3,1),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- Indexes for common analytics queries
CONSTRAINT unique_recording UNIQUE (uniqueid, recording_path)
);
CREATE INDEX idx_recorded_at ON recording_metadata(recorded_at);
CREATE INDEX idx_agent ON recording_metadata(agent);
CREATE INDEX idx_queue ON recording_metadata(queue_name);
CREATE INDEX idx_caller ON recording_metadata(caller_id);
CREATE INDEX idx_disposition ON recording_metadata(disposition);
CREATE INDEX idx_direction ON recording_metadata(direction);Metama'lumotlarni avtomatik yig'ish skripti
#!/usr/bin/env python3
"""
recording_indexer.py — Scans recordings, extracts metadata, populates database.
Run every 15 minutes via cron.
"""
import os
import re
import wave
import subprocess
import psycopg2
from datetime import datetime
from pathlib import Path
DB_CONFIG = {
'host': 'localhost',
'database': 'asterisk',
'user': 'asterisk',
'password': 'your_password'
}
MONITOR_DIR = '/var/spool/asterisk/monitor'
FILENAME_PATTERN = re.compile(
r'(\d{8}-\d{6})-(\d+\.\d+)-(\d+)-(\d+)\.wav$'
)
def get_wav_duration(filepath):
"""Get duration in seconds from WAV file."""
try:
with wave.open(filepath, 'r') as wf:
frames = wf.getnframes()
rate = wf.getframerate()
return frames / float(rate)
except Exception:
return None
def detect_silence_percentage(filepath):
"""Detect percentage of silence in recording using sox."""
try:
result = subprocess.run(
['sox', filepath, '-n', 'stats'],
capture_output=True, text=True, timeout=30
)
# Parse sox stats for RMS level
for line in result.stderr.split('\n'):
if 'RMS lev dB' in line:
rms = float(line.split()[-1])
# Very rough: if RMS < -40dB, significant silence
if rms < -40:
return 80.0
elif rms < -30:
return 50.0
elif rms < -20:
return 20.0
return 5.0
except Exception:
return None
def index_recordings():
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
indexed = 0
for root, dirs, files in os.walk(MONITOR_DIR):
for filename in files:
if not filename.endswith('.wav'):
continue
filepath = os.path.join(root, filename)
# Skip already indexed
cur.execute(
"SELECT 1 FROM recording_metadata WHERE recording_path = %s",
(filepath,)
)
if cur.fetchone():
continue
# Extract metadata from filename
match = FILENAME_PATTERN.search(filename)
if match:
timestamp_str, uniqueid, caller, dest = match.groups()
recorded_at = datetime.strptime(timestamp_str, '%Y%m%d-%H%M%S')
else:
# Fallback: use file modification time
uniqueid = filename.replace('.wav', '')
recorded_at = datetime.fromtimestamp(os.path.getmtime(filepath))
caller = dest = None
duration = get_wav_duration(filepath)
file_size = os.path.getsize(filepath)
silence_pct = detect_silence_percentage(filepath)
cur.execute("""
INSERT INTO recording_metadata
(uniqueid, recording_path, file_size_bytes, duration_seconds,
silence_percentage, caller_id, destination, recorded_at)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (uniqueid, recording_path) DO NOTHING
""", (uniqueid, filepath, file_size, duration,
silence_pct, caller, dest, recorded_at))
indexed += 1
conn.commit()
cur.close()
conn.close()
print(f"Indexed {indexed} new recordings")
if __name__ == '__main__':
index_recordings()CDR ma'lumotlari bilan bog'lash
Yozuvlar va CDR o'rtasidagi asosiy join maydoni — uniqueid:
-- Join recordings with CDR for complete call context
SELECT
r.recording_path,
r.duration_seconds,
r.silence_percentage,
c.src AS caller,
c.dst AS destination,
c.dcontext AS context,
c.billsec AS billable_seconds,
c.disposition,
c.accountcode,
c.userfield AS queue_name
FROM recording_metadata r
JOIN cdr c ON r.uniqueid = c.uniqueid
WHERE r.recorded_at >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY r.recorded_at DESC;4-qadam. Yozuvlar analitikasi uchun asosiy so'rovlar
Yozuvlar CDR ma'lumotlariga bog'langach, kuchli analitik dashboard'lar qurish mumkin.
1-so'rov. Kunlik yozuvlar hajmi va saqlash
-- Daily recording stats: count, total duration, storage used
SELECT
DATE(recorded_at) AS day,
COUNT(*) AS total_recordings,
ROUND(SUM(duration_seconds) / 3600.0, 1) AS total_hours,
ROUND(SUM(file_size_bytes) / 1073741824.0, 2) AS storage_gb,
ROUND(AVG(duration_seconds), 0) AS avg_duration_sec,
ROUND(AVG(silence_percentage), 1) AS avg_silence_pct
FROM recording_metadata
WHERE recorded_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY DATE(recorded_at)
ORDER BY day DESC;2-so'rov. Operatorlar kesimida yozuvlar tahlili
-- Per-agent recording metrics: identify coaching opportunities
SELECT
c.dstchannel AS agent_channel,
SUBSTRING(c.dstchannel FROM 'SIP/(.+)-') AS agent,
COUNT(*) AS calls_recorded,
ROUND(AVG(r.duration_seconds), 0) AS avg_duration,
ROUND(AVG(r.silence_percentage), 1) AS avg_silence_pct,
SUM(CASE WHEN r.duration_seconds < 30 THEN 1 ELSE 0 END) AS short_calls,
SUM(CASE WHEN r.silence_percentage > 50 THEN 1 ELSE 0 END) AS high_silence_calls,
ROUND(AVG(c.billsec), 0) AS avg_billsec
FROM recording_metadata r
JOIN cdr c ON r.uniqueid = c.uniqueid
WHERE r.recorded_at >= CURRENT_DATE - INTERVAL '7 days'
AND c.disposition = 'ANSWERED'
GROUP BY c.dstchannel, SUBSTRING(c.dstchannel FROM 'SIP/(.+)-')
ORDER BY calls_recorded DESC;3-so'rov. Yozib olish qamrovi tahlili
-- What percentage of calls are being recorded?
-- Identifies gaps in recording coverage
SELECT
DATE(calldate) AS day,
COUNT(*) AS total_calls,
COUNT(r.id) AS recorded_calls,
ROUND(COUNT(r.id)::DECIMAL / COUNT(*) * 100, 1) AS coverage_pct,
COUNT(*) - COUNT(r.id) AS missing_recordings
FROM cdr c
LEFT JOIN recording_metadata r ON c.uniqueid = r.uniqueid
WHERE c.calldate >= CURRENT_DATE - INTERVAL '7 days'
AND c.disposition = 'ANSWERED'
AND c.billsec > 5
GROUP BY DATE(calldate)
ORDER BY day DESC;4-so'rov. Jimlikni aniqlash — muammoli qo'ng'iroqlarni topish
-- Calls with excessive silence (potential quality issues)
-- High silence = hold without music, dead air, or connection problems
SELECT
r.recorded_at,
r.caller_id,
r.destination,
r.duration_seconds,
r.silence_percentage,
r.recording_path,
c.disposition,
c.userfield AS queue
FROM recording_metadata r
JOIN cdr c ON r.uniqueid = c.uniqueid
WHERE r.silence_percentage > 40
AND r.duration_seconds > 60
AND r.recorded_at >= CURRENT_DATE - INTERVAL '7 days'
ORDER BY r.silence_percentage DESC
LIMIT 20;Navbatlarda nima sodir bo'layotganini taxmin qilishdan charchadingizmi?
Astervis sizning Asterisk PBX'ingiz uchun 30+ realtime grafik, operator KPI va CRM-integratsiya beradi. On-premise. 5 daqiqada o'rnatiladi. $119/oydan flat — operatorlar soni cheklanmagan.
5-so'rov. Soatlik yozuvlar heatmap'i
-- Recording volume by hour and day of week
-- Identifies peak periods and potential capacity issues
SELECT
EXTRACT(DOW FROM recorded_at) AS day_of_week,
EXTRACT(HOUR FROM recorded_at) AS hour,
COUNT(*) AS recordings,
ROUND(AVG(duration_seconds), 0) AS avg_duration,
ROUND(SUM(file_size_bytes) / 1048576.0, 0) AS storage_mb
FROM recording_metadata
WHERE recorded_at >= CURRENT_DATE - INTERVAL '30 days'
GROUP BY EXTRACT(DOW FROM recorded_at), EXTRACT(HOUR FROM recorded_at)
ORDER BY day_of_week, hour;5-qadam. AI asosidagi nutq analitikasi
Zamonaviy yozuvlar analitikasi metama'lumotlar bilan cheklanmaydi. AI nutq analitikasi yozuvlarni avtomatik transkripsiya qilib, mijoz kayfiyati, mavzuni aniqlash va compliance tekshiruvi kabi insight'larni ajratib bera oladi.
Arxitekturaga umumiy nazar
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Asterisk │────>│ Storage │────>│ Transcribe │────>│ Analyze │
│ MixMonitor │ │ (WAV/Opus) │ │ (Whisper) │ │ (NLP/LLM) │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│
┌──────┴──────┐
│ Dashboard │
│ (Metrics) │
└─────────────┘
1-variant. Whisper'ni o'z serveringizda ishlatish
OpenAI'ning Whisper modeli bepul, ochiq kodli va o'zingizning uskunangizda ishlaydi:
#!/usr/bin/env python3
"""
transcribe_recordings.py — Batch transcribe recordings using Whisper.
Requires: pip install openai-whisper torch
"""
import whisper
import json
import os
import psycopg2
from pathlib import Path
# Load Whisper model (options: tiny, base, small, medium, large-v3)
# 'small' is the best balance of speed and accuracy for telephony
model = whisper.load_model("small")
DB_CONFIG = {
'host': 'localhost',
'database': 'asterisk',
'user': 'asterisk',
'password': 'your_password'
}
TRANSCRIPT_DIR = '/var/spool/asterisk/monitor/transcripts'
def transcribe_pending():
conn = psycopg2.connect(**DB_CONFIG)
cur = conn.cursor()
# Get un-transcribed recordings
cur.execute("""
SELECT id, recording_path, recorded_at
FROM recording_metadata
WHERE transcribed = FALSE
AND duration_seconds > 10
AND duration_seconds < 1800
ORDER BY recorded_at DESC
LIMIT 50
""")
for rec_id, rec_path, recorded_at in cur.fetchall():
if not os.path.exists(rec_path):
continue
try:
# Transcribe with Whisper
result = model.transcribe(
rec_path,
language=None, # Auto-detect language
task="transcribe",
fp16=False # Use fp32 for CPU
)
# Save transcript
transcript_path = os.path.join(
TRANSCRIPT_DIR,
recorded_at.strftime('%Y/%m/%d'),
f"{os.path.basename(rec_path).replace('.wav', '.json')}"
)
os.makedirs(os.path.dirname(transcript_path), exist_ok=True)
transcript_data = {
'text': result['text'],
'language': result.get('language', 'unknown'),
'segments': [
{
'start': seg['start'],
'end': seg['end'],
'text': seg['text']
}
for seg in result.get('segments', [])
]
}
with open(transcript_path, 'w') as f:
json.dump(transcript_data, f, indent=2)
# Update database
cur.execute("""
UPDATE recording_metadata
SET transcribed = TRUE, transcript_path = %s
WHERE id = %s
""", (transcript_path, rec_id))
conn.commit()
print(f"Transcribed: {os.path.basename(rec_path)} "
f"({result.get('language', '?')})")
except Exception as e:
print(f"Error transcribing {rec_path}: {e}")
continue
cur.close()
conn.close()
if __name__ == '__main__':
transcribe_pending()Whisper uchun uskuna talablari
| Model | VRAM | CPU: audio daqiqasiga vaqt | GPU: audio daqiqasiga vaqt | Aniqlik |
|---|---|---|---|---|
| tiny | ~1 GB | ~10 soniya | ~1 soniya | Kalit so'z qidirish uchun yetarli |
| base | ~1 GB | ~15 soniya | ~2 soniya | Analitika uchun maqbul |
| small | ~2 GB | ~30 soniya | ~3 soniya | Telefoniya uchun tavsiya etiladi |
| medium | ~5 GB | ~60 soniya | ~5 soniya | Yuqori aniqlik |
| large-v3 | ~10 GB | ~120 soniya | ~8 soniya | Eng yuqori aniqlik |
Kuniga o'rtacha 5 daqiqalik 300 ta yozuvni qayta ishlaydigan 50 operatorli call-markaz uchun GPU'dagi small modeli butun kunlik yozuvlarni taxminan 75 daqiqada ko'rib chiqadi.
2-variant. Bulutli transkripsiya API'si
Boshqariladigan xizmatni afzal ko'radigan jamoalar uchun:
# Using OpenAI Whisper API (cloud)
import openai
client = openai.OpenAI(api_key="your-api-key")
def transcribe_cloud(audio_path):
with open(audio_path, "rb") as audio_file:
transcript = client.audio.transcriptions.create(
model="whisper-1",
file=audio_file,
response_format="verbose_json",
timestamp_granularities=["segment"]
)
return transcriptBulutli API taxminan audio daqiqasiga $0.006 turadi. Kuniga 300 qo'ng'iroq × 5 daqiqa hisobida bu kuniga $9, ya'ni oyiga ~$270.
Kalit so'zlar va mavzularni aniqlash
Transkriptlar tayyor bo'lgach, kalit so'zlar va mavzularni AI'siz ham topish mumkin:
#!/usr/bin/env python3
"""
keyword_analyzer.py — Detect keywords and topics in call transcripts.
"""
import json
import re
from collections import Counter
# Define keyword categories relevant to your business
KEYWORD_CATEGORIES = {
'complaint': [
'complaint', 'unhappy', 'dissatisfied', 'terrible', 'worst',
'cancel', 'refund', 'manager', 'supervisor', 'unacceptable'
],
'upsell_opportunity': [
'upgrade', 'additional', 'more features', 'enterprise',
'premium', 'advanced', 'expand', 'grow', 'scale'
],
'technical_issue': [
'not working', 'broken', 'error', 'bug', 'crash',
'down', 'outage', 'slow', 'timeout', 'failed'
],
'positive': [
'thank you', 'excellent', 'great', 'wonderful', 'perfect',
'appreciate', 'helpful', 'resolved', 'solved', 'happy'
],
'compliance_risk': [
'guarantee', 'promise', 'definitely', 'always',
'never', 'lawsuit', 'legal', 'attorney', 'sue'
]
}
def analyze_transcript(transcript_path):
with open(transcript_path) as f:
data = json.load(f)
text = data['text'].lower()
results = {}
for category, keywords in KEYWORD_CATEGORIES.items():
found = []
for keyword in keywords:
count = len(re.findall(r'\b' + re.escape(keyword) + r'\b', text))
if count > 0:
found.append({'keyword': keyword, 'count': count})
results[category] = {
'matches': found,
'total_hits': sum(m['count'] for m in found),
'flagged': len(found) > 0
}
return resultsSegmentlar bo'yicha kayfiyat dinamikasi
# Simple sentiment scoring per transcript segment
# For production: use a fine-tuned model or LLM API
from textblob import TextBlob
def segment_sentiment(transcript_path):
"""Analyze sentiment across call segments to detect escalation patterns."""
with open(transcript_path) as f:
data = json.load(f)
timeline = []
for segment in data.get('segments', []):
blob = TextBlob(segment['text'])
timeline.append({
'start': segment['start'],
'end': segment['end'],
'text': segment['text'],
'polarity': round(blob.sentiment.polarity, 2), # -1 to 1
'subjectivity': round(blob.sentiment.subjectivity, 2) # 0 to 1
})
# Detect escalation: sentiment dropping over time
if len(timeline) > 4:
first_quarter = sum(s['polarity'] for s in timeline[:len(timeline)//4])
last_quarter = sum(s['polarity'] for s in timeline[-len(timeline)//4:])
escalation = first_quarter - last_quarter > 0.5
else:
escalation = False
return {
'segments': timeline,
'avg_polarity': round(sum(s['polarity'] for s in timeline) / max(len(timeline), 1), 2),
'escalation_detected': escalation
}6-qadam. Compliance va saqlash muddatlari
Qo'ng'iroqlarni yozib olish qoidalari yurisdiksiyalar bo'yicha jiddiy farq qiladi. Bu talablarga rioya qilmaslik jarimalar va yuridik javobgarlikka olib kelishi mumkin.
Yozib olishga rozilik modellari
| Model | Talab | Yurisdiksiyalar |
|---|---|---|
| Bir tomon roziligi | Suhbatdagi bir kishi bilishi yetarli | AQSh (federal daraja), Buyuk Britaniya, Yevropa Ittifoqining ko'p qismi |
| Ikki/barcha tomon roziligi | Suhbatdagi hamma bilishi shart | Kaliforniya, Florida, Germaniya, ba'zi Yevropa Ittifoqi davlatlari |
| Rozilik talab qilinmaydi | Ishga oid qo'ng'iroqlar istisno | Ba'zi B2B holatlar |
Rozilik e'lonini qanday qo'shish kerak
; extensions.conf — Play recording notification before connecting
[inbound-queue]
exten => s,1,Answer()
same => n,Playback(this-call-may-be-recorded)
same => n,Wait(0.5)
same => n,Macro(record-call)
same => n,Queue(support,t,,,180)
same => n,Hangup()Avtomatik saqlash siyosati
#!/bin/bash
# recording-retention.sh — Enforce data retention policies
# Run weekly via cron
MONITOR_DIR="/var/spool/asterisk/monitor"
TRANSCRIPT_DIR="$MONITOR_DIR/transcripts"
# Retention periods (adjust per your compliance requirements)
RECORDING_RETENTION_DAYS=365 # Keep recordings for 1 year
TRANSCRIPT_RETENTION_DAYS=730 # Keep transcripts for 2 years
COMPRESSED_RETENTION_DAYS=730 # Keep compressed archives for 2 years
echo "$(date): Starting retention cleanup"
# Delete original WAV files older than retention period
find "$MONITOR_DIR" -name "*.wav" -mtime +$RECORDING_RETENTION_DAYS \
-not -path "*/compressed/*" -delete -print | wc -l | \
xargs -I {} echo "Deleted {} expired WAV files"
# Delete compressed files older than retention period
find "$MONITOR_DIR/compressed" -name "*.opus" \
-mtime +$COMPRESSED_RETENTION_DAYS -delete -print | wc -l | \
xargs -I {} echo "Deleted {} expired compressed files"
# Delete transcripts older than retention period
find "$TRANSCRIPT_DIR" -name "*.json" \
-mtime +$TRANSCRIPT_RETENTION_DAYS -delete -print | wc -l | \
xargs -I {} echo "Deleted {} expired transcripts"
# Clean empty directories
find "$MONITOR_DIR" -type d -empty -delete
echo "$(date): Retention cleanup complete"GDPR va ma'lumot subyektlarining so'rovlari
GDPR talablariga javob berish uchun sizda muayyan qo'ng'iroq qiluvchiga tegishli barcha yozuvlarni topish va o'chirish imkoniyati bo'lishi kerak:
-- Find all recordings for a specific caller (data subject request)
SELECT
recording_path,
transcript_path,
recorded_at,
duration_seconds,
destination
FROM recording_metadata
WHERE caller_id = '2125551234'
ORDER BY recorded_at DESC;
-- Delete all data for a specific caller (right to erasure)
-- Step 1: Get file paths for physical deletion
SELECT recording_path, transcript_path
FROM recording_metadata
WHERE caller_id = '2125551234';
-- Step 2: Delete database records
DELETE FROM recording_metadata WHERE caller_id = '2125551234';7-qadam. Dashboard qurish
Yozuvlar analitikasi dashboard'i xulosalarni o'zi ko'rsatishi kerak — supervayzerni har bir yozuvni qo'lda qayta tinglashga majburlamasdan.
Dashboard karkasi: uch daraja
1-daraja — real vaqtdagi wallboard (bir qarashda tushunarli):
- —Ayni damda ketayotgan yozuvlar
- —Bugungi yozuvlar soni va reja solishtiruvi
- —Saqlash hajmining to'lganlik foizi
- —Yozib olishdagi nosozliklar haqida ogohlantirishlar
2-daraja — kundalik operatsion nazorat (supervayzerlar uchun):
- —Yozib olish qamrovi foizi (barcha qo'ng'iroqlar yozilyaptimi?)
- —O'rtacha qo'ng'iroq davomiyligi dinamikasi
- —Jimlik ulushining taqsimoti
- —Ko'rib chiqish uchun jimligi yuqori qo'ng'iroqlar belgisi
- —Kalit so'z detektori belgilagan qo'ng'iroqlar
3-daraja — strategik analitika (haftalik/oylik):
- —Yozuvlar hajmi trendlari
- —Saqlash o'sishi prognozi
- —Transkriptlardan insight'lar: eng ko'p uchragan mavzular, kayfiyat dinamikasi
- —Operatorlarni o'qitish nuqtalari (ko'p jimlik, qisqa qo'ng'iroqlar)
- —Compliance auditi: qamrovdagi bo'shliqlar, rozilik e'lonini tekshirish
Kuzatib boriladigan asosiy metrikalar
| Metrika | Formula | Maqsad | Nega muhim |
|---|---|---|---|
| Yozib olish qamrovi | Yozilgan qo'ng'iroqlar / Javob berilgan barcha qo'ng'iroqlar × 100 | >98% | Qo'ng'iroqlar yozilmasa — compliance riski |
| O'rtacha yozuv davomiyligi | Yozuvlarning umumiy soniyasi / Yozuvlar soni | Biznesga bog'liq | Trend o'zgarishi jarayondagi muammodan darak beradi |
| Jimlik ulushi | Jimlik soniyalari / Umumiy davomiylik × 100 | <20% | Ko'p jimlik = kutish vaqti, "o'lik efir" |
| Saqlash o'sish tezligi | Kuniga qo'shiladigan GB | 2 barobar zaxira bilan rejalang | Disk to'lib qolishining oldini oladi |
| Transkripsiya navbati | Transkripsiya qilinmagan / Barcha yozuvlar | <5% | Analitikaning dolzarbligini ta'minlaydi |
| Salbiy kayfiyat ulushi | Salbiy qo'ng'iroqlar / Transkripsiya qilinganlar × 100 | <15% | Mijoz mamnunligi indikatori |
| Compliance belgilari ulushi | Belgilangan qo'ng'iroqlar / Transkripsiya qilinganlar × 100 | <2% | Risklarni boshqarish |
Solishtiruv: yozuvlar analitikasiga yondashuvlar
| Xususiyat | O'z skriptlaringiz | QueueMetrics | CallCabinet | Astervis |
|---|---|---|---|---|
| Joriy etish mehnati | Yuqori (haftalar) | O'rtacha (kunlar) | Past (soatlar) | Past (daqiqalar) |
| Yozuvlarni tinglash | Fayllarga qo'lda kirish | Ichki pleyer | Bulutli pleyer | Ichki pleyer |
| CDR bilan bog'lanish | O'z SQL'ingiz | Avtomatik | Avtomatik | Avtomatik |
| Raqam/sana bo'yicha qidiruv | SQL so'rovlar | GUI qidiruvi | GUI qidiruvi | Bir zumda qidiruv |
| Nutq analitikasi | O'zingiz yozasiz | Yo'q | AI asosida ($$$) | Tez orada |
| Jimlikni aniqlash | O'z skriptlaringiz | Yo'q | Bor | Bor |
| Compliance vositalari | Qo'lda | Asosiy | To'liq to'plam | Ichki saqlash siyosatlari |
| Operatorlarni baholash | Yo'q | Qo'lda QA formalari | AI baholash | Avtomatik KPI'lar |
| Narxi | Bepul + sizning vaqtingiz | CHF 8/agent/oy | Narx so'rov bo'yicha | $119/oydan |
| Self-hosted | Ha | Ha | Faqat bulut | Ha |
| Real vaqtdagi dashboard | O'zingiz yozasiz | Asosiy | Ha | 30+ grafik |
Tez start uchun cheklist
Noldan ishlaydigan qo'ng'iroq yozuvlari analitikasigacha bo'lgan yo'l:
- — 1-qadam: yozib olishni yoqing — dialplan'ga MixMonitor'ni tuzilgan fayl nomlari bilan qo'shing
- — 2-qadam: saqlashni tashkil qiling — sana bo'yicha kataloglar yarating, hajmni rejalang
- — 3-qadam: CDR bilan bog'lang —
CDR(recordingfile)to'lib turishiga ishonch hosil qiling, metama'lumotlar jadvalini yarating - — 4-qadam: yozuvlarni indekslang — indekslash skriptini cron orqali har 15 daqiqada ishga tushiring
- — 5-qadam: eski fayllarni siqing — kunlik siqish cron vazifasini sozlang
- — 6-qadam: oddiy dashboard yig'ing — qamrov va davomiylik so'rovlaridan boshlang
- — 7-qadam: transkripsiyani qo'shing — Whisper'ni o'rnating, paketli transkripsiyani ishga tushiring
- — 8-qadam: kalit so'zlarni aniqlashni sozlang — kategoriyalarni belgilang, transkriptlarni avtomatik skanerlang
- — 9-qadam: saqlash siyosatini belgilang — compliance talablaringizga mos avtomatik tozalashni sozlang
- — 10-qadam: ko'rib chiqing va yaxshilang — har hafta dashboard metrikalarini tahlil qiling, chegaralarni moslang
Keyingi qadam
Qo'ng'iroq yozuvlari analitikasini noldan qurish kuchli natija beradi, lekin ko'p vaqt oladi. Skriptlarni qo'llab-quvvatlash, saqlashni boshqarish, transkripsiya pipeline'larini ishlab turishga majbur qilish va dashboard'lar qurish kerak — bularning barchasi call-markazni boshqarish bilan bir vaqtda.
Astervis og'ir yukni o'z zimmasiga oladi. Bitta buyruq bilan o'rnating va darhol 30+ analitik grafik, CDR bilan bog'langan qo'ng'iroq yozuvlarini tinglash, operatorlar samaradorligini kuzatish va navbatlarni real vaqtda monitoring qilish imkoniyatiga ega bo'ling — bitta ham SQL so'rov yozmasdan.
14 kunlik bepul sinov bilan boshlang: astervis.io
Asterisk analitikasi bo'yicha yana qo'llanmalar kerakmi? Asterisk navbatlarini real vaqtda monitoring qilish, CDR hisobotining eng yaxshi amaliyotlari va operatorlar samaradorligini kuzatish haqidagi maqolalarimizni o'qing.
Taxmin qilishni bas qiling. Ko'rishni boshlang.
Asterisk call-markazingizning haqiqiy ko'rinishi: navbatlardagi kutish vaqti, operatorlar faolligi, trunk yuklamasi va 30+ grafik. Sizning serveringizda on-premise. 5 daqiqada o'rnatish. Kartasiz.
$119/oydan flat. Operatorlar soni cheklanmagan. 14 kunlik triаl.
