nonebot-plugin-latex 0.0.2.3__tar.gz → 0.0.3.1__tar.gz

Sign up to get free protection for your applications and to get access to all the features.
Files changed (17) hide show
  1. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/PKG-INFO +3 -3
  2. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex/__init__.py +17 -8
  3. nonebot_plugin_latex-0.0.3.1/nonebot_plugin_latex/converter.py +13 -0
  4. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex/data.py +91 -65
  5. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex/main.py +16 -27
  6. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex.egg-info/PKG-INFO +3 -3
  7. nonebot_plugin_latex-0.0.3.1/nonebot_plugin_latex.egg-info/requires.txt +3 -0
  8. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/pyproject.toml +6 -3
  9. nonebot_plugin_latex-0.0.2.3/nonebot_plugin_latex/converter.py +0 -6
  10. nonebot_plugin_latex-0.0.2.3/nonebot_plugin_latex.egg-info/requires.txt +0 -3
  11. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/LICENSE +0 -0
  12. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/README.md +0 -0
  13. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex/config.py +0 -0
  14. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex.egg-info/SOURCES.txt +0 -0
  15. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex.egg-info/dependency_links.txt +0 -0
  16. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/nonebot_plugin_latex.egg-info/top_level.txt +0 -0
  17. {nonebot_plugin_latex-0.0.2.3 → nonebot_plugin_latex-0.0.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nonebot-plugin-latex
3
- Version: 0.0.2.3
3
+ Version: 0.0.3.1
4
4
  Summary: 通过互联网公共服务渲染LaTeX公式
5
5
  Author-email: Eilles <EillesWan@outlook.com>
6
6
  License: 木兰宽松许可证, 第2版
@@ -136,9 +136,9 @@ Project-URL: Bug Tracker, https://github.com/EillesWan/nonebot-plugin-latex/issu
136
136
  Requires-Python: <4.0,>=3.9
137
137
  Description-Content-Type: text/markdown
138
138
  License-File: LICENSE
139
- Requires-Dist: nonebot2>=2.2.0
139
+ Requires-Dist: nonebot2<1000.0.0,>=2.2.0
140
140
  Requires-Dist: httpx<0.28.0,>=0.27.0
141
- Requires-Dist: nonebot-adapter-onebot>=2.4.3
141
+ Requires-Dist: nonebot-plugin-alconna<1000.0.0,>=0.48.0
142
142
 
143
143
  # nonebot-plugin-latex
144
144
 
@@ -13,25 +13,34 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13
13
  See the Mulan PSL v2 for more details.
14
14
  """
15
15
 
16
- from nonebot import get_plugin_config
17
- from nonebot.plugin import PluginMetadata
16
+ from nonebot import get_plugin_config, get_driver
17
+ from nonebot.plugin import PluginMetadata, inherit_supported_adapters
18
18
 
19
19
  from .config import Config
20
- from .converter import converter
20
+ from .converter import _converter, get_converter
21
21
 
22
- __version__ = "0.0.2.3"
22
+ __version__ = "0.0.3.1"
23
23
 
24
24
  __author__ = "Eilles"
25
25
 
26
26
  __plugin_meta__ = PluginMetadata(
27
- name="LaTeX图形渲染插件",
28
- description="从互联网服务渲染LaTeX公式并发送",
27
+ name="LaTeX 在线渲染插件",
28
+ description="从互联网服务渲染 LaTeX 公式",
29
29
  usage="发送 latex 或 公式,后接内容或回复公式信息。",
30
- type="application",
31
- homepage="https://github.com/LiteyukiStudio/nonebot-plugin-marshoai",
30
+ type="library",
31
+ homepage="https://github.com/EillesWan/nonebot-plugin-latex",
32
+ config=Config,
33
+ supported_adapters=inherit_supported_adapters("nonebot_plugin_alconna"),
32
34
  extra={"License": "Mulan PSL v2", "Author": __author__},
33
35
  )
34
36
 
37
+ __all__ = ["get_converter"]
38
+
39
+
40
+ @get_driver().on_startup
41
+ async def init():
42
+ await _converter.load_channel()
43
+
35
44
 
36
45
  config = get_plugin_config(Config)
37
46
 
@@ -0,0 +1,13 @@
1
+ from .data import ConvertLatex
2
+
3
+ _converter = ConvertLatex()
4
+ """
5
+ Latex 渲染器
6
+ """
7
+
8
+
9
+ def get_converter() -> ConvertLatex:
10
+ """
11
+ 获取渲染器
12
+ """
13
+ return _converter
@@ -13,10 +13,23 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13
13
  See the Mulan PSL v2 for more details.
14
14
  """
15
15
 
16
- from typing import Optional, Literal, Tuple
17
- import httpx
18
- import time
19
16
  import re
17
+ import time
18
+ import asyncio
19
+ from typing import Literal, Optional, Tuple
20
+
21
+ import httpx
22
+ from nonebot import logger
23
+
24
+
25
+ # 正则匹配 LaTeX 公式内容
26
+ LATEX_PATTERN = re.compile(
27
+ r"\\begin\{equation\}(.*?)\\end\{equation\}|(?<!\$)(\$(.*?)\$|\$\$(.*?)\$\$|\\\[(.*?)\\\]|\\\[.*?\\\]|\\\((.*?)\\\))",
28
+ re.DOTALL,
29
+ )
30
+
31
+
32
+ MAX_TIME = 0xFFFFFF
20
33
 
21
34
 
22
35
  class ConvertChannel:
@@ -33,8 +46,8 @@ class ConvertChannel:
33
46
  return False, "请勿直接调用母类"
34
47
 
35
48
  @staticmethod
36
- def channel_test() -> int:
37
- return -1
49
+ async def channel_test() -> int:
50
+ return MAX_TIME
38
51
 
39
52
 
40
53
  class L2PChannel(ConvertChannel):
@@ -52,6 +65,7 @@ class L2PChannel(ConvertChannel):
52
65
 
53
66
  async with httpx.AsyncClient(
54
67
  timeout=timeout,
68
+ verify=False,
55
69
  ) as client:
56
70
  while retry > 0:
57
71
  try:
@@ -87,36 +101,38 @@ class L2PChannel(ConvertChannel):
87
101
  return False, "未知错误"
88
102
 
89
103
  @staticmethod
90
- def channel_test() -> int:
91
- with httpx.Client(timeout=5) as client:
104
+ async def channel_test() -> int:
105
+ async with httpx.AsyncClient(timeout=5, verify=False) as client:
92
106
  try:
93
107
  start_time = time.time_ns()
94
108
  latex2png = (
95
- client.get(
109
+ await client.get(
96
110
  "http://www.latex2png.com{}"
97
- + client.post(
98
- "http://www.latex2png.com/api/convert",
99
- json={
100
- "auth": {"user": "guest", "password": "guest"},
101
- "latex": "\\\\int_{a}^{b} x^2 \\\\, dx = \\\\frac{b^3}{3} - \\\\frac{a^3}{5}\n",
102
- "resolution": 600,
103
- "color": "000000",
104
- },
111
+ + (
112
+ await client.post(
113
+ "http://www.latex2png.com/api/convert",
114
+ json={
115
+ "auth": {"user": "guest", "password": "guest"},
116
+ "latex": "\\\\int_{a}^{b} x^2 \\\\, dx = \\\\frac{b^3}{3} - \\\\frac{a^3}{5}\n",
117
+ "resolution": 600,
118
+ "color": "000000",
119
+ },
120
+ )
105
121
  ).json()["url"]
106
122
  ),
107
123
  time.time_ns() - start_time,
108
124
  )
109
125
  except:
110
- return 99999
126
+ return MAX_TIME
111
127
  if latex2png[0].status_code == 200:
112
128
  return latex2png[1]
113
129
  else:
114
- return 99999
130
+ return MAX_TIME
115
131
 
116
132
 
117
133
  class CDCChannel(ConvertChannel):
118
134
 
119
- URL = "http://latex.codecogs.com"
135
+ URL = "https://latex.codecogs.com"
120
136
 
121
137
  async def get_to_convert(
122
138
  self,
@@ -128,6 +144,7 @@ class CDCChannel(ConvertChannel):
128
144
  ) -> Tuple[Literal[True], bytes] | Tuple[Literal[False], bytes | str]:
129
145
  async with httpx.AsyncClient(
130
146
  timeout=timeout,
147
+ verify=False,
131
148
  ) as client:
132
149
 
133
150
  while retry > 0:
@@ -152,27 +169,27 @@ class CDCChannel(ConvertChannel):
152
169
  return False, "未知错误"
153
170
 
154
171
  @staticmethod
155
- def channel_test() -> int:
156
- with httpx.Client(timeout=5) as client:
172
+ async def channel_test() -> int:
173
+ async with httpx.AsyncClient(timeout=5, verify=False) as client:
157
174
  try:
158
175
  start_time = time.time_ns()
159
176
  codecogs = (
160
- client.get(
161
- r"http://latex.codecogs.com/png.image?\huge%20\dpi{600}\\int_{a}^{b}x^2\\,dx=\\frac{b^3}{3}-\\frac{a^3}{5}"
177
+ await client.get(
178
+ r"https://latex.codecogs.com/png.image?\huge%20\dpi{600}\\int_{a}^{b}x^2\\,dx=\\frac{b^3}{3}-\\frac{a^3}{5}"
162
179
  ),
163
180
  time.time_ns() - start_time,
164
181
  )
165
182
  except:
166
- return 99999
183
+ return MAX_TIME
167
184
  if codecogs[0].status_code == 200:
168
185
  return codecogs[1]
169
186
  else:
170
- return 99999
187
+ return MAX_TIME
171
188
 
172
189
 
173
190
  class JRTChannel(ConvertChannel):
174
191
 
175
- URL = "http://latex2image.joeraut.com"
192
+ URL = "https://latex2image.joeraut.com"
176
193
 
177
194
  async def get_to_convert(
178
195
  self,
@@ -185,6 +202,7 @@ class JRTChannel(ConvertChannel):
185
202
 
186
203
  async with httpx.AsyncClient(
187
204
  timeout=timeout,
205
+ verify=False,
188
206
  ) as client:
189
207
  while retry > 0:
190
208
  try:
@@ -196,7 +214,6 @@ class JRTChannel(ConvertChannel):
196
214
  "outputScale": "{}%".format(dpi / 3 * 5),
197
215
  },
198
216
  )
199
- print(post_response)
200
217
  if post_response.status_code == 200:
201
218
 
202
219
  if not (json_response := post_response.json())["error"]:
@@ -218,29 +235,31 @@ class JRTChannel(ConvertChannel):
218
235
  return False, "未知错误"
219
236
 
220
237
  @staticmethod
221
- def channel_test() -> int:
222
- with httpx.Client(timeout=5) as client:
238
+ async def channel_test() -> int:
239
+ async with httpx.AsyncClient(timeout=5, verify=False) as client:
223
240
  try:
224
241
  start_time = time.time_ns()
225
242
  joeraut = (
226
- client.get(
227
- client.post(
228
- "http://www.latex2png.com/api/convert",
229
- json={
230
- "latexInput": "\\\\int_{a}^{b} x^2 \\\\, dx = \\\\frac{b^3}{3} - \\\\frac{a^3}{5}",
231
- "outputFormat": "PNG",
232
- "outputScale": "1000%",
233
- },
243
+ await client.get(
244
+ (
245
+ await client.post(
246
+ "http://www.latex2png.com/api/convert",
247
+ json={
248
+ "latexInput": "\\\\int_{a}^{b} x^2 \\\\, dx = \\\\frac{b^3}{3} - \\\\frac{a^3}{5}",
249
+ "outputFormat": "PNG",
250
+ "outputScale": "1000%",
251
+ },
252
+ )
234
253
  ).json()["imageUrl"]
235
254
  ),
236
255
  time.time_ns() - start_time,
237
256
  )
238
257
  except:
239
- return 99999
258
+ return MAX_TIME
240
259
  if joeraut[0].status_code == 200:
241
260
  return joeraut[1]
242
261
  else:
243
- return 99999
262
+ return MAX_TIME
244
263
 
245
264
 
246
265
  CHANNEL_LIST: list[type[ConvertChannel]] = [L2PChannel, CDCChannel, JRTChannel]
@@ -248,20 +267,17 @@ CHANNEL_LIST: list[type[ConvertChannel]] = [L2PChannel, CDCChannel, JRTChannel]
248
267
 
249
268
  class ConvertLatex:
250
269
 
251
- channel: ConvertChannel
252
-
253
- def __init__(self, channel: Optional[ConvertChannel] = None) -> None:
254
- """
255
- LaTeX在线渲染类
270
+ channel: Optional[ConvertChannel]
256
271
 
257
- Args:
258
- channel (Optional[ConvertChannel], optional):
259
- 选择何种在线转换通道,若为空,则自动选择延迟最低的通道。默认为空。
260
- [WARNING] 请注意!选择通道时采取的是同步函数,因此可能造成阻塞。
261
- """
272
+ def __init__(self, channel: Optional[ConvertChannel] = None):
273
+ self.channel = channel
274
+ logger.info("LaTeX 转换服务将在 Bot 连接时异步加载")
262
275
 
276
+ async def load_channel(self, channel: ConvertChannel | None = None) -> None:
263
277
  if channel is None:
264
- self.channel = self.auto_choose_channel()
278
+ logger.info("正在选择 LaTeX 转换服务频道,请稍等...")
279
+ self.channel = await self.auto_choose_channel()
280
+ logger.info(f"已选择 {self.channel.__class__.__name__} 服务频道")
265
281
  else:
266
282
  self.channel = channel
267
283
 
@@ -276,8 +292,7 @@ class ConvertLatex:
276
292
  """
277
293
  LaTeX 在线渲染
278
294
 
279
- 参数
280
- ====
295
+ 参数:
281
296
 
282
297
  latex: str
283
298
  LaTeX 代码
@@ -289,26 +304,37 @@ class ConvertLatex:
289
304
  超时时间
290
305
  retry_: int
291
306
  重试次数
292
- 返回
293
- ====
307
+ 返回:
294
308
  bytes
295
309
  图片
296
310
  """
297
- return await self.channel.get_to_convert(
311
+ if self.channel is None:
312
+ await self.load_channel()
313
+
314
+ return await self.channel.get_to_convert( # type: ignore
298
315
  latex, dpi, foreground_colour, timeout_, retry_
299
316
  )
300
317
 
301
318
  @staticmethod
302
- def auto_choose_channel() -> ConvertChannel:
319
+ async def auto_choose_channel() -> ConvertChannel:
320
+ """
321
+ 依据访问延迟,自动选择 LaTeX 转换服务频道
303
322
 
304
- return min(
305
- CHANNEL_LIST,
306
- key=lambda channel: channel.channel_test(),
307
- )()
323
+ 返回
324
+ ====
325
+ ConvertChannel
326
+ LaTeX 转换服务实例
327
+ """
308
328
 
329
+ async def channel_test_wrapper(
330
+ channel: type[ConvertChannel],
331
+ ) -> Tuple[int, type[ConvertChannel]]:
332
+ score = await channel.channel_test()
333
+ return score, channel
309
334
 
310
- # 正则匹配 LaTeX 公式内容
311
- LATEX_PATTERN = re.compile(
312
- r"\\begin\{equation\}(.*?)\\end\{equation\}|(?<!\$)(\$(.*?)\$|\$\$(.*?)\$\$|\\\[(.*?)\\\]|\\\[.*?\\\]|\\\((.*?)\\\))",
313
- re.DOTALL,
314
- )
335
+ return min(
336
+ await asyncio.gather(
337
+ *(channel_test_wrapper(channel) for channel in CHANNEL_LIST)
338
+ ),
339
+ key=lambda x: x[0],
340
+ )[1]()
@@ -14,22 +14,22 @@ See the Mulan PSL v2 for more details.
14
14
  """
15
15
 
16
16
  import nonebot
17
- from nonebot.adapters.onebot.v11 import MessageEvent
18
17
 
18
+ from nonebot_plugin_alconna.uniseg import Text
19
19
 
20
- # from nonebot.matcher import Matcher
21
20
 
22
21
  nonebot.require("nonebot_plugin_alconna")
23
22
 
24
- # from nonebot_plugin_alconna.util import annotation
25
23
  from nonebot_plugin_alconna import (
26
24
  Image as Alconna_Image,
25
+ Reply,
27
26
  Text as Alconnna_Text,
28
27
  UniMessage,
28
+ UniMsg
29
29
  )
30
30
 
31
31
  from .data import LATEX_PATTERN
32
- from .converter import converter
32
+ from .converter import _converter
33
33
 
34
34
  command_heads = (
35
35
  "latex",
@@ -47,28 +47,16 @@ command_heads = (
47
47
 
48
48
 
49
49
  async def check_for_scan(
50
- event: MessageEvent,
50
+ msg: UniMsg,
51
51
  # state: T_State,
52
52
  ) -> bool:
53
53
  """
54
54
  检查是否为 LaTeX 指令
55
55
  """
56
-
57
- # print("检查消息满足渲染要求:", event)
58
- if isinstance(event, MessageEvent):
59
- # print("此为原始信息:", event.raw_message)
60
- # event.message
61
- for msg in event.message:
62
- # print("这是其中一个信息---", msg)
63
- if msg.type == "text" and (msgdata := msg.data["text"].strip()):
64
- if msgdata.startswith(command_heads):
65
-
66
- # print("判断:这确实是指令发出")
67
- return True
68
- else:
69
- # print("判断:这不是指令")
70
- return False
71
- return False
56
+ return any(
57
+ isinstance(seg, Text) and seg.text.strip().startswith(command_heads)
58
+ for seg in msg
59
+ )
72
60
 
73
61
 
74
62
  latexg = nonebot.on_message(
@@ -80,18 +68,19 @@ latexg = nonebot.on_message(
80
68
 
81
69
  @latexg.handle()
82
70
  async def handle_pic(
83
- event: MessageEvent,
71
+ msgs: UniMsg,
84
72
  # state: T_State,
85
73
  # arg: Optional[Message] = CommandArg(),
86
74
  ):
87
75
  # print("正在解决reply指令……")
88
76
  latexes = []
89
- if event.reply:
90
- latexes.extend(LATEX_PATTERN.finditer(event.reply.message.extract_plain_text()))
77
+ if msgs.has(Reply):
78
+ i = msgs[Reply, 0]
79
+ if i.msg:
80
+ latexes.extend(LATEX_PATTERN.finditer(i.msg if isinstance(i.msg, str) else i.msg.extract_plain_text()))
91
81
 
92
82
  # print(arg)
93
- if event.message:
94
- latexes.extend(LATEX_PATTERN.finditer(event.message.extract_plain_text()))
83
+ latexes.extend(LATEX_PATTERN.finditer(msgs.extract_plain_text()))
95
84
 
96
85
  if not latexes:
97
86
  await latexg.finish(
@@ -103,7 +92,7 @@ async def handle_pic(
103
92
 
104
93
  for tex_macher in latexes:
105
94
  tex = tex_macher.group().replace("$", "")
106
- if (result := await converter.generate_png(tex))[0]:
95
+ if (result := await _converter.generate_png(tex))[0]:
107
96
  result_msg.append(
108
97
  Alconna_Image(raw=result[1], mimetype="image/png", name="latex.png") # type: ignore
109
98
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: nonebot-plugin-latex
3
- Version: 0.0.2.3
3
+ Version: 0.0.3.1
4
4
  Summary: 通过互联网公共服务渲染LaTeX公式
5
5
  Author-email: Eilles <EillesWan@outlook.com>
6
6
  License: 木兰宽松许可证, 第2版
@@ -136,9 +136,9 @@ Project-URL: Bug Tracker, https://github.com/EillesWan/nonebot-plugin-latex/issu
136
136
  Requires-Python: <4.0,>=3.9
137
137
  Description-Content-Type: text/markdown
138
138
  License-File: LICENSE
139
- Requires-Dist: nonebot2>=2.2.0
139
+ Requires-Dist: nonebot2<1000.0.0,>=2.2.0
140
140
  Requires-Dist: httpx<0.28.0,>=0.27.0
141
- Requires-Dist: nonebot-adapter-onebot>=2.4.3
141
+ Requires-Dist: nonebot-plugin-alconna<1000.0.0,>=0.48.0
142
142
 
143
143
  # nonebot-plugin-latex
144
144
 
@@ -0,0 +1,3 @@
1
+ nonebot2<1000.0.0,>=2.2.0
2
+ httpx<0.28.0,>=0.27.0
3
+ nonebot-plugin-alconna<1000.0.0,>=0.48.0
@@ -1,12 +1,12 @@
1
1
  [project]
2
2
  name = "nonebot-plugin-latex"
3
- version = "0.0.2.3"
3
+ version = "0.0.3.1"
4
4
  description = "通过互联网公共服务渲染LaTeX公式"
5
5
  authors = [{ name = "Eilles", email = "EillesWan@outlook.com" }]
6
6
  dependencies = [
7
- "nonebot2>=2.2.0",
7
+ "nonebot2>=2.2.0,<1000.0.0",
8
8
  "httpx>=0.27.0,<0.28.0",
9
- "nonebot-adapter-onebot>=2.4.3",
9
+ "nonebot-plugin-alconna>=0.48.0,<1000.0.0",
10
10
  ]
11
11
  requires-python = ">=3.9,<4.0"
12
12
  readme = "README.md"
@@ -15,3 +15,6 @@ license = { file = "LICENSE" }
15
15
  [project.urls]
16
16
  "Homepage" = "https://github.com/EillesWan/nonebot-plugin-latex"
17
17
  "Bug Tracker" = "https://github.com/EillesWan/nonebot-plugin-latex/issues"
18
+
19
+ [tool.pyright]
20
+ typeCheckingMode = "standard"
@@ -1,6 +0,0 @@
1
- from .data import ConvertLatex
2
-
3
- converter = ConvertLatex()
4
- """
5
- Latex 渲染器
6
- """
@@ -1,3 +0,0 @@
1
- nonebot2>=2.2.0
2
- httpx<0.28.0,>=0.27.0
3
- nonebot-adapter-onebot>=2.4.3