我們今天兜了三個小工具,
程式在這裡的days/day1python get_transcription.py
是從自帶字幕的youtube連結獲取字幕,存成txt檔python yt_download.py
如果本身沒有自帶字幕的話,就先把影片的音訊檔載下來python whisper_audio2txt.py
然後用whisper轉成文字檔
結果在專案目錄下的data下的lee.txt和hung.json
我們想要替RAG系統獲得成對的(context, question, answer)供後續方法論的驗證
當前的子任務是:先想辦法獲得context,我們後續再prompt llm從context生成(Q, A) pair
這部分的想法是從youtube影片獲取,那這又區分成兩個case:
case1: 當youtube影片有提供字幕的時候,我們直接把字幕載下來
case2: 當youtube影片本身沒有提供字幕的時候,我們可以把音訊檔下載下來,丟給whisper
我們準備了兩個youtube的連結:
一個有字幕的例子:
【生成式人工智慧與機器學習導論2025】第0講:開場與課程簡介
感覺累積起來可以變成發問有關生程式AI的問題->查找李老師的youtube課程並且精確到秒
一個沒有字幕的例子:
# 寶寶睡不過夜?總是半夜起床哭鬧討奶喝怎麼安撫?影響寶寶睡眠的因素是什麼?|黃瑽寧醫師健康講堂【寶寶系列 EP21】
這個可能可以變成一個育兒上有疑難雜症就問他的應用
pip install youtube-transcript-api
sudo apt install -y ffmpeg
pip install yt-dlp
pip install faster-whisper
def _extract_video_id(url: str) -> str:
 p = urlparse(url)
 if p.netloc.endswith("youtu.be"):
     return p.path.lstrip("/").split("/")[0]
 q = parse_qs(p.query)
 if "v" in q:
     return q["v"][0]
 m = re.search(r"/(shorts|embed)/([A-Za-z0-9_-]{6,})", p.path)
 if m:
     return m.group(2)
 raise ValueError("無法從網址解析出 YouTube 影片 ID。")
def has_youtube_captions(url: str, preferred_langs=None) -> bool:
 from youtube_transcript_api import YouTubeTranscriptApi
 from youtube_transcript_api._errors import TranscriptsDisabled
 from youtube_transcript_api import NoTranscriptFound
 video_id = _extract_video_id(url)
 api = YouTubeTranscriptApi()
 try:
     tlist = api.list(video_id)  # TranscriptList,可疊代
 except (TranscriptsDisabled, NoTranscriptFound):
     return False
 except Exception:
     return False
 if preferred_langs:
     try:
         tlist.find_transcript(preferred_langs)
         return True
     except NoTranscriptFound:
         return False
 else:
     return len(list(tlist)) > 0
def fetch_youtube_captions(
 url: str,
 preferred_langs=None,
 translate_to: str | None = None,
 join_with: str = "\n",
 preserve_formatting: bool = False,
 ) -> str:
 if preferred_langs is None:
     preferred_langs = ["zh-Hant", "zh-TW", "zh-Hans", "zh", "en"]
 video_id = _extract_video_id(url)
 from youtube_transcript_api import YouTubeTranscriptApi, NoTranscriptFound
 api = YouTubeTranscriptApi()
 if translate_to:
     # 先找到一個字幕,再翻譯
     tlist = api.list(video_id)
     try:
         base_t = tlist.find_transcript(preferred_langs)
     except NoTranscriptFound:
         base_t = next(iter(tlist), None)
     fetched = base_t.translate(translate_to).fetch(preserve_formatting=preserve_formatting)
 else:
     fetched = api.fetch(video_id, languages=preferred_langs, preserve_formatting=preserve_formatting)
 raw = fetched.to_raw_data()
 lines = [d["text"].strip() for d in raw if d.get("text", "").strip()]
 junk = {"[Music]", "[Applause]", "[Laughter]"}
 return join_with.join([ln for ln in lines if ln not in junk])
到這邊看一下結果:
text = fetch_youtube_captions(links[0])
print(text[:30])
'各位同學大家好 我們來上課吧\n剛才只是用Google的VO3'
我們要先用yt_dlp把影片載下來,這個如果安裝上有問題,我覺得就直接去colab上用比較省事
4. 下載mp3
def download_audio(url, output):
    ydl_opts = {
        "format": "bestaudio/best",
        "outtmpl": output,
        "postprocessors": [{
            "key": "FFmpegExtractAudio",
            "preferredcodec": "mp3",
            "preferredquality": "192"
        }]
    }
    with yt_dlp.YoutubeDL(ydl_opts) as ydl:
        ydl.download([url])
    return output
    
output_path = 'audio.mp3'
download_audio(links[1], output_path)
到這邊路徑下會有一個audio.mp3檔案,點開來就是影片的語音檔了。
from faster_whisper import WhisperModel
from pathlib import Path
def transcribe_faster_whisper(
    audio_file: str | Path,
    model_name: str = "large-v3",
    device: str = "auto",          # "cuda" | "cpu" | "auto"
    compute_type: str = "auto",     # "float16" | "int8_float16" | "int8" | "auto"
    language: str | None = None,    # "zh"、"en"、None=自動偵測
):
    audio_file = str(audio_file)
    model = WhisperModel(model_name, device=device, compute_type=compute_type)
    segments, info = model.transcribe(
        audio_file,
        language=language,
        vad_filter=True,        # 內建 Voice Activity Detection,通常品質更穩
        beam_size=5,
    )
    # 收集所有 segments
    segs = []
    full_text = []
    for seg in segments:
        segs.append({"start": seg.start, "end": seg.end, "text": seg.text})
        full_text.append(seg.text)
    return {
        "text": " ".join(full_text).strip(),
        "segments": segs,
        "language": info.language,
        "language_probability": info.language_probability,
    }
到這邊看一下結果:
zh 0.9990234375
大家平安 我是黃宗霖醫師 在當新手父母的過程當中 寶寶的睡眠這件事情 一直都是我們黃宗霖醫師健康講上 留人區最頻繁被爸媽提出來的問題 而且我自己孩子很小的時候 我曾經腦袋有一種邪惡的一種念頭 就是當寶
dur: 46.231650829315186 sec
可以看到比如人名的辨識會有問題,沒有標點,還有一些特殊的詞彙也做不好,但也就堪用吧!
如果faster_whisper執行有問題的話,通常是因為找不到cudnn
我遇到的是顯示:
Unable to load any of {libcudnn_ops.so.9.1.0, libcudnn_ops.so.9.1, libcudnn_ops.so.9, libcudnn_ops.so}
Invalid handle. Cannot load symbol cudnnCreateTensorDescriptor
Aborted (core dumped)
除了直接安裝cudnn以外:pip install -U --no-cache-dir nvidia-cudnn-cu12 ctranslate2
還要記得把lib加到LD_LIBRARY_PATH
export LD_LIBRARY_PATH="$(
python - <<'PY'
import os, site
libdirs=[]
for base in site.getsitepackages()+[site.getusersitepackages()]:
    for sub in [("nvidia","cudnn","lib"), ("nvidia","cublas","lib")]:
        d=os.path.join(base, *sub)
        if os.path.isdir(d): libdirs.append(d)
print(":".join(libdirs))
PY
):${LD_LIBRARY_PATH}"
再不然就是改用cpu跑model選tiny其實也不慢
老樣子,本地環境弄不起來的話就可以直接去colab上用省事
我們今天兜了兩個小工具,
一個是從自帶字幕的youtube連結獲取字幕,準備當成上下文
一個是當youtube影片本身沒有附字幕的時候,我們把它下載下來,再用whisper轉成文字檔