File size: 11,951 Bytes
af53b0c
 
 
 
 
 
 
 
 
 
 
5a78b29
af53b0c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
import torch  # นำเข้า PyTorch สำหรับการใช้งาน GPU

import gradio as gr  # นำเข้า Gradio สำหรับสร้าง UI
import yt_dlp as youtube_dl  # นำเข้า yt-dlp สำหรับการดาวน์โหลดวิดีโอจาก YouTube
from transformers import pipeline  # นำเข้า pipeline จาก transformers สำหรับ ASR
from transformers.pipelines.audio_utils import ffmpeg_read  # นำเข้า ffmpeg_read สำหรับการอ่านไฟล์เสียง

import tempfile  # นำเข้า tempfile สำหรับการสร้างไฟล์ชั่วคราว
import os  # นำเข้า os สำหรับการจัดการไฟล์และไดเรกทอรี

# ตั้งค่าค่าคงที่ต่าง ๆ
MODEL_NAME = "fruk19/N_ASR_"  # ชื่อของโมเดลที่ใช้
BATCH_SIZE = 8  # ขนาดของ batch ที่ใช้ในการประมวลผล
FILE_LIMIT_MB = 1000  # ขนาดไฟล์สูงสุด (MB)
YT_LENGTH_LIMIT_S = 3600  # จำกัดความยาวไฟล์ YouTube สูงสุดที่ 1 ชั่วโมง

# ตรวจสอบว่ามี GPU หรือไม่ ถ้ามีให้ใช้ GPU (device=0) ถ้าไม่มีให้ใช้ CPU
device = 0 if torch.cuda.is_available() else "cpu"

# สร้าง pipeline สำหรับ automatic speech recognition (ASR)
pipe = pipeline(
    task="automatic-speech-recognition",  # งานที่ทำคือการรู้จำเสียงอัตโนมัติ
    model=MODEL_NAME,  # โมเดลที่ใช้
    chunk_length_s=30,  # ความยาวของ chunk ในหน่วยวินาที
    device=device,  # อุปกรณ์ที่ใช้ (GPU หรือ CPU)
)

def transcribe(inputs):
    """
    Transcribe the given audio input to text using the Whisper model.
    
    Args:
        inputs (str): Path to the audio file.

    Returns:
        str: Transcribed text.

    Raises:
        gr.Error: If no audio file is submitted.
    """
    if inputs is None:
        # ถ้าไม่มีไฟล์เสียงถูกส่งเข้ามา ให้แสดงข้อผิดพลาด
        raise gr.Error("No audio file submitted! Please upload or record an audio file before submitting your request.")

    # ถอดความเสียงเป็นข้อความ
    text = pipe(inputs, batch_size=BATCH_SIZE, return_timestamps=True)["text"]
    return text  # ส่งคืนข้อความที่ถอดความแล้ว

def _return_yt_html_embed(yt_url):
    """
    Return an HTML string to embed a YouTube video.

    Args:
        yt_url (str): YouTube video URL.

    Returns:
        str: HTML string for embedding the YouTube video.
    """
    # ดึง video_id จาก URL
    video_id = yt_url.split("?v=")[-1]
    # สร้าง HTML สำหรับฝังวิดีโอ YouTube
    HTML_str = (
        f'<center> <iframe width="500" height="320" src="https://www.youtube.com/embed/{video_id}"> </iframe>'
        " </center>"
    )
    return HTML_str  # ส่งคืน HTML string

