commit de0ee68ded274688badbd50c3f62c36a98150027 Author: Daniel Knüttel Date: Thu Jan 18 09:09:39 2018 +0100 initial diff --git a/mathbot/__init__.py b/mathbot/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/mathbot/__main__.py b/mathbot/__main__.py new file mode 100644 index 0000000..51896e0 --- /dev/null +++ b/mathbot/__main__.py @@ -0,0 +1,26 @@ +from .main import main + +import sys, logging + +if( __name__ == "__main__"): + + + logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + level=logging.INFO) + + logger = logging.getLogger(__name__) + + if(len(sys.argv) < 2): + print("E: missing bot api token file") + print(" usage:") + print(" {} ".format(sys.argv[0])) + sys.exit(1) + try: + f = open(sys.argv[1]) + token = f.read().strip() + f.close() + except: + print("E: failed to open and read token file") + sys.exit(1) + + main(token) diff --git a/mathbot/bot.py b/mathbot/bot.py new file mode 100644 index 0000000..ac7e1e5 --- /dev/null +++ b/mathbot/bot.py @@ -0,0 +1,42 @@ +from telegram.ext import RegexHandler +from .rendering import get_png +from .static import static_content + +def handle_exception_in_get_png(bot, update, exception, text): + update.message.reply_text("**Error** while processing '__{}__'.\n\nException was: **{}**.".format(text, exception), parse_mode = "Markdown") + +def render_math(bot, update): + text = update.message.text[len("/rmath"):] + tex = "${}$".format(text) + + try: + png = get_png(tex) + except Exception as e: + handle_exception_in_get_png(bot, update, e, tex) + return + + update.message.reply_photo(png, caption = "{}".format(text)) + +def render_math_caption(bot, update): + text = update.message.text[len("/rmath"):] + + if( not ("<" in text and ">" in text)): + update.message.reply_text("**Error**: missing caption seperators: < and >", parse_mode = "Markdown") + return + + caption = text[text.index("<") + 1:text.index(">")] + text = text[text.index(">") + 1:] + + tex = "${}$".format(text) + + try: + png = get_png(tex) + except Exception as e: + handle_exception_in_get_png(bot, update, e, tex) + return + + update.message.reply_photo(png, caption = "{}\n\nLaTeX: {}".format(caption, text)) + +def help(bot, update): + update.message.reply_text(static_content.help_text, parse_mode = "Markdown") + diff --git a/mathbot/main.py b/mathbot/main.py new file mode 100644 index 0000000..2c8e100 --- /dev/null +++ b/mathbot/main.py @@ -0,0 +1,16 @@ +from telegram.ext import Updater, CommandHandler, RegexHandler +from . import bot + + +def main(api_token): + updater = Updater(api_token) + + dispatcher = updater.dispatcher + + dispatcher.add_handler(CommandHandler("help", bot.help)) + dispatcher.add_handler(CommandHandler("rmath", bot.render_math)) + dispatcher.add_handler(CommandHandler("rcmath", bot.render_math_caption)) + + updater.start_polling() + + updater.idle() diff --git a/mathbot/rendering.py b/mathbot/rendering.py new file mode 100644 index 0000000..a41a0f1 --- /dev/null +++ b/mathbot/rendering.py @@ -0,0 +1,27 @@ +from sympy import preview +from io import BytesIO +import cairosvg, time, os + + +def get_png(tex): + buf = BytesIO() + preview(tex, output = "svg", viewer = "BytesIO", outputbuffer = buf) + buf.seek(0) + + fname = "/tmp/{}".format(time.time()) + + cairosvg.svg2png(bytestring=buf.read(), parent_widht=500, parent_height=500, write_to=fname) + + buf.seek(0) + + with open(fname, "rb") as fin: + buf.write(fin.read()) + with open(fname, "rb") as fin: + with open("test.png", "wb") as fout: + fout.write(fin.read()) + + os.unlink(fname) + + buf.seek(0) + + return buf diff --git a/mathbot/static.py b/mathbot/static.py new file mode 100644 index 0000000..64cf492 --- /dev/null +++ b/mathbot/static.py @@ -0,0 +1,19 @@ + +_help_text = ''' +**RMathBot** -- render LaTeX math commands + +Usage: + +- `/help` print this help message and exit +- `/rmath LATEX` render __LATEX__ and return the resulting PNG with the input text +- `/rcmath LATEX` render __LATEX__ and return the resulting PNG with the input text + and caption __CAPTION__ + + +''' + +class StaticContent(object): + def __init__(self): + self.help_text = _help_text + +static_content = StaticContent()