adam-community 0.2__py3-none-any.whl → 0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- adam_community/cli/build.py +37 -4
- adam_community/cli/cli.py +4 -0
- adam_community/cli/init.py +156 -0
- adam_community/cli/parser.py +212 -7
- adam_community/cli/templates/__init__.py +1 -0
- {adam_community-0.2.dist-info → adam_community-0.3.dist-info}/METADATA +2 -2
- adam_community-0.3.dist-info/RECORD +14 -0
- {adam_community-0.2.dist-info → adam_community-0.3.dist-info}/WHEEL +1 -1
- adam_community-0.2.dist-info/RECORD +0 -12
- {adam_community-0.2.dist-info → adam_community-0.3.dist-info}/entry_points.txt +0 -0
- {adam_community-0.2.dist-info → adam_community-0.3.dist-info}/top_level.txt +0 -0
adam_community/cli/build.py
CHANGED
|
@@ -13,24 +13,57 @@ def check_python_files(directory: Path) -> Tuple[bool, List[str]]:
|
|
|
13
13
|
"""检查所有 Python 文件是否都有参数定义"""
|
|
14
14
|
tree = Tree("📦 Python 文件检查")
|
|
15
15
|
errors = []
|
|
16
|
+
warnings = []
|
|
16
17
|
functions = parse_directory(directory)
|
|
17
18
|
|
|
18
19
|
tree.add(f"找到 {len(functions)} 个类定义")
|
|
19
20
|
for func in functions:
|
|
20
21
|
func_info = func["function"]
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
|
|
23
|
+
# 检查描述长度
|
|
24
|
+
description = func_info.get("description")
|
|
25
|
+
if description is None or not description:
|
|
26
|
+
warning_msg = f"⚠️ {func_info['file']}: {func_info['name']} 没有描述"
|
|
27
|
+
tree.add(warning_msg)
|
|
28
|
+
warnings.append(warning_msg)
|
|
29
|
+
elif len(description) > 1024:
|
|
30
|
+
error_msg = f"❌ {func_info['file']}: {func_info['name']} 描述长度超过1024字符 ({len(description)})"
|
|
31
|
+
tree.add(error_msg)
|
|
32
|
+
errors.append(error_msg)
|
|
33
|
+
else:
|
|
34
|
+
tree.add(f"✓ {func_info['file']}: {func_info['name']} 描述长度: {len(description)}")
|
|
23
35
|
|
|
36
|
+
# 检查参数定义
|
|
24
37
|
if not func_info["parameters"]["properties"]:
|
|
25
|
-
|
|
38
|
+
warning_msg = f"⚠️ {func_info['file']}: {func_info['name']} 没有参数定义"
|
|
39
|
+
tree.add(warning_msg)
|
|
40
|
+
warnings.append(warning_msg)
|
|
26
41
|
else:
|
|
27
|
-
|
|
42
|
+
# 检查参数类型是否都是有效的JSON Schema类型
|
|
43
|
+
param_errors = []
|
|
44
|
+
for param_name, param_info in func_info["parameters"]["properties"].items():
|
|
45
|
+
if "type" not in param_info:
|
|
46
|
+
param_errors.append(f"参数 '{param_name}' 缺少类型定义")
|
|
47
|
+
elif param_info["type"] not in ["string", "integer", "number", "boolean", "array", "object", "null"]:
|
|
48
|
+
param_errors.append(f"参数 '{param_name}' 类型 '{param_info['type']}' 不是有效的JSON Schema类型")
|
|
49
|
+
|
|
50
|
+
if param_errors:
|
|
51
|
+
for param_error in param_errors:
|
|
52
|
+
error_msg = f"❌ {func_info['file']}: {func_info['name']} - {param_error}"
|
|
53
|
+
tree.add(error_msg)
|
|
54
|
+
errors.append(error_msg)
|
|
55
|
+
else:
|
|
56
|
+
tree.add(f"✓ {func_info['file']}: {func_info['name']} 参数类型验证通过")
|
|
28
57
|
|
|
29
58
|
if errors:
|
|
30
59
|
tree.add("❌ 检查未通过")
|
|
31
60
|
else:
|
|
32
61
|
tree.add("✅ 检查通过")
|
|
33
62
|
|
|
63
|
+
# 显示警告信息
|
|
64
|
+
if warnings:
|
|
65
|
+
tree.add(f"⚠️ 发现 {len(warnings)} 个警告(不影响构建)")
|
|
66
|
+
|
|
34
67
|
console.print(tree)
|
|
35
68
|
return len(errors) == 0, errors
|
|
36
69
|
|
adam_community/cli/cli.py
CHANGED
|
@@ -3,6 +3,7 @@ import json
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from .parser import parse_directory
|
|
5
5
|
from .build import build_package
|
|
6
|
+
from .init import init
|
|
6
7
|
|
|
7
8
|
@click.group()
|
|
8
9
|
def cli():
|
|
@@ -40,5 +41,8 @@ def build(directory):
|
|
|
40
41
|
click.echo(f"- {error}")
|
|
41
42
|
raise click.Abort()
|
|
42
43
|
|
|
44
|
+
# 添加 init 命令
|
|
45
|
+
cli.add_command(init)
|
|
46
|
+
|
|
43
47
|
if __name__ == '__main__':
|
|
44
48
|
cli()
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import click
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import re
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from jinja2 import Environment, FileSystemLoader
|
|
7
|
+
from typing import Dict, Any
|
|
8
|
+
|
|
9
|
+
@click.command()
|
|
10
|
+
@click.option('--name', prompt='项目名称(仅支持字母、数字、连字符,不能有空格)', help='项目的英文名称(用于文件夹和配置)')
|
|
11
|
+
@click.option('--display-name', prompt='显示名称', help='项目的中文显示名称')
|
|
12
|
+
@click.option('--description', prompt='项目描述', help='项目的简短描述')
|
|
13
|
+
@click.option('--version', default='1.0.0', prompt='版本号', help='项目版本号')
|
|
14
|
+
@click.option('--author', prompt='作者', help='项目作者')
|
|
15
|
+
@click.option('--type',
|
|
16
|
+
type=click.Choice(['kit', 'toolbox']),
|
|
17
|
+
prompt='项目类型',
|
|
18
|
+
help='选择项目类型: kit(表单工具) 或 toolbox(智能体工具)')
|
|
19
|
+
@click.argument('directory', type=click.Path(exists=True, file_okay=False, dir_okay=True), default='.')
|
|
20
|
+
def init(name: str, display_name: str, description: str, version: str, author: str, type: str, directory: str):
|
|
21
|
+
"""初始化一个新的 Adam 工具项目"""
|
|
22
|
+
|
|
23
|
+
# 验证项目名称格式
|
|
24
|
+
if not validate_project_name(name):
|
|
25
|
+
click.echo(f"错误: 项目名称 '{name}' 格式不正确")
|
|
26
|
+
click.echo("项目名称只能包含字母、数字和连字符(-),不能包含空格或其他特殊字符")
|
|
27
|
+
click.echo("示例: my-tool, data-processor, image-analyzer")
|
|
28
|
+
return
|
|
29
|
+
|
|
30
|
+
directory_path = Path(directory)
|
|
31
|
+
project_path = directory_path / name
|
|
32
|
+
|
|
33
|
+
# 检查目录是否已存在
|
|
34
|
+
if project_path.exists():
|
|
35
|
+
click.echo(f"错误: 目录 '{name}' 已存在")
|
|
36
|
+
return
|
|
37
|
+
|
|
38
|
+
# 创建项目目录
|
|
39
|
+
project_path.mkdir(parents=True, exist_ok=True)
|
|
40
|
+
click.echo(f"创建项目目录: {project_path}")
|
|
41
|
+
|
|
42
|
+
# 创建config目录
|
|
43
|
+
config_path = project_path / "config"
|
|
44
|
+
config_path.mkdir(parents=True, exist_ok=True)
|
|
45
|
+
|
|
46
|
+
# 设置Jinja2环境
|
|
47
|
+
template_dir = Path(__file__).parent / "templates"
|
|
48
|
+
env = Environment(loader=FileSystemLoader(template_dir))
|
|
49
|
+
|
|
50
|
+
# 模板变量
|
|
51
|
+
template_vars = {
|
|
52
|
+
'name': name,
|
|
53
|
+
'display_name': display_name,
|
|
54
|
+
'description': description,
|
|
55
|
+
'version': version,
|
|
56
|
+
'author': author,
|
|
57
|
+
'project_type': type
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# 生成配置文件
|
|
61
|
+
render_and_save(env, 'configure.json.j2', config_path / "configure.json", template_vars)
|
|
62
|
+
click.echo(f"生成配置文件: config/configure.json")
|
|
63
|
+
|
|
64
|
+
# 生成描述文件
|
|
65
|
+
render_and_save(env, 'long_description.md.j2', config_path / "long_description.md", template_vars)
|
|
66
|
+
click.echo(f"生成描述文件: config/long_description.md")
|
|
67
|
+
|
|
68
|
+
if type == 'kit':
|
|
69
|
+
generate_kit_files(env, project_path, config_path, template_vars)
|
|
70
|
+
else:
|
|
71
|
+
generate_toolbox_files(env, project_path, config_path, template_vars)
|
|
72
|
+
|
|
73
|
+
# 生成 Makefile
|
|
74
|
+
render_and_save(env, 'Makefile.j2', project_path / "Makefile", template_vars)
|
|
75
|
+
click.echo(f"生成构建脚本: Makefile")
|
|
76
|
+
|
|
77
|
+
# 生成 README 文件
|
|
78
|
+
if type == 'kit':
|
|
79
|
+
render_and_save(env, 'README_kit.md.j2', project_path / "README.md", template_vars)
|
|
80
|
+
else:
|
|
81
|
+
render_and_save(env, 'README_toolbox.md.j2', project_path / "README.md", template_vars)
|
|
82
|
+
click.echo(f"生成项目文档: README.md")
|
|
83
|
+
|
|
84
|
+
click.echo(f"\n✅ 项目 '{name}' 初始化完成!")
|
|
85
|
+
click.echo(f"📁 项目路径: {project_path}")
|
|
86
|
+
click.echo("\n📋 后续步骤:")
|
|
87
|
+
click.echo("1. 📖 阅读 README.md 了解详细的开发指南")
|
|
88
|
+
click.echo("2. 🔧 根据需要修改 Python 代码实现")
|
|
89
|
+
if type == 'kit':
|
|
90
|
+
click.echo("3. 📝 自定义 config/input.json 表单配置")
|
|
91
|
+
else:
|
|
92
|
+
click.echo("3. 🤖 自定义 config/initial_system_prompt.md 和 config/initial_assistant_message.md")
|
|
93
|
+
click.echo("4. 📄 完善 config/long_description.md 描述文档")
|
|
94
|
+
click.echo("5. ⚙️ 运行 'make parse' 生成 functions.json")
|
|
95
|
+
click.echo("6. 📦 运行 'make build' 打包项目")
|
|
96
|
+
click.echo(f"\n💡 详细的开发指南请查看: {project_path}/README.md")
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def render_and_save(env: Environment, template_name: str, output_path: Path, template_vars: Dict[str, Any]):
|
|
100
|
+
"""渲染模板并保存到文件"""
|
|
101
|
+
template = env.get_template(template_name)
|
|
102
|
+
content = template.render(**template_vars)
|
|
103
|
+
with open(output_path, 'w', encoding='utf-8') as f:
|
|
104
|
+
f.write(content)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def generate_kit_files(env: Environment, project_path: Path, config_path: Path, template_vars: Dict[str, Any]):
|
|
108
|
+
"""生成 kit 项目的特定文件"""
|
|
109
|
+
|
|
110
|
+
# 生成 input.json 表单配置
|
|
111
|
+
render_and_save(env, 'input.json.j2', config_path / "input.json", template_vars)
|
|
112
|
+
click.echo(f"生成表单配置: config/input.json")
|
|
113
|
+
|
|
114
|
+
# 生成主要的Python实现文件
|
|
115
|
+
python_filename = f"{template_vars['name'].replace('-', '_')}.py"
|
|
116
|
+
render_and_save(env, 'kit_python.py.j2', project_path / python_filename, template_vars)
|
|
117
|
+
click.echo(f"生成主要实现文件: {python_filename}")
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def generate_toolbox_files(env: Environment, project_path: Path, config_path: Path, template_vars: Dict[str, Any]):
|
|
121
|
+
"""生成 toolbox 项目的特定文件"""
|
|
122
|
+
|
|
123
|
+
# 生成 initial_system_prompt.md
|
|
124
|
+
render_and_save(env, 'initial_system_prompt.md.j2', config_path / "initial_system_prompt.md", template_vars)
|
|
125
|
+
click.echo(f"生成系统提示文件: config/initial_system_prompt.md")
|
|
126
|
+
|
|
127
|
+
# 生成 initial_assistant_message.md
|
|
128
|
+
render_and_save(env, 'initial_assistant_message.md.j2', config_path / "initial_assistant_message.md", template_vars)
|
|
129
|
+
click.echo(f"生成助手消息文件: config/initial_assistant_message.md")
|
|
130
|
+
|
|
131
|
+
# 生成主要的Python实现文件
|
|
132
|
+
python_filename = f"{template_vars['name'].replace('-', '_')}.py"
|
|
133
|
+
render_and_save(env, 'toolbox_python.py.j2', project_path / python_filename, template_vars)
|
|
134
|
+
click.echo(f"生成主要实现文件: {python_filename}")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def validate_project_name(name: str) -> bool:
|
|
138
|
+
"""验证项目名称格式"""
|
|
139
|
+
# 项目名称只能包含字母、数字和连字符,不能有空格
|
|
140
|
+
pattern = r'^[a-zA-Z0-9-]+$'
|
|
141
|
+
if not re.match(pattern, name):
|
|
142
|
+
return False
|
|
143
|
+
|
|
144
|
+
# 不能以连字符开始或结束
|
|
145
|
+
if name.startswith('-') or name.endswith('-'):
|
|
146
|
+
return False
|
|
147
|
+
|
|
148
|
+
# 不能有连续的连字符
|
|
149
|
+
if '--' in name:
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
# 长度限制
|
|
153
|
+
if len(name) < 1 or len(name) > 50:
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
return True
|
adam_community/cli/parser.py
CHANGED
|
@@ -3,6 +3,196 @@ from pathlib import Path
|
|
|
3
3
|
from typing import List, Dict, Any
|
|
4
4
|
from docstring_parser import parse as dsp
|
|
5
5
|
|
|
6
|
+
def convert_python_type_to_json_schema(python_type: str) -> Dict[str, Any]:
|
|
7
|
+
"""将 Python 类型转换为 JSON Schema 类型
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
python_type: Python 类型字符串
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
Dict[str, Any]: JSON Schema 类型定义
|
|
14
|
+
|
|
15
|
+
Raises:
|
|
16
|
+
ValueError: 当无法转换类型时抛出异常
|
|
17
|
+
"""
|
|
18
|
+
python_type = python_type.lower().strip()
|
|
19
|
+
|
|
20
|
+
# 基本类型映射
|
|
21
|
+
basic_types = {
|
|
22
|
+
'str': 'string',
|
|
23
|
+
'string': 'string',
|
|
24
|
+
'int': 'integer',
|
|
25
|
+
'integer': 'integer',
|
|
26
|
+
'float': 'number',
|
|
27
|
+
'number': 'number',
|
|
28
|
+
'bool': 'boolean',
|
|
29
|
+
'boolean': 'boolean',
|
|
30
|
+
'list': 'array',
|
|
31
|
+
'array': 'array',
|
|
32
|
+
'dict': 'object',
|
|
33
|
+
'object': 'object',
|
|
34
|
+
'tuple': 'array',
|
|
35
|
+
'set': 'array',
|
|
36
|
+
'none': 'null',
|
|
37
|
+
'null': 'null',
|
|
38
|
+
'any': 'object' # 添加对 any 类型的支持
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
# 处理基本类型
|
|
42
|
+
if python_type in basic_types:
|
|
43
|
+
return {"type": basic_types[python_type]}
|
|
44
|
+
|
|
45
|
+
# 处理 Literal[T1, T2, ...] 格式
|
|
46
|
+
if python_type.startswith('literal[') and python_type.endswith(']'):
|
|
47
|
+
content = python_type[8:-1] # 提取 Literal[ 和 ] 之间的内容
|
|
48
|
+
values = [v.strip().strip('"\'') for v in content.split(',')]
|
|
49
|
+
|
|
50
|
+
# 尝试推断类型
|
|
51
|
+
if all(v.isdigit() or (v.startswith('-') and v[1:].isdigit()) for v in values):
|
|
52
|
+
# 所有值都是整数
|
|
53
|
+
return {
|
|
54
|
+
"type": "integer",
|
|
55
|
+
"enum": [int(v) for v in values]
|
|
56
|
+
}
|
|
57
|
+
elif all(v.replace('.', '').replace('-', '').isdigit() for v in values):
|
|
58
|
+
# 所有值都是数字
|
|
59
|
+
return {
|
|
60
|
+
"type": "number",
|
|
61
|
+
"enum": [float(v) for v in values]
|
|
62
|
+
}
|
|
63
|
+
else:
|
|
64
|
+
# 字符串类型
|
|
65
|
+
return {
|
|
66
|
+
"type": "string",
|
|
67
|
+
"enum": values
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# 处理 Union[T1, T2, ...] 或 T1 | T2 格式
|
|
71
|
+
if python_type.startswith('union[') and python_type.endswith(']'):
|
|
72
|
+
content = python_type[6:-1]
|
|
73
|
+
types = [t.strip() for t in content.split(',')]
|
|
74
|
+
return convert_union_types(types)
|
|
75
|
+
|
|
76
|
+
# 处理 T1 | T2 格式(Python 3.10+ 的联合类型语法)
|
|
77
|
+
if '|' in python_type and not python_type.startswith('literal['):
|
|
78
|
+
types = [t.strip() for t in python_type.split('|')]
|
|
79
|
+
return convert_union_types(types)
|
|
80
|
+
|
|
81
|
+
# 处理 Optional[T] 格式
|
|
82
|
+
if python_type.startswith('optional[') and python_type.endswith(']'):
|
|
83
|
+
inner_type = python_type[9:-1].strip()
|
|
84
|
+
try:
|
|
85
|
+
inner_schema = convert_python_type_to_json_schema(inner_type)
|
|
86
|
+
return {
|
|
87
|
+
"oneOf": [
|
|
88
|
+
inner_schema,
|
|
89
|
+
{"type": "null"}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
except ValueError as e:
|
|
93
|
+
raise ValueError(f"无法转换Optional类型 '{python_type}': {str(e)}")
|
|
94
|
+
|
|
95
|
+
# 处理 List[T] 格式
|
|
96
|
+
if python_type.startswith('list[') and python_type.endswith(']'):
|
|
97
|
+
inner_type = python_type[5:-1] # 提取 List[ 和 ] 之间的内容
|
|
98
|
+
try:
|
|
99
|
+
items_schema = convert_python_type_to_json_schema(inner_type)
|
|
100
|
+
return {
|
|
101
|
+
"type": "array",
|
|
102
|
+
"items": items_schema
|
|
103
|
+
}
|
|
104
|
+
except ValueError as e:
|
|
105
|
+
raise ValueError(f"无法转换列表元素类型 '{inner_type}': {str(e)}")
|
|
106
|
+
|
|
107
|
+
# 处理 List[T] 格式(大写)
|
|
108
|
+
if python_type.startswith('list[') and python_type.endswith(']'):
|
|
109
|
+
inner_type = python_type[5:-1]
|
|
110
|
+
try:
|
|
111
|
+
items_schema = convert_python_type_to_json_schema(inner_type)
|
|
112
|
+
return {
|
|
113
|
+
"type": "array",
|
|
114
|
+
"items": items_schema
|
|
115
|
+
}
|
|
116
|
+
except ValueError as e:
|
|
117
|
+
raise ValueError(f"无法转换列表元素类型 '{inner_type}': {str(e)}")
|
|
118
|
+
|
|
119
|
+
# 处理 Dict[K, V] 格式
|
|
120
|
+
if python_type.startswith('dict[') and python_type.endswith(']'):
|
|
121
|
+
# 提取键值类型
|
|
122
|
+
content = python_type[5:-1]
|
|
123
|
+
if ',' in content:
|
|
124
|
+
key_type, value_type = content.split(',', 1)
|
|
125
|
+
key_type = key_type.strip()
|
|
126
|
+
value_type = value_type.strip()
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
key_schema = convert_python_type_to_json_schema(key_type)
|
|
130
|
+
value_schema = convert_python_type_to_json_schema(value_type)
|
|
131
|
+
return {
|
|
132
|
+
"type": "object",
|
|
133
|
+
"additionalProperties": value_schema
|
|
134
|
+
}
|
|
135
|
+
except ValueError as e:
|
|
136
|
+
raise ValueError(f"无法转换字典类型 '{python_type}': {str(e)}")
|
|
137
|
+
else:
|
|
138
|
+
# 只有值类型的情况
|
|
139
|
+
try:
|
|
140
|
+
value_schema = convert_python_type_to_json_schema(content.strip())
|
|
141
|
+
return {
|
|
142
|
+
"type": "object",
|
|
143
|
+
"additionalProperties": value_schema
|
|
144
|
+
}
|
|
145
|
+
except ValueError as e:
|
|
146
|
+
raise ValueError(f"无法转换字典值类型 '{content}': {str(e)}")
|
|
147
|
+
|
|
148
|
+
# 处理枚举类型
|
|
149
|
+
if python_type == 'enum':
|
|
150
|
+
return {"type": "string"}
|
|
151
|
+
|
|
152
|
+
# 如果无法识别,抛出异常
|
|
153
|
+
raise ValueError(f"无法转换的Python类型: '{python_type}'")
|
|
154
|
+
|
|
155
|
+
def convert_union_types(types: List[str]) -> Dict[str, Any]:
|
|
156
|
+
"""转换联合类型为 JSON Schema
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
types: 类型列表
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Dict[str, Any]: JSON Schema 联合类型定义
|
|
163
|
+
"""
|
|
164
|
+
schemas = []
|
|
165
|
+
for t in types:
|
|
166
|
+
try:
|
|
167
|
+
if t.lower() == 'none':
|
|
168
|
+
schemas.append({"type": "null"})
|
|
169
|
+
else:
|
|
170
|
+
schemas.append(convert_python_type_to_json_schema(t))
|
|
171
|
+
except ValueError as e:
|
|
172
|
+
raise ValueError(f"无法转换联合类型中的类型 '{t}': {str(e)}")
|
|
173
|
+
|
|
174
|
+
if len(schemas) == 1:
|
|
175
|
+
return schemas[0]
|
|
176
|
+
else:
|
|
177
|
+
return {"oneOf": schemas}
|
|
178
|
+
|
|
179
|
+
def validate_description_length(description: str, function_name: str, file_path: str) -> None:
|
|
180
|
+
"""验证函数描述长度
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
description: 函数描述
|
|
184
|
+
function_name: 函数名称
|
|
185
|
+
file_path: 文件路径
|
|
186
|
+
|
|
187
|
+
Raises:
|
|
188
|
+
ValueError: 当描述长度超过1024字符时抛出异常
|
|
189
|
+
"""
|
|
190
|
+
if len(description) > 1024:
|
|
191
|
+
raise ValueError(
|
|
192
|
+
f"函数 '{function_name}' 在文件 '{file_path}' 中的描述长度 ({len(description)}) "
|
|
193
|
+
f"超过了1024字符限制。请缩短描述长度。"
|
|
194
|
+
)
|
|
195
|
+
|
|
6
196
|
def parse_python_file(file_path: Path) -> List[Dict[str, Any]]:
|
|
7
197
|
"""解析单个 Python 文件,提取类信息
|
|
8
198
|
|
|
@@ -32,6 +222,7 @@ def parse_python_file(file_path: Path) -> List[Dict[str, Any]]:
|
|
|
32
222
|
mem_per_cpu = 4000
|
|
33
223
|
partition = "gpu"
|
|
34
224
|
conda_env = "base"
|
|
225
|
+
display_name = None
|
|
35
226
|
|
|
36
227
|
for item in node.body:
|
|
37
228
|
if isinstance(item, ast.Assign):
|
|
@@ -72,13 +263,27 @@ def parse_python_file(file_path: Path) -> List[Dict[str, Any]]:
|
|
|
72
263
|
# 使用 docstring_parser 解析类的文档字符串
|
|
73
264
|
docs = dsp(docstring)
|
|
74
265
|
if docs:
|
|
266
|
+
# 验证描述长度
|
|
267
|
+
if docs.short_description:
|
|
268
|
+
validate_description_length(docs.short_description, node.name, str(file_path))
|
|
269
|
+
|
|
75
270
|
for p in docs.params:
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
271
|
+
try:
|
|
272
|
+
# 转换Python类型为JSON Schema类型
|
|
273
|
+
json_schema_type = convert_python_type_to_json_schema(p.type_name or "string")
|
|
274
|
+
|
|
275
|
+
parameters["properties"][p.arg_name] = {
|
|
276
|
+
"description": p.description or "",
|
|
277
|
+
**json_schema_type
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if not p.is_optional:
|
|
281
|
+
parameters["required"].append(p.arg_name)
|
|
282
|
+
except ValueError as e:
|
|
283
|
+
raise ValueError(
|
|
284
|
+
f"在文件 '{file_path}' 的函数 '{node.name}' 中,"
|
|
285
|
+
f"参数 '{p.arg_name}' 的类型转换失败: {str(e)}"
|
|
286
|
+
)
|
|
82
287
|
|
|
83
288
|
class_info = {
|
|
84
289
|
"function": {
|
|
@@ -118,4 +323,4 @@ def parse_directory(directory: Path) -> List[Dict[str, Any]]:
|
|
|
118
323
|
if not py_file.name.startswith('_') and 'config' not in py_file.parts:
|
|
119
324
|
classes = parse_python_file(py_file)
|
|
120
325
|
all_classes.extend(classes)
|
|
121
|
-
return all_classes
|
|
326
|
+
return all_classes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Template module for init command
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
adam_community/__init__.py,sha256=XC_W9nEYq0KSXRRIotZi02ZbLSVIf-XZO-nrhBYUOSg,180
|
|
2
|
+
adam_community/tool.py,sha256=CCzWosxtuZ0yk7mupmnlgMpO59jr1hl-a_brSGIqhDI,4867
|
|
3
|
+
adam_community/util.py,sha256=W4SD4x-Tg_JVAINoi2Q2j5FqbWrQxvg0TRYfE9Yh2WI,11031
|
|
4
|
+
adam_community/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
adam_community/cli/build.py,sha256=XZK5OjbuihmwI9fZEKU7HkvYn0Ws5_MrE6okOxwwaOE,9753
|
|
6
|
+
adam_community/cli/cli.py,sha256=i26C8A2iZKDKzGCcpxUg-Jn2uxnPBb9K6FiIsAwFZ2c,1451
|
|
7
|
+
adam_community/cli/init.py,sha256=ut7ifGGiMG6gdTJl1JSbcxuZV7OS57JOb5hCGW-rEh0,6574
|
|
8
|
+
adam_community/cli/parser.py,sha256=H4NjJSwjmgVxOdP8Ppp8rY_ZYBvmM-IYfAhZ1FnuLQA,12482
|
|
9
|
+
adam_community/cli/templates/__init__.py,sha256=43rU9rFkpsVrWjxR-brDnT2eakgRtb4XpnunbE-ais4,34
|
|
10
|
+
adam_community-0.3.dist-info/METADATA,sha256=z_ivcAXxjfhl4NfR3M1wRD1T1-1TzRyJN_A4Pwskom0,1184
|
|
11
|
+
adam_community-0.3.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
|
|
12
|
+
adam_community-0.3.dist-info/entry_points.txt,sha256=4I7yRkn7cHwPY8-fWQLeAvKjc24zUy8Z65VsZNs0Wos,56
|
|
13
|
+
adam_community-0.3.dist-info/top_level.txt,sha256=MS8jbePXKZChih9kGizNVX0I1MFZFGWBMCIW_r86qhU,15
|
|
14
|
+
adam_community-0.3.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
adam_community/__init__.py,sha256=XC_W9nEYq0KSXRRIotZi02ZbLSVIf-XZO-nrhBYUOSg,180
|
|
2
|
-
adam_community/tool.py,sha256=CCzWosxtuZ0yk7mupmnlgMpO59jr1hl-a_brSGIqhDI,4867
|
|
3
|
-
adam_community/util.py,sha256=W4SD4x-Tg_JVAINoi2Q2j5FqbWrQxvg0TRYfE9Yh2WI,11031
|
|
4
|
-
adam_community/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
-
adam_community/cli/build.py,sha256=A3rlPCz5iGNe3WS82dEMqVX2kwE6AuU18g5nCl1wjZU,8088
|
|
6
|
-
adam_community/cli/cli.py,sha256=JoL8ePd1DdeRac1nRmtrcaa6oy6mKqtWBG2GjZr-3SM,1384
|
|
7
|
-
adam_community/cli/parser.py,sha256=krqZiCgjTAPNPWw34lhuKROEI6pfHa0Txbne_oYRsvM,5042
|
|
8
|
-
adam_community-0.2.dist-info/METADATA,sha256=bWBEnli5reo75dKu3c_Dcm1ZLiQMbbYuNMi-KgzysPc,1184
|
|
9
|
-
adam_community-0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
10
|
-
adam_community-0.2.dist-info/entry_points.txt,sha256=4I7yRkn7cHwPY8-fWQLeAvKjc24zUy8Z65VsZNs0Wos,56
|
|
11
|
-
adam_community-0.2.dist-info/top_level.txt,sha256=MS8jbePXKZChih9kGizNVX0I1MFZFGWBMCIW_r86qhU,15
|
|
12
|
-
adam_community-0.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|