トップ 最新 追記

Masa's blog

検索キーワード:

2026年03月01日 yt-dlpでダウンロードした字幕ファイルをChatGPTの助けを借りたpythonスクリプトで日本語に翻訳 [長年日記]

_ とある外国映画のフルサイズ動画をyt-dlpで取得。日本語字幕に対応していなかったのでChatGPTに相談したら、「あなたにはpythonスクリプトを使った方法をおすすめ...」とアドバイスされた。

_ youtubeからyt-dlpを使って動画と字幕ファイルをダウンロード

字幕でサポートされる言語を確認。

$ yt-dlp --list-subs 'https://www.youtube.com/... snip ...'

動画と字幕ファイルをダウンロード

$ yt-dlp --write-subs --sub-langs "en.*" --convert-subs srt 'https://www.youtube.com/... snip ...'

字幕ファイルが、動画ファイルと共に拡張子「srt」でダウンロードされる。

_ pythonからgoogle翻訳を呼び出して字幕ファイルを日本語に翻訳

作業ディレクトリを用意

$ mkdir srt_translate
$ cd srt_translate

pythonの仮想環境を準備

$ python3 -m venv venv

pythonの仮想環境を有効化

$ source venv/bin/activate

必要なモジュールをインストール

$ pip install pysrt deep-translator

インストールされたモジュールを確認

$ pip list
Package            Version
------------------ -----------
beautifulsoup4     4.14.3
certifi            2026.2.25
chardet            6.0.0.post1
charset-normalizer 3.4.4
deep-translator    1.11.4
idna               3.11
pip                26.0.1
pysrt              1.1.2
requests           2.32.5
soupsieve          2.8.3
typing_extensions  4.15.0
urllib3            2.6.3

翻訳pythonスクリプトを準備。ChatGPTいわく「netflixレベル」とのこと...

$ vi translate_netflix.py
# --- 必要なライブラリの読み込み ---

import pysrt                 # SRT字幕ファイルの読み込み・編集・保存用
import json                  # 翻訳結果をキャッシュとして保存するため
import os                    # ファイルの存在確認などのOS操作
import time                  # API連続アクセスを避けるための待機処理
from deep_translator import GoogleTranslator  # Google翻訳を利用するライブラリ


# --- 入出力ファイル設定 ---

INPUT_FILE = "input.srt"                # 英語字幕ファイル
OUTPUT_FILE = "output_netflix_ja.srt"   # 日本語字幕の出力先
CACHE_FILE = "cache.json"               # 翻訳結果を保存するキャッシュファイル


# --- 動作パラメータ(調整可能) ---

BATCH_SIZE = 40      # まとめて翻訳する字幕行数(大きいほど高速)
SLEEP_TIME = 1       # バッチごとに待機する秒数(API制限回避)

MAX_CHARS_PER_LINE = 15   # 1行あたり最大文字数(放送基準)
MAX_LINES = 2              # 字幕は最大2行まで
CHARS_PER_SECOND = 4       # 1秒あたり読める文字数(放送字幕の目安)


# --- 翻訳エンジン初期化(英語→日本語) ---

translator = GoogleTranslator(source='en', target='ja')


# --- キャッシュ読み込み ---
# 既に翻訳した文章は再翻訳しない(高速化+API負荷軽減)

if os.path.exists(CACHE_FILE):
    with open(CACHE_FILE, "r", encoding="utf-8") as f:
        cache = json.load(f)
else:
    cache = {}  # キャッシュが無ければ空辞書


# --- キャッシュ保存関数 ---
# 翻訳途中で止まっても再開できるよう、随時保存

def save_cache():
    with open(CACHE_FILE, "w", encoding="utf-8") as f:
        json.dump(cache, f, ensure_ascii=False)


# --- 字幕表示時間(秒)を計算する関数 ---
# SRTの開始時刻と終了時刻から表示秒数を求める

def duration_seconds(sub):
    return (sub.end.ordinal - sub.start.ordinal) / 1000.0


