【Pythonで音声ファイルの文字起こし】Jupyterlabで、自動翻訳まで実行させる方法
はじめに
会議などで録音した音声ファイルをPythonで自動的に文字起こしできないものか、と誰かが耳元でつぶやいたので調べてみたところ、既に先達がいて見事なコードを公開されていたのでそれを有り難く利用させてもらいつつ、ついでに英語翻訳も自動でさせてしまおう、ということでそのコードを公開してみる。
DockerにてPythonを動かす環境を構築するので、そのDocker ImageとContainerを作成するDockerfileとDocker Composeも公開する。
またPythonの記述はJupyterlabで行うが、その際参照元のPythonコードの1行だけ変更する必要があるので、それについても言及する。
ディレクトリ
desktop └python_transcriptionフォルダ ├Docker Composeファイル ├Dockerfile └workフォルダ └ipynbファイル(jupyterlabで作成・編集) └waveファイル(文字起こしする音声ファイル) (└outputフォルダ(コードを走らせると自動生成される))
拝借したコードの公開元
公開元は、以下のサイト。
会議議事録作成など、音声ファイルをPythonとGoogle Speech recognitionを使って、文字起こしにチャレンジします。 Google Speech recognitionは無料で使えるのは1~3分程...
このサイトの「プログラムソース」内「音声文字変換3.py」を元に、Jupyterlab用に一部コードを修正し、かつ英語翻訳用のライブラリとコードなどを追加していった。
各コードの完成版
Dockerfile完成版
FROM ubuntu:latest ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ python3 \ python3-pip \ libx11-dev \ python3-tk RUN pip3 install jupyterlab \ scipy \ numpy \ SpeechRecognition \ googletrans==4.0.0-rc1 \ deepl \ openpyxl \ pandas
Docker Compose完成版
version: "3.8" services: web: build: context: . dockerfile: Dockerfile environment: - DISPLAY=host.docker.internal:0.0 - DEEPL_AUTH_KEY=◆◆◆◆◆◆◆◆◆◆◆ # deepL APIに登録後取得した認証キーをここに追加 volumes: - ./work:/work ports: - 8000:8888 image: python_ts:latest container_name: python_transcription command: jupyter lab --ip=0.0.0.0 --allow-root --notebook-dir='/work' --LabApp.token=''
Pythonコード完成版
以下の各コードで追加修正した行には「# ●●●●●:今回追加分」または「# ●●●●●:今回修正分」とコメントしている
import wave import struct import os import math import tkinter.filedialog from pathlib import Path # 音声ファイル読込時のファイルパス選定用:今回追加分 # 以下は外部ライブラリ(要インストール:Dockerfileにてインストールするよう記述) from scipy import fromstring,int16 import numpy as np import speech_recognition as sr from googletrans import Translator # 翻訳用(google):今回追加分 import deepl # 翻訳用(deepL):今回追加分 import openpyxl # Excelファイルを生成するときに必要:今回追加分 import pandas as pd # filenameに読み込むファイル、timeにカットする間隔 def cut_wav(filename,time): # timeの単位は[sec] # ファイルを読み出し wavf = filename wr = wave.open(wavf, 'r') # waveファイルが持つ性質を取得 ch = wr.getnchannels() width = wr.getsampwidth() fr = wr.getframerate() fn = wr.getnframes() total_time = 1.0 * fn / fr integer = math.floor(total_time*100) # 小数点以下切り捨て t = int(time*100) # 秒数[sec] frames = int(ch * fr * t /100) num_cut = int(integer//t) # waveの実データを取得し、数値化 data = wr.readframes(wr.getnframes()) wr.close() X = np.frombuffer(data, dtype=int16) for i in range(num_cut + 1): # 出力データを生成 outf = out_dir + '/' + str(i) + '.wav' # 音声をカットした部分は少し巻き戻す;今回は巻き戻さないので以下3行コメントアウトする:今回修正分 #if i > 0: # start_cut = int(i*frames) - int(180000) #else: start_cut = int(i*frames) # 巻き戻し設定する場合はこの行をインデントすること:今回修正分 end_cut = int(i*frames + frames) # print(start_cut) # print(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() str_out = "" str_tr_out = ""# 翻訳用:今回追加分;翻訳不要の場合はコメントアウトする #list1 = [wavf,"",""] # 翻訳不要の場合はこちらを使用し、下記をコメントアウトする list1 = [wavf,"","","",""] # 翻訳用;上記に「,"",""」を追加:今回追加分 df_x = pd.DataFrame([list1]) #df_x.columns = ['No', '音声ファイル', '変換結果'] # 翻訳不要の場合はこちらを使用し、下記をコメントアウトする df_x.columns = ['No','音声ファイル','変換結果','ggl翻訳','dpl翻訳'] # 翻訳用;上記に「,'ggl翻訳','dpl翻訳'」を追加:今回追加分 for ii in range(num_cut + 1): outf = out_dir + '/' + str(ii) + '.wav' str_out = wav_to_text(outf) str_ggl_out = Translate_ggl(str_out) # str_outをggl翻訳:今回追加分;翻訳不要の場合はコメントアウトする str_dpl_out = Translate_dpl(str_out) # str_outをdpl翻訳:今回追加分;翻訳不要の場合はコメントアウトする #df_x.loc[ii] = [ii,str(ii) + '.wav',str_out] # 翻訳不要の場合はこちらを使用し、下記をコメントアウトする df_x.loc[ii] = [ii,str(ii) + '.wav',str_out,str_ggl_out,str_dpl_out] # 上記に「,str_ggl_out,str_dpl_out」を追加:今回追加分 # excelへ書き出し with pd.ExcelWriter(out_file) as writer: df_x.to_excel(writer, sheet_name='結果', index=False) def wav_to_text(wavfile): r = sr.Recognizer() with sr.AudioFile(wavfile) as source: audio = r.record(source) wav_to_text = r.recognize_google(audio, language='ja-JP') print(wav_to_text) return wav_to_text # google翻訳:今回追加分;翻訳不要の場合は下記をコメントアウトする def Translate_ggl(wavtext): translator = Translator() wavtext2 = translator.translate(wavtext, dest='en', src='ja') tr_text = wavtext2.text print(tr_text) return tr_text # deepL翻訳:今回追加分;翻訳不要の場合は下記をコメントアウトする def Translate_dpl(wavtext): translator = deepl.Translator(os.getenv("DEEPL_AUTH_KEY")) # DEEPL_AUTH_KEYはDocker Composeに記述している result = translator.translate_text(wavtext, target_lang="EN-US") print(result) return result # 一応既に同じ名前のディレクトリがないか確認。 out_dir = "output" file = os.path.exists(out_dir) # print(file) if file == False: #保存先のディレクトリの作成 os.mkdir(out_dir) fTyp = [("","*.wav")] #iDir = os.path.abspath(os.path.dirname(__file__)) はJupyterlabではエラーになる iDir = os.path.join(Path().resolve()) #Jupyterlabではこちらでパスを指定する:今回修正分 f_name = tkinter.filedialog.askopenfilename(filetypes = fTyp,initialdir = iDir) cut_time = 60 out_file = "output/out.xlsx" cut_wav(f_name,float(cut_time))
Pythonコード修正の解説
追加分
6行目【from pathlib import Path】:音声ファイル読込時のファイルパス選定用
12行目【from googletrans import Translator】:google翻訳用
13行目【import deepl】:deepL翻訳用
14行目【import openpyxl】:Excelファイルを生成するときに必要
修正分
43〜46行目:今回は巻き戻さないので、音声をカットした部分を少し巻き戻すコード以下3行をコメントアウトする。
#if i > 0: # start_cut = int(i*frames) - int(180000) #else:
47行目:巻き戻さないので、インデントを削除。削除しないとエラーになる。逆に、巻き戻し設定する場合はこの行をインデントすること。インデントしないとエラーになる。
start_cut = int(i*frames)
翻訳用追加分(共通)
64行目:翻訳テキストを収納する変数で、初期値を空に設定。
str_tr_out = ""
65行目:翻訳不要時の設定。翻訳不要の場合はこちらを使用すること。
#list1 = [wavf,"",""] #
66行目:翻訳用。65行目に「,"",""」を追加。翻訳不要時はこちらをコメントアウトすること。
list1 = [wavf,"","","",""]
68行目:Excelの項目名。翻訳不要時の設定。翻訳不要の場合はこちらを使用すること。
#df_x.columns = ['No', '音声ファイル', '変換結果']
69行目:Excelの項目名。翻訳用。68行目に「,'ggl翻訳','dpl翻訳'」を追加。翻訳不要時はこちらをコメントアウトすること。
df_x.columns = ['No','音声ファイル','変換結果','ggl翻訳','dpl翻訳']
76行目:Excelへ収納する内容。翻訳不要時の設定。翻訳不要の場合はこちらを使用すること。
#df_x.loc[ii] = [ii,str(ii) + '.wav',str_out]
77行目:Excelへ収納する内容。翻訳用。76行目に「,str_ggl_out,str_dpl_out」を追加。翻訳不要時はこちらをコメントアウトすること。
df_x.loc[ii] = [ii,str(ii) + '.wav',str_out,str_ggl_out,str_dpl_out]
翻訳用追加分(google)
74行目:73行目のstr_outをgoogle翻訳する。翻訳不要の場合はコメントアウトすること。
str_ggl_out = Translate_ggl(str_out)
96〜101行目:google翻訳を定義する関数。翻訳不要の場合はコメントアウトすること。
def Translate_ggl(wavtext): translator = Translator() wavtext2 = translator.translate(wavtext, dest='en', src='ja') tr_text = wavtext2.text print(tr_text) return tr_text
Pythonを使って日本語から多言語への自動翻訳をやってみる。自動翻訳=音声認識+機械翻訳+音声合成
これまでの記事で、Pythonを使って、音声認識、音声合成、機械翻訳のやり方を説明してきました。今回はこれらの応用として、Pythonを自動翻訳(自動音声翻訳)の実装を解説していきたいと思います。
実は、googletransが悪さをして、『AttributeError: 'NoneType' object has no attribute 'group'』というエラーを吐いて全く進まなかった。
調べたところ、googletransは長らく安定していなかったようで、気まぐれに成功したりエラーになったり、ということだった。
googletransの最新バージョンは安定しているということだったので、最新版のgoogletrans==4.0.0-rc1をインストールするようDockerfileを書き換えたところ、上手くいった。
pythonでgoogletransライブラリを使って翻訳していると、ある日 AttributeError: 'NoneType' object has no attribut...
翻訳用追加分(deepL)
自動翻訳では定評のあるdeepLにも、Python用のライブラリが用意されている。
無料版もあるが、deepLのサイトでdeepL API Freeに事前登録し、API認証キーを取得しなければならない。
DeepL APIで使えるPythonのクライアントライブラリ
We’re excited to announce the release of our Python client library for the DeepL API.
75行目:73行目のstr_outをdeepL翻訳する。翻訳不要の場合はコメントアウトすること。
str_dpl_out = Translate_dpl(str_out)
104〜108行目:deepL翻訳を定義する関数。翻訳不要の場合はコメントアウトすること。
下記DEEPL_AUTH_KEYはDocker Composeの9行目の認証キーを読み込む。
def Translate_dpl(wavtext): translator = deepl.Translator(os.getenv("DEEPL_AUTH_KEY")) result = translator.translate_text(wavtext, target_lang="EN-US") print(result) return result
Jupyterlab用の修正
120〜121行目:文字起こしするwaveファイルを選択できるようにダイアログを表示させるためのもの。
120行目の設定ではJupyterlabではエラーになるのでコメントアウトする。__file__がJupyterlabでは対応していないとのこと。
Jupyterlabに対応した121行目を追加する。
#iDir = os.path.abspath(os.path.dirname(__file__)) iDir = os.path.join(Path().resolve())
Jupyter Notebookで__file__が使用できない - 筋肉エンジニアのAIって何なの?
直感ディープラーニングの写経をJupyter Notebookで行っていて、 __file__ が使用できないことがわかった。 以下のように対象ファイルのパス情報を取得できない。 import os os.path.dirname(__file__) 代わりに、以下を使用する。 from pathlib import Path Path().resolve() 直感ディープラーニングではログディレクトリを作成して 学習結果を出力し、TensorBoardで確認を行う。 書籍場では以下のように実行ファイルが含まれているディレクトリ情報を取得し、 その配下にlogdirというディレクトリを作成する…
Docker ImageとContainerの作成
上記のディレクトリの通りにセットし、Terminalを起動して必要なコマンドを打ってDocker ImageとContainerを作成する。
そのあと、xhostの設定やJupyterlabを開くなどあるが、それらの詳細は、以下をご覧あれ。
【完成版】MacでJupyterlabからPythonのGUIライブラリが使えるDockerの設定方法
PythonのGUIライブラリ(Tkinter、pillow、openpyxl)をDocker Container内にインストールし、JupyterlabからXQuartzを介して稼働させる方法と、Docker ComposeとDockrfileの作成方法を紹介します。
コードを走らせる
1分ごとに音声を分割して文字起こし
2分強のサンプル音声データを以下からお借りしております。
AI(人工知能)による 音声翻訳(音声→テキスト変換→機械翻訳),文字起こし(音声→テキスト変換),読み上げ(テキスト→音声変換),日本語文章校正サービス チョイミテーナ
人工知能で海外の動画の理解、議事録作成、文字(テープ)起こし作業、音声作成を強力に支援します。
ブラウザを開き、URL欄に
localhost:8000
と入力しJupyterlabを開き、上記のPythonコードをコピペしてコードを走らせる。
すると、読み込むwavファイルを尋ねてくるので該当するものを選択。
選択後、自動でoutputフォルダが生成し、outputフォルダ内に分割されたwavファイルと文字起こしテキストが収納されたexcelファイルが生成されたら成功。
音声ファイルを分割せずに文字起こし
2分強なので分割しなくてもいけるかも。
音声ファイルを分割しているのは、googletransの仕様で制限があるためらしい。deepLはどうだろうか?(未調査)
分割の場合、分割箇所を制御出来ないので、文の途中で分割されて翻訳が怪しくなる。
Pythonコードの下から3行目を以下の通り修正して3分で分割するように変更し、コードを走らせる。
cut_time = 60*3
翻訳ありの場合は、音声分割しない方がよいですね。
他の参考サイト
wavファイルを等間隔に分割 【Python】WAVファイルを等間隔に分割するプログラム【サウンドプログラミング】を参考にして以下のコードを書きました...
Pythonで音声からテキストへ変換【SpeechRecognition】
「Pythonでの音声認識に関する検索結果を見て混乱していませんか?」この記事では、Pythonで音声認識をする上での正しい情報を提供しています。この記事を読めば、コピペでよくわからないまま無駄なライブラリをインストールすることもなくなります。
コメント
コメントを投稿