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

Watson Conversationを使って天気予報をするSlack botを作ってみた

More than 3 years have passed since last update.

Watson Conversationを使って天気予報をするSlack botを作ってみました。
この投稿では、その作成手順を紹介します。
以前投稿した記事では、ランダムに天気を答えさせていましたが、今回は天気予報APIを呼び出して実際に天気予報を行います。
* 以前投稿した記事:会話エンジンにWatson Conversationを使ったSlack botを作ってみた

処理のイメージは以下の図のような感じです。
Watson Conversationで入力文章を解析し、天気予報API(Weather Company Data)を呼び出します。
今回Slackとのやり取りと処理フローの作成にはNode-REDを使っています。
nodered28.png

作成手順は以下のようになります。
1. Bluemix上にNode-REDをセットアップ
2. Watson Conversation、Weather Company DataをNode-REDにバインド
3. Watson ConversationのWorkspace作成
4. SlackにBotを追加
5. Node-REDフローの作成

Weather Company Data APIとは

Bluemixのサービスのひとつで、天気情報が取得できるAPIです。
ドキュメントはこちら→Weather Company Data の概要

Node-REDとは

Node-REDについては以下の投稿が参考になります。
BluemixのNode-REDで簡単Webアプリ開発

今回、Slackアクセスするためのノードを追加します。
Node-REDパレットに新しいノードを追加する方法については以下の投稿が参考になります。
BluemixのNode-REDパレットにノードを追加する

1. Bluemix上にNode-REDをセットアップ

「カタログ」の「ボイラープレート」カテゴリの中から「Node-RED Starter」を選択します。
nodered1.PNG

任意のアプリ名、ホスト名を付けて、「作成」ボタンを押します。
nodered2.PNG

作成後、「DOWNLOAD STARTER CODE」ボタンを押して、STARTER CODEをDownloadします。
zipファイルがDownloadされるので、任意のディレクトリに解凍します。
nodered3.PNG

解凍するとpackage.jsonがあるので、これに"node-red-contrib-slack":"*"の記述を追加します。この追加したライブラリがSlackにアクセスするためのノードです。
追加する場所は以下の修正例を参考にしてください。

package.json(修正例)
{
    "name"         : "node-red-bluemix",
    "version"      : "0.5.0",
    "dependencies": {
        "when": "~3.x",
        "mongodb": "~1.4.x",
        "nano": "~5.11.0",
        "cfenv":"~1.0.0",
        "feedparser":"~0.19.2",
        "redis":"~0.10.1",
        "node-red": "0.x",
        "node-red-bluemix-nodes":"1.x",
        "node-red-node-watson":"0.x",
        "node-red-node-openwhisk":"0.x",
        "node-red-node-cf-cloudant":"0.x",
        "node-red-contrib-scx-ibmiotapp":"0.x",
        "node-red-contrib-ibmpush":"0.x",
        "node-red-contrib-bluemix-hdfs":"0.x",
        "node-red-nodes-cf-sqldb-dashdb":"0.x",
        "node-red-contrib-slack":"*"
    },
    "scripts": {
        "start": "node --max-old-space-size=384 node_modules/node-red/red.js --settings ./bluemix-settings.js -v"
    },
    "engines": {
        "node": "4.x"
    }
}

package.jsonのあるディレクトリで、以下のコマンドでNode-REDをBluemixにデプロイします。

実行例
コマンド:cf push
========
以下は実行結果(以下のようにstateがrunningになれば正常にデプロイ出来ています)
requested state: started
instances: 1/1
usage: 512M x 1 instances
urls: xxxxxx.mybluemix.net
last uploaded: Sat Nov 19 14:58:25 UTC 2016
stack: unknown
buildpack: SDK for Node.js(TM) (ibm-node.js-4.6.0, buildpack-v3.8-20161006-1211)

     state     since                    cpu    memory           disk           details
#0   running   2016-11-20 12:00:48 AM   0.0%   318.8M of 512M   448.2M of 1G

2. Watson Conversation、Weather Company DataをNode-REDにバインド

