見出し画像

⑦OpenAI Whisperを利用した文字起こし>字幕作成コード。OpenAI API 1.0以降対応版。

openaiのAPI挙動が変わってしまい、自分用のツールで困っていたので書き直しました。まずはバージョン確認していきます。

pip show openai
openai==1.3.7で動かしています

上記のように記述がだいぶ変わってしまうのでバージョンを上げない選択肢もあると思います。その場合venvなどでご対応ください。


(2023/12/11編集)
バージョンを以前のものに戻したい場合は以下

pip uninstall openai

and then reinstall targeted to the pre-1.x release with:

pip install openai==0.28.1


前回作ったツールでおむすびころりんの動画をダウンロードしてきました。


著作権フリーなものを選択

今回のコード


import gradio as gr
import os
from pydub import AudioSegment
from openai import OpenAI

# OpenAIのクライアントを初期化
client = OpenAI(api_key=os.environ['OPENAI_API_KEY'])

def clear_tmp_folder():
    """'tmp' フォルダの中身をクリアする"""
    tmp_folder = "tmp"
    os.makedirs(tmp_folder, exist_ok=True)
    for file_name in os.listdir(tmp_folder):
        file_path = os.path.join(tmp_folder, file_name)
        if os.path.isfile(file_path):
            os.unlink(file_path)

def get_duration(inputs, language):
    """音声ファイルを分割し、各チャンクを文字起こししてSRTファイルとトランスクリプトを生成する"""
    audio = AudioSegment.from_file(inputs, format="m4a")
    length = len(audio)
    chunk_length = 1000000  # 1,000,000ミリ秒ごとに分割
    overlap_length = 10000  # 10,000ミリ秒のオーバーラップ
    chunks = []

    # チャンクを生成する際にオーバーラップを考慮
    for i in range(0, length, chunk_length - overlap_length):
        end = min(i + chunk_length, length)
        chunk = audio[i:end]
        chunks.append((chunk, i, end))  # チャンクと実際の開始/終了時間を保存

    all_segments = []
    transcript_text = ""

    for i, (chunk, start, end) in enumerate(chunks, start=1):
        output_file = f"tmp/split{i}.mp3"
        chunk.export(output_file, format="mp3")
        with open(output_file, "rb") as audio_file:
            transcript = client.audio.transcriptions.create(
                file=audio_file, model="whisper-1", response_format="verbose_json", language=language)
            for segment in transcript.segments:
                segment['start'] += start / 1000  # チャンクの実際の開始時間を加算
                segment['end'] += start / 1000  # チャンクの実際の終了時間を加算
                all_segments.append(segment)
            transcript_text += transcript.text + "\n"

    srt_content = convert_to_srt(all_segments)
    save_srt_file(srt_content, "tmp/output.srt")
    save_srt_file(transcript_text, "tmp/full_transcript.txt")

    return srt_content, transcript_text

def convert_to_srt(segments):
    """セグメントをSRTフォーマットに変換する"""
    def format_time(time_in_seconds):
        """秒をHH:MM:SS,mmmフォーマットに変換する"""
        hours, remainder = divmod(time_in_seconds, 3600)
        minutes, seconds = divmod(remainder, 60)
        milliseconds = int((seconds - int(seconds)) * 1000)
        return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02},{milliseconds:03}"

    return "\n".join([
        f"{index + 1}\n{format_time(segment['start'])} --> {format_time(segment['end'])}\n{segment['text']}\n"
        for index, segment in enumerate(segments)
    ])

def save_srt_file(srt_content, file_name):
    """SRTコンテンツをファイルに保存する"""
    with open(file_name, "w", encoding="utf-8") as file:
        file.write(srt_content)

clear_tmp_folder()

# Gradioインターフェイスの設定
iface = gr.Interface(
    fn=get_duration,
    inputs=[gr.Audio(type="filepath", label="会議ファイルをアップロード"), gr.Dropdown(choices=["en", "ja"], label="言語選択")],
    outputs=["text", "text"],
    title="Video to srt",
    description="Upload an audio file to Generate."
)

iface.launch(inbrowser=True)


動作画面


コード直下、
テンポラリフォルダにsrtファイルが生成されます


字幕ファイルはこのようにリネームして、
VLCプレーヤなどで再生すると字幕がつきます


字幕


言語セレクター
 transcript = client.audio.transcriptions.create(
                file=audio_file, model="whisper-1", response_format="verbose_json", language=language)

client.audio.transcriptions.createの中にlanguageを入力できるので付けてみました。基本的には入力言語の設定ですので以下のようになってしまいますが、短い動画とかならば何故か英語変換もできる感じでしたので付けたままにしてあります。
client.audio.translations.create()に書き換えるとおそらくすべての言語を英語に翻訳して出力すると思います。


一部英訳字幕を生成後、日本語の発声をtranscript

文字起こしできる言語は以下のようになっています。

https://platform.openai.com/docs/guides/speech-to-text/quickstart

基礎となるモデルは 98 の言語でトレーニングされましたが、音声テキスト変換モデルの精度の業界標準ベンチマークである単語誤り率(WER)が 50% 未満を超えた言語のみをリストします。モデルは上記にリストされていない言語の結果を返しますが、品質は低くなります」


コスト

安いと思います