def download_yt_audio(yt_url, filename):
    """
    Download audio from a YouTube video and save it to a file.

    Args:
        yt_url (str): YouTube video URL.
        filename (str): Path to save the downloaded file.

    Raises:
        gr.Error: If there is a problem with downloading the YouTube video.
    """
    # สร้างตัวโหลดข้อมูลจาก YouTube
    info_loader = youtube_dl.YoutubeDL()
    
    try:
        # ดึงข้อมูลของวิดีโอจาก YouTube โดยไม่ดาวน์โหลด
        info = info_loader.extract_info(yt_url, download=False)
    except youtube_dl.utils.DownloadError as err:
        # ถ้ามีข้อผิดพลาดในการดึงข้อมูล ให้แสดงข้อผิดพลาด
        raise gr.Error(str(err))
    
    # ตรวจสอบความยาวของไฟล์
    file_length = info["duration_string"]  # ความยาวของไฟล์ในรูปแบบ HH:MM:SS
    file_h_m_s = file_length.split(":")  # แยกเวลาเป็นชั่วโมง นาที และวินาที
    file_h_m_s = [int(sub_length) for sub_length in file_h_m_s]  # แปลงค่าเวลาเป็นจำนวนเต็ม
    
    if len(file_h_m_s) == 1:
        file_h_m_s.insert(0, 0)  # ถ้ามีแค่ค่าเดียว ให้เพิ่มชั่วโมงเป็น 0
    if len(file_h_m_s) == 2:
        file_h_m_s.insert(0, 0)  # ถ้ามีสองค่า ให้เพิ่มชั่วโมงเป็น 0
    # คำนวณความยาวของไฟล์ในหน่วยวินาที
    file_length_s = file_h_m_s[0] * 3600 + file_h_m_s[1] * 60 + file_h_m_s[2]
    
    if file_length_s > YT_LENGTH_LIMIT_S:
        # ถ้าความยาวไฟล์เกินขีดจำกัด ให้แสดงข้อผิดพลาด
        yt_length_limit_hms = time.strftime("%HH:%MM:%SS", time.gmtime(YT_LENGTH_LIMIT_S))
        file_length_hms = time.strftime("%HH:%MM:%SS", time.gmtime(file_length_s))
        raise gr.Error(f"Maximum YouTube length is {yt_length_limit_hms}, got {file_length_hms} YouTube video.")
    
    # ตั้งค่าตัวเลือกสำหรับ yt-dlp
    ydl_opts = {"outtmpl": filename, "format": "worstvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"}
    
    with youtube_dl.YoutubeDL(ydl_opts) as ydl:
        try:
            # ดาวน์โหลดวิดีโอจาก YouTube
            ydl.download([yt_url])
        except youtube_dl.utils.ExtractorError as err:
            # ถ้ามีข้อผิดพลาดในการดาวน์โหลด ให้แสดงข้อผิดพลาด
            raise gr.Error(str(err))

def yt_transcribe(yt_url):
    """
    Transcribe the audio from a YouTube video to text using the Whisper model.

    Args:
        yt_url (str): YouTube video URL.

    Returns:
        tuple: HTML string for embedding the YouTube video, transcribed text.
    """
    # สร้าง HTML สำหรับฝังวิดีโอ YouTube
    html_embed_str = _return_yt_html_embed(yt_url)

    with tempfile.TemporaryDirectory() as tmpdirname:
        # สร้างไดเรกทอรีชั่วคราว
        filepath = os.path.join(tmpdirname, "video.mp4")
        # ดาวน์โหลดไฟล์เสียงจาก YouTube
        download_yt_audio(yt_url, filepath)
        with open(filepath, "rb") as f:
            # อ่านข้อมูลจากไฟล์
            inputs = f.read()

    # อ่านข้อมูลเสียงจากไฟล์วิดีโอ
    inputs = ffmpeg_read(inputs, pipe.feature_extractor.sampling_rate)
    inputs = {"array": inputs, "sampling_rate": pipe.feature_extractor.sampling_rate}

    # ถอดความเสียงเป็นข้อความ
    text = pipe(inputs, batch_size=BATCH_SIZE, return_timestamps=True)["text"]

    return html_embed_str, text  # ส่งคืน HTML string และข้อความที่ถอดความแล้ว

# สร้าง UI สำหรับแอปพลิเคชันด้วย Gradio
demo = gr.Blocks()

