fariedalfarizi's picture
Add profanity detection feature with 150+ Indonesian/English words
c7e434a
"""
Tempo Analysis Service
Analisis tempo dan jeda bicara menggunakan Silero VAD
"""
import torch
from typing import Dict, List
import warnings
warnings.filterwarnings('ignore')
class TempoService:
"""Analisis tempo dan jeda bicara"""
def __init__(self):
"""Initialize Silero VAD model"""
print("πŸ”„ Loading Silero VAD model...")
torch.set_num_threads(1)
self.model, utils = torch.hub.load(
repo_or_dir='snakers4/silero-vad',
model='silero_vad',
force_reload=False
)
(self.get_speech_timestamps,
self.save_audio,
self.read_audio,
self.VADIterator,
self.collect_chunks) = utils
print("βœ… Silero VAD model loaded!\n")
def analyze(self, audio_path: str, transcription: str, sampling_rate: int = 16000) -> Dict:
"""
Analisis tempo berdasarkan jumlah kata per menit dan deteksi jeda panjang
Kriteria penilaian:
- Poin 5 (Sangat Baik): 140-150 kata dalam 48-60 detik, tidak ada jeda >3 detik
- Poin 4 (Baik): 110-139 kata dalam 36-60 detik, tidak ada jeda >3 detik
- Poin 3 (Cukup): 60-109 kata dalam 60 detik, tidak ada jeda >3 detik
- Poin 2 (Buruk): <60 kata dalam 60 detik, tidak ada jeda >3 detik
- Poin 1 (Perlu Ditingkatkan): Berhenti sebelum 60 detik ATAU ada jeda >3 detik
Args:
audio_path: Path ke file audio
transcription: Teks hasil transcription untuk hitung jumlah kata
sampling_rate: Sample rate audio (default: 16000)
Returns:
Dict berisi hasil analisis lengkap
"""
print(f"🎧 Analyzing tempo: {audio_path}")
# Load audio
wav = self.read_audio(audio_path)
# Deteksi segmen bicara
speech_timestamps = self.get_speech_timestamps(
wav, self.model, sampling_rate=sampling_rate
)
# Hitung total durasi audio
total_duration_sec = len(wav) / sampling_rate
# Hitung jumlah kata dari transcription
word_count = len(transcription.split())
# Hitung kata per menit (normalize ke 60 detik)
words_per_minute = (word_count / total_duration_sec) * 60 if total_duration_sec > 0 else 0
# Deteksi jeda panjang (>3 detik)
long_pauses = []
has_long_pause = False
data = []
for i, seg in enumerate(speech_timestamps):
start_time = seg['start'] / sampling_rate
end_time = seg['end'] / sampling_rate
duration = end_time - start_time
if i == 0:
pause_before = start_time
else:
pause_before = start_time - (speech_timestamps[i - 1]['end'] / sampling_rate)
# Check jeda panjang
if pause_before > 3.0:
has_long_pause = True
long_pauses.append({
'after_segment': i,
'pause_duration': round(pause_before, 2)
})
data.append({
'segment': i + 1,
'start_sec': round(start_time, 2),
'end_sec': round(end_time, 2),
'duration_sec': round(duration, 2),
'pause_before_sec': round(pause_before, 2)
})
# Tentukan skor berdasarkan kriteria
if total_duration_sec < 60 or has_long_pause:
# Poin 1: Berhenti sebelum 60 detik ATAU ada jeda >3 detik
poin = 1
kategori = "Perlu Ditingkatkan"
if total_duration_sec < 60:
alasan = f"Durasi bicara hanya {round(total_duration_sec, 1)} detik (kurang dari 60 detik)"
else:
alasan = f"Terdapat {len(long_pauses)} jeda lebih dari 3 detik"
elif words_per_minute >= 140 and words_per_minute <= 150 and total_duration_sec >= 48:
# Poin 5: 140-150 kata dalam 48-60 detik
poin = 5
kategori = "Sangat Baik"
alasan = f"Tempo ideal: {round(words_per_minute, 1)} kata/menit dalam {round(total_duration_sec, 1)} detik"
elif words_per_minute >= 110 and words_per_minute <= 139 and total_duration_sec >= 36:
# Poin 4: 110-139 kata dalam 36-60 detik
poin = 4
kategori = "Baik"
alasan = f"Tempo baik: {round(words_per_minute, 1)} kata/menit dalam {round(total_duration_sec, 1)} detik"
elif words_per_minute >= 60 and words_per_minute <= 109:
# Poin 3: 60-109 kata dalam 60 detik
poin = 3
kategori = "Cukup"
alasan = f"Tempo cukup: {round(words_per_minute, 1)} kata/menit"
else:
# Poin 2: <60 kata dalam 60 detik
poin = 2
kategori = "Buruk"
alasan = f"Tempo lambat: hanya {round(words_per_minute, 1)} kata/menit"
print("βœ… Tempo analysis complete!\n")
return {
'score': poin,
'category': kategori,
'reason': alasan,
'total_duration_sec': round(total_duration_sec, 2),
'word_count': word_count,
'words_per_minute': round(words_per_minute, 1),
'has_long_pause': has_long_pause,
'long_pauses': long_pauses,
'total_segments': len(speech_timestamps),
# 'segments': data
}