Whisper API で音声を文字起こし【Python】

2024年2月12日

業務中、議事録を作成する必要が生じるときがあります。

基本的には録音しておいた音声データで確認しながら議事録を作成していくのですが、音声データだけでは会議中の発言を確認するのも手間が掛かります。

そこで、音声データを一括で文字起こしできると内容確認が捗るため、OpenAI社が提供している音声文字起こし用のサービス Whisper API で一括文字起こしするプログラムを作成してみます。

Whisper API の仕様確認

まずは Whisper API の仕様を確認する必要があります。

公式ページを見ると、対応しているフォーマットは mp3, mp4, mpeg, mpga, m4a, wav, webm に対応しており、一度に読み込める最大ファイルサイズは 25MB、料金は $0.006/分 (約1円/分)となっています。(2023年7月時点)

API は時間あたりの料金となっており、全体のファイルサイズは気にする必要は無さそうなので、今回は音声元データをwavファイルを前提とします。

セキュリティ面に関して明言されているものは見当たりませんでしたが、恐らくはChatGPTと同様、API利用でやりとりしたデータはモデル学習には用いず削除、というスキームと思います。(オープンソース版のWhisperもありますが、そちらは提供データをモデル学習に用いている可能性あり)

今回は、単体で25MBを超えるwav形式の音声ファイルを文字起こしする前提とします。

プログラム本文

プログラムは以下の2部構成としています。

  • API制限の25MB以下のファイルサイズになるようにファイルを分割
  • Whisper API へデータの受け渡し

まず、プログラムに必要なライブラリとAPI Keyを読み込みます。API Key は事前に環境変数として設定しておきます。

import wave
import struct
import math
import os
import shutil
import numpy as np
from openai import OpenAI

# API key を設定
client = OpenAI(
        api_key=os.environ.get("OPENAI_API_KEY"),
)

前者のwavファイル分割部分を以下で作成します。

ファイルサイズを25MB以下とするには色々な方法があると思いますが、今回は1ファイルが3分以下になるよう機械的に分割して、それを順次APIへ渡していく形とします。

# API制限25MB用に加工準備
# ===================================================================

# 繰り返し作業用に事前に削除
if os.path.exists("./wave_split"):
    shutil.rmtree("./wave_split")

# 読み込むwaveファイル名
f_name = input("ファイル名を入力(wavのみ。拡張子不要): ")

# 切り取り時間[sec]
cut_time = 3 * 60

# 保存するフォルダの作成
file = os.path.exists("wave_split")
if file == False:
    os.mkdir("wave_split")


def wav_cut(filename, time):

    # ファイルを読み出し
    wavf = filename + '.wav'
    wr = wave.open(wavf, 'r')

    # waveファイルが持つ性質を取得
    ch = wr.getnchannels()           # オーディオチャンネル数(モノラルなら 1 、ステレオなら 2 )を返します。
    width = wr.getsampwidth()        # サンプルサイズをバイト数で返します。
    fr = wr.getframerate()           # サンプリングレートを返します。
    fn = wr.getnframes()             # オーディオフレーム数を返します。
    total_time = 1.0 * fn / fr       # 曲の長さ
    integer = math.floor(total_time)  # 曲の長さから小数点以下を切り捨てて整数の秒数に修正
    t = int(time)                    # 切り分けする秒数[sec]
    frames = int(ch * fr * t)        # 切り分けした秒数におけるオーディオフレーム数
    num_cut = int(integer//t + 1)    # 切り分け出力する数。末尾のオーディオフレームを追加するために+1としている

    # 確認用
    print("Channel: ", ch)
    print("Sample width: ", width)
    print("Frame Rate: ", fr)
    print("Frame num: ", fn)
    print("Params: ", wr.getparams())
    print("Total time: ", total_time)
    print("Total time(integer)", integer)
    print("Time: ", t)
    print("Frames: ", frames)
    print("Number of cut: ", num_cut)

    # waveの実データを取得し、数値化
    data = wr.readframes(wr.getnframes())
    wr.close()
    X = np.frombuffer(data, dtype=np.int16)
    print(X)

    for i in range(num_cut):
        print("No.", i+1)
        # 出力データを生成
        outf = 'wave_split/' + str(i+1) + '.wav'
        start_cut = i*frames
        end_cut = i*frames + frames
        print("Start Cut", start_cut)
        print("End Cut", end_cut)
        Y = X[start_cut:end_cut]
        outd = struct.pack("h" * len(Y), *Y)

        # 書き出し
        ww = wave.open(outf, 'w')
        ww.setnchannels(ch)
        ww.setsampwidth(width)
        ww.setframerate(fr)
        ww.writeframes(outd)
        ww.close()


# 実行
wav_cut(f_name, cut_time)

次に、分割したwavをAPIへ渡していく部分を書きます。分割したファイルから文字起こししたテキストデータは、transcript_from_ファイル名.txt へ集約して書き込みしていく形にします。

# Whisper API へデータの受け渡し
# ===================================================================

# 保存するフォルダの作成
file = os.path.exists("transcript_output")
if file == False:
    os.mkdir("transcript_output")

# 読み込む音声ファイルを取得
read_list = os.listdir("./wave_split")
file_list = list(range(1, len(read_list)+1))

# Whisper APIで文字起こししてテキストファイルへ書き込み
with open(f"./transcript_output/transcript_from_{f_name}.txt", mode="w", encoding="utf-8_sig") as f:

    for file_path in file_list:
        print(file_path, "is reading...")
        audio_file = open(f"./wave_split/{file_path}.wav", "rb")
        transcript = client.audio.transcriptions.create(
            model = "whisper-1",
            file = audio_file,
            response_format="text"
        )
        print(transcript)

        # テキストファイルへ書き込み
        wave_time = str(file_path*3-3) + "min.~" + str(file_path*3) + "min."

        f.write(str(file_path)+".wav 内容")
        f.write("\n")
        f.write(wave_time)
        f.write("\n")
        f.write(str(transcript))
        f.write("\n\n")

以上、音声文字起こしをWhisper API を用いて行うプログラムの一例を載せてみました。

面倒な議事録作成などの一助になれば幸いです。


珈琲1杯でもおごるつもりでご支援して頂けたら大変喜びます😊

スポンサーリンク