# อินเตอร์เฟสสำหรับถอดความจากไมโครโฟน
mf_transcribe = gr.Interface(
    fn=transcribe,  # ฟังก์ชันที่ใช้ในการถอดความ
    inputs=[
        gr.inputs.Audio(source="microphone", type="filepath", optional=True),  # อินพุตเป็นเสียงจากไมโครโฟน
    ],
    outputs="text",  # ผลลัพธ์เป็นข้อความ
    layout="horizontal",  # เลย์เอาต์แบบแนวนอน
    theme="huggingface",  # ธีมของ Gradio
    title="Whisper Large V2: Transcribe Audio",  # ชื่อของแอปพลิเคชัน
    description=(
        "Transcribe long-form microphone or audio inputs with the click of a button! Demo uses the"
        f" checkpoint [{MODEL_NAME}](https://huggingface.co/{MODEL_NAME}) and 🤗 Transformers to transcribe audio files"
        " of arbitrary length."
    ),  # คำอธิบายของแอปพลิเคชัน
    allow_flagging="never",  # ไม่อนุญาตให้ flag ผลลัพธ์
)

# อินเตอร์เฟสสำหรับถอดความจากไฟล์เสียงที่อัปโหลด
file_transcribe = gr.Interface(
    fn=transcribe,  # ฟังก์ชันที่ใช้ในการถอดความ
    inputs=[
        gr.inputs.Audio(source="upload", type="filepath", optional=True, label="Audio file"),  # อินพุตเป็นไฟล์เสียงที่อัปโหลด
    ],
    outputs="text",  # ผลลัพธ์เป็นข้อความ
    layout="horizontal",  # เลย์เอาต์แบบแนวนอน
    theme="huggingface",  # ธีมของ Gradio
    title="Whisper Large V2: Transcribe Audio",  # ชื่อของแอปพลิเคชัน
    description=(
        "Transcribe long-form microphone or audio inputs with the click of a button! Demo uses the"
        f" checkpoint [{MODEL_NAME}](https://huggingface.co/{MODEL_NAME}) and 🤗 Transformers to transcribe audio files"
        " of arbitrary length."
    ),  # คำอธิบายของแอปพลิเคชัน
    allow_flagging="never",  # ไม่อนุญาตให้ flag ผลลัพธ์
)

# อินเตอร์เฟสสำหรับถอดความจากวิดีโอ YouTube
yt_transcribe = gr.Interface(
    fn=yt_transcribe,  # ฟังก์ชันที่ใช้ในการถอดความ
    inputs=[
        gr.inputs.Textbox(lines=1, placeholder="Paste the URL to a YouTube video here", label="YouTube URL"),  # อินพุตเป็น URL ของ YouTube
    ],
    outputs=["html", "text"],  # ผลลัพธ์เป็น HTML สำหรับฝังวิดีโอและข้อความที่ถอดความแล้ว
    layout="horizontal",  # เลย์เอาต์แบบแนวนอน
    theme="huggingface",  # ธีมของ Gradio
    title="Whisper Large V2: Transcribe YouTube",  # ชื่อของแอปพลิเคชัน
    description=(
        "Transcribe long-form YouTube videos with the click of a button! Demo uses the checkpoint"
        f" [{MODEL_NAME}](https://huggingface.co/{MODEL_NAME}) and 🤗 Transformers to transcribe video files of"
        " arbitrary length."
    ),  # คำอธิบายของแอปพลิเคชัน
    allow_flagging="never",  # ไม่อนุญาตให้ flag ผลลัพธ์
)

# รวม UI ของทุกส่วนเข้าด้วยกันใน Tabbed Interface
with demo:
    gr.TabbedInterface([mf_transcribe, file_transcribe, yt_transcribe], ["Microphone", "Audio file", "YouTube"])

# เริ่มต้น Gradio demo
demo.launch(enable_queue=True)