Hubotで英語学習bot作った

f:id:amagitakayosi:20181127144718g:plain

どうも天城です。最近は戸籍について悩んでます。

きょうは英単語を覚えるためのSlack botを作ったので紹介します。 Slackの #dictionary に英単語とその意味をメモしておくと、トランプ大統領が定期的にクイズを出題してくれる。

もくじ

前回までのあらすじ

blog.gmork.in

TOEICではいい点数とれたけど、まだまだボキャブラリーが無いのでもっと勉強したい。

我が家では以前からSlackを利用しており、Hubotでを洗濯やゴミ出しのリマインダーを作っていた。 このSlackに #dictionary に単語をメモしていたのだが、このbotを利用して単語クイズができればいいな〜ということを思いついた。

単語学習サービスは既にAnkiなどがあるが、様々なデバイスでデータを共有するのが大変そうなのと、新たにツールを導入するのは面倒なので、既にあるHubotを利用することにした。

仕組み

HerokuでDBといえばPostgresだけど、無料だと10000行までという制約がある。 実際困る事はないかもしれないが、なんとなく制限のことを考えるのがめんどい。 HerokuのAdd-onは他もだいたい無料だと制限があるので見送り。

というわけで、今回はGoogle Spreadsheetを使うことにした。 Google Spreadsheetなら200万セルまでらしいので、1単語に5セル使っても400000単語まで記録できる。

API周りの処理は、node-google-spreadsheetを利用した。 Google謹製のgoogleapisというのもあるけど、前者のほうが認証周りがシンプルそうだった。

github.com

事前にSpreadsheetで以下のようなシートを作成しておき、botが記録/閲覧できるようにしておく。

f:id:amagitakayosi:20181127153932p:plain

サービスアカウント作成

botがSpreadsheetにアクセスするためには、Googleダッシュボード上でサービスアカウントを作成する必要がある。 詳しい手順はこの辺を参照。

https://github.com/theoephraim/node-google-spreadsheet#service-account-recommended-method

サービスアカウントを作成できたら認証用データの入ったJSONがダウンロードされる。 JSON内のメールアドレス、プライベートキー等は、Herokuの設定画面などから環境変数に入れておくとよい。

f:id:amagitakayosi:20181127154226p:plain

記録部分

特定の形式のメッセージが来たらスプレッドシートに記録する。 今回は以下の形式を採用。

*america* 
アメリカ

Hubotレポジトリの /scripts に以下のスクリプトを保存すると良い。 doc.addRow() を呼ぶだけで行を追加できて便利。

const GoogleSpreadsheet = require('google-spreadsheet');
const p = require('pify'); // promisify

// 認証周りのデータ
const doc = new GoogleSpreadsheet(process.env.SPREADSHEET_KEY);
const creds = { 
  client_email: process.env.SPREADSHEET_CLIENT_EMAIL,
  private_key: process.env.SPREADSHEET_PRIVATE_KEY,
};

// メッセージにマッチする正規表現
const re = /\*?([^\n\*]+)\*?\n(.+)/;

module.exports = (robot) => {
  robot.hear(re, async (res) => {
    let m = res.message.rawText.match(re);
    if (m) {
      // メッセージから英単語と意味を抽出
      const english = m[1];
      const japanese = m[2];

      // 認証
      await p(doc.useServiceAccountAuth)(creds); 

      // スプレッドシートに保存      
      p(doc.addRow)(1, { english, japanese })
        .then(() => res.send('OK, saved.'))
        .catch((e) => res.send('ERROR! Try again.'));
    }
  });
};

クイズ部分

こういう感じでSpreadsheetから単語を取得して

const GoogleSpreadsheet = require('google-spreadsheet');
const p = require('pify'); // promisify

const doc = new GoogleSpreadsheet(process.env.SPREADSHEET_KEY);
const creds = { 
  client_email: process.env.SPREADSHEET_CLIENT_EMAIL,
  private_key: process.env.SPREADSHEET_PRIVATE_KEY,
};

// 認証
await p(doc.useServiceAccountAuth)(creds); 

// 行を取得
const info = await p(doc.getInfo)();
const rows = p(info.worksheets[0].getRows)({}));

// セルのデータを取得
const words = rows.map(r => ({
  english: r.english,
  japanese: r.japanese,
}));

こういうのでSlackに発言すればよい。 send.trump はメッセージ送信部分のラッパー。

module.exports = async (robot, room) => {
  send.trump(robot, room, '@channel 今から皆さんに、英語に関するクイズを出すピィ〜♪\n');

  // 単語を取得
  let rows = await sheet.getRows();
  rows = shuffle(rows);

  for (let i = 0; i < limit; i++) {
    const r = rows[i];

    send.trump(robot, room, `*${r.english}* は何という意味でしょう?`)
    await sleep(5000);
    send.trump(robot, room, `正解は \`${r.japanese}\` でした!!\n.\n`);
    await sleep(5000);
  }

  await sleep(1000);
  send.trump(robot, room, 'お疲れ様!!今日も一日頑張ろうヾ(๑╹◡╹)ノ"');
};