Bluemixのコンソールでアプリケーションの画面を開き「接続」メニューの「新規に接続」ボタンを押します。

nodered4.PNG

「Watson」カテゴリの「Conversation」を選択します。
nodered5.PNG

任意のサービス名で「作成」ボタンを押します。
nodered6.PNG

続けて「新規に接続」ボタンを押して、Weather Company Dataを追加します。
「データ&分析」カテゴリの「Weather Company Data」を選択します。
nodered7.PNG

任意のサービス名で「作成」ボタンを押します。
nodered8.PNG

3. Watson ConversationのWorkspace作成

この投稿では、会話定義は行わず作成済みの会話をImportしてWorkspaceを作成します。
以下の会話定義をコピーして、任意の名前(例:workspace-WeatherCompany.json)で保存します。(注意!!文字コードはUTF-8で保存してください。拡張子はjsonにしてください)

workspace-WeatherCompany.json
{"name":"天気予報","created":"2016-09-30T08:35:40.682Z","intents":[{"intent":"あいさつ","created":"2016-11-19T13:27:08.415Z","updated":"2016-11-19T13:28:07.949Z","examples":[{"text":"おはよう","created":"2016-11-19T13:27:36.419Z","updated":"2016-11-19T13:27:36.419Z"},{"text":"オハヨウ","created":"2016-11-19T13:27:30.984Z","updated":"2016-11-19T13:27:30.984Z"},{"text":"こんにちは","created":"2016-11-19T13:27:15.601Z","updated":"2016-11-19T13:27:15.601Z"},{"text":"こんばんは","created":"2016-11-19T13:27:47.696Z","updated":"2016-11-19T13:27:47.696Z"},{"text":"コンニチハ","created":"2016-11-19T13:27:26.419Z","updated":"2016-11-19T13:27:26.419Z"},{"text":"はじめまして","created":"2016-11-19T13:27:59.902Z","updated":"2016-11-19T13:27:59.902Z"},{"text":"おはようございます","created":"2016-11-19T13:27:42.055Z","updated":"2016-11-19T13:27:42.055Z"},{"text":"Hello","created":"2016-11-19T13:28:03.555Z","updated":"2016-11-19T13:28:03.555Z"},{"text":"Hi","created":"2016-11-19T13:28:07.949Z","updated":"2016-11-19T13:28:07.949Z"},{"text":"今日は","created":"2016-11-19T13:27:21.230Z","updated":"2016-11-19T13:27:21.230Z"},{"text":"今晩は","created":"2016-11-19T13:27:54.174Z","updated":"2016-11-19T13:27:54.174Z"}],"description":null},{"intent":"天気","created":"2016-10-03T05:45:11.444Z","updated":"2016-11-19T13:53:28.837Z","examples":[{"text":"予報","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"今日の天気は?","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"天候が気になる","created":"2016-11-19T13:53:16.757Z","updated":"2016-11-19T13:53:16.757Z"},{"text":"天気","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"天気は?","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"天気いいかな?","created":"2016-11-19T13:53:08.689Z","updated":"2016-11-19T13:53:08.689Z"},{"text":"天気がきになる","created":"2016-11-19T13:53:28.837Z","updated":"2016-11-19T13:53:28.837Z"},{"text":"天気予報","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"どんな感じ?","created":"2016-11-19T13:52:51.367Z","updated":"2016-11-19T13:52:51.367Z"},{"text":"晴れかな?","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"曇りかな?","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"},{"text":"雨かな?","created":"2016-10-03T05:45:11.444Z","updated":"2016-10-03T05:45:11.444Z"}],"description":null}],"updated":"2016-11-19T15:13:51.941Z","entities":[{"type":null,"entity":"place","source":null,"values":[{"value":"三重","created":"2016-10-04T06:19:58.683Z","updated":"2016-10-04T06:19:58.683Z","metadata":null,"synonyms":[]},{"value":"京都","created":"2016-10-04T06:17:45.335Z","updated":"2016-10-04T06:17:45.335Z","metadata":null,"synonyms":[]},{"value":"佐賀","created":"2016-10-04T06:18:12.604Z","updated":"2016-10-04T06:18:12.604Z","metadata":null,"synonyms":[]},{"value":"兵庫","created":"2016-10-04T06:19:34.236Z","updated":"2016-10-04T06:19:34.236Z","metadata":null,"synonyms":[]},{"value":"北海道","created":"2016-10-03T05:54:57.004Z","updated":"2016-10-03T05:55:08.368Z","metadata":null,"synonyms":["ほっかいどう"]},{"value":"千葉","created":"2016-10-04T06:18:36.975Z","updated":"2016-10-04T06:18:36.975Z","metadata":null,"synonyms":[]},{"value":"和歌山","created":"2016-10-04T06:20:32.361Z","updated":"2016-10-04T06:20:32.361Z","metadata":null,"synonyms":[]},{"value":"埼玉","created":"2016-10-04T06:18:08.635Z","updated":"2016-10-04T06:18:08.635Z","metadata":null,"synonyms":[]},{"value":"大分","created":"2016-10-04T06:16:50.603Z","updated":"2016-10-04T06:16:50.603Z","metadata":null,"synonyms":[]},{"value":"大阪","created":"2016-10-04T06:16:55.584Z","updated":"2016-10-04T06:16:55.584Z","metadata":null,"synonyms":[]},{"value":"奈良","created":"2016-10-04T06:19:23.624Z","updated":"2016-10-04T06:19:23.624Z","metadata":null,"synonyms":[]},{"value":"宮城","created":"2016-10-04T06:20:02.371Z","updated":"2016-10-04T06:20:02.371Z","metadata":null,"synonyms":[]},{"value":"宮崎","created":"2016-10-04T06:20:10.637Z","updated":"2016-10-04T06:20:10.637Z","metadata":null,"synonyms":[]},{"value":"富山","created":"2016-10-04T06:18:59.191Z","updated":"2016-10-04T06:18:59.191Z","metadata":null,"synonyms":[]},{"value":"山口","created":"2016-10-04T06:20:20.496Z","updated":"2016-10-04T06:20:20.496Z","metadata":null,"synonyms":[]},{"value":"山形","created":"2016-10-04T06:20:16.563Z","updated":"2016-10-04T06:20:16.563Z","metadata":null,"synonyms":[]},{"value":"山梨","created":"2016-10-04T06:20:27.283Z","updated":"2016-10-04T06:20:27.283Z","metadata":null,"synonyms":[]},{"value":"岐阜","created":"2016-10-04T06:17:50.881Z","updated":"2016-10-04T06:17:50.881Z","metadata":null,"synonyms":[]},{"value":"岡山","created":"2016-10-04T06:16:59.595Z","updated":"2016-10-04T06:16:59.595Z","metadata":null,"synonyms":[]},{"value":"岩手","created":"2016-10-04T06:16:40.879Z","updated":"2016-10-04T06:16:40.879Z","metadata":null,"synonyms":[]},{"value":"島根","created":"2016-10-04T06:18:30.877Z","updated":"2016-10-04T06:18:30.877Z","metadata":null,"synonyms":[]},{"value":"広島","created":"2016-10-04T06:19:38.397Z","updated":"2016-10-04T06:19:38.397Z","metadata":null,"synonyms":[]},{"value":"徳島","created":"2016-10-04T06:18:41.298Z","updated":"2016-10-04T06:18:41.298Z","metadata":null,"synonyms":[]},{"value":"愛媛","created":"2016-10-04T06:16:45.164Z","updated":"2016-10-04T06:16:45.164Z","metadata":null,"synonyms":[]},{"value":"愛知","created":"2016-10-04T06:16:12.728Z","updated":"2016-10-04T06:16:12.728Z","metadata":null,"synonyms":[]},{"value":"新潟","created":"2016-10-04T06:19:29.165Z","updated":"2016-10-04T06:19:29.165Z","metadata":null,"synonyms":[]},{"value":"東京","created":"2016-10-03T05:54:36.913Z","updated":"2016-10-03T05:54:53.054Z","metadata":null,"synonyms":["とうきょう","東京都"]},{"value":"栃木","created":"2016-10-04T06:18:47.632Z","updated":"2016-10-04T06:18:47.632Z","metadata":null,"synonyms":[]},{"value":"沖縄","created":"2016-10-03T06:32:08.037Z","updated":"2016-10-03T06:32:12.926Z","metadata":null,"synonyms":["おきなわ"]},{"value":"滋賀","created":"2016-10-04T06:18:15.995Z","updated":"2016-10-04T06:18:15.995Z","metadata":null,"synonyms":[]},{"value":"熊本","created":"2016-10-04T06:17:55.294Z","updated":"2016-10-04T06:17:55.294Z","metadata":null,"synonyms":[]},{"value":"石川","created":"2016-10-04T06:16:31.029Z","updated":"2016-10-04T06:16:31.029Z","metadata":null,"synonyms":[]},{"value":"神奈川","created":"2016-10-04T06:17:15.690Z","updated":"2016-10-04T06:17:15.690Z","metadata":null,"synonyms":[]},{"value":"福井","created":"2016-10-04T06:19:42.306Z","updated":"2016-10-04T06:19:42.306Z","metadata":null,"synonyms":[]},{"value":"福岡","created":"2016-10-04T06:19:46.204Z","updated":"2016-10-04T06:19:46.204Z","metadata":null,"synonyms":[]},{"value":"福島","created":"2016-10-04T06:19:50.400Z","updated":"2016-10-04T06:19:50.400Z","metadata":null,"synonyms":[]},{"value":"秋田","created":"2016-10-04T06:16:26.604Z","updated":"2016-10-04T06:16:26.604Z","metadata":null,"synonyms":[]},{"value":"群馬","created":"2016-10-04T06:18:00.033Z","updated":"2016-10-04T06:18:00.033Z","metadata":null,"synonyms":[]},{"value":"茨城","created":"2016-10-04T06:16:37.051Z","updated":"2016-10-04T06:16:37.051Z","metadata":null,"synonyms":[]},{"value":"長崎","created":"2016-10-04T06:19:02.952Z","updated":"2016-10-04T06:19:02.952Z","metadata":null,"synonyms":[]},{"value":"長野","created":"2016-10-04T06:19:07.350Z","updated":"2016-10-04T06:19:07.350Z","metadata":null,"synonyms":[]},{"value":"青森","created":"2016-10-04T06:16:21.055Z","updated":"2016-10-04T06:16:21.055Z","metadata":null,"synonyms":[]},{"value":"静岡","created":"2016-10-04T06:18:20.868Z","updated":"2016-10-04T06:18:20.868Z","metadata":null,"synonyms":[]},{"value":"香川","created":"2016-10-04T06:17:04.111Z","updated":"2016-10-04T06:17:04.111Z","metadata":null,"synonyms":[]},{"value":"高知","created":"2016-10-04T06:18:04.365Z","updated":"2016-10-04T06:18:04.365Z","metadata":null,"synonyms":[]},{"value":"鳥取","created":"2016-10-04T06:18:53.614Z","updated":"2016-10-04T06:18:53.614Z","metadata":null,"synonyms":[]},{"value":"鹿児島","created":"2016-10-04T06:17:09.051Z","updated":"2016-10-04T06:17:09.051Z","metadata":null,"synonyms":[]}],"created":"2016-10-03T05:54:29.463Z","updated":"2016-10-03T05:59:22.146Z","open_list":false,"description":null}],"language":"ja","metadata":null,"description":"Weather Company Data APIで天気予報","dialog_nodes":[{"go_to":null,"output":{"text":"<? input.text ?>!あいさつ以外に 天気予報が出来ます。(質問例:天気を教えて、東京の天気は?)"},"parent":null,"context":null,"created":"2016-11-19T13:26:42.726Z","metadata":null,"conditions":"#あいさつ","description":null,"dialog_node":"node_4_1479562007404","previous_sibling":"node_4_1475474627358"},{"go_to":null,"output":{"text":"$(place)の天気は1時間後には<? input.text ?>になりそうです。"},"parent":"node_5_1475474674293","context":null,"created":"2016-11-19T13:16:28.061Z","metadata":null,"conditions":"true","description":null,"dialog_node":"node_3_1479561392701","previous_sibling":null},{"go_to":null,"output":{"text":"weather.search"},"parent":"node_4_1475474627358","context":{"place":"@place"},"created":"2016-10-03T06:04:32.913Z","metadata":null,"conditions":"@place","description":null,"dialog_node":"node_5_1475474674293","previous_sibling":null},{"go_to":null,"output":{"text":"よくわかりません。もう一度言ってください(質問例:天気を教えて?、千葉の天気は?)"},"parent":null,"context":null,"created":"2016-10-03T01:17:45.854Z","metadata":null,"conditions":"anything_else","description":null,"dialog_node":"node_2_1475457466501","previous_sibling":"node_4_1479562007404"},{"go_to":null,"output":{"text":"こんにちは、あいさつと天気予報が出来ます。(質問例:こんにちは、天気は?、東京の天気は?)"},"parent":null,"context":null,"created":"2016-10-03T02:06:24.477Z","metadata":null,"conditions":"conversation_start","description":null,"dialog_node":"node_6_1475460385696","previous_sibling":null},{"go_to":{"return":null,"selector":"condition","dialog_node":"node_5_1475474674293"},"output":{},"parent":null,"context":null,"created":"2016-10-03T06:03:45.975Z","metadata":null,"conditions":"#天気","description":null,"dialog_node":"node_4_1475474627358","previous_sibling":"node_6_1475460385696"},{"go_to":{"return":null,"selector":"user_input","dialog_node":"node_5_1475474674293"},"output":{"text":"どこの天気ですか?(回答例:東京、千葉、北海道)"},"parent":"node_4_1475474627358","context":null,"created":"2016-11-19T13:11:59.121Z","metadata":null,"conditions":"true","description":null,"dialog_node":"node_1_1479561123876","previous_sibling":"node_5_1475474674293"}],"workspace_id":"dd5d8e91-49ca-46cd-b8c7-22eeea4d7a09"}

