Linebot Django 2
LINE BOT Message 初學者記錄(二)Permalink
參考 LINE 官方網站提供新的 API referense Create LINE@ Manager account from LINE Business Center > Messaging API LINE Developer Set Webhook URL and get Channel Access Token
Process Picture:Permalink
Code:Permalink
views.py
import json | |
import sys | |
import re | |
import urllib.request | |
import urllib.error | |
from os import path | |
import random | |
from urllib.parse import quote | |
from django.http import HttpResponse | |
from django.views.decorators.csrf import csrf_exempt | |
_weather_record_status={} | |
def record_weather_userid(userid): | |
status_value = 'weather' | |
if userid in _weather_record_status.keys(): | |
print("waiting_weather_status") | |
return status_value | |
else: | |
print("new_weather_status") | |
_weather_record_status[userid] = status_value | |
return status_value | |
def weather_w_judgment(userid, text): | |
if userid in _weather_record_status.keys(): | |
text = "weather " + text | |
return text | |
else: | |
return text | |
def del_weather_userid(userid): | |
if userid in _weather_record_status.keys(): | |
del _weather_record_status[userid] | |
def test_weather(reuest, location): | |
_weather_pic = _weather(location) | |
return HttpResponse(_weather_pic["_weather_pic"]) | |
def _cal_news_article_nums(): | |
req = urllib.request.urlopen( | |
"https://newsapi.org/v1/articles?source=techcrunch&apiKey=Ericbalabababa_key") | |
req_decode = req.read().decode() | |
req_object = json.loads(req_decode) | |
all_articles = (req_object)['articles'] | |
articles_num = len(all_articles) | |
if articles_num > 4 : | |
articles_num = 4 | |
return articles_num | |
else: | |
articles_num = articles_num | |
return articles_num | |
def _get_news(): | |
req = urllib.request.urlopen( | |
"https://newsapi.org/v1/articles?source=techcrunch&apiKey=Ericbalabababa_key") | |
req_decode = req.read().decode() | |
req_object = json.loads(req_decode) | |
news_object = req_object | |
return news_object | |
def _news(news_object, i): | |
_title ='{:.40}'.format(news_object['articles'][i]['title']) | |
_description ='{:.59}'.format(news_object['articles'][i]['description']) | |
_urlToImage = news_object['articles'][i]['urlToImage'] | |
_url = news_object['articles'][i]['url'] | |
return {"_title":_title, "_description":_description, "_urlToImage": _urlToImage, "_url":_url} | |
def _weather(location): | |
utf_location=quote(location) #request to weather need be UTF8 (E.g.enter chonese) | |
req = urllib.request.urlopen( | |
"http://api.openweathermap.org/data/2.5/weather?APPID=Ericbalabababa_ID" | |
% utf_location) | |
req_decode = req.read().decode('utf-8') | |
req_object = json.loads(req_decode) | |
_country='{:.2}'.format(req_object['sys']['country']) | |
_weather_pic='{:.10}'.format(req_object['weather'][0]['main']) | |
_temperature='{:.1f}'.format(req_object['main']['temp'] - 273.15) | |
return {"_country":_country, "_weather_pic":_weather_pic, "_temperature":_temperature} | |
def weather_picture(request, weather, size): | |
BASE_DIR = path.dirname(path.dirname(path.abspath(__file__))) | |
image_path='app/weather_image' | |
full_path=path.join(BASE_DIR ,image_path, weather, size+".jpg") | |
with open(full_path, "rb") as read_file: | |
return HttpResponse(read_file.read(), content_type="image/jpeg") | |
def whattoeat_picture(request, choose, random_num, size): | |
BASE_DIR = path.dirname(path.dirname(path.abspath(__file__))) | |
image_path='app/whattoeat_image' | |
full_path=path.join(BASE_DIR ,image_path,choose,random_num, size+".jpg") | |
with open(full_path, "rb") as read_file: | |
return HttpResponse(read_file.read(), content_type="image/jpeg") | |
def button_picture(request, button, size): | |
BASE_DIR = path.dirname(path.dirname(path.abspath(__file__))) | |
image_path='app/button_image' | |
full_path=path.join(BASE_DIR ,image_path, button, size+".jpg") | |
with open(full_path, "rb") as read_file: | |
return HttpResponse(read_file.read(), content_type="image/jpeg") | |
@csrf_exempt | |
def elapp(request): | |
input_type = _paser_input_type(request) # type message or postback | |
print("-------------",input_type) | |
if input_type == 'message': | |
(token, text, userid)=_decode_json(request) | |
text = weather_w_judgment(userid, text) #judge input weather button or not | |
_pasered_input = _paser_input_text(text) | |
if _pasered_input == "userid": | |
payload = echo_payload(token, userid) | |
result = _to_LINE_server(payload) | |
elif _pasered_input == "Cheap_Food" or _pasered_input == "Delicious_Food": | |
payload = food_payload(token, text) | |
result = _to_LINE_server(payload) | |
elif _pasered_input == text: | |
payload = echo_payload(token, text) | |
result = _to_LINE_server(payload) | |
else: | |
payload = weather_payload(token, _pasered_input) | |
result = _to_LINE_server(payload) | |
del_weather_userid(userid) # del user id from dictionary | |
else: #postback event | |
(token, postback_data, userid) = _decode_postback_json(request) | |
if postback_data == "get_weather": | |
print("to get_weather") | |
status_value = record_weather_userid(userid) #always return weather and add userid | |
print(status_value) | |
payload = _reply_weather_payload(token) | |
result = _to_LINE_server(payload) | |
elif postback_data == 'get_eat': | |
payload = _reply_food_HL_payload(token) | |
result = _to_LINE_server(payload) | |
elif postback_data == 'get_news': | |
payload = _reply_news_payload(token) | |
print("---------news_payload",payload) | |
result = _to_LINE_server(payload) | |
else: | |
print("not support") | |
if request.method == 'GET': | |
return HttpResponse("GET") | |
elif request.method == 'POST': | |
return HttpResponse(json.dumps(result)) | |
def _paser_input_type(request): | |
body_unicode = request.body.decode('utf-8') #亂碼變正常 | |
body = json.loads(body_unicode) #JSON 文字轉物件 | |
input_type = body["events"][0]["type"] # LINE message from client msg type | |
return input_type | |
def _paser_input_text(_text): | |
text_split = _text.split() | |
first_split = text_split[0] #from user text | |
if first_split == 'weather' or first_split == 'Weather' or first_split == 'WEATHER' or first_split == 'W' or first_split == 'w': | |
location = text_split[1] | |
return _weather(location) | |
elif first_split == 'userid' or first_split == 'userId' or first_split == 'UserId': | |
return "userid" | |
else: | |
return _text | |
def _decode_json(request): | |
body_unicode = request.body.decode('utf-8') #亂碼變正常 | |
body = json.loads(body_unicode) #JSON 文字轉物件 | |
_token=body["events"][0]["replyToken"] # LINE message from client | |
_text=body["events"][0]["message"]["text"] # LINE message from client | |
_userid=body["events"][0]["source"]["userId"] | |
return (_token, _text, _userid) | |
def _decode_postback_json(request): | |
body_unicode = request.body.decode('utf-8') #亂碼變正常 | |
body = json.loads(body_unicode) #JSON 文字轉物件 | |
_token=body["events"][0]["replyToken"] # LINE token from client | |
_postback_data=body["events"][0]["postback"]["data"] # LINE postback from client | |
_userid=body["events"][0]["source"]["userId"] | |
return (_token, _postback_data, _userid) | |
def echo_payload(_token, _text): | |
payload = { | |
"replyToken": _token, | |
"messages":[ | |
{ | |
"type": "template", | |
"altText": "this is a button template", | |
"template": { | |
"type": "buttons", | |
"thumbnailImageUrl": "https://Ericbalabababa_URL/button_picture/pumpkin/240.jpg", | |
"title": "I want to search", | |
"text": "Echo: %s" % _text, | |
"actions": [ | |
{ | |
"type": "postback", | |
"label": "Weather", | |
"data": "get_weather" | |
}, | |
{ | |
"type": "postback", | |
"label": "Eat", | |
"data": "get_eat" | |
}, | |
{ | |
"type": "postback", | |
"label": "News", | |
"data": "get_news" | |
} | |
] | |
} | |
} | |
] | |
} | |
return payload | |
def weather_payload(_token, _text): | |
all_weather = ["Wind", "Clouds", "Snow", "Rain", "Sun", "Clear"] | |
weather_string="It's " + _text["_temperature"] + "C and " + _text["_weather_pic"] +" in "+ _text["_country"] | |
print(weather_string) | |
weather = _text["_weather_pic"] | |
if weather in all_weather: | |
weather = weather | |
else: | |
weather = '404' | |
payload = { | |
"replyToken": _token, | |
"messages":[ | |
{ | |
"type":"text", | |
"text":weather_string | |
}, | |
{ | |
"type": "image", | |
"originalContentUrl": | |
"https://Ericbalabababa_URL/weather_picture/%s/1024.jpg" %weather, | |
"previewImageUrl": | |
"https://Ericbalabababa_URL/weather_picture/%s/240.jpg" %weather | |
} | |
] | |
} | |
return payload | |
def _reply_weather_payload(_token): | |
payload = { | |
"replyToken": _token, | |
"messages":[ | |
{ | |
"type":"text", | |
"text":"Enter a city name." | |
} | |
] | |
} | |
print("_reply_weather_payload") | |
return payload | |
def _reply_food_HL_payload(_token): | |
payload = { | |
"replyToken": _token, | |
"messages":[ | |
{ | |
"type": "template", | |
"altText": "this is a confirm template", | |
"template": { | |
"type": "confirm", | |
"text": "Choose food", | |
"actions": [ | |
{ | |
"type": "message", | |
"label": "Cheap", | |
"text": "Cheap_Food" | |
}, | |
{ | |
"type": "message", | |
"label": "Delicious", | |
"text": "Delicious_Food" | |
} | |
] | |
} | |
} | |
] | |
} | |
return payload | |
def food_payload(token, text): | |
random_num = random.randint(1,6) | |
print("FOOD_RANDOM_NUM--------------",random_num) | |
choose = text | |
payload = { | |
"replyToken": token, | |
"messages":[ | |
{ | |
"type": "image", | |
"originalContentUrl": | |
"https://el-server.azurewebsites.net/whattoeat_picture/{0}/{1}/1024.jpg".format(choose,random_num), | |
"previewImageUrl": | |
#"https://el-server.azurewebsites.net/whattoeat_picture/Delicious_Food/1/240.jpg" | |
"https://el-server.azurewebsites.net/whattoeat_picture/{0}/{1}/240.jpg".format(choose,random_num) | |
} | |
] | |
} | |
return payload | |
def _reply_news_payload(token): | |
articles_num = _cal_news_article_nums() | |
news_object = _get_news() #只取一次比較快 | |
_columns = [] | |
for i in range(articles_num): | |
news = _news(news_object, i) # 0, 1, 2, 3, 4 | |
title = news["_title"] | |
description = news["_description"] | |
urltoimage = news["_urlToImage"] | |
url = news["_url"] | |
_columns[len(_columns):] = [ | |
{ | |
"thumbnailImageUrl": urltoimage, | |
"title": title, | |
"text": description, | |
"actions": [ | |
{ | |
"type": "uri", | |
"label": "View detail", | |
"uri": url | |
} | |
] | |
} | |
] | |
payload = { | |
"replyToken": token, | |
"messages":[ | |
{ | |
"type": "template", | |
"altText": "this is a carousel template", | |
"template": { | |
"type": "carousel", | |
"columns": _columns | |
} | |
} | |
] | |
} | |
return payload | |
def _to_LINE_server(payload): | |
payload = payload | |
req=urllib.request.Request("https://api.line.me/v2/bot/message/reply", | |
data=json.dumps(payload).encode('utf8'), | |
headers={ | |
"Content-type": "application/json; charset=UTF-8", | |
"Authorization": "Bearer Ericbalabababa_ID", | |
}) | |
try: | |
with urllib.request.urlopen(req) as response: | |
print(response.read()) | |
except urllib.error.HTTPError as err: | |
print(err) |
Result:Permalink
Request: here
Response : Hello, I am Nanguachumo.
Type ‘w cityname’ get weather! here Request: w london
Response : Current country: GB Current weather: Rain Current tempearture: 12.12
小撇步:Permalink
- 練習時, 一樣先跑 local server, 透過 REST 發出 POST + content, 做初步判斷程式碼有錯誤否.
Next:Permalink
- ㄧ些 Function 看起來不只做ㄧ件事呀!, 要讓 function 都可被重覆使用
- 圖片不知為何電腦 LINE 無法顯示
- Template & Confirm 官方回應目前 IOS 無法正常顯示, 下ㄧ版更新後即可正常
Reference:Permalink
Get knowhow:Permalink
- Azure run Django 無法正常使用 Static. 故強制於 urls.py 直接指定 load picture.
- Azure local Git 不知為何有時 Clone 會失敗…
- Line official 晚上 9點 可能 server 繁忙無法正常發送訊息
- Python - re module
- Python - “’”, “””, “”””” 有點不一樣
- Python - NoneType not equal ‘None’
心得:Permalink
- 純練習寫小程式, 95% 時間花在debug
Leave a comment