実際には、同じ単語は3回までしかクイズに出ないようにしたり、一日の出題数を制限したりしてる。 大量にあると疲れてしまうので……


今回のbotは単語帳サービスみたいなものなので、英語に限らず何でも記録出来ます。 ことわざとか技術用語の学習に使ってもいいかも。

f:id:amagitakayosi:20181127153707p:plain

TOEICで935点を取ったので勉強法を振り返る

先日、TOEICで935点をゲットした。

f:id:amagitakayosi:20181119220340p:plain

忙しくてあまり勉強できなかったけど、思ったより良い点数で驚いた。 大学時代に受けた時は800点だったので、普段の生活でもそれなりに英語力が上がってたんだなー。

というわけで、ここ数年やってきた英語活動?についてまとめます。

一言で言うと、 英語に触れる心理的障壁を下げる ことが大事っぽい。


筆者のスペック

英語Podcastを聴く

僕はプログラマーなので、技術系のPodcastをたまに聴いている。 毎日聴いているわけではなくて、たまに意識が高まった時とか、暇だけど疲れてて読書とかはできない時に聴いてる。 昔は早朝や深夜にジョギングしていたので、そのついでに聴いたりもしていた。

余裕があればシャドーイングもしている。 聞き取れる部分だけでも真似して発音してみると、自分の発音のおかしい所に気付けるし、ネイティブスピーカーが発音を省略してる感じもわかってくる。

電車のなかでシャドーイングしてると不審者っぽいけど、まあ誰もお前のことなんて気にしてないよ、と自分に言い聞かせてブツブツやってる。

以下は僕が聴いてるPodcast

Web系

JavaScript Jabber

https://devchat.tv/js-jabber/devchat.tv

レギュラー陣が3,4人 + ゲスト1人、という布陣。 JSのライブラリの開発者やChrome開発チームの人がゲストになる。 普段使ってるライブラリの開発経緯や、中の人の人となりがわかるので、聴いてて楽しい。

会話のスピードは中くらい。 たまにゲストのマイクの音質が悪かったり、早口で聞き取れないこともあるけど、進行役のCharles Max Woodが気を利かせて「ごめん聞こえなかった、もう一回言って」とかやってくれたりする。

ジョークを言ってる時は早口になるので聞き取れないけど……😇、

SoftwareEngineering Daily

https://softwareengineeringdaily.com/softwareengineeringdaily.com

タイトルの通り、Webに限らず様々な分野の技術について紹介してくれるPodcast。 インフラ系の技術はわからないのでスルーしてる……。

更新頻度がめちゃ高い(マジでほぼ毎日更新される)ので、興味のある回だけ聴くのがオススメ。

CG系

CG Garage

www.chaosgroup.com

V-Rayという3DCGのレンダリングエンジンを開発している、Chaos GroupによるPodcast。 Epic、ノーティドッグといったゲームスタジオや、MarvelやDisney Researchなど映画業界からゲストを迎え、有名作品の舞台裏について聴くことができる。

デザイン系

Wireframe

creative.gimletmedia.com

AdobeのデザイナーKhoi Vinhによる、デザインについてのポッドキャスト。 全エピソードが Good Design is ~~ というタイトルで、毎回いろんなデザイナーに取材している。

会話のスピードもゆっくりだし、音質も編集もしっかりしている。 デザイン系のポッドキャストは話題が散らばったり、会話がネイティブ過ぎて全然ついていけなかったりしがちなんだけど、Wireframeはテーマもわかりやすいし、とても聴きやすくてオススメ!

コツ1. 良いPodcastクライアントを使う

iOSではOvercastを、AndroidではPocketCastsを使っている。 どちらもフル機能は有料だけど、いくつか試したところこの2つが最も使い勝手が良かった。

スピード調整、無音部分のスキップ、声を聞き取りやすくするvoice boost機能があり、かつPodcast毎に設定を保存してくれる。 僕は日本語のPodcastは3倍速 + 無音部分スキップ、英語Podcastは等倍 + voice boostで使っている。

Overcast

Overcast

  • Overcast Radio, LLC
  • ニュース
  • 無料

play.google.com

コツ2. 日本語のPodcastもいろいろ聴く

英語Podcastしか登録していないと、Podcastアプリを開くのが苦痛になり、よほどモチベーションが高くないとアプリを開けなくなってしまう(体験談)。 ので、日本語のPodcastも登録しておいて、「今日は英語のやつ聴くか〜」くらいのテンションで気軽に聴けるようにしておくと良い。