Conversation toolを起動します。
Conversation Serviceの「管理」タブから「Launch tool」ボタンを押して起動します。
nodered9.PNG

「Create」ボタンの右にある、「Import」ボタンを押します。
nodered10.PNG

先ほど保存した会話定義をImportします。
ImportのタイプはEverythingを選択します。「Import」ボタンを押します。
nodered11.PNG

Importが完了すると「天気予報」という名前のWorkspaceが出来るので、右上にあるメニューから「View details」を選択します。
nodered12.PNG

詳細画面では、WorkspaceIDが表示されます。
こちらのIDは後ほど使用しますので控えておいてください。
nodered13.PNG

4. SlackにBotを追加

以前の投稿で説明した"2. SlackにBotを追加"を実施してください(下記リンク参照)。
Bot作成後、BotのAPI Tokenは後ほど使用しますので控えておきます。
以前の投稿:会話エンジンにWatson Conversationを使ったSlack botを作ってみた

5. Node-REDフローの作成

Bluemixコンソールのアプリケーションの画面から「アプリ表示」ボタンを押して、Node-REDにアクセスします。
nodered14.PNG

「Go to your Node-RED flow editor」ボタンを押して、フローエディターを開きます。
nodered15.PNG

右上にあるメニューから、「Import」→「Clipboard」を選択し、下のNode-REDフロー定義を貼り付けます。
nodered16.PNG