# --- 放送・配信レベルの字幕整形関数 ---
# ・口語化
# ・文字数制限
# ・最大2行
# ・読みやすい改行

def format_subtitle(text, max_chars):

    # --- 簡易口語化(字幕向けに簡潔に) ---
    text = text.replace("私は", "")
    text = text.replace("です。", "。")
    text = text.replace("ます。", "。")

    # --- 改行候補を作成(句読点ごと) ---
    parts = text.replace("、", "、\n").replace("。", "。\n").split("\n")

    lines = []

    # --- 各パートを最大文字数以内に分割 ---
    for part in parts:
        while len(part) > max_chars:
            lines.append(part[:max_chars])
            part = part[max_chars:]
        if part:
            lines.append(part)

    # --- 行数が多すぎる場合は2行にまとめる ---
    if len(lines) > MAX_LINES:
        half = len(lines) // 2
        lines = [
            "".join(lines[:half]),
            "".join(lines[half:])
        ]

    # 最大2行まで返す
    return "\n".join(lines[:MAX_LINES])


# --- SRTファイル読み込み ---

print("Loading...")
subs = pysrt.open(INPUT_FILE, encoding='utf-8')
total = len(subs)
print("Total:", total)


# --- バッチ処理用の一時領域 ---
batch = []          # 翻訳待ちテキスト
batch_index = []    # 元の字幕番号


# --- メイン処理ループ ---
for i, sub in enumerate(subs):

    # 改行をスペースに変換(翻訳エンジン対策)
    text = sub.text.replace("\n", " ")

    # --- 表示時間に応じた最大文字数を計算 ---
    duration = duration_seconds(sub)

    # 字幕全体で表示できる最大文字数
    max_chars_total = int(duration * CHARS_PER_SECOND)

    # 下限10文字、上限30文字(15×2行)
    max_chars_total = max(10, min(max_chars_total, MAX_CHARS_PER_LINE * MAX_LINES))

    # 1行あたりの文字数
    max_chars_per_line = max_chars_total // MAX_LINES


    # --- キャッシュにあれば翻訳せず使用 ---
    if text in cache:
        subs[i].text = format_subtitle(cache[text], max_chars_per_line)
        continue


    # --- バッチに追加 ---
    batch.append((text, max_chars_per_line))
    batch_index.append(i)


    # --- 一定数たまったらまとめて翻訳 ---
    if len(batch) >= BATCH_SIZE:

        # テキストを改行区切りで結合
        joined = "\n".join([b[0] for b in batch])

        try:
            # 一括翻訳(高速化)
            translated = translator.translate(joined)

            # 結果を行ごとに分割
            results = translated.split("\n")

            # 元の字幕に戻す
            for (src, maxc), idx, dst in zip(batch, batch_index, results):
                cache[src] = dst
                subs[idx].text = format_subtitle(dst, maxc)

            # キャッシュ保存
            save_cache()

            print(f"{i+1}/{total}")

        except Exception as e:
            print("Error:", e)

        # バッチをリセット
        batch = []
        batch_index = []

        # API負荷軽減
        time.sleep(SLEEP_TIME)


# --- 残りのバッチ処理 ---
if batch:
    joined = "\n".join([b[0] for b in batch])
    translated = translator.translate(joined)
    results = translated.split("\n")

    for (src, maxc), idx, dst in zip(batch, batch_index, results):
        cache[src] = dst
        subs[idx].text = format_subtitle(dst, maxc)

    save_cache()


# --- 日本語字幕として保存 ---
print("Saving...")
subs.save(OUTPUT_FILE, encoding='utf-8')
print("Done")

翻訳前の字幕ファイルを準備

$ cp ~/... snip .../ダウンロードした字幕ファイル.srt input.srt

翻訳スクリプトを実行

$ python translate_netflix.py

変換結果が「output_netflix_ja.srt」に出力される。

変換が途中で停止しても

  • cache.json に保存
  • 再実行すると未翻訳分だけ処理

とのこと。

python仮想環境の無効化

$ deactivate

