《编程思维与实践》大作业之聊天机器人TeruBot

《编程思维与实践》大作业之聊天机器人TeruBot

本次李骏老师的《编程思维与实践》大作业要求编写一个简易的聊天机器人,我的代码在原有基础上增加了一些情感分析、天气预报等功能,详见注释,代码仅供参考。

import random
import json
import requests                             # Getting HTTP Data
import tushare                              # Stock Market Data
import pandas
import csv
from simpleeval import simple_eval          # Expression Evaluation
from datetime import datetime
from time import sleep
from termcolor import colored               # Coloring Terminal
from textblob import TextBlob               # English Analysis
from snownlp import SnowNLP                 # Chinese Analysis
from math import sin, cos, tan, sinh, cosh, tanh,\
                sqrt, exp, log, log10, pow,\
                asin, acos, atan, asinh, acosh, atanh
from math import pi, e

# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #
# It Will take some time to initializing at the beginning of running #
# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! #

#########################################################
# Teruteru is a cute paper toy                          #
# popular in China and Japanese to pray for a sunny day #
#########################################################

#########################################################
################  Defination of Abstract Classes
#########################################################

class Chat:
    usrName = "Me"

    def __init__(self):
        self.rsp = ""

    def _thinking(self):
        # Waiting for 0.6~1.2 sec beforing responding
        sleep(random.uniform(0.6, 1.2)) 

    def chat(self):
        self._botTime(f"{self.rsp}\n")

    def _usrTime(self):
        print(f"{Chat.usrName}:", end="")
        return input()

    def _botTime(self, rsp):
        self._thinking()
        print(colored(f"Bot:{rsp}", 'blue'))

class Question(Chat):
    def _respond(self, ans):
        pass

    def chat(self):
        self._botTime(self.rsp)
        self._respond(self._usrTime())
        print("")

class Gossip(Chat):
    def __init__(self):
        self.rsp = ""

#########################################################
################  Defination of Gossip
#########################################################

class Hello(Gossip):
# Say hello to the user
    def __init__(self):
        self.rsp = "Hello! I'm Teru Bot. Let's have a chat!"

class Bye(Gossip):
# Say goodbye to the user
    def __init__(self):
        self.rsp = "Have a good time with you. Looking forward to chatting with you next time!"

class Weather(Gossip):
# Get weather forecast from the Internet
    def _getWeather(self):
        shJson = requests.get("http://wthrcdn.etouch.cn/weather_mini?city=%E4%B8%8A%E6%B5%B7")
        shJson.encoding='utf-8'
        sh = json.loads(shJson.text)
        return f"Oh, I just heard about some weather information. The weather in {sh['data']['city']} will be {sh['data']['forecast'][0]['type']}, and the temperature will be {sh['data']['forecast'][0]['high']} and {sh['data']['forecast'][0]['low']}. It suggested that {sh['data']['ganmao']}"

    def __init__(self):
        self.rsp = self._getWeather()

class Stock(Gossip):
# Get SH and SZ stock market's index from Internet
    def _drpIcs(self, num):
        if num < 0:
            return f"dropped by {-num}%"
        else:
            return f"increased by {num}%"

    def _getStock(self):
        idx = tushare.get_index()
        return f"Hey, are you interested in stock market? Now the SH index is {idx.at[0, 'close']}, {self._drpIcs(idx.at[0, 'change'])}, and the SZ index is {idx.at[19, 'close']}, {self._drpIcs(idx.at[19, 'change'])}. It's so attractive, right?"

    def __init__(self):
        self.rsp = self._getStock()

class Lyrics(Gossip):
# Randomly print a lyric
    def _chooseLyrics(self):
        lyrics = ["东方红,太阳升,中国出了个毛泽东...",\
                "Every time I'm feeling down, I can hear you say...",\
                "Country road, take me home...",\
                "I want something just like this, dododo dododo...",\
                "时のかくれんぼ、はぐれっこはもういやなんだ...",\
                "君の前前前世から仆は、君を探しはじめたよ...",\
                "今天只有残留的躯壳,迎接光辉岁月...",\
                "原谅我这一生不羁放纵爱自由..."]
        return f"{random.choice(lyrics)} Are you hearing this song? I'm very fond of it!"

    def __init__(self):
        self.rsp = self._chooseLyrics()

#########################################################
################  Defination of Problem
#########################################################

class AskName(Question):
# Ask name of the user
    def __init__(self):
        self.rsp = "At first, what's your name?"

    def _respond(self, ans):
        Chat.usrName = ans      # Change the user's name of displaying
        self._botTime(f"All right, Nice to meet you, {Chat.usrName}.")

class ComeFrom(Question):
# Ask where the user is from
    def chat(self):
        self.rsp = f"Well, {Chat.usrName}, where are you from?"
        super().chat()

    def _respond(self, ans):
        self._botTime(f"{ans}? It sounds like a fantastic place! Maybe I'll travel there one day.")

