🎨 更新 Python 依赖版本至 3.10,新增 pre-commit 工作流及配置文件

This commit is contained in:
远野千束(神羽) 2024-12-13 02:23:38 +08:00
parent 8462830c91
commit 8defcfdd66
38 changed files with 350 additions and 229 deletions

24
.github/workflows/pre-commit.yml vendored Normal file
View File

@ -0,0 +1,24 @@
name: Pre-commit checks
on: [push, pull_request]
jobs:
pre-commit:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v3
with:
python-version: '3.10' # 选择适合你的项目的 Python 版本
- name: Install dependencies
run: |
python -m pip install pdm
pdm install
- name: Run pre-commit
run: pre-commit run --all-files

25
.pre-commit-config.yaml Normal file
View File

@ -0,0 +1,25 @@
fail_fast: true
repos:
- repo: https://github.com/timothycrosley/isort
rev: 5.13.2
hooks:
- id: isort
# - repo: https://github.com/psf/black
# rev: 24.4.2
# hooks:
# - id: black
# args: [--config=./pyproject.toml]
# - repo: https://github.com/pre-commit/mirrors-mypy
# rev: v0.910
# hooks:
# - id: mypy
# - repo: https://github.com/pre-commit/pre-commit-hooks
# rev: v4.0.1
# hooks:
# - id: trailing-whitespace
# - id: end-of-file-fixer
# - id: check-yaml
# - id: check-added-large-files

View File

@ -3,8 +3,8 @@ from nonebot.plugin import require
require("nonebot_plugin_alconna") require("nonebot_plugin_alconna")
require("nonebot_plugin_localstore") require("nonebot_plugin_localstore")
from nonebot import get_driver, logger
import nonebot_plugin_localstore as store import nonebot_plugin_localstore as store
from nonebot import get_driver, logger
# from .hunyuan import * # from .hunyuan import *
from .azure import * from .azure import *

View File

