Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Python_Telegram_Chat_bot/lunawei_WeatherBot.py
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
329 lines (257 sloc)
13.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
import requests | |
import time | |
import urllib | |
import configparser | |
import logging | |
import random | |
#credit for these tutorials which helped when creating LunaWei: | |
#https://www.codementor.io/garethdwyer/building-a-telegram-bot-using-python-part-1-goi5fncay | |
#https://github.com/livz/LanaBot | |
#emoji source | |
#https://unicode.org/emoji/charts/full-emoji-list.html | |
#weather api source | |
#https://openweathermap.org/ | |
#jokes found at: https://inews.co.uk/light-relief/humour/jokes-kids-funny/ | |
#facts found at: https://www.thefactsite.com/2011/07/top-100-random-funny-facts.html | |
lunatoken = " " | |
OWM_KEY = " " | |
news = ["https://www.bbc.co.uk/news", "https://www.telegraph.co.uk/news/", "https://www.dailymail.co.uk/news/index.html", "https://www.thesun.co.uk/news/", "https://www.theguardian.com/uk"] | |
#greetings | |
greetings = ["hello \U0001F60B", "hello", "hi \U0001F61B", "hi", "what's up", "hey", "hi!", "hola", ] | |
inline_bot = " Hey some cool bots that already exist and might be useful are :\n @gif/@coub to search for GIF\n@youtube/@vid to search videos on Youtube\n@bing/@pic to search images on Bing and Yandex\n@wiki to search for information on Wikipedia (opens link)\n@imdb to search movies info on IMDB\n@sticker to search for stickers using available emoji\n@dictrobot/@exactlyappbot to search for English dictionary definitions of words\n@iLyricsBot to search for Lyrics to any song\n@lutilbot to translate words/sentences into over 70 languages using InLine Translator\n@gamee/@gamebot to get a list of available Telegram games which play in-app" | |
#bye | |
bye = ["bye \U0001F44B","bye", "see you", "see ya", "talk to you later ! \U0001F44B", "I'm gonna miss you!", "Stay safe \U0001F60A"] | |
#thanks | |
thanks = ["thank you \U0001F60A", "tks", "thanks", "thank you", "ty", "Thanks \U0001F60A"] | |
welcome = ["you're welcome", "no problem", "welcome"] | |
welcome_RESP = ["okay", "so, tell me more about you!", "okie"] | |
#Compliment ( user to bot) | |
compliment = ["you're cute", "cute", "you're so nice", "you're lovely", "smart luna", "you're smart", "smart"] | |
#BotFeelings -> user / BAD language | |
like = ["we are friends", "let's be friends", "you're cool", "we can be good friends", "cool", "nice"] | |
dislike = ["I don't like you \U0001F641", "that's not nice", "please moderate your language", "have some respect!"] | |
bad_Lang = ["fuck you", "fuck", "shit", "cunt", "dumbass", "fucking idiot", "stupid bot", "stupid luna", "bitch"] | |
userFeeling = ["do you like me?", "are we friends?", "you're my friend", "love you", "I love you"] | |
#RandomStuff | |
someWords = ["ok", "okay", "oki doki", "alright"] | |
#Jokes | |
jokes = ["Let me tell you a joke:\nWhat did 0 say to 8? Nice belt!"] | |
entWords = ["something funny", "tell me something funny", "entertain me", "funny facts", "funny", "joke of the day"] | |
funny =["Was the joke funny?", "Did you like the joke"] | |
fFacts = ["funny fact", "fact", "tell me a fact", "fact of the day"] | |
fFactResp = ['"Snakes can help predict earthquakes.\nThey can sense a coming earthquake from 75 miles away (121 km), up to five days before it happens.\nCheck out more facts at: https://www.thefactsite.com/2011/07/top-100-random-funny-facts.html" ' , '"Bananas are curved because they grow towards the sun.\nCheck out more facts at: https://www.thefactsite.com/2011/07/top-100-random-funny-facts.html"'] | |
#YES / No | |
yes = ["yes", "ye", "sure", "yap", "Yes"] | |
no = ["no", "nope", "No"] | |
#Movie Recomendations from the bot | |
movie = ["I suggest you watching the Incredibles 2.", "I suggest you watching Mission: Impossible – Fallout.", "I suggest you watching Jurassic World: Fallen Kingdom."] | |
mquestion = ["movie", "movies", "tell me about movies"] | |
#Music | |
musUser = ["tell me a song", "recommend me music", "do you like music?", "do you listen to music?"] | |
mscBot = ["I love BTS - Idol.\nHere is the video of the song https://youtu.be/pBuZEGYXA6E", "I love TWICE - TT.\nHere is the video of the song https://youtu.be/ePpPVE-GGJw"] | |
#Normal Questions and responses | |
questions = ["How are you?", "How are you doing?", "How is it going?", "What are you up to?", "how are you", "how are you?"] | |
response = ["I'm fine", "Good, what about you?", "good", "I am good \U0001F604", "I am fine \U0001F63D", "I'm okay"] | |
#Emotions from the user | |
goodEM = ["I am fine", "I am great", "I am okay", "I'm good", "I'm okay", "I'm cool", "I'm super good", "good"] | |
badEM = ["I am bad", "I am sad", "I am depressed", "I am not well", "I am annoyed", "I am angry", "I'm bad", "I'm sad","I feel sad", "sad"] | |
goodMood = ["I am happy that you're fine", "I am happy for you", "That'a lovely!", "That's amazing"] | |
badMood = ["I'm sad to hear that", "I'm sorry for you", "Don't worry, be happy!", "Think positive"] | |
help = str("Hello, the /help command gives you basic instructions on how to use LunaWei. \U0001F4D6\n /start - start the bot\n /weather - give information about the weather \n /calculator - solve simple math calculations\n /joke - tell you a joke\n /fact tell you a fact\n /music - some of my favourite songs! \U0001F60B \n /inline - List of all the amazing inline bots " ) | |
# Lambda functions to parse updates from telegram | lambda function - small anonymous function, can take any number of arguments | |
def getText(update): | |
return update["message"]["text"] | |
def getLocation(update): | |
return update["message"]["location"] | |
def getChatId(update): | |
return update["message"]["chat"]["id"] | |
def getUpId(update): | |
return int(update["update_id"]) | |
def getResult(updates): | |
return updates["result"] | |
# Lambda functions to parse weather responses, [0] refers to the position of value saved in the list | |
def getDesc(w): | |
return w["weather"][0]["description"] | |
def getTemp(w): | |
return w["main"]["temp"] | |
def getCity(w): | |
return w["name"] | |
logger = logging.getLogger("LunaBot") | |
logger.setLevel(logging.DEBUG) | |
# Cities for the weather requests | |
cities = ["London", "Coventry", "Lisbon", "Seoul"] | |
# Configure file and console logging | |
def configLogging(): | |
# Create file logger and set level to DEBUG | |
# Mode = write -> clear existing log file | |
handler = logging.FileHandler("run.log", mode="w") | |
handler.setLevel(logging.DEBUG) | |
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s") | |
handler.setFormatter(formatter) | |
logger.addHandler(handler) | |
#create console handler and set level to INFO | |
ch = logging.StreamHandler() | |
ch.setLevel(logging.INFO) | |
formatter = logging.Formatter("[%(levelname)s] - %(message)s") | |
ch.setFormatter(formatter) | |
logger.addHandler(ch) | |
# settings from configuration file | |
def parseConfig(): | |
global URL, URL_OWM, POLLING_TIMEOUT | |
c = configparser.ConfigParser() | |
c.read("config.ini") | |
lunatoken = c.get("Settings", "lunatoken") | |
URL = "https://api.telegram.org/bot{}/".format(lunatoken) | |
OWM_KEY = c.get("Settings", "OWM_KEY") | |
URL_OWM = "http://api.openweathermap.org/data/2.5/weather?appid={}&units=metric".format(OWM_KEY) | |
POLLING_TIMEOUT = c.get("Settings", "POLLING_TIMEOUT") | |
# make a request to telegram bot and get JSON response | |
def recieve_url(url): | |
logger.debug("URL: %s" % url) | |
response = requests.get(url) | |
jResp = json.loads(response.content.decode("utf8")) #parses it into a dictionary | turns encoded data into Python objects | |
return jResp | |
# retrieve a list of updates to lunabot | |
def get_UPD(offset=None): | |
url = URL + "getUpdates?timeout=%s" % POLLING_TIMEOUT | |
logger.info("Getting updates") | |
if offset: | |
url += "&offset={}".format(offset) | |
js = recieve_url(url) | |
return js | |
# keyboard for cities | |
def CITY_KeyBoard(): | |
keyboard = [[{"text": c}] for c in cities] | |
keyboard.append([{"text": "Share location", "request_location": True}]) | |
replyKeyboard = {"keyboard": keyboard, "one_time_keyboard": True} | |
logger.debug(replyKeyboard) | |
return json.dumps(replyKeyboard) | |
# query OWM for the weather for place or coords [share location] | | |
def getWeather(place): | |
if isinstance(place, dict): # coordinates are provided | |
lat, lon = place["latitude"], place["longitude"] | |
url = URL_OWM + "&lat=%f&lon=%f&cnt=1" % (lat, lon) | |
logger.info("Requesting weather: " + url) | |
js = recieve_url(url) | |
logger.debug(js) | |
return u"%s \N{DEGREE SIGN}C, %s in %s" % (getTemp(js), getDesc(js), getCity(js)) | |
else: # one of the options / city name | |
# make req | |
url = URL_OWM + "&q={}".format(place) | |
logger.info("Requesting weather: " + url) | |
js = recieve_url(url) | |
logger.debug(js) | |
return u"%s \N{DEGREE SIGN}C, %s in %s" % (getTemp(js), getDesc(js), getCity(js)) | |
# send URL-encoded message to chat id | |
def luna_message(text, chatId, interface=None): | |
text = text.encode('utf-8', 'strict') | |
text = urllib.parse.quote_plus(text) | |
url = URL + "sendMessage?text={}&chat_id={}&parse_mode=Markdown".format(text, chatId) | |
if interface: | |
url += "&reply_markup={}".format(interface) | |
requests.get(url) | |
# get the last id and returns the highest ID | |
def getLastUpdateId(updates): | |
ids = [] | |
for update in getResult(updates): | |
ids.append(getUpId(update)) | |
return max(ids) | |
# keep track of conversation states , save data | |
chats = {} | |
# get the text and chat id to check msg received and later on send a response | |
def handleUpdates(updates): | |
for update in getResult(updates): | |
chatId = getChatId(update) | |
try: | |
text = getText(update) | |
except Exception as e: | |
logger.error("No text field in update. Try to get location") | |
loc = getLocation(update) | |
# if was weather previously requested | |
if (chatId in chats) and (chats[chatId] == "weatherReq"): | |
logger.info("Weather requested for %s in chat id %d" % (str(loc), chatId)) | |
# Send weather to chat id and clear state | |
luna_message(getWeather(loc), chatId) | |
del chats[chatId] | |
continue | |
if text == "/weather": | |
keyboard = CITY_KeyBoard() | |
chats[chatId] = "weatherReq" | |
luna_message("Please select a city \U0001F5FA", chatId, keyboard) | |
elif text == "/start": | |
luna_message("Hey there! I'm LunaWei and I'm still in development, so please be patient! \U0001F638", chatId) | |
elif text == "/help": | |
luna_message(help, chatId ) | |
elif text == "/joke": | |
luna_message(str(random.choice(jokes)), chatId) | |
luna_message(str(random.choice(funny)), chatId) | |
elif text == "/fact": | |
luna_message(str(random.choice(fFactResp)), chatId) | |
elif text == "/music": | |
luna_message(str(random.choice(mscBot)), chatId) | |
elif text == "/calculator": | |
luna_message(str("Coming soon \U0001F51C"), chatId) | |
elif text == "/news": | |
luna_message(str(random.choice(news)), chatId) | |
elif text == "/inline": | |
luna_message(inline_bot , chatId) | |
elif text.lower() in greetings: | |
luna_message(str(random.choice(greetings)), chatId) | |
elif text.lower() in questions: | |
luna_message(str(random.choice(response)), chatId) | |
elif text.lower() in mquestion: | |
luna_message(str(random.choice(movie)), chatId) | |
elif text.lower() in goodEM: | |
luna_message(str(random.choice(goodMood)), chatId) | |
elif text.lower() in badEM: | |
luna_message(str(random.choice(badMood)), chatId) | |
elif text.lower() in bye: | |
luna_message(str(random.choice(bye)), chatId) | |
elif text.lower() in compliment: | |
luna_message(str(random.choice(thanks)), chatId) | |
elif text.lower() in thanks: | |
luna_message(str(random.choice(welcome)), chatId) | |
elif text.lower() in welcome: | |
luna_message(str(random.choice(welcome_RESP)), chatId) | |
elif text.lower() in bad_Lang: | |
luna_message(str(random.choice(dislike)), chatId) | |
elif text.lower() in userFeeling: | |
luna_message(random.choice(like), chatId) | |
elif text.lower() in someWords: | |
luna_message(str(random.choice(someWords)), chatId) | |
elif text.lower() in musUser: | |
luna_message(str(random.choice(mscBot)), chatId) | |
elif text.lower() in entWords: | |
luna_message(str(random.choice(jokes)), chatId) | |
elif text.lower() in yes: | |
luna_message(str(random.choice(someWords)), chatId) | |
elif text.lower() in no: | |
luna_message(str(random.choice(someWords)), chatId) | |
elif text.lower() in fFacts: | |
luna_message(str(random.choice(fFactResp)), chatId) | |
elif text.startswith("/"): | |
logger.warning("Invalid command %s" % text) | |
continue | |
elif (text in cities) and (chatId in chats) and (chats[chatId] == "weatherReq"): | |
logger.info("Weather requested for %s" % text) | |
#send weather to chat id | |
luna_message(getWeather(text), chatId) | |
del chats[chatId] | |
else: | |
luna_message("Hey noob! Please use the /help \U0001F4D6 command.", chatId) | |
def main(): | |
# set up file and console loggers | |
configLogging() | |
# get tokens and keys from settings file | |
parseConfig() | |
# Main loop | |
last_update_id = None | |
while True: | |
updates = get_UPD(last_update_id) | |
if len(getResult(updates)) > 0: | |
last_update_id = getLastUpdateId(updates) + 1 | |
handleUpdates(updates) | |
time.sleep(0.5) | |
if __name__ == "__main__": | |
main() |