A program that failed when trying to create a linebot with reference to "Dialogue system made with python"

12/26 was done

I tried to make the weather forecast on the official line by referring to the weather forecast bot of the book "Dialogue system made with python".

An incomplete weather forecast program that could not retain state transition information

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

What I thought

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.

What I tried

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)....... 

result

No change.

What i don't understand

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.)

Programs

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

A program that failed when trying to create a linebot with reference to "Dialogue system made with python"
A story that I was addicted to when I made SFTP communication with python
A story that failed when trying to remove the suffix from the string with rstrip
[python] A note when trying to use numpy with Cython
Let's create a program that automatically registers ID/PW from CSV to Bitwarden with Python + Selenium
[Python] A program that creates stairs with #
[Python] Create a LineBot that runs regularly
I tried to create a program to convert hexadecimal numbers to decimal numbers with python
[Python / Pandas] A bug occurs when trying to replace a DataFrame with `None` with` replace`
I get a UnicodeDecodeError when trying to connect to oracle with python sqlalchemy
Procedure for creating a LineBot made with Python
Create a page that loads infinitely with python
Steps to create a Twitter bot with python
When I tried to create a virtual environment with Python, it didn't work
I tried to easily create a fully automatic attendance system with Selenium + Python
I made a system that automatically decides whether to run tomorrow with Python and adds it to Google Calendar.
I made a Twitter BOT with GAE (python) (with a reference)
From buying a computer to running a program with python
A program to write Lattice Hinge with Rhinoceros with Python
[Python] How to create a 2D histogram with Matplotlib
[Python] Create a Tkinter program distribution file with cx_Freeze
A story that required preparation when trying to do a Django tutorial with plain centos7
A story that got stuck when trying to upgrade the Python version on GCE
I made a program to convert images into ASCII art with Python and OpenCV
I got stuck when trying to specify a relative path with relative_to () in python
A memo of misunderstanding when trying to load the entire self-made module with Python3
Try to create a waveform (audio spectrum) that moves according to the sound with python
A story that stumbled when I made a chatbot with Transformer
Error and solution when trying to run a classifier made with Labellio with my own ubuntu
Create a Mastodon bot with a function to automatically reply with Python
I made a package to filter time series with python
I wrote a program quickly to study DI with Python ①
When writing to a csv file with python, a story that I made a mistake and did not meet the delivery date
[Python] Create a linebot that draws any date on a photo
Let's create a script that registers with Ideone.com in Python.
Probably the easiest way to create a pdf with Python3
[Tips] Dealing with errors that occur when trying to install Python 3 series less than 3.5.3 with pyenv
Use a macro that runs when saving python with vscode
Summary of points to keep in mind when writing a program that runs on Python 2.5
Create a message corresponding to localization with python translation string
Create a directory with python
[Python] Create a program to delete line breaks in the clipboard + Register as a shortcut with windows
A story that didn't work when I tried to log in with the Python requests module
Create a program that can generate your favorite images with Selenium
How to batch start a python program created with Jupyter notebook
I made a library to easily read config files with Python
IPynb scoring system made with TA of Introduction to Programming (Python)
I made a package that can compare morphological analyzers with Python
I want to use a wildcard that I want to shell with Python remove
A story about adding a REST API to a daemon made with Python
[Python] A memo that I tried to get started with asyncio
Try to create a python environment with Visual Studio Code & WSL
Don't you want to say that you made a face recognition program?
I tried to create a list of prime numbers with python
How to create a heatmap with an arbitrary domain in Python
[Ev3dev] Create a program that captures the LCD (screen) using python
I made a shuffle that can be reset (reverted) with Python
[LINE Messaging API] Create a BOT that connects with someone with Python
I tried to create Bulls and Cows with a shell program
Create a poster with matplotlib to visualize multiplication tables that remember multiplication
"Value Error: Unable to configure handler'file_output_handler'" when starting a python program