mm-qa-mcp 1.0.0__tar.gz → 2.0.0__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.
- {mm_qa_mcp-1.0.0/mm_qa_mcp.egg-info → mm_qa_mcp-2.0.0}/PKG-INFO +1 -1
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/server.py +18 -1
- {mm_qa_mcp-1.0.0/minimax_qa_mcp/src/demo_langchain → mm_qa_mcp-2.0.0/minimax_qa_mcp/src/get_full_api_call_chain}/__init__.py +1 -1
- mm_qa_mcp-2.0.0/minimax_qa_mcp/src/get_full_api_call_chain/get_full_api_call_chain.py +291 -0
- mm_qa_mcp-2.0.0/minimax_qa_mcp/utils/mysql_op.py +175 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0/mm_qa_mcp.egg-info}/PKG-INFO +1 -1
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/mm_qa_mcp.egg-info/SOURCES.txt +3 -2
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/pyproject.toml +1 -1
- mm_qa_mcp-1.0.0/minimax_qa_mcp/src/demo_langchain/langchain_demo.py +0 -1
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/MANIFEST.in +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/README.md +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/conf/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/conf/conf.ini +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/gateway_case/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/gateway_case/get_case.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/generator_case/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/generator_case/generator_case.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/generator_case/generator_case_langchain.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/get_weaviate_info/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/get_weaviate_info/get_weaviate_info.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/grafana/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/grafana/service.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/query_segments/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/query_segments/query_segments.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/xmind2markdown/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/xmind2markdown/xmind_to_markdown.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/utils/__init__.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/utils/logger.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/utils/utils.py +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/mm_qa_mcp.egg-info/dependency_links.txt +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/mm_qa_mcp.egg-info/entry_points.txt +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/mm_qa_mcp.egg-info/requires.txt +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/mm_qa_mcp.egg-info/top_level.txt +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/setup.cfg +0 -0
- {mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/setup.py +0 -0
@@ -19,7 +19,7 @@ from minimax_qa_mcp.src.get_weaviate_info.get_weaviate_info import GetWeaviateIn
|
|
19
19
|
from minimax_qa_mcp.src.grafana.service import GetFromGrafana, GetApiFromGrafana
|
20
20
|
from minimax_qa_mcp.src.gateway_case.get_case import CaseGrafanaService
|
21
21
|
from minimax_qa_mcp.src.query_segments.query_segments import query_main, TYPE_API, TYPE_FUNC, TYPE_CODE, TYPE_ANY, TYPE_FUNC_DETAIL
|
22
|
-
|
22
|
+
from minimax_qa_mcp.src.get_full_api_call_chain.get_full_api_call_chain import GetFullApiCallChain
|
23
23
|
|
24
24
|
# Initialize FastMCP server
|
25
25
|
mcp = FastMCP("mcp")
|
@@ -162,6 +162,23 @@ async def get_weaviate_info(input_data: str) -> dict:
|
|
162
162
|
return result
|
163
163
|
|
164
164
|
|
165
|
+
@mcp.tool()
|
166
|
+
async def get_full_api_call_chain(api_path: str) -> dict:
|
167
|
+
"""
|
168
|
+
获取API调用链
|
169
|
+
Args:
|
170
|
+
api_path: str,API路径(demo:/weaver/api/v1/ugc/get_npc_list_by_user_id)
|
171
|
+
Return:
|
172
|
+
API调用链信息
|
173
|
+
"""
|
174
|
+
logger.info(f"===== The input params is :{api_path}")
|
175
|
+
|
176
|
+
api_call_chain = GetFullApiCallChain(api_path)
|
177
|
+
result = api_call_chain.get_full_call_chain()
|
178
|
+
logger.info(f"===== The result of get_full_api_call_chain is :{result}")
|
179
|
+
return result
|
180
|
+
|
181
|
+
|
165
182
|
def main():
|
166
183
|
print("Starting Minimax QA MCP server")
|
167
184
|
"""Run the Minimax QA MCP server"""
|
@@ -0,0 +1,291 @@
|
|
1
|
+
"""
|
2
|
+
coding:utf-8
|
3
|
+
@Software: PyCharm
|
4
|
+
@Time: 2025/6/8 14:37
|
5
|
+
@Author: xingyun
|
6
|
+
@description:
|
7
|
+
根据api_path 获取完整的API调用链
|
8
|
+
输入:api_path
|
9
|
+
输出:完整的API调用链(包括所有下游调用)
|
10
|
+
"""
|
11
|
+
|
12
|
+
|
13
|
+
from minimax_qa_mcp.utils.mysql_op import MysqlOp
|
14
|
+
from minimax_qa_mcp.utils.logger import logger
|
15
|
+
|
16
|
+
default_service = "weaver.gateway.weaver"
|
17
|
+
|
18
|
+
|
19
|
+
class GetFullApiCallChain:
|
20
|
+
def __init__(self, api_path):
|
21
|
+
"""
|
22
|
+
初始化调用链获取类
|
23
|
+
:param api_path: /path/to/endpoint (HTTP路径格式)
|
24
|
+
"""
|
25
|
+
self.api_path = api_path
|
26
|
+
self.mysql_op = MysqlOp()
|
27
|
+
# API路径,获取服务名和方法名
|
28
|
+
self.caller_service = default_service
|
29
|
+
self.caller_method = api_path
|
30
|
+
# 存储已访问的调用路径,避免循环调用
|
31
|
+
self.visited_paths = set()
|
32
|
+
# 存储最终的调用链结果
|
33
|
+
self.call_chain_results = []
|
34
|
+
|
35
|
+
def get_downstream_calls(self, service, method):
|
36
|
+
"""
|
37
|
+
获取指定服务和方法的所有下游调用
|
38
|
+
:param service: 服务名称
|
39
|
+
:param method: 方法名称
|
40
|
+
:return: 下游调用列表
|
41
|
+
"""
|
42
|
+
sql = """
|
43
|
+
SELECT caller_service, caller_method, callee_service, callee_method, call_type, code_chain
|
44
|
+
FROM qa_tools.code_call_chain
|
45
|
+
WHERE caller_service = %s AND caller_method = %s
|
46
|
+
"""
|
47
|
+
|
48
|
+
result = self.mysql_op.connect(sql_=sql, data=(service, method), op='select')
|
49
|
+
return result if result else []
|
50
|
+
|
51
|
+
def _build_call_path(self, call_record, level=0, path=None):
|
52
|
+
"""
|
53
|
+
递归构建调用路径
|
54
|
+
:param call_record: 当前调用记录
|
55
|
+
:param level: 当前调用层级
|
56
|
+
:param path: 当前已构建的路径
|
57
|
+
:return: 构建完成的调用路径
|
58
|
+
"""
|
59
|
+
caller_service = call_record[0]
|
60
|
+
caller_method = call_record[1]
|
61
|
+
callee_service = call_record[2]
|
62
|
+
callee_method = call_record[3]
|
63
|
+
call_type = call_record[4]
|
64
|
+
|
65
|
+
# 构建调用路径标识
|
66
|
+
call_id = f"{caller_service}.{caller_method} -> {callee_service}.{callee_method}"
|
67
|
+
|
68
|
+
# 检查是否已经访问过该路径,避免循环调用
|
69
|
+
if call_id in self.visited_paths:
|
70
|
+
return
|
71
|
+
|
72
|
+
self.visited_paths.add(call_id)
|
73
|
+
|
74
|
+
# 初始化路径
|
75
|
+
if path is None:
|
76
|
+
path = []
|
77
|
+
|
78
|
+
# 添加当前调用到路径
|
79
|
+
current_call = {
|
80
|
+
"level": level,
|
81
|
+
"caller_service": caller_service,
|
82
|
+
"caller_method": caller_method,
|
83
|
+
"callee_service": callee_service,
|
84
|
+
"callee_method": callee_method,
|
85
|
+
"call_type": call_type
|
86
|
+
}
|
87
|
+
|
88
|
+
path.append(current_call)
|
89
|
+
|
90
|
+
# 复制当前路径,添加到结果中
|
91
|
+
self.call_chain_results.append(path.copy())
|
92
|
+
|
93
|
+
# 递归获取下游调用
|
94
|
+
downstream_calls = self.get_downstream_calls(callee_service, callee_method)
|
95
|
+
for downstream_call in downstream_calls:
|
96
|
+
self._build_call_path(downstream_call, level + 1, path.copy())
|
97
|
+
|
98
|
+
def get_full_call_chain(self):
|
99
|
+
"""
|
100
|
+
获取完整的API调用链
|
101
|
+
:return: 字典,包含原始API信息和完整调用链
|
102
|
+
"""
|
103
|
+
# 先清空之前的结果
|
104
|
+
self.visited_paths = set()
|
105
|
+
self.call_chain_results = []
|
106
|
+
|
107
|
+
# 获取起始API的下游调用
|
108
|
+
downstream_calls = self.get_downstream_calls(self.caller_service, self.caller_method)
|
109
|
+
|
110
|
+
if not downstream_calls:
|
111
|
+
logger.info(f"未找到API {self.caller_service}.{self.caller_method} 的下游调用")
|
112
|
+
return {
|
113
|
+
"api_path": self.api_path,
|
114
|
+
"service": self.caller_service,
|
115
|
+
"method": self.caller_method,
|
116
|
+
"downstream_calls_count": 0,
|
117
|
+
"downstream_calls": [],
|
118
|
+
"call_tree": {},
|
119
|
+
"statistics": {
|
120
|
+
"total_calls": 0,
|
121
|
+
"max_depth": 0,
|
122
|
+
"service_count": 0,
|
123
|
+
"call_type_distribution": {}
|
124
|
+
}
|
125
|
+
}
|
126
|
+
|
127
|
+
# 构建每个下游调用的完整路径
|
128
|
+
for call in downstream_calls:
|
129
|
+
self._build_call_path(call)
|
130
|
+
|
131
|
+
# 构建树形结构
|
132
|
+
call_tree = self._build_call_tree()
|
133
|
+
|
134
|
+
# 计算统计信息
|
135
|
+
statistics = self._calculate_statistics()
|
136
|
+
|
137
|
+
# 格式化结果
|
138
|
+
formatted_results = []
|
139
|
+
for path in self.call_chain_results:
|
140
|
+
formatted_path = {
|
141
|
+
"path_length": len(path),
|
142
|
+
"calls": []
|
143
|
+
}
|
144
|
+
for call in path:
|
145
|
+
formatted_path["calls"].append({
|
146
|
+
"level": call["level"],
|
147
|
+
"caller": f"{call['caller_service']}.{call['caller_method']}",
|
148
|
+
"callee": f"{call['callee_service']}.{call['callee_method']}",
|
149
|
+
"call_type": call["call_type"],
|
150
|
+
"detail": f"{call['caller_service']}.{call['caller_method']} -> {call['callee_service']}.{call['callee_method']} ({call['call_type']})"
|
151
|
+
})
|
152
|
+
formatted_results.append(formatted_path)
|
153
|
+
|
154
|
+
return {
|
155
|
+
"api_path": self.api_path,
|
156
|
+
"service": self.caller_service,
|
157
|
+
"method": self.caller_method,
|
158
|
+
"downstream_calls_count": len(self.call_chain_results),
|
159
|
+
"downstream_calls": formatted_results,
|
160
|
+
"call_tree": call_tree,
|
161
|
+
"statistics": statistics
|
162
|
+
}
|
163
|
+
|
164
|
+
def _build_call_tree(self):
|
165
|
+
"""
|
166
|
+
构建调用树形结构
|
167
|
+
"""
|
168
|
+
tree = {}
|
169
|
+
|
170
|
+
for path in self.call_chain_results:
|
171
|
+
current_node = tree
|
172
|
+
for call in path:
|
173
|
+
key = f"{call['callee_service']}.{call['callee_method']}"
|
174
|
+
if key not in current_node:
|
175
|
+
current_node[key] = {
|
176
|
+
"service": call['callee_service'],
|
177
|
+
"method": call['callee_method'],
|
178
|
+
"call_type": call['call_type'],
|
179
|
+
"caller": f"{call['caller_service']}.{call['caller_method']}",
|
180
|
+
"children": {}
|
181
|
+
}
|
182
|
+
current_node = current_node[key]["children"]
|
183
|
+
|
184
|
+
return tree
|
185
|
+
|
186
|
+
def _calculate_statistics(self):
|
187
|
+
"""
|
188
|
+
计算调用链的统计信息
|
189
|
+
"""
|
190
|
+
# 统计各种信息
|
191
|
+
service_set = set()
|
192
|
+
call_type_count = {}
|
193
|
+
max_depth = 0
|
194
|
+
|
195
|
+
for path in self.call_chain_results:
|
196
|
+
# 更新最大深度
|
197
|
+
if len(path) > max_depth:
|
198
|
+
max_depth = len(path)
|
199
|
+
|
200
|
+
# 收集服务和调用类型
|
201
|
+
for call in path:
|
202
|
+
service_set.add(call['callee_service'])
|
203
|
+
call_type = call['call_type']
|
204
|
+
call_type_count[call_type] = call_type_count.get(call_type, 0) + 1
|
205
|
+
|
206
|
+
# 统计每个服务被调用的次数
|
207
|
+
service_call_count = {}
|
208
|
+
for path in self.call_chain_results:
|
209
|
+
for call in path:
|
210
|
+
service_key = f"{call['callee_service']}.{call['callee_method']}"
|
211
|
+
service_call_count[service_key] = service_call_count.get(service_key, 0) + 1
|
212
|
+
|
213
|
+
# 找出被调用最多的服务
|
214
|
+
top_called_services = sorted(service_call_count.items(), key=lambda x: x[1], reverse=True)[:5]
|
215
|
+
|
216
|
+
return {
|
217
|
+
"total_calls": len(self.call_chain_results),
|
218
|
+
"max_depth": max_depth,
|
219
|
+
"service_count": len(service_set),
|
220
|
+
"call_type_distribution": call_type_count,
|
221
|
+
"top_called_services": top_called_services
|
222
|
+
}
|
223
|
+
|
224
|
+
def print_call_chain(self):
|
225
|
+
"""
|
226
|
+
以可读性强的格式打印完整的调用链
|
227
|
+
"""
|
228
|
+
result = self.get_full_call_chain()
|
229
|
+
|
230
|
+
# 打印基本信息
|
231
|
+
print(f"\n{'=' * 100}")
|
232
|
+
print(f"📍 API调用链分析报告")
|
233
|
+
print(f"{'=' * 100}")
|
234
|
+
print(f"🔗 API路径: {result['api_path']}")
|
235
|
+
print(f"🏢 服务名: {result['service']}")
|
236
|
+
print(f"📋 方法名: {result['method']}")
|
237
|
+
print(f"\n{'=' * 100}")
|
238
|
+
|
239
|
+
# 打印统计信息
|
240
|
+
stats = result['statistics']
|
241
|
+
print(f"📊 统计信息:")
|
242
|
+
print(f" • 总调用链数: {stats['total_calls']}")
|
243
|
+
print(f" • 最大调用深度: {stats['max_depth']}")
|
244
|
+
print(f" • 涉及服务数量: {stats['service_count']}")
|
245
|
+
print(f" • 调用类型分布: {stats['call_type_distribution']}")
|
246
|
+
|
247
|
+
if stats.get('top_called_services'):
|
248
|
+
print(f"\n • 🔥 高频调用服务 TOP5:")
|
249
|
+
for service, count in stats['top_called_services']:
|
250
|
+
print(f" - {service} (被调用 {count} 次)")
|
251
|
+
|
252
|
+
print(f"\n{'=' * 100}")
|
253
|
+
|
254
|
+
if result.get('downstream_calls_count', 0) == 0:
|
255
|
+
print("❌ 没有找到下游调用")
|
256
|
+
print(f"{'=' * 100}\n")
|
257
|
+
return result
|
258
|
+
|
259
|
+
# 打印树形结构
|
260
|
+
print("🌳 调用树形结构:")
|
261
|
+
print(f"{'-' * 100}")
|
262
|
+
self._print_tree(result['call_tree'], indent=0)
|
263
|
+
|
264
|
+
return result
|
265
|
+
|
266
|
+
def _print_tree(self, tree, indent=0, prefix=""):
|
267
|
+
"""
|
268
|
+
递归打印树形结构
|
269
|
+
"""
|
270
|
+
items = list(tree.items())
|
271
|
+
for i, (key, node) in enumerate(items):
|
272
|
+
is_last = i == len(items) - 1
|
273
|
+
|
274
|
+
# 打印当前节点
|
275
|
+
connector = "└── " if is_last else "├── "
|
276
|
+
type_symbol = {"HTTP": "🌐", "RPC": "⚡", "LOCAL": "🏠"}.get(node['call_type'], "📡")
|
277
|
+
print(f"{prefix}{connector}{type_symbol} {key}")
|
278
|
+
|
279
|
+
# 打印子节点
|
280
|
+
if node['children']:
|
281
|
+
extension = " " if is_last else "│ "
|
282
|
+
self._print_tree(node['children'], indent + 1, prefix + extension)
|
283
|
+
|
284
|
+
|
285
|
+
if __name__ == '__main__':
|
286
|
+
# 使用示例 - HTTP路径格式
|
287
|
+
api_path_ = "/weaver/api/v1/ugc/get_npc_list_by_user_id"
|
288
|
+
call_chain = GetFullApiCallChain(api_path_)
|
289
|
+
result = call_chain.print_call_chain()
|
290
|
+
print("结果:")
|
291
|
+
print(result)
|
@@ -0,0 +1,175 @@
|
|
1
|
+
"""
|
2
|
+
coding:utf-8
|
3
|
+
@Software: PyCharm
|
4
|
+
@Time: 2024/6/4 下午5:48
|
5
|
+
@Author: xingyun
|
6
|
+
"""
|
7
|
+
|
8
|
+
import pymysql
|
9
|
+
|
10
|
+
from minimax_qa_mcp.utils.logger import logger
|
11
|
+
|
12
|
+
|
13
|
+
class MysqlOp(object):
|
14
|
+
def __init__(self):
|
15
|
+
self.password = "ngo0nZYnPvpoke7P"
|
16
|
+
self.host = "10.11.24.40"
|
17
|
+
self.database = "qa_tools"
|
18
|
+
self.user = "qa_test"
|
19
|
+
self.port = 3306
|
20
|
+
|
21
|
+
def connect(self, sql_, data=None, op=None):
|
22
|
+
# 连接到MySQL数据库
|
23
|
+
conn = pymysql.connect(host=self.host,
|
24
|
+
user=self.user,
|
25
|
+
password=self.password,
|
26
|
+
db=self.database,
|
27
|
+
port=self.port)
|
28
|
+
|
29
|
+
# 创建Cursor对象
|
30
|
+
try:
|
31
|
+
with conn.cursor() as cursor:
|
32
|
+
if op == 'insert':
|
33
|
+
cursor.execute(sql_, data)
|
34
|
+
conn.commit()
|
35
|
+
# 插入成功后,可以获取插入数据的ID(如果表有自增主键)
|
36
|
+
last_id = cursor.lastrowid
|
37
|
+
logger.info(f"Last inserted record ID is {last_id}")
|
38
|
+
return last_id
|
39
|
+
elif op == 'select':
|
40
|
+
cursor.execute(sql_, data)
|
41
|
+
# 获取查询结果
|
42
|
+
results = cursor.fetchall()
|
43
|
+
# 打印结果
|
44
|
+
for row in results:
|
45
|
+
logger.info(row)
|
46
|
+
return results
|
47
|
+
elif op == 'delete':
|
48
|
+
cursor.execute(sql_, data)
|
49
|
+
# 提交到数据库执行
|
50
|
+
conn.commit()
|
51
|
+
logger.info("记录已成功删除。")
|
52
|
+
elif op == 'update':
|
53
|
+
cursor.execute(sql_, data)
|
54
|
+
# 提交到数据库执行
|
55
|
+
conn.commit()
|
56
|
+
logger.info("数据更新成功!")
|
57
|
+
# 获取更新的行数
|
58
|
+
affected_rows = cursor.rowcount
|
59
|
+
logger.info(f"Number of rows affected: {affected_rows}")
|
60
|
+
return affected_rows
|
61
|
+
|
62
|
+
except pymysql.MySQLError as e:
|
63
|
+
# 如果发生错误,打印错误信息
|
64
|
+
logger.info(f"Error: {e}")
|
65
|
+
finally:
|
66
|
+
# 关闭Cursor和Connection
|
67
|
+
conn.close()
|
68
|
+
|
69
|
+
def batch_insert(self, sql_, batch_data):
|
70
|
+
"""
|
71
|
+
批量插入数据到MySQL数据库
|
72
|
+
:param sql_: 带有占位符的SQL插入语句
|
73
|
+
:param batch_data: 包含多组参数的列表,每组参数对应一条记录
|
74
|
+
:return: 成功插入的记录数
|
75
|
+
"""
|
76
|
+
if not batch_data:
|
77
|
+
logger.info("批量插入数据为空,跳过")
|
78
|
+
return 0
|
79
|
+
|
80
|
+
# 连接到MySQL数据库
|
81
|
+
conn = pymysql.connect(host=self.host,
|
82
|
+
user=self.user,
|
83
|
+
password=self.password,
|
84
|
+
db=self.database,
|
85
|
+
port=self.port)
|
86
|
+
|
87
|
+
success_count = 0
|
88
|
+
try:
|
89
|
+
with conn.cursor() as cursor:
|
90
|
+
# 执行批量插入
|
91
|
+
success_count = cursor.executemany(sql_, batch_data)
|
92
|
+
conn.commit()
|
93
|
+
logger.info(f"成功批量插入 {success_count} 条记录")
|
94
|
+
return success_count
|
95
|
+
except pymysql.MySQLError as e:
|
96
|
+
# 如果发生错误,回滚事务并打印错误信息
|
97
|
+
conn.rollback()
|
98
|
+
logger.info(f"批量插入错误: {e}")
|
99
|
+
return 0
|
100
|
+
finally:
|
101
|
+
# 关闭连接
|
102
|
+
conn.close()
|
103
|
+
|
104
|
+
def batch_update(self, sql_, batch_data):
|
105
|
+
"""
|
106
|
+
批量更新MySQL数据库中的记录
|
107
|
+
:param sql_: 带有占位符的SQL更新语句
|
108
|
+
:param batch_data: 包含多组参数的列表,每组参数对应一条记录
|
109
|
+
:return: 成功更新的记录数
|
110
|
+
"""
|
111
|
+
if not batch_data:
|
112
|
+
logger.info("批量更新数据为空,跳过")
|
113
|
+
return 0
|
114
|
+
|
115
|
+
# 连接到MySQL数据库
|
116
|
+
conn = pymysql.connect(host=self.host,
|
117
|
+
user=self.user,
|
118
|
+
password=self.password,
|
119
|
+
db=self.database,
|
120
|
+
port=self.port)
|
121
|
+
|
122
|
+
success_count = 0
|
123
|
+
try:
|
124
|
+
with conn.cursor() as cursor:
|
125
|
+
# 执行批量更新
|
126
|
+
success_count = cursor.executemany(sql_, batch_data)
|
127
|
+
conn.commit()
|
128
|
+
logger.info(f"成功批量更新 {success_count} 条记录")
|
129
|
+
return success_count
|
130
|
+
except pymysql.MySQLError as e:
|
131
|
+
# 如果发生错误,回滚事务并打印错误信息
|
132
|
+
conn.rollback()
|
133
|
+
logger.info(f"批量更新错误: {e}")
|
134
|
+
return 0
|
135
|
+
finally:
|
136
|
+
# 关闭连接
|
137
|
+
conn.close()
|
138
|
+
|
139
|
+
|
140
|
+
if __name__ == '__main__':
|
141
|
+
# group_id = '112233445566'
|
142
|
+
# bank_account_no = 'test_1234'
|
143
|
+
# card_num = 'test_card_num'
|
144
|
+
# redis_key = 'cred_group_id_data'
|
145
|
+
# ping_an_resp = 'xxx'
|
146
|
+
# time_stamp = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
147
|
+
# mysql_op = MysqlOp('qa_db')
|
148
|
+
# # sql_ = 'insert into pingan_un_bank_info (group_id, bank_account_no, card_num, redis_key, pingan_url_resp, creat_time, delete_time) values (%s, %s, %s, %s, %s, %s, %s)'
|
149
|
+
# # mysql_op.connect(sql_=sql_, data=(group_id, bank_account_no, card_num, redis_key, ping_an_resp, time_stamp, time_stamp), op='insert')
|
150
|
+
# update_sql = 'update pingan_un_bank_info set pingan_url_resp = %s where group_id = %s'
|
151
|
+
# mysql_op.connect(sql_=update_sql, data=('test_resp sxxxxxxxxxxxxxx', '112233445566'), op='update')
|
152
|
+
|
153
|
+
# operator_ = 'xingyun1'
|
154
|
+
# psm_ = 'open_platform'
|
155
|
+
# task_name_ = '开放平台线上环境巡检'
|
156
|
+
# job_id = '20240612124204'
|
157
|
+
# report_url_ = ''
|
158
|
+
# report_tos_key_ = 'qa-tool-1315599187/swingReport/20240604/swing_report_20240604_123456.zip'
|
159
|
+
# status_ = True
|
160
|
+
# create_time_ = str(datetime.now())
|
161
|
+
# env_ = 'prod'
|
162
|
+
# sql = 'insert into swing_report (operator, psm, task_name, task_id, report_tos_key, status, create_time, env, job_id) values (%s, %s, %s, %s, %s, %s, %s, %s, %s)'
|
163
|
+
# MysqlOp().connect(sql, data=(operator_, psm_, task_name_, task_id_, report_tos_key_, status_, create_time_, env_, job_id), op='insert')
|
164
|
+
# sql = 'select * from swing_report limit 10'
|
165
|
+
# sql = 'select * from user_group limit 10'
|
166
|
+
# # # sql = 'delete from swing_report where operator = %s'
|
167
|
+
# # mys = MysqlOp('kaiping_usercore_online_db')
|
168
|
+
# mys.connect(sql_=sql, data=None, op='select')
|
169
|
+
# sql = 'update swing_report set status = %s where id = %s'
|
170
|
+
# mys.connect(sql_=sql, data=('2', 1), op='update')
|
171
|
+
sql = "select * from qa_tools.api_meta where psm_name = %s"
|
172
|
+
mysql_op = MysqlOp()
|
173
|
+
result = mysql_op.connect(sql, data=('weaver.conversation.biz',), op='select')
|
174
|
+
print(result)
|
175
|
+
|
@@ -7,13 +7,13 @@ minimax_qa_mcp/server.py
|
|
7
7
|
minimax_qa_mcp/conf/__init__.py
|
8
8
|
minimax_qa_mcp/conf/conf.ini
|
9
9
|
minimax_qa_mcp/src/__init__.py
|
10
|
-
minimax_qa_mcp/src/demo_langchain/__init__.py
|
11
|
-
minimax_qa_mcp/src/demo_langchain/langchain_demo.py
|
12
10
|
minimax_qa_mcp/src/gateway_case/__init__.py
|
13
11
|
minimax_qa_mcp/src/gateway_case/get_case.py
|
14
12
|
minimax_qa_mcp/src/generator_case/__init__.py
|
15
13
|
minimax_qa_mcp/src/generator_case/generator_case.py
|
16
14
|
minimax_qa_mcp/src/generator_case/generator_case_langchain.py
|
15
|
+
minimax_qa_mcp/src/get_full_api_call_chain/__init__.py
|
16
|
+
minimax_qa_mcp/src/get_full_api_call_chain/get_full_api_call_chain.py
|
17
17
|
minimax_qa_mcp/src/get_weaviate_info/__init__.py
|
18
18
|
minimax_qa_mcp/src/get_weaviate_info/get_weaviate_info.py
|
19
19
|
minimax_qa_mcp/src/grafana/__init__.py
|
@@ -24,6 +24,7 @@ minimax_qa_mcp/src/xmind2markdown/__init__.py
|
|
24
24
|
minimax_qa_mcp/src/xmind2markdown/xmind_to_markdown.py
|
25
25
|
minimax_qa_mcp/utils/__init__.py
|
26
26
|
minimax_qa_mcp/utils/logger.py
|
27
|
+
minimax_qa_mcp/utils/mysql_op.py
|
27
28
|
minimax_qa_mcp/utils/utils.py
|
28
29
|
mm_qa_mcp.egg-info/PKG-INFO
|
29
30
|
mm_qa_mcp.egg-info/SOURCES.txt
|
@@ -1 +0,0 @@
|
|
1
|
-
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/generator_case/generator_case_langchain.py
RENAMED
File without changes
|
File without changes
|
{mm_qa_mcp-1.0.0 → mm_qa_mcp-2.0.0}/minimax_qa_mcp/src/get_weaviate_info/get_weaviate_info.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|