RaspberryPiでTwitterのタイムラインを読み上げてみる(Amazon Polly & Twitter & Python)
以前のエントリーでAmazon Polly
(以下Polly
)を使っていましたが、流石にもう少しちゃんと動くものを作ってみようかなと思います。具体的にはTwitter
のタイムラインを取得してそれを読み上げようと思います。これまでも似たようなものとして、OpenJTalk
で読み上げを行っていましたがOpenJTalk
では文章量が長くなると途中できれてしまうということが稀にあり、Pollyではそんなこともないと信じたいのでチャレンジしてみました。(Pollyは有料サービスなんでそんなには使えないですけどね)
この組み合わせは Polly & Twitterバードの鳥鳥コンビなのはちょっと楽しい。
インストール
TwitterのタイムラインをPythonで取得するtweepy
は以前のエントリーでも使っていますが、かなり前の話なので念のためインストールについても書いておきます。といってもpip
を使えばそれでOKです。
$ sudo pip install tweepy Collecting tweepy Downloading tweepy-3.5.0-py2.py3-none-any.whl Requirement already satisfied: six>=1.7.3 in /usr/lib/python2.7/dist-packages (from tweepy) Requirement already satisfied: requests>=2.4.3 in /usr/local/lib/python2.7/dist-packages (from tweepy) Requirement already satisfied: requests-oauthlib>=0.4.1 in /usr/lib/python2.7/dist-packages (from tweepy) Requirement already satisfied: oauthlib>=0.6.2 in /usr/lib/python2.7/dist-packages (from requests-oauthlib>=0.4.1->tweepy) Installing collected packages: tweepy Successfully installed tweepy-3.5.0
とても簡単です。
あとはPolly
ですが、これでも以前のエントリーを参考にしてインストールしておきます。bot3
のインストールを行えばOKです。
これでPython
からTwitter
とPolly
を使う準備が整いました。
読み上げプログラムを作ってみる
行おうとしているプログラムは基本的には以下の動作から構成されます。
Twitter
の認証(tweepy
モジュールの使用)- タイムラインの取得(
tweepy
モジュールの使用) - タイムラインの不要な部分の削除(正規表現:reモジュールの使用)
Polly
へテキストの送信とファイルへの保存(bot3
へのアクセス)pygame
のmixerで再生
こちらがソースの全体となります。(関数化とかしてない…)
#!/usr/bin/env python # -*- coding: utf-8 -*- import tweepy import re import datetime from boto3 import Session from botocore.exceptions import BotoCoreError, ClientError from contextlib import closing import os import sys import subprocess import pygame.mixer import time # 個別にTwitterクライアント作成時に設定されるCONSUMER_KEY、CONSUMER_SECRETを設定してください CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXXX' CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) auth_url = auth.get_authorization_url() print('Please authorize: ' + auth_url) verifier = raw_input('PIN: ').strip() auth.get_access_token(verifier) print("ACCESS_KEY = '%s'" % auth.access_token) print("ACCESS_SECRET = '%s'" % auth.access_token_secret) ACCESS_KEY = auth.access_token ACCESS_SECRET = auth.access_token_secret auth.set_access_token(ACCESS_KEY, ACCESS_SECRET) api = tweepy.API(auth) print(api.me().name) now = datetime.datetime.now() print(now) # api.update_status('Tweepy! Sample start! ' + str(now)) session = Session(region_name="us-west-2") polly = session.client("polly") public_tweets = api.home_timeline() for i, tweet in enumerate(public_tweets): print('---{}---'.format(i)) print(tweet.author.screen_name + ":") # print(tweet.text) text = re.sub('RT', "", tweet.text) text = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", text) text = re.sub(r'[##]([\w一-龠ぁ-んァ-ヴーa-z]+)', "", text) text = re.sub(r'@([\w]+):', "", text) text = re.sub('\s', "", text) print(text) try: response = polly.synthesize_speech( Text=text, OutputFormat="mp3", VoiceId="Mizuki") except (BotoCoreError, ClientError) as error: print(error) sys.exit(-1) if "AudioStream" in response: with closing(response["AudioStream"]) as stream: output = "speech.mp3" try: with open(output, "wb") as file: file.write(stream.read()) except IOError as error: print(error) sys.exit(-1) print("synthesize_speech OK ->>" + output) else: print("Could not stream audio") sys.exit(-1) pygame.init() pygame.mixer.init() pygame.mixer.music.load("speech.mp3") pygame.mixer.music.play() print("PLAY") while pygame.mixer.music.get_busy() == True: continue print("END") pygame.mixer.music.stop() pygame.mixer.quit() pygame.quit()
ソースの説明
以下では部分的に説明をしていきます。
Twitter
の認証(tweepy
モジュールの使用)
以下の部分でTwitter
に関する認証を行っています。
CONSUMER_KEY
とCONSUMER_SECRET
はTwitter
のアプリの作成画面に出ます。これを使って認証用のURLを呼び出し、PIN生成を行っていきます。
表示されるURLをブラウザに与えることでPIN表示まで持っていきます。
起動すると以下のようなPINの入力待ち画面になります。
この処理を行っているのが以下の処理になります。
CONSUMER_KEY
とCONSUMER_SECRET
の値がXXXXX…となっていますがTwitterのアプリケーション設定画面の
の値を入れるようにしてください。
【Pythonの処理部分】
# 個別にTwitterクライアント作成時に設定されるCONSUMER_KEY、CONSUMER_SECRETを設定してください CONSUMER_KEY = 'XXXXXXXXXXXXXXXXXXX' CONSUMER_SECRET = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' auth = tweepy.OAuthHandler(CONSUMER_KEY, CONSUMER_SECRET) auth_url = auth.get_authorization_url() print('Please authorize: ' + auth_url) verifier = raw_input('PIN: ').strip()
表示されたURLをクリックすると
認証画面に遷移します。【連携アプリを認証】をクリックします。(ログインを事前にしていないと、ログインを促された後にこの画面になるかもしれません。)
すると7桁のPINコードが表示されるので、この値をコンソールに入力します。
PINを入力すると実際に使用するACCESS_TOKEN
とACCESS_TOKEN_SECRET
を取得する処理となります。
【Pythonの処理部分】
auth.get_access_token(verifier) print("ACCESS_KEY = '%s'" % auth.access_token) print("ACCESS_SECRET = '%s'" % auth.access_token_secret) ACCESS_KEY = auth.access_token ACCESS_SECRET = auth.access_token_secret auth.set_access_token(ACCESS_KEY, ACCESS_SECRET) api = tweepy.API(auth)
これでアプリケーションの使用に必要なACCESS_KEY
とACCESS_TOKEN_SECRET
の取得ができました。あとは認証処理に与えれば完了となりますauth.set_access_token(ACCESS_KEY, ACCESS_SECRET)
の部分になります。これでTwitter API
の処理を行える様になりました。
本来であればこれらキーはファイルに保存して再利用するのですが、今回は端折っています。保存する場合にはアクセス権などには注意してください。
タイムラインの取得(tweepy
モジュールの使用)
APIの使用ができるようになればタイムラインの取得は簡単です。今回はHomeタイムラインを取得しています。
【Pythonの処理部分】
public_tweets = api.home_timeline() for i, tweet in enumerate(public_tweets): print('---{}---'.format(i)) print(tweet.author.screen_name + ":") # 表示する場合には以下のコメントを外してください # print(tweet.text) …
取得したタイムラインはデフォルト件数は20件になります。必要であれば引数に追加を与えることになりますが、Pollyが有料サービスなのでこのままにしておきます。
タイムラインの不要な部分の削除(正規表現:reモジュールの使用)
タイムラインの文面から不要なURLなどを正規表現で削除して読み上げに適した文面に変換します。さすがにURLを読み上げられても?となってしまうので。
以下は正規表現でURL、【RT】接頭辞、ハッシュタグ、ユーザ名の削除を行いプレーンな文章に変換をして行きます。
【Pythonの処理部分】
text = re.sub('RT', "", tweet.text) text = re.sub(r'https?://[\w/:%#\$&\?\(\)~\.=\+\-…]+', "", text) text = re.sub(r'[##]([\w一-龠ぁ-んァ-ヴーa-z]+)', "", text) text = re.sub(r'@([\w]+):', "", text) text = re.sub('\s', "", text)
これで完璧というわけではないのですがおおよそ大丈夫かなと思います。
Polly
へテキストの送信とファイルへの保存(bot3
へのアクセス)
得られたタイムラインのデータをbot3
にアクセスして、Polly
が読み上げした音声のデータを取得していきます。
このあたりは過去エントリー参照で大丈夫でしょう。
【Pythonの処理部分】
print(text) try: response = polly.synthesize_speech( Text=text, OutputFormat="mp3", VoiceId="Mizuki") except (BotoCoreError, ClientError) as error: print(error) sys.exit(-1) if "AudioStream" in response: with closing(response["AudioStream"]) as stream: output = "speech.mp3" try: with open(output, "wb") as file: file.write(stream.read()) except IOError as error: print(error) sys.exit(-1) print("synthesize_speech OK ->>" + output)
この処理が終わるとPolly
で生成された音声ファイルはspeech.mp3
とされて保存されます。
pygame
のmixerで再生
あとは変換された音声を再生するだけです。
【Pythonの処理部分】
pygame.init() pygame.mixer.init() pygame.mixer.music.load("speech.mp3") pygame.mixer.music.play() print("PLAY") while pygame.mixer.music.get_busy() == True: continue print("END") pygame.mixer.music.stop() pygame.mixer.quit() pygame.quit()
こちらも先程のエントリーを参考にしてもらえればと思います。(初期化処理・終了処理は毎回しなくてもいいかなとは思いますが。)
終わりに
ようやくPython
を使ってTwitter
のタイムラインを取得して読み上げることができました。
まあ、読み上げられた文面もなんとか分かるかなという感じですがAAや絵文字なんかがあると謎の文面になってしまいますね。さすがに仕方ないですね。
長い文章での読み上げがうまくいくなら、ネットワークアクセスがある分遅くなってしまいますのでOpenJTalk
の方がいいかも。