mirror of
https://github.com/LiteyukiStudio/nonebot-plugin-marshoai.git
synced 2025-01-26 18:12:47 +08:00
✨ 添加开发模式配置;新增入口文件和函数调用处理逻辑;重构文档字符串解析类
This commit is contained in:
parent
52046ba032
commit
4083aba99f
16
main.py
Normal file
16
main.py
Normal file
@ -0,0 +1,16 @@
|
||||
"""该入口文件仅在nb run无法正常工作时使用
|
||||
"""
|
||||
|
||||
import nonebot
|
||||
from nonebot import get_driver
|
||||
from nonebot.adapters.onebot.v11 import Adapter
|
||||
from nonebot.plugin import load_plugin
|
||||
|
||||
nonebot.init()
|
||||
load_plugin("nonebot_plugin_marshoai")
|
||||
|
||||
driver = get_driver()
|
||||
driver.register_adapter(Adapter)
|
||||
|
||||
if __name__ == "__main__":
|
||||
nonebot.run()
|
@ -49,6 +49,9 @@ class ConfigModel(BaseModel):
|
||||
marshoai_tencent_secretkey: str | None = None
|
||||
|
||||
marshoai_plugin_dirs: list[str] = []
|
||||
"""插件目录(不是工具)"""
|
||||
marshoai_devmode: bool = False
|
||||
"""开发者模式"""
|
||||
|
||||
|
||||
yaml = YAML()
|
||||
|
@ -204,7 +204,6 @@ class JRTChannel(ConvertChannel):
|
||||
"outputScale": "{}%".format(dpi / 3 * 5),
|
||||
},
|
||||
)
|
||||
print(post_response)
|
||||
if post_response.status_code == 200:
|
||||
|
||||
if not (json_response := post_response.json())["error"]:
|
||||
|
7
nonebot_plugin_marshoai/dev.py
Normal file
7
nonebot_plugin_marshoai/dev.py
Normal file
@ -0,0 +1,7 @@
|
||||
from nonebot import require
|
||||
|
||||
require("nonebot_plugin_alconna")
|
||||
|
||||
from nonebot_plugin_alconna import Alconna, on_alconna
|
||||
|
||||
function_call = on_alconna("marshocall")
|
10
nonebot_plugin_marshoai/plugin/docstring/__init__.py
Normal file
10
nonebot_plugin_marshoai/plugin/docstring/__init__.py
Normal file
@ -0,0 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午1:46
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : __init__.py.py
|
||||
@Software: PyCharm
|
||||
"""
|
123
nonebot_plugin_marshoai/plugin/docstring/docstring.py
Normal file
123
nonebot_plugin_marshoai/plugin/docstring/docstring.py
Normal file
@ -0,0 +1,123 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Copyright (C) 2020-2024 LiteyukiStudio. All Rights Reserved
|
||||
|
||||
@Time : 2024/8/28 下午1:46
|
||||
@Author : snowykami
|
||||
@Email : snowykami@outlook.com
|
||||
@File : docstring.py
|
||||
@Software: PyCharm
|
||||
"""
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class Attr(BaseModel):
|
||||
name: str
|
||||
type: str = ""
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Args(BaseModel):
|
||||
name: str
|
||||
type: str = ""
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Return(BaseModel):
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Exception_(BaseModel):
|
||||
name: str
|
||||
desc: str = ""
|
||||
|
||||
|
||||
class Raise(BaseModel):
|
||||
exceptions: list[Exception_] = []
|
||||
|
||||
|
||||
class Example(BaseModel):
|
||||
desc: str = ""
|
||||
input: str = ""
|
||||
output: str = ""
|
||||
|
||||
|
||||
class Docstring(BaseModel):
|
||||
raw: str = ""
|
||||
desc: str = ""
|
||||
args: list[Args] = []
|
||||
attrs: list[Attr] = []
|
||||
return_: Optional[Return] = None
|
||||
raise_: list[Exception_] = []
|
||||
example: Optional[str] = None
|
||||
|
||||
front_matter: Optional[dict[str, str]] = None
|
||||
|
||||
is_module: bool = False
|
||||
|
||||
def add_desc(self, desc: str):
|
||||
if self.desc == "":
|
||||
self.desc = desc
|
||||
else:
|
||||
self.desc += "\n" + desc
|
||||
|
||||
def add_arg(self, name: str, type_: str = "", desc: str = ""):
|
||||
self.args.append(Args(name=name, type=type_, desc=desc))
|
||||
|
||||
def add_attrs(self, name: str, type_: str = "", desc: str = ""):
|
||||
self.attrs.append(Attr(name=name, type=type_, desc=desc))
|
||||
|
||||
def add_return(self, desc: str = ""):
|
||||
self.return_ = Return(desc=desc)
|
||||
|
||||
def add_raise(self, name: str, desc: str = ""):
|
||||
self.raise_.append(Exception_(name=name, desc=desc))
|
||||
|
||||
def add_example(self, desc: str = ""):
|
||||
if self.example is None:
|
||||
self.example = desc
|
||||
else:
|
||||
self.example += "\n" + desc
|
||||
|
||||
def add_front_matter(self, key: str, value: str):
|
||||
if self.front_matter is None:
|
||||
self.front_matter = {}
|
||||
self.front_matter[key] = value
|
||||
|
||||
def reduction(self, style: str = "google") -> str:
|
||||
"""
|
||||
通过解析结果还原docstring
|
||||
Args:
|
||||
style: docstring风格
|
||||
Returns:
|
||||
|
||||
"""
|
||||
ret = ""
|
||||
if style == "google":
|
||||
ret += self.desc + "\n"
|
||||
if self.args:
|
||||
ret += "Args:\n"
|
||||
for arg in self.args:
|
||||
ret += f" {arg.name}: {arg.type}\n {arg.desc}\n"
|
||||
if self.attrs:
|
||||
ret += "Attributes:\n"
|
||||
for attr in self.attrs:
|
||||
ret += f" {attr.name}: {attr.type}\n {attr.desc}\n"
|
||||
if self.return_:
|
||||
ret += "Returns:\n"
|
||||
ret += f" {self.return_.desc}\n"
|
||||
|
||||
if self.raise_:
|
||||
ret += "Raises:\n"
|
||||
for exception in self.raise_:
|
||||
ret += f" {exception.name}\n {exception.desc}\n"
|
||||
|
||||
if self.example:
|
||||
ret += "Examples:\n"
|
||||
ret += f" {self.example}\n"
|
||||
return ret
|
||||
|
||||
def __str__(self):
|
||||
return self.desc
|
222
nonebot_plugin_marshoai/plugin/docstring/parser.py
Normal file
222
nonebot_plugin_marshoai/plugin/docstring/parser.py
Normal file
@ -0,0 +1,222 @@
|
||||
"""
|
||||
Google docstring parser for Python.
|
||||
"""
|
||||
|
||||
from typing import Optional
|
||||
|
||||
from .docstring import Docstring
|
||||
|
||||
placeholder = {
|
||||
"%20": " ",
|
||||
"%3A": ":",
|
||||
}
|
||||
|
||||
|
||||
def reduction(s: str) -> str:
|
||||
"""还原特殊字符"""
|
||||
for k, v in placeholder.items():
|
||||
s = s.replace(k, v)
|
||||
return s
|
||||
|
||||
|
||||
pre_handle_ph = {
|
||||
"://": "%3A//",
|
||||
}
|
||||
|
||||
|
||||
def pre_handle(s: str) -> str:
|
||||
"""特殊字符保护"""
|
||||
for k, v in pre_handle_ph.items():
|
||||
s = s.replace(k, v)
|
||||
return s
|
||||
|
||||
|
||||
class Parser: ...
|
||||
|
||||
|
||||
class GoogleDocstringParser(Parser):
|
||||
_tokens = {
|
||||
"Args": "args",
|
||||
"Arguments": "args",
|
||||
"参数": "args",
|
||||
"Return": "return",
|
||||
"Returns": "return",
|
||||
"返回": "return",
|
||||
"Attribute": "attribute",
|
||||
"Attributes": "attribute",
|
||||
"属性": "attribute",
|
||||
"Raises": "raises",
|
||||
"Raise": "raises",
|
||||
"引发": "raises",
|
||||
"Example": "example",
|
||||
"Examples": "example",
|
||||
"示例": "example",
|
||||
"Yields": "yields",
|
||||
"Yield": "yields",
|
||||
"产出": "yields",
|
||||
"Requires": "requires",
|
||||
"Require": "requires",
|
||||
"需要": "requires",
|
||||
"FrontMatter": "front_matter",
|
||||
"前言": "front_matter",
|
||||
}
|
||||
|
||||
def __init__(self, docstring: str, indent: int = 4, **kwargs):
|
||||
self.lines = pre_handle(docstring).splitlines()
|
||||
self.indent = indent
|
||||
self.lineno = 0 # Current line number
|
||||
self.char = 0 # Current character position
|
||||
|
||||
self.is_module = kwargs.get("is_module", False)
|
||||
"""是否为模块的docstring,是则不在说明处添加说明字样"""
|
||||
self.docstring = Docstring(raw=docstring, **kwargs)
|
||||
|
||||
def read_line(self, move: bool = True) -> str:
|
||||
"""
|
||||
每次读取一行
|
||||
Args:
|
||||
move: 是否移动指针
|
||||
Returns:
|
||||
"""
|
||||
if self.lineno >= len(self.lines):
|
||||
return ""
|
||||
line = self.lines[self.lineno]
|
||||
if move:
|
||||
self.lineno += 1
|
||||
return line
|
||||
|
||||
def match_token(self) -> Optional[str]:
|
||||
"""
|
||||
解析下一行的token
|
||||
Returns:
|
||||
|
||||
"""
|
||||
for token in self._tokens:
|
||||
line = self.read_line(move=False)
|
||||
if line.strip().startswith(token):
|
||||
self.lineno += 1
|
||||
return self._tokens[token]
|
||||
return None
|
||||
|
||||
def parse_args(self):
|
||||
"""
|
||||
依次解析后面的参数行,直到缩进小于等于当前行的缩进
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_arg(reduction(name.strip()), reduction(desc.strip()))
|
||||
else:
|
||||
self.docstring.add_arg(reduction(line.strip()))
|
||||
|
||||
def parse_return(self):
|
||||
"""
|
||||
解析返回值行
|
||||
"""
|
||||
if line := self.match_next_line():
|
||||
self.docstring.add_return(reduction(line.strip()))
|
||||
|
||||
def parse_raises(self):
|
||||
"""
|
||||
解析异常行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_raise(
|
||||
reduction(name.strip()), reduction(desc.strip())
|
||||
)
|
||||
else:
|
||||
self.docstring.add_raise(reduction(line.strip()))
|
||||
|
||||
def parse_example(self):
|
||||
"""
|
||||
解析示例行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
self.docstring.add_example(
|
||||
reduction(line if line.startswith(" ") else line.strip())
|
||||
)
|
||||
|
||||
def parse_attrs(self):
|
||||
"""
|
||||
解析属性行
|
||||
"""
|
||||
while line := self.match_next_line():
|
||||
if ":" in line:
|
||||
name, desc = line.split(":", 1)
|
||||
self.docstring.add_attrs(
|
||||
reduction(name.strip()), reduction(desc.strip())
|
||||
)
|
||||
else:
|
||||
self.docstring.add_attrs(reduction(line.strip()))
|
||||
|
||||
def match_next_line(self) -> Optional[str]:
|
||||
"""
|
||||
在一个子解析器中,解析下一行,直到缩进小于等于当前行的缩进
|
||||
Returns:
|
||||
"""
|
||||
line = self.read_line(move=False)
|
||||
if line.startswith(" " * self.indent):
|
||||
self.lineno += 1
|
||||
return line[self.indent :]
|
||||
else:
|
||||
return None
|
||||
|
||||
def parse(self) -> Docstring:
|
||||
"""
|
||||
逐行解析,直到遇到token,解析token对应的内容,
|
||||
|
||||
最开始未解析到的内容全部加入desc
|
||||
|
||||
Returns:
|
||||
Docstring
|
||||
"""
|
||||
add_desc = True
|
||||
add_front_matter = False
|
||||
while self.lineno < len(self.lines):
|
||||
token = self.match_token()
|
||||
|
||||
if token is None and add_desc:
|
||||
if self.is_module and self.lines[self.lineno].strip() == "---":
|
||||
add_front_matter = not add_front_matter
|
||||
self.lineno += 1
|
||||
continue
|
||||
if add_front_matter and ":" in self.lines[self.lineno]:
|
||||
key, value = map(str.strip, self.lines[self.lineno].split(":", 1))
|
||||
self.docstring.add_front_matter(key, value)
|
||||
else:
|
||||
self.docstring.add_desc(reduction(self.lines[self.lineno].strip()))
|
||||
if token is not None:
|
||||
add_desc = False
|
||||
|
||||
match token:
|
||||
case "args":
|
||||
self.parse_args()
|
||||
case "return":
|
||||
self.parse_return()
|
||||
case "attribute":
|
||||
self.parse_attrs()
|
||||
case "raises":
|
||||
self.parse_raises()
|
||||
case "example":
|
||||
self.parse_example()
|
||||
case _:
|
||||
self.lineno += 1
|
||||
|
||||
return self.docstring
|
||||
|
||||
|
||||
class NumpyDocstringParser(Parser): ...
|
||||
|
||||
|
||||
class ReStructuredParser(Parser): ...
|
||||
|
||||
|
||||
def parse(
|
||||
docstring: str, parser: str = "google", indent: int = 4, **kwargs
|
||||
) -> Docstring:
|
||||
if parser == "google":
|
||||
return GoogleDocstringParser(docstring, indent, **kwargs).parse()
|
||||
else:
|
||||
raise ValueError(f"Unknown parser: {parser}")
|
@ -3,6 +3,7 @@
|
||||
|
||||
import inspect
|
||||
|
||||
import litedoc
|
||||
from nonebot import logger
|
||||
|
||||
from nonebot_plugin_marshoai.plugin.utils import is_coroutine_callable
|
||||
@ -42,21 +43,24 @@ def function_call(*funcs: FUNCTION_CALL_FUNC) -> None:
|
||||
Returns:
|
||||
str: 函数定义信息
|
||||
"""
|
||||
# for func in funcs:
|
||||
# function_call = get_function_info(func)
|
||||
# # TODO: 注册函数
|
||||
for func in funcs:
|
||||
function_call = get_function_info(func)
|
||||
# TODO: 注册函数
|
||||
|
||||
|
||||
# def get_function_info(func: FUNCTION_CALL_FUNC) -> FunctionCall:
|
||||
# """获取函数信息
|
||||
def get_function_info(func: FUNCTION_CALL_FUNC):
|
||||
"""获取函数信息
|
||||
|
||||
# Args:
|
||||
# func: 函数对象
|
||||
Args:
|
||||
func: 函数对象
|
||||
|
||||
# Returns:
|
||||
# FunctionCall: 函数信息对象模型
|
||||
# """
|
||||
# description = func.__doc__
|
||||
# # TODO: 获取函数参数信息
|
||||
# parameters = {}
|
||||
# pass
|
||||
Returns:
|
||||
FunctionCall: 函数信息对象模型
|
||||
"""
|
||||
description = func.__doc__
|
||||
# TODO: 获取函数参数信息
|
||||
parameters = {} # type: ignore
|
||||
# 使用inspect解析函数的传参及类型
|
||||
sig = inspect.signature(func)
|
||||
for name, param in sig.parameters.items():
|
||||
logger.debug(name, param)
|
||||
|
@ -32,3 +32,7 @@ def is_coroutine_callable(call: Callable[..., Any]) -> bool:
|
||||
return False
|
||||
func_ = getattr(call, "__call__", None)
|
||||
return inspect.iscoroutinefunction(func_)
|
||||
|
||||
|
||||
def parse_function_docsring():
|
||||
pass
|
||||
|
Loading…
x
Reference in New Issue
Block a user