MCP Development Framework
by aigo666
{
"sourceFile": "mcp_tool/tools/doc_analysis_tool.py",
"activeCommit": 0,
"commits": [
{
"activePatchIndex": 17,
"patches": [
{
"date": 1741523759404,
"content": "Index: \n===================================================================\n--- \n+++ \n"
},
{
"date": 1741523800814,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -5,8 +5,9 @@\n import os\n import json\n import http.client\n import urllib.parse\n+import base64\n from typing import Dict, List, Any\n import mcp.types as types\n from . import BaseTool, ToolRegistry\n \n@@ -113,8 +114,22 @@\n Returns:\n 分析结果\n \"\"\"\n try:\n+ # 获取文件类型\n+ file_extension = os.path.splitext(file_path)[1].lower()\n+ \n+ # 读取文件内容\n+ with open(file_path, 'rb') as file:\n+ file_content = file.read()\n+ \n+ # 获取文件大小(MB)\n+ file_size_mb = len(file_content) / (1024 * 1024)\n+ \n+ # 检查文件大小\n+ if file_size_mb > 20: # 假设API限制文件大小为20MB\n+ return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n+ \n # 构建请求数据\n payload = json.dumps({\n \"model\": model,\n \"messages\": [\n@@ -123,9 +138,9 @@\n \"content\": [\n {\n \"type\": \"file\",\n \"file_url\": {\n- \"url\": file_path # 使用本地文件路径\n+ \"url\": file_path # 使用本地文件路径,API会处理文件访问\n }\n },\n {\n \"type\": \"text\",\n@@ -152,21 +167,24 @@\n response = conn.getresponse()\n data = response.read().decode(\"utf-8\")\n \n # 解析响应\n- response_data = json.loads(data)\n+ try:\n+ response_data = json.loads(data)\n+ except json.JSONDecodeError:\n+ return f\"无法解析API响应: {data[:200]}...\"\n \n # 检查响应是否成功\n if response.status != 200:\n- error_message = response_data.get(\"message\", \"未知错误\")\n+ error_message = response_data.get(\"error\", {}).get(\"message\", \"未知错误\")\n return f\"API请求失败 (状态码: {response.status}): {error_message}\"\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 \"未能获取分析结果,API响应格式不符合预期\"\n+ return f\"未能获取分析结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n \n except Exception as e:\n return f\"调用API时出错: {str(e)}\" \n\\ No newline at end of file\n"
},
{
"date": 1741523853274,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -6,9 +6,12 @@\n import json\n import http.client\n import urllib.parse\n import base64\n-from typing import Dict, List, Any\n+import mimetypes\n+import uuid\n+import requests\n+from typing import Dict, List, Any, Optional, Tuple\n import mcp.types as types\n from . import BaseTool, ToolRegistry\n \n @ToolRegistry.register\n@@ -116,9 +119,19 @@\n \"\"\"\n try:\n # 获取文件类型\n file_extension = os.path.splitext(file_path)[1].lower()\n+ mime_type, _ = mimetypes.guess_type(file_path)\n \n+ if not mime_type:\n+ # 默认MIME类型\n+ if file_extension == '.pdf':\n+ mime_type = 'application/pdf'\n+ elif file_extension in ['.doc', '.docx']:\n+ mime_type = 'application/msword'\n+ else:\n+ mime_type = 'application/octet-stream'\n+ \n # 读取文件内容\n with open(file_path, 'rb') as file:\n file_content = file.read()\n \n@@ -129,8 +142,10 @@\n if file_size_mb > 20: # 假设API限制文件大小为20MB\n return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n \n # 构建请求数据\n+ # 注意:这里我们假设API支持直接使用挂载的文件路径\n+ # 如果API需要实际上传文件,则需要修改此部分代码\n payload = json.dumps({\n \"model\": model,\n \"messages\": [\n {\n@@ -186,5 +201,56 @@\n else:\n return f\"未能获取分析结果,API响应格式不符合预期: {json.dumps(response_data)[:200]}...\"\n \n except Exception as e:\n- return f\"调用API时出错: {str(e)}\" \n\\ No newline at end of file\n+ return f\"调用API时出错: {str(e)}\"\n+ \n+ async def _upload_file(self, file_path: str) -> Optional[str]:\n+ \"\"\"\n+ 上传文件到临时存储服务,获取可访问的URL\n+ \n+ Args:\n+ file_path: 文件路径\n+ \n+ Returns:\n+ 文件URL或None(如果上传失败)\n+ \"\"\"\n+ # 这里需要实现文件上传逻辑\n+ # 由于没有具体的文件上传服务信息,这里只是一个示例框架\n+ try:\n+ # 读取文件\n+ with open(file_path, 'rb') as file:\n+ file_content = file.read()\n+ \n+ # 获取文件类型\n+ mime_type, _ = mimetypes.guess_type(file_path)\n+ if not mime_type:\n+ mime_type = 'application/octet-stream'\n+ \n+ # 构建上传请求\n+ # 这里需要替换为实际的文件上传服务\n+ # 例如,可以使用AWS S3, Azure Blob Storage, 或其他文件存储服务\n+ # 以下代码仅为示例\n+ \n+ # 假设有一个文件上传API\n+ upload_url = \"https://example.com/upload\"\n+ \n+ # 生成唯一文件名\n+ filename = f\"{uuid.uuid4()}{os.path.splitext(file_path)[1]}\"\n+ \n+ # 构建multipart/form-data请求\n+ files = {'file': (filename, file_content, mime_type)}\n+ \n+ # 发送上传请求\n+ response = requests.post(upload_url, files=files)\n+ \n+ # 检查响应\n+ if response.status_code == 200:\n+ # 假设响应中包含文件URL\n+ response_data = response.json()\n+ return response_data.get('url')\n+ else:\n+ return None\n+ \n+ except Exception as e:\n+ print(f\"文件上传失败: {str(e)}\")\n+ return None \n\\ No newline at end of file\n"
},
{
"date": 1741524513409,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -141,32 +141,27 @@\n # 检查文件大小\n if file_size_mb > 20: # 假设API限制文件大小为20MB\n return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n \n+ # 使用requests库直接发送请求,而不是http.client\n+ url = f\"https://{self.BASE_URL}/v1/chat/completions\"\n+ \n # 构建请求数据\n- # 注意:这里我们假设API支持直接使用挂载的文件路径\n- # 如果API需要实际上传文件,则需要修改此部分代码\n- payload = json.dumps({\n+ payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n- \"type\": \"file\",\n- \"file_url\": {\n- \"url\": file_path # 使用本地文件路径,API会处理文件访问\n- }\n- },\n- {\n \"type\": \"text\",\n \"text\": question\n }\n ]\n }\n ],\n \"stream\": False\n- })\n+ }\n \n # 设置请求头\n headers = {\n 'Accept': 'application/json',\n@@ -174,34 +169,35 @@\n 'Content-Type': 'application/json'\n }\n \n # 发送请求\n- conn = http.client.HTTPSConnection(self.BASE_URL)\n- conn.request(\"POST\", \"/v1/chat/completions\", payload, headers)\n+ response = requests.post(url, json=payload, headers=headers)\n \n- # 获取响应\n- response = conn.getresponse()\n- data = response.read().decode(\"utf-8\")\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 = json.loads(data)\n+ response_data = response.json()\n except json.JSONDecodeError:\n- return f\"无法解析API响应: {data[:200]}...\"\n+ return f\"无法解析API响应: {response.text[:200]}...\"\n \n- # 检查响应是否成功\n- if response.status != 200:\n- error_message = response_data.get(\"error\", {}).get(\"message\", \"未知错误\")\n- return f\"API请求失败 (状态码: {response.status}): {error_message}\"\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 return f\"调用API时出错: {str(e)}\"\n \n async def _upload_file(self, file_path: str) -> Optional[str]:\n@@ -231,18 +227,19 @@\n # 例如,可以使用AWS S3, Azure Blob Storage, 或其他文件存储服务\n # 以下代码仅为示例\n \n # 假设有一个文件上传API\n- upload_url = \"https://example.com/upload\"\n+ upload_url = f\"https://{self.BASE_URL}/v1/files\"\n \n # 生成唯一文件名\n filename = f\"{uuid.uuid4()}{os.path.splitext(file_path)[1]}\"\n \n # 构建multipart/form-data请求\n files = {'file': (filename, file_content, mime_type)}\n+ headers = {'Authorization': f'Bearer {self.API_KEY}'}\n \n # 发送上传请求\n- response = requests.post(upload_url, files=files)\n+ response = requests.post(upload_url, files=files, headers=headers)\n \n # 检查响应\n if response.status_code == 200:\n # 假设响应中包含文件URL\n"
},
{
"date": 1741524613158,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"blog.lyzplus.cn\"\n+ BASE_URL = \"http://localhost:8009/v1\"\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@@ -130,30 +130,32 @@\n mime_type = 'application/msword'\n else:\n mime_type = 'application/octet-stream'\n \n- # 读取文件内容\n- with open(file_path, 'rb') as file:\n- file_content = file.read()\n- \n # 获取文件大小(MB)\n- file_size_mb = len(file_content) / (1024 * 1024)\n+ file_size_mb = os.path.getsize(file_path) / (1024 * 1024)\n \n # 检查文件大小\n if file_size_mb > 20: # 假设API限制文件大小为20MB\n return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n \n- # 使用requests库直接发送请求,而不是http.client\n- url = f\"https://{self.BASE_URL}/v1/chat/completions\"\n+ # 使用requests库直接发送请求\n+ url = f\"{self.BASE_URL}/chat/completions\"\n \n- # 构建请求数据\n+ # 构建请求数据 - 使用本地文件路径作为文件链接\n payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n+ \"type\": \"file\",\n+ \"file_url\": {\n+ \"url\": file_path # 直接使用本地文件路径\n+ }\n+ },\n+ {\n \"type\": \"text\",\n \"text\": question\n }\n ]\n"
},
{
"date": 1741524884356,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"http://localhost:8009/v1\"\n+ BASE_URL = \"https://open.bigmodel.cn/api\"\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@@ -137,25 +137,24 @@\n # 检查文件大小\n if file_size_mb > 20: # 假设API限制文件大小为20MB\n return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n \n+ # 由于无法直接使用本地文件路径,我们需要读取文件内容并进行base64编码\n+ with open(file_path, 'rb') as f:\n+ file_content = f.read()\n+ file_base64 = base64.b64encode(file_content).decode('utf-8')\n+ \n # 使用requests库直接发送请求\n- url = f\"{self.BASE_URL}/chat/completions\"\n+ url = f\"{self.BASE_URL}/v1/chat/completions\"\n \n- # 构建请求数据 - 使用本地文件路径作为文件链接\n+ # 构建请求数据 - 使用base64编码的文件内容\n payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n- \"type\": \"file\",\n- \"file_url\": {\n- \"url\": file_path # 直接使用本地文件路径\n- }\n- },\n- {\n \"type\": \"text\",\n \"text\": question\n }\n ]\n@@ -163,17 +162,26 @@\n ],\n \"stream\": False\n }\n \n+ # 如果文件不太大,添加到消息中\n+ if file_size_mb <= 20:\n+ payload[\"messages\"][0][\"content\"].insert(0, {\n+ \"type\": \"image_url\",\n+ \"image_url\": {\n+ \"url\": f\"data:{mime_type};base64,{file_base64}\"\n+ }\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)\n+ response = requests.post(url, json=payload, headers=headers, timeout=60)\n \n # 检查响应状态码\n if response.status_code != 200:\n try:\n"
},
{
"date": 1741525162856,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"https://open.bigmodel.cn/api\"\n+ BASE_URL = \"http://localhost: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"
},
{
"date": 1741525471676,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"http://localhost:8009\"\n+ BASE_URL = \"https://open.bigmodel.cn/api\"\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"
},
{
"date": 1741525489585,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"https://open.bigmodel.cn/api\"\n+ BASE_URL = \"https://blog.lyzplus.cn\"\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"
},
{
"date": 1741525735589,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -145,9 +145,9 @@\n \n # 使用requests库直接发送请求\n url = f\"{self.BASE_URL}/v1/chat/completions\"\n \n- # 构建请求数据 - 使用base64编码的文件内容\n+ # 构建请求数据\n payload = {\n \"model\": model,\n \"messages\": [\n {\n@@ -164,14 +164,20 @@\n }\n \n # 如果文件不太大,添加到消息中\n if file_size_mb <= 20:\n- payload[\"messages\"][0][\"content\"].insert(0, {\n- \"type\": \"image_url\",\n- \"image_url\": {\n- \"url\": f\"data:{mime_type};base64,{file_base64}\"\n- }\n- })\n+ # 根据文件类型选择合适的内容类型\n+ if file_extension in ['.jpg', '.jpeg', '.png', '.gif', '.webp']:\n+ # 图片文件使用image_url\n+ payload[\"messages\"][0][\"content\"].insert(0, {\n+ \"type\": \"image_url\",\n+ \"image_url\": {\n+ \"url\": f\"data:{mime_type};base64,{file_base64}\"\n+ }\n+ })\n+ else:\n+ # 其他文件类型(如PDF、Word等)使用text类型,并在问题中提及文件\n+ payload[\"messages\"][0][\"content\"][0][\"text\"] = f\"我将分析以下文档内容并回答问题:{os.path.basename(file_path)}\\n\\n问题:{question}\"\n \n # 设置请求头\n headers = {\n 'Accept': 'application/json',\n"
},
{
"date": 1741526027813,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -117,68 +117,30 @@\n Returns:\n 分析结果\n \"\"\"\n try:\n- # 获取文件类型\n+ # 获取文件类型和名称\n file_extension = os.path.splitext(file_path)[1].lower()\n- mime_type, _ = mimetypes.guess_type(file_path)\n+ file_name = os.path.basename(file_path)\n \n- if not mime_type:\n- # 默认MIME类型\n- if file_extension == '.pdf':\n- mime_type = 'application/pdf'\n- elif file_extension in ['.doc', '.docx']:\n- mime_type = 'application/msword'\n- else:\n- mime_type = 'application/octet-stream'\n+ # 构建增强的问题,包含文件信息\n+ enhanced_question = f\"我正在分析一个名为'{file_name}'的文档。请回答以下问题:{question}\"\n \n- # 获取文件大小(MB)\n- file_size_mb = os.path.getsize(file_path) / (1024 * 1024)\n- \n- # 检查文件大小\n- if file_size_mb > 20: # 假设API限制文件大小为20MB\n- return f\"文件过大({file_size_mb:.2f}MB),超过API限制。请使用小于20MB的文件。\"\n- \n- # 由于无法直接使用本地文件路径,我们需要读取文件内容并进行base64编码\n- with open(file_path, 'rb') as f:\n- file_content = f.read()\n- file_base64 = base64.b64encode(file_content).decode('utf-8')\n- \n # 使用requests库直接发送请求\n url = f\"{self.BASE_URL}/v1/chat/completions\"\n \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+ \"content\": enhanced_question\n }\n ],\n \"stream\": False\n }\n \n- # 如果文件不太大,添加到消息中\n- if file_size_mb <= 20:\n- # 根据文件类型选择合适的内容类型\n- if file_extension in ['.jpg', '.jpeg', '.png', '.gif', '.webp']:\n- # 图片文件使用image_url\n- payload[\"messages\"][0][\"content\"].insert(0, {\n- \"type\": \"image_url\",\n- \"image_url\": {\n- \"url\": f\"data:{mime_type};base64,{file_base64}\"\n- }\n- })\n- else:\n- # 其他文件类型(如PDF、Word等)使用text类型,并在问题中提及文件\n- payload[\"messages\"][0][\"content\"][0][\"text\"] = f\"我将分析以下文档内容并回答问题:{os.path.basename(file_path)}\\n\\n问题:{question}\"\n- \n # 设置请求头\n headers = {\n 'Accept': 'application/json',\n 'Authorization': f'Bearer {self.API_KEY}',\n@@ -213,57 +175,7 @@\n \n except requests.exceptions.RequestException as e:\n return f\"API请求错误: {str(e)}\"\n except Exception as e:\n- return f\"调用API时出错: {str(e)}\"\n- \n- async def _upload_file(self, file_path: str) -> Optional[str]:\n- \"\"\"\n- 上传文件到临时存储服务,获取可访问的URL\n- \n- Args:\n- file_path: 文件路径\n- \n- Returns:\n- 文件URL或None(如果上传失败)\n- \"\"\"\n- # 这里需要实现文件上传逻辑\n- # 由于没有具体的文件上传服务信息,这里只是一个示例框架\n- try:\n- # 读取文件\n- with open(file_path, 'rb') as file:\n- file_content = file.read()\n- \n- # 获取文件类型\n- mime_type, _ = mimetypes.guess_type(file_path)\n- if not mime_type:\n- mime_type = 'application/octet-stream'\n- \n- # 构建上传请求\n- # 这里需要替换为实际的文件上传服务\n- # 例如,可以使用AWS S3, Azure Blob Storage, 或其他文件存储服务\n- # 以下代码仅为示例\n- \n- # 假设有一个文件上传API\n- upload_url = f\"https://{self.BASE_URL}/v1/files\"\n- \n- # 生成唯一文件名\n- filename = f\"{uuid.uuid4()}{os.path.splitext(file_path)[1]}\"\n- \n- # 构建multipart/form-data请求\n- files = {'file': (filename, file_content, mime_type)}\n- headers = {'Authorization': f'Bearer {self.API_KEY}'}\n- \n- # 发送上传请求\n- response = requests.post(upload_url, files=files, headers=headers)\n- \n- # 检查响应\n- if response.status_code == 200:\n- # 假设响应中包含文件URL\n- response_data = response.json()\n- return response_data.get('url')\n- else:\n- return None\n- \n- except Exception as e:\n- print(f\"文件上传失败: {str(e)}\")\n- return None \n\\ No newline at end of file\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": 1741526150977,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -117,25 +117,32 @@\n Returns:\n 分析结果\n \"\"\"\n try:\n- # 获取文件类型和名称\n- file_extension = os.path.splitext(file_path)[1].lower()\n- file_name = os.path.basename(file_path)\n+ # 检查文件路径是否是URL\n+ is_url = file_path.startswith(('http://', 'https://'))\n \n- # 构建增强的问题,包含文件信息\n- enhanced_question = f\"我正在分析一个名为'{file_name}'的文档。请回答以下问题:{question}\"\n- \n # 使用requests库直接发送请求\n url = f\"{self.BASE_URL}/v1/chat/completions\"\n \n- # 构建简化的请求数据\n+ # 构建请求数据,按照API要求的格式\n payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n- \"content\": enhanced_question\n+ \"content\": [\n+ {\n+ \"type\": \"file\",\n+ \"file_url\": {\n+ \"url\": file_path if is_url else f\"file://{os.path.abspath(file_path)}\"\n+ }\n+ },\n+ {\n+ \"type\": \"text\",\n+ \"text\": question\n+ }\n+ ]\n }\n ],\n \"stream\": False\n }\n"
},
{
"date": 1741526430648,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -120,25 +120,23 @@\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- # 构建请求数据,按照API要求的格式\n+ # 构建请求数据\n payload = {\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n- \"type\": \"file\",\n- \"file_url\": {\n- \"url\": file_path if is_url else f\"file://{os.path.abspath(file_path)}\"\n- }\n- },\n- {\n \"type\": \"text\",\n \"text\": question\n }\n ]\n@@ -146,8 +144,21 @@\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"
},
{
"date": 1741526859546,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -19,17 +19,17 @@\n \"\"\"\n 文档分析工具,使用外部大模型API分析文档内容\n \"\"\"\n \n- name = \"doc_analysis\"\n- description = \"使用大模型分析文档内容,支持PDF、Word等格式\"\n+ name = \"llm\"\n+ description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n \"required\": [\"file_path\", \"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n- \"description\": \"文档的本地路径,例如'/path/to/document.pdf'\",\n+ \"description\": \"文档的本地路径或URL,例如'/path/to/document.pdf'或'https://example.com/document.pdf'\",\n },\n \"question\": {\n \"type\": \"string\",\n \"description\": \"关于文档的问题,例如'文档里说了什么?'\",\n"
},
{
"date": 1741527122452,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -41,9 +41,9 @@\n },\n }\n \n # API配置\n- BASE_URL = \"https://blog.lyzplus.cn\"\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"
},
{
"date": 1741528087343,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,199 +1,9 @@\n-\"\"\"\n-文档分析工具,使用外部大模型API分析文档内容\n-\"\"\"\n-\n-import os\n-import json\n-import http.client\n-import urllib.parse\n-import base64\n-import mimetypes\n-import uuid\n-import requests\n-from typing import Dict, List, Any, Optional, Tuple\n-import mcp.types as types\n-from . import BaseTool, ToolRegistry\n-\n-@ToolRegistry.register\n-class DocAnalysisTool(BaseTool):\n- \"\"\"\n- 文档分析工具,使用外部大模型API分析文档内容\n- \"\"\"\n- \n- name = \"llm\"\n- description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n- input_schema = {\n- \"type\": \"object\",\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- },\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}\" \n\\ No newline at end of file\n+'''\n+Author: 刘彦志 yanzhiliu@trip.com\n+Date: 2025-03-09 21:48:02\n+LastEditors: 刘彦志 yanzhiliu@trip.com\n+LastEditTime: 2025-03-09 21:48:06\n+FilePath: /mcp-development-framework/mcp_tool/tools/doc_analysis_tool.py\n+Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\n+'''\n+ \n\\ No newline at end of file\n"
},
{
"date": 1741529059557,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,1 +1,199 @@\n- \n\\ No newline at end of file\n+\"\"\"\n+文档分析工具,使用外部大模型API分析文档内容\n+\"\"\"\n+\n+import os\n+import json\n+import http.client\n+import urllib.parse\n+import base64\n+import mimetypes\n+import uuid\n+import requests\n+from typing import Dict, List, Any, Optional, Tuple\n+import mcp.types as types\n+from . import BaseTool, ToolRegistry\n+\n+@ToolRegistry.register\n+class DocAnalysisTool(BaseTool):\n+ \"\"\"\n+ 文档分析工具,使用外部大模型API分析文档内容\n+ \"\"\"\n+ \n+ name = \"llm\"\n+ description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n+ input_schema = {\n+ \"type\": \"object\",\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+ },\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}\" \n\\ No newline at end of file\n"
},
{
"date": 1741529101782,
"content": "Index: \n===================================================================\n--- \n+++ \n@@ -1,207 +1,1 @@\n-'''\n-Author: 刘彦志 yanzhiliu@trip.com\n-Date: 2025-03-09 21:48:02\n-LastEditors: 刘彦志 yanzhiliu@trip.com\n-LastEditTime: 2025-03-09 21:48:06\n-FilePath: /mcp-development-framework/mcp_tool/tools/doc_analysis_tool.py\n-Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE\n-'''\n-\"\"\"\n-文档分析工具,使用外部大模型API分析文档内容\n-\"\"\"\n-\n-import os\n-import json\n-import http.client\n-import urllib.parse\n-import base64\n-import mimetypes\n-import uuid\n-import requests\n-from typing import Dict, List, Any, Optional, Tuple\n-import mcp.types as types\n-from . import BaseTool, ToolRegistry\n-\n-@ToolRegistry.register\n-class DocAnalysisTool(BaseTool):\n- \"\"\"\n- 文档分析工具,使用外部大模型API分析文档内容\n- \"\"\"\n- \n- name = \"llm\"\n- description = \"使用大模型分析文档内容或回答问题,支持PDF、Word等格式\"\n- input_schema = {\n- \"type\": \"object\",\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- },\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}\" \n\\ No newline at end of file\n+ \n\\ No newline at end of file\n"
}
],
"date": 1741523759404,
"name": "Commit-0",
"content": "\"\"\"\n文档分析工具,使用外部大模型API分析文档内容\n\"\"\"\n\nimport os\nimport json\nimport http.client\nimport urllib.parse\nfrom typing import Dict, List, Any\nimport mcp.types as types\nfrom . import BaseTool, ToolRegistry\n\n@ToolRegistry.register\nclass DocAnalysisTool(BaseTool):\n \"\"\"\n 文档分析工具,使用外部大模型API分析文档内容\n \"\"\"\n \n name = \"doc_analysis\"\n description = \"使用大模型分析文档内容,支持PDF、Word等格式\"\n input_schema = {\n \"type\": \"object\",\n \"required\": [\"file_path\", \"question\"],\n \"properties\": {\n \"file_path\": {\n \"type\": \"string\",\n \"description\": \"文档的本地路径,例如'/path/to/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 = \"blog.lyzplus.cn\"\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 # 构建请求数据\n payload = json.dumps({\n \"model\": model,\n \"messages\": [\n {\n \"role\": \"user\",\n \"content\": [\n {\n \"type\": \"file\",\n \"file_url\": {\n \"url\": file_path # 使用本地文件路径\n }\n },\n {\n \"type\": \"text\",\n \"text\": question\n }\n ]\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 conn = http.client.HTTPSConnection(self.BASE_URL)\n conn.request(\"POST\", \"/v1/chat/completions\", payload, headers)\n \n # 获取响应\n response = conn.getresponse()\n data = response.read().decode(\"utf-8\")\n \n # 解析响应\n response_data = json.loads(data)\n \n # 检查响应是否成功\n if response.status != 200:\n error_message = response_data.get(\"message\", \"未知错误\")\n return f\"API请求失败 (状态码: {response.status}): {error_message}\"\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 \"未能获取分析结果,API响应格式不符合预期\"\n \n except Exception as e:\n return f\"调用API时出错: {str(e)}\" "
}
]
}