-State transition was made using SQLite3 instead of XML
-When I tried to use the code of the book as it is for the official line, I could not retain the transition information, so I used SQLite3.
Make it possible to cancel the input like "Not Osaka". To the non-task version of the dialogue system made with python
w_system.py
import sys
from PySide2 import QtCore, QtScxml
import requests
import json
from datetime import datetime, timedelta, time
import sqlite3
DATES = ['today','tomorrow']
TYPES = ['weather','temperature']
#Dictionary for getting latitude and longitude from prefecture name
PLACES = {'Hokkaido': (43.06, 141.35), 'Aomori': (40.82, 140.74), 'Iwate': (39.7, 141.15), 'Miyagi': (38.27, 140.87),
'Akita': (39.72, 140.1), 'Yamagata': (38.24, 140.36), 'Fukushima': (37.75, 140.47), 'Ibaraki': (36.34, 140.45),
'Tochigi': (36.57, 139.88), 'Gunma': (36.39, 139.06), 'Saitama': (35.86, 139.65), 'Chiba': (35.61, 140.12),
'Tokyo': (35.69, 139.69), 'Kanagawa': (35.45, 139.64), 'Niigata': (37.9, 139.02), 'Toyama': (36.7, 137.21),
'Ishikawa': (36.59, 136.63), 'Fukui': (36.07, 136.22), 'Yamanashi': (35.66, 138.57), 'Nagano': (36.65, 138.18),
'Gifu': (35.39, 136.72), 'Shizuoka': (34.98, 138.38), 'Aichi': (35.18, 136.91), 'Triple': (34.73, 136.51),
'Shiga': (35.0, 135.87), 'Kyoto': (35.02, 135.76), 'Osaka': (34.69, 135.52), 'Hyogo': (34.69, 135.18),
'Nara': (34.69, 135.83), 'Wakayama': (34.23, 135.17), 'Tottori': (35.5, 134.24), 'Shimane': (35.47, 133.05),
'Okayama': (34.66, 133.93), 'Hiroshima': (34.4, 132.46), 'Yamaguchi': (34.19, 131.47), 'Tokushima': (34.07, 134.56),
'Kagawa': (34.34, 134.04), 'Ehime': (33.84, 132.77), 'Kochi': (33.56, 133.53), 'Fukuoka': (33.61, 130.42),
'Saga': (33.25, 130.3), 'Nagasaki': (32.74, 129.87), 'Kumamoto': (32.79, 130.74), 'Oita': (33.24, 131.61),
'Miyazaki': (31.91, 131.42), 'Kagoshima': (31.56, 130.56), 'Okinawa': (26.21, 127.68)}
current_weather_url = 'http://api.openweathermap.org/data/2.5/weather'
forecast_url = 'http://api.openweathermap.org/data/2.5/forecast'
appid = '6dbf61393fba9e88099d19dcdafc6c25' #Please enter your APP ID
def get_current_weather(lat,lon):
#Get weather information
response = requests.get("{}?lat={}&lon={}&lang=ja&units=metric&APPID={}".format(self.current_weather_url,lat,lon,self.appid))
return response.json()
def get_tomorrow_weather(lat,lon):
#Get time today
today = datetime.today()
#Get tomorrow's time
tomorrow = today + timedelta(days=1)
#Get tomorrow noon time
tomorrow_noon = datetime.combine(tomorrow, time(12,0))
#Convert to UNIX time
timestamp = tomorrow_noon.timestamp()
#Get weather information
response = requests.get("{}?lat={}&lon={}&lang=ja&units=metric&APPID={}".format(forecast_url,lat,lon,appid))
dic = response.json()
#Loop for weather information every 3 hours
for i in range(len(dic["list"])):
#i-th weather information (UNIX time)
dt = float(dic["list"][i]["dt"])
#The weather information will be returned when the data becomes data after noon tomorrow.
if dt >= timestamp:
return dic["list"][i]
return ""
def create_db(cur):
cur.execute('CREATE TABLE test(place STRING,date STRING, type STRING)')
def update_db(cur, text):
for place in PLACES:
if place in text:
cur.execute(f'INSERT INTO test values("{place}","","")')
for date in DATES:
if date in text:
cur.execute(f'INSERT INTO test values("", "{date}", "")')
for type_ in TYPES:
if type_ in text:
cur.execute(f'INSERT INTO test values("", "", "{type_}")')
def read_db(cur):
cur.execute('SELECT * FROM test')
data = cur.fetchall()
place, date, type_ = "","",""
for p, d, t in data:
place = p or place
date = d or date
type_ = t or type_
print(place,date,type_)
return place,date,type_
def clear_db():
dbname = "weather.db"
conn = sqlite3.connect(dbname)
cur = conn.cursor()
cur.execute('DROP TABLE test')
def reply_000(place,date,type_):
return 'What are your requirements?'
def reply_001(place,date,type_):
return 'Please tell me the prefecture and someday (today / tomorrow)'
def reply_011(place,date,type_):
return 'Please tell me the prefecture'
def reply_100(place,date,type_):
return 'Please tell me what (weather / temperature) you want to know someday (today / tomorrow)'
def reply_110(place,date,type_):
return 'What (weather / temperature) do you want to know'
def reply_101(place,date,type_):
return 'Please tell me someday (today / tomorrow)'
def reply_010(place,date,type_):
return 'Please tell me what prefecture you want to know (weather / temperature)'
def reply_111(place,date,type_):
print("place is",place)
lat = PLACES[place][0] #Get latitude from place
lon = PLACES[place][1] #Get longitude from place
print("lat=",lat,"lon=",lon)
#Clear table
clear_db()
if date == "today":
print("Today's weather forecast")
cw = get_current_weather(lat,lon)
if type_ == "weather":
return(cw["weather"][0]["description"]+"is")
elif type_ == "temperature":
return(str(cw["main"]["temp"])+"Degree")
elif date == "tomorrow":
tw = get_tomorrow_weather(lat,lon)
if type_ == "weather":
return(tw["weather"][0]["description"]+"is")
elif type_ == "temperature":
return (str(tw["main"]["temp"])+"Degree")
def start(text):
dbname = "weather.db"
conn = sqlite3.connect(dbname)
cur = conn.cursor()
if text == "start":
create_db(cur)
else:
update_db(cur,text)
conn.commit()
place,date,type_ = read_db(cur)
print(place,"Dao")
return place,date,type_
PATTERN = {
(False,False,False):reply_000,
(False,False,True):reply_001,
(False,True,True):reply_011,
(True,False,False):reply_100,
(True,True,False):reply_110,
(True,False,True):reply_101,
(False,True,False):reply_010,
(True,True,True):reply_111,
}
def apply(text):
place, date, type_ = start(text)
return PATTERN[place!="",date!="",type_!=""](place,date,type_)
main.py
from flask import Flask,request,abort
from linebot import LineBotApi,WebhookHandler
from linebot.exceptions import InvalidSignatureError
from linebot.models import MessageEvent,TextMessage,TextSendMessage
import os
import requests
import pprint
import w_system
app=Flask(__name__)
#Get environment variables
YOUR_CHANNEL_ACCESS_TOKEN = os.environ["YOUR_CHANNEL_ACCESS_TOKEN"]
YOUR_CHANNEL_SECRET = os.environ["YOUR_CHANNEL_SECRET"]
line_bot_api=LineBotApi(YOUR_CHANNEL_ACCESS_TOKEN)
handler=WebhookHandler(YOUR_CHANNEL_SECRET)
@app.route("/callback",methods=["POST"])
def callback():
print("Callback 1")
signature=request.headers["X-Line-Signature"]
print(signature)
body=request.get_data(as_text=True)
app.logger.info("Request body"+body)
try:
handler.handle(body,signature)
except InvalidSignatureError:
abort(400)
print('Callback')
return "OK"
@handler.add(MessageEvent,message=TextMessage)
def handle_message(event):
print('Handle message')
#Stores the entered character string
push_text = event.message.text
reply_text = w_system.apply(push_text)
#Description of reply part
line_bot_api.reply_message(event.reply_token,TextSendMessage(text=reply_text))
if __name__=="__main__":
port=int(os.getenv("PORT",5000))
app.run(host="0.0.0.0",port=port)
Recommended Posts