When I ran the program below, the state transition did not go well. linebot> Please enter the place name
User> Nara Prefecture
linebot> Please enter the date
User> Today
linebot> Please enter the place name
Since it has transitioned from ask_place to ask_date once by sending the place name ・ Transition information cannot be retained -The transition information is initialized every time a message is received from the user. It may be either.
In weather_system1.py, every time the reply method is called, sm.start () transitions to the initial state, so when sm.activeStateNames () is empty, it transitions to the initial state.
def reply(self, push_text):
sm = QtScxml.QScxmlStateMachine.fromFile('states.scxml')
if sm.activeStateNames() == []:
sm.start()
self.el.processEvents()
else:
text = push_text
self.sessiondic = {"statemachine":sm, "place":"", "date":"", "type":""}
current_state = sm.activeStateNames()[0]
print("current_state=", current_state).......
No change.
How to make state transitions through conversation. Whether there is a dispatcher or idle of python-telegram-bot in line-bot-sdk. (I searched for it, but I'm not good at English, so I might miss it.)
weather_system1.py
import sys
from PySide2 import QtCore, QtScxml
import requests
import json
from datetime import datetime, timedelta, time
class WeatherSystem:
#List of prefecture names
prefs = ['Triple', 'Kyoto', 'Saga', 'Hyogo', 'Hokkaido', 'Chiba', 'Wakayama', 'Saitama', 'Oita',
'Osaka', 'Nara', 'Miyagi', 'Miyazaki', 'Toyama', 'Yamaguchi', 'Yamagata', 'Yamanashi', 'Gifu', 'Okayama',
'Iwate', 'Shimane', 'Hiroshima', 'Tokushima', 'Ehime', 'Aichi', 'Niigata', 'Tokyo',
'Tochigi', 'Okinawa', 'Shiga', 'Kumamoto', 'Ishikawa', 'Kanagawa', 'Fukui', 'Fukuoka', 'Fukushima', 'Akita',
'Gunma', 'Ibaraki', 'Nagasaki', 'Nagano', 'Aomori', 'Shizuoka', 'Kagawa', 'Kochi', 'Tottori', 'Kagoshima','ksjgihurhtknskhifhsignrw22']
#Dictionary for getting latitude and longitude from prefecture name
latlondic = {'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)}
#A dictionary that links states and system utterances
uttdic = {"ask_place": "Please say the place name",
"ask_date": "Please say the date",
"ask_type": "Please tell me the information type"}
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 __init__(self):
#Magic about Qt
app = QtCore.QCoreApplication()
#Dictionary for managing dialogue sessions
self.sessiondic = {}
#A function that extracts prefecture names from text. If not found, an empty string is returned.
def get_place(self, text):
for pref in self.prefs:
if pref in text:
print(pref)
return pref
elif pref == 'ksjgihurhtknskhifhsignrw22':
return ""
else:
continue
#If the text has "today" or "tomorrow", it is returned. If not found, an empty string is returned.
def get_date(self, text):
if "today" in text:
return "today"
elif "tomorrow" in text:
return "tomorrow"
else:
return ""
#If the text has "weather" or "temperature", it is returned. If not found, an empty string is returned.
def get_type(self, text):
if "weather" in text:
return "weather"
elif "temperature" in text:
return "temperature"
else:
return ""
def get_current_weather(self, 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(self, 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(self.forecast_url,lat,lon,self.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 initial_message(self):
self.el = QtCore.QEventLoop()
#Read SCXML file
sm = QtScxml.QScxmlStateMachine.fromFile('states.scxml')
#A dictionary containing session IDs and session-related information
self.sessiondic = {"statemachine":sm, "place":"", "date":"", "type":""}
#Transition to the initial state
sm.start()
self.el.processEvents()
#Get the initial state
current_state = sm.activeStateNames()[0]
print("current_state=", current_state)
#Acquisition and output of system utterances linked to the initial state
sysutt = self.uttdic[current_state]
return {"utt":"This is a weather information guidance system." + sysutt, "end":False}"""
def reply(self, push_text):
self.el = QtCore.QEventLoop()
#Read SCXML file
sm = QtScxml.QScxmlStateMachine.fromFile('states.scxml')
#A dictionary containing session IDs and session-related information
self.sessiondic = {"statemachine":sm, "place":"", "date":"", "type":""}
#Transition to the initial state
sm.start()
self.el.processEvents()
print('It's cool so far')
text = push_text
self.sessiondic = {"statemachine":sm, "place":"", "date":"", "type":""}
current_state = sm.activeStateNames()[0]
print("current_state=", current_state)
#State transition using user input
if current_state == "ask_place":
place = self.get_place(text)
if place != "":
sm.submitEvent("place")
self.el.processEvents()
self.sessiondic["place"] = place
print('Cheeks')
print("current_state=", current_state)
elif current_state == "ask_date":
date = self.get_date(text)
if date != "":
sm.submitEvent("date")
self.el.processEvents()
self.sessiondic["date"] = date
print('Hehehe')
print("current_state=", current_state)
elif current_state == "ask_type":
_type = self.get_type(text)
if _type != "":
sm.submitEvent("type")
self.el.processEvents()
self.sessiondic["type"] = _type
#Get the state of the transition destination
current_state = sm.activeStateNames()[0]
print("current_state=", current_state)
#The transition destination is tell_In the case of info, tell the information and finish
if current_state == "tell_info":
utts = []
utts.append("I will tell you")
place = self.sessiondic["place"]
date = self.sessiondic["date"]
_type = self.sessiondic["type"]
lat = self.latlondic[place][0] #Get latitude from place
lon = self.latlondic[place][1] #Get longitude from place
print("lat=",lat,"lon=",lon)
if date == "today":
cw = self.get_current_weather(lat,lon)
if _type == "weather":
utts.append(cw["weather"][0]["description"]+"is")
elif _type == "temperature":
utts.append(str(cw["main"]["temp"])+"Degree")
elif date == "tomorrow":
tw = self.get_tomorrow_weather(lat,lon)
if _type == "weather":
utts.append(tw["weather"][0]["description"]+"is")
elif _type == "temperature":
utts.append(str(tw["main"]["temp"])+"Degree")
utts.append("Thank you for using")
del self.sessiondic
return {"utt":"。".join(utts), "end": True}
else:
#For other transition destinations, generate system utterances associated with the state
sysutt = self.uttdic[current_state]
return {'utt':sysutt,'end':False}
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
from weather_system1 import WeatherSystem
import weather_system1
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)
weather = WeatherSystem()
@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
#weather_system1.Weather in py_Instantiate the system class
reply_text = weather.reply(push_text)["utt"]
#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)
state.scxml
<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" initial="ask_place">
<state id="ask_place">
<transition event="place" target="ask_date"/>
</state>
<state id="ask_date">
<transition event="date" target="ask_type"/>
</state>
<state id="ask_type">
<transition event="type" target="tell_info"/>
</state>
<final id="tell_info"/>
</scxml>
Recommended Posts