fbradyirl / webex_bot

Python package for a Webex Bot based on websockets.
MIT License
68 stars 44 forks source link

Introduction

Pypi Build Status

[!IMPORTANT] This repository is only sporadically maintained. Breaking API changes will be maintained on a best efforts basis.

Collaborators are welcome, as are PRs for enhancements.

Bug reports unrelated to API changes may not get the attention you want.

By using this module, you can create a Webex Teams messaging bot quickly in just a couple of lines of code.

This module does not require you to set up an ngrok tunnel to receive incoming messages when behind a firewall or inside a LAN. This package instead uses a websocket to receive messages from the Webex cloud.

Features

🚀 Getting started


✨ Sample Project

You can find a sample project, using OpenAI/ChatGPT with this library here: https://github.com/fbradyirl/openai_bot


Only Python 3.9 is tested at this time.

  1. Install this module from pypi:

pip install webex_bot

If you need optional proxy support, use this command instead:

pip install webex_bot[proxy]

  1. On the Webex Developer portal, create a new bot token and expose it as an environment variable.
export WEBEX_TEAMS_ACCESS_TOKEN=<your bots token>
  1. Run your script:

python example.py

See example.py for details:

import os

from webex_bot.commands.echo import EchoCommand
from webex_bot.webex_bot import WebexBot

# (Optional) Proxy configuration
# Supports https or wss proxy, wss prioritized.
proxies = {
    'https': 'http://proxy.esl.example.com:80',
    'wss': 'socks5://proxy.esl.example.com:1080'
}

# Create a Bot Object
bot = WebexBot(teams_bot_token=os.getenv("WEBEX_TEAMS_ACCESS_TOKEN"),
               approved_rooms=['06586d8d-6aad-4201-9a69-0bf9eeb5766e'],
               bot_name="My Teams Ops Bot",
               include_demo_commands=True,
               proxies=proxies)

# Add new commands for the bot to listen out for.
bot.add_command(EchoCommand())

# Call `run` for the bot to wait for incoming messages.
bot.run()

where EchoCommand is defined as:

import logging

from webexteamssdk.models.cards import Colors, TextBlock, FontWeight, FontSize, Column, AdaptiveCard, ColumnSet, \
    Text, Image, HorizontalAlignment
from webexteamssdk.models.cards.actions import Submit

from webex_bot.formatting import quote_info
from webex_bot.models.command import Command
from webex_bot.models.response import response_from_adaptive_card

log = logging.getLogger(__name__)

class EchoCommand(Command):

    def __init__(self):
        super().__init__(
            command_keyword="echo",
            help_message="Echo Words Back to You!",
            chained_commands=[EchoCallback()])

    def pre_execute(self, message, attachment_actions, activity):
        """
        (optional function).
        Reply before running the execute function.

        Useful to indicate the bot is handling it if it is a long running task.

        :return: a string or Response object (or a list of either). Use Response if you want to return another card.
        """

        image = Image(url="https://i.postimg.cc/2jMv5kqt/AS89975.jpg")
        text1 = TextBlock("Working on it....", weight=FontWeight.BOLDER, wrap=True, size=FontSize.DEFAULT,
                          horizontalAlignment=HorizontalAlignment.CENTER, color=Colors.DARK)
        text2 = TextBlock("I am busy working on your request. Please continue to look busy while I do your work.",
                          wrap=True, color=Colors.DARK)
        card = AdaptiveCard(
            body=[ColumnSet(columns=[Column(items=[image], width=2)]),
                  ColumnSet(columns=[Column(items=[text1, text2])]),
                  ])

        return response_from_adaptive_card(card)

    def execute(self, message, attachment_actions, activity):
        """
        If you want to respond to a submit operation on the card, you
        would write code here!

        You can return text string here or even another card (Response).

        This sample command function simply echos back the sent message.

        :param message: message with command already stripped
        :param attachment_actions: attachment_actions object
        :param activity: activity object

        :return: a string or Response object (or a list of either). Use Response if you want to return another card.
        """

        text1 = TextBlock("Echo", weight=FontWeight.BOLDER, size=FontSize.MEDIUM)
        text2 = TextBlock("Type in something here and it will be echo'd back to you. How useful is that!",
                          wrap=True, isSubtle=True)
        input_text = Text(id="message_typed", placeholder="Type something here", maxLength=30)
        input_column = Column(items=[input_text], width=2)

        submit = Submit(title="Submit",
                        data={
                            "callback_keyword": "echo_callback"})

        card = AdaptiveCard(
            body=[ColumnSet(columns=[Column(items=[text1, text2], width=2)]),
                  ColumnSet(columns=[input_column]),
                  ], actions=[submit])

        return response_from_adaptive_card(card)

class EchoCallback(Command):

    def __init__(self):
        super().__init__(
            card_callback_keyword="echo_callback",
            delete_previous_message=True)

    def execute(self, message, attachment_actions, activity):
        return quote_info(attachment_actions.inputs.get("message_typed"))
  1. Now, just interact 1-1 with the bot. Send it a message with the text:

echo

and off you go!

Help

History

0.1.2 (2021-03-15)

0.1.4 (2021-03-23)

0.1.5 (2021-03-23)

0.1.6 (2021-03-25)

0.1.7 (2021-03-26)

0.1.8 (2021-05-04)

0.2.0 (2021-05-07)

0.2.1 (2021-05-07)

0.2.2 (2021-05-08)

0.2.3 (2021-05-10)

0.2.5 (2021-05-10)

0.2.6 (2021-05-21)

0.2.7 (2021-09-27)

0.2.8 (2022-01-06)

Breaking change for existing cards:

    def execute(self, message, attachment_actions, activity):
        log.info(
            f"activity={activity} ")
        email = activity["actor"]['emailAddress']
        return quote_info(f"person email is '{email}'")

0.2.9 (2022-03-03)

0.2.10 (2022-03-03)

0.2.11 (2022-03-08)

0.2.12 (2022-03-09)

0.2.13 (2022-03-09)

0.2.14 (2022-03-09)

0.2.15 (2022-03-09)

0.2.16 (2022-03-10)

0.2.17 (2022-03-11)

0.2.18 (2022-03-11)

0.2.19 (2022-03-14)

0.2.20 (2022-04-07)

0.2.21 (2022-04-07)

0.2.22 (2022-04-11)

0.3.0 (2022-04-26)

0.3.1 (2022-04-26)

0.3.3 (2022-06-07)

0.3.4 (2022-11-01)

0.4.0 (2023-April-03)

0.4.1 (2023-Sept-07)

0.4.6 (2024-Apr-24)

0.5.0 (2024-Apr-25)

0.5.1 (2024-Apr-25)

0.5.2 (2024-Aug-21)