class HowsGoing(Question):
# Ask how the user's daily life is
    def __init__(self):
        self.rsp = "So how's it going recently?"

    def _ChineseOrEnglish(self, text):
    # Check if they are Chinese sentences
        for ch in text:
            if u'\u4e00' <= ch <= u'\u9fff':
                return True
        return False

    def _EnglishAnalysis(self, text):
        blob = TextBlob(text)
        return blob.sentiment.polarity

    def _ChineseAnalysis(self, text):
        # Chinese analysis has some bugs
        snow = SnowNLP(text)
        return snow.sentiments * 2 - 1

    def _respond(self, ans):
        if self._ChineseOrEnglish(ans):
            sentiment = self._ChineseAnalysis(ans)
        else:
            sentiment = self._EnglishAnalysis(ans)

        # Different responds for different emotions
        if sentiment >= 0.6:
            self._botTime("Haha, I'm happy too!")
        elif sentiment >= 0.3:
            self._botTime("That sounds great!")
        elif sentiment >= 0:
            self._botTime("Well, all right.")
        elif sentiment <= -0.6:
            self._botTime("Don't be so sad, everything would be OK!")
        elif sentiment <= 0.3:
            self._botTime("Sorry to hear that.")
        elif sentiment <= 0:
            self._botTime("Well, not too bad.")

class FavColor(Question):
# Ask the user's favorite color
    def __init__(self):
        self.rsp = "What's your favorite color?"

    def _respond(self, ans):
        color = ["red", "yellow", "orange", "brown",\
                "purple", "pink", "blue", "black",\
                "white", "grey", "gray", "gold", "silver"]
        FavClr = random.choice(color)
        usrColor = ans.lower()
        known = 0

        for clr in color:
            if usrColor.find(clr) != -1:
                known = 1
        if not known:
            self._botTime(f"Oh, sorry I don't know what {usrColor} looks like, but my favorite color is {FavClr}.")
        else:
            if usrColor.find(FavClr) != -1:
                self._botTime(f"Wonderful, {FavClr} is my favorite color, too!")
            else:
                self._botTime(f"Well, I agree that {usrColor} is beautiful, but my favorite color is {FavClr}.")

class Calc(Question):
# A simple Calculator
    def __init__(self):
        self.rsp = "I'm learning some arithmetic recently, so you could tell me a simple formula in Python-like format and I will tell you the answer, and press q, x, exit or quit to exit."

    def chat(self):
        self._botTime(self.rsp)
        formular = ""
        while True:
            formular = self._usrTime()
            if formular == "x" or formular == "q"\
                or formular == "exit" or formular == "quit":
                break
            self._respond(formular)

        print("")

    def _errTime(self, err):
        self._thinking()
        print(colored(f"Bot:{err}", 'red'))

    def _respond(self, ans):
        try:
            # Including some useful math functions and constants
            answer = "It's a piece of cake, the answer is " + str(simple_eval(ans,
                            functions={"sin": lambda x: sin(x), "cos": lambda x: cos(x),\
                            "tan": lambda x: tan(x), "sinh": lambda x: sinh(x),\
                            "cosh": lambda x: cosh(x), "tanh": lambda x: tanh(x),\
                            "sqrt": lambda x: sqrt(x), "exp": lambda x: exp(x),\
                            "log": lambda x: log(x), "log10": lambda x: log10(x),\
                            "exp": lambda x: exp(x), "pow": lambda x, y: pow(x, y),\
                            "asin": lambda x: asin(x), "acos": lambda x: acos(x),\
                            "atan": lambda x: atan(x), "asinh": lambda x: asinh(x),\
                            "acosh": lambda x: acosh(x), "atanh": lambda x: atanh(x)},\
                            names={"e": e, "pi": pi}))\
                            + ". You can ask me another!"
            self._botTime(answer)
        except SyntaxError:
            self._errTime(f"Maybe you entered something wrong? Try again!")
        except ZeroDivisionError:
            self._errTime(f"Aaa-oh, it's seems like you entered something that does'nt fit math's law. Try again!")
        except:
            self._errTime(f"There is something I don't know in your formula? Try again!.")

#########################################################
################  Defination of TeruBot
#########################################################

class Teru:
    def __init__(self):
        random.seed(datetime.now())

        ## Gossip
        self.hello = Hello()
        self.bye = Bye()
        self.weather = Weather()
        self.stock = Stock()
        self.lyrics = Lyrics()

        ## Problem
        self.askName = AskName()
        self.comeFrom = ComeFrom()
        self.howsGoing = HowsGoing()
        self.favColor = FavColor()
        self.calc = Calc()

        ## Execution Table
        self.queList = [self.comeFrom, self.howsGoing, self.favColor, self.calc]
        self.gspList = [self.weather, self.stock, self.lyrics]
        self.gspNum = len(self.gspList)

    def runBot(self):
        self.hello.chat()
        self.askName.chat()
        self._askQue()
        self.bye.chat()

    def _askQue(self):
        for que in self.queList:
            self._sayGossip()
            que.chat()

    def _sayGossip(self):
        # 68% Possibility to run
        if not(random.random() < 0.68 and self.gspNum):
            return

        choiceGsp = random.randint(0, self.gspNum - 1)
        self.gspList[choiceGsp].chat()

        # Fisher–Yates Shuffle Algorithm
        tmpGsp = self.gspList[self.gspNum - 1]
        self.gspList[self.gspNum - 1] = self.gspList[choiceGsp]
        self.gspList[choiceGsp] = tmpGsp
        self.gspNum -= 1

#########################################################
################  Runing Entrance
#########################################################

teruBot = Teru()
teruBot.runBot()

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注