- Python 98.2%
- Dockerfile 1%
- Nix 0.8%
| onehundredfourty | [states] search for state patterns using fullmatch | |
| .dockerignore | [docker] update to use uv | |
| .gitignore | [nix] add nix development environment | |
| .python-version | [build] switch to uv | |
| Dockerfile | [docker] change default command to point to /config | |
| init.py | [init] allow custom bot names | |
| LICENSE | LICENSE | |
| pyproject.toml | [build] switch to uv | |
| README.md | [readme] clean up readme | |
| shell.nix | [nix] add nix development environment | |
| telegram_bot.py | make fit for consumption | |
| uv.lock | [build] switch to uv | |
140characters
Have you ever wanted to post to mastodon using sms*? No? Now presenting my state-of-the-art** mastodon client: 140characters***!
*: telegram, though there is very only a loose dependency on the messenger itself
**: circa 2006
***: not actually restricted to 140 characters, i just thought it was cute that you used to be able to post to twitter using text messages.
running
To run the telegram frontend, you can use the Dockerfile. Ensure you have the app settings in a folder data/.
docker build -t 140ch_telegram_bot .
docker run -v data:/data 140ch_telegram_bot
settings.json
{
"client_id": "",
"client_secret": "",
"access_token": "",
"allowlist": [
// list of strings of telegram user ids
],
"base_url": "",
"database": "",
"telegram": {
"token": ""
}
}
background/technology
This is a python application formulated as a state machine. This means it can be hooked up to sms, telegram, or whatever your favorite messenger is with very little effort, as the input is a user state and the output is a user state and a text reply. User states are stored in sqlite, though other storage backends can be made to work though dependency injection.
example usage
Here is an example of using the bot on the console (a live example can be found here)
import logging
logging.basicConfig(level=logging.NOTSET)
logger = logging.getLogger(__name__)
import traceback
from onehundredfourty import states, Application, messaging, constants
from onehundredfourty.storage import SQLiteStorage
def handle_connection(identifier: str, msg: str, app: Application):
logger.debug(f"Handling connection: identifier={identifier} msg={msg}")
# if you choose to use the allowlist
if not app.check_allowlist(identifier):
return
user = app.fetch_user(identifier)
if user is None:
user = app.register_user(identifier)
# first interaction: send welcome message
print(states.state_reply(app, user.state))
try:
state, reply = states.process_state(user.state)(app, user, msg)
user.state = state
if reply:
print("\n".join([reply, states.state_reply(app, user.state)]).rstrip())
else:
print(states.state_reply(app, user.state))
except Exception as e:
logger.error(f"Error occurred while processing user state! {e}")
logger.error(traceback.format_exc())
user.state, _ = states.EXCEPTION_LANDING
app.save_user(user)
def main():
storage = SQLiteStorage("path_to_sqlite.db")
storage.ensure_storage()
app = Application(
"mastodon.instance",
"mastodon client id",
"mastodon client secret",
storage,
set(), # allowlist
)
while True:
msg = input("> ")
handle_connection("localhost", msg, app)
if __name__ == "__main__":
main()