File size: 3,781 Bytes
c800820
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import whisper
import gradio as gr
from docx import Document
import time
import librosa
import soundfile as sf
from scipy.cluster.hierarchy import dendrogram, fcluster
from sklearn.preprocessing import StandardScaler
import numpy as np

import ssl
import urllib.request

# ไธดๆ—ถ็ฆ็”จ่ฏไนฆ้ชŒ่ฏ
context = ssl._create_unverified_context()
urllib.request.urlopen("https://huggingface.co", context=context)

# Load the Whisper model (choose a model based on performance/accuracy requirements)
model = whisper.load_model("base")  # You can use "small", "medium", "large" for better accuracy

def extract_mfcc(audio_path, sr=None):
    """Extract MFCC features from audio file"""
    y, sr = librosa.load(audio_path, sr=sr)
    mfccs = librosa.feature.mfcc(y=y, sr=sr, n_mfcc=13)
    return mfccs.T  # Transpose to get (time_steps, n_mfcc)

def perform_clustering(features):
    """Perform hierarchical clustering on MFCC features"""
    scaler = StandardScaler()
    scaled_features = scaler.fit_transform(features)
    
    # Compute pairwise distances
    distance_matrix = np.sqrt(((scaled_features - scaled_features[:, np.newaxis])**2).sum(axis=2))
    
    # Perform hierarchical clustering
    linkage = np.linalg.norm(distance_matrix[:, np.newaxis] - distance_matrix[np.newaxis, :], axis=2)
    
    # Generate dendrogram and get flat clusters
    clusters = fcluster(linkage, t=0.5, criterion='distance')  # Threshold needs tuning
    return clusters

def transcribe_and_generate_docx(audio_path, language):
    # Step 1: Basic transcription with Whisper
    audio_file = whisper.load_audio(audio_path)
    language_code = 'en' if language == "English" else 'zh'
    result = model.transcribe(audio_file, language=language_code)
    transcribed_text = result["text"]
    
    # Step 2: Extract MFCC features for clustering
    mfcc_features = extract_mfcc(audio_path)
    if len(mfcc_features) < 2:
        return "output_transcription.docx", transcribed_text
    
    # Step 3: Perform hierarchical clustering
    try:
        clusters = perform_clustering(mfcc_features)
    except Exception as e:
        log_message(f"Clustering error: {str(e)}")
        raise RuntimeError("Failed to cluster speakers") from e
    
    # Assign speaker labels
    unique_speakers = list(np.unique(clusters))
    speaker_map = {i+1: speaker for i, speaker in enumerate(unique_speakers)}
    
    # Split transcription text by speaker clusters
    time_segments = model.get_timestamps(audio_file)
    speaker_texts = {}
    
    for cluster_id, segment in zip(clusters, time_segments):
        speaker_id = speaker_map[cluster_id]
        start_time = segment['start']
        end_time = segment['end']
        
        # Find corresponding text็‰‡ๆฎต (approximation method)
        current_text = []
        for part in result["alternatives"][0]["transcript"].split(' '):
            part_duration = len(part) * 0.03  # Approximate word duration
            if start_time <= cumulative_time < end_time:
                current_text.append(part)
                cumulative_time += part_duration
        
        speaker_texts[speaker_id] = ' '.join(current_text).strip()
    
    # Create a docx document with speaker separation
    doc = Document()
    doc.add_heading("Speaker Transcription", level=1)
    
    for speaker_id, text in speaker_texts.items():
        doc.add_heading(f"Speaker {speaker_id}", level=2)
        doc.add_paragraph(text)
    
    # Save the document
    output_filename = f"speaker_transcription_{os.path.basename(audio_path)}.docx"
    doc.save(output_filename)
    
    return output_filename, "\n\n".join([f"Speaker {i}: {text}" for i, text in speaker_texts.items()])

# ... [Keep Gradio interface code unchanged] ...

# Launch the interface
iface.launch()