sycommon-python-lib 0.1.9__tar.gz → 0.1.11__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.
Files changed (57) hide show
  1. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/PKG-INFO +1 -1
  2. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/pyproject.toml +4 -1
  3. sycommon_python_lib-0.1.11/src/command/cli.py +167 -0
  4. sycommon_python_lib-0.1.11/src/sycommon/middleware/docs.py +30 -0
  5. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/middleware.py +4 -0
  6. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/traceid.py +32 -4
  7. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/base_http.py +27 -25
  8. sycommon_python_lib-0.1.11/src/sycommon/rabbitmq/rabbitmq_client.py +905 -0
  9. sycommon_python_lib-0.1.11/src/sycommon/rabbitmq/rabbitmq_service.py +696 -0
  10. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/services.py +16 -9
  11. sycommon_python_lib-0.1.11/src/sycommon/synacos/feign.py +513 -0
  12. sycommon_python_lib-0.1.11/src/sycommon/tools/docs.py +42 -0
  13. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon_python_lib.egg-info/PKG-INFO +1 -1
  14. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon_python_lib.egg-info/SOURCES.txt +4 -0
  15. sycommon_python_lib-0.1.11/src/sycommon_python_lib.egg-info/entry_points.txt +2 -0
  16. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon_python_lib.egg-info/top_level.txt +1 -0
  17. sycommon_python_lib-0.1.9/src/sycommon/rabbitmq/rabbitmq_client.py +0 -749
  18. sycommon_python_lib-0.1.9/src/sycommon/rabbitmq/rabbitmq_service.py +0 -533
  19. sycommon_python_lib-0.1.9/src/sycommon/synacos/feign.py +0 -301
  20. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/README.md +0 -0
  21. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/setup.cfg +0 -0
  22. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/__init__.py +0 -0
  23. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/Config.py +0 -0
  24. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/DatabaseConfig.py +0 -0
  25. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/EmbeddingConfig.py +0 -0
  26. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/LLMConfig.py +0 -0
  27. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/MQConfig.py +0 -0
  28. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/RerankerConfig.py +0 -0
  29. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/config/__init__.py +0 -0
  30. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/database/base_db_service.py +0 -0
  31. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/database/database_service.py +0 -0
  32. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/health/__init__.py +0 -0
  33. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/health/health_check.py +0 -0
  34. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/health/ping.py +0 -0
  35. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/logging/__init__.py +0 -0
  36. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/logging/kafka_log.py +0 -0
  37. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/logging/logger_wrapper.py +0 -0
  38. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/__init__.py +0 -0
  39. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/context.py +0 -0
  40. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/cors.py +0 -0
  41. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/exception.py +0 -0
  42. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/monitor_memory.py +0 -0
  43. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/mq.py +0 -0
  44. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/middleware/timeout.py +0 -0
  45. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/__init__.py +0 -0
  46. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/log.py +0 -0
  47. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/mqlistener_config.py +0 -0
  48. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/mqmsg_model.py +0 -0
  49. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/mqsend_config.py +0 -0
  50. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/models/sso_user.py +0 -0
  51. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/synacos/__init__.py +0 -0
  52. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/synacos/nacos_service.py +0 -0
  53. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/tools/__init__.py +0 -0
  54. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/tools/snowflake.py +0 -0
  55. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon/tools/timing.py +0 -0
  56. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon_python_lib.egg-info/dependency_links.txt +0 -0
  57. {sycommon_python_lib-0.1.9 → sycommon_python_lib-0.1.11}/src/sycommon_python_lib.egg-info/requires.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sycommon-python-lib
3
- Version: 0.1.9
3
+ Version: 0.1.11
4
4
  Summary: Add your description here
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "sycommon-python-lib"
3
- version = "0.1.9"
3
+ version = "0.1.11"
4
4
  description = "Add your description here"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -23,3 +23,6 @@ dependencies = [
23
23
 
24
24
  [tool.setuptools]
25
25
  packages = {find = {where = ["src"]}}
26
+
27
+ [project.scripts]
28
+ sycommon = "command.cli:main"
@@ -0,0 +1,167 @@
1
+ import argparse
2
+ import os
3
+ import datetime
4
+ import re
5
+ from pathlib import Path
6
+ from importlib.resources import files
7
+
8
+
9
+ def get_all_files_in_directory(directory: Path) -> list[tuple[Path, str]]:
10
+ """
11
+ 获取目录下所有文件的相对路径(忽略__pycache__目录)
12
+ 返回值: 元组列表 (模板文件路径, 相对目标路径)
13
+ """
14
+ file_mappings = []
15
+ if not directory.exists() or not directory.is_dir():
16
+ return file_mappings
17
+
18
+ # 遍历目录下所有文件
19
+ for root, _, files in os.walk(directory):
20
+ # 跳过包含__pycache__的目录
21
+ if "__pycache__" in root:
22
+ continue
23
+
24
+ for file in files:
25
+ # 获取文件的绝对路径
26
+ file_path = Path(root) / file
27
+ # 计算相对模板目录的路径
28
+ rel_path = file_path.relative_to(directory)
29
+ # 添加到映射列表
30
+ file_mappings.append((file_path, str(rel_path)))
31
+
32
+ return file_mappings
33
+
34
+
35
+ def init_project(project_name: str, project_type: str) -> None:
36
+ """
37
+ 初始化项目,自动读取模板文件并替换占位符
38
+ """
39
+ project_path = Path(os.getcwd()) / project_name
40
+ if project_path.exists():
41
+ print(f"❌ 错误:工程 '{project_path}' 已存在")
42
+ return
43
+
44
+ template_root = files("command.templates")
45
+ if not template_root.is_dir():
46
+ print("❌ 错误:未找到模板文件目录(command/templates)")
47
+ return
48
+
49
+ # 处理项目名称
50
+ short_project_name = project_name.replace("shengye-platform-", "")
51
+ short_project_name_upper = short_project_name.upper()
52
+
53
+ # 定义模板变量
54
+ context = {
55
+ "__cli__.project_name": project_name,
56
+ "__cli__.short_project_name": short_project_name,
57
+ "__cli__.short_project_name_upper": short_project_name_upper,
58
+ "__cli__.project_type": project_type,
59
+ "__cli__.create_time": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
60
+ "__cli__.author": os.getlogin(),
61
+ "__cli__.default_port": 8080
62
+ }
63
+
64
+ # 自动获取基础模板文件和特定类型模板文件
65
+ base_dir = template_root / "base"
66
+ type_dir = template_root / project_type
67
+
68
+ base_files = get_all_files_in_directory(base_dir)
69
+ type_specific_files = get_all_files_in_directory(type_dir)
70
+
71
+ # 合并所有文件映射
72
+ file_mappings = base_files + type_specific_files
73
+ copied_files = 0
74
+
75
+ # 处理每个文件
76
+ for template_file, target_rel_path in file_mappings:
77
+ try:
78
+ # 1. 读取模板内容
79
+ template_content = template_file.read_text(encoding="utf-8")
80
+
81
+ # 2. 替换所有占位符(包含花括号)
82
+ rendered_content = template_content
83
+ for key, value in context.items():
84
+ # 精确匹配带有花括号的占位符
85
+ pattern = re.compile(rf'{{\s*{re.escape(key)}\s*}}')
86
+ rendered_content = pattern.sub(str(value), rendered_content)
87
+
88
+ # 3. 清理引号(针对YAML键值对格式)
89
+ rendered_content = re.sub(
90
+ r'(\w+)\s*:\s*["\']([^"\']+)["\']',
91
+ r'\1: \2',
92
+ rendered_content
93
+ )
94
+
95
+ # 4. 最后检查并移除任何残留的花括号
96
+ for value in context.values():
97
+ rendered_content = re.sub(
98
+ rf'{{+{re.escape(str(value))}+}}',
99
+ str(value),
100
+ rendered_content
101
+ )
102
+
103
+ # 5. 处理文件后缀:直接移除.tpl后缀
104
+ if target_rel_path.endswith('.tpl'):
105
+ target_rel_path = target_rel_path[:-4]
106
+
107
+ # 6. 写入文件
108
+ target_file = project_path / target_rel_path
109
+ target_file.parent.mkdir(parents=True, exist_ok=True)
110
+ target_file.write_text(rendered_content, encoding="utf-8")
111
+
112
+ copied_files += 1
113
+ except Exception as e:
114
+ print(f"❌ 处理模板 {template_file} 失败: {str(e)}")
115
+
116
+ if copied_files > 0:
117
+ print(f"✅ 模板{project_type}工程 {project_name} 创建完成!")
118
+ print(f"📁 工程路径:{project_path}")
119
+ print(f"📊 共创建 {copied_files} 个文件")
120
+ else:
121
+ print(f"\n⚠️ 未创建任何文件,可能是缺少模板文件或模板路径配置错误")
122
+
123
+
124
+ def main() -> None:
125
+ parser = argparse.ArgumentParser(
126
+ prog="sycommon",
127
+ description="sycommon 工具集 - 项目初始化工具",
128
+ formatter_class=argparse.RawTextHelpFormatter
129
+ )
130
+ subparsers = parser.add_subparsers(
131
+ dest="command", required=True, help="子命令(当前支持:init)"
132
+ )
133
+
134
+ init_parser = subparsers.add_parser(
135
+ "init",
136
+ help="创建Web/Agent类型项目模板",
137
+ formatter_class=argparse.RawTextHelpFormatter,
138
+ epilog="示例:\n"
139
+ " sycommon init web my_project # 创建Web类型项目\n"
140
+ " sycommon init agent my_project # 创建AI Agent类型项目"
141
+ )
142
+ init_parser.add_argument(
143
+ "project_type",
144
+ choices=["web", "agent"],
145
+ help="项目类型:web - Web服务项目;agent - AI Agent服务项目"
146
+ )
147
+ init_parser.add_argument(
148
+ "project_name",
149
+ help="工程名称(如 my_web_project,将创建同名根目录)"
150
+ )
151
+
152
+ try:
153
+ args = parser.parse_args()
154
+ if args.command == "init":
155
+ init_project(args.project_name, args.project_type)
156
+ except argparse.ArgumentError as e:
157
+ print(f"❌ 错误:{e}\n")
158
+ print(
159
+ f"请使用 {parser.prog} {args.command if 'args' in locals() else ''} -h 查看帮助")
160
+ except SystemExit:
161
+ pass
162
+
163
+
164
+ if __name__ == "__main__":
165
+ # uv pip install -e .
166
+ # sycommon init web my_project
167
+ main()
@@ -0,0 +1,30 @@
1
+ from fastapi import FastAPI, APIRouter
2
+ from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
3
+
4
+
5
+ def setup_docs_handler(app: FastAPI):
6
+ docs_router = APIRouter()
7
+
8
+ @docs_router.get("/docs", include_in_schema=False)
9
+ async def custom_swagger_ui_html():
10
+ return get_swagger_ui_html(
11
+ openapi_url=app.openapi_url,
12
+ title=f"{app.title}",
13
+ swagger_favicon_url="https://static.sytechnology.com/img/sylogopng.png",
14
+ swagger_js_url="https://cdn.bootcdn.net/ajax/libs/swagger-ui/5.27.1/swagger-ui-bundle.js",
15
+ swagger_css_url="https://cdn.bootcdn.net/ajax/libs/swagger-ui/5.27.1/swagger-ui.css",
16
+ swagger_ui_parameters={"defaultModelsExpandDepth": -1},
17
+ )
18
+
19
+ @docs_router.get("/redoc", include_in_schema=False)
20
+ async def custom_redoc_html():
21
+ return get_redoc_html(
22
+ openapi_url=app.openapi_url,
23
+ title=f"{app.title}",
24
+ redoc_favicon_url="https://static.sytechnology.com/img/sylogopng.png",
25
+ redoc_js_url="https://cdn.bootcdn.net/ajax/libs/redoc/2.1.5/redoc.standalone.js",
26
+ )
27
+
28
+ app.include_router(docs_router)
29
+
30
+ return app
@@ -1,5 +1,6 @@
1
1
  from sycommon.health.ping import setup_ping_handler
2
2
  from sycommon.middleware.cors import setup_cors_handler
3
+ from sycommon.middleware.docs import setup_docs_handler
3
4
  from sycommon.middleware.exception import setup_exception_handler
4
5
  from sycommon.middleware.monitor_memory import setup_monitor_memory_middleware
5
6
  from sycommon.middleware.mq import setup_mq_middleware
@@ -36,4 +37,7 @@ class Middleware:
36
37
  # 添加mq中间件
37
38
  # app = setup_mq_middleware(app)
38
39
 
40
+ # doc
41
+ # app = setup_docs_handler(app)
42
+
39
43
  return app
@@ -78,13 +78,19 @@ def setup_trace_id_handler(app):
78
78
  response = await call_next(request)
79
79
 
80
80
  content_type = response.headers.get("Content-Type", "")
81
+
82
+ # 处理 SSE 响应 - 关键修复点
81
83
  if "text/event-stream" in content_type:
82
- # 处理 SSE 响应
84
+ # 流式响应不能有Content-Length,移除它
85
+ if "Content-Length" in response.headers:
86
+ del response.headers["Content-Length"]
83
87
  response.headers["x-traceId-header"] = trace_id
84
88
  return response
85
89
 
90
+ # 处理普通响应
86
91
  response_body = b""
87
92
  try:
93
+ # 收集所有响应块
88
94
  async for chunk in response.body_iterator:
89
95
  response_body += chunk
90
96
 
@@ -98,14 +104,36 @@ def setup_trace_id_handler(app):
98
104
  data["traceId"] = trace_id
99
105
  new_body = json.dumps(
100
106
  data, ensure_ascii=False).encode()
107
+
108
+ # 创建新响应,确保Content-Length正确
101
109
  response = Response(
102
110
  content=new_body,
103
111
  status_code=response.status_code,
104
- headers=dict(response.headers)
112
+ headers=dict(response.headers),
113
+ media_type=response.media_type
105
114
  )
115
+ # 显式设置正确的Content-Length
106
116
  response.headers["Content-Length"] = str(len(new_body))
107
117
  except json.JSONDecodeError:
108
- pass
118
+ # 如果不是JSON,恢复原始响应体并更新长度
119
+ response = Response(
120
+ content=response_body,
121
+ status_code=response.status_code,
122
+ headers=dict(response.headers),
123
+ media_type=response.media_type
124
+ )
125
+ response.headers["Content-Length"] = str(
126
+ len(response_body))
127
+ else:
128
+ # 非JSON响应,恢复原始响应体
129
+ response = Response(
130
+ content=response_body,
131
+ status_code=response.status_code,
132
+ headers=dict(response.headers),
133
+ media_type=response.media_type
134
+ )
135
+ response.headers["Content-Length"] = str(
136
+ len(response_body))
109
137
  except StopAsyncIteration:
110
138
  pass
111
139
 
@@ -129,7 +157,7 @@ def setup_trace_id_handler(app):
129
157
  "uploaded_files": files_info if files_info else None
130
158
  }
131
159
  error_message_str = json.dumps(error_message, ensure_ascii=False)
132
- SYLogger.error(error_message_str) # 无需显式传递 trace_id
160
+ SYLogger.error(error_message_str)
133
161
  raise
134
162
  finally:
135
163
  # 清理上下文变量,防止泄漏
@@ -3,14 +3,15 @@ from pydantic import BaseModel, Field
3
3
  from fastapi.responses import JSONResponse
4
4
  from fastapi import status
5
5
 
6
- # 修改泛型约束,支持任意类型(包括基础类型和BaseModel)
6
+ # 支持任意类型的泛型约束
7
7
  T = TypeVar('T')
8
8
 
9
9
 
10
10
  class BaseResponseModel(BaseModel, Generic[T]):
11
- """基础响应模型,支持多种数据类型(包括字符串、字典和Pydantic模型)"""
12
- code: int = Field(default=0, description="业务响应码,成功0,失败非0")
13
- message: str = Field(default="success", description="业务响应信息")
11
+ """基础响应模型,支持自定义状态码"""
12
+ code: int = Field(default=0, description="业务响应码,默认0成功,1失败,支持自定义")
13
+ message: str | None = Field(default=None, description="业务响应信息")
14
+ success: bool = Field(default=True, description="请求是否成功")
14
15
  data: T | None = Field(default=None, description="业务响应数据,支持任意类型")
15
16
  traceId: str | None = Field(default=None, description="请求链路追踪ID")
16
17
 
@@ -22,22 +23,22 @@ class BaseResponseModel(BaseModel, Generic[T]):
22
23
  def build_response_content(
23
24
  data: T | Any = None,
24
25
  code: int = 0,
25
- message: str = "success"
26
+ message: str = None
26
27
  ) -> dict:
27
28
  """
28
- 只构建响应内容的字典部分
29
+ 构建响应内容字典,自动根据code判断success
29
30
 
30
- Args:
31
- data: 响应数据(支持字符串、字典、Pydantic模型等)
32
- code: 业务响应码
33
- message: 响应信息
34
-
35
- Returns:
36
- 响应内容字典,格式为{"code": int, "message": str, "data": Any}
31
+ 规则:
32
+ - code为0时success=True(默认成功)
33
+ - 其他任何code值success=False(包括200等自定义状态码)
37
34
  """
35
+ # 成功状态仅当code为0时成立,其他任何code都视为失败
36
+ success = code == 0 or code == 200
37
+
38
38
  response = BaseResponseModel(
39
39
  code=code,
40
40
  message=message,
41
+ success=success,
41
42
  data=data
42
43
  )
43
44
 
@@ -45,6 +46,7 @@ def build_response_content(
45
46
  return {
46
47
  "code": response.code,
47
48
  "message": response.message,
49
+ "success": response.success,
48
50
  "data": response.data.model_dump()
49
51
  }
50
52
  else:
@@ -54,10 +56,10 @@ def build_response_content(
54
56
  def create_response(
55
57
  data: T | Any = None,
56
58
  code: int = 0,
57
- message: str = "success",
59
+ message: str = None,
58
60
  status_code: int = status.HTTP_200_OK
59
61
  ) -> JSONResponse:
60
- """创建完整的JSONResponse响应"""
62
+ """创建完整响应,支持自定义业务状态码"""
61
63
  content = build_response_content(data=data, code=code, message=message)
62
64
  return JSONResponse(
63
65
  content=content,
@@ -65,18 +67,18 @@ def create_response(
65
67
  )
66
68
 
67
69
 
68
- def success_response(data: T | Any = None, message: str = "success") -> JSONResponse:
69
- """快捷创建成功响应"""
70
- return create_response(data=data, message=message)
70
+ def success_response(data: T | Any = None, code: int = 0, message: str = None) -> JSONResponse:
71
+ """快捷创建成功响应(code=0, success=True)"""
72
+ return create_response(data=data, code=code, message=message)
71
73
 
72
74
 
73
75
  def error_response(
74
- message: str = "error",
76
+ message: str = None,
75
77
  code: int = 1,
76
78
  data: T | Any = None,
77
79
  status_code: int = status.HTTP_500_INTERNAL_SERVER_ERROR
78
80
  ) -> JSONResponse:
79
- """快捷创建错误响应"""
81
+ """快捷创建错误响应,支持自定义错误码(如200)"""
80
82
  return create_response(
81
83
  data=data,
82
84
  code=code,
@@ -85,15 +87,15 @@ def error_response(
85
87
  )
86
88
 
87
89
 
88
- def success_content(data: T | Any = None, message: str = "success") -> dict:
89
- """只构建成功响应的内容字典"""
90
- return build_response_content(data=data, message=message)
90
+ def success_content(data: T | Any = None) -> dict:
91
+ """构建成功响应内容字典"""
92
+ return build_response_content(data=data)
91
93
 
92
94
 
93
95
  def error_content(
94
- message: str = "error",
96
+ message: str = None,
95
97
  code: int = 1,
96
98
  data: T | Any = None
97
99
  ) -> dict:
98
- """只构建错误响应的内容字典"""
100
+ """构建错误响应内容字典,支持自定义错误码"""
99
101
  return build_response_content(data=data, code=code, message=message)