@ -1,33 +1,23 @@
import traceback
import contextlib import contextlib
from typing import Optional import traceback
from pathlib import Path from pathlib import Path
from typing import Optional
from arclet.alconna import Alconna, Args, AllParam import nonebot_plugin_localstore as store
from azure.ai.inference.models import ( from arclet.alconna import Alconna, AllParam, Args
UserMessage, from azure.ai.inference.models import (AssistantMessage,
AssistantMessage,
ToolMessage,
TextContentItem,
ImageContentItem,
ImageUrl,
CompletionsFinishReason,
ChatCompletionsToolCall, ChatCompletionsToolCall,
) CompletionsFinishReason,
ImageContentItem, ImageUrl,
TextContentItem, ToolMessage,
UserMessage)
from azure.core.credentials import AzureKeyCredential from azure.core.credentials import AzureKeyCredential
from nonebot import on_command, on_message, logger, get_driver from nonebot import get_driver, logger, on_command, on_message
from nonebot.adapters import Message, Event from nonebot.adapters import Event, Message
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot.rule import Rule, to_me from nonebot.rule import Rule, to_me
from nonebot_plugin_alconna import ( from nonebot_plugin_alconna import MsgTarget, UniMessage, UniMsg, on_alconna
on_alconna,
MsgTarget,
UniMessage,
UniMsg,
)
import nonebot_plugin_localstore as store
from .metadata import metadata from .metadata import metadata
from .models import MarshoContext, MarshoTools from .models import MarshoContext, MarshoTools
@ -203,7 +193,7 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
not text not text
and event.get_message().extract_plain_text() != config.marshoai_default_name and event.get_message().extract_plain_text() != config.marshoai_default_name
): ):
text = event.get_message() text = event.get_message() # type: ignore
if not text: if not text:
# 发送说明 # 发送说明
await UniMessage(metadata.usage + "\n当前使用的模型:" + model_name).send() await UniMessage(metadata.usage + "\n当前使用的模型:" + model_name).send()
@ -233,12 +223,12 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
for i in text: for i in text:
if i.type == "text": if i.type == "text":
if is_support_image_model: if is_support_image_model:
usermsg += [TextContentItem(text=i.data["text"] + nickname_prompt)] usermsg += [TextContentItem(text=i.data["text"] + nickname_prompt)] # type: ignore
else: else:
usermsg += str(i.data["text"] + nickname_prompt) usermsg += str(i.data["text"] + nickname_prompt) # type: ignore
elif i.type == "image": elif i.type == "image":
if is_support_image_model: if is_support_image_model:
usermsg.append( usermsg.append( # type: ignore
ImageContentItem( ImageContentItem(
image_url=ImageUrl( image_url=ImageUrl(
url=str(await get_image_b64(i.data["url"])) url=str(await get_image_b64(i.data["url"]))
@ -260,7 +250,7 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
response = await make_chat( response = await make_chat(
client=client, client=client,
model_name=model_name, model_name=model_name,
msg=context_msg + [UserMessage(content=usermsg)], msg=context_msg + [UserMessage(content=usermsg)], # type: ignore
tools=tools.get_tools_list(), tools=tools.get_tools_list(),
) )
# await UniMessage(str(response)).send() # await UniMessage(str(response)).send()
@ -268,7 +258,7 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
if choice["finish_reason"] == CompletionsFinishReason.STOPPED: if choice["finish_reason"] == CompletionsFinishReason.STOPPED:
# 当对话成功时将dict的上下文添加到上下文类中 # 当对话成功时将dict的上下文添加到上下文类中
context.append( context.append(
UserMessage(content=usermsg).as_dict(), target.id, target.private UserMessage(content=usermsg).as_dict(), target.id, target.private # type: ignore
) )
context.append(choice.message.as_dict(), target.id, target.private) context.append(choice.message.as_dict(), target.id, target.private)
if [target.id, target.private] not in target_list: if [target.id, target.private] not in target_list:
@ -314,12 +304,12 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
tool_call.function.name, function_args tool_call.function.name, function_args
) # 获取返回值 ) # 获取返回值
tool_msg.append( tool_msg.append(
ToolMessage(tool_call_id=tool_call.id, content=func_return) ToolMessage(tool_call_id=tool_call.id, content=func_return) # type: ignore
) )
response = await make_chat( response = await make_chat(
client=client, client=client,
model_name=model_name, model_name=model_name,
msg=context_msg + [UserMessage(content=usermsg)] + tool_msg, msg=context_msg + [UserMessage(content=usermsg)] + tool_msg, # type: ignore
tools=tools.get_tools_list(), tools=tools.get_tools_list(),
) )
choice = response.choices[0] choice = response.choices[0]
@ -327,7 +317,7 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
# 对话成功 添加上下文 # 对话成功 添加上下文
context.append( context.append(
UserMessage(content=usermsg).as_dict(), target.id, target.private UserMessage(content=usermsg).as_dict(), target.id, target.private # type: ignore
) )
# context.append(tool_msg, target.id, target.private) # context.append(tool_msg, target.id, target.private)
context.append(choice.message.as_dict(), target.id, target.private) context.append(choice.message.as_dict(), target.id, target.private)
@ -351,6 +341,7 @@ async def marsho(target: MsgTarget, event: Event, text: Optional[UniMsg] = None)
with contextlib.suppress(ImportError): # 优化先不做() with contextlib.suppress(ImportError): # 优化先不做()
import nonebot.adapters.onebot.v11 # type: ignore import nonebot.adapters.onebot.v11 # type: ignore
from .azure_onebot import poke_notify from .azure_onebot import poke_notify
@poke_notify.handle() @poke_notify.handle()

View File

@ -1,5 +1,5 @@
from nonebot import on_type from nonebot import on_type
from nonebot.rule import to_me
from nonebot.adapters.onebot.v11 import PokeNotifyEvent # type: ignore from nonebot.adapters.onebot.v11 import PokeNotifyEvent # type: ignore
from nonebot.rule import to_me
poke_notify = on_type((PokeNotifyEvent,), rule=to_me()) poke_notify = on_type((PokeNotifyEvent,), rule=to_me())

View File

@ -1,11 +1,11 @@
import shutil import shutil
from pydantic import BaseModel
from nonebot import logger, get_plugin_config
from ruamel.yaml import YAML
import yaml as yaml_
from pathlib import Path from pathlib import Path
import yaml as yaml_
from nonebot import get_plugin_config, logger
from pydantic import BaseModel
from ruamel.yaml import YAML
class ConfigModel(BaseModel): class ConfigModel(BaseModel):
marshoai_use_yaml_config: bool = False marshoai_use_yaml_config: bool = False

View File

@ -1,4 +1,5 @@
import re import re
from .config import config from .config import config
USAGE: str = f"""MarshoAI-NoneBot Beta by Asankilp USAGE: str = f"""MarshoAI-NoneBot Beta by Asankilp

View File

@ -14,10 +14,11 @@ MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details. See the Mulan PSL v2 for more details.
""" """
from typing import Optional, Literal, Tuple
from nonebot import logger
import httpx
import time import time
from typing import Literal, Optional, Tuple
import httpx
from nonebot import logger
class ConvertChannel: class ConvertChannel:
@ -90,7 +91,7 @@ class L2PChannel(ConvertChannel):
@staticmethod @staticmethod
def channel_test() -> int: def channel_test() -> int:
with httpx.Client(timeout=5,verify=False) as client: with httpx.Client(timeout=5, verify=False) as client:
try: try:
start_time = time.time_ns() start_time = time.time_ns()
latex2png = ( latex2png = (
@ -156,7 +157,7 @@ class CDCChannel(ConvertChannel):
@staticmethod @staticmethod
def channel_test() -> int: def channel_test() -> int:
with httpx.Client(timeout=5,verify=False) as client: with httpx.Client(timeout=5, verify=False) as client:
try: try:
start_time = time.time_ns() start_time = time.time_ns()
codecogs = ( codecogs = (
@ -223,7 +224,7 @@ class JRTChannel(ConvertChannel):
@staticmethod @staticmethod
def channel_test() -> int: def channel_test() -> int:
with httpx.Client(timeout=5,verify=False) as client: with httpx.Client(timeout=5, verify=False) as client:
try: try:
start_time = time.time_ns() start_time = time.time_ns()
joeraut = ( joeraut = (

View File

@ -1,27 +1,29 @@
import contextlib import contextlib
import traceback
import json import json
import traceback
from typing import Optional from typing import Optional
from arclet.alconna import Alconna, Args, AllParam from arclet.alconna import Alconna, AllParam, Args
from nonebot import on_command, logger from nonebot import get_driver, logger, on_command
from nonebot.adapters import Message, Event from nonebot.adapters import Event, Message
from nonebot.params import CommandArg from nonebot.params import CommandArg
from nonebot.permission import SUPERUSER from nonebot.permission import SUPERUSER
from nonebot_plugin_alconna import on_alconna, MsgTarget from nonebot_plugin_alconna import MsgTarget, on_alconna
from nonebot_plugin_alconna.uniseg import UniMessage, UniMsg from nonebot_plugin_alconna.uniseg import UniMessage, UniMsg
from nonebot import get_driver
from .config import config
from .constants import * from .constants import *
from .metadata import metadata from .metadata import metadata
from .models import MarshoContext from .models import MarshoContext
from .util_hunyuan import * from .util_hunyuan import *
from .config import config
genimage_cmd = on_alconna( genimage_cmd = on_alconna(
Alconna( Alconna(
"genimage", "genimage",
Args["prompt?", str], Args["prompt?", str],
) )
) )
@genimage_cmd.handle() @genimage_cmd.handle()
async def genimage(event: Event, prompt=None): async def genimage(event: Event, prompt=None):

View File

@ -1,14 +1,15 @@
from .util import *
from .config import config
import os
import json
import importlib import importlib
import json
import os
import sys import sys
# import importlib.util # import importlib.util
import traceback import traceback
from nonebot import logger from nonebot import logger
from .config import config
from .util import *
class MarshoContext: class MarshoContext:
""" """

View File

@ -1,22 +1,26 @@
import httpx
import traceback import traceback
import httpx
async def fetch_calendar(): async def fetch_calendar():
url = 'https://api.bgm.tv/calendar' url = "https://api.bgm.tv/calendar"
headers = { headers = {
'User-Agent': 'LiteyukiStudio/nonebot-plugin-marshoai (https://github.com/LiteyukiStudio/nonebot-plugin-marshoai)' "User-Agent": "LiteyukiStudio/nonebot-plugin-marshoai (https://github.com/LiteyukiStudio/nonebot-plugin-marshoai)"
} }
async with httpx.AsyncClient() as client: async with httpx.AsyncClient() as client:
response = await client.get(url, headers=headers) response = await client.get(url, headers=headers)
#print(response.text) # print(response.text)
return response.json() return response.json()
async def get_bangumi_news(): async def get_bangumi_news():
result = await fetch_calendar() result = await fetch_calendar()
info = "" info = ""
try: try:
for i in result: for i in result:
weekday = i["weekday"]["cn"] weekday = i["weekday"]["cn"]
#print(weekday) # print(weekday)
info += f"{weekday}:" info += f"{weekday}:"
items = i["items"] items = i["items"]
for item in items: for item in items:

View File

@ -1,4 +1,5 @@
import os import os
from zhDateTime import DateTime from zhDateTime import DateTime

View File

@ -1,37 +1,41 @@
from . import mk_Common, mk_Info, mk_MorseCode, mk_NyaCode
from . import mk_Info
from . import mk_Common
from . import mk_MorseCode
from . import mk_NyaCode
# Twisuki # Twisuki
async def twisuki(): async def twisuki():
return str(await mk_Info.twisuki()) return str(await mk_Info.twisuki())
# MegaKits # MegaKits
async def megakits(): async def megakits():
return str(await mk_Info.megakits()) return str(await mk_Info.megakits())
# Random Turntable # Random Turntable
async def random_turntable(upper: int, lower: int = 0): async def random_turntable(upper: int, lower: int = 0):
return str(await mk_Common.random_turntable(upper, lower)) return str(await mk_Common.random_turntable(upper, lower))
# Number Calc # Number Calc
async def number_calc(a: str, b: str, op: str): async def number_calc(a: str, b: str, op: str):
return str(await mk_Common.number_calc(a, b, op)) return str(await mk_Common.number_calc(a, b, op))
# MorseCode Encrypt # MorseCode Encrypt
async def morse_encrypt(msg: str): async def morse_encrypt(msg: str):
return str(await mk_MorseCode.morse_encrypt(msg)) return str(await mk_MorseCode.morse_encrypt(msg))
# MorseCode Decrypt # MorseCode Decrypt
async def morse_decrypt(msg: str): async def morse_decrypt(msg: str):
return str(await mk_MorseCode.morse_decrypt(msg)) return str(await mk_MorseCode.morse_decrypt(msg))
# NyaCode Encrypt # NyaCode Encrypt
async def nya_encode(msg: str): async def nya_encode(msg: str):
return str(await mk_NyaCode.nya_encode(msg)) return str(await mk_NyaCode.nya_encode(msg))
# NyaCode Decrypt # NyaCode Decrypt
async def nya_decode(msg: str): async def nya_decode(msg: str):
return str(await mk_NyaCode.nya_decode(msg)) return str(await mk_NyaCode.nya_decode(msg))

View File

@ -1,9 +1,11 @@
import random import random
# Random Turntable # Random Turntable
async def random_turntable(upper: int, lower: int): async def random_turntable(upper: int, lower: int):
return random.randint(lower, upper) return random.randint(lower, upper)
# Number Calc # Number Calc
async def number_calc(a: str, b: str, op: str): async def number_calc(a: str, b: str, op: str):
a, b = float(a), float(b) a, b = float(a), float(b)
@ -17,7 +19,7 @@ async def number_calc(a: str, b: str, op: str):
case "/": case "/":
return str(a / b) return str(a / b)
case "**": case "**":
return str(a ** b) return str(a**b)
case "%": case "%":
return str(a % b) return str(a % b)
case _: case _:

View File

@ -1,7 +1,8 @@
# Twisuki # Twisuki
async def twisuki(): async def twisuki():
return "Twiuski(苏阳)是megakits插件作者, Github : \"https://github.com/Twisuki\"" return 'Twiuski(苏阳)是megakits插件作者, Github : "https://github.com/Twisuki"'
# MegaKits # MegaKits
async def megakits(): async def megakits():
return "MegaKits插件是一个功能混杂的MarshoAI插件, 由Twisuki(Github : \"https://github.com/Twisuki\")开发, 插件仓库 : \"https://github.com/LiteyukiStudio/marsho-toolsets/tree/main/Twisuki/marshoai-megakits\"" return 'MegaKits插件是一个功能混杂的MarshoAI插件, 由Twisuki(Github : "https://github.com/Twisuki")开发, 插件仓库 : "https://github.com/LiteyukiStudio/marsho-toolsets/tree/main/Twisuki/marshoai-megakits"'

View File

@ -1,17 +1,59 @@
# MorseCode # MorseCode
MorseEncode = { MorseEncode = {
"A": ".-", "B": "-...", "C": "-.-.", "D": "-..", "E": ".", "F": "..-.", "A": ".-",
"G": "--.", "H": "....", "I": "..", "J": ".---", "K": "-.-", "L": ".-..", "B": "-...",
"M": "--", "N": "-.", "O": "---", "P": ".--.", "Q": "--.-", "R": ".-.", "C": "-.-.",
"S": "...", "T": "-", "U": "..-", "V": "...-", "W": ".--", "X": "-..-", "D": "-..",
"Y": "-.--", "Z": "--..", "E": ".",
"1": ".----", "2": "..---", "3": "...--", "4": "....-", "5": ".....", "F": "..-.",
"6": "-....", "7": "--...", "8": "---..", "9": "----.", "0": "-----", "G": "--.",
".": ".-.-.-", ":": "---...", ",": "--..--", ";": "-.-.-.", "H": "....",
"?": "..--..", "=": "-...-", "\'": ".----.", "/": "-..-.", "I": "..",
"!": "-.-.--", "-": "-....-", "_": "..--.-", "\"": ".-..-.", "J": ".---",
"(": "-.--.", ")": "-.--.-", "$": "...-..-", "&": "....", "K": "-.-",
"@": ".--.-.", " ": " " "L": ".-..",
"M": "--",
"N": "-.",
"O": "---",
"P": ".--.",
"Q": "--.-",
"R": ".-.",
"S": "...",
"T": "-",
"U": "..-",
"V": "...-",
"W": ".--",
"X": "-..-",
"Y": "-.--",
"Z": "--..",
"1": ".----",
"2": "..---",
"3": "...--",
"4": "....-",
"5": ".....",
"6": "-....",
"7": "--...",
"8": "---..",
"9": "----.",
"0": "-----",
".": ".-.-.-",
":": "---...",
",": "--..--",
";": "-.-.-.",
"?": "..--..",
"=": "-...-",
"'": ".----.",
"/": "-..-.",
"!": "-.-.--",
"-": "-....-",
"_": "..--.-",
'"': ".-..-.",
"(": "-.--.",
")": "-.--.-",
"$": "...-..-",
"&": "....",
"@": ".--.-.",
" ": " ",
} }
MorseDecode = {value: key for key, value in MorseEncode.items()} MorseDecode = {value: key for key, value in MorseEncode.items()}

View File

@ -1,18 +1,23 @@
import random
import base64 import base64
import random
# NyaCode # NyaCode
NyaCodeCharset = [ NyaCodeCharset = ["", "", "?", "~"]
"", "", "?", "~" NyaCodeSpecialCharset = ["", "!", "...", ".."]
]
NyaCodeSpecialCharset = [
"", "!", "...", ".."
]
NyaCodeEncode = {} NyaCodeEncode = {}
for i in range(64): for i in range(64):
triplet = "".join(NyaCodeCharset[(i // (4 ** j)) % 4] for j in range(3)) triplet = "".join(NyaCodeCharset[(i // (4**j)) % 4] for j in range(3))
NyaCodeEncode[chr(65 + i if i < 26 else 97 + (i - 26) if i < 52 else 48 + (i - 52) if i < 62 else ( NyaCodeEncode[
43 if i == 62 else 47))] = triplet chr(
65 + i
if i < 26
else (
97 + (i - 26)
if i < 52
else 48 + (i - 52) if i < 62 else (43 if i == 62 else 47)
)
)
] = triplet
NyaCodeDecode = {value: key for key, value in NyaCodeEncode.items()} NyaCodeDecode = {value: key for key, value in NyaCodeEncode.items()}
@ -37,7 +42,7 @@ async def nya_decode(msg: str):
msg = msg.replace("", "").replace("!", "").replace(".", "") msg = msg.replace("", "").replace("!", "").replace(".", "")
msg_nyastr = [] msg_nyastr = []
i = 0 i = 0
if len(msg) % 3 != 0 : if len(msg) % 3 != 0:
return "这句话不是正确的猫语" return "这句话不是正确的猫语"
while i < len(msg): while i < len(msg):
nyachar = msg[i : i + 3] nyachar = msg[i : i + 3]

View File

@ -1,16 +1,16 @@
from . import mg_Info, mg_Introduce, mg_Search
from . import mg_Info
from . import mg_Search
from . import mg_Introduce
# meogirl # meogirl
async def meogirl () : async def meogirl():
return mg_Info.meogirl() return mg_Info.meogirl()
# Search # Search
async def search (msg : str, num : int = 3) : async def search(msg: str, num: int = 3):
return str(await mg_Search.search(msg, num)) return str(await mg_Search.search(msg, num))
# Show # Show
async def introduce (msg : str) : async def introduce(msg: str):
return str(await mg_Introduce.introduce(msg)) return str(await mg_Introduce.introduce(msg))

View File

@ -1,4 +1,3 @@
# Meogirl # Meogirl
def meogirl(): def meogirl():
return "Meogirl指的是\"萌娘百科\"(https://zh.moegirl.org.cn/ , 简称\"萌百\"), 是一个\"万物皆可萌的百科全书!\"; 同时, MarshoTools也配有\"Meogirl\"插件, 可调用萌百的api" return 'Meogirl指的是"萌娘百科"(https://zh.moegirl.org.cn/ , 简称"萌百"), 是一个"万物皆可萌的百科全书!"; 同时, MarshoTools也配有"Meogirl"插件, 可调用萌百的api'

View File

@ -1,30 +1,32 @@
from nonebot.log import logger
import re import re
import httpx
import urllib.parse import urllib.parse
import httpx
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from nonebot.log import logger
headers = { headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36" "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
} }
async def get_async_data (url) :
async with httpx.AsyncClient(timeout = None) as client:
return await client.get(url, headers = headers)
async def introduce (msg : str) : async def get_async_data(url):
logger.info(f"介绍 : \"{msg}\" ...") async with httpx.AsyncClient(timeout=None) as client:
return await client.get(url, headers=headers)
async def introduce(msg: str):
logger.info(f'介绍 : "{msg}" ...')
result = "" result = ""
url = "https://mzh.moegirl.org.cn/" + urllib.parse.quote_plus(msg) url = "https://mzh.moegirl.org.cn/" + urllib.parse.quote_plus(msg)
response = await get_async_data(url) response = await get_async_data(url)
logger.success(f"连接\"{url}\"完成, 状态码 : {response.status_code}") logger.success(f'连接"{url}"完成, 状态码 : {response.status_code}')
soup = BeautifulSoup(response.text, "html.parser") soup = BeautifulSoup(response.text, "html.parser")
# 正常页 # 正常页
if response.status_code == 200 : if response.status_code == 200:
""" """
萌娘百科页面结构 萌娘百科页面结构
div#mw-content-text div#mw-content-text
@ -44,7 +46,9 @@ async def introduce (msg : str) :
num = 0 num = 0
for p_tag in p_tags: for p_tag in p_tags:
p = str(p_tag) p = str(p_tag)
p = re.sub(r"<script.*?</script>|<style.*?</style>", "", p, flags=re.DOTALL) p = re.sub(
r"<script.*?</script>|<style.*?</style>", "", p, flags=re.DOTALL
)
p = re.sub(r"<.*?>", "", p, flags=re.DOTALL) p = re.sub(r"<.*?>", "", p, flags=re.DOTALL)
p = re.sub(r"\[.*?]", "", p, flags=re.DOTALL) p = re.sub(r"\[.*?]", "", p, flags=re.DOTALL)
@ -57,20 +61,21 @@ async def introduce (msg : str) :
return result return result
# 空白页 # 空白页
elif response.status_code == 404 : elif response.status_code == 404:
logger.info(f"未找到\"{msg}\", 进行搜索") logger.info(f'未找到"{msg}", 进行搜索')
from . import mg_Search from . import mg_Search
context = await mg_Search.search(msg, 1)
keyword = re.search(r".*?\n", context, flags = re.DOTALL).group()[: -1]
logger.success(f"搜索完成, 打开\"{keyword}\"") context = await mg_Search.search(msg, 1)
keyword = re.search(r".*?\n", context, flags=re.DOTALL).group()[:-1]
logger.success(f'搜索完成, 打开"{keyword}"')
return await introduce(keyword) return await introduce(keyword)
# 搜索失败 # 搜索失败
elif response.status_code == 301 : elif response.status_code == 301:
return f"未找到{msg}" return f"未找到{msg}"
else : else:
logger.error(f"网络错误, 状态码 : {response.status_code}") logger.error(f"网络错误, 状态码 : {response.status_code}")
return f"网络错误, 状态码 : {response.status_code}" return f"网络错误, 状态码 : {response.status_code}"

View File

@ -1,27 +1,29 @@
from nonebot.log import logger import urllib.parse
import httpx import httpx
import urllib.parse
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from nonebot.log import logger
headers = { headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36" "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.127 Safari/537.36"
} }
async def get_async_data (url) :
async with httpx.AsyncClient(timeout = None) as client:
return await client.get(url, headers = headers)
async def search (msg : str, num : int) : async def get_async_data(url):
logger.info(f"搜索 : \"{msg}\" ...") async with httpx.AsyncClient(timeout=None) as client:
return await client.get(url, headers=headers)
async def search(msg: str, num: int):
logger.info(f'搜索 : "{msg}" ...')
result = "" result = ""
url = "https://mzh.moegirl.org.cn/index.php?search=" + urllib.parse.quote_plus(msg) url = "https://mzh.moegirl.org.cn/index.php?search=" + urllib.parse.quote_plus(msg)
response = await get_async_data(url) response = await get_async_data(url)
logger.success(f"连接\"{url}\"完成, 状态码 : {response.status_code}") logger.success(f'连接"{url}"完成, 状态码 : {response.status_code}')
# 正常搜索 # 正常搜索
if response.status_code == 200 : if response.status_code == 200:
""" """
萌娘百科搜索页面结构 萌娘百科搜索页面结构
div.searchresults div.searchresults
@ -37,40 +39,47 @@ async def search (msg : str, num : int) :
soup = BeautifulSoup(response.text, "html.parser") soup = BeautifulSoup(response.text, "html.parser")
# 检测ul.mw-search-results, 是否有结果 # 检测ul.mw-search-results, 是否有结果
ul_tag = soup.find("ul", class_ = "mw-search-results") ul_tag = soup.find("ul", class_="mw-search-results")
if ul_tag : if ul_tag:
li_tags = ul_tag.find_all("li") li_tags = ul_tag.find_all("li")
for li_tag in li_tags : for li_tag in li_tags:
div_heading = li_tag.find("div", class_ = "mw-search-result-heading") div_heading = li_tag.find("div", class_="mw-search-result-heading")
if div_heading : if div_heading:
a_tag = div_heading.find("a") a_tag = div_heading.find("a")
result += a_tag["title"] + "\n" result += a_tag["title"] + "\n"
logger.info(f"搜索到 : \"{a_tag["title"]}\"") logger.info(f'搜索到 : "{a_tag["title"]}"')
div_result = li_tag.find("div", class_="searchresult") div_result = li_tag.find("div", class_="searchresult")
if div_result : if div_result:
content = str(div_result).replace("<div class=\"searchresult\">", "").replace("</div>", "") content = (
content = content.replace("<span class=\"searchmatch\">", "").replace("</span>", "") str(div_result)
.replace('<div class="searchresult">', "")
.replace("</div>", "")
)
content = content.replace('<span class="searchmatch">', "").replace(
"</span>", ""
)
result += content + "\n" result += content + "\n"
num -= 1 num -= 1
if num == 0 : if num == 0:
break break
return result return result
# 无ul.mw-search-results, 无结果 # 无ul.mw-search-results, 无结果
else : else:
logger.info("无结果") logger.info("无结果")
return "无结果" return "无结果"
# 重定向 # 重定向
elif response.status_code == 302 : elif response.status_code == 302:
logger.info(f"\"{msg}\"已被重定向至\"{response.headers.get("location")}\"") logger.info(f'"{msg}"已被重定向至"{response.headers.get("location")}"')
# 读取重定向结果 # 读取重定向结果
from . import mg_Introduce from . import mg_Introduce
return await mg_Introduce.introduce(msg) return await mg_Introduce.introduce(msg)
else : else:
logger.error(f"网络错误, 状态码 : {response.status_code}") logger.error(f"网络错误, 状态码 : {response.status_code}")
return f"网络错误, 状态码 : {response.status_code}" return f"网络错误, 状态码 : {response.status_code}"

View File

@ -1,26 +1,19 @@
import os
import json
import uuid
import httpx
import base64 import base64
import json
import mimetypes import mimetypes
import os
import uuid
from typing import Any, Optional from typing import Any, Optional
from nonebot.log import logger import httpx
import nonebot_plugin_localstore as store import nonebot_plugin_localstore as store
from nonebot_plugin_alconna import (
Text as TextMsg,
Image as ImageMsg,
UniMessage,
)
# from zhDateTime import DateTime # from zhDateTime import DateTime
from azure.ai.inference.aio import ChatCompletionsClient from azure.ai.inference.aio import ChatCompletionsClient
from azure.ai.inference.models import SystemMessage from azure.ai.inference.models import SystemMessage
from nonebot.log import logger
from nonebot_plugin_alconna import Image as ImageMsg
from nonebot_plugin_alconna import Text as TextMsg
from nonebot_plugin_alconna import UniMessage
from .config import config from .config import config
from .constants import * from .constants import *
@ -304,7 +297,7 @@ if config.marshoai_enable_richtext_parse:
if not IMG_LATEX_PATTERN.search(msg): # 没有图片和LaTeX标签 if not IMG_LATEX_PATTERN.search(msg): # 没有图片和LaTeX标签
return UniMessage(msg) return UniMessage(msg)
result_msg = UniMessage() result_msg = UniMessage() # type: ignore
code_blank_uuid_map = [ code_blank_uuid_map = [
(uuid.uuid4().hex, cbp.group()) for cbp in CODE_BLOCK_PATTERN.finditer(msg) (uuid.uuid4().hex, cbp.group()) for cbp in CODE_BLOCK_PATTERN.finditer(msg)
] ]
@ -380,7 +373,7 @@ if config.marshoai_enable_richtext_parse:
if latex_generate_ok: if latex_generate_ok:
result_msg.append( result_msg.append(
ImageMsg( ImageMsg(
raw=latex_generate_result, raw=latex_generate_result, # type: ignore
mimetype="image/png", mimetype="image/png",
name="latex.png", name="latex.png",
) )

View File

@ -1,12 +1,16 @@
import json import json
import types import types
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile from tencentcloud.common import credential # type: ignore
from tencentcloud.common.profile.http_profile import HttpProfile from tencentcloud.common.exception.tencent_cloud_sdk_exception import \
from tencentcloud.common.exception.tencent_cloud_sdk_exception import ( TencentCloudSDKException # type: ignore
TencentCloudSDKException, from tencentcloud.common.profile.client_profile import \
) ClientProfile # type: ignore
from tencentcloud.hunyuan.v20230901 import hunyuan_client, models from tencentcloud.common.profile.http_profile import \
HttpProfile # type: ignore
from tencentcloud.hunyuan.v20230901 import hunyuan_client # type: ignore
from tencentcloud.hunyuan.v20230901 import models
from .config import config from .config import config

View File

@ -3,7 +3,7 @@ name = "nonebot-plugin-marshoai"
dynamic = ["version"] dynamic = ["version"]
description = "Nonebot2插件调用Azure OpenAI等AI服务实现猫娘聊天" description = "Nonebot2插件调用Azure OpenAI等AI服务实现猫娘聊天"
readme = "README.md" readme = "README.md"
requires-python = "<4.0,>=3.9" requires-python = "<4.0,>=3.10"
authors = [{ name = "Asankilp", email = "asankilp@outlook.com" }] authors = [{ name = "Asankilp", email = "asankilp@outlook.com" }]
dependencies = [ dependencies = [
"nonebot2>=2.2.0", "nonebot2>=2.2.0",
@ -14,7 +14,9 @@ dependencies = [
"aiohttp>=3.9", "aiohttp>=3.9",
"httpx>=0.27.0", "httpx>=0.27.0",
"ruamel.yaml>=0.18.6", "ruamel.yaml>=0.18.6",
"pyyaml>=6.0.2" "pyyaml>=6.0.2",
"psutil>=6.1.0",
"beautifulsoup4>=4.12.3"
] ]
license = { text = "MIT, Mulan PSL v2" } license = { text = "MIT, Mulan PSL v2" }
@ -32,6 +34,9 @@ adapters = [
[tool.pdm] [tool.pdm]
distribution = true distribution = true
python.use_venv = true
python.venv_in_project = true
[tool.pdm.version] [tool.pdm.version]
source = "scm" source = "scm"
@ -49,4 +54,6 @@ build-backend = "pdm.backend"
dev = [ dev = [
"nb-cli>=1.4.2", "nb-cli>=1.4.2",
"pytest>=8.3.4", "pytest>=8.3.4",
"pre-commit>=4.0.1",
"nonebot-adapter-onebot>=2.4.6",
] ]

View File

@ -1,7 +1,7 @@
import logging import logging
def test_none(): def test_none():
"""基准测试示例 """基准测试示例"""
"""
logging.info("测试成功") logging.info("测试成功")
pass pass