mcp-proxy-adapter 1.0.0__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.
- adapters/__init__.py +16 -0
- analyzers/__init__.py +14 -0
- analyzers/docstring_analyzer.py +199 -0
- analyzers/type_analyzer.py +151 -0
- cli/__init__.py +12 -0
- cli/__main__.py +79 -0
- cli/command_runner.py +233 -0
- dispatchers/__init__.py +14 -0
- dispatchers/base_dispatcher.py +85 -0
- dispatchers/json_rpc_dispatcher.py +198 -0
- generators/__init__.py +14 -0
- generators/endpoint_generator.py +172 -0
- generators/openapi_generator.py +254 -0
- generators/rest_api_generator.py +207 -0
- mcp_proxy_adapter-1.0.0.dist-info/METADATA +262 -0
- mcp_proxy_adapter-1.0.0.dist-info/RECORD +28 -0
- mcp_proxy_adapter-1.0.0.dist-info/WHEEL +5 -0
- mcp_proxy_adapter-1.0.0.dist-info/licenses/LICENSE +21 -0
- mcp_proxy_adapter-1.0.0.dist-info/top_level.txt +7 -0
- openapi_schema/__init__.py +38 -0
- openapi_schema/command_registry.py +312 -0
- openapi_schema/rest_schema.py +510 -0
- openapi_schema/rpc_generator.py +307 -0
- openapi_schema/rpc_schema.py +416 -0
- validators/__init__.py +14 -0
- validators/base_validator.py +23 -0
- validators/docstring_validator.py +75 -0
- validators/metadata_validator.py +76 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
"""
|
2
|
+
REST API endpoint generator based on registered commands.
|
3
|
+
"""
|
4
|
+
from typing import Any, Callable, Dict, List, Optional
|
5
|
+
import inspect
|
6
|
+
import asyncio
|
7
|
+
from fastapi import APIRouter, Depends, Request, HTTPException
|
8
|
+
from pydantic import BaseModel, create_model
|
9
|
+
|
10
|
+
class EndpointGenerator:
|
11
|
+
"""
|
12
|
+
REST API endpoint generator based on registered commands.
|
13
|
+
|
14
|
+
Creates dynamic FastAPI endpoints by automatically generating
|
15
|
+
request and response models based on signatures and docstrings
|
16
|
+
of registered handler functions.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def __init__(self, router: APIRouter, dispatcher: Any):
|
20
|
+
"""
|
21
|
+
Initialize endpoint generator.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
router: FastAPI router for registering endpoints
|
25
|
+
dispatcher: Command dispatcher providing access to registered commands
|
26
|
+
"""
|
27
|
+
self.router = router
|
28
|
+
self.dispatcher = dispatcher
|
29
|
+
self.registered_endpoints = []
|
30
|
+
|
31
|
+
def generate_endpoint(self, command_name: str, handler_func: Callable, metadata: Dict[str, Any]) -> None:
|
32
|
+
"""
|
33
|
+
Generates REST API endpoint for specified command.
|
34
|
+
|
35
|
+
Args:
|
36
|
+
command_name: Command name
|
37
|
+
handler_func: Command handler function
|
38
|
+
metadata: Command metadata from docstring
|
39
|
+
"""
|
40
|
+
# Get function signature
|
41
|
+
sig = inspect.signature(handler_func)
|
42
|
+
|
43
|
+
# Create request model based on function parameters
|
44
|
+
param_fields = {}
|
45
|
+
for name, param in sig.parameters.items():
|
46
|
+
# Skip self parameter
|
47
|
+
if name == 'self':
|
48
|
+
continue
|
49
|
+
|
50
|
+
# Get parameter type and default value
|
51
|
+
param_type = param.annotation if param.annotation != inspect.Parameter.empty else Any
|
52
|
+
default_value = ... if param.default == inspect.Parameter.empty else param.default
|
53
|
+
|
54
|
+
# Add field to model
|
55
|
+
param_fields[name] = (param_type, default_value)
|
56
|
+
|
57
|
+
# Create request model
|
58
|
+
request_model = create_model(
|
59
|
+
f"{command_name.capitalize()}Request",
|
60
|
+
**param_fields
|
61
|
+
)
|
62
|
+
|
63
|
+
# Create endpoint
|
64
|
+
endpoint_path = f"/{command_name}"
|
65
|
+
|
66
|
+
# Define endpoint handler
|
67
|
+
async def endpoint_handler(request_data: request_model):
|
68
|
+
# Call command through dispatcher
|
69
|
+
try:
|
70
|
+
# Get parameters from model
|
71
|
+
params = request_data.__dict__ if hasattr(request_data, "__dict__") else {}
|
72
|
+
|
73
|
+
# Call dispatcher's execute method
|
74
|
+
result = self.dispatcher.execute(command_name, **params)
|
75
|
+
|
76
|
+
# If result is coroutine, await its completion
|
77
|
+
if inspect.iscoroutine(result):
|
78
|
+
result = await result
|
79
|
+
|
80
|
+
return {"success": True, "result": result}
|
81
|
+
except Exception as e:
|
82
|
+
raise HTTPException(status_code=500, detail=str(e))
|
83
|
+
|
84
|
+
# Add documentation from metadata
|
85
|
+
if 'description' in metadata:
|
86
|
+
endpoint_handler.__doc__ = metadata['description']
|
87
|
+
|
88
|
+
# Register endpoint
|
89
|
+
self.router.post(endpoint_path, response_model=None)(endpoint_handler)
|
90
|
+
self.registered_endpoints.append(endpoint_path)
|
91
|
+
|
92
|
+
def generate_all_endpoints(self) -> List[str]:
|
93
|
+
"""
|
94
|
+
Generates endpoints for all registered commands.
|
95
|
+
|
96
|
+
Returns:
|
97
|
+
List[str]: List of created endpoints
|
98
|
+
"""
|
99
|
+
# Create endpoints for all commands
|
100
|
+
commands_info = self.dispatcher.get_commands_info()
|
101
|
+
|
102
|
+
for command_name, command_info in commands_info.items():
|
103
|
+
# Get command handler
|
104
|
+
handler = self.dispatcher._handlers[command_name] if hasattr(self.dispatcher, "_handlers") else None
|
105
|
+
|
106
|
+
# If handler couldn't be obtained, skip command
|
107
|
+
if not handler:
|
108
|
+
continue
|
109
|
+
|
110
|
+
self.generate_endpoint(
|
111
|
+
command_name,
|
112
|
+
handler,
|
113
|
+
command_info
|
114
|
+
)
|
115
|
+
|
116
|
+
# Create help endpoint
|
117
|
+
self.generate_help_endpoint()
|
118
|
+
|
119
|
+
return self.registered_endpoints
|
120
|
+
|
121
|
+
def generate_help_endpoint(self) -> None:
|
122
|
+
"""
|
123
|
+
Creates special /help endpoint that returns information
|
124
|
+
about all available commands and their endpoints.
|
125
|
+
"""
|
126
|
+
async def help_handler(command: Optional[str] = None):
|
127
|
+
if command:
|
128
|
+
# If specific command is specified, return information about it
|
129
|
+
command_info = self.dispatcher.get_command_info(command)
|
130
|
+
if not command_info:
|
131
|
+
return {
|
132
|
+
"success": False,
|
133
|
+
"error": f"Command '{command}' not found",
|
134
|
+
"available_commands": self.dispatcher.get_valid_commands()
|
135
|
+
}
|
136
|
+
|
137
|
+
# Add endpoint URL
|
138
|
+
endpoint_path = f"/{command}"
|
139
|
+
|
140
|
+
return {
|
141
|
+
"success": True,
|
142
|
+
"command": command,
|
143
|
+
"info": command_info,
|
144
|
+
"endpoint": endpoint_path
|
145
|
+
}
|
146
|
+
|
147
|
+
# Otherwise return information about all commands
|
148
|
+
commands_info = {}
|
149
|
+
for cmd in self.dispatcher.get_valid_commands():
|
150
|
+
info = self.dispatcher.get_command_info(cmd)
|
151
|
+
if not info:
|
152
|
+
continue
|
153
|
+
|
154
|
+
endpoint_path = f"/{cmd}"
|
155
|
+
commands_info[cmd] = {
|
156
|
+
"summary": info.get("summary", ""),
|
157
|
+
"description": info.get("description", ""),
|
158
|
+
"endpoint": endpoint_path,
|
159
|
+
"params_count": len(info.get("params", {}))
|
160
|
+
}
|
161
|
+
|
162
|
+
return {
|
163
|
+
"success": True,
|
164
|
+
"commands": commands_info,
|
165
|
+
"total": len(commands_info),
|
166
|
+
"endpoints": self.registered_endpoints,
|
167
|
+
"note": "Use 'command' parameter to get detailed information about a specific command"
|
168
|
+
}
|
169
|
+
|
170
|
+
help_handler.__doc__ = "Get list of all available commands and API endpoints"
|
171
|
+
self.router.get("/help", response_model=None)(help_handler)
|
172
|
+
self.registered_endpoints.append("/help")
|
@@ -0,0 +1,254 @@
|
|
1
|
+
"""
|
2
|
+
OpenAPI schema generator for API documentation based on registered commands.
|
3
|
+
"""
|
4
|
+
from typing import Any, Dict, List, Optional, Callable
|
5
|
+
import inspect
|
6
|
+
from pydantic import BaseModel, create_model
|
7
|
+
|
8
|
+
class OpenApiGenerator:
|
9
|
+
"""
|
10
|
+
OpenAPI schema generator for API documentation based on registered commands.
|
11
|
+
|
12
|
+
Creates OpenAPI schema describing all registered commands and their parameters
|
13
|
+
for use in automatic API documentation.
|
14
|
+
"""
|
15
|
+
|
16
|
+
def __init__(self, dispatcher: Any, title: str = "Vector Store API",
|
17
|
+
version: str = "1.0.0", description: str = "Vector Store API Documentation"):
|
18
|
+
"""
|
19
|
+
Initialize OpenAPI schema generator.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
dispatcher: Command dispatcher providing access to registered commands
|
23
|
+
title: API title
|
24
|
+
version: API version
|
25
|
+
description: API description
|
26
|
+
"""
|
27
|
+
self.dispatcher = dispatcher
|
28
|
+
self.title = title
|
29
|
+
self.version = version
|
30
|
+
self.description = description
|
31
|
+
|
32
|
+
def generate_schema(self) -> Dict[str, Any]:
|
33
|
+
"""
|
34
|
+
Generates complete OpenAPI schema for all registered commands.
|
35
|
+
|
36
|
+
Returns:
|
37
|
+
Dict[str, Any]: OpenAPI schema as dictionary
|
38
|
+
"""
|
39
|
+
# Base OpenAPI schema structure
|
40
|
+
schema = {
|
41
|
+
"openapi": "3.0.0",
|
42
|
+
"info": {
|
43
|
+
"title": self.title,
|
44
|
+
"version": self.version,
|
45
|
+
"description": self.description
|
46
|
+
},
|
47
|
+
"paths": {},
|
48
|
+
"components": {
|
49
|
+
"schemas": {}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
# Get all registered commands
|
54
|
+
commands = self.dispatcher.get_registered_commands()
|
55
|
+
|
56
|
+
# Generate schemas for each command
|
57
|
+
for command_name, command_data in commands.items():
|
58
|
+
handler_func = command_data['handler']
|
59
|
+
metadata = command_data.get('metadata', {})
|
60
|
+
|
61
|
+
# Add path for endpoint
|
62
|
+
path = f"/{command_name}"
|
63
|
+
method = "post" # By default all commands are handled via POST
|
64
|
+
|
65
|
+
# Get request schema
|
66
|
+
request_schema = self._generate_request_schema(command_name, handler_func)
|
67
|
+
|
68
|
+
# Add response schema
|
69
|
+
response_schema = self._generate_response_schema(command_name, handler_func, metadata)
|
70
|
+
|
71
|
+
# Add path to schema
|
72
|
+
schema["paths"][path] = {
|
73
|
+
method: {
|
74
|
+
"summary": metadata.get('summary', f"Execute {command_name} command"),
|
75
|
+
"description": metadata.get('description', ""),
|
76
|
+
"operationId": f"{command_name}",
|
77
|
+
"requestBody": {
|
78
|
+
"required": True,
|
79
|
+
"content": {
|
80
|
+
"application/json": {
|
81
|
+
"schema": request_schema
|
82
|
+
}
|
83
|
+
}
|
84
|
+
},
|
85
|
+
"responses": {
|
86
|
+
"200": {
|
87
|
+
"description": "Successful operation",
|
88
|
+
"content": {
|
89
|
+
"application/json": {
|
90
|
+
"schema": response_schema
|
91
|
+
}
|
92
|
+
}
|
93
|
+
},
|
94
|
+
"500": {
|
95
|
+
"description": "Internal server error",
|
96
|
+
"content": {
|
97
|
+
"application/json": {
|
98
|
+
"schema": {
|
99
|
+
"type": "object",
|
100
|
+
"properties": {
|
101
|
+
"success": {
|
102
|
+
"type": "boolean",
|
103
|
+
"example": False
|
104
|
+
},
|
105
|
+
"error": {
|
106
|
+
"type": "string"
|
107
|
+
}
|
108
|
+
}
|
109
|
+
}
|
110
|
+
}
|
111
|
+
}
|
112
|
+
}
|
113
|
+
}
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
# Add /help endpoint
|
118
|
+
schema["paths"]["/help"] = {
|
119
|
+
"get": {
|
120
|
+
"summary": "Get API help",
|
121
|
+
"description": "Get list of all available commands and API endpoints",
|
122
|
+
"operationId": "getHelp",
|
123
|
+
"responses": {
|
124
|
+
"200": {
|
125
|
+
"description": "Successful operation",
|
126
|
+
"content": {
|
127
|
+
"application/json": {
|
128
|
+
"schema": {
|
129
|
+
"type": "object",
|
130
|
+
"properties": {
|
131
|
+
"success": {
|
132
|
+
"type": "boolean",
|
133
|
+
"example": True
|
134
|
+
},
|
135
|
+
"registered_commands": {
|
136
|
+
"type": "object",
|
137
|
+
"additionalProperties": {
|
138
|
+
"type": "object",
|
139
|
+
"properties": {
|
140
|
+
"endpoint": {
|
141
|
+
"type": "string"
|
142
|
+
},
|
143
|
+
"description": {
|
144
|
+
"type": "string"
|
145
|
+
},
|
146
|
+
"parameters": {
|
147
|
+
"type": "object"
|
148
|
+
}
|
149
|
+
}
|
150
|
+
}
|
151
|
+
},
|
152
|
+
"endpoints": {
|
153
|
+
"type": "array",
|
154
|
+
"items": {
|
155
|
+
"type": "string"
|
156
|
+
}
|
157
|
+
}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}
|
165
|
+
}
|
166
|
+
|
167
|
+
return schema
|
168
|
+
|
169
|
+
def _generate_request_schema(self, command_name: str, handler_func: Callable) -> Dict[str, Any]:
|
170
|
+
"""
|
171
|
+
Generates request schema for specified command.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
command_name: Command name
|
175
|
+
handler_func: Command handler function
|
176
|
+
|
177
|
+
Returns:
|
178
|
+
Dict[str, Any]: Request schema in OpenAPI format
|
179
|
+
"""
|
180
|
+
# Get function signature
|
181
|
+
sig = inspect.signature(handler_func)
|
182
|
+
|
183
|
+
# Create request schema
|
184
|
+
properties = {}
|
185
|
+
required = []
|
186
|
+
|
187
|
+
for name, param in sig.parameters.items():
|
188
|
+
# Skip self parameter
|
189
|
+
if name == 'self':
|
190
|
+
continue
|
191
|
+
|
192
|
+
# Get parameter type
|
193
|
+
param_type = param.annotation if param.annotation != inspect.Parameter.empty else Any
|
194
|
+
|
195
|
+
# Determine type for OpenAPI
|
196
|
+
if param_type == str:
|
197
|
+
prop_type = {"type": "string"}
|
198
|
+
elif param_type == int:
|
199
|
+
prop_type = {"type": "integer"}
|
200
|
+
elif param_type == float:
|
201
|
+
prop_type = {"type": "number"}
|
202
|
+
elif param_type == bool:
|
203
|
+
prop_type = {"type": "boolean"}
|
204
|
+
elif param_type == list or param_type == List:
|
205
|
+
prop_type = {"type": "array", "items": {"type": "string"}}
|
206
|
+
elif param_type == dict or param_type == Dict:
|
207
|
+
prop_type = {"type": "object"}
|
208
|
+
else:
|
209
|
+
prop_type = {"type": "object"}
|
210
|
+
|
211
|
+
# Add property to schema
|
212
|
+
properties[name] = prop_type
|
213
|
+
|
214
|
+
# If parameter is required, add it to required list
|
215
|
+
if param.default == inspect.Parameter.empty:
|
216
|
+
required.append(name)
|
217
|
+
|
218
|
+
schema = {
|
219
|
+
"type": "object",
|
220
|
+
"properties": properties
|
221
|
+
}
|
222
|
+
|
223
|
+
if required:
|
224
|
+
schema["required"] = required
|
225
|
+
|
226
|
+
return schema
|
227
|
+
|
228
|
+
def _generate_response_schema(self, command_name: str, handler_func: Callable,
|
229
|
+
metadata: Dict[str, Any]) -> Dict[str, Any]:
|
230
|
+
"""
|
231
|
+
Generates response schema for specified command.
|
232
|
+
|
233
|
+
Args:
|
234
|
+
command_name: Command name
|
235
|
+
handler_func: Command handler function
|
236
|
+
metadata: Command metadata
|
237
|
+
|
238
|
+
Returns:
|
239
|
+
Dict[str, Any]: Response schema in OpenAPI format
|
240
|
+
"""
|
241
|
+
# Base response structure
|
242
|
+
return {
|
243
|
+
"type": "object",
|
244
|
+
"properties": {
|
245
|
+
"success": {
|
246
|
+
"type": "boolean",
|
247
|
+
"example": True
|
248
|
+
},
|
249
|
+
"result": {
|
250
|
+
"type": "object",
|
251
|
+
"description": metadata.get("returns", "Command result")
|
252
|
+
}
|
253
|
+
}
|
254
|
+
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
"""
|
2
|
+
Генератор REST API на основе команд и их метаданных.
|
3
|
+
"""
|
4
|
+
from typing import Dict, Any, Optional, List, Callable
|
5
|
+
import inspect
|
6
|
+
import logging
|
7
|
+
from command_registry.dispatchers.base_dispatcher import BaseDispatcher
|
8
|
+
|
9
|
+
logger = logging.getLogger("command_registry")
|
10
|
+
|
11
|
+
class RestApiGenerator:
|
12
|
+
"""
|
13
|
+
Генератор REST API для FastAPI на основе команд.
|
14
|
+
|
15
|
+
Этот класс создает REST эндпоинты для FastAPI на основе
|
16
|
+
зарегистрированных команд и их метаданных.
|
17
|
+
"""
|
18
|
+
|
19
|
+
def __init__(self, app, dispatcher: Optional[BaseDispatcher] = None, prefix: str = ""):
|
20
|
+
"""
|
21
|
+
Инициализирует генератор REST API.
|
22
|
+
|
23
|
+
Args:
|
24
|
+
app: Экземпляр FastAPI приложения
|
25
|
+
dispatcher: Диспетчер команд для доступа к метаданным
|
26
|
+
prefix: Префикс для всех эндпоинтов (например, "/api")
|
27
|
+
"""
|
28
|
+
self.app = app
|
29
|
+
self.dispatcher = dispatcher
|
30
|
+
self.prefix = prefix.rstrip("/")
|
31
|
+
|
32
|
+
# Словарь для хранения соответствия между командами и эндпоинтами
|
33
|
+
self._endpoints = {}
|
34
|
+
|
35
|
+
def set_dispatcher(self, dispatcher: BaseDispatcher) -> None:
|
36
|
+
"""
|
37
|
+
Устанавливает диспетчер команд.
|
38
|
+
|
39
|
+
Args:
|
40
|
+
dispatcher: Диспетчер команд
|
41
|
+
"""
|
42
|
+
self.dispatcher = dispatcher
|
43
|
+
|
44
|
+
def generate_endpoints(self) -> None:
|
45
|
+
"""
|
46
|
+
Генерирует REST эндпоинты для всех команд.
|
47
|
+
|
48
|
+
Создает эндпоинты для всех команд, зарегистрированных в диспетчере,
|
49
|
+
включая автоматический хелп-эндпоинт.
|
50
|
+
"""
|
51
|
+
if not self.dispatcher:
|
52
|
+
logger.warning("Диспетчер команд не установлен, невозможно сгенерировать эндпоинты")
|
53
|
+
return
|
54
|
+
|
55
|
+
# Получаем информацию о всех командах
|
56
|
+
commands_info = self.dispatcher.get_commands_info()
|
57
|
+
|
58
|
+
# Генерируем эндпоинты для каждой команды
|
59
|
+
for command, info in commands_info.items():
|
60
|
+
# Генерируем путь для эндпоинта
|
61
|
+
path = f"{self.prefix}/{command.replace('_', '-')}"
|
62
|
+
|
63
|
+
# Генерируем обработчик для эндпоинта
|
64
|
+
endpoint = self._create_endpoint_handler(command, info)
|
65
|
+
|
66
|
+
# Регистрируем эндпоинт в FastAPI
|
67
|
+
self.app.post(
|
68
|
+
path,
|
69
|
+
summary=info.get("summary", command),
|
70
|
+
description=info.get("description", ""),
|
71
|
+
tags=self._get_tags_for_command(command)
|
72
|
+
)(endpoint)
|
73
|
+
|
74
|
+
# Сохраняем соответствие между командой и эндпоинтом
|
75
|
+
self._endpoints[command] = path
|
76
|
+
|
77
|
+
logger.debug(f"Сгенерирован REST эндпоинт для команды '{command}': {path}")
|
78
|
+
|
79
|
+
# Генерируем хелп-эндпоинт
|
80
|
+
self._generate_help_endpoint()
|
81
|
+
|
82
|
+
def _create_endpoint_handler(self, command: str, info: Dict[str, Any]) -> Callable:
|
83
|
+
"""
|
84
|
+
Создает функцию-обработчик для эндпоинта.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
command: Имя команды
|
88
|
+
info: Метаданные команды
|
89
|
+
|
90
|
+
Returns:
|
91
|
+
Callable: Функция-обработчик для FastAPI
|
92
|
+
"""
|
93
|
+
dispatcher = self.dispatcher
|
94
|
+
|
95
|
+
# Создаем динамическую функцию-обработчик
|
96
|
+
async def endpoint(**kwargs):
|
97
|
+
try:
|
98
|
+
# Выполняем команду через диспетчер
|
99
|
+
result = dispatcher.execute(command, **kwargs)
|
100
|
+
|
101
|
+
# Если результат корутина, ожидаем его завершения
|
102
|
+
if inspect.iscoroutine(result):
|
103
|
+
result = await result
|
104
|
+
|
105
|
+
return result
|
106
|
+
except Exception as e:
|
107
|
+
# В случае ошибки возвращаем структурированный ответ с ошибкой
|
108
|
+
return {
|
109
|
+
"error": {
|
110
|
+
"message": str(e),
|
111
|
+
"code": 500
|
112
|
+
}
|
113
|
+
}
|
114
|
+
|
115
|
+
# Устанавливаем имя функции и докстринг
|
116
|
+
endpoint.__name__ = f"{command}_endpoint"
|
117
|
+
endpoint.__doc__ = info.get("description", "")
|
118
|
+
|
119
|
+
# Возвращаем функцию-обработчик
|
120
|
+
return endpoint
|
121
|
+
|
122
|
+
def _generate_help_endpoint(self) -> None:
|
123
|
+
"""
|
124
|
+
Генерирует хелп-эндпоинт для API.
|
125
|
+
|
126
|
+
Создает специальный эндпоинт /help, который возвращает информацию
|
127
|
+
о всех доступных командах и их эндпоинтах.
|
128
|
+
"""
|
129
|
+
app = self.app
|
130
|
+
dispatcher = self.dispatcher
|
131
|
+
endpoints = self._endpoints
|
132
|
+
|
133
|
+
# Путь для хелп-эндпоинта
|
134
|
+
help_path = f"{self.prefix}/help"
|
135
|
+
|
136
|
+
# Функция-обработчик для хелп-эндпоинта
|
137
|
+
async def help_endpoint(command: Optional[str] = None):
|
138
|
+
if command:
|
139
|
+
# Если указана конкретная команда, возвращаем информацию о ней
|
140
|
+
command_info = dispatcher.get_command_info(command)
|
141
|
+
if not command_info:
|
142
|
+
return {
|
143
|
+
"error": f"Команда '{command}' не найдена",
|
144
|
+
"available_commands": list(dispatcher.get_valid_commands())
|
145
|
+
}
|
146
|
+
|
147
|
+
# Добавляем URL эндпоинта
|
148
|
+
endpoint_url = endpoints.get(command)
|
149
|
+
if endpoint_url:
|
150
|
+
command_info["endpoint"] = endpoint_url
|
151
|
+
|
152
|
+
return {
|
153
|
+
"command": command,
|
154
|
+
"info": command_info
|
155
|
+
}
|
156
|
+
|
157
|
+
# Иначе возвращаем информацию о всех командах
|
158
|
+
commands_info = {}
|
159
|
+
for cmd, info in dispatcher.get_commands_info().items():
|
160
|
+
endpoint_url = endpoints.get(cmd)
|
161
|
+
commands_info[cmd] = {
|
162
|
+
"summary": info.get("summary", ""),
|
163
|
+
"description": info.get("description", ""),
|
164
|
+
"endpoint": endpoint_url,
|
165
|
+
"params_count": len(info.get("params", {}))
|
166
|
+
}
|
167
|
+
|
168
|
+
return {
|
169
|
+
"commands": commands_info,
|
170
|
+
"total": len(commands_info),
|
171
|
+
"base_url": self.prefix,
|
172
|
+
"note": "Для получения подробной информации о команде используйте параметр 'command'"
|
173
|
+
}
|
174
|
+
|
175
|
+
# Регистрируем хелп-эндпоинт в FastAPI
|
176
|
+
app.get(
|
177
|
+
help_path,
|
178
|
+
summary="API справка",
|
179
|
+
description="Возвращает информацию о доступных командах и эндпоинтах API",
|
180
|
+
tags=["help"]
|
181
|
+
)(help_endpoint)
|
182
|
+
|
183
|
+
logger.debug(f"Сгенерирован хелп-эндпоинт: {help_path}")
|
184
|
+
|
185
|
+
def _get_tags_for_command(self, command: str) -> List[str]:
|
186
|
+
"""
|
187
|
+
Определяет теги для команды.
|
188
|
+
|
189
|
+
Args:
|
190
|
+
command: Имя команды
|
191
|
+
|
192
|
+
Returns:
|
193
|
+
List[str]: Список тегов для документации OpenAPI
|
194
|
+
"""
|
195
|
+
# Простая эвристика для определения категории команды
|
196
|
+
if command.startswith(("get_", "search_", "find_", "list_")):
|
197
|
+
return ["query"]
|
198
|
+
elif command.startswith(("create_", "add_", "insert_")):
|
199
|
+
return ["mutation", "create"]
|
200
|
+
elif command.startswith(("update_", "change_", "modify_")):
|
201
|
+
return ["mutation", "update"]
|
202
|
+
elif command.startswith(("delete_", "remove_")):
|
203
|
+
return ["mutation", "delete"]
|
204
|
+
else:
|
205
|
+
# Используем первую часть имени команды в качестве тега
|
206
|
+
parts = command.split("_")
|
207
|
+
return [parts[0]] if parts else ["other"]
|