考古学者のためのOpenAI APIを利用した議事録作成

OpenAIを利用した議事録作成は数多く紹介されていますが、最低限のAPIを利用した議事録作成方法を紹介します。Python環境はインストールされている前提です。

# 手順

1. 必要なパッケージをpipでインストールする
2. whisperを利用して音声を文字起こしする（API不要）
2. 文字起こしテキストのトークン数を計測する（API不要）
2. テキストを分割する（API不要）
2. 文章校正を行う（API利用）

# 必要なパッケージをインストールする

文字起こしを行うwhisperをインストールします。ffmpegも必要になるので、インストールしていない場合はインストールしてください。

```shell
# ffmgeg必要
sudo apt install ffmpeg


# whisperインストール
pip install git+https://github.com/openai/whisper.git

# tiktokenインストール
pip install tiktoken

# janemeインストール
pip install -qq janome
```

# whisperで文字起こし

OpenAIのGitHubリポジトリからダウンロードしてローカルで使用します。

モデルサイズは複数から選択できます。最大のlargeモデルだと3時間弱の会議で5〜6時間（11th Gen Intel® Core™ i7-1165G7 @ 2.80GHz × 8）というところでしょうか？largeモデルを読み込むためにはメモリが10GB以上必要ですが、可能な限りlargeモデルの使用をおすすめします。

```python
import whisper
model = whisper.load_model('large') # 最大のモデルを使用
result = model.transcribe('audioFile.m4a') # 読み込む音声ファイルを指定
with open("audioFile.txt", "w") as f: # 出力するテキストファイルを指定
    print(result['text'], file=f)

# tiny：最速。精度低い。
# base：tinyよりも高精度だが、よほど良い音源でなければ使えない。
# small：これがデフォルトモデルらしい。性能的には不満。
# medium：ようやく使えるレベル。
# large：最大モデルで、処理時間はめっちゃかかるが、背に腹は代えられない。おすすめ。

```

音源さえきれいにとれていれば、こんな感じでまあまあ良い感じの文字起こしテキストが出力されます。これをもう一度ChatGPTなどで処理して句読点などを付与してもよいのですが、ひたすらコピペを繰り返すのでかなりの手間になります。ちなみに、音源は史跡整備検討委員会をイメージしたダミー音源です（サクラを切るか残すかの判断について説明している、という想定）。

> 当面の間は今の状態を維持して桜もいずれ樹齢で老齢化していきますのでその時に危険木なり地消木として伐採するというようなことになるのかなと新たな処方箋を作ることができるようになっていますのでその後は今の状態を維持するという形で対応したらどうかというご意見をいただいております


# 文字起こしテキストのトークン数を計測する

