🌟tex
This commit is contained in:
parent
a1ed7f8dd1
commit
e0b9f35a76
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -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"]
|
||||
|
@ -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"]
|
||||
|
@ -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
|
||||
|
@ -1,2 +1,4 @@
|
||||
aiohttp>=3.7.4,<4
|
||||
discord.py~=2.3.2
|
||||
pillow~=10.2.0
|
||||
sympy~=1.12
|
||||
|
Loading…
Reference in New Issue
Block a user