MCP Development Framework
by aigo666
{
"sourceFile": "mcp_tool/tools/llm_tool.py",
"activeCommit": 0,
"commits": [
{
"activePatchIndex": 7,
"patches": [
{
"date": 1741527987944,
"content": "Index: \n===================================================================\n--- \n+++ \n"
},
{
"date": 1741528008639,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -47,45 +47,41 @@\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n- 分析文档内容\n+ 分析文档内容或回答问题\n \n Args:\n- arguments: 参数字典,必须包含'file_path'和'question'键\n+ arguments: 参数字典,必须包含'question'键,可选包含'file_path'和'model'键\n \n Returns:\n- 分析结果\n+ 分析结果或回答\n \"\"\"\n # 参数验证\n- if \"file_path\" not in arguments:\n- return [types.TextContent(\n- type=\"text\",\n- text=\"错误: 缺少必要参数 'file_path'\"\n- )]\n- \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n- file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n- # 检查文件是否存在\n- if not os.path.exists(file_path):\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n- )]\n- \n- try:\n+ # 检查是否提供了文件路径\n+ if \"file_path\" in arguments and arguments[\"file_path\"]:\n+ file_path = arguments[\"file_path\"]\n+ # 检查文件是否存在(如果是本地文件)\n+ is_url = file_path.startswith(('http://', 'https://'))\n+ if not is_url and not os.path.exists(file_path):\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n+ )]\n+ \n # 添加处理信息\n results = [types.TextContent(\n type=\"text\",\n- text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n+ text=f\"# 文档分析\\n\\n正在分析{'远程文件' if is_url else '文件'}: {os.path.basename(file_path) if not is_url else file_path}\\n问题: {question}\\n\\n请稍候...\"\n )]\n \n # 调用外部API分析文档\n analysis_result = await self._analyze_document(file_path, question, model)\n@@ -96,15 +92,25 @@\n text=f\"## 分析结果\\n\\n{analysis_result}\"\n ))\n \n return results\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n- return [types.TextContent(\n+ else:\n+ # 直接提问模式,不涉及文档\n+ results = [types.TextContent(\n type=\"text\",\n- text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ text=f\"# 问答\\n\\n问题: {question}\\n\\n请稍候...\"\n )]\n+ \n+ # 调用外部API回答问题\n+ answer = await self._ask_question(question, model)\n+ \n+ # 添加回答结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 回答\\n\\n{answer}\"\n+ ))\n+ \n+ return results\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n"
},
{
"date": 1741528034034,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -201,5 +201,72 @@\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n+ return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n+\n+ async def _ask_question(self, question: str, model: str) -> str:\n+ \"\"\"\n+ 调用外部API直接回答问题\n+ \n+ Args:\n+ question: 问题\n+ model: 模型名称\n+ \n+ Returns:\n+ 回答结果\n+ \"\"\"\n+ try:\n+ # 使用requests库直接发送请求\n+ url = f\"{self.BASE_URL}/v1/chat/completions\"\n+ \n+ # 构建请求数据\n+ payload = {\n+ \"model\": model,\n+ \"messages\": [\n+ {\n+ \"role\": \"user\",\n+ \"content\": question\n+ }\n+ ],\n+ \"stream\": False\n+ }\n+ \n+ # 设置请求头\n+ headers = {\n+ 'Accept': 'application/json',\n+ 'Authorization': f'Bearer {self.API_KEY}',\n+ 'Content-Type': 'application/json'\n+ }\n+ \n+ # 发送请求\n+ response = requests.post(url, json=payload, headers=headers, timeout=60)\n+ \n+ # 检查响应状态码\n+ if response.status_code != 200:\n+ try:\n+ error_data = response.json()\n+ error_message = error_data.get(\"message\", \"未知错误\")\n+ return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n+ except:\n+ return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n+ \n+ # 解析响应\n+ try:\n+ response_data = response.json()\n+ except json.JSONDecodeError:\n+ return f\"无法解析API响应: {response.text[:200]}...\"\n+ \n+ # 提取回答结果\n+ if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n+ message = response_data[\"choices\"][0].get(\"message\", {})\n+ content = message.get(\"content\", \"未能获取回答\")\n+ return content\n+ else:\n+ return f\"未能获取回答,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n+ \n+ except requests.exceptions.RequestException as e:\n+ return f\"API请求错误: {str(e)}\"\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n\\ No newline at end of file\n"
},
{
"date": 1741528083240,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,6 +1,6 @@\n \"\"\"\n-大语言模型交互工具,使用外部大模型API分析文档内容或回答问题\n+文档分析工具,使用外部大模型API分析文档内容\n \"\"\"\n \n import os\n import json\n@@ -14,26 +14,26 @@\n import mcp.types as types\n from . import BaseTool, ToolRegistry\n \n @ToolRegistry.register\n-class LLMTool(BaseTool):\n+class DocAnalysisTool(BaseTool):\n \"\"\"\n- 大语言模型交互工具,使用外部大模型API分析文档内容或回答问题\n+ 文档分析工具,使用外部大模型API分析文档内容\n \"\"\"\n \n name = \"llm\"\n description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n- \"required\": [\"question\"],\n+ \"required\": [\"file_path\", \"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n },\n \"question\": {\n \"type\": \"string\",\n- \"description\": \"关于文档的问题或直接提问,例如'文档里说了什么?'或'什么是人工智能?'\",\n+ \"description\": \"关于文档的问题,例如'文档里说了什么?'\",\n },\n \"model\": {\n \"type\": \"string\",\n \"description\": \"使用的模型名称,默认为'glm-4'\",\n@@ -47,41 +47,45 @@\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n- 分析文档内容或回答问题\n+ 分析文档内容\n \n Args:\n- arguments: 参数字典,必须包含'question'键,可选包含'file_path'和'model'键\n+ arguments: 参数字典,必须包含'file_path'和'question'键\n \n Returns:\n- 分析结果或回答\n+ 分析结果\n \"\"\"\n # 参数验证\n+ if \"file_path\" not in arguments:\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=\"错误: 缺少必要参数 'file_path'\"\n+ )]\n+ \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n+ file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n- # 检查是否提供了文件路径\n- if \"file_path\" in arguments and arguments[\"file_path\"]:\n- file_path = arguments[\"file_path\"]\n- # 检查文件是否存在(如果是本地文件)\n- is_url = file_path.startswith(('http://', 'https://'))\n- if not is_url and not os.path.exists(file_path):\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n- )]\n- \n+ # 检查文件是否存在\n+ if not os.path.exists(file_path):\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n+ )]\n+ \n+ try:\n # 添加处理信息\n results = [types.TextContent(\n type=\"text\",\n- text=f\"# 文档分析\\n\\n正在分析{'远程文件' if is_url else '文件'}: {os.path.basename(file_path) if not is_url else file_path}\\n问题: {question}\\n\\n请稍候...\"\n+ text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n )]\n \n # 调用外部API分析文档\n analysis_result = await self._analyze_document(file_path, question, model)\n@@ -92,25 +96,15 @@\n text=f\"## 分析结果\\n\\n{analysis_result}\"\n ))\n \n return results\n- else:\n- # 直接提问模式,不涉及文档\n- results = [types.TextContent(\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n type=\"text\",\n- text=f\"# 问答\\n\\n问题: {question}\\n\\n请稍候...\"\n+ text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n )]\n- \n- # 调用外部API回答问题\n- answer = await self._ask_question(question, model)\n- \n- # 添加回答结果\n- results.append(types.TextContent(\n- type=\"text\",\n- text=f\"## 回答\\n\\n{answer}\"\n- ))\n- \n- return results\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n@@ -201,72 +195,5 @@\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n- return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n-\n- async def _ask_question(self, question: str, model: str) -> str:\n- \"\"\"\n- 调用外部API直接回答问题\n- \n- Args:\n- question: 问题\n- model: 模型名称\n- \n- Returns:\n- 回答结果\n- \"\"\"\n- try:\n- # 使用requests库直接发送请求\n- url = f\"{self.BASE_URL}/v1/chat/completions\"\n- \n- # 构建请求数据\n- payload = {\n- \"model\": model,\n- \"messages\": [\n- {\n- \"role\": \"user\",\n- \"content\": question\n- }\n- ],\n- \"stream\": False\n- }\n- \n- # 设置请求头\n- headers = {\n- 'Accept': 'application/json',\n- 'Authorization': f'Bearer {self.API_KEY}',\n- 'Content-Type': 'application/json'\n- }\n- \n- # 发送请求\n- response = requests.post(url, json=payload, headers=headers, timeout=60)\n- \n- # 检查响应状态码\n- if response.status_code != 200:\n- try:\n- error_data = response.json()\n- error_message = error_data.get(\"message\", \"未知错误\")\n- return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n- except:\n- return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n- \n- # 解析响应\n- try:\n- response_data = response.json()\n- except json.JSONDecodeError:\n- return f\"无法解析API响应: {response.text[:200]}...\"\n- \n- # 提取回答结果\n- if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n- message = response_data[\"choices\"][0].get(\"message\", {})\n- content = message.get(\"content\", \"未能获取回答\")\n- return content\n- else:\n- return f\"未能获取回答,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n- \n- except requests.exceptions.RequestException as e:\n- return f\"API请求错误: {str(e)}\"\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n\\ No newline at end of file\n"
},
{
"date": 1741528567167,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -47,64 +47,89 @@\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n- 分析文档内容\n+ 分析文档内容或回答问题\n \n Args:\n- arguments: 参数字典,必须包含'file_path'和'question'键\n+ arguments: 参数字典,可以包含'file_path'和'question'键\n \n Returns:\n 分析结果\n \"\"\"\n # 参数验证\n- if \"file_path\" not in arguments:\n- return [types.TextContent(\n- type=\"text\",\n- text=\"错误: 缺少必要参数 'file_path'\"\n- )]\n- \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n- file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n- # 检查文件是否存在\n- if not os.path.exists(file_path):\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n- )]\n- \n- try:\n- # 添加处理信息\n- results = [types.TextContent(\n- type=\"text\",\n- text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n- )]\n+ # 检查是否提供了文件路径\n+ if \"file_path\" in arguments:\n+ file_path = arguments[\"file_path\"]\n+ # 检查文件路径是否是URL\n+ is_url = file_path.startswith(('http://', 'https://'))\n \n- # 调用外部API分析文档\n- analysis_result = await self._analyze_document(file_path, question, model)\n+ # 如果不是URL,检查文件是否存在\n+ if not is_url and not os.path.exists(file_path):\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\\n如果使用Docker,请确保文件路径在容器内可访问,例如使用挂载的目录。\"\n+ )]\n \n- # 添加分析结果\n- results.append(types.TextContent(\n- type=\"text\",\n- text=f\"## 分析结果\\n\\n{analysis_result}\"\n- ))\n- \n- return results\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n- )]\n+ try:\n+ # 添加处理信息\n+ results = [types.TextContent(\n+ type=\"text\",\n+ text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path) if not is_url else file_path}\\n问题: {question}\\n\\n请稍候...\"\n+ )]\n+ \n+ # 调用外部API分析文档\n+ analysis_result = await self._analyze_document(file_path, question, model)\n+ \n+ # 添加分析结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 分析结果\\n\\n{analysis_result}\"\n+ ))\n+ \n+ return results\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ )]\n+ else:\n+ # 直接回答问题,不分析文档\n+ try:\n+ # 添加处理信息\n+ results = [types.TextContent(\n+ type=\"text\",\n+ text=f\"# 问题\\n\\n{question}\\n\\n请稍候...\"\n+ )]\n+ \n+ # 调用外部API回答问题\n+ answer = await self._ask_question(question, model)\n+ \n+ # 添加回答结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 回答\\n\\n{answer}\"\n+ ))\n+ \n+ return results\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 回答问题失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ )]\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n@@ -195,5 +220,72 @@\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n+ return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\"\n+ \n+ async def _ask_question(self, question: str, model: str) -> str:\n+ \"\"\"\n+ 调用外部API回答问题\n+ \n+ Args:\n+ question: 问题\n+ model: 模型名称\n+ \n+ Returns:\n+ 回答结果\n+ \"\"\"\n+ try:\n+ # 使用requests库直接发送请求\n+ url = f\"{self.BASE_URL}/v1/chat/completions\"\n+ \n+ # 构建请求数据\n+ payload = {\n+ \"model\": model,\n+ \"messages\": [\n+ {\n+ \"role\": \"user\",\n+ \"content\": question\n+ }\n+ ],\n+ \"stream\": False\n+ }\n+ \n+ # 设置请求头\n+ headers = {\n+ 'Accept': 'application/json',\n+ 'Authorization': f'Bearer {self.API_KEY}',\n+ 'Content-Type': 'application/json'\n+ }\n+ \n+ # 发送请求\n+ response = requests.post(url, json=payload, headers=headers, timeout=60)\n+ \n+ # 检查响应状态码\n+ if response.status_code != 200:\n+ try:\n+ error_data = response.json()\n+ error_message = error_data.get(\"message\", \"未知错误\")\n+ return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n+ except:\n+ return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n+ \n+ # 解析响应\n+ try:\n+ response_data = response.json()\n+ except json.JSONDecodeError:\n+ return f\"无法解析API响应: {response.text[:200]}...\"\n+ \n+ # 提取回答结果\n+ if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n+ message = response_data[\"choices\"][0].get(\"message\", {})\n+ content = message.get(\"content\", \"未能获取回答结果\")\n+ return content\n+ else:\n+ return f\"未能获取回答结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n+ \n+ except requests.exceptions.RequestException as e:\n+ return f\"API请求错误: {str(e)}\"\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n\\ No newline at end of file\n"
},
{
"date": 1741528589156,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -23,17 +23,17 @@\n name = \"llm\"\n description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n- \"required\": [\"file_path\", \"question\"],\n+ \"required\": [\"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n- \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n+ \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'(可选,如果只是提问则不需要)\",\n },\n \"question\": {\n \"type\": \"string\",\n- \"description\": \"关于文档的问题,例如'文档里说了什么?'\",\n+ \"description\": \"关于文档的问题或直接提问,例如'文档里说了什么?'或'什么是人工智能?'\",\n },\n \"model\": {\n \"type\": \"string\",\n \"description\": \"使用的模型名称,默认为'glm-4'\",\n"
},
{
"date": 1741529059568,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -23,17 +23,17 @@\n name = \"llm\"\n description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n- \"required\": [\"question\"],\n+ \"required\": [\"file_path\", \"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n- \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'(可选,如果只是提问则不需要)\",\n+ \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n },\n \"question\": {\n \"type\": \"string\",\n- \"description\": \"关于文档的问题或直接提问,例如'文档里说了什么?'或'什么是人工智能?'\",\n+ \"description\": \"关于文档的问题,例如'文档里说了什么?'\",\n },\n \"model\": {\n \"type\": \"string\",\n \"description\": \"使用的模型名称,默认为'glm-4'\",\n@@ -47,89 +47,64 @@\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n- 分析文档内容或回答问题\n+ 分析文档内容\n \n Args:\n- arguments: 参数字典,可以包含'file_path'和'question'键\n+ arguments: 参数字典,必须包含'file_path'和'question'键\n \n Returns:\n 分析结果\n \"\"\"\n # 参数验证\n+ if \"file_path\" not in arguments:\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=\"错误: 缺少必要参数 'file_path'\"\n+ )]\n+ \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n+ file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n- # 检查是否提供了文件路径\n- if \"file_path\" in arguments:\n- file_path = arguments[\"file_path\"]\n- # 检查文件路径是否是URL\n- is_url = file_path.startswith(('http://', 'https://'))\n+ # 检查文件是否存在\n+ if not os.path.exists(file_path):\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n+ )]\n+ \n+ try:\n+ # 添加处理信息\n+ results = [types.TextContent(\n+ type=\"text\",\n+ text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n+ )]\n \n- # 如果不是URL,检查文件是否存在\n- if not is_url and not os.path.exists(file_path):\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\\n如果使用Docker,请确保文件路径在容器内可访问,例如使用挂载的目录。\"\n- )]\n+ # 调用外部API分析文档\n+ analysis_result = await self._analyze_document(file_path, question, model)\n \n- try:\n- # 添加处理信息\n- results = [types.TextContent(\n- type=\"text\",\n- text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path) if not is_url else file_path}\\n问题: {question}\\n\\n请稍候...\"\n- )]\n- \n- # 调用外部API分析文档\n- analysis_result = await self._analyze_document(file_path, question, model)\n- \n- # 添加分析结果\n- results.append(types.TextContent(\n- type=\"text\",\n- text=f\"## 分析结果\\n\\n{analysis_result}\"\n- ))\n- \n- return results\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n- )]\n- else:\n- # 直接回答问题,不分析文档\n- try:\n- # 添加处理信息\n- results = [types.TextContent(\n- type=\"text\",\n- text=f\"# 问题\\n\\n{question}\\n\\n请稍候...\"\n- )]\n- \n- # 调用外部API回答问题\n- answer = await self._ask_question(question, model)\n- \n- # 添加回答结果\n- results.append(types.TextContent(\n- type=\"text\",\n- text=f\"## 回答\\n\\n{answer}\"\n- ))\n- \n- return results\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 回答问题失败: {str(e)}\\n详细错误信息: {error_details}\"\n- )]\n+ # 添加分析结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 分析结果\\n\\n{analysis_result}\"\n+ ))\n+ \n+ return results\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ )]\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n@@ -220,72 +195,5 @@\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n- return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\"\n- \n- async def _ask_question(self, question: str, model: str) -> str:\n- \"\"\"\n- 调用外部API回答问题\n- \n- Args:\n- question: 问题\n- model: 模型名称\n- \n- Returns:\n- 回答结果\n- \"\"\"\n- try:\n- # 使用requests库直接发送请求\n- url = f\"{self.BASE_URL}/v1/chat/completions\"\n- \n- # 构建请求数据\n- payload = {\n- \"model\": model,\n- \"messages\": [\n- {\n- \"role\": \"user\",\n- \"content\": question\n- }\n- ],\n- \"stream\": False\n- }\n- \n- # 设置请求头\n- headers = {\n- 'Accept': 'application/json',\n- 'Authorization': f'Bearer {self.API_KEY}',\n- 'Content-Type': 'application/json'\n- }\n- \n- # 发送请求\n- response = requests.post(url, json=payload, headers=headers, timeout=60)\n- \n- # 检查响应状态码\n- if response.status_code != 200:\n- try:\n- error_data = response.json()\n- error_message = error_data.get(\"message\", \"未知错误\")\n- return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n- except:\n- return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n- \n- # 解析响应\n- try:\n- response_data = response.json()\n- except json.JSONDecodeError:\n- return f\"无法解析API响应: {response.text[:200]}...\"\n- \n- # 提取回答结果\n- if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n- message = response_data[\"choices\"][0].get(\"message\", {})\n- content = message.get(\"content\", \"未能获取回答结果\")\n- return content\n- else:\n- return f\"未能获取回答结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n- \n- except requests.exceptions.RequestException as e:\n- return f\"API请求错误: {str(e)}\"\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n\\ No newline at end of file\n"
},
{
"date": 1741529102551,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -23,17 +23,17 @@\n name = \"llm\"\n description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n- \"required\": [\"file_path\", \"question\"],\n+ \"required\": [\"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n- \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n+ \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'(可选,如果只是提问则不需要)\",\n },\n \"question\": {\n \"type\": \"string\",\n- \"description\": \"关于文档的问题,例如'文档里说了什么?'\",\n+ \"description\": \"关于文档的问题或直接提问,例如'文档里说了什么?'或'什么是人工智能?'\",\n },\n \"model\": {\n \"type\": \"string\",\n \"description\": \"使用的模型名称,默认为'glm-4'\",\n@@ -47,64 +47,89 @@\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n- 分析文档内容\n+ 分析文档内容或回答问题\n \n Args:\n- arguments: 参数字典,必须包含'file_path'和'question'键\n+ arguments: 参数字典,可以包含'file_path'和'question'键\n \n Returns:\n 分析结果\n \"\"\"\n # 参数验证\n- if \"file_path\" not in arguments:\n- return [types.TextContent(\n- type=\"text\",\n- text=\"错误: 缺少必要参数 'file_path'\"\n- )]\n- \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n- file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n- # 检查文件是否存在\n- if not os.path.exists(file_path):\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n- )]\n- \n- try:\n- # 添加处理信息\n- results = [types.TextContent(\n- type=\"text\",\n- text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n- )]\n+ # 检查是否提供了文件路径\n+ if \"file_path\" in arguments:\n+ file_path = arguments[\"file_path\"]\n+ # 检查文件路径是否是URL\n+ is_url = file_path.startswith(('http://', 'https://'))\n \n- # 调用外部API分析文档\n- analysis_result = await self._analyze_document(file_path, question, model)\n+ # 如果不是URL,检查文件是否存在\n+ if not is_url and not os.path.exists(file_path):\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\\n如果使用Docker,请确保文件路径在容器内可访问,例如使用挂载的目录。\"\n+ )]\n \n- # 添加分析结果\n- results.append(types.TextContent(\n- type=\"text\",\n- text=f\"## 分析结果\\n\\n{analysis_result}\"\n- ))\n- \n- return results\n- except Exception as e:\n- import traceback\n- error_details = traceback.format_exc()\n- return [types.TextContent(\n- type=\"text\",\n- text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n- )]\n+ try:\n+ # 添加处理信息\n+ results = [types.TextContent(\n+ type=\"text\",\n+ text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path) if not is_url else file_path}\\n问题: {question}\\n\\n请稍候...\"\n+ )]\n+ \n+ # 调用外部API分析文档\n+ analysis_result = await self._analyze_document(file_path, question, model)\n+ \n+ # 添加分析结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 分析结果\\n\\n{analysis_result}\"\n+ ))\n+ \n+ return results\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ )]\n+ else:\n+ # 直接回答问题,不分析文档\n+ try:\n+ # 添加处理信息\n+ results = [types.TextContent(\n+ type=\"text\",\n+ text=f\"# 问题\\n\\n{question}\\n\\n请稍候...\"\n+ )]\n+ \n+ # 调用外部API回答问题\n+ answer = await self._ask_question(question, model)\n+ \n+ # 添加回答结果\n+ results.append(types.TextContent(\n+ type=\"text\",\n+ text=f\"## 回答\\n\\n{answer}\"\n+ ))\n+ \n+ return results\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n+ return [types.TextContent(\n+ type=\"text\",\n+ text=f\"错误: 回答问题失败: {str(e)}\\n详细错误信息: {error_details}\"\n+ )]\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n@@ -195,5 +220,72 @@\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n+ return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\"\n+ \n+ async def _ask_question(self, question: str, model: str) -> str:\n+ \"\"\"\n+ 调用外部API回答问题\n+ \n+ Args:\n+ question: 问题\n+ model: 模型名称\n+ \n+ Returns:\n+ 回答结果\n+ \"\"\"\n+ try:\n+ # 使用requests库直接发送请求\n+ url = f\"{self.BASE_URL}/v1/chat/completions\"\n+ \n+ # 构建请求数据\n+ payload = {\n+ \"model\": model,\n+ \"messages\": [\n+ {\n+ \"role\": \"user\",\n+ \"content\": question\n+ }\n+ ],\n+ \"stream\": False\n+ }\n+ \n+ # 设置请求头\n+ headers = {\n+ 'Accept': 'application/json',\n+ 'Authorization': f'Bearer {self.API_KEY}',\n+ 'Content-Type': 'application/json'\n+ }\n+ \n+ # 发送请求\n+ response = requests.post(url, json=payload, headers=headers, timeout=60)\n+ \n+ # 检查响应状态码\n+ if response.status_code != 200:\n+ try:\n+ error_data = response.json()\n+ error_message = error_data.get(\"message\", \"未知错误\")\n+ return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n+ except:\n+ return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n+ \n+ # 解析响应\n+ try:\n+ response_data = response.json()\n+ except json.JSONDecodeError:\n+ return f\"无法解析API响应: {response.text[:200]}...\"\n+ \n+ # 提取回答结果\n+ if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n+ message = response_data[\"choices\"][0].get(\"message\", {})\n+ content = message.get(\"content\", \"未能获取回答结果\")\n+ return content\n+ else:\n+ return f\"未能获取回答结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n+ \n+ except requests.exceptions.RequestException as e:\n+ return f\"API请求错误: {str(e)}\"\n+ except Exception as e:\n+ import traceback\n+ error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" \n\\ No newline at end of file\n"
}
],
"date": 1741527987944,
"name": "Commit-0",
"content": "\"\"\"\n大语言模型交互工具,使用外部大模型API分析文档内容或回答问题\n\"\"\"\n\nimport os\nimport json\nimport http.client\nimport urllib.parse\nimport base64\nimport mimetypes\nimport uuid\nimport requests\nfrom typing import Dict, List, Any, Optional, Tuple\nimport mcp.types as types\nfrom . import BaseTool, ToolRegistry\n\n@ToolRegistry.register\nclass LLMTool(BaseTool):\n \"\"\"\n 大语言模型交互工具,使用外部大模型API分析文档内容或回答问题\n \"\"\"\n \n name = \"llm\"\n description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n \"required\": [\"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n },\n \"question\": {\n \"type\": \"string\",\n \"description\": \"关于文档的问题或直接提问,例如'文档里说了什么?'或'什么是人工智能?'\",\n },\n \"model\": {\n \"type\": \"string\",\n \"description\": \"使用的模型名称,默认为'glm-4'\",\n }\n },\n }\n \n # API配置\n BASE_URL = \"http://host.docker.internal:8009\"\n API_KEY = \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhMjI3ZDkwYjVmMTY0MzcxYTcxMTdlMmRiODRjYzJiNSIsImV4cCI6MTc1NjYyMTg3NCwibmJmIjoxNzQxMDY5ODc0LCJpYXQiOjE3NDEwNjk4NzQsImp0aSI6IjhhZjA4YTU4YjIyNTQzODY5MDdkNGNlNTcwMzFjNmQ5IiwidWlkIjoiNjZkMDQ2NzdkM2IzNmZlYmU1ODFkMWZkIiwidHlwZSI6InJlZnJlc2gifQ.cAOioruMC0jLneIcbSyhuXJ9JIx_Bz79ndTTxlsWe5I\"\n DEFAULT_MODEL = \"glm-4\"\n \n async def execute(self, arguments: Dict[str, Any]) -> List[types.TextContent | types.ImageContent | types.EmbeddedResource]:\n \"\"\"\n 分析文档内容\n \n Args:\n arguments: 参数字典,必须包含'file_path'和'question'键\n \n Returns:\n 分析结果\n \"\"\"\n # 参数验证\n if \"file_path\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'file_path'\"\n )]\n \n if \"question\" not in arguments:\n return [types.TextContent(\n type=\"text\",\n text=\"错误: 缺少必要参数 'question'\"\n )]\n \n file_path = arguments[\"file_path\"]\n question = arguments[\"question\"]\n model = arguments.get(\"model\", self.DEFAULT_MODEL)\n \n # 检查文件是否存在\n if not os.path.exists(file_path):\n return [types.TextContent(\n type=\"text\",\n text=f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n )]\n \n try:\n # 添加处理信息\n results = [types.TextContent(\n type=\"text\",\n text=f\"# 文档分析\\n\\n正在分析文件: {os.path.basename(file_path)}\\n问题: {question}\\n\\n请稍候...\"\n )]\n \n # 调用外部API分析文档\n analysis_result = await self._analyze_document(file_path, question, model)\n \n # 添加分析结果\n results.append(types.TextContent(\n type=\"text\",\n text=f\"## 分析结果\\n\\n{analysis_result}\"\n ))\n \n return results\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n return [types.TextContent(\n type=\"text\",\n text=f\"错误: 分析文档失败: {str(e)}\\n详细错误信息: {error_details}\"\n )]\n \n async def _analyze_document(self, file_path: str, question: str, model: str) -> str:\n \"\"\"\n 调用外部API分析文档\n \n Args:\n file_path: 文档路径\n question: 问题\n model: 模型名称\n \n Returns:\n 分析结果\n \"\"\"\n try:\n # 检查文件路径是否是URL\n is_url = file_path.startswith(('http://', 'https://'))\n \n # 如果不是URL,检查文件是否存在\n if not is_url and not os.path.exists(file_path):\n return f\"错误: 文件不存在: {file_path}\\n请检查路径是否正确,并确保文件可访问。\"\n \n # 使用requests库直接发送请求\n url = f\"{self.BASE_URL}/v1/chat/completions\"\n \n # 构建请求数据\n payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"text\",\n \"text\": question\n }\n ]\n }\n ],\n \"stream\": False\n }\n \n # 如果是URL,添加到消息中\n if is_url:\n payload[\"messages\"][0][\"content\"].insert(0, {\n \"type\": \"file\",\n \"file_url\": {\n \"url\": file_path\n }\n })\n else:\n # 如果是本地文件,使用文本方式提问\n file_name = os.path.basename(file_path)\n payload[\"messages\"][0][\"content\"][0][\"text\"] = f\"我正在分析一个名为'{file_name}'的文档。请回答以下问题:{question}\"\n \n # 设置请求头\n headers = {\n 'Accept': 'application/json',\n 'Authorization': f'Bearer {self.API_KEY}',\n 'Content-Type': 'application/json'\n }\n \n # 发送请求\n response = requests.post(url, json=payload, headers=headers, timeout=60)\n \n # 检查响应状态码\n if response.status_code != 200:\n try:\n error_data = response.json()\n error_message = error_data.get(\"message\", \"未知错误\")\n return f\"API请求失败 (状态码: {response.status_code}): {error_message}\"\n except:\n return f\"API请求失败 (状态码: {response.status_code}): {response.text[:200]}...\"\n \n # 解析响应\n try:\n response_data = response.json()\n except json.JSONDecodeError:\n return f\"无法解析API响应: {response.text[:200]}...\"\n \n # 提取分析结果\n if \"choices\" in response_data and len(response_data[\"choices\"]) > 0:\n message = response_data[\"choices\"][0].get(\"message\", {})\n content = message.get(\"content\", \"未能获取分析结果\")\n return content\n else:\n return f\"未能获取分析结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n \n except requests.exceptions.RequestException as e:\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n import traceback\n error_details = traceback.format_exc()\n return f\"调用API时出错: {str(e)}\\n详细错误信息: {error_details}\" "
}
]
}