Skip to content

Commit

Permalink
init project
Browse files Browse the repository at this point in the history
  • Loading branch information
João Pedro committed Mar 11, 2024
0 parents commit 2fd57d5
Show file tree
Hide file tree
Showing 17 changed files with 2,482 additions and 0 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# This is a basic workflow to help you get started with Actions

name: Docs

# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
push:
branches: [ main ]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v2
with:
fetch-depth: 0
- uses: actions/setup-python@v2
- run: pip install --upgrade pip && pip install mkdocs mkdocs-gen-files
- run: git config user.name 'github-actions[bot]' && git config user.email 'github-actions[bot]@users.noreply.github.com'
- name: Publish docs
run: mkdocs gh-deploy
129 changes: 129 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib63/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest


# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery_app beat schedule file
celerybeat-schedule

# dotenv
_penv

# virtualenv
.venv/
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject

# vscode
.vscode
.chalice/deployments/
.chalice/venv/

# Pycharm Files
.idea/*
ml/.idea/*

requirements.txt
ca-bundle.crt

celery_states.db
celery_states.db.*
celerybeat-schedule.*
flower.*

#Image Files
*.png

# End of https://www.toptal.com/developers/gitignore/api/python,django,data
# Ignore dynaconf secret files
.secrets.*

.env

/tests/resources/report_test/
/tests/resources/report_prod/

#Ignoring MacBookPro data
.DS_Store

.env

# Mkdocs files
site/
36 changes: 36 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# See https://pre-commit.com for more information
# See https://pre-commit.com/hooks.html for more hooks
repos:
- repo: https://github.com/psf/black
rev: 22.3.0
hooks:
- id: black
args: [--safe, --line-length=100]

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v3.2.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-added-large-files
- id: debug-statements
language_version: python3

- repo: https://github.com/asottile/reorder_python_imports
rev: v2.6.0
hooks:
- id: reorder-python-imports
args: [--application-directories=.:src, --py38-plus]

- repo: https://github.com/asottile/pyupgrade
rev: v2.29.0
hooks:
- id: pyupgrade
args: [--py38-plus]

- repo: https://github.com/pre-commit/mirrors-mypy
rev: v0.910
hooks:
- id: mypy
files: ^src/
args: []
60 changes: 60 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
*Python-based open source developer tool for building chat bots, apps and custom integrations for major messaging platforms.*

This repository is inspired by the javascript library [botgen](https://github.com/howdyai/botgen) and the [BotFramework SDK](https://github.com/microsoft/botframework-sdk) concepts.

### Adapters

You can connect major plataforms using the same bot core code by setting different adapters. Adapter is a interface between your bot and message plataforms.


| Adapter | Docs | Availability |
|---------| -----|--------------|
| Web | | 0.0.1 |
| Slack | | |
| Telegram | | |
| Facebook | | |
| Twilio (SMS) | | |
| Whatsapp | | |

### Usage

Installation

`pip install botgen` (coming soon)

Copy and paste the code below to a file called `run.py`

```python
# run.py
from botgen import botgen
from botgen import BotMessage
from botgen import BotWorker
from botgen.adapters import WebAdapter

adapter = WebAdapter()
bot = botgen(adapter=adapter)

async def hello(bot_worker: BotWorker, message: BotMessage):
await bot_worker.say("hello from bot")


bot.hears(pattern="hello", event="message", handler=hello)

bot.start()
```

So you can run the project using:

`python run.py`

Then start a conversation:

```bash
curl -L -X POST 'http://localhost:8080/api/messages' -H 'Content-Type: application/json' -d '{
"user": "dummy",
"text": "hello",
"type": "message"
}'
```

### How to contribute
3 changes: 3 additions & 0 deletions botgen/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from .core import Bot
from .core import BotMessage
from .core import BotWorker
1 change: 1 addition & 0 deletions botgen/adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .web_adapter import WebAdapter
90 changes: 90 additions & 0 deletions botgen/adapters/web_adapter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import dataclasses
from datetime import datetime
from typing import Awaitable
from typing import Callable

from aiohttp.web import Request
from botbuilder.core import BotAdapter
from botbuilder.core import TurnContext
from botbuilder.schema import Activity
from botbuilder.schema import ActivityTypes
from botbuilder.schema import ConversationReference
from botbuilder.schema import ResourceResponse
from loguru import logger

from botgen.core import BotMessage


class WebAdapter(BotAdapter):
""" Connects PyBot to websocket or webhook """

def __init__(self, on_turn_error: Callable[[TurnContext, Exception], Awaitable] = None):
super().__init__(on_turn_error)

def activity_to_message(self, activity: Activity) -> BotMessage:
""" Caste a message to the simple format used by the websocket client """
message = BotMessage(
type=activity.type,
text=activity.text,
)

if activity.channel_data:
message.__dict__ = activity.channel_data.__dict__

return message

async def send_activities(
self, context: TurnContext, activities: list[Activity]
) -> ResourceResponse:
""" Standard BotBuilder adapter method to send a message from the bot to the messaging API """

responses = list()

for i in range(len(activities)):
activity = activities[i]
message = self.activity_to_message(activity=activity)
channel = context.activity.channel_id

if channel == "websocket":
raise NotImplementedError("Web socket not implemented")
elif channel == "webhook":
outbound = context.turn_state.get("httpBody")

if not outbound:
outbound = []

outbound.append(dataclasses.asdict(message))
context.turn_state["httpBody"] = outbound

return responses

async def update_activity(self, context: TurnContext, activity: Activity) -> None:
""" """
raise NotImplementedError()

async def delete_activity(self, context: TurnContext, reference: ConversationReference) -> None:
""" Accept an incoming webhook request and convert it into a TurnContext which can be processed by the bot's logic """
raise NotImplementedError()

async def process_activity(self, request: Request, logic: callable):
body = await request.json()
message = BotMessage(**body)

activity = Activity(
timestamp=datetime.now(),
channel_id="webhook",
conversation={"id": message.user},
from_property={"id": message.user},
recipient={"id": "bot"},
channel_data=message,
text=message.text,
type=message.type,
)

context = TurnContext(self, activity)

context.turn_state["httpStatus"] = 200

await self.run_pipeline(context=context, callback=logic)

return context.turn_state.get("httpBody")
Loading

0 comments on commit 2fd57d5

Please sign in to comment.