Skip to content

Commit

Permalink
Merge pull request #50 from sudoskys/dev
Browse files Browse the repository at this point in the history
🔧 refactor(mermaid): replace aiohttp_client_cache with aiohttp
  • Loading branch information
sudoskys authored Dec 15, 2024
2 parents 07aa576 + 22c9b13 commit cc274ee
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 79 deletions.
55 changes: 1 addition & 54 deletions pdm.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion playground/markdownify_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
print("Hello, World!")
```
This is `inline code`
1. First ordered list item
1. **First ordered list item**
2. Another item
- Unordered sub-list.
- Another item.
Expand Down
16 changes: 10 additions & 6 deletions playground/telegramify_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import pathlib
from time import sleep

from aiohttp import ClientSession
from dotenv import load_dotenv
from telebot import TeleBot

Expand Down Expand Up @@ -32,12 +33,15 @@

# Write an async function to send message
async def send_message():
boxs = await telegramify_markdown.telegramify(
content=md,
interpreters_use=[BaseInterpreter(), MermaidInterpreter()], # Render mermaid diagram
latex_escape=True,
max_word_count=4090 # The maximum number of words in a single message.
)
global_session = ClientSession()
async with global_session:
boxs = await telegramify_markdown.telegramify(
content=md,
interpreters_use=[BaseInterpreter(), MermaidInterpreter(session=global_session)], # Render mermaid diagram
latex_escape=True,
normalize_whitespace=True,
max_word_count=4090 # The maximum number of words in a single message.
)
for item in boxs:
print("Sent one item")
sleep(0.2)
Expand Down
3 changes: 1 addition & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "telegramify-markdown"
version = "0.3.0"
version = "0.3.1"
description = "Makes it easy to send Markdown in Telegram MarkdownV2 style"
authors = [
{ name = "sudoskys", email = "[email protected]" },
Expand All @@ -12,7 +12,6 @@ dependencies = [
"Pillow>=10.4.0",
"pydantic>=2.10.3",
"aiohttp>=3.10.11",
"aiohttp-client-cache>=0.12.4",
]
requires-python = ">=3.8"
readme = "README.md"
Expand Down
13 changes: 12 additions & 1 deletion src/telegramify_markdown/interpreters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import List, Any, Callable
from typing import TYPE_CHECKING

import mistletoe

Expand All @@ -7,6 +8,9 @@
from telegramify_markdown.mime import get_filename
from telegramify_markdown.type import TaskType, File, Text, Photo, SentType

if TYPE_CHECKING:
from aiohttp import ClientSession


class BaseInterpreter(object):
name = "base"
Expand Down Expand Up @@ -72,6 +76,10 @@ async def render_task(self,

class MermaidInterpreter(BaseInterpreter):
name = "mermaid"
session = None

def __init__(self, session: "ClientSession" = None):
self.session = session

async def merge(self, tasks: List[TaskType]) -> List[TaskType]:
"""
Expand Down Expand Up @@ -149,7 +157,10 @@ async def render_task(self,
if isinstance(_raw_text, mistletoe.span_token.RawText):
file_content = _raw_text.content
try:
img_io, url = await render_mermaid(file_content.replace("```mermaid", "").replace("```", ""))
img_io, url = await render_mermaid(
diagram=file_content.replace("```mermaid", "").replace("```", ""),
session=self.session
)
message = f"[edit in mermaid.live]({url})"
except Exception as e:
logger.warn(f"Mermaid render error: {e}")
Expand Down
49 changes: 35 additions & 14 deletions src/telegramify_markdown/mermaid.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
from typing import Union, Tuple

from PIL import Image
from aiohttp_client_cache import CachedSession
from aiohttp_client_cache.backends import CacheBackend
from aiohttp import ClientSession

from telegramify_markdown.logger import logger

Expand All @@ -18,25 +17,41 @@ class MermaidConfig:
theme: str = "neutral"


async def download_image(url: str) -> BytesIO:
async def download_image(
url: str,
session: ClientSession = None,
) -> BytesIO:
"""
Download the image from the URL asynchronously.
:param url: Image URL
:raises: aiohttp.ClientError, asyncio.TimeoutError
:param session: Optional aiohttp.ClientSession. If not provided, a new session will be created.
:raises ValueError: If the request fails or the image cannot be downloaded.
:return: BytesIO object containing the image data.
"""
logger.debug(f"telegramify_markdown: Downloading mermaid image from {url}")
headers = {
"User-Agent": ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
"(KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
}
async with CachedSession(cache=CacheBackend(expire_after=60 * 60)) as session:
try:
async with session.get(url, headers=headers, timeout=10) as response:
response.raise_for_status()
content = await response.read()
except Exception as e:
raise ValueError(f"telegramify_markdown: Render failed on the mermaid graph from {url}") from e
return BytesIO(content)

needs_closing = False

if session is None:
session = ClientSession()
needs_closing = True

try:
async with session.get(url, headers=headers, timeout=10) as response:
response.raise_for_status() # Raise exception for HTTP errors (e.g., 404, 500)
content = await response.read() # Read response content as bytes
return BytesIO(content)

except Exception as e:
raise ValueError(f"telegramify_markdown: Render failed on the mermaid graph from {url}") from e
finally:
# Only close the session if we created it
if needs_closing:
await session.close()


def is_image(data: BytesIO) -> bool:
Expand Down Expand Up @@ -133,12 +148,18 @@ def get_mermaid_ink_url(graph_markdown: str) -> str:
return f'https://mermaid.ink/img/{generate_pako(graph_markdown)}?theme=neutral&width=500&scale=2&type=webp'


async def render_mermaid(diagram: str) -> Tuple[BytesIO, str]:
async def render_mermaid(
diagram: str,
session: ClientSession = None,
) -> Tuple[BytesIO, str]:
# render picture
img_url = get_mermaid_ink_url(diagram)
caption = get_mermaid_live_url(diagram)
# Download the image
img_data = await download_image(img_url)
img_data = await download_image(
url=img_url,
session=session
)
if not is_image(img_data):
raise ValueError("The URL does not return an image.")
img_data.seek(0) # Reset the file pointer to the beginning
Expand Down
4 changes: 3 additions & 1 deletion src/telegramify_markdown/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,9 @@ def render_list_item(
) -> Iterable[str]:
token_origin = str(token.leader).strip()
if token_origin.endswith("."):
token.leader = formatting.escape_markdown(token.leader) + " "
if not token.leader.endswith(" "):
token.leader += " "
token.leader = formatting.escape_markdown(token.leader)
else:
token.leader = formatting.escape_markdown("⦁")
return super().render_list_item(token, max_line_length)
Expand Down

0 comments on commit cc274ee

Please sign in to comment.