- 本記事は 虎の穴ラボ Advent Calendar 2023 21日目の記事です。
- 前回はデザインTさんによる「虎の穴ラボのロゴとサイトをリニューアルしたよ!」でした。
- 次回はT.Hさんによる「【VOICEVOX × RVC】ずんだもんに自分の声で喋ってもらった 」です。ご期待ください!
はじめに
こんにちは!虎の穴ラボのnagaです。
今回は、Advent Calendar 7日目にH.Hさんが投稿した「Whisperを使用した音声ファイルの文字起こしの検証をしてみた」に関連して、Whisper Micというライブラリをご紹介します。 活用例として、ライブ配信者のリスナーをOpenAIに演じてもらい、話した内容に対してコメントを返す、というプログラムを作成しました。
Whisper Micとは
Whisper Micは、マイクからの入力音声をリアルタイムに文字起こしするライブラリです。このライブラリは、SpeechRecognitionという録音が可能なライブラリを使用し、録音された音声データをWhisperで文字に変換しています。 github.com
検証環境
- M2 MacBookPro Ventura 13.6.2
- Python 3.9.6
- Whisper Mic 1.3.1
- OpenAI Python API library 1.3.5
Whisper Mic導入手順
Whisper Micを使用して、日本語の文字起こしを行うまでの手順は以下の通りです。
1) pipでWhisper Micをインストールします。
pip install whisper-mic
2) 次に、whisper_mic.pyの__transcribe()
という文字起こしをするメソッドを修正します。この対応により、日本語での文字起こしが可能になります。
修正内容は以下の通り、Whisperのモデルに文字起こしを指示するself.audio_model.transcibe()
にlanguageの引数を追加し、日本語で文字起こしするようにします。
def __transcribe(self,data=None, realtime: bool = False) -> None: if data is None: audio_data = self.__get_all_audio() else: audio_data = data audio_data = self.__preprocess(audio_data) if self.english: result = self.audio_model.transcribe(audio_data,language='english') else: # result = self.audio_model.transcribe(audio_data) result = self.audio_model.transcribe(audio_data,language="japanese") # 以下略・・・
文字起こしの動作確認
ここまでで日本語音声の文字起こしができるようになりました。 今回は、下記のコードでテストしてみます。
from whisper_mic import WhisperMic mic = WhisperMic(model="medium") mic.listen_loop()
原稿内容を話してみた様子がこちらです。
みなさん初めましてnagaです。本日はブログを見ていただきありがとうございます。 これはWhisper Micのテスト用に書き起こした原稿です。 好きな食べ物はハンバーグです。 ばいばーい
文字起こしされるまでにタイムラグが数秒発生しますが、話した内容はおおむね正しく文字起こしされているように感じます。
誤出力への対策
文字起こしの動作確認をしている時に、話していないのに「ご視聴ありがとうございました!」や「Thanks for watching!」のようなテキストがWhisperによって出力されることがありました。 これはハルシネーション(Hallucination)と呼ばれる現象で、AIがまるで幻覚・幻聴を見聞きしているかのように、意図しない回答を出力することがあるそうです。
ハルシネーションを完全に防ぐことは難しいため、今回はこの現象で出力される可能性があるテキストを定義しておき、後続の処理をスキップする手法を取ります。
以下のように、whisper_mic.pyのlisten_loop()
メソッドを修正しました。
# ハルシネーションで出力される可能性があるテキストを定義 hallucinationTexts = [ "ご視聴ありがとうございました", "Thanks for watching!", ] def listen_loop(self, dictate: bool = False, phrase_time_limit=None) -> None: self.recorder.listen_in_background(self.source, self.__record_load, phrase_time_limit=phrase_time_limit) self.logger.info("Listening...") threading.Thread(target=self.__transcribe_forever, daemon=True).start() while True: result = self.result_queue.get() # ハルシネーションで回答される可能性があるテキストと一致したら処理をスキップする if result in self.hallucinationTexts: continue self.logger.info(f"you said: {result}") # 以下略・・・
活用例:配信者気分を味わってみる
最後にWhisper MicとOpenAI Python API libraryを使用して、自身を配信者に見立てAIリスナーとお話ししてみます。
事前準備
1) pipを使用してライブラリをインストールします。
pip install openai
2) OpenAI Developer Platform から API のキーとOrganizationのキーを取得します。
実装
まず、OpenAI APIにリクエストを送るクラスを作成します。この時に、OpenAIにどんなリスナーを演じさせるかを定義しておきます。
使う側は、postMessage()
を呼び出すことで、結果を標準出力に表示できるようにしました。
import copy import json import os from openai import OpenAI class AIListener: def __init__(self) -> None: self.client = OpenAI( # 事前準備で取得したAPIのキーとOrganizationのキーを設定(環境変数から取得) api_key=os.environ.get("OPENAI_API_KEY"), organization=os.environ.get("OPENAI_ORGANIZATION")) # プロンプトの設定 self.initialPrompt = [ {"role": "system", "content": """charactor: あなたは、targetで定義するYoutuberのリスナーを3人分演じてください。 Youtuberが一人での雑談が苦じゃなくなるようなコメントを返すのがあなたたちの役割です。 あなたたちの特徴は、以下になります。 - 30代男性(Aさん): - 聡明で洞察力がある。 - 仕事終わりにリラックスしてお酒を飲みながら配信を楽しんでいる。 - 敬語を使って丁寧にコメントする。 - 10代男性(Bさん): - 若々しくユーモアがあり、積極的な姿勢をもつ高校生。 - 開放的で自信に満ち溢れている。 - 友達のような感覚で気軽にコメントする。 - 10代女性(Cさん): - 高校生でありながらYoutuberに情熱を傾ける熱心なファン。 - 自然体で率直な意見をコメントする。 また、下記ルールを守ったコメントをしてください。 - とても短いコメントをする - 基本的には、下記の例のように1単語でコメントをする - こんにちは - 美味しそう - かわいい - そう - うんうん - ネガティブなコメントはしない - 議論になるようなコメントはしない - targetが入力した内容以外に言及しない - 3人ともがコメントを返す必要はない - 1人は必ずコメントを返す - コメントに悩んだら「うんうん」と返す target: あなたたちが見ているYoutuberの特徴は以下になります。 - 男性 - 30代 - 若者向けの親しみやすい内容 - 食べることを楽しむライフスタイル - 自宅での活動を好む - ゲームプレイのスキルが高い format: 以下のjson形式のレスポンスを返してください。 { comments: [ { "name": コメントしたリスナー名 "comment": something to comment } ] } """}, ] def postMessage(self, message): # チャットプロンプトにメッセージを追加 messages = copy.deepcopy(self.initialPrompt) messages.append({"role": "user", "content": message}) # リクエストを送信 response = self.client.chat.completions.create( model="gpt-3.5-turbo", messages=messages, ) # レスポンスをJson形式でパースする comments = json.loads(response.choices[0].message.content) # コメントと名前を表示する for comment in comments["comments"]: print(f'{comment["comment"]} @{comment["name"]}')
次に、whisper_mic.pyのlisten_loop()
という無限に文字起こしを行うメソッドで、postMessage()
を呼び出せるように修正します。
def listen_loop(self, dictate: bool = False, phrase_time_limit=None) -> None: self.recorder.listen_in_background(self.source, self.__record_load, phrase_time_limit=phrase_time_limit) self.logger.info("Listening...") threading.Thread(target=self.__transcribe_forever, daemon=True).start() # 上で紹介したクラスのインスタンスを作成 aiListener = AIListener() while True: result = self.result_queue.get() # ハルシネーションで回答される可能性がある文字列を除外 if result in self.hallucinationTexts: continue self.logger.info(f"you said: {result}") # 文字起こしした内容をOpenAI APIにPOST aiListener.postMessage(result)
動作確認
下記原稿を喋った際の様子がこちらになります。
みなさん初めましてnagaです。本日はブログを見ていただきありがとうございます。 好きな食べ物はハンバーグです。 ばいばーい
やはり多少のタイムラグはあります。ですが、実際の配信もコメントが配信者に届くまでにタイムラグがあるので、ある意味リアルになったかもしれません。
まとめ
今回はWhisper Micを使用して、マイクに話した内容の文字起こしを試しました。さらに、活用例としてOpenAI Python API libraryを使用してOpenAIと連携してみました。
ハルシネーションに対する対策例を挙げましたが、ブログに記載したテキストと異なるテキストが出力されることもあるため、環境に合わせてカスタマイズする必要があります。
単純に音声ファイルから文字起こしを行いたい場合は、Whisperをそのまま利用できます。しかし、リアルタイムで話した内容を文字起こししたい場合は、Whisper Micを試してみてください。
採用情報
虎の穴ラボでは一緒に働く仲間を募集中です!
この記事を読んで、興味を持っていただけた方はぜひ弊社の採用情報をご覧ください。
c
Kotlin / Next.js / TypeScript /Tailwind CSS 等、モダン環境でのシステム開発に携わることができます。
toranoana-lab.co.jp