| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- """A minimal, runnable Chatto bot using the chattolib bot framework.
- Run it against a preview deployment::
- export CHATTO_BOT_KEY="cht_BK_..."
- export CHATTO_BASE_URL="https://next.preview.chatto.run" # optional
- python examples/bot/echo_bot.py
- The bot:
- * logs in with its key (used directly as a bearer token),
- * sets its presence to online,
- * joins every room it can see,
- * and echoes back any message that mentions it.
- It also reacts to presence changes and typing, to show the full event
- surface. Ctrl-C stops the bot cleanly.
- """
- from __future__ import annotations
- import asyncio
- import contextlib
- import os
- import signal
- from chattolib.bot import Bot, BotMessageEvent, BotPresenceEvent, BotTypingEvent
- from chattolib.types import PresenceStatus
- async def on_message(bot: Bot, event: BotMessageEvent) -> None:
- # Only answer when we're actually mentioned, to keep things quiet.
- if not event.is_mention:
- return
- if event.actor is not None and event.actor.id == bot.user.id:
- return # ignore our own echoes
- await bot.reply(event, f"you said: {event.body!r}")
- async def on_presence(bot: Bot, event: BotPresenceEvent) -> None:
- print(f"[presence] {event.user_id} is now {event.status.value}")
- async def on_typing(bot: Bot, event: BotTypingEvent) -> None:
- print(f"[typing] someone is typing in {event.room_id}")
- async def main() -> None:
- key = os.environ.get("CHATTO_BOT_KEY")
- if not key:
- raise SystemExit("set CHATTO_BOT_KEY to your bot key (cht_BK_...)")
- base_url = os.environ.get("CHATTO_BASE_URL")
- async with await Bot.login(key, base_url=base_url) as bot:
- print(f"logged in as {bot.login_name!r} (is_bot={bot.user.is_bot})")
- # Register handlers. `on` returns the handler, so it doubles as a
- # decorator if you prefer that style.
- bot.on("message", lambda e: on_message(bot, e))
- bot.on("presence", lambda e: on_presence(bot, e))
- bot.on("typing", lambda e: on_typing(bot, e))
- # Get online and join the rooms we can see, group by group (the way
- # the UI's one-click "join group" works). Swap for selective joins if
- # your bot should only be present in some rooms.
- await bot.set_presence(PresenceStatus.ONLINE)
- for group in await bot.list_room_groups():
- joined = await bot.join_room_group(group.id)
- if joined:
- print(f"joined group {group.name!r}: {joined}")
- # Run until interrupted.
- stop = asyncio.Event()
- loop = asyncio.get_running_loop()
- for sig in (signal.SIGINT, signal.SIGTERM):
- with contextlib.suppress(NotImplementedError):
- loop.add_signal_handler(sig, stop.set)
- await bot.run(until=stop)
- print("stopped")
- if __name__ == "__main__":
- asyncio.run(main())
|