#概要
lineにてdocomo APIによる画像認識を行い、送った写真から製品を判断し想定される製品のAmazonサイトを紹介するbotです。
#結果
想定していたよりも画像認識技術が高性能でした。
このように商品のパッケージの写真を撮ってbotに送信する。
画像から推定される商品を3つ表示するようにしました。
最大で10つの推定される商品の情報を取得可能です。
docomoAPIによりその商品のamazon urlを取得できるため「Amazonで見る」をクリックするとそのページに飛べる機能を作成できます。
以下の画像のように、写真の一部分に商品が写っている写真(スクショ等)でも商品の判定を行ってくれました。ただし、一番目の候補には別の商品が判定されました、、、
商品が判定されてなかった場合は、「見つかりませんでした。」のメッセージが表示されるようにしました。
また、メッセージを送っても何も返事がないのは寂しいので、recruitAPIのTalkAPI機能を実装し、メッセージに答えてくれるようになっています。
#ソースコード
Github
#参考
linebotを作成する際に、以下のサイトがとても参考になりました。
Django+HerokuでLINE Messaging APIのおそ松botを作るまで
LINE Messaging APIとPythonを使ってChatbotを作ってみた
#環境
アプリケーションフレームワークにはDjangoを使用し、herokuにてサーバーを立てました。
Os:macOS Sierra
Python:Python 3.6.1
Django:1.11.5
#作成方法
すでにline bot、docomoAPIの使い方や、herokuサーバーの構築方法はたくさんの記事があるため、
作成したview.pyのみ説明します。
全コードはgithubを参照ください。
# Reply text
def reply_text(reply_token, rep_meg):
payload = {
"replyToken": reply_token,
"messages": [
{
"type": "text",
"text": rep_meg
}
]
}
reply
requests.post(REPLY_ENDPOINT, headers=HEADER, data=json.dumps(payload)) # to send data to LINE
return rep_meg
# Save image
def save_image(messegeid):
message_content = lINE_BOT_API.get_message_content(messegeid)
i = Image.open(BytesIO(message_content.content))
filename = '/tmp/' + messegeid + '.jpg'
i.save(filename)
return filename
# Get json
def get_json(filename):
with open(filename, mode='rb') as f:
result = requests.post(
url=__build_url('recognize'),
params={'APIKEY': docomoapikey, 'recog': 'product-all', 'numOfCandidates': 5},
data=f,
headers={'Content-Type': 'application/octet-stream'})
result.raise_for_status()
result = result.json()
return result
reply_test・・・ユーザが送信したメッセージを元に、recruitAPIのtalk機能より
得られたメッセージを返します。request post を行う。
save_image・・・ユーザが送信した画像をサーバ側で取得します。
get_jshon・・・docomoAPIの画像認識機能より商品の情報(jshon)を取得します。
# Reply carousel
def post_carousel(reply_token,imageUrl,title,brand,releaseDate,maker,url,itmeName):
payload = {
"replyToken":reply_token,
"messages":[
{
"type": "template",
"altText": "商品結果",
"template": {
"type": "carousel",
"columns": [
{
"thumbnailImageUrl": imageUrl[0],
"title": itmeName[0],
"text": "ブランド名:" + brand[0] + " メーカー名:"+ maker[0] +" 発売日:" +releaseDate[0],
"actions": [
{
"type": "uri",
"label": "Amazonで見る",
"uri": url[0]
}
]
},
{
"thumbnailImageUrl": imageUrl[1],
"title": itmeName[1],
"text": "ブランド名:" + brand[1] + " メーカー名:"+ maker[1] +" 発売日:" +releaseDate[1],
"actions": [
{
"type": "uri",
"label": "Amazonで見る",
"uri": url[1]
}
]
},
{
"thumbnailImageUrl": imageUrl[2],
"title": itmeName[2],
"text": "ブランド名:" + brand[2] + " メーカー名:"+ maker[2] +" 発売日:" +releaseDate[2],
"actions": [
{
"type": "uri",
"label": "Amazonで見る",
"uri": url[2]
}
]
}
]
}
}
]
}
req = requests.post(REPLY_ENDPOINT, headers=HEADER, data=json.dumps(payload))
return title[0]
画像判定された商品の結果をTemplate Message機能を使って表示します。
表示する情報は、商品イメージ、商品名、ブランド名、メーカー名、発売日、amazonurlへのアクセスとしました。そのほかにも、重さ、サイズ、等を取得し表示できます。
def callback(request):
reply = ""
request_json = json.loads(request.body.decode('utf-8')) # to get json
for e in request_json['events']:
reply_token = e['replyToken'] # to get reply_token
message_type = e['message']['type'] # to get type
# reply for test
if message_type == 'text':
text = e['message']['text'] # to get message
rep_meg = client.talk(text)["results"][0]["reply"] # to get reply message by recuitTalk
reply += reply_text(reply_token, rep_meg)
# reply for image
if message_type == 'image':
messegeid = e['message']['id'] # to get messageID
filename = save_image(messegeid)
result = get_json(filename)
if (result.get('candidates') != None):
imageUrl,title,brand,releaseDate,maker,url,itemName =[],[],[],[],[],[],[]
for i in range(0,3): # to get item info
imageUrl.append(result['candidates'][i]['imageUrl'])
title.append(result['candidates'][i]['sites'][0]['title'])
brand.append(result['candidates'][i]['detail']['brand'])
releaseDate.append(result['candidates'][i]['detail']['releaseDate'])
maker.append(result['candidates'][0]['detail']['maker'])
url.append(result['candidates'][i]['sites'][0]['url'])
itemName.append(result['candidates'][i]['detail']['itemName'][0:29]) # to restrict length
reply += post_carousel(reply_token,imageUrl,title,brand,releaseDate,maker,url,itemName)
else:
rep_meg = "お探しのものは見つかりませんでした。"
reply += reply_text(reply_token, rep_meg)
return HttpResponse(reply) # for test
ユーザがテキストを送信したか画像を送信したか判定をし、それぞれにおいてrequest post
する処理です。
#まとめ
すでにたくさんのlinebotについて記事があり、一度自身で作成したいと思い作成に至った。docomoAPIの画像認識を用いて作成したところ、思っていた以上に性能が良かったため、それについて伝えたく記事を書いて見ました。