Skip to content

Commit 6229508

Browse files
committed
better openapi resolver
1 parent 0dc1fee commit 6229508

File tree

3 files changed

+90
-16
lines changed

3 files changed

+90
-16
lines changed

apps/agentfabric/server.py

+20-6
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,17 @@ def openapi_schema_parser(uuid_str):
569569
params_str = request.get_data(as_text=True)
570570
params = json.loads(params_str)
571571
openapi_schema = params.get('openapi_schema')
572+
host = openapi_schema.get('host', '')
573+
basePath = openapi_schema.get('basePath', '')
574+
if host and basePath:
575+
return make_response(
576+
jsonify({
577+
'success': False,
578+
'status': 429,
579+
'message': 'The Swagger 2.0 format is not support, '
580+
'please convert it to OpenAPI 3.0 format at https://petstore.swagger.io/',
581+
'request_id': request_id_var.get('')
582+
}), 429)
572583
try:
573584
if not isinstance(openapi_schema, dict):
574585
openapi_schema = json.loads(openapi_schema)
@@ -579,11 +590,14 @@ def openapi_schema_parser(uuid_str):
579590
f'OpenAPI schema format error, should be a valid json with error message: {e}'
580591
)
581592
if not openapi_schema:
582-
return jsonify({
583-
'success': False,
584-
'message': 'OpenAPI schema format error, should be valid json',
585-
'request_id': request_id_var.get('')
586-
})
593+
return make_response(
594+
jsonify({
595+
'success': False,
596+
'status': 429,
597+
'message':
598+
'OpenAPI schema format error, should be a valid json',
599+
'request_id': request_id_var.get('')
600+
}), 429)
587601
openapi_schema_instance = OpenapiServiceProxy(openapi=openapi_schema)
588602
import copy
589603
schema_info = copy.deepcopy(openapi_schema_instance.api_info_dict)
@@ -716,4 +730,4 @@ def handle_error(error):
716730

717731
if __name__ == '__main__':
718732
port = int(os.getenv('PORT', '5001'))
719-
app.run(host='0.0.0.0', port=5002, debug=False)
733+
app.run(host='0.0.0.0', port=port, debug=False)

modelscope_agent/tools/utils/openapi_utils.py

+69-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22

33
import requests
4-
from jsonschema import RefResolver
54

65

76
def execute_api_call(url: str, method: str, headers: dict, params: dict,
@@ -33,7 +32,7 @@ def parse_nested_parameters(param_name, param_info, parameters_list, content):
3332
param_type = param_info['type']
3433
param_description = param_info.get('description',
3534
f'用户输入的{param_name}') # 按需更改描述
36-
param_required = param_name in content['required']
35+
param_required = param_name in content.get('required', [])
3736
try:
3837
if param_type == 'object':
3938
properties = param_info.get('properties')
@@ -65,7 +64,7 @@ def parse_nested_parameters(param_name, param_info, parameters_list, content):
6564
'enum':
6665
inner_param_info.get('enum', ''),
6766
'in':
68-
'requestBody'
67+
'body'
6968
})
7069
else:
7170
# Non-nested parameters are added directly to the parameter list
@@ -75,7 +74,7 @@ def parse_nested_parameters(param_name, param_info, parameters_list, content):
7574
'required': param_required,
7675
'type': param_type,
7776
'enum': param_info.get('enum', ''),
78-
'in': 'requestBody'
77+
'in': 'body'
7978
})
8079
except Exception as e:
8180
raise ValueError(f'{e}:schema结构出错')
@@ -89,17 +88,75 @@ def extract_references(schema_content):
8988
references.append(schema_content['$ref'])
9089
for key, value in schema_content.items():
9190
references.extend(extract_references(value))
91+
# if properties exist, record the schema content in references and deal later
92+
if 'properties' in schema_content:
93+
references.append(schema_content)
9294
elif isinstance(schema_content, list):
9395
for item in schema_content:
9496
references.extend(extract_references(item))
9597
return references
9698

9799

100+
def swagger_to_openapi(swagger_data):
101+
openapi_data = {
102+
'openapi': '3.0.0',
103+
'info': swagger_data.get('info', {}),
104+
'paths': swagger_data.get('paths', {}),
105+
'components': {
106+
'schemas': swagger_data.get('definitions', {}),
107+
'securitySchemes': swagger_data.get('securityDefinitions', {})
108+
}
109+
}
110+
111+
# 转换基本信息
112+
if 'host' in swagger_data:
113+
openapi_data['servers'] = [{
114+
'url':
115+
f"https://{swagger_data['host']}{swagger_data.get('basePath', '')}"
116+
}]
117+
118+
# 转换路径
119+
for path, methods in openapi_data['paths'].items():
120+
for method, operation in methods.items():
121+
# 转换参数
122+
if 'parameters' in operation:
123+
new_parameters = []
124+
for param in operation['parameters']:
125+
if param.get('in') == 'body':
126+
if 'requestBody' not in operation:
127+
operation['requestBody'] = {'content': {}}
128+
operation['requestBody']['content'] = {
129+
'application/json': {
130+
'schema': param.get('schema', {})
131+
}
132+
}
133+
else:
134+
new_parameters.append(param)
135+
operation['parameters'] = new_parameters
136+
137+
# 转换响应
138+
if 'responses' in operation:
139+
for status, response in operation['responses'].items():
140+
if 'schema' in response:
141+
response['content'] = {
142+
'application/json': {
143+
'schema': response.pop('schema')
144+
}
145+
}
146+
147+
return openapi_data
148+
149+
98150
def openapi_schema_convert(schema: dict, auth: dict = {}):
99151
config_data = {}
152+
host = schema.get('host', '')
153+
if host:
154+
schema = swagger_to_openapi(schema)
155+
156+
schema = jsonref.replace_refs(schema)
100157

101-
resolver = RefResolver.from_schema(schema)
102158
servers = schema.get('servers', [])
159+
103160
if servers:
104161
servers_url = servers[0].get('url')
105162
else:
@@ -120,6 +177,10 @@ def openapi_schema_convert(schema: dict, auth: dict = {}):
120177
if isinstance(path_parameters, dict):
121178
path_parameters = [path_parameters]
122179
for path_parameter in path_parameters:
180+
if 'schema' in path_parameter:
181+
path_type = path_parameter['schema']['type']
182+
else:
183+
path_type = path_parameter['type']
123184
parameters_list.append({
124185
'name':
125186
path_parameter['name'],
@@ -130,7 +191,7 @@ def openapi_schema_convert(schema: dict, auth: dict = {}):
130191
'required':
131192
path_parameter.get('required', False),
132193
'type':
133-
path_parameter['schema']['type'],
194+
path_type,
134195
'enum':
135196
path_parameter.get('enum', '')
136197
})
@@ -160,13 +221,11 @@ def openapi_schema_convert(schema: dict, auth: dict = {}):
160221
schema_content = content_details.get('schema', {})
161222
references = extract_references(schema_content)
162223
for reference in references:
163-
resolved_schema = resolver.resolve(reference)
164-
content = resolved_schema[1]
165-
for param_name, param_info in content[
224+
for param_name, param_info in reference[
166225
'properties'].items():
167226
parse_nested_parameters(
168227
param_name, param_info, parameters_list,
169-
content)
228+
reference)
170229
X_DashScope_Async = requestBody.get(
171230
'X-DashScope-Async', '')
172231
if X_DashScope_Async == '':

requirements.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ faiss-cpu
33
grpcio
44
jieba
55
json5
6+
jsonref
67
jupyter>=1.0.0
78
langchain
89
langchain-community

0 commit comments

Comments
 (0)