ErisPulse 2.1.14.dev1__tar.gz → 2.1.15__tar.gz
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.
- erispulse-2.1.15/.github/ISSUE_TEMPLATE/config.yml +5 -0
- erispulse-2.1.15/.github/ISSUE_TEMPLATE/module_submission.md +38 -0
- erispulse-2.1.15/.github/PULL_REQUEST_TEMPLATE.md +22 -0
- erispulse-2.1.15/.github/scripts/update_packages.py +125 -0
- erispulse-2.1.15/.github/tools/merge_md.py +226 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.github/tools/update-api-docs.py +25 -34
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.github/workflows/auto-tag-release.yml +34 -4
- erispulse-2.1.15/.github/workflows/auto-update-packages.yml +84 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.gitignore +1 -0
- erispulse-2.1.15/.worker/worker.js +118 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/LICENSE +7 -1
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/PKG-INFO +40 -19
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/README.md +30 -15
- erispulse-2.1.15/SECURITY.md +25 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/devs/test.py +101 -132
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AIDocs/ErisPulse-AdapterDev.md +1379 -1044
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AIDocs/ErisPulse-Core.md +1438 -512
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AIDocs/ErisPulse-Full.md +1371 -1070
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AIDocs/ErisPulse-ModuleDev.md +1440 -1052
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AdapterStandards/APIResponse.md +1 -1
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/CHANGELOG.md +77 -1
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/CLI.md +74 -10
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/Development/Adapter.md +3 -3
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/Development/Module.md +6 -8
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/PlatformFeatures.md +64 -7
- {erispulse-2.1.14.dev1/style_guide → erispulse-2.1.15/docs/StyleGuide}/README.md +1 -1
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/UseCore.md +44 -11
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/Core/adapter.md +16 -16
- erispulse-2.1.15/docs/api/ErisPulse/Core/config.md +17 -0
- erispulse-2.1.15/docs/api/ErisPulse/Core/env.md +19 -0
- erispulse-2.1.15/docs/api/ErisPulse/Core/erispulse_config.md +60 -0
- erispulse-2.1.15/docs/api/ErisPulse/Core/exceptions.md +45 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/Core/logger.md +41 -5
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/Core/mods.md +5 -5
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/Core/router.md +7 -7
- erispulse-2.1.14.dev1/docs/api/ErisPulse/Core/env.md → erispulse-2.1.15/docs/api/ErisPulse/Core/storage.md +56 -55
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/__init__.md +16 -19
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/api/ErisPulse/__main__.md +156 -23
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-adapter/MyAdapter/Core.py +4 -4
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-module/MyModule/Core.py +3 -3
- erispulse-2.1.15/packages.json +231 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/pyproject.toml +4 -5
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/scripts/install/install.ps1 +120 -17
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/scripts/install/install.sh +36 -12
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/Core/__init__.py +4 -2
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/Core/adapter.py +16 -13
- erispulse-2.1.15/src/ErisPulse/Core/config.py +78 -0
- erispulse-2.1.15/src/ErisPulse/Core/env.py +15 -0
- erispulse-2.1.15/src/ErisPulse/Core/erispulse_config.py +105 -0
- erispulse-2.1.15/src/ErisPulse/Core/exceptions.py +108 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/Core/logger.py +79 -2
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/Core/mods.py +22 -18
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/Core/router.py +6 -1
- erispulse-2.1.14.dev1/src/ErisPulse/Core/env.py → erispulse-2.1.15/src/ErisPulse/Core/storage.py +64 -59
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/src/ErisPulse/__init__.py +40 -22
- erispulse-2.1.15/src/ErisPulse/__main__.py +2024 -0
- erispulse-2.1.14.dev1/.github/tools/merge_md.py +0 -141
- erispulse-2.1.14.dev1/CHANGELOG_1.x.md +0 -378
- erispulse-2.1.14.dev1/docs/api/ErisPulse/Core/config.md +0 -61
- erispulse-2.1.14.dev1/docs/api/ErisPulse/Core/exceptions.md +0 -74
- erispulse-2.1.14.dev1/src/ErisPulse/Core/config.py +0 -172
- erispulse-2.1.14.dev1/src/ErisPulse/Core/exceptions.py +0 -136
- erispulse-2.1.14.dev1/src/ErisPulse/__main__.py +0 -1104
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.github/assets/docs/install_pip.gif +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.github/assets/erispulse_logo.png +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.github/workflows/pypi-publish.yml +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/.python-version +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/CODE_OF_CONDUCT.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/devs/test_adapter.py +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/devs/test_files/test.docx +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/devs/test_files/test.jpg +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/devs/test_files/test.mp4 +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AIModuleGeneration.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AdapterStandards/EventConversion.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/AdapterStandards/README.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/Development/CLI.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/Development/README.md +0 -0
- /erispulse-2.1.14.dev1/style_guide/DOCSTRING_SPEC.md → /erispulse-2.1.15/docs/StyleGuide/DocstringSpec.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/docs/quick-start.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-adapter/LICENSE +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-adapter/MyAdapter/__init__.py +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-adapter/README.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-adapter/pyproject.toml +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-cli-module/LICENSE +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-cli-module/README.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-cli-module/my_cli_module/__init__.py +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-cli-module/my_cli_module/cli.py +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-cli-module/pyproject.toml +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-module/LICENSE +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-module/MyModule/__init__.py +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-module/README.md +0 -0
- {erispulse-2.1.14.dev1 → erispulse-2.1.15}/examples/example-module/pyproject.toml +0 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 模块/适配器/CLI扩展提交
|
|
3
|
+
about: 提交一个新的模块、适配器或CLI扩展到 ErisPulse 生态系统
|
|
4
|
+
title: '[提交] '
|
|
5
|
+
labels: 'submission'
|
|
6
|
+
assignees: ''
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 提交类型
|
|
11
|
+
<!-- 请在适用的选项前打勾 -->
|
|
12
|
+
- [ ] 模块 (Module)
|
|
13
|
+
- [ ] 适配器 (Adapter)
|
|
14
|
+
- [ ] CLI 扩展 (CLI Extension)
|
|
15
|
+
|
|
16
|
+
## 基本信息
|
|
17
|
+
- **名称**:
|
|
18
|
+
- **描述**:
|
|
19
|
+
- **作者**:
|
|
20
|
+
- **仓库地址**:
|
|
21
|
+
|
|
22
|
+
## 技术信息
|
|
23
|
+
- **最低 SDK 版本要求** (如适用):
|
|
24
|
+
- **依赖项** (如适用):
|
|
25
|
+
|
|
26
|
+
## 其他信息
|
|
27
|
+
- [ ] 官方维护
|
|
28
|
+
- **标签** (用逗号分隔):
|
|
29
|
+
|
|
30
|
+
## 检查清单
|
|
31
|
+
<!-- 请确认以下事项 -->
|
|
32
|
+
- [ ] 代码遵循 ErisPulse 开发规范
|
|
33
|
+
- [ ] 包含适当的文档
|
|
34
|
+
- [ ] 包含测试用例(如适用)
|
|
35
|
+
- [ ] 已在 PyPI 发布(如适用)
|
|
36
|
+
|
|
37
|
+
## 备注
|
|
38
|
+
<!-- 其他需要说明的信息 -->
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
## 提交类型
|
|
2
|
+
<!-- 请在适用的选项前打勾 -->
|
|
3
|
+
- [ ] 功能新增
|
|
4
|
+
- [ ] Bug 修复
|
|
5
|
+
- [ ] 文档更新
|
|
6
|
+
- [ ] 代码优化
|
|
7
|
+
- [ ] 其他
|
|
8
|
+
|
|
9
|
+
## 变更描述
|
|
10
|
+
<!-- 请详细描述本次提交的内容 -->
|
|
11
|
+
|
|
12
|
+
## 相关 Issue
|
|
13
|
+
<!-- 如果有相关的 Issue,请填写链接 -->
|
|
14
|
+
|
|
15
|
+
## 检查清单
|
|
16
|
+
- [ ] 代码符合项目规范
|
|
17
|
+
- [ ] 已进行充分测试
|
|
18
|
+
- [ ] 文档已更新(如适用)
|
|
19
|
+
- [ ] CHANGELOG 已更新(如适用)
|
|
20
|
+
|
|
21
|
+
## 其他说明
|
|
22
|
+
<!-- 其他需要说明的信息 -->
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
|
|
4
|
+
"""
|
|
5
|
+
🌟 艾莉丝的版本探知魔法阵 ~
|
|
6
|
+
这是一个用于自动检测和更新 packages.json 中模块版本的魔法脚本
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
import requests
|
|
11
|
+
import os
|
|
12
|
+
from datetime import datetime, timezone
|
|
13
|
+
import re
|
|
14
|
+
|
|
15
|
+
# 魔法咒语准备
|
|
16
|
+
headers = {
|
|
17
|
+
'Authorization': f'token {os.environ["GITHUB_TOKEN"]}',
|
|
18
|
+
'Accept': 'application/vnd.github.v3+json'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def get_latest_pypi_version(package_name):
|
|
22
|
+
try:
|
|
23
|
+
print(f"正在探查 {package_name} 的 PyPI 版本...")
|
|
24
|
+
response = requests.get(f'https://pypi.org/pypi/{package_name}/json', timeout=10)
|
|
25
|
+
if response.status_code == 200:
|
|
26
|
+
data = response.json()
|
|
27
|
+
version = data['info']['version']
|
|
28
|
+
print(f"找到了 {package_name} 的最新版本: {version}")
|
|
29
|
+
return version
|
|
30
|
+
except Exception as e:
|
|
31
|
+
print(f"💢 探查 {package_name} 的 PyPI 版本时遇到了障碍: {e}")
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
def get_latest_github_release(repo_url):
|
|
35
|
+
try:
|
|
36
|
+
print(f"正在探查 {repo_url} 的 GitHub 发布版本...")
|
|
37
|
+
if 'github.com' in repo_url:
|
|
38
|
+
# 从仓库 URL 提取 owner/repo
|
|
39
|
+
parts = repo_url.rstrip('/').split('/')
|
|
40
|
+
owner_repo = f"{parts[-2]}/{parts[-1]}"
|
|
41
|
+
|
|
42
|
+
response = requests.get(f'https://api.github.com/repos/{owner_repo}/releases/latest', headers=headers, timeout=10)
|
|
43
|
+
if response.status_code == 200:
|
|
44
|
+
data = response.json()
|
|
45
|
+
version = data['tag_name'].lstrip('v') # 移除可能的 'v' 前缀
|
|
46
|
+
print(f"✨ 找到了 {owner_repo} 的最新发布版本: {version}")
|
|
47
|
+
return version
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"💢 探查 {repo_url} 的 GitHub 版本时遇到了障碍: {e}")
|
|
50
|
+
return None
|
|
51
|
+
|
|
52
|
+
def is_version_newer(new_version, old_version):
|
|
53
|
+
try:
|
|
54
|
+
def version_to_tuple(v):
|
|
55
|
+
# 移除版本字符串中的非数字和点字符(如 dev, alpha, beta 等)
|
|
56
|
+
v = re.sub(r'[^\d.]', '', v)
|
|
57
|
+
return tuple(map(int, (v.split('.'))))
|
|
58
|
+
|
|
59
|
+
return version_to_tuple(new_version) > version_to_tuple(old_version)
|
|
60
|
+
except:
|
|
61
|
+
# 如果无法解析,保守地认为需要更新
|
|
62
|
+
return new_version != old_version
|
|
63
|
+
|
|
64
|
+
def update_packages():
|
|
65
|
+
print("🌟 艾莉丝的版本探知魔法阵启动!")
|
|
66
|
+
|
|
67
|
+
# 读取当前的魔法书
|
|
68
|
+
try:
|
|
69
|
+
with open('packages.json', 'r', encoding='utf-8') as f:
|
|
70
|
+
packages = json.load(f)
|
|
71
|
+
print("成功打开了 packages.json 魔法书!")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
print(f"无法打开 packages.json 魔法书: {e}")
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
current_time = datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')
|
|
77
|
+
packages['last_updated'] = current_time
|
|
78
|
+
print(f"更新时间戳: {current_time}")
|
|
79
|
+
|
|
80
|
+
updated_count = 0
|
|
81
|
+
|
|
82
|
+
for category in ['modules', 'adapters', 'cli_extensions']:
|
|
83
|
+
if category in packages:
|
|
84
|
+
print(f"开始探查 {category} 分类...")
|
|
85
|
+
for name, info in packages[category].items():
|
|
86
|
+
try:
|
|
87
|
+
old_version = info.get('version', '0.0.0')
|
|
88
|
+
print(f"检查 {name} (当前版本: {old_version})")
|
|
89
|
+
|
|
90
|
+
# 尝试从 PyPI 获取最新版本
|
|
91
|
+
new_version = None
|
|
92
|
+
if 'package' in info:
|
|
93
|
+
new_version = get_latest_pypi_version(info.get('package', ''))
|
|
94
|
+
|
|
95
|
+
# 如果 PyPI 获取失败,尝试从 GitHub 获取
|
|
96
|
+
if not new_version and 'repository' in info:
|
|
97
|
+
new_version = get_latest_github_release(info['repository'])
|
|
98
|
+
|
|
99
|
+
# 如果找到了新版本且版本更高,则更新
|
|
100
|
+
if new_version and is_version_newer(new_version, old_version):
|
|
101
|
+
packages[category][name]['version'] = new_version
|
|
102
|
+
print(f"更新 {name}: {old_version} -> {new_version}")
|
|
103
|
+
updated_count += 1
|
|
104
|
+
else:
|
|
105
|
+
print(f"✨ {name} 已经是最新版本啦~")
|
|
106
|
+
|
|
107
|
+
except Exception as e:
|
|
108
|
+
print(f"处理 {name} 时遇到了意外: {e}")
|
|
109
|
+
|
|
110
|
+
# 写回魔法书
|
|
111
|
+
try:
|
|
112
|
+
with open('packages.json', 'w', encoding='utf-8') as f:
|
|
113
|
+
json.dump(packages, f, ensure_ascii=False, indent=4)
|
|
114
|
+
print(f"魔法书更新完成! 共更新了 {updated_count} 个模块~")
|
|
115
|
+
except Exception as e:
|
|
116
|
+
print(f"无法保存魔法书: {e}")
|
|
117
|
+
return
|
|
118
|
+
|
|
119
|
+
if updated_count > 0:
|
|
120
|
+
print("艾莉丝的版本探知魔法大成功!")
|
|
121
|
+
else:
|
|
122
|
+
print("今天没有发现需要更新的模块呢~")
|
|
123
|
+
|
|
124
|
+
if __name__ == '__main__':
|
|
125
|
+
update_packages()
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from datetime import datetime
|
|
3
|
+
|
|
4
|
+
def merge_md_files(output_file, files_to_merge, title="文档合集"):
|
|
5
|
+
"""
|
|
6
|
+
合并多个Markdown文件
|
|
7
|
+
|
|
8
|
+
:param output_file: 输出文件路径
|
|
9
|
+
:param files_to_merge: 要合并的文件列表,包含文件路径和描述
|
|
10
|
+
:param title: 文档标题
|
|
11
|
+
"""
|
|
12
|
+
with open(output_file, 'w', encoding='utf-8') as outfile:
|
|
13
|
+
# 写入头部说明
|
|
14
|
+
outfile.write(f"# ErisPulse {title}\n\n")
|
|
15
|
+
outfile.write(f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}\n\n")
|
|
16
|
+
outfile.write("本文件由多个开发文档合并而成,用于辅助开发者理解 ErisPulse 的相关功能。\n\n")
|
|
17
|
+
|
|
18
|
+
# 写入目录
|
|
19
|
+
outfile.write("## 目录\n\n")
|
|
20
|
+
for i, file_info in enumerate(files_to_merge, 1):
|
|
21
|
+
filename = os.path.basename(file_info['path'])
|
|
22
|
+
outfile.write(f"{i}. [{file_info.get('description', filename)}](#{filename.replace('.', '').replace(' ', '-')})\n")
|
|
23
|
+
outfile.write("\n")
|
|
24
|
+
|
|
25
|
+
outfile.write("## 各文件对应内容说明\n\n")
|
|
26
|
+
outfile.write("| 文件名 | 作用 |\n")
|
|
27
|
+
outfile.write("|--------|------|\n")
|
|
28
|
+
|
|
29
|
+
# 写入文件说明
|
|
30
|
+
for file_info in files_to_merge:
|
|
31
|
+
filename = os.path.basename(file_info['path'])
|
|
32
|
+
outfile.write(f"| [{filename}](#{filename.replace('.', '').replace(' ', '-')}) | {file_info.get('description', '')} |\n")
|
|
33
|
+
|
|
34
|
+
outfile.write("\n---\n\n")
|
|
35
|
+
|
|
36
|
+
# 合并文件内容
|
|
37
|
+
for file_info in files_to_merge:
|
|
38
|
+
file_path = file_info['path']
|
|
39
|
+
if os.path.exists(file_path):
|
|
40
|
+
filename = os.path.basename(file_path)
|
|
41
|
+
outfile.write(f"<a id=\"{filename.replace('.', '').replace(' ', '-')}\"></a>\n")
|
|
42
|
+
outfile.write(f"## {file_info.get('description', filename)}\n\n")
|
|
43
|
+
|
|
44
|
+
with open(file_path, 'r', encoding='utf-8') as infile:
|
|
45
|
+
content = infile.read()
|
|
46
|
+
outfile.write(content)
|
|
47
|
+
outfile.write(f"\n\n---\n\n")
|
|
48
|
+
else:
|
|
49
|
+
print(f"文件不存在,跳过: {file_path}")
|
|
50
|
+
|
|
51
|
+
def merge_api_docs(api_dir, output_file):
|
|
52
|
+
"""
|
|
53
|
+
合并API文档
|
|
54
|
+
|
|
55
|
+
:param api_dir: API文档目录
|
|
56
|
+
:param output_file: 输出文件路径
|
|
57
|
+
"""
|
|
58
|
+
if not os.path.exists(api_dir):
|
|
59
|
+
print(f"API文档目录不存在: {api_dir}")
|
|
60
|
+
return
|
|
61
|
+
|
|
62
|
+
with open(output_file, 'a', encoding='utf-8') as outfile:
|
|
63
|
+
outfile.write("# API参考\n\n")
|
|
64
|
+
|
|
65
|
+
# 收集所有API文档文件
|
|
66
|
+
api_files = []
|
|
67
|
+
for root, _, files in os.walk(api_dir):
|
|
68
|
+
for file in files:
|
|
69
|
+
if file.endswith('.md'):
|
|
70
|
+
file_path = os.path.join(root, file)
|
|
71
|
+
api_files.append(file_path)
|
|
72
|
+
|
|
73
|
+
# 按路径排序以保持一致性
|
|
74
|
+
api_files.sort()
|
|
75
|
+
|
|
76
|
+
# 生成API文档目录
|
|
77
|
+
outfile.write("## API文档目录\n\n")
|
|
78
|
+
for file_path in api_files:
|
|
79
|
+
rel_path = os.path.relpath(file_path, api_dir)
|
|
80
|
+
anchor = rel_path.replace(os.sep, "_").replace(".md", "")
|
|
81
|
+
outfile.write(f"- [{rel_path}](#{anchor})\n")
|
|
82
|
+
outfile.write("\n---\n\n")
|
|
83
|
+
|
|
84
|
+
# 合并API文档内容
|
|
85
|
+
for file_path in api_files:
|
|
86
|
+
rel_path = os.path.relpath(file_path, api_dir)
|
|
87
|
+
anchor = rel_path.replace(os.sep, "_").replace(".md", "")
|
|
88
|
+
|
|
89
|
+
outfile.write(f"<a id=\"{anchor}\"></a>\n")
|
|
90
|
+
outfile.write(f"## {rel_path}\n\n")
|
|
91
|
+
|
|
92
|
+
try:
|
|
93
|
+
with open(file_path, 'r', encoding='utf-8') as infile:
|
|
94
|
+
content = infile.read()
|
|
95
|
+
# 移除原有标题,因为我们已经添加了
|
|
96
|
+
lines = content.split('\n')
|
|
97
|
+
if lines and lines[0].startswith('# '):
|
|
98
|
+
content = '\n'.join(lines[1:])
|
|
99
|
+
|
|
100
|
+
outfile.write(content)
|
|
101
|
+
outfile.write("\n\n")
|
|
102
|
+
except Exception as e:
|
|
103
|
+
outfile.write(f"无法读取文件 {file_path}: {str(e)}\n\n")
|
|
104
|
+
|
|
105
|
+
outfile.write("---\n")
|
|
106
|
+
|
|
107
|
+
def generate_full_document():
|
|
108
|
+
print("正在生成完整文档...")
|
|
109
|
+
|
|
110
|
+
# 要合并的文件
|
|
111
|
+
files_to_merge = [
|
|
112
|
+
{"path": "docs/quick-start.md", "description": "快速开始指南"},
|
|
113
|
+
{"path": "docs/UseCore.md", "description": "核心功能使用说明"},
|
|
114
|
+
{"path": "docs/PlatformFeatures.md", "description": "平台功能说明"},
|
|
115
|
+
{"path": "docs/Development/Module.md", "description": "模块开发指南"},
|
|
116
|
+
{"path": "docs/Development/Adapter.md", "description": "适配器开发指南"},
|
|
117
|
+
{"path": "docs/AdapterStandards/APIResponse.md", "description": "API响应标准"},
|
|
118
|
+
{"path": "docs/AdapterStandards/EventConversion.md", "description": "事件转换标准"},
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
# 过滤不存在的文件
|
|
122
|
+
existing_files = [f for f in files_to_merge if os.path.exists(f['path'])]
|
|
123
|
+
if len(existing_files) != len(files_to_merge):
|
|
124
|
+
print(f"警告: {len(files_to_merge) - len(existing_files)} 个文件不存在,已跳过")
|
|
125
|
+
|
|
126
|
+
output_file = "docs/AIDocs/ErisPulse-Full.md"
|
|
127
|
+
os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
|
128
|
+
|
|
129
|
+
merge_md_files(output_file, existing_files, "完整开发文档")
|
|
130
|
+
merge_api_docs("docs/api", output_file)
|
|
131
|
+
|
|
132
|
+
print(f"完整文档生成完成,已保存到: {output_file}")
|
|
133
|
+
|
|
134
|
+
def generate_core_document():
|
|
135
|
+
print("正在生成核心功能文档...")
|
|
136
|
+
|
|
137
|
+
files_to_merge = [
|
|
138
|
+
{"path": "docs/quick-start.md", "description": "快速开始指南"},
|
|
139
|
+
{"path": "docs/UseCore.md", "description": "核心功能使用说明"},
|
|
140
|
+
{"path": "docs/PlatformFeatures.md", "description": "平台功能说明"},
|
|
141
|
+
]
|
|
142
|
+
|
|
143
|
+
# 过滤不存在的文件
|
|
144
|
+
existing_files = [f for f in files_to_merge if os.path.exists(f['path'])]
|
|
145
|
+
|
|
146
|
+
output_file = "docs/AIDocs/ErisPulse-Core.md"
|
|
147
|
+
os.makedirs(os.path.dirname(output_file), exist_ok=True)
|
|
148
|
+
|
|
149
|
+
merge_md_files(output_file, existing_files, "核心功能文档")
|
|
150
|
+
# 合并API文档
|
|
151
|
+
merge_api_docs("docs/api", output_file)
|
|
152
|
+
|
|
153
|
+
print(f"核心功能文档生成完成,已保存到: {output_file}")
|
|
154
|
+
|
|
155
|
+
def generate_dev_documents():
|
|
156
|
+
print("正在生成开发文档...")
|
|
157
|
+
|
|
158
|
+
# 模块开发文档
|
|
159
|
+
module_files = [
|
|
160
|
+
{"path": "docs/quick-start.md", "description": "快速开始指南"},
|
|
161
|
+
{"path": "docs/UseCore.md", "description": "核心功能使用说明"},
|
|
162
|
+
{"path": "docs/PlatformFeatures.md", "description": "平台支持的发送类型及差异性说明"},
|
|
163
|
+
{"path": "docs/Development/Module.md", "description": "模块开发指南"}
|
|
164
|
+
]
|
|
165
|
+
|
|
166
|
+
# 过滤不存在的文件
|
|
167
|
+
existing_module_files = [f for f in module_files if os.path.exists(f['path'])]
|
|
168
|
+
|
|
169
|
+
module_output = "docs/AIDocs/ErisPulse-ModuleDev.md"
|
|
170
|
+
os.makedirs(os.path.dirname(module_output), exist_ok=True)
|
|
171
|
+
merge_md_files(module_output, existing_module_files, "模块开发文档")
|
|
172
|
+
# 合并API文档
|
|
173
|
+
merge_api_docs("docs/api", module_output)
|
|
174
|
+
|
|
175
|
+
print(f"模块开发文档生成完成,已保存到: {module_output}")
|
|
176
|
+
|
|
177
|
+
# 适配器开发文档
|
|
178
|
+
adapter_files = [
|
|
179
|
+
{"path": "docs/quick-start.md", "description": "快速开始指南"},
|
|
180
|
+
{"path": "docs/UseCore.md", "description": "核心功能使用说明"},
|
|
181
|
+
{"path": "docs/Development/Adapter.md", "description": "适配器开发指南"},
|
|
182
|
+
{"path": "docs/AdapterStandards/APIResponse.md", "description": "API响应标准"},
|
|
183
|
+
{"path": "docs/AdapterStandards/EventConversion.md", "description": "事件转换标准"},
|
|
184
|
+
]
|
|
185
|
+
|
|
186
|
+
# 过滤不存在的文件
|
|
187
|
+
existing_adapter_files = [f for f in adapter_files if os.path.exists(f['path'])]
|
|
188
|
+
|
|
189
|
+
adapter_output = "docs/AIDocs/ErisPulse-AdapterDev.md"
|
|
190
|
+
os.makedirs(os.path.dirname(adapter_output), exist_ok=True)
|
|
191
|
+
merge_md_files(adapter_output, existing_adapter_files, "适配器开发文档")
|
|
192
|
+
# 合并API文档
|
|
193
|
+
merge_api_docs("docs/api", adapter_output)
|
|
194
|
+
|
|
195
|
+
print(f"适配器开发文档生成完成,已保存到: {adapter_output}")
|
|
196
|
+
|
|
197
|
+
def generate_custom_document(title, files, api_dirs, output_path):
|
|
198
|
+
"""
|
|
199
|
+
生成自定义文档
|
|
200
|
+
|
|
201
|
+
:param title: 文档标题
|
|
202
|
+
:param files: 要合并的文件列表
|
|
203
|
+
:param api_dirs: 要合并的API目录列表
|
|
204
|
+
:param output_path: 输出路径
|
|
205
|
+
"""
|
|
206
|
+
print(f"正在生成{title}...")
|
|
207
|
+
|
|
208
|
+
# 过滤不存在的文件
|
|
209
|
+
existing_files = [f for f in files if os.path.exists(f['path'])]
|
|
210
|
+
|
|
211
|
+
os.makedirs(os.path.dirname(output_path), exist_ok=True)
|
|
212
|
+
merge_md_files(output_path, existing_files, title)
|
|
213
|
+
|
|
214
|
+
# API文档
|
|
215
|
+
merge_api_docs("docs/api", output_path)
|
|
216
|
+
|
|
217
|
+
print(f"{title}生成完成,已保存到: {output_path}")
|
|
218
|
+
|
|
219
|
+
if __name__ == "__main__":
|
|
220
|
+
try:
|
|
221
|
+
generate_full_document()
|
|
222
|
+
generate_core_document()
|
|
223
|
+
generate_dev_documents()
|
|
224
|
+
print("所有文档生成完成")
|
|
225
|
+
except Exception as e:
|
|
226
|
+
print(f"文档生成过程中出现错误: {str(e)}")
|
|
@@ -102,7 +102,7 @@ def parse_python_file(file_path: str) -> Tuple[Optional[str], List[Dict], List[D
|
|
|
102
102
|
try:
|
|
103
103
|
module = ast.parse(source)
|
|
104
104
|
except SyntaxError:
|
|
105
|
-
print(f"
|
|
105
|
+
print(f"语法错误,跳过文件: {file_path}")
|
|
106
106
|
return None, [], []
|
|
107
107
|
|
|
108
108
|
# 提取模块文档
|
|
@@ -211,9 +211,9 @@ def generate_markdown(module_path: str, module_doc: Optional[str],
|
|
|
211
211
|
content = []
|
|
212
212
|
|
|
213
213
|
# 文档头部
|
|
214
|
-
content.append(f"""#
|
|
214
|
+
content.append(f"""# `{module_path}` 模块
|
|
215
215
|
|
|
216
|
-
<sup
|
|
216
|
+
<sup>更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</sup>
|
|
217
217
|
|
|
218
218
|
---
|
|
219
219
|
|
|
@@ -229,9 +229,9 @@ def generate_markdown(module_path: str, module_doc: Optional[str],
|
|
|
229
229
|
|
|
230
230
|
# 函数部分
|
|
231
231
|
if functions:
|
|
232
|
-
content.append("##
|
|
232
|
+
content.append("## 函数列表\n")
|
|
233
233
|
for func in functions:
|
|
234
|
-
async_marker = "
|
|
234
|
+
async_marker = "async " if func["is_async"] else ""
|
|
235
235
|
content.append(f"""### {async_marker}`{func['signature']}`
|
|
236
236
|
|
|
237
237
|
{func['doc']}
|
|
@@ -241,7 +241,7 @@ def generate_markdown(module_path: str, module_doc: Optional[str],
|
|
|
241
241
|
|
|
242
242
|
# 类部分
|
|
243
243
|
if classes:
|
|
244
|
-
content.append("##
|
|
244
|
+
content.append("## 类列表\n")
|
|
245
245
|
for cls in classes:
|
|
246
246
|
content.append(f"""### `{cls['signature']}`
|
|
247
247
|
|
|
@@ -251,9 +251,9 @@ def generate_markdown(module_path: str, module_doc: Optional[str],
|
|
|
251
251
|
|
|
252
252
|
# 类方法
|
|
253
253
|
if cls["methods"]:
|
|
254
|
-
content.append("####
|
|
254
|
+
content.append("#### 方法列表\n")
|
|
255
255
|
for method in cls["methods"]:
|
|
256
|
-
async_marker = "
|
|
256
|
+
async_marker = "async " if method["is_async"] else ""
|
|
257
257
|
content.append(f"""##### {async_marker}`{method['signature']}`
|
|
258
258
|
|
|
259
259
|
{method['doc']}
|
|
@@ -480,8 +480,8 @@ def generate_html(module_path: str, module_doc: Optional[str],
|
|
|
480
480
|
<body>
|
|
481
481
|
<header>
|
|
482
482
|
<div class="container">
|
|
483
|
-
<h1
|
|
484
|
-
<p><small
|
|
483
|
+
<h1>`{module_path}` 模块</h1>
|
|
484
|
+
<p><small>更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</small></p>
|
|
485
485
|
</div>
|
|
486
486
|
</header>
|
|
487
487
|
|
|
@@ -498,18 +498,18 @@ def generate_html(module_path: str, module_doc: Optional[str],
|
|
|
498
498
|
|
|
499
499
|
# 函数部分
|
|
500
500
|
if functions:
|
|
501
|
-
html_content.append("</section>\n\n<section>\n<h2
|
|
501
|
+
html_content.append("</section>\n\n<section>\n<h2>函数列表</h2>\n")
|
|
502
502
|
for func in functions:
|
|
503
|
-
async_marker = "
|
|
503
|
+
async_marker = "async " if func["is_async"] else ""
|
|
504
504
|
html_content.append(f"""<article>
|
|
505
|
-
<h3
|
|
505
|
+
<h3><code class="signature function-signature">{async_marker}{func['signature']}</code></h3>
|
|
506
506
|
<div>{func['doc']}</div>
|
|
507
507
|
</article>
|
|
508
508
|
""")
|
|
509
509
|
|
|
510
510
|
# 类部分
|
|
511
511
|
if classes:
|
|
512
|
-
html_content.append("</section>\n\n<section>\n<h2
|
|
512
|
+
html_content.append("</section>\n\n<section>\n<h2>类列表</h2>\n")
|
|
513
513
|
for cls in classes:
|
|
514
514
|
html_content.append(f"""<article>
|
|
515
515
|
<h3><code class="signature class-signature">{cls['signature']}</code></h3>
|
|
@@ -518,11 +518,11 @@ def generate_html(module_path: str, module_doc: Optional[str],
|
|
|
518
518
|
|
|
519
519
|
# 类方法
|
|
520
520
|
if cls["methods"]:
|
|
521
|
-
html_content.append("<h4
|
|
521
|
+
html_content.append("<h4>方法列表</h4>\n")
|
|
522
522
|
for method in cls["methods"]:
|
|
523
|
-
async_marker = "
|
|
523
|
+
async_marker = "async " if method["is_async"] else ""
|
|
524
524
|
html_content.append(f"""<article>
|
|
525
|
-
<h5
|
|
525
|
+
<h5><code class="signature method-signature">{async_marker}{method['signature']}</code></h5>
|
|
526
526
|
<div>{method['doc']}</div>
|
|
527
527
|
</article>
|
|
528
528
|
""")
|
|
@@ -539,7 +539,7 @@ def generate_html(module_path: str, module_doc: Optional[str],
|
|
|
539
539
|
</footer>
|
|
540
540
|
</body>
|
|
541
541
|
</html>""")
|
|
542
|
-
|
|
542
|
+
|
|
543
543
|
return "\n".join(html_content)
|
|
544
544
|
|
|
545
545
|
def generate_api_docs(src_dir: str, output_dir: str, format: str = "markdown"):
|
|
@@ -568,7 +568,7 @@ def generate_api_docs(src_dir: str, output_dir: str, format: str = "markdown"):
|
|
|
568
568
|
|
|
569
569
|
# 跳过没有文档的文件
|
|
570
570
|
if not module_doc and not classes and not functions:
|
|
571
|
-
print(f"
|
|
571
|
+
print(f"跳过无文档文件: {file_path}")
|
|
572
572
|
continue
|
|
573
573
|
|
|
574
574
|
# 生成内容
|
|
@@ -586,7 +586,7 @@ def generate_api_docs(src_dir: str, output_dir: str, format: str = "markdown"):
|
|
|
586
586
|
with open(output_path, "w", encoding="utf-8") as f:
|
|
587
587
|
f.write(content)
|
|
588
588
|
|
|
589
|
-
print(f"
|
|
589
|
+
print(f"已生成: {output_path}")
|
|
590
590
|
|
|
591
591
|
if __name__ == "__main__":
|
|
592
592
|
parser = argparse.ArgumentParser(description="API文档生成器")
|
|
@@ -597,20 +597,11 @@ if __name__ == "__main__":
|
|
|
597
597
|
|
|
598
598
|
args = parser.parse_args()
|
|
599
599
|
|
|
600
|
-
print(f"""
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
600
|
+
print(f"""源代码目录: {args.src}
|
|
601
|
+
输出目录: {args.output}
|
|
602
|
+
输出格式: {args.format}
|
|
603
|
+
正在生成API文档...""")
|
|
604
604
|
|
|
605
605
|
generate_api_docs(args.src, args.output, args.format)
|
|
606
606
|
|
|
607
|
-
print(f"
|
|
608
|
-
|
|
609
|
-
生成文档包含以下改进:
|
|
610
|
-
✨ 更现代化的样式和布局
|
|
611
|
-
📅 自动添加生成时间戳
|
|
612
|
-
🔖 使用emoji图标提高可读性
|
|
613
|
-
📝 优化了参数和返回值的显示方式
|
|
614
|
-
📱 响应式设计,适配移动设备
|
|
615
|
-
💡 改进了示例代码的展示方式
|
|
616
|
-
""")
|
|
607
|
+
print(f"API文档生成完成!")
|
|
@@ -33,12 +33,16 @@ jobs:
|
|
|
33
33
|
|
|
34
34
|
commit_msg=$(git log -1 --pretty=%B)
|
|
35
35
|
commit_short=$(git rev-parse --short HEAD)
|
|
36
|
+
commit_author=$(git log -1 --pretty=%an)
|
|
37
|
+
commit_email=$(git log -1 --pretty=%ae)
|
|
36
38
|
echo "commit_short=$commit_short" >> $GITHUB_OUTPUT
|
|
39
|
+
echo "commit_author=$commit_author" >> $GITHUB_OUTPUT
|
|
40
|
+
echo "commit_email=$commit_email" >> $GITHUB_OUTPUT
|
|
37
41
|
echo "commit_msg<<EOF" >> $GITHUB_OUTPUT
|
|
38
42
|
echo "$commit_msg" >> $GITHUB_OUTPUT
|
|
39
43
|
echo "EOF" >> $GITHUB_OUTPUT
|
|
40
44
|
|
|
41
|
-
- name:
|
|
45
|
+
- name: 获取变更文件列表和贡献者
|
|
42
46
|
id: changed_files
|
|
43
47
|
shell: bash
|
|
44
48
|
run: |
|
|
@@ -52,15 +56,21 @@ jobs:
|
|
|
52
56
|
echo "before=$before" >> $GITHUB_OUTPUT
|
|
53
57
|
echo "after=$after" >> $GITHUB_OUTPUT
|
|
54
58
|
|
|
59
|
+
# 获取变更文件列表
|
|
55
60
|
files=$(git diff --name-only $before..$after | head -n 50 | xargs)
|
|
56
61
|
file_count=$(git diff --name-only $before..$after | wc -l)
|
|
57
62
|
|
|
58
63
|
if [ "$file_count" -gt 50 ]; then
|
|
59
64
|
files="$files ..."
|
|
60
65
|
fi
|
|
61
|
-
|
|
62
66
|
echo "files=$files" >> $GITHUB_OUTPUT
|
|
63
67
|
|
|
68
|
+
# 获取贡献者列表
|
|
69
|
+
contributors=$(git log $before..$after --format="%an <%ae>" | sort -u)
|
|
70
|
+
echo "contributors<<EOF" >> $GITHUB_OUTPUT
|
|
71
|
+
echo "$contributors" >> $GITHUB_OUTPUT
|
|
72
|
+
echo "EOF" >> $GITHUB_OUTPUT
|
|
73
|
+
|
|
64
74
|
- name: 施展版本魔法
|
|
65
75
|
env:
|
|
66
76
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -68,19 +78,38 @@ jobs:
|
|
|
68
78
|
run: |
|
|
69
79
|
version="${{ steps.info.outputs.version }}"
|
|
70
80
|
commit_short="${{ steps.info.outputs.commit_short }}"
|
|
81
|
+
commit_author="${{ steps.info.outputs.commit_author }}"
|
|
82
|
+
commit_email="${{ steps.info.outputs.commit_email }}"
|
|
71
83
|
commit_msg="${{ steps.info.outputs.commit_msg }}"
|
|
72
84
|
is_dev="${{ steps.info.outputs.is_dev }}"
|
|
85
|
+
contributors="${{ steps.changed_files.outputs.contributors }}"
|
|
73
86
|
tag_name="v$version"
|
|
74
87
|
|
|
88
|
+
# 构建发布说明
|
|
75
89
|
if [ -f "docs/CHANGELOG.md" ]; then
|
|
76
90
|
changelog=$(sed -n "/^## \[$version\]/,/^## /p" docs/CHANGELOG.md | sed '1d;$d')
|
|
77
91
|
fi
|
|
92
|
+
|
|
78
93
|
if [ -z "$changelog" ]; then
|
|
79
|
-
changelog="###
|
|
94
|
+
changelog="### ✨✨ 魔法更新\n\n- $commit_msg ($commit_short)\n\n"
|
|
95
|
+
else
|
|
96
|
+
changelog="$changelog\n\n"
|
|
80
97
|
fi
|
|
98
|
+
|
|
99
|
+
# 贡献信息
|
|
100
|
+
changelog="${changelog}### 🧙♀️ 魔法贡献者\n\n"
|
|
101
|
+
while IFS= read -r contributor; do
|
|
102
|
+
escaped_contributor=$(echo "$contributor" | sed 's/>/\>/g' | sed 's/</\</g')
|
|
103
|
+
changelog="${changelog}- ${escaped_contributor}\n"
|
|
104
|
+
done <<< "$contributors"
|
|
105
|
+
|
|
106
|
+
changelog="${changelog}\n### 📜 魔法卷轴更新\n\n"
|
|
107
|
+
escaped_commit_msg=$(echo "$commit_msg" | sed 's/#/\\#/g')
|
|
108
|
+
changelog="${changelog}- 最新提交: $escaped_commit_msg (by $commit_author, $commit_short)\n"
|
|
109
|
+
changelog="${changelog}- 变更文件: ${{ steps.changed_files.outputs.files }}\n"
|
|
81
110
|
|
|
82
111
|
if ! git rev-parse "$tag_name" >/dev/null 2>&1; then
|
|
83
|
-
echo "
|
|
112
|
+
echo "🎀🎀 施加新的魔法印记..."
|
|
84
113
|
git tag "$tag_name"
|
|
85
114
|
git push origin "$tag_name"
|
|
86
115
|
fi
|
|
@@ -97,3 +126,4 @@ jobs:
|
|
|
97
126
|
--prerelease=$is_dev
|
|
98
127
|
echo "✨ 已发布新的魔法版本 $tag_name"
|
|
99
128
|
fi
|
|
129
|
+
|