~nova/fletcher

fletcher/mathemagical.py -rw-r--r-- 2.7 KiB
ece10afa — Novalinium f-string issue 9 days ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from sys import exc_info
import discord
import io
import logging
import matplotlib.pyplot as plt
import messagefuncs
import sympy
import tempfile

logger = logging.getLogger("fletcher")


def renderLatex(formula, fontsize=12, dpi=300, format="svg", file=None, preamble=""):
    """Renders LaTeX formula into image or prints to file.
    """
    plt.rc("text", usetex=True)
    plt.rc("text.latex", preamble=preamble)
    plt.rc("font", family="serif")
    fig = plt.figure(figsize=(0.01, 0.01))
    fig.text(
        0,
        0,
        formula,
        fontsize=fontsize,
        verticalalignment="center_baseline",
        clip_on=True,
    )
    plt.tight_layout()

    output = io.BytesIO() if file is None else file
    fig.savefig(
        output,
        dpi=dpi,
        transparent=False,
        format=format,
        bbox_inches="tight",
        pad_inches=None,
        frameon=True,
    )

    plt.close(fig)

    if file is None:
        output.seek(0)
        return output


async def latex_render_function(message, client, args):
    global config
    try:
        renderstring = message.content.split(" ", 1)[1]
        if message.content.split(" ", 1)[0] == "!math":
            renderstring = f"$${renderstring}$$"
        if "math" in config and "extra-packages" in config["math"]:
            preamble = (
                r"\usepackage{"
                + r"}\usepackage{".join(config["math"]["extra-packages"].split(","))
                + r"}"
            )
        else:
            preamble = ""
        await messagefuncs.sendWrappedMessage(
            "||```tex\n" + renderstring + "```||",
            message.channel,
            files=[
                discord.File(
                    renderLatex(renderstring, format="png", preamble=preamble),
                    filename="fletcher-render.png",
                )
            ],
        )
    except RuntimeError as e:
        exc_type, exc_obj, exc_tb = exc_info()
        logger.debug("LRF[{}]: {} {}".format(exc_tb.tb_lineno, type(e).__name__, e))
        await message.add_reaction("🚫")
        await messagefuncs.sendWrappedMessage(
            f"Error rendering LaTeX: {e}", message.author
        )
    except Exception as e:
        exc_type, exc_obj, exc_tb = exc_info()
        logger.error("LRF[{}]: {} {}".format(exc_tb.tb_lineno, type(e).__name__, e))


# Register functions in client
def autoload(ch):
    ch.add_command(
        {
            "trigger": ["!math", "!latex"],
            "function": latex_render_function,
            "async": True,
            "args_num": 0,
            "long_run": True,
            "args_name": [],
            "description": "Render arguments as LaTeX formula (does not require `$$` in `!math` mode)",
        }
    )


async def autounload(ch):
    pass