これは僕のPocket Castsのスクショ。 Rebuild.fm, YATTEIKI.fm等をよく聴いています。

f:id:amagitakayosi:20181119231438j:plain

HackerNewsやMediumの記事を読む

休憩時間にHackerNewsというプログラマー向けニュースサイトを読んでいる。 HackerNewsはUIのアクが強くて心理的障壁が高いので、BitBarでいつでもサッと読めるようにしている。 1クリックで人気記事一覧を見れるようになり、非常に便利。

f:id:amagitakayosi:20181119212607p:plain

HackerNewsは正直話題が広すぎるので、タイトルだけ見て、面白い記事があれば読むか、くらい。 あまり知られていないけどDesignerNewsというサイトも存在していて、デザイン/UI系の記事が多いので、こっちの方がよく読んでるかも。 僕はPandaというChrome拡張機能を入れていて、新しいタブを開いたらDesignerNewsとABDUZEEDOAWWWARDSの最新記事一覧を見れるようにしている。

f:id:amagitakayosi:20181119225610g:plain

Panda 5 | News & Inspiration Dashboard - Chrome Web Store

Mediumの記事はネイティブ向けに書かれたこなれた文章が多く、知らない単語がバンバン出てくるので、ボキャブラリーを増やすにはもってこいだ。長さも短いので、10分から20分あれば大抵読めるしね。 僕は新幹線の中でよくMediumの記事を読んでる。紙の本を読むと大抵酔ってしまうので、Mediumくらいの分量が丁度いい。

あと、はてなブックマークにはマイホットエントリーという神機能があり、お気に入り登録しているユーザーのブックマークや、Twitterでフォローしてる人々が話題にしている記事をサジェストしてくれるので、そこで気になった英語記事をチェックしている。

f:id:amagitakayosi:20181119212323p:plain

コツ3. すぐに辞書を開けるようにする

意外と知られてないけど、Macだと単語をタップするだけで辞書で調べる事ができる。 設定はシステム環境設定でチェックを入れるだけ。

f:id:amagitakayosi:20181119211913p:plain

僕は 3本指でタップ にしてる。

Windowsでも使える奴だと、Mouse Dictionaryというブラウザ拡張が良さそうだった。 (Chrome/Firefox対応)

qiita.com

この辺の環境を整えるだけで、英語の文章を読むのが5000億倍ラクになる。

海外旅行に行く

一昨年はタイ、去年は台湾、今年はデンマークフィンランドに行った。

毎回初日はめっちゃ怖いんだけど、ホテルにチェックインする頃には「意外となんとかなる……!」という気分になっていて、とにかく行けばどうにかなることがわかる。 最終日には「俺の英語はショボい……ショボショボ野郎……ショボボ」となって多少落ち込んでるけど、行く前よりは良くなってるはず、と自分に言い聞かせてる。

カンファレンスで外国の人と話す

プログラマーは技術カンファレンスに参加することがあり、そこで交流するチャンスがある。

大きめのカンファレンスに行くと外国からのゲストがいるので、質問したり懇親会で話しかけたりしてみると良い。 特に、みんながビビって話しかけてくれず、ゲストだけで固まってしまってるケースは、頑張って声をかけると沢山話してくれるし、色々教えてもらえたりする。

交流の場では「どういう仕事してるの?」と何度も聞かれることになるので、ある程度脳内でテンプレを用意しとくと便利。

そういえば最近は技術系のイベントに出てない。もっと活発になりてえなあ。

英語圏の人とチャットする

f:id:amagitakayosi:20181119213059p:plain

これは大分ハードル高い気もするけど……

僕は去年からVEDAというVJアプリを作っているのだけど、英語圏の人から質問を受けたり、SlackなどでVJ界隈の人とつるんだりと、英語でやりとりする機会が増えた。 文章をリアルタイムで考えるのはかなり難しく、未だに毎回ググってるんだけど、ググる度に語彙が増えていってると考えることにしてる😇

f:id:amagitakayosi:20181119213624p:plain

死にたくなった時に勉強する

大学の時は人生が嫌になり、数日間講義サボって電車に乗りひたすらDUOだけを読み続けてボロボロになって帰ってくる、みたいなことをたまにやってた。

最近は人生が好転しているのでやってない。ので語彙力が増えてないかもしれない……けど幸せだから良いや


以上、万人に当てはまらない事もたくさん書いたけど、参考になれば幸いです。
英語に触れる機会を増やすと良い、というのは自明だけど、頑張るのはしんどいので、なるべく頑張らずに英語に触れられる仕組みを作れるといいですね。

ちょっと自信がついたので、英語圏からの仕事もガンガン受けていきたいな〜