This commit is contained in:
AF 2024-01-23 06:57:20 +00:00
parent a1ed7f8dd1
commit e0b9f35a76
4 changed files with 81 additions and 1 deletions

View File

@ -4,7 +4,7 @@
"python.testing.pytestEnabled": false,
"python.testing.unittestEnabled": true,
"search.exclude": {
"**/venv": true
"**/.venv": true
},
"isort.args": ["--profile", "black"],
"black-formatter.args": ["--line-length", "120"]

View File

@ -1,5 +1,8 @@
FROM python:3.11 as base
WORKDIR /app/
RUN apt-get update && apt-get install -y texlive
RUN apt-get update && apt-get install -y texlive-latex-extra
RUN apt-get update && apt-get install -y dvipng
COPY requirements.txt requirements.txt
RUN pip --no-cache-dir install -r requirements.txt
CMD ["python3", "-m", "nightly"]

View File

@ -1,10 +1,60 @@
from __future__ import annotations
import asyncio
import re
from io import BytesIO
from textwrap import dedent
from typing import Annotated
import discord
import sympy
from aiohttp import ClientSession
from discord.ext import commands
from PIL import Image
# https://github.com/python-discord/bot-core/blob/main/pydis_core/utils/regex.py#L29
FORMATTED_CODE_REGEX = re.compile(
r"(?P<delim>(?P<block>```)|``?)"
r"(?(block)(?:(?P<lang>[a-z]+)\n)?)"
r"(?:[ \t]*\n)*"
r"(?P<code>.*?)"
r"\s*"
r"(?P=delim)",
flags=re.DOTALL | re.IGNORECASE,
)
# https://github.com/python-discord/bot-core/blob/main/pydis_core/utils/regex.py#L44C1-L49C2
RAW_CODE_REGEX = re.compile(r"^(?:[ \t]*\n)*" r"(?P<code>.*?)" r"\s*$", flags=re.DOTALL)
# https://github.com/python-discord/bot/blob/main/bot/exts/utils/snekbox/_cog.py#L97
class CodeblockConverter(commands.Converter):
@classmethod
async def convert(cls, ctx: commands.Context, code: str) -> list[str]:
if match := list(FORMATTED_CODE_REGEX.finditer(code)):
blocks = [block for block in match if block.group("block")]
if len(blocks) > 1:
codeblocks = [block.group("code") for block in blocks]
info = "several code blocks"
else:
match = match[0] if len(blocks) == 0 else blocks[0]
code, block, lang, delim = match.group("code", "block", "lang", "delim")
codeblocks = [dedent(code)]
if block:
info = (f"'{lang}' highlighted" if lang else "plain") + " code block"
else:
info = f"{delim}-enclosed inline code"
else:
m = RAW_CODE_REGEX.fullmatch(code)
if m is None:
raise RuntimeError("what")
codeblocks = [dedent(m.group("code"))]
info = "unformatted or badly formatted code"
code = "\n".join(codeblocks)
print(f"Extracted {info} for evaluation:\n{code}")
return codeblocks
class Night(commands.Cog):
@ -63,6 +113,31 @@ class Night(commands.Cog):
return
await message.pin()
@commands.hybrid_command()
async def tex(self, ctx: commands.Context, *, code: Annotated[list[str], CodeblockConverter]):
print(code)
buf = BytesIO()
def preview():
sympy.preview(
code[0],
viewer="BytesIO",
euler=False,
outputbuffer=buf,
dvioptions=["-fg", "White", "-bg", "Black"],
)
await asyncio.to_thread(preview)
buf.seek(0)
im0 = Image.open(buf)
print(im0.size)
im1 = Image.new(im0.mode, (im0.width + 40, im0.height + 40))
im1.paste(im0, (20, 20))
buf = BytesIO()
im1.save(buf, format="png")
buf.seek(0)
await ctx.reply(file=discord.File(buf, filename="tex.png"))
async def setup(bot: commands.Bot):
global cog

View File

@ -1,2 +1,4 @@
aiohttp>=3.7.4,<4
discord.py~=2.3.2
pillow~=10.2.0
sympy~=1.12