Help us understand the problem. What is going on with this article?

Pythonを使って、Google Homeに喋らせてみる

More than 1 year has passed since last update.

Google Homeに自発的に喋ってもらいたくなったので色々と調べてみたのですが、google-home-notifierが大多数を占めていたので、Pythonのみで書いてみました。

面倒な人向け

Gistにソースがあるので見てください

序:google-home-notifierについて(ざっくりと

node.js製の、Google Homeに対してテキストを喋らせるライブラリです。

雑にコードを読んだり、Qiitaにある記事なんかを読んところ、

  1. mDNSでLAN内のGoogle Homeを探す
  2. テキストをGoogle Text-to-Speechを使ってmp3のURLを作成する
  3. (2)のURLをGoogle Homeに渡して再生させる

といった感じになるようです。

破:google-home-notifierの仕組みはPythonのライブラリにあるか

とりあえず目についたのが、この2個。
うまい具合に不足部分を補えれば、再現に近いことができそうです。

pychromecast

Chromecastとの通信をしてくれるライブラリです。

Check out Home Assistant for a ready-made solution using PyChromecast for controlling and automating your Chromecast or Cast-enabled device like Google Home.

とREADMEにあるとおり、Google HomeはGoogleCast仕様に基づくらしく、このライブラリでそのまま拾うことができます。

pychromecast_sample
>>> import pychromecast
>>> chromecasts = pychromecast.get_chromecasts()
>>> len(chromecasts)
>>> chromecasts[0]
Chromecast(
    '192.168.0.12',
    port=8009,
    device=DeviceStatus(
        friendly_name='自室のGoogle Home',
        model_name='Google Home',
        manufacturer='Google Inc.',
        uuid=UUID('XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'),
        cast_type='audio'
    )
)

gTTS

Google Text-to-speechを利用して、テキストをmp3に変換してローカルに保存する事ができるライブラリです。

gtts_sample
>>> from gtts import gTTS
>>> tts = gTTS(text='ハローワールド', lang='ja')
>>> tts.save('./hello_world_ja.mp3')

わずか3行で変換できる優れもの。ただし、このライブラリのみではgoogle-home-notifierのようにGoogle側にあるURLを扱えないのが考えものです。
(とはいえ、色々実装するの面倒なので、今回は眼をつぶることにします)

急:実際に作ってみる

用意するもの

bottleも使って、ローカルにWebサーバーを用意します。
パスはこんな感じ。

  • /form
    • テキスト送信フォームのURL
  • /talks/xxxxxxxx
    • 保存済みテキストmp3のURL

/formの処理概要

  1. ブラウザからフォームでテキストと言語を送信
  2. POSTリクエスト内で、
    1. gTTSを使ってテキストのmp3を作成してローカルに保存
    2. pychromecastを使って、保存済みのmp3を示すURLをGoogleHomeに再生させる
  3. Google Homeが喋る

ソース抜粋

※処理の流れが終える程度に圧縮

server.py
# -*- coding: utf-8 -*-
# インポート周りは省略

BASE_DIR = Path(__file__).parent
TALK_DIR = BASE_DIR / 'var'
app = Bottle()


@app.route('/talks/<file_path:path>')
def get_talk_mp3(file_path):
    return static_file(file_path, root=TALK_DIR)


@app.route('/form', method='GET')
def get_talk_form():
    """フォーム表示"""
    content = BASE_DIR / 'template.html'
    text = request.forms.text or ''
    lang = request.forms.lang or 'ja'
    return template(
        content.open().read(), langs=gTTS.LANGUAGES, lang=lang, text=text)


@app.route('/form', method='POST')
def post_talk_form():
    """トークテキストを保存して、再生指示"""
    text_token = generate_talk(request.forms.text, request.forms.lang)
    # 面倒なので、目についたGoogleCast端末に決め打ち
    chromecasts = pychromecast.get_chromecasts()
    chromecasts[0].media_controller.play_media(
        f"http://192.168.0.20:8080/talks/{text_token}", 'audio/mp3')
    return get_talk_form()


def generate_talk(text, lang):
    """言語もテキストも一致したらキャッシュを使うように"""
    text_token = hashlib.sha256((lang + text).encode()).hexdigest()
    talk_path = TALK_DIR / text_token
    if not talk_path.exists():
        tts = gTTS(text=text, lang=lang)
        tts.save(talk_path)
    return text_token


if __name__ == '__main__':
    if not TALK_DIR.exists():
        TALK_DIR.mkdir()
    app.run(host='0.0.0.0', port='8080', reloader=True)

(時間があったら、動画でも用意します)

あとがき

google-home-notifierでも十分だったりするのですが、「この辺の仕組みを上手く広げていくと面白い何かができないかなー」なんて考えてみたりしたいですね。

こんなのもあったので、参考にしたいと思います。

attakei
東京湾岸にて勤務中。 【公私】主にインフラ・サーバサイドWeb担当。Pythonista 【他】徒歩バカ
nijibox
ニジボックスの開発は、社内のUI/UXデザインチームと連携をとりながらワンストップで行う開発支援サービスです。Reactを始めPHP(Laravel)・Ruby on Rails、Swift・Kotlinを使った開発実績も多く、バックエンドからアプリまで幅広く対応しています。Twitterで情報発信しています: https://twitter.com/nijibox_jp
https://nijibox.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした