ErisPulse 2.1.13rc3__py3-none-any.whl → 2.1.14__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.
@@ -1,6 +1,8 @@
1
+ # router.py (新文件名)
1
2
  """
2
- ErisPulse Adapter Server
3
- 提供统一的适配器服务入口,支持HTTP和WebSocket路由
3
+ ErisPulse 路由系统
4
+
5
+ 提供统一的HTTP和WebSocket路由管理,支持多适配器路由注册和生命周期管理。
4
6
 
5
7
  {!--< tips >!--}
6
8
  1. 适配器只需注册路由,无需自行管理服务器
@@ -19,9 +21,9 @@ from hypercorn.config import Config
19
21
  from hypercorn.asyncio import serve
20
22
 
21
23
 
22
- class AdapterServer:
24
+ class RouterManager:
23
25
  """
24
- 适配器服务器管理器
26
+ 路由管理器
25
27
 
26
28
  {!--< tips >!--}
27
29
  核心功能:
@@ -33,18 +35,18 @@ class AdapterServer:
33
35
 
34
36
  def __init__(self):
35
37
  """
36
- 初始化适配器服务器
38
+ 初始化路由管理器
37
39
 
38
40
  {!--< tips >!--}
39
41
  会自动创建FastAPI实例并设置核心路由
40
42
  {!--< /tips >!--}
41
43
  """
42
44
  self.app = FastAPI(
43
- title="ErisPulse Adapter Server",
44
- description="统一适配器服务入口点",
45
+ title="ErisPulse Router",
46
+ description="统一路由管理入口点",
45
47
  version="1.0.0"
46
48
  )
47
- self._webhook_routes: Dict[str, Dict[str, Callable]] = defaultdict(dict)
49
+ self._http_routes: Dict[str, Dict[str, Callable]] = defaultdict(dict)
48
50
  self._websocket_routes: Dict[str, Dict[str, Tuple[Callable, Optional[Callable]]]] = defaultdict(dict)
49
51
  self.base_url = ""
50
52
  self._server_task: Optional[asyncio.Task] = None
@@ -66,7 +68,7 @@ class AdapterServer:
66
68
  :return:
67
69
  Dict[str, str]: 包含服务状态的字典
68
70
  """
69
- return {"status": "ok", "service": "ErisPulse Adapter Server"}
71
+ return {"status": "ok", "service": "ErisPulse Router"}
70
72
 
71
73
  @self.app.get("/routes")
72
74
  async def list_routes() -> Dict[str, Any]:
@@ -74,36 +76,23 @@ class AdapterServer:
74
76
  列出所有已注册路由
75
77
 
76
78
  :return:
77
- Dict[str, Any]: 包含所有路由信息的字典,格式为:
78
- {
79
- "http_routes": [
80
- {
81
- "path": "/adapter1/route1",
82
- "adapter": "adapter1",
83
- "methods": ["POST"]
84
- },
85
- ...
86
- ],
87
- "websocket_routes": [
88
- {
89
- "path": "/adapter1/ws",
90
- "adapter": "adapter1",
91
- "requires_auth": true
92
- },
93
- ...
94
- ],
95
- "base_url": self.base_url
96
- }
79
+ Dict[str, Any]: 包含所有路由信息的字典
97
80
  """
98
81
  http_routes = []
99
- for adapter, routes in self._webhook_routes.items():
82
+ for adapter, routes in self._http_routes.items():
100
83
  for path, handler in routes.items():
101
- route = self.app.router.routes[-1] # 获取最后添加的路由
102
- if isinstance(route, APIRoute) and route.path == path:
84
+ # 查找对应的路由对象
85
+ route_obj = None
86
+ for route in self.app.router.routes:
87
+ if isinstance(route, APIRoute) and route.path == path:
88
+ route_obj = route
89
+ break
90
+
91
+ if route_obj:
103
92
  http_routes.append({
104
93
  "path": path,
105
94
  "adapter": adapter,
106
- "methods": route.methods
95
+ "methods": list(route_obj.methods)
107
96
  })
108
97
 
109
98
  websocket_routes = []
@@ -121,9 +110,9 @@ class AdapterServer:
121
110
  "base_url": self.base_url
122
111
  }
123
112
 
124
- def register_webhook(
113
+ def register_http_route(
125
114
  self,
126
- adapter_name: str,
115
+ module_name: str,
127
116
  path: str,
128
117
  handler: Callable,
129
118
  methods: List[str] = ["POST"]
@@ -131,35 +120,37 @@ class AdapterServer:
131
120
  """
132
121
  注册HTTP路由
133
122
 
134
- :param adapter_name: str 适配器名称
135
- :param path: str 路由路径(如"/message")
123
+ :param module_name: str 模块名称
124
+ :param path: str 路由路径
136
125
  :param handler: Callable 处理函数
137
126
  :param methods: List[str] HTTP方法列表(默认["POST"])
138
127
 
139
128
  :raises ValueError: 当路径已注册时抛出
140
-
141
- {!--< tips >!--}
142
- 路径会自动添加适配器前缀,如:/adapter_name/path
143
- {!--< /tips >!--}
144
129
  """
145
- full_path = f"/{adapter_name}{path}"
130
+ full_path = f"/{module_name}{path}"
146
131
 
147
- if full_path in self._webhook_routes[adapter_name]:
132
+ if full_path in self._http_routes[module_name]:
148
133
  raise ValueError(f"路径 {full_path} 已注册")
149
134
 
150
135
  route = APIRoute(
151
136
  path=full_path,
152
137
  endpoint=handler,
153
138
  methods=methods,
154
- name=f"{adapter_name}{path}"
139
+ name=f"{module_name}_{path.replace('/', '_')}"
155
140
  )
156
141
  self.app.router.routes.append(route)
157
- self._webhook_routes[adapter_name][full_path] = handler
142
+ self._http_routes[module_name][full_path] = handler
158
143
  logger.info(f"注册HTTP路由: {self.base_url}{full_path} 方法: {methods}")
159
144
 
145
+ def register_webhook(self, *args, **kwargs) -> None:
146
+ """
147
+ 兼容性方法:注册HTTP路由(适配器旧接口)
148
+ """
149
+ return self.register_http_route(*args, **kwargs)
150
+
160
151
  def register_websocket(
161
152
  self,
162
- adapter_name: str,
153
+ module_name: str,
163
154
  path: str,
164
155
  handler: Callable[[WebSocket], Awaitable[Any]],
165
156
  auth_handler: Optional[Callable[[WebSocket], Awaitable[bool]]] = None,
@@ -167,29 +158,21 @@ class AdapterServer:
167
158
  """
168
159
  注册WebSocket路由
169
160
 
170
- :param adapter_name: str 适配器名称
171
- :param path: str WebSocket路径(如"/ws")
161
+ :param module_name: str 模块名称
162
+ :param path: str WebSocket路径
172
163
  :param handler: Callable[[WebSocket], Awaitable[Any]] 主处理函数
173
164
  :param auth_handler: Optional[Callable[[WebSocket], Awaitable[bool]]] 认证函数
174
165
 
175
166
  :raises ValueError: 当路径已注册时抛出
176
-
177
- {!--< tips >!--}
178
- 认证函数应返回布尔值,False将拒绝连接
179
- {!--< /tips >!--}
180
167
  """
181
- full_path = f"/{adapter_name}{path}"
168
+ full_path = f"/{module_name}{path}"
182
169
 
183
- if full_path in self._websocket_routes[adapter_name]:
170
+ if full_path in self._websocket_routes[module_name]:
184
171
  raise ValueError(f"WebSocket路径 {full_path} 已注册")
185
172
 
186
173
  async def websocket_endpoint(websocket: WebSocket) -> None:
187
174
  """
188
175
  WebSocket端点包装器
189
-
190
- {!--< internal-use >!--}
191
- 处理连接生命周期和错误处理
192
- {!--< /internal-use >!--}
193
176
  """
194
177
  await websocket.accept()
195
178
 
@@ -209,17 +192,16 @@ class AdapterServer:
209
192
  self.app.add_api_websocket_route(
210
193
  path=full_path,
211
194
  endpoint=websocket_endpoint,
212
- name=f"{adapter_name}{path}"
195
+ name=f"{module_name}_{path.replace('/', '_')}"
213
196
  )
214
- self._websocket_routes[adapter_name][full_path] = (handler, auth_handler)
197
+ self._websocket_routes[module_name][full_path] = (handler, auth_handler)
215
198
  logger.info(f"注册WebSocket: {self.base_url}{full_path} {'(需认证)' if auth_handler else ''}")
216
199
 
217
200
  def get_app(self) -> FastAPI:
218
201
  """
219
202
  获取FastAPI应用实例
220
203
 
221
- :return:
222
- FastAPI: FastAPI应用实例
204
+ :return: FastAPI应用实例
223
205
  """
224
206
  return self.app
225
207
 
@@ -231,7 +213,7 @@ class AdapterServer:
231
213
  ssl_keyfile: Optional[str] = None
232
214
  ) -> None:
233
215
  """
234
- 启动适配器服务器
216
+ 启动路由服务器
235
217
 
236
218
  :param host: str 监听地址(默认"0.0.0.0")
237
219
  :param port: int 监听端口(默认8000)
@@ -252,25 +234,24 @@ class AdapterServer:
252
234
  config.keyfile = ssl_keyfile
253
235
 
254
236
  self.base_url = f"http{'s' if ssl_certfile else ''}://{host}:{port}"
255
- logger.info(f"启动服务器 {self.base_url}")
237
+ logger.info(f"启动路由服务器 {self.base_url}")
256
238
 
257
239
  self._server_task = asyncio.create_task(serve(self.app, config))
258
240
 
259
241
  async def stop(self) -> None:
260
242
  """
261
243
  停止服务器
262
-
263
- {!--< tips >!--}
264
- 会等待所有连接正常关闭
265
- {!--< /tips >!--}
266
244
  """
267
245
  if self._server_task:
268
246
  self._server_task.cancel()
269
247
  try:
270
248
  await self._server_task
271
249
  except asyncio.CancelledError:
272
- logger.info("服务器已停止")
250
+ logger.info("路由服务器已停止")
273
251
  self._server_task = None
274
252
 
253
+ # 主要实例
254
+ router = RouterManager()
275
255
 
276
- adapter_server = AdapterServer()
256
+ # 兼容性实例
257
+ adapter_server = router
ErisPulse/__init__.py CHANGED
@@ -10,37 +10,47 @@ ErisPulse SDK 主模块
10
10
  {!--< /tips >!--}
11
11
  """
12
12
 
13
+ __version__ = "2.1.14"
14
+ __author__ = "ErisPulse"
15
+
13
16
  import os
14
17
  import sys
15
18
  import importlib
19
+ import asyncio
16
20
  import inspect
17
21
  import importlib.metadata
18
22
  from typing import Dict, List, Tuple, Type, Any
19
23
  from pathlib import Path
20
24
 
21
25
  # BaseModules: SDK核心模块
22
- from .Core import util
23
- from .Core import raiserr
24
26
  from .Core import logger
25
27
  from .Core import env
26
28
  from .Core import mods
27
29
  from .Core import adapter, AdapterFather, SendDSL
28
- from .Core import adapter_server
30
+ from .Core import router, adapter_server
31
+ from .Core import exceptions
32
+ from .Core import config
29
33
 
30
34
  sdk = sys.modules[__name__]
31
35
 
32
36
  BaseModules = {
33
- "util": util,
34
37
  "logger": logger,
35
- "raiserr": raiserr,
38
+ "config": config,
39
+ "exceptions": exceptions,
36
40
  "env": env,
37
41
  "mods": mods,
38
42
  "adapter": adapter,
43
+ "router": router,
44
+ "adapter_server": adapter_server,
39
45
  "SendDSL": SendDSL,
40
46
  "AdapterFather": AdapterFather,
41
47
  "BaseAdapter": AdapterFather
42
48
  }
43
49
 
50
+ asyncio_loop = asyncio.get_event_loop()
51
+
52
+ exceptions.setup_async_loop(asyncio_loop)
53
+
44
54
  for module, moduleObj in BaseModules.items():
45
55
  setattr(sdk, module, moduleObj)
46
56
 
@@ -664,23 +674,24 @@ def _prepare_environment() -> bool:
664
674
  {!--< internal-use >!--}
665
675
  准备运行环境
666
676
 
667
- 1. 初始化项目环境文件
668
- 2. 加载环境变量配置
677
+ 初始化项目环境文件
669
678
 
670
679
  :return: bool 环境准备是否成功
671
680
  """
672
681
  logger.info("[Init] 准备初始化环境...")
673
682
  try:
683
+ from .Core.erispulse_config import get_erispulse_config
684
+ get_erispulse_config()
685
+ logger.info("[Init] 配置文件已加载")
686
+
674
687
  main_init = init_progress()
675
688
  if main_init:
676
689
  logger.info("[Init] 项目入口已生成, 你可以在 main.py 中编写一些代码")
677
- env.load_env_file()
678
690
  return True
679
691
  except Exception as e:
680
692
  logger.error(f"环境准备失败: {e}")
681
693
  return False
682
694
 
683
-
684
695
  def init() -> bool:
685
696
  """
686
697
  SDK初始化入口
ErisPulse/__main__.py CHANGED
@@ -19,7 +19,6 @@ import json
19
19
  import asyncio
20
20
  from urllib.parse import urlparse
21
21
  from typing import List, Dict, Tuple, Optional, Callable, Any
22
- from importlib.metadata import version, PackageNotFoundError
23
22
  from watchdog.observers import Observer
24
23
  from watchdog.events import FileSystemEventHandler
25
24
 
@@ -188,26 +187,38 @@ class PackageManager:
188
187
 
189
188
  try:
190
189
  # 查找模块和适配器
191
- for dist in importlib.metadata.distributions():
192
- if "ErisPulse-" in dist.metadata["Name"]:
193
- entry_points = dist.entry_points
194
- for ep in entry_points:
195
- if ep.group == "erispulse.module":
196
- packages["modules"][ep.name] = {
197
- "package": dist.metadata["Name"],
198
- "version": dist.version,
199
- "summary": dist.metadata["Summary"],
200
- "enabled": self._is_module_enabled(ep.name)
201
- }
202
- elif ep.group == "erispulse.adapter":
203
- packages["adapters"][ep.name] = {
204
- "package": dist.metadata["Name"],
205
- "version": dist.version,
206
- "summary": dist.metadata["Summary"]
207
- }
190
+ entry_points = importlib.metadata.entry_points()
191
+
192
+ # 处理模块
193
+ if hasattr(entry_points, 'select'):
194
+ module_entries = entry_points.select(group='erispulse.module')
195
+ else:
196
+ module_entries = entry_points.get('erispulse.module', [])
197
+
198
+ for entry in module_entries:
199
+ dist = entry.dist
200
+ packages["modules"][entry.name] = {
201
+ "package": dist.metadata["Name"],
202
+ "version": dist.version,
203
+ "summary": dist.metadata["Summary"],
204
+ "enabled": self._is_module_enabled(entry.name)
205
+ }
206
+
207
+ # 处理适配器
208
+ if hasattr(entry_points, 'select'):
209
+ adapter_entries = entry_points.select(group='erispulse.adapter')
210
+ else:
211
+ adapter_entries = entry_points.get('erispulse.adapter', [])
212
+
213
+ for entry in adapter_entries:
214
+ dist = entry.dist
215
+ packages["adapters"][entry.name] = {
216
+ "package": dist.metadata["Name"],
217
+ "version": dist.version,
218
+ "summary": dist.metadata["Summary"]
219
+ }
208
220
 
209
221
  # 查找CLI扩展
210
- entry_points = importlib.metadata.entry_points()
211
222
  if hasattr(entry_points, 'select'):
212
223
  cli_entries = entry_points.select(group='erispulse.cli')
213
224
  else:
@@ -222,9 +233,9 @@ class PackageManager:
222
233
  }
223
234
 
224
235
  except Exception as e:
225
- console.print(f"[error]获取已安装包信息失败: {e}[/]")
236
+ print(f"[error] 获取已安装包信息失败: {e}")
226
237
  import traceback
227
- console.print(traceback.format_exc())
238
+ print(traceback.format_exc())
228
239
 
229
240
  return packages
230
241
 
@@ -443,12 +454,44 @@ class ReloadHandler(FileSystemEventHandler):
443
454
 
444
455
  def _handle_reload(self, event, reason: str):
445
456
  """
446
- 处理重载逻辑
447
-
457
+ 处理热重载逻辑
448
458
  :param event: 文件系统事件
449
- :param reason: 重载原因描述
459
+ :param reason: 重载原因
450
460
  """
451
- console.print(f"\n[reload]{reason}: [path]{event.src_path}[/][/]")
461
+ from ErisPulse.Core import adapter, logger
462
+ # 在重载前确保所有适配器正确停止
463
+ try:
464
+ # 检查适配器是否正在运行
465
+ if hasattr(adapter, '_started_instances') and adapter._started_instances:
466
+ logger.info("正在停止适配器...")
467
+ # 创建新的事件循环来运行异步停止操作
468
+ import asyncio
469
+ import threading
470
+
471
+ # 如果在主线程中
472
+ if threading.current_thread() is threading.main_thread():
473
+ try:
474
+ # 尝试获取当前事件循环
475
+ loop = asyncio.get_running_loop()
476
+ # 在新线程中运行适配器停止
477
+ stop_thread = threading.Thread(target=lambda: asyncio.run(adapter.shutdown()))
478
+ stop_thread.start()
479
+ stop_thread.join(timeout=10) # 最多等待10秒
480
+ except RuntimeError:
481
+ # 没有运行中的事件循环
482
+ asyncio.run(adapter.shutdown())
483
+ else:
484
+ # 在非主线程中,创建新的事件循环
485
+ new_loop = asyncio.new_event_loop()
486
+ asyncio.set_event_loop(new_loop)
487
+ new_loop.run_until_complete(adapter.shutdown())
488
+
489
+ logger.info("适配器已停止")
490
+ except Exception as e:
491
+ logger.warning(f"停止适配器时出错: {e}")
492
+
493
+ # 原有的重载逻辑
494
+ logger.info(f"检测到文件变更 ({reason}),正在重启...")
452
495
  self._terminate_process()
453
496
  self.start_process()
454
497
 
@@ -1035,9 +1078,10 @@ class CLI:
1035
1078
 
1036
1079
  try:
1037
1080
  while True:
1038
- time.sleep(1)
1081
+ time.sleep(0.5)
1039
1082
  except KeyboardInterrupt:
1040
1083
  console.print("\n[info]正在安全关闭...[/]")
1084
+ self._cleanup_adapters()
1041
1085
  self._cleanup()
1042
1086
  console.print("[success]已安全退出[/]")
1043
1087
 
@@ -1076,6 +1120,44 @@ class CLI:
1076
1120
  console.print(traceback.format_exc())
1077
1121
  self._cleanup()
1078
1122
  sys.exit(1)
1123
+
1124
+ def _cleanup_adapters(self):
1125
+ """
1126
+ 清理适配器资源
1127
+ """
1128
+ from ErisPulse import adapter, logger
1129
+ try:
1130
+ import asyncio
1131
+ import threading
1132
+
1133
+ # 检查是否有正在运行的适配器
1134
+ if (hasattr(adapter, '_started_instances') and
1135
+ adapter._started_instances):
1136
+
1137
+ logger.info("正在停止所有适配器...")
1138
+
1139
+ if threading.current_thread() is threading.main_thread():
1140
+ try:
1141
+ loop = asyncio.get_running_loop()
1142
+ if loop.is_running():
1143
+ # 在新线程中运行
1144
+ stop_thread = threading.Thread(
1145
+ target=lambda: asyncio.run(adapter.shutdown())
1146
+ )
1147
+ stop_thread.start()
1148
+ stop_thread.join(timeout=5)
1149
+ else:
1150
+ asyncio.run(adapter.shutdown())
1151
+ except RuntimeError:
1152
+ asyncio.run(adapter.shutdown())
1153
+ else:
1154
+ new_loop = asyncio.new_event_loop()
1155
+ asyncio.set_event_loop(new_loop)
1156
+ new_loop.run_until_complete(adapter.shutdown())
1157
+
1158
+ logger.info("适配器已全部停止")
1159
+ except Exception as e:
1160
+ logger.error(f"清理适配器资源时出错: {e}")
1079
1161
 
1080
1162
  def main():
1081
1163
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 2.1.13rc3
3
+ Version: 2.1.14
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>, runoneall <runoobsteve@gmail.com>
6
6
  License: MIT License
@@ -68,17 +68,26 @@ Description-Content-Type: text/markdown
68
68
  [![FramerOrg](https://img.shields.io/badge/合作伙伴-FramerOrg-blue?style=flat-square)](https://github.com/FramerOrg)
69
69
  [![Python Versions](https://img.shields.io/pypi/pyversions/ErisPulse?style=flat-square)](https://pypi.org/project/ErisPulse/)
70
70
 
71
- > 文档站:
72
- [![Docs-Main](https://img.shields.io/badge/docs-main_site-blue?style=flat-square)](https://www.erisdev.com/docs.html)
73
- [![Docs-CF Pages](https://img.shields.io/badge/docs-cloudflare-blue?style=flat-square)](https://erispulse.pages.dev/docs.html)
74
- [![Docs-GitHub](https://img.shields.io/badge/docs-github-blue?style=flat-square)](https://erispulse.github.io/docs.html)
75
- [![Docs-Netlify](https://img.shields.io/badge/docs-netlify-blue?style=flat-square)](https://erispulse.netlify.app/docs.htm)
71
+ ## 文档站
76
72
 
73
+ [![Docs-Main](https://img.shields.io/badge/docs-main_site-blue?style=flat-square)](https://www.erisdev.com/#docs)
74
+ [![Docs-CF Pages](https://img.shields.io/badge/docs-cloudflare-blue?style=flat-square)](https://erispulse.pages.dev/#docs)
75
+ [![Docs-GitHub](https://img.shields.io/badge/docs-github-blue?style=flat-square)](https://erispulse.github.io/#docs)
76
+ [![Docs-Netlify](https://img.shields.io/badge/docs-netlify-blue?style=flat-square)](https://erispulse.netlify.app/#docs)
77
+
78
+ ## 模块市场
79
+
80
+ [![Market-Main](https://img.shields.io/badge/market-erisdev-blue?style=flat-square)](https://www.erisdev.com/#market)
81
+ [![Market-CF Pages](https://img.shields.io/badge/market-cloudflare-blue?style=flat-square)](https://erispulse.pages.dev/#market)
82
+ [![Market-GitHub](https://img.shields.io/badge/market-github-blue?style=flat-square)](https://erispulse.github.io/#market)
83
+ [![Market-Netlify](https://img.shields.io/badge/market-netlify-blue?style=flat-square)](https://erispulse.netlify.app/#market)
84
+
85
+ ---
77
86
 
78
87
  ## 核心特性
79
88
 
80
89
  | 特性 | 描述 |
81
- |------|------|
90
+ |:-----|:-----|
82
91
  | **异步架构** | 完全基于 async/await 的异步设计 |
83
92
  | **模块化系统** | 灵活的插件和模块管理 |
84
93
  | **热重载** | 开发时自动重载,无需重启 |
@@ -100,6 +109,7 @@ irm https://get.erisdev.com/install.ps1 -OutFile install.ps1; powershell -Execut
100
109
  ```
101
110
 
102
111
  #### macOS/Linux:
112
+
103
113
  ```bash
104
114
  curl -sSL https://get.erisdev.com/install.sh | tee install.sh >/dev/null && chmod +x install.sh && ./install.sh
105
115
  ```
@@ -108,14 +118,14 @@ curl -sSL https://get.erisdev.com/install.sh | tee install.sh >/dev/null && chmo
108
118
 
109
119
  ## 测试与开发
110
120
 
111
- ### 克隆项目并进入目录
121
+ ### 1. 克隆项目并进入目录
112
122
 
113
123
  ```bash
114
124
  git clone -b Develop/v2 https://github.com/ErisPulse/ErisPulse.git
115
125
  cd ErisPulse
116
126
  ```
117
127
 
118
- ### 使用 `uv` 同步项目环境
128
+ ### 2. 使用 `uv` 同步项目环境
119
129
 
120
130
  ```bash
121
131
  uv sync
@@ -127,15 +137,15 @@ source .venv/bin/activate
127
137
 
128
138
  > `ErisPulse` 目前正在使用 `python3.13` 进行开发(所以您同步环境时会自动安装 `3.13`),但也可以使用其他版本(版本不应低于 `3.10`)。
129
139
 
130
- ### 安装依赖并开始
140
+ ### 3. 安装依赖并开始
131
141
 
132
142
  ```bash
133
143
  uv pip install -e .
134
144
  ```
135
145
 
136
- 这将以“开发模式”安装 SDK,所有本地修改都会立即生效。
146
+ 这将以"开发模式"安装 SDK,所有本地修改都会立即生效。
137
147
 
138
- ### 验证安装
148
+ ### 4. 验证安装
139
149
 
140
150
  运行以下命令确认 SDK 正常加载:
141
151
 
@@ -143,7 +153,7 @@ uv pip install -e .
143
153
  python -c "from ErisPulse import sdk; sdk.init()"
144
154
  ```
145
155
 
146
- ### 运行测试
156
+ ### 5. 运行测试
147
157
 
148
158
  我们提供了一个交互式测试脚本,可以帮助您快速验证SDK功能:
149
159
 
@@ -158,14 +168,15 @@ uv run devs/test.py
158
168
  - 工具函数测试
159
169
  - 适配器功能测试
160
170
 
161
- ### 开发模式 (热重载)
171
+ ### 6. 开发模式 (热重载)
172
+
162
173
  ```bash
163
174
  epsdk run your_script.py --reload
164
175
  ```
165
176
 
166
177
  ---
167
178
 
168
- ## 🤝 贡献指南
179
+ ## 贡献指南
169
180
 
170
181
  我们欢迎各种形式的贡献,包括但不限于:
171
182
 
@@ -181,6 +192,10 @@ epsdk run your_script.py --reload
181
192
  4. **文档改进**
182
193
  帮助完善文档和示例代码
183
194
 
195
+ [加入社区讨论 →](https://github.com/ErisPulse/ErisPulse/discussions)
196
+
184
197
  ---
185
198
 
186
- [加入社区讨论 →](https://github.com/ErisPulse/ErisPulse/discussions)
199
+ [![](https://starchart.cc/ErisPulse/ErisPulse.svg?variant=adaptive)](https://starchart.cc/ErisPulse/ErisPulse)
200
+
201
+
@@ -0,0 +1,16 @@
1
+ ErisPulse/__init__.py,sha256=PfRuqOSlKcneLN1KrqcW5wFsgnVmpzrDOWrYYweUBjM,26423
2
+ ErisPulse/__main__.py,sha256=sWlvqyvt3LGrkp7WBSsOSbuPrujqgJvLzt5nA5Bdf4w,40790
3
+ ErisPulse/Core/__init__.py,sha256=hX2yEt9VSD3JubiofoQdcY4v1lnQUU02dhuVADkMTVo,437
4
+ ErisPulse/Core/adapter.py,sha256=oBJOp6SS8sm8NgIxQwetGsHu24wHNXz7ESQ5yKJSo7Q,18234
5
+ ErisPulse/Core/config.py,sha256=2BRWINOqKtHSCP4KfhuiRpGwR96jWGKV7gjZSi_VQHE,2397
6
+ ErisPulse/Core/env.py,sha256=U45f9WtriVyd3tW1N8to-ZvpzcF9gD8DJzNTC1jY2cM,17665
7
+ ErisPulse/Core/erispulse_config.py,sha256=QDx401hNX9JcSHqCSVK33X6VTubl6HI1znAK3T_J0K0,3034
8
+ ErisPulse/Core/exceptions.py,sha256=zuTREGczwGzbYT4Z6dACqHwgNRpiJeLFR8aCxFdOg7k,3667
9
+ ErisPulse/Core/logger.py,sha256=8hdbF6x3JpsQbbeEjvbSej134q5oV0wafagpWq3Nbeg,11223
10
+ ErisPulse/Core/mods.py,sha256=2yIq8t9Ca9CBPRiZU0yr8Lc0XGmmkB7LlH-5FWqXjw4,7023
11
+ ErisPulse/Core/router.py,sha256=66hT8VC2dVNX-dANldoOPDcqQ94hidFkNnvKgAPemGQ,8491
12
+ erispulse-2.1.14.dist-info/METADATA,sha256=_vPGvuW0ovuDT71VdSXESB73bvagY1rpskOrPaGY964,6888
13
+ erispulse-2.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
14
+ erispulse-2.1.14.dist-info/entry_points.txt,sha256=Jss71M6nEha0TA-DyVZugPYdcL14s9QpiOeIlgWxzOc,182
15
+ erispulse-2.1.14.dist-info/licenses/LICENSE,sha256=4jyqikiB0G0n06CEEMMTzTXjE4IShghSlB74skMSPQs,1464
16
+ erispulse-2.1.14.dist-info/RECORD,,