高性能なGPUを持っていなくても、colaboratoryを利用することで、音声データから自動的に議事録を作成することが可能です。
Pyannote.audio、Whisper等のモジュール、ChatGPT、Notion等のAPIを使って、Colaboratory上で音声データからの議事録を作成して、保存できるようなコードを作りました。
以下、colaboratoryのリンクです。
Google Colab
※不要な機能は適宜削除して利用してください
主要な機能について
pyannote.audio | 音声データを解析し、話している人を認識、区別する |
Whisper | 音声データを解析し、文字として出力する |
ChatGPT | 人工知能(AI)を使ったチャットサービスであり、色々な事ができる |
Notion | ドキュメント作成や社内Wiki、タスク管理などのさまざまな機能を備えたアプリ |
なお、ChatGPT及びNotionを利用するためには、それぞれ公式ホームページからAPIキーを取得する必要があります。(取得方法については、説明を省略します)
使う前の準備
音声データを保存
・GoogleDriveに、録音データ(.wav)を”yyyymmdd”の形式でアップロードする。
(例 今日の日付が2023年5月28日の場合、”20230528.wav”として保存する
APIへのアクセス情報を入力
・上記colaboratoryのリンクを開き、openAIの組織情報、APIキーを入力する
・notionのアクセストークン、投稿したいデータベースIDを入力する
# openAIのアクセス情報を定義
openai.organization = "ここにopenaiの組織情報を入力"
openai.api_key = "ここにopenaiのAPIキーを入力"
# notionへのアクセス情報を定義
NOTION_ACCESS_TOKEN = "ここにNotionのアクセストークンを入力"
NOTION_DATABASE_ID = "ここにNotionのデータベースIDを入力"
GPUを使用する設定に変更
最初に「編集」→「ノートブックの設定」→「NoneをGPUに変更」→「保存」
コードを順番に実行
・一番上のコードを実行し、「Googleドライブに接続」→「許可」を選択
・二番目のコードを実行し、「許可」を選択
・「ランタイム」→「以降のセルを実行」を選択
※もしくは「ctrl+F10」を押す
これで議事録が作成される。
コードの説明
試しに実行した場合の動きを確認してみる
pyannote.audio
pipインストール
!pip install datetime
!pip install sys
!pip install io
# Install pyannote.audio packages
# for speechbrain
!pip install -qq torch==1.11.0 torchvision==0.12.0 torchaudio==0.11.0 torchtext==0.12.0
!pip install -qq speechbrain==0.5.12
# pyannote.audio
!pip install -qq pyannote.audio
# for visualization purposes
!pip install -qq ipython==7.34.0
実行
from pyannote.audio import Pipeline
import sys
import datetime
from pytz import timezone
# 音声ファイルはGoogleDriveのルート(MyDrive内)に"yyyymmdd"の形式で保存する
now = datetime.datetime.now()
now = now.astimezone(timezone('Asia/Tokyo')) #colaboは世界標準時刻のため、タイムゾーンを東京に変更
daytime = now.strftime("%Y-%m-%d %H:%M:%S")
base_path = r"/content/drive/MyDrive/"
ymd = now.strftime("%Y%m%d") + ".wav"
filepath = base_path + ymd
print("filepath: " + filepath)
# 音声データ取得部
# Pyannote.audioで話者識別の実施
pipeline = Pipeline.from_pretrained("pyannote/speaker-diarization@2.1", use_auth_token="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")
diarization = pipeline(filepath) #(filepath, num_speakers=xx)で話者数の設定が可能
speaker_list = [
[turn.start, turn.end, speaker, ""]
for turn, _, speaker in diarization.itertracks(yield_label=True)
]
print(speaker_list)
・GoogleDriveのルートに保存した音声データを解析し、誰がどの時間に発言したのかをlistにしている。
・pipeline(filepath)の部分はpipeline(filepath, num_speakers=2)に変更すると、話している人数を指定して解析することが可能
出力結果
[[0.4978125, 1.9490625000000001, ‘SPEAKER_01’, ”],
[6.184687500000001, 6.707812500000001, ‘SPEAKER_01’, ”],
[8.8509375, 11.922187500000003, ‘SPEAKER_01’, ”],
[9.559687500000003, 10.099687500000002, ‘SPEAKER_00’, ”]
・・・]
[[0.4978125, 1.9490625000000001, ‘SPEAKER_01’, ”],
[6.184687500000001, 6.707812500000001, ‘SPEAKER_01’, ”],
[8.8509375, 11.922187500000003, ‘SPEAKER_01’, ”],
[9.559687500000003, 10.099687500000002, ‘SPEAKER_00’, ”]
・・・]
Whisper
pipインストール部分
# Install whisper packages
!pip install git+https://github.com/openai/whisper.git
実行部分
import whisper
# Whisperで音声認識の実施
model = whisper.load_model("large")
print("filepath: " + filepath)
result = model.transcribe(filepath)
for i in range(len(result["segments"])):
talk_data = result["segments"][i]
print(
str(i) + " start={:.1f}s stop={:.1f}s {}".format(
talk_data["start"], talk_data["end"], talk_data["text"]
)
)
・GoogleDriveのルートに保存した音声データを解析し、台詞を時間ごとに整理している。
・resultは辞書型であり、’text’、’segments’、’language’がそれぞれ格納されている。
・segments(talk_data)には、下記のようなデータが格納されている。
talk_dataに入っているデータ(list型の中に辞書型が格納されている)
[{‘id’: 0, ‘seek’: 0, ‘start’: 0.0, ‘end’: 2.0, ‘text’: ‘今日のスーパーで何買う?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …},
{‘id’: 1, ‘seek’: 0, ‘start’: 6.0, ‘end’: 7.0, ‘text’: ‘何買う?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …},
{‘id’: 2, ‘seek’: 0, ‘start’: 9.0, ‘end’: 10.0, ‘text’: ‘なんで?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …}
・・・]
[{‘id’: 0, ‘seek’: 0, ‘start’: 0.0, ‘end’: 2.0, ‘text’: ‘今日のスーパーで何買う?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …},
{‘id’: 1, ‘seek’: 0, ‘start’: 6.0, ‘end’: 7.0, ‘text’: ‘何買う?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …},
{‘id’: 2, ‘seek’: 0, ‘start’: 9.0, ‘end’: 10.0, ‘text’: ‘なんで?’, ‘tokens’: […], ‘temperature’: 0.0, ‘avg_logprob’: 略, ‘compression_ratio’: 略, …}
・・・]
誰がどの発言をしたのかを組み合わせる
pyannote.audioとWhisperのデータを組み合わせて、台詞の発言者を区別する。
# Whisperの発話範囲から、Pyannote.audioの発話者を特定する関数
def speaker_selector(s, e, speaker_dict={}):
longest_duration = 0
longest_speaker = None
for speaker in speaker_list:
speaker_start = speaker[0]
speaker_end = speaker[1]
if s <= speaker_start <= e or s <= speaker_end <= e:
duration = min(speaker_end, e) - max(speaker_start, s)
elif speaker_start <= s and e <= speaker_end: duration = e - s else: continue if duration > longest_duration:
longest_duration = duration
longest_speaker = speaker[2]
elif duration == longest_duration:
longest_speaker = "unknown"
return longest_speaker
# 標準出力をキャプチャするために、新しいストリームを作成
captured_output = io.StringIO()
sys.stdout = captured_output
# speakerが紐づけられた音声の書き起こしをターミナルに出力
speaker_turn = 0
for i in range(len(result["segments"])):
talk_data = result["segments"][i]
speaker = speaker_selector(talk_data["start"], talk_data["end"])
print(speaker, talk_data["text"])
# 標準出力を元に戻す
sys.stdout = sys.__stdout__
# キャプチャされた出力をテキストとして格納
voice_text = captured_output.getvalue()
print("voice_text: " + voice_text)
出力結果
SPEAKER_01 今日のスーパーで何買うの?
SPEAKER_01 何買うの?
SPEAKER_01 なんで?
SPEAKER_01 来週の夜ご飯
SPEAKER_00 鶏肉にしようかなって思ってるけど
・・・
SPEAKER_01 今日のスーパーで何買うの?
SPEAKER_01 何買うの?
SPEAKER_01 なんで?
SPEAKER_01 来週の夜ご飯
SPEAKER_00 鶏肉にしようかなって思ってるけど
・・・
・「なんで?」の発言者はSPEAKER_00である。あまり精度が高いとは言えない。ちなみに、speaker_selector()については、ChatGPTに以下の指示をして作成してもらった。
ChatGPT
pipインストール部分
!pip install openai
実行部分
import openai
# openAIのアクセス情報を定義
openai.organization = "ここにopenaiの組織情報を入力"
openai.api_key = "ここにopenaiのAPIキーを入力"
# ChatGPTcにテキストを渡してサマリーを作成
summary = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "system",
"content": "Create a summary from the transcript of the discussion.",
},
{
"role": "user",
"content": "We discussed the meeting. The transcript is written in Japanese.",
},
{
"role": "assistant",
"content": "Please give us the text of the transcript of the discussion.",
},
{"role": "user", "content": voice_text},
{
"role": "assistant",
"content": "The transcriptions may contain typographical errors and should be converted appropriately.",
},
{
"role": "user",
"content": "The [Decision] and [Notes] and [Todo] sections should be itemized.",
},
{"role": "system", "content": "以上を踏まえて、日本語でサマリーを作成します。"},
],
)
print("summaryは右: " + str(summary))
発言リストを解析し、内容を要約してもらう。
※一度に送付できる文字数(トークン数)に限度があり、大体4000文字を超えた文章を要約しようとするとエラーとなってしまう。
Notion
実行部分
import requests
# notionへのアクセス情報を定義
NOTION_ACCESS_TOKEN = "ここにNotionのアクセストークンを入力"
NOTION_DATABASE_ID = "ここにNotionのデータベースIDを入力"
url = "https://api.notion.com/v1/pages"
# notionに投稿
notion = f"{summary['choices'][0]['message']['content']}"
headers = {
"accept": "application/json",
"Notion-Version": "2022-06-28",
"Authorization": f"Bearer {NOTION_ACCESS_TOKEN}",
}
json_data = {
"parent": {"type": "database_id", "database_id": NOTION_DATABASE_ID},
# プロパティ
"properties": {
# タイトル
"title": {"title": [{"text": {"content": daytime}}]},
},
# 本文
"children": [
# ブロック
{
"object": "block",
"heading_2": {"rich_text": [{"text": {"content": notion}}]},
},
{
"object": "block",
"paragraph": {
"rich_text": [
{
"text": {
"content": voice_text,
},
}
],
},
},
],
}
response = requests.post(url, json=json_data, headers=headers)
print("response.textは右: " + str(response.text))
・ChatGPTが要約したテキストを、Notionへ投稿する。
※送付できるデータ量に上限がある。
完成した投稿がこちら
テキストファイルとしてColaboratoryからGoogleDriveへデータを送付する
実行部分
#GoogleDriveへファイルを送付するため
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from google.colab import auth
from oauth2client.client import GoogleCredentials
auth.authenticate_user()
gauth = GoogleAuth()
gauth.credentials = GoogleCredentials.get_application_default()
drive = GoogleDrive(gauth)
# ファイルに保存するパスとファイル名
output_file_path = now.strftime("%Y%m%d") + ".txt"
# ファイルに返事を保存
with open(output_file_path, "w", encoding="utf-8") as output_file:
output_file.write(str(voice_text))
# ファイルへの保存が完了したことを表示
print("Chat response saved to", output_file_path)
#GoogleDriveへダウンロード
upload_file = drive.CreateFile()
upload_file.SetContentFile(output_file_path)
upload_file.Upload()
・Notionへデータを送付しない場合は、発言リストをtxtデータとしてGoogleDriveへ送付する。
参考にしたサイト
音声認識Whisperと話者識別Pyannote.audioで議事録自動作成
Pythonの音声認識ライブラリWhisperと話者識別ライブラリPyannote.audioで面倒な議事録の自動作成をしてみます。WhisperはOpenAIからMITライセンスで提供されています。Pyannote.audioもMITライセンスで提供されています。いずれも適切なライセンス表示下で改変、配布、商用利用が...
PythonでプロットしたグラフをGoogle ColaboratoryからGoogle driveにアップロードする方法
コメント