File size: 6,688 Bytes
e8f3c21
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import gradio as gr
from transformers import pipeline, AutoModelForSpeechSeq2Seq, AutoTokenizer, AutoProcessor
import torch
import logging
import os
import time
import shutil  # เพิ่มการ import shutil
from pydub import AudioSegment, silence
from concurrent.futures import ProcessPoolExecutor
from io import StringIO

# ตั้งค่า logging
log_stream = StringIO()
logging.basicConfig(level=logging.DEBUG, stream=log_stream)
logger = logging.getLogger(__name__)

# กำหนด path สำหรับ model, audio, segment, และ text
MODEL_DIR = "/content/model"
AUDIO_DIR = "/content/audio"
TEXT_DIR = "/content/text"

# สร้าง directories ถ้ายังไม่มี
os.makedirs(MODEL_DIR, exist_ok=True)
os.makedirs(AUDIO_DIR, exist_ok=True)
os.makedirs(TEXT_DIR, exist_ok=True)

# กำหนดชื่อโมเดลและภาษา
MODEL_NAME = "FILM6912/Whisper-small-thai"
lang = "th"

# ตรวจสอบว่าใช้ GPU ได้หรือไม่ ถ้าไม่ได้ใช้ CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
logger.info(f"Using device: {'GPU' if device.type == 'cuda' else 'CPU'}")

# โหลดโมเดลและ Tokenizer ล่วงหน้าเพื่อเก็บใน cache directory
try:
    logger.info("Loading model...")
    model = AutoModelForSpeechSeq2Seq.from_pretrained(MODEL_NAME, cache_dir=MODEL_DIR).to(device)
    tokenizer = AutoTokenizer.from_pretrained(MODEL_NAME, cache_dir=MODEL_DIR)
    processor = AutoProcessor.from_pretrained(MODEL_NAME, cache_dir=MODEL_DIR)

    # สร้าง pipeline สำหรับการแปลงเสียงเป็นข้อความ
    pipe = pipeline(
        task="automatic-speech-recognition",
        model=model,
        tokenizer=tokenizer,
        feature_extractor=processor.feature_extractor,
        chunk_length_s=30,
        device=0 if device.type == 'cuda' else -1,  # บังคับให้ใช้ GPU (device=0) ถ้ามี
    )
    logger.info("Model loaded successfully.")
except Exception as e:
    logger.error(f"Error loading model: {e}")
    raise

# ฟังก์ชันสำหรับการถอดเสียงแบบขนาน
def transcribe_segment(segment: AudioSegment):
    try:
        # ส่งออก segment เป็นไฟล์ WAV ในหน่วยความจำ
        segment_wav = segment.export(format="wav")
        # ถอดเสียงจากไฟล์ segment
        transcription = pipe(segment_wav)["text"]
        return transcription
    except Exception as e:
        logger.error(f"Error during segment transcription: {e}")
        return ""

# ฟังก์ชันสำหรับการแปลงเสียงเป็นข้อความ
def transcribe_with_parallel_processing(microphone_audio, upload_audio):
    audio_path = microphone_audio or upload_audio

    # ตรวจสอบเส้นทางไฟล์เพื่อให้แน่ใจว่าไฟล์มีอยู่จริง
    if not audio_path or not os.path.exists(audio_path):
        logger.error("No audio input received or file does not exist.")
        return "No audio input received or file does not exist.", None, None

    logger.debug(f"Processing audio file: {audio_path}")

    # 8387rcPNz8SRX6pYXgdxCZg3VMLFwtdJB3Z9LeX8Ge2n
    sanitized_filename = os.path.basename(audio_path).replace(" ", "_")
    audio_filename = os.path.join(AUDIO_DIR, sanitized_filename)
    shutil.copyfile(audio_path, audio_filename)

    try:
        # โหลดไฟล์เสียงด้วย pydub
        audio = AudioSegment.from_wav(audio_filename)

        # แบ่งไฟล์เสียงเมื่อเสียงเงียบ
        chunks = silence.split_on_silence(audio, min_silence_len=1000, silence_thresh=-30, keep_silence=500)
        logger.info(f"Audio split into {len(chunks)} segments.")

        if not chunks:
            logger.error("No segments created. Ensure the audio file is correct.")
            return "No segments created. Ensure the audio file is correct.", None, log_stream.getvalue()

        # ถอดเสียงแบบขนาน
        with ProcessPoolExecutor() as executor:
            transcriptions = list(executor.map(transcribe_segment, chunks))

        # รวมผลลัพธ์จากแต่ละส่วนเข้าด้วยกัน
        full_transcription = " ".join(transcriptions)
        logger.info("Transcription completed successfully.")

        # บันทึกผลลัพธ์เป็นไฟล์ .txt โดยตั้งชื่อไฟล์ตาม Unix Time
        output_filename = os.path.join(TEXT_DIR, f"transcription_{int(time.time())}.txt")
        with open(output_filename, "w", encoding="utf-8") as file:
            file.write(full_transcription)
        logger.info(f"Transcription exported to {output_filename}.")

        # ลบไฟล์เสียงต้นฉบับหลังการใช้งานเสร็จสิ้น
        os.remove(audio_filename)

        return full_transcription, output_filename, log_stream.getvalue()
    except Exception as e:
        logger.error(f"Error during transcription: {e}")
        return "Error during transcription.", None, log_stream.getvalue()

# สร้างอินเทอร์เฟซด้วย Gradio พร้อมปุ่มยืนยัน
with gr.Blocks() as interface:
    with gr.Row():
        audio_input = gr.Audio(type="filepath", label="Record or Upload your voice")  # ใช้ filepath สำหรับการบันทึกเสียง
        submit_btn = gr.Button("Start Transcription")
    output_text = gr.Textbox(label="Transcription")
    output_file = gr.File(label="Download Transcription File")
    log_output = gr.Textbox(label="Logs", lines=10)  # ช่องสำหรับแสดง logs

    submit_btn.click(
        fn=transcribe_with_parallel_processing,
        inputs=[audio_input, audio_input],  # ใช้ input เดียวกันสำหรับไฟล์อัปโหลดและการบันทึก
        outputs=[output_text, output_file, log_output]  # เพิ่ม log_output สำหรับแสดง logs
    )

# รันแอปพลิเคชันและแชร์ลิงก์
logger.info("Launching Gradio interface...")
interface.launch(share=True)
logger.info("Gradio interface launched successfully.")