def handle_input(self, message: Dict[str, str], bot_handler: BotHandler) -> None: original_content = message["content"] if self.is_help(original_content) or (original_content == ""): bot_handler.send_reply(message, HELP_MESSAGE) else: sentence = self.format_input(original_content) try: reply_message = self.send_to_yoda_api(sentence) if len(reply_message) == 0: reply_message = "Invalid input, please check the sentence you have entered." except (ssl.SSLError, TypeError): reply_message = "The service is temporarily unavailable, please try again." logging.error(reply_message) except ApiKeyError: reply_message = ( "Invalid Api Key. Did you follow the instructions in the `readme.md` file?" ) logging.error(reply_message) bot_handler.send_reply(message, reply_message)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: command = message["content"] if command == "": command = "help" msg = dbx_command(self.client, command) bot_handler.send_reply(message, msg)
def start_new_quiz(message: Dict[str, Any], bot_handler: BotHandler) -> None: quiz = get_trivia_quiz() quiz_id = generate_quiz_id(bot_handler.storage) bot_response = format_quiz_for_markdown(quiz_id, quiz) widget_content = format_quiz_for_widget(quiz_id, quiz) bot_handler.storage.put(quiz_id, json.dumps(quiz)) bot_handler.send_reply(message, bot_response, widget_content)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: query = message['content'] if query == 'new': try: start_new_quiz(message, bot_handler) return except NotAvailableException: bot_response = 'Uh-Oh! Trivia service is down.' bot_handler.send_reply(message, bot_response) return elif query.startswith('answer'): try: (quiz_id, answer) = parse_answer(query) except InvalidAnswerException: bot_response = 'Invalid answer format' bot_handler.send_reply(message, bot_response) return try: quiz_payload = get_quiz_from_id(quiz_id, bot_handler) except (KeyError, TypeError): bot_response = 'Invalid quiz id' bot_handler.send_reply(message, bot_response) return quiz = json.loads(quiz_payload) start_new_question, bot_response = handle_answer( quiz, answer, quiz_id, bot_handler, message['sender_full_name']) bot_handler.send_reply(message, bot_response) if start_new_question: start_new_quiz(message, bot_handler) return else: bot_response = 'type "new" for a new question' bot_handler.send_reply(message, bot_response)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: content = 'beep boop' # type: str bot_handler.send_reply(message, content) emoji_name = 'wave' # type: str bot_handler.react(message, emoji_name) return
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: if message["content"] == "" or message["content"] == "help": bot_handler.send_reply(message, self.help_content) else: cmd, query = get_command_query(message) bot_response = get_bot_response(query, cmd, self.config_info) logging.info(bot_response.format()) bot_handler.send_reply(message, bot_response)
def move_computer(self, message: Dict[str, str], bot_handler: BotHandler, last_fen: str, move_san: str) -> None: """Preforms a move for a user in a game with the computer and then makes the computer's move. Replies to the bot handler. Unlike `move`, replies only once to the bot handler every two moves (only after the computer moves) instead of after every move. Doesn't require a call in order to make the computer move. To make the computer move without the user going first, use `move_computer_first`. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - last_fen: The FEN string of the board before the user's move. - move_san: The SAN of the user's move to make. """ last_board = self.validate_board(message, bot_handler, last_fen) if not last_board: return move = self.validate_move(message, bot_handler, last_board, move_san, True) if not move: return new_board = copy.copy(last_board) new_board.push(move) if self.check_game_over(message, bot_handler, new_board): return computer_move = calculate_computer_move(new_board, self.engine) if not computer_move: bot_handler.send_reply(message, make_engine_failed_response()) return new_board_after_computer_move = copy.copy(new_board) new_board_after_computer_move.push(computer_move) if self.check_game_over(message, bot_handler, new_board_after_computer_move): return bot_handler.send_reply( message, make_move_reponse(new_board, new_board_after_computer_move, computer_move)) bot_handler.storage.put("last_fen", new_board_after_computer_move.fen())
def start_new_incident(query: str, message: Dict[str, Any], bot_handler: BotHandler) -> None: # Here is where we would enter the incident in some sort of backend # system. We just simulate everything by having an incident id that # we generate here. incident = query[len("new "):] ticket_id = generate_ticket_id(bot_handler.storage) bot_response = format_incident_for_markdown(ticket_id, incident) widget_content = format_incident_for_widget(ticket_id, incident) bot_handler.send_reply(message, bot_response, widget_content)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: msg = message["content"] if msg == "help" or msg == "": bot_handler.send_reply(message, self.usage()) return reply = requests.get("https://api.susi.ai/susi/chat.json", params=dict(q=msg)) try: answer = reply.json()["answers"][0]["actions"][0]["expression"] except Exception: answer = "I don't understand. Can you rephrase?" bot_handler.send_reply(message, answer)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: req = message['content'].strip().split() if req == []: bot_handler.send_reply(message, 'No Command Specified') return req[0] = req[0].lower() response = '' if req == ['my-events']: response = helpers.get_my_events(message['sender_id']) if response: bot_handler.send_reply(message, response) elif req == ['all-events']: response = helpers.get_all_events() if response: bot_handler.send_reply(message, response) else: bot_handler.send_reply( message, "I don't understand what you're saying...try again :)") return
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: HELP_STR = ( 'Use this bot with any of the following commands:' '\n* `@uploader <local_file_path>` : Upload a file, where `<local_file_path>` is the path to the file' '\n* `@uploader help` : Display help message' ) content = message['content'].strip() if content == 'help': bot_handler.send_reply(message, HELP_STR) return path = Path(os.path.expanduser(content)) if not path.is_file(): bot_handler.send_reply(message, 'File `{}` not found'.format(content)) return path = path.resolve() upload = bot_handler.upload_file_from_path(str(path)) if upload['result'] != 'success': msg = upload['msg'] bot_handler.send_reply(message, 'Failed to upload `{}` file: {}'.format(path, msg)) return uploaded_file_reply = '[{}]({})'.format(path.name, upload['uri']) bot_handler.send_reply(message, uploaded_file_reply)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: HELP_STR = ( "Use this bot with any of the following commands:" "\n* `@uploader <local_file_path>` : Upload a file, where `<local_file_path>` is the path to the file" "\n* `@uploader help` : Display help message") content = message["content"].strip() if content == "help": bot_handler.send_reply(message, HELP_STR) return path = Path(os.path.expanduser(content)) if not path.is_file(): bot_handler.send_reply(message, f"File `{content}` not found") return path = path.resolve() upload = bot_handler.upload_file_from_path(str(path)) if upload["result"] != "success": msg = upload["msg"] bot_handler.send_reply(message, f"Failed to upload `{path}` file: {msg}") return uploaded_file_reply = "[{}]({})".format(path.name, upload["uri"]) bot_handler.send_reply(message, uploaded_file_reply)
def start(self, message: Dict[str, str], bot_handler: BotHandler) -> None: """Starts a game with another user, with the current user as white. Replies to the bot handler. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. """ new_board = chess.Board() bot_handler.send_reply(message, make_start_reponse(new_board)) # `bot_handler`'s `storage` only accepts `str` values. bot_handler.storage.put("is_with_computer", str(False)) bot_handler.storage.put("last_fen", new_board.fen())
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: if message['content'] == '': bot_response = "Please specify the message you want to send to followup stream after @mention-bot" bot_handler.send_reply(message, bot_response) elif message['content'] == 'help': bot_handler.send_reply(message, self.usage()) else: bot_response = self.get_bot_followup_response(message) bot_handler.send_message( dict( type='stream', to=self.stream, subject=message['sender_email'], content=bot_response, ))
def resign(self, message: Dict[str, str], bot_handler: BotHandler, last_fen: str) -> None: """Resigns the game for the current player. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - last_fen: The FEN string of the board. """ last_board = self.validate_board(message, bot_handler, last_fen) if not last_board: return bot_handler.send_reply(message, make_loss_response(last_board, "resigned"))
def check_game_over(self, message: Dict[str, str], bot_handler: BotHandler, new_board: chess.Board) -> bool: """Checks if a game is over due to - checkmate, - stalemate, - insufficient material, - 50 moves without a capture or pawn move, or - 3-fold repetition. Replies to the bot handler if it is game over. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - new_board: The board object. Returns: True if it is game over, false if it's not. """ # This assumes that the players will claim a draw after 3-fold # repetition or 50 moves go by without a capture or pawn move. # According to the official rules, the game is only guaranteed to # be over if it's *5*-fold or *75* moves, but if either player # wants the game to be a draw, after 3 or 75 it a draw. For now, # just assume that the players would want the draw. if new_board.is_game_over(claim_draw=True): game_over_output = "" if new_board.is_checkmate(): game_over_output = make_loss_response(new_board, "was checkmated") elif new_board.is_stalemate(): game_over_output = make_draw_response("stalemate") elif new_board.is_insufficient_material(): game_over_output = make_draw_response("insufficient material") elif new_board.can_claim_fifty_moves(): game_over_output = make_draw_response( "50 moves without a capture or pawn move") elif new_board.can_claim_threefold_repetition(): game_over_output = make_draw_response("3-fold repetition") bot_handler.send_reply(message, game_over_output) return True return False
def validate_board(self, message: Dict[str, str], bot_handler: BotHandler, fen: str) -> Optional[chess.Board]: """Validates a board based on its FEN string. Replies to the bot handler if there is an error with the board. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - fen: The FEN string of the board. Returns: `None` if the board didn't pass, or the board object itself if it did. """ try: last_board = chess.Board(fen) except ValueError: bot_handler.send_reply(message, make_copied_wrong_response()) return None return last_board
def move_computer_first(self, message: Dict[str, str], bot_handler: BotHandler, last_fen: str) -> None: """Preforms a move for the computer without having the user go first in a game with the computer. Replies to the bot handler. Like `move_computer`, but doesn't have the user move first. This is usually only useful at the beginning of a game. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - last_fen: The FEN string of the board before the computer's move. """ last_board = self.validate_board(message, bot_handler, last_fen) if not last_board: return computer_move = calculate_computer_move(last_board, self.engine) if not computer_move: bot_handler.send_reply(message, make_engine_failed_response()) return new_board_after_computer_move = copy.copy(last_board) new_board_after_computer_move.push(computer_move) if self.check_game_over(message, bot_handler, new_board_after_computer_move): return bot_handler.send_reply( message, make_move_reponse(last_board, new_board_after_computer_move, computer_move)) bot_handler.storage.put("last_fen", new_board_after_computer_move.fen()) # `bot_handler`'s `storage` only accepts `str` values. bot_handler.storage.put("is_with_computer", str(True))
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: REGEX_STR = ( r"(" r"(?:http|https):\/\/" # This allows for the HTTP or HTTPS # protocol. r'[^"<>\{\}|\^~[\]` ]+' # This allows for any character except # for certain non-URL-safe ones. r")") HELP_STR = ("Mention the link shortener bot in a conversation and " "then enter any URLs you want to shorten in the body of " "the message.") content = message["content"] if content.strip() == "help": bot_handler.send_reply(message, HELP_STR) return link_matches = re.findall(REGEX_STR, content) shortened_links = [self.shorten_link(link) for link in link_matches] link_pairs = [(link_match + ": " + shortened_link) for link_match, shortened_link in zip( link_matches, shortened_links) if shortened_link != ""] final_response = "\n".join(link_pairs) if final_response == "": bot_handler.send_reply(message, "No links found. " + HELP_STR) return bot_handler.send_reply(message, final_response)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: content = message["content"].strip().split() if content == []: bot_handler.send_reply(message, "Empty Query") return content[0] = content[0].lower() if content == ["help"]: bot_handler.send_reply(message, self.usage()) return if content == ["list-commands"]: bot_reply = self.get_all_supported_commands() elif content == ["get-all-boards"]: bot_reply = self.get_all_boards() else: if content[0] == "get-all-cards": bot_reply = self.get_all_cards(content) elif content[0] == "get-all-checklists": bot_reply = self.get_all_checklists(content) elif content[0] == "get-all-lists": bot_reply = self.get_all_lists(content) else: bot_reply = "Command not supported" bot_handler.send_reply(message, bot_reply)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: content = message['content'].strip().split() if content == []: bot_handler.send_reply(message, 'Empty Query') return content[0] = content[0].lower() if content == ['help']: bot_handler.send_reply(message, self.usage()) return if content == ['list-commands']: bot_reply = self.get_all_supported_commands() elif content == ['get-all-boards']: bot_reply = self.get_all_boards() else: if content[0] == 'get-all-cards': bot_reply = self.get_all_cards(content) elif content[0] == 'get-all-checklists': bot_reply = self.get_all_checklists(content) elif content[0] == 'get-all-lists': bot_reply = self.get_all_lists(content) else: bot_reply = 'Command not supported' bot_handler.send_reply(message, bot_reply)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: content = message["content"] if content == "": bot_handler.send_reply(message, self.usage()) return start_regex_match = START_REGEX.match(content) start_computer_regex_match = START_COMPUTER_REGEX.match(content) move_regex_match = MOVE_REGEX.match(content) resign_regex_match = RESIGN_REGEX.match(content) is_with_computer = False last_fen = chess.Board().fen() if bot_handler.storage.contains("is_with_computer"): is_with_computer = ( # `bot_handler`'s `storage` only accepts `str` values. bot_handler.storage.get("is_with_computer") == str(True)) if bot_handler.storage.contains("last_fen"): last_fen = bot_handler.storage.get("last_fen") if start_regex_match: self.start(message, bot_handler) elif start_computer_regex_match: self.start_computer( message, bot_handler, start_computer_regex_match.group("user_color") == "white") elif move_regex_match: if is_with_computer: self.move_computer(message, bot_handler, last_fen, move_regex_match.group("move_san")) else: self.move(message, bot_handler, last_fen, move_regex_match.group("move_san")) elif resign_regex_match: self.resign(message, bot_handler, last_fen)
def validate_move( self, message: Dict[str, str], bot_handler: BotHandler, last_board: chess.Board, move_san: str, is_computer: object, ) -> Optional[chess.Move]: """Validates a move based on its SAN string and the current board. Replies to the bot handler if there is an error with the move. Parameters: - message: The Zulip Bots message object. - bot_handler: The Zulip Bots bot handler object. - last_board: The board object before the move. - move_san: The SAN of the move. - is_computer: Whether or not the user is playing against a computer (used in the response if the move is not legal). Returns: `False` if the move didn't pass, or the move object itself if it did. """ try: move = last_board.parse_san(move_san) except ValueError: bot_handler.send_reply( message, make_not_legal_response(last_board, move_san)) return None if move not in last_board.legal_moves: bot_handler.send_reply( message, make_not_legal_response(last_board, move_san)) return None return move
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: help_content = """ This bot returns weather info for specified city. You specify city in the following format: city, state/country state and country parameter is optional(useful when there are many cities with the same name) For example: @**Weather Bot** Portland @**Weather Bot** Portland, Me """.strip() if (message["content"] == "help") or (message["content"] == ""): response = help_content else: api_params = dict(q=message["content"], APPID=self.api_key) r = requests.get(api_url, params=api_params) if r.json()["cod"] == "404": response = "Sorry, city not found" else: response = format_response(r, message["content"], self.response_pattern) bot_handler.send_reply(message, response)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: if message["content"] == "" or message["content"] == "help": bot_handler.send_reply(message, self.help_message) return try: res = self.client.message(message["content"]) message_for_user = self.handle(res) if message_for_user: bot_handler.send_reply(message, message_for_user) except wit.wit.WitError: bot_handler.send_reply(message, "Sorry, I don't know how to respond to that!") except Exception as e: bot_handler.send_reply(message, "Sorry, there was an internal error.") print(e) return
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: storage = bot_handler.storage num = storage.get('number') # num should already be an int, but we do `int()` to force an # explicit type check num = int(num) + 1 storage.put('number', num) if storage.get('message_id') is None: result = bot_handler.send_reply(message, str(num)) if result is not None: storage.put('message_id', result['id']) else: bot_handler.update_message(dict( message_id=storage.get('message_id'), content=str(num) ))
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: message["content"] = message["content"].strip() if message["content"].lower() == "help": bot_handler.send_reply(message, self.usage()) return if message["content"] == "": bot_handler.send_reply(message, "Empty Mention Query") return keyword = message["content"] content = self.generate_response(keyword) bot_handler.send_reply(message, content)
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: content = message["content"].strip().split() if content == []: bot_handler.send_reply(message, "No Command Specified") return content[0] = content[0].lower() if content == ["help"]: bot_handler.send_reply(message, self.usage()) return if content == ["list-commands"]: response = "**Available Commands:** \n" for command, description in zip(self.commands, self.descriptions): response += f" - {command} : {description}\n" bot_handler.send_reply(message, response) return response = self.generate_response(content) bot_handler.send_reply(message, response)
def handle_message(self, message: Dict[str, str], bot_handler: BotHandler) -> None: storage = bot_handler.storage num = storage.get('number') # num should already be an int, but we do `int()` to force an # explicit type check num = int(num) + 1 storage.put('number', num) if storage.get('message_id') is not None: result = bot_handler.update_message( dict(message_id=storage.get('message_id'), content=str(num))) # When there isn't an error while updating the message, we won't # attempt to send the it again. if result is None or result.get('result') != 'error': return message_info = bot_handler.send_reply(message, str(num)) if message_info is not None: storage.put('message_id', message_info['id'])
def handle_message(self, message: Dict[str, Any], bot_handler: BotHandler) -> None: content = message['content'].strip().split() if content == []: bot_handler.send_reply(message, 'No Command Specified') return content[0] = content[0].lower() if content == ['help']: bot_handler.send_reply(message, self.usage()) return if content == ['list-commands']: response = '**Available Commands:** \n' for command, description in zip(self.commands, self.descriptions): response += ' - {} : {}\n'.format(command, description) bot_handler.send_reply(message, response) return response = self.generate_response(content) bot_handler.send_reply(message, response)