ここからはほぼ、以下の記事の内容そのままです。
[Whisperで文字起こしをした文章をChatGPTでいい感じにする](https://zenn.dev/karaage0703/articles/6b81561d245968)

OpenAI APIは最大入出力トークン数が決められています。たとえば、GPT4-oでは入力128,000トークン、出力16,384トークンが上限です。

- Context window 128,000 tokens
- Max output tokens 16,384 tokens

```python
import tiktoken
from tqdm import tqdm
f = open('240925_0858.txt', 'r')
transcription_text = f.read()
encoding = tiktoken.get_encoding("cl100k_base")
count = len(encoding.encode(transcription_text))
print(count)
39839 # トークン数
```

トークン数は39,839となりました。出力トークンの上限が16,384トークンですから、このテキストを一発で変換することは難しいことがわかります。適切なサイズのトークン数となるように、テキストの分割を行います。

# テキストを分割する

以下のコードでは最大3,000トークンとなるように、テキストを分割します。形態素を抽出して、文章の途中で分割されないようにしているらしいです。最大トークンは10,000トークンぐらいでも大丈夫だと思いますが、念のため3000に刻んでいます。

```python
from janome.tokenizer import Tokenizer

f = open('240924Comitte/240925_0858.txt', 'r')
transcription_text = f.read()

def split_text_into_chunks(text, max_tokens=3000):  # 最大トークンを3000で分割
	tokenizer = Tokenizer()
	tokens = list(tokenizer.tokenize(text, wakati=True)) # wakati=True returns a list of words
	
	chunks = []
	for i in range(0, len(tokens), max_tokens):
		chunk = tokens[i:i+max_tokens]
		chunks.append(''.join(chunk))

	return chunks

chunks = split_text_into_chunks(transcription_text) # 分割したテキストのリスト
```

# 文章校正を行う

## APIキーとプロンプト

OpenAIのAPIキーの取得方法はこちらを参考にしました。
[OpenAIのAPIキー取得方法](https://qiita.com/kurata04/items/a10bdc44cc0d1e62dad3)
私は10ドル課金しました。

```python
# APIキーとモデルの設定
openai.api_key = '自分のAPIキー'
model_name = 'gpt-4o-mini' # 今回は安くて高性能なgpt-4o-miniを使用

# プロンプト
order = """次の文章の誤記訂正、句読点の追加をしてください。極力元の文章は変更しないようにしてください。


"""
```

## 文章校正

いよいよ文章校正です。分割したテキストのリストにfor文でプロンプトをあてていきます。

```python
# 文章校正
from time import sleep
from tqdm import tqdm
import openai

fix_text = ''

for chunk in tqdm(chunks):
    prompt = order + chunk
    print(f"Sending prompt: {prompt}")

    retry_interval = 2
    max_trial_numb = 4
    response = None

    for i in range(max_trial_numb):
        try:
            # ChatCompletionの新しいAPI呼び出し形式
            response = openai.chat.completions.create(
                model=model_name,
                messages=[
                    {"role": "user", "content": prompt},  # プロンプトはメッセージとして送信
                ],
            )
            break  # 成功した場合、ループを抜ける
        except Exception as e:
            print(f"Error during request: {e}")
            if i + 1 == max_trial_numb:
                print('Over max trial number')
                break
            sleep(retry_interval)
            print(f'Retry number: {i + 1}')
            continue

    if response: 
        # 新しいAPIのレスポンスからのメッセージ取得
        print(response.choices[0].message.content.strip())
        fix_text += response.choices[0].message.content.strip()
    else:
        print("Failed to get a response.")

# ファイル保存
save_fixed_file_name = 'transcription_fix.txt'

with open(save_fixed_file_name, 'w', encoding='utf_8') as f:
	f.write(fix_text)
```

## 出力結果

元の文字起こしテキストのできが良いので小幅な修正ですが句読点はきちんと設定されています。また、全体は4万文字を超える長文のテキストなので、適宜段落が設定されたことで非常に読みやすくなっています。

文字起こしテキスト
> 当面の間は今の状態を維持して桜もいずれ樹齢で老齢化していきますのでその時に危険木なり地消木として伐採するというようなことになるのかなと新たな処方箋を作ることができるようになっていますのでその後は今の状態を維持するという形で対応したらどうかというご意見をいただいております

gpt-4o-miniによる文章改善
>当面の間は今の状態を維持して、桜もいずれ樹齢で老齢化していきますので、その時に危険木なり地消木として伐採するというようなことになるのかなと、新たな処方箋を作ることができるようになっています。その後は今の状態を維持するという形で対応したらどうかというご意見をいただいております。

# 気になるお値段

39,839トークンの文章校正のお値段はこちら。0.03ドル、日本円換算で4.5円ぐらいでしょうか。これなら、3時間級の議事録を毎日校正しても1年もちますね。

![billing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60438/bc2bc4ba-a3ce-9f6a-eb48-e0ba887de56f.png)


# GPT4-oも試してみた

GPT4-oは「最も先進的なモデル」だそうで、お金は10倍ぐらいかかります。校正結果はあまり変わらなかったので、議事録の校正ならGPT-4o-miniで十分かな、という感じです。

![billing_gpt4o.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60438/71a45c63-c003-fe2e-936a-8e146babc8b8.png)