_ ffmpegを使って動画に字幕ファイルを合成

$ ffmpeg -i ダウンロードした動画ファイル.mp4 -vf subtitles=output_netflix_ja.srt  字幕ファイル合成後の動画ファイル.mp4

翻訳された結果が直訳されたっぽい違和感のあるものだったので、さらにChatGPTに相談したところ、ローカルAI環境を構築する方法を提案してきた...こちらの話はまた後ほど。


2026年03月15日 llama.cpp + qwen3.5 small + SYCL(level_zero:gpu) on Slackware64-current(i7-1195G7) [長年日記]

_ Intel(R) Graphics Compute Runtime for oneAPI Level Zero and OpenCL(TM) Driver

インテルのサイト(https://github.com/intel/compute-runtime/releases/tag/26.05.37020.3/)からdeb形式のバイナリを取得する。

$ mkdir neo
$ cd neo
$ wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.28.4/intel-igc-core-2_2.28.4+20760_amd64.deb
$ wget https://github.com/intel/intel-graphics-compiler/releases/download/v2.28.4/intel-igc-opencl-2_2.28.4+20760_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/intel-ocloc-dbgsym_26.05.37020.3-0_amd64.ddeb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/intel-ocloc_26.05.37020.3-0_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/intel-opencl-icd-dbgsym_26.05.37020.3-0_amd64.ddeb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/intel-opencl-icd_26.05.37020.3-0_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/libigdgmm12_22.9.0_amd64.deb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/libze-intel-gpu1-dbgsym_26.05.37020.3-0_amd64.ddeb
$ wget https://github.com/intel/compute-runtime/releases/download/26.05.37020.3/libze-intel-gpu1_26.05.37020.3-0_amd64.deb

rootに成って、*.deb、*.ddebを展開する。

# for f in *.deb *.ddeb; do
#     ar x $f
#     tar xf data.tar.*
#     rm -f data.tar.*
# done

格納先のディレクトリ(/opt/intel/compute-runtime)を作り、「etc」「usr」をコピーする。

# mkdir /opt/intel/compute-runtime
# cp -r etc /opt/intel/compute-runtime/
# cp -r usr /opt/intel/compute-runtime/

/etc/ld.so.conf.d/intel-compute-runtime.conf を作成する。

/opt/intel/compute-runtime/usr/local/lib
/opt/intel/compute-runtime/usr/lib/x86_64-linux-gnu
/opt/intel/compute-runtime/usr/lib/x86_64-linux-gnu/intel-opencl

/opt/intel/compute-runtime/etc/OpenCL/vendors/intel.icd を修正する。

/opt/intel/compute-runtime/usr/lib/x86_64-linux-gnu/intel-opencl/libigdrcl.so

intel.icd のシンボリックリンクをはる。

# cd /etc/OpenCL/vendors/
# ln -s /opt/intel/compute-runtime/etc/OpenCL/vendors/intel.icd .

_ Intel® oneAPI Base Toolkit

インテルのサイト(https://www.intel.com/content/www/us/en/developer/tools/oneapi/base-toolkit-download.html)からインストーラーシェルスクリプト(intel-oneapi-base-toolkit-2025.3.1.36_offline.sh)をダウンロードし、rootで実行する。 /opt/intel/oneapi/配下にインストールされる。

# chmod +x intel-oneapi-base-toolkit-2025.3.1.36_offline.sh
# ./intel-oneapi-base-toolkit-2025.3.1.36_offline.sh

_ oneAPI Level Zero

github(https://github.com/oneapi-src/level-zero/releases/)より、deb形式のバイナリーを取得する。

$ wget https://github.com/oneapi-src/level-zero/releases/download/v1.28.0/level-zero_1.28.0+u24.04_amd64.deb

rootに成って、*.debを展開する。

# ar x level-zero_1.28.0+u24.04_amd64.deb
# tar xvf data.tar.gz

格納先のディレクトリ(/opt/intel/level-zero/1.28.0)を作り、「usr」をコピーする。

# mkdir /opt/intel/level-zero
# mkdir /opt/intel/level-zero/1.28.0
# cp -r usr /opt/intel/level-zero/1.28.0/

/etc/ld.so.conf.d/intel-compute-runtime.conf に設定行を追加する。

# echo /opt/intel/level-zero/1.28.0/usr/lib/x86_64-linux-gnu >>/etc/ld.so.conf.d/intel-compute-runtime.conf

追加したライブラリをOSに認識させる。

# ldconfig -v

ここまでの作業でlevel_zero:gpuを認識するか確認する。

$ source /opt/intel/oneapi/setvars.sh
:: initializing oneAPI environment ...
   bash: BASH_VERSION = 5.3.9(1)-release
   args: Using "$@" for setvars.sh arguments:
:: advisor -- latest
:: ccl -- latest
:: compiler -- latest
:: dal -- latest
:: debugger -- latest
:: dev-utilities -- latest
:: dnnl -- latest
:: dpcpp-ct -- latest
:: dpl -- latest
:: ipp -- latest
:: ippcp -- latest
:: mkl -- latest
:: mpi -- latest
:: tbb -- latest
:: umf -- latest
:: vtune -- latest
:: oneAPI environment initialized ::

$ sycl-ls
[level_zero:gpu][level_zero:0] Intel(R) oneAPI Unified Runtime over Level-Zero, Intel(R) Iris(R) Xe Graphics 12.0.0 [1.14.37020+3]
[opencl:cpu][opencl:0] Intel(R) OpenCL, 11th Gen Intel(R) Core(TM) i7-1195G7 @ 2.90GHz OpenCL 3.0 (Build 0) [2026.20.1.0.12_160000]
[opencl:gpu][opencl:1] Intel(R) OpenCL Graphics, Intel(R) Iris(R) Xe Graphics OpenCL 3.0 NEO  [26.05.37020.3]

_ モデル(Qwen3.5-9B-GGUF 90億パラメータ,量子化4bit)の取得

生成AIモデルをHugging Face(https://huggingface.co/unsloth/Qwen3.5-9B-GGUF)から取得し、~/AI/models/Qwen3.5-9B-Q4_K_M.ggufに格納。

_ llama.cpp

github(https://github.com/ggml-org/llama.cpp/releases/)から最新版ソースを取得しビルドする。

$ tar xvf llama.cpp-b8352.tar.gz
$ cd llama.cpp-b8352
$ source /opt/intel/oneapi/setvars.sh
$ cmake -B build \
          -DCMAKE_BUILD_TYPE=Release \
          -DGGML_SYCL=ON \
          -DGGML_NATIVE=ON \
          -DGGML_LTO=ON \
          -DGGML_AVX2=ON \
          -DGGML_FMA=ON \
          -DGGML_F16C=ON \
          -DGGML_OPENMP=ON \
          -DGGML_SYCL_F16=ON \
          -DCMAKE_C_COMPILER=icx \
          -DCMAKE_CXX_COMPILER=icpx \
          -DGGML_SYCL_TARGET=INTEL

$ cmake --build build --config Release -j $(nproc) -v

ビルドしたOpenAIプロトコル互換のサーバを起動する。

$ cd build/bin
$ export SYCL_DEVICE_FILTER=level_zero:gpu
$ export SYCL_PI_LEVEL_ZERO_USE_IMMEDIATE_COMMANDLISTS=1
$ export ZES_ENABLE_SYSMAN=1
$ export GGML_SYCL_ENABLE_FLASH_ATTN=1

$ ./llama-server -m ~/AI/models/Qwen3.5-9B-Q4_K_M.gguf \
        --host 192.168.0.3 \
        --ctx-size 8192 \
        --threads 8 \
        --n-gpu-layers 99 \
        --temp 0.7 \
        --top-p 0.8 \
        --top-k 20 \
        --min-p 0.00 \
        --presence-penalty 0.6 \
        --repeat-penalty 1.0 \
        --chat-template-kwargs '{"enable-thinking": false}' \
        --reasoning-budget 0