Skip to main content

A Lightweight BOT Framework.

Project description

FastBot

A lightweight bot framework base on FastAPI and OneBot v11 protocol.

Quick Start

Installation

Install from Github

pip install --no-cache --upgrade git+https://github.com/OrganRemoved/fastbot.git

or

pip install --no-cache --upgrade https://github.com/OrganRemoved/fastbot/archive/refs/heads/main.zip

Install from PYPI

pip install --no-cache --upgrade fastbot-onebot

Example

The directory structure is as follows:

bot_example
|   __init__.py
|   bot.py
|
\---plugins
        __init__.py
        plugin_example.py

bot.py

from contextlib import asynccontextmanager
from typing import AsyncGenerator

from fastapi import FastAPI
from fastbot.bot import FastBot
from fastbot.plugin import PluginManager


@asynccontextmanager
async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
    # Register a websocket adapter to `FastAPI`
    app.add_api_websocket_route("/onebot/v11/ws", FastBot.ws_adapter)

    await asyncio.gather(
        *(
            init() if asyncio.iscoroutinefunction(init) else asyncio.to_thread(init)
            for plugin in PluginManager.plugins.values()
            if (init := plugin.init)
        ),
    )

    yield


if __name__ == "__main__":
    (
        FastBot
        # `plugins` parameter will pass to `fastbot.plugin.PluginManager.import_from(...)`
        # the rest parameter will pass to `FastAPI(...)`
        .build(plugins=["plugins"], lifespan=lifespan)
        # Parameter will pass to `uvicorn.run(...)`
        .run(host="0.0.0.0", port=80)
    )

plugin_example.py

from typing import AsyncGenerator

from fastbot.event import Context
from fastbot.event.message import GroupMessageEvent, PrivateMessageEvent
from fastbot.matcher import Matcher
from fastbot.plugin import Dependency, PluginManager, middleware, on
from redis.asyncio.client import Redis, Pipeline


# Passing rules to the matcher
IsNotGroupAdmin = Matcher(rule=lambda event: event.sender.role != "admin")


# Refactoring the Matcher
class IsInGroupBlacklist(Matcher):
    def __init__(self, *blacklist):
        self.blacklist = blacklist

    def __call__(self, event: GroupMessageEvent) -> bool:
        return event.group_id in self.blacklist


async def init() -> None:
    # Do some initial work here
    ...


# Dependency injection
async def get_redis(*args, **kwargs) -> AsyncGenerator[Redis, None]:
    if "url" in kwargs:
        redis = Redis.from_url(decode_responses=True, *args, **kwargs)

    elif "connection_pool" in kwargs:
        redis = Redis.from_pool(*args, **kwargs)

    else:
        redis = Redis(
            host=kwargs.pop("host", environ["REDIS_HOST"]),
            port=kwargs.pop("port", int(environ["REDIS_PORT"])),
            db=kwargs.pop("db", environ["REDIS_DB"]),
            password=kwargs.pop("password", environ["REDIS_PASSWORD"]),
            decode_responses=kwargs.pop("decode_responses", True),
            **kwargs,
        )

    async with redis as r:
        yield r


# Chaining dependency injection
async def get_pipeline(
    redis: Redis = Dependency.provide(dependency=redis), *args, **kwargs
) -> AsyncGenerator[Pipeline, None]:
    async with redis.pipeline(*args, **kwargs) as pipeline:
        yield pipeline

        await pipeline.execute()


# All middlewares will be executed in sequence
@middleware(priority=0)
async def preprocessing(ctx: Context):
    if (group_id := ctx.get("group_id")) == ...:
        # Temporarily disable the plugin
        PluginManager.plugins["plugins.plugin_example"].state.set(False)
    elif group_id is None:
        # When the `Context` is clear, the middleware will discard
        # the event and terminate processing
        ctx.clear()


# Combining multiple rules via `&(and)`, `|(or)`,`~(not)`
@on(matcher=IsNotGroupAdmin & ~IsInGroupBlacklist(...))
# For the best performance, you can use `callable function`
# E.g. `lambda event: event.get("group_id") in (...)`
async def func(
    # The event type to be handled must be specified via type hints
    # You can use `|`  or `typing.Union` types
    event: GroupMessageEvent | PrivateMessageEvent,
    *,
    redis: Redis = Dependency.provide(dependency=get_redis),
    pipeline: Pipeline = Dependency.provide(dependency=get_pipeline),
) -> None:
    if event.text == "guess":
        await event.send("Start guessing the number game now: [0-10]!")

        while new_event := await event.defer("Enter a number: "):
            if new_event.text != "10":
                await new_event.send("Guess wrong!")
                continue

            await new_event.send("Guess right!")
            return

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

fastbot_onebot-2025.3.7.tar.gz (11.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fastbot_onebot-2025.3.7-py3-none-any.whl (15.5 kB view details)

Uploaded Python 3

File details

Details for the file fastbot_onebot-2025.3.7.tar.gz.

File metadata

  • Download URL: fastbot_onebot-2025.3.7.tar.gz
  • Upload date:
  • Size: 11.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.9.21

File hashes

Hashes for fastbot_onebot-2025.3.7.tar.gz
Algorithm Hash digest
SHA256 cb0f945a0cad4dc7e3dedba2f70959b0322447f112894ff6570d1afba4aae21f
MD5 7db543050ea5d672064c1a5e8da5c373
BLAKE2b-256 84c89322b4735968acc52bfa6edbfe8ca2e35f7a02ac7bf4a754f123cec421bc

See more details on using hashes here.

File details

Details for the file fastbot_onebot-2025.3.7-py3-none-any.whl.

File metadata

File hashes

Hashes for fastbot_onebot-2025.3.7-py3-none-any.whl
Algorithm Hash digest
SHA256 dc5c70e3aa15ac0c35771e495d1bc0a1275a7cb046f956778e80eb7988ffa722
MD5 bd78167d41eb0537bbd02125717aa80e
BLAKE2b-256 b861e35e231693e95a405c3b38bef60e4a281fa946cb71e4d11590604945e19b

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page