Node-REDフロー定義
[{"id":"43908569.0dd2ec","type":"watson-conversation-v1","z":"4f545adf.c1ce54","name":"Watson Conversation","workspaceid":"","multiuser":false,"context":true,"x":354.25006103515625,"y":213.7142333984375,"wires":[["aa34f61e.c3abd8"]]},{"id":"18e9ea7e.6d77f6","type":"function","z":"4f545adf.c1ce54","name":"返答テキスト抽出","func":"msg.payload = msg.payload.output.text[0]\nreturn msg;","outputs":1,"noerr":0,"x":445.2501220703125,"y":337.9642333984375,"wires":[["84aec0d0.e007d"]]},{"id":"aa34f61e.c3abd8","type":"switch","z":"4f545adf.c1ce54","name":"アクション(外部API呼び出し)判定","property":"payload.output.text","propertyType":"msg","rules":[{"t":"eq","v":"weather.search","vt":"str"},{"t":"else"}],"checkall":"true","outputs":2,"x":187.75006103515625,"y":324.4642333984375,"wires":[["3ab74942.a298a6"],["18e9ea7e.6d77f6"]]},{"id":"3ab74942.a298a6","type":"function","z":"4f545adf.c1ce54","name":"都道府県名(エンティティ)抽出","func":"msg.payload = encodeURI(msg.payload.entities[0].value)\nreturn msg;","outputs":1,"noerr":0,"x":481.25,"y":295.7142333984375,"wires":[["adb754b8.876338"]]},{"id":"adb754b8.876338","type":"http request","z":"4f545adf.c1ce54","name":"地点名を経度・緯度に変換(with Google API)","method":"GET","ret":"obj","url":"https://maps.googleapis.com/maps/api/geocode/json?address={{payload}}&sensor=false","tls":"","x":791.3572387695312,"y":297.60711669921875,"wires":[["99def6ac.efece8"]]},{"id":"99def6ac.efece8","type":"function","z":"4f545adf.c1ce54","name":"経度・緯度抽出","func":"var location = msg.payload.results[0].geometry.location;\nvar lat = location.lat;\nvar lng = location.lng;\nmsg.payload = lat + \",\" + lng;\nreturn msg;","outputs":1,"noerr":0,"x":332.71435546875,"y":81,"wires":[["d7cc8e48.a381b"]]},{"id":"95cc8b2f.6af5f8","type":"function","z":"4f545adf.c1ce54","name":"1時間後の天気抽出","func":"msg.payload = msg.forecasts[0].phrase_32char;\nreturn msg;","outputs":1,"noerr":0,"x":694.7857666015625,"y":81,"wires":[["43908569.0dd2ec"]]},{"id":"d7cc8e48.a381b","type":"weather_insights","z":"4f545adf.c1ce54","name":"天気予報","service":"/forecast/hourly/48hour.json","geocode":"","units":"m","language":"ja","x":514.96435546875,"y":81.392822265625,"wires":[["95cc8b2f.6af5f8"]]},{"id":"c1be6300.b3c0c","type":"Slack Bot In","z":"4f545adf.c1ce54","name":"Slack In","apiToken":"","channel":"","x":72,"y":215.4642333984375,"wires":[["43908569.0dd2ec"]]},{"id":"84aec0d0.e007d","type":"Slack Bot Out","z":"4f545adf.c1ce54","name":"Slack out","apiToken":"","channel":"","x":643,"y":338.4642333984375,"wires":[]}]

Importすると以下のようなフローが作成されます。
このフローにBotのAPI TokenとWatson ConversationのWorkspace IDを設定します。
nodered17.PNG

「Slack In」のノードをクリックして開き、前のステップで控えておいたBot API Tokenを入力します。入力後、「Done」ボタンを押します。
nodered18.PNG
nodered19.PNG

「Slack Out」のノードも同様に、クリックして開き、前のステップで控えておいたBot API Tokenを入力します。入力後、「Done」ボタンを押します。
nodered20.PNG
nodered21.PNG

「Watson Conversation」のノードをクリックして、前のステップで控えておいたWorkspaceIDを入力します。入力後、「Done」ボタンを押します。
nodered22.PNG
nodered23.PNG

「Deploy」ボタンを押して、Node-REDフローをデプロイします。
nodered24.PNG

Node-REDのフローをデプロイ後、SlackのBotがactiveになります。
nodered27.PNG

DIRECT MESSAGESで何か話しかけると以下のような会話ができます。
nodered26.PNG

これで、Watson Conversationを使って天気予報をするSlack botが完成しました。

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
ユーザーは見つかりませんでした