はじめに
- 最近のAIは学習済みでツールとして使えるようになったものがあります。
例えば、音声認識ツール:VOSK、翻訳ツール:argostranslate - これらと読上げライブラリ:pyttsx3 をくっつけて、音声認識ー翻訳ー読み上げをしてみました。
- これらはオフラインで動くツールで、その実力を試してみました。
工夫したこと
- ローカル化
ネットワーク環境に縛られないツールを組み合わせました。 - 翻訳ループ防止
そのまま繋げたら、PCが自分で読上げた音声を再認識して、再翻訳して、再読上げして、、、と無限ループしたので、読上げ中は認識を止めるようにしました。
内容
1. PC環境
実施したPC環境は以下のとおりです。
CPU | Celeron N4100 |
メモリ | 8GB LPDDR4 |
2. 前準備
Windowsで使えるようにするため、以下のツール / システムをインストールしました。
インストール時に参考にしたサイトも記載します。
-
python(使用したのはVer.3.7 )
実行時のベースシステムです。
(参考)https://qiita.com/ssbb/items/b55ca899e0d5ce6ce963 -
pip(使用したのはVer.21.2.4 )
他のツールをダウンロードする際に使うツールです。
(python3系ではバージョン3.4以降であれば、pythonのインストールと共にpipもインストールされます。)
(参考)https://gammasoft.jp/python/python-library-install/ -
VOSK(使用したのはVer.0.3.42 )
音声認識ツールです。
(参考)https://alphacephei.com/vosk/ -
VOSK models(使用したのはvosk-model-small-ja-0.22 )
日本の音声認識で使用するモデルです。
展開したファイル群をVOSK_try/models/jaというフォルダに入れました。
(参考)https://alphacephei.com/vosk/models -
sounddevice(使用したのはVer.0.4.4 )
マイクを使うためのライブラリです。
(参考)https://www.wizard-notes.com/entry/python/sounddevice -
argostranslate(使用したのはVer.1.7.0)
翻訳ツールです。
(参考)https://portal.kemu.site/blog/1258346492 -
pyttsx3(使用したのはVer.2.90 )
読上げライブラリです。
(参考)https://pypi.org/project/pyttsx3/
また、作成にあたり、以下のサイトを参照しました。
- VOSK:
(参照)https://qiita.com/hatt_takumi/items/0aedc8f6768cd8efee5e
(参照)https://github.com/alphacep/vosk-api/blob/master/python/example/test_simple.py
(参照)https://github.com/alphacep/vosk-api/blob/master/python/example/test_microphone.py - argostranslate:
(参照)https://www.argosopentech.com/ - pyttsx3
(参照)https://qiita.com/be_tiger/items/370ce30a81f4b420f0dd
3.pyファイルの作成
組んだコードは次のとおりです。
#--- VOSK 初期化 ---
import argparse
import os
import queue
import sounddevice as sd
import vosk
import sys
#---
#--- argotranslate 初期化 ---
import argostranslate.package, argostranslate.translate
from_code = "ja"
to_code = "en"
# Download and install Argos Translate package
available_packages = argostranslate.package.get_available_packages()
available_package = list(
filter(
lambda x: x.from_code == from_code and x.to_code == to_code, available_packages
)
)[0]
download_path = available_package.download()
argostranslate.package.install_from_path(download_path)
# Translate
installed_languages = argostranslate.translate.get_installed_languages()
from_lang = list(filter(
lambda x: x.code == from_code,
installed_languages))[0]
to_lang = list(filter(
lambda x: x.code == to_code,
installed_languages))[0]
translation = from_lang.get_translation(to_lang)
translation.translate("私")#dummy 'input over flow'を表示させないため
#---
#--- pyttsx3 初期化 ---
import pyttsx3
engine = pyttsx3.init()
#rate
rate = engine.getProperty('rate') # getting details of current speaking rate
print (rate) #printing current voice rate
engine.setProperty('rate', 125) # setting up new voice rate
#volume
volume = engine.getProperty('volume') #getting to know current volume level (min=0 and max=1)
print (volume) #printing current volume level
engine.setProperty('volume',1.0) # setting up volume level between 0 and 1
#voice
voices = engine.getProperty('voices') #getting details of current voice
#---
# rec : VOSKの音声認識エンジン
# translation : argostranslateの翻訳エンジン
# engine : pyttsx3の読上げエンジン
#--- メインルーチン ---
q = queue.Queue()
rec_flg = True
def int_or_str(text):
"""Helper function for argument parsing."""
try:
return int(text)
except ValueError:
return text
def callback(indata, frames, time, status):
"""This is called (from a separate thread) for each audio block."""
if status:
print(status, file=sys.stderr)
if rec_flg:
q.put(bytes(indata))
parser = argparse.ArgumentParser(add_help=False)
parser.add_argument(
'-l', '--list-devices', action='store_true',
help='show list of audio devices and exit')
args, remaining = parser.parse_known_args()
if args.list_devices:
print(sd.query_devices())
parser.exit(0)
parser = argparse.ArgumentParser(
description=__doc__,
formatter_class=argparse.RawDescriptionHelpFormatter,
parents=[parser])
parser.add_argument(
'-f', '--filename', type=str, metavar='FILENAME',
help='audio file to store recording to')
parser.add_argument(
'-d', '--device', type=int_or_str,
help='input device (numeric ID or substring)')
parser.add_argument(
'-r', '--samplerate', type=int, help='sampling rate')
args = parser.parse_args(remaining)
try:
if args.samplerate is None:
device_info = sd.query_devices(args.device, 'input')
# soundfile expects an int, sounddevice provides a float:
args.samplerate = int(device_info['default_samplerate'])
model = vosk.Model("../VOSK_try/models/ja")
if args.filename:
dump_fn = open(args.filename, "wb")
else:
dump_fn = None
with sd.RawInputStream(samplerate=args.samplerate, blocksize = 8000, device=args.device, dtype='int16',
channels=1, callback=callback):
print('#' * 80)
print('Press Ctrl+C to stop the recording')
print('#' * 80)
rec = vosk.KaldiRecognizer(model, args.samplerate)
# -- メインループ start --
while True:
data = q.get()
if rec.AcceptWaveform(data):
#--- 音声認識の結果から文字だけ抽出
txt = rec.Result()
txt2 = txt.split("\"")[3]
txt2 = txt2.replace(' ','')
#---
if len(txt2) > 0:
rec_flg = False
#--- 認識結果の表示・読み上げ
print(txt2)
engine.setProperty('voice', voices[0].id) #changing index, changes voices. o for japanese female
engine.say(txt2)
#---
engine.setProperty('voice', voices[1].id) #changing index, changes voices. o for english female
#--- argostranslateでの翻訳と表示・読み上げ
translatedText = translation.translate(txt2)
print(translatedText)
engine.say(translatedText)
#---
engine.runAndWait() #engineが終わるまで待つ
engine.stop()
rec_flg = True
if dump_fn is not None:
dump_fn.write(data)
# -- メインループ end --
except KeyboardInterrupt:
print('\nDone')
parser.exit(0)
except Exception as e:
parser.exit(type(e).__name__ + ': ' + str(e))
4.説明
1. ローカル化
3つのツールを組み合わせただけなので、特記なしです。
2. 翻訳ループ防止
rec_flgというBOOL変数を入れ、これがTrueのときだけindataを記録するように変更、
if rec_flg:
q.put(bytes(indata))
読上げ前にrec_flgをFalseに、読上げ後Trueに変更するようにしました。
rec_flg = False
#省略(読上げ処理コード)
rec_flg = True
5.結果
- 同時通訳とはいきませんが、まあまあな速さで処理できました。
- 音声認識は、はきはき話せば大体正しく伝わりました。数字はあまり得意ではなさそうです。
- 翻訳は少々意訳されるように感じました。
例えば「私は今日東京駅に行きます」が「I go to Tokyo Station」になりました。 - 今回は日本語から英語への変換ですが、様々な言語が用意されてます。
参考
参考コード
https://github.com/alphacep/vosk-api/blob/master/python/example/test_microphone.py