diff --git a/.opencode/skills/create_model/scripts/create_result.json b/.opencode/skills/create_model/scripts/create_result.json index 4dd71d7..ef8fdf3 100644 --- a/.opencode/skills/create_model/scripts/create_result.json +++ b/.opencode/skills/create_model/scripts/create_result.json @@ -15,7 +15,7 @@ "identifier": "fanshuai_model_20260525110238", "is_public": false, "relative_paths": "fanshuai/model/143/fanshuai_model_20260525110238/origin/model", - "preview_pic": "http://172.20.32.121:31213/minio/data/mini-model-platform-data/temp/fanshuai/1761528061144/model/材料筛选.png", + "preview_pic": "https://www.ai4mats.com/minio/data/mini-model-platform-data/temp/fanshuai/1761528061144/model/材料筛选.png", "is_hot_stone": false, "git_id": 143 } diff --git a/.opencode/skills/dataset/common/login_mcp_server.py b/.opencode/skills/dataset/common/login_mcp_server.py index ecab272..eb33be3 100644 --- a/.opencode/skills/dataset/common/login_mcp_server.py +++ b/.opencode/skills/dataset/common/login_mcp_server.py @@ -8,7 +8,7 @@ from mcp.server.fastmcp import FastMCP def load_config(): config_path = os.path.join(os.path.dirname(__file__), "config.json") default_config = { - "API_BASE_URL": "http://172.20.32.121:31213", + "API_BASE_URL": "https://www.ai4mats.com", "MCP_TRANSPORT": "stdio" } diff --git a/.opencode/skills/dataset/create_dataset/SKILL.md b/.opencode/skills/dataset/create_dataset/SKILL.md index 42bce46..a7bfe0b 100644 --- a/.opencode/skills/dataset/create_dataset/SKILL.md +++ b/.opencode/skills/dataset/create_dataset/SKILL.md @@ -5,7 +5,7 @@ triggers: - "新增数据集" - "创建数据集" metadata: - api-base: http://172.20.32.121:31213 + api-base: https://www.ai4mats.com --- # 创建数据集(调用接口) @@ -22,7 +22,6 @@ metadata: - 密码 `password` - 数据集名称 `name` - 数据集标签 `data_tag` - - 数据类型 `data_type`(可选,默认为"通用数据") - 若缺失,必须先向用户询问 2. **调用登录接口获取token** @@ -31,33 +30,52 @@ metadata: - 获取 `access_token` - 保存为临时变量 `token` -3. **创建数据集** - - 调用`scripts/dataset_mcp_server.create_dataset`方法 - - 参数:`token`(来自步骤2), `name`, `data_tag`, `data_type` +3. **获取父级分类列表** + - 调用`scripts/dataset_mcp_server.get_parent_categories`方法 + - 参数: `token`(来自步骤2) + - 返回父级分类列表,供用户选择需要展开的分类 -4. **反馈结果** +4. **选择需要展开的父级分类** + - 展示父级分类列表给用户 + - 询问用户需要展开哪个父级分类 + - 获取用户选择的父级分类ID `parent_id` + +5. **获取叶子节点列表** + - 调用`scripts/dataset_mcp_server.get_child_categories`方法 + - 参数: `token`(来自步骤2), `parent_id`(来自步骤4) + - 返回该父级分类下的所有叶子节点列表 + +6. **选择数据类型** + - 展示叶子节点列表给用户 + - 询问用户选择哪种数据类型 `data_type` + +7. **创建数据集** + - 调用`scripts/dataset_mcp_server.create_dataset`方法 + - 参数:`token`(来自步骤2), `name`, `data_tag`, `data_type`(来自步骤6) + +8. **反馈结果** - ✅ 成功:返回数据集名称和创建结果 - ❌ 失败:返回错误码和错误信息 -5. **询问是否创建数据集版本** +9. **询问是否创建数据集版本** - 如果创建数据集成功,则继续询问用户是否需要创建数据集版本 - 用户回答是则进行以下步骤,否则终止。 -6. **输入版本描述** +10. **输入版本描述** - 输入版本描述version_desc -7. **上传文件** +11. **上传文件** - 调用`scripts/upload_file.upload_file`方法分片上传文件 -8. **获取最新的版本号** +12. **获取最新的版本号** - 调用`scripts/dataset_mcp_server.query_next_version`方法获取最新的版本号 -9. **创建数据集版本** +13. **创建数据集版本** - 调用`scripts/dataset_mcp_server.create_dataset_version`方法 - - 参数:`token`(来自步骤2), `git_id`(来自步骤3), `id`(来自步骤3), `identifier`(来自步骤3), `file_path`(来自步骤7的输入), `file_data`(来自步骤7的结果), `name`:name, `owner`:username, `version`(来自步骤8), `version_desc`(来自步骤6) + - 参数:`token`(来自步骤2), `git_id`(来自步骤7), `id`(来自步骤7), `identifier`(来自步骤7), `file_path`(来自步骤11的输入), `file_data`(来自步骤11的结果), `name`:name, `owner`:username, `version`(来自步骤12), `version_desc`(来自步骤10) -10. **反馈结果** - - 打印第9步的参数 +14. **反馈结果** + - 打印第13步的参数 - ✅ 成功:返回创建数据集版本结果 - ❌ 失败:返回错误码和错误信息 @@ -66,24 +84,32 @@ metadata: ## 示例对话 **用户:** -> 帮我创建一个数据集,名字叫 test121,标签是 test,数据类型是通用数据 +> 帮我创建一个数据集,名字叫 test121,标签是 test **Agent 行为:** 1. 询问用户名和密码(如未知) 2. 调用登录接口获取token -3. 调用创建数据集 -4. 返回: - > ✅ 数据集 `test121` 创建成功 -5. 询问是否创建数据集版本 -6. 输入版本描述 -7. 上传文件 -8. 获取最新的版本号 -9. 创建数据集版本 -10. 反馈结果 +3. 调用获取父级分类列表接口,返回:知识层级数据 +4. 询问用户需要展开哪个父级分类 +5. 用户选择"知识层级数据" +6. 调用获取叶子节点列表接口,返回:通用数据、领域基础数据、领域专业数据 +7. 询问用户选择哪种数据类型 +8. 用户选择"通用数据" +9. 调用创建数据集 +10. 返回: + > ✅ 数据集 `test121` 创建成功 +11. 询问是否创建数据集版本 +12. 输入版本描述 +13. 上传文件 +14. 获取最新的版本号 +15. 创建数据集版本 +16. 反馈结果 --- ## 注意事项 - Token 有效期由服务端控制,过期需重新登录 - 不建议将用户名、密码、Token 写入日志 -- 创建失败时应明确提示是 **登录失败** 还是 **创建失败** \ No newline at end of file +- 创建失败时应明确提示是 **登录失败** 还是 **创建失败** +- 数据类型选择流程:先选择父级分类 → 展开叶子节点 → 选择叶子节点作为数据类型 +- 如用户直接指定数据类型名称,可调用`get_data_types`获取所有叶子节点进行匹配验证 \ No newline at end of file diff --git a/.opencode/skills/dataset/create_dataset/scripts/dataset_mcp_server.py b/.opencode/skills/dataset/create_dataset/scripts/dataset_mcp_server.py index 407aa09..54b5f70 100644 --- a/.opencode/skills/dataset/create_dataset/scripts/dataset_mcp_server.py +++ b/.opencode/skills/dataset/create_dataset/scripts/dataset_mcp_server.py @@ -20,7 +20,7 @@ async def create_dataset( } payload = { "name": name, - "preview_pic": "http://172.20.32.121:31213/minio/data/mini-model-platform-data/temp/fanshuai/1761528061144/dataset/电学材料.png", + "preview_pic": "https://www.ai4mats.com/minio/data/mini-model-platform-data/temp/fanshuai/1761528061144/dataset/电学材料.png", "dataset_source": "add", "data_type": data_type, "data_tag": data_tag, @@ -134,6 +134,177 @@ async def query_asset_icon( return f"❌ 查询数据集分类失败: {str(e)}" +@mcp.tool() +async def get_parent_categories(token: str) -> str: + """ + 获取父级分类列表,用于用户选择需要展开的分类 + + 参数: + - token: 访问令牌 + + 返回: 父级分类列表,格式为 {"code": 200, "msg": "操作成功", "data": [{"id": 137, "name": "知识层级数据"}, ...]} + """ + import json + + try: + asset_icon_result = await query_asset_icon(token) + + if isinstance(asset_icon_result, str): + try: + asset_icon_result = json.loads(asset_icon_result) + except: + return f"❌ 解析数据集分类失败" + + if asset_icon_result.get("code") != 200: + return f"❌ 获取数据集分类失败: {asset_icon_result.get('msg', '未知错误')}" + + data = asset_icon_result.get("data", []) + parent_categories = [] + + for category in data: + parent_categories.append({ + "id": category.get("id"), + "name": category.get("name"), + "category_id": category.get("category_id"), + "parent_id": category.get("parent_id") + }) + + return { + "code": 200, + "msg": "操作成功", + "data": parent_categories + } + + except Exception as e: + return f"❌ 获取父级分类列表失败: {str(e)}" + + +@mcp.tool() +async def get_child_categories(token: str, parent_id: int) -> str: + """ + 根据父级分类ID获取其下的叶子节点列表 + + 参数: + - token: 访问令牌 + - parent_id: 父级分类ID + + 返回: 叶子节点列表,格式为 {"code": 200, "msg": "操作成功", "data": [{"id": 138, "name": "通用数据", "parent_id": 137, "path": "icon-tongyongshuju"}, ...]} + """ + import json + + try: + asset_icon_result = await query_asset_icon(token) + + if isinstance(asset_icon_result, str): + try: + asset_icon_result = json.loads(asset_icon_result) + except: + return f"❌ 解析数据集分类失败" + + if asset_icon_result.get("code") != 200: + return f"❌ 获取数据集分类失败: {asset_icon_result.get('msg', '未知错误')}" + + data = asset_icon_result.get("data", []) + child_categories = [] + + for category in data: + if category.get("id") == parent_id: + second_list = category.get("second_asset_icon_list", []) + if second_list: + for item in second_list: + grandchild_list = item.get("second_asset_icon_list", []) + if grandchild_list: + for grandchild in grandchild_list: + child_categories.append({ + "id": grandchild.get("id"), + "name": grandchild.get("name"), + "parent_id": grandchild.get("parent_id"), + "path": grandchild.get("path") + }) + else: + child_categories.append({ + "id": item.get("id"), + "name": item.get("name"), + "parent_id": item.get("parent_id"), + "path": item.get("path") + }) + break + + return { + "code": 200, + "msg": "操作成功", + "data": child_categories + } + + except Exception as e: + return f"❌ 获取叶子节点列表失败: {str(e)}" + + +@mcp.tool() +async def get_data_types(token: str) -> str: + """ + 获取所有可用的数据类型列表(仅叶子节点),用于直接选择 + + 参数: + - token: 访问令牌 + + 返回: 所有叶子节点列表,格式为 {"code": 200, "msg": "操作成功", "data": [{"id": 138, "name": "通用数据", "parent_id": 137, "path": "icon-tongyongshuju"}, ...]} + """ + import json + + try: + asset_icon_result = await query_asset_icon(token) + + if isinstance(asset_icon_result, str): + try: + asset_icon_result = json.loads(asset_icon_result) + except: + return f"❌ 解析数据集分类失败" + + if asset_icon_result.get("code") != 200: + return f"❌ 获取数据集分类失败: {asset_icon_result.get('msg', '未知错误')}" + + data = asset_icon_result.get("data", []) + data_types = [] + + for category in data: + second_list = category.get("second_asset_icon_list", []) + if second_list: + for item in second_list: + grandchild_list = item.get("second_asset_icon_list", []) + if grandchild_list: + for grandchild in grandchild_list: + data_types.append({ + "id": grandchild.get("id"), + "name": grandchild.get("name"), + "parent_id": grandchild.get("parent_id"), + "path": grandchild.get("path") + }) + else: + data_types.append({ + "id": item.get("id"), + "name": item.get("name"), + "parent_id": item.get("parent_id"), + "path": item.get("path") + }) + else: + data_types.append({ + "id": category.get("id"), + "name": category.get("name"), + "parent_id": category.get("parent_id"), + "path": category.get("path") + }) + + return { + "code": 200, + "msg": "操作成功", + "data": data_types + } + + except Exception as e: + return f"❌ 获取数据类型列表失败: {str(e)}" + + if __name__ == "__main__": print(f"🚀 启动数据集 MCP 服务,传输模式: {TRANSPORT_MODE}") mcp.run(transport=TRANSPORT_MODE) \ No newline at end of file diff --git a/.opencode/skills/dataset/create_dataset/scripts/upload_file.py b/.opencode/skills/dataset/create_dataset/scripts/upload_file.py index f97a62f..f114930 100644 --- a/.opencode/skills/dataset/create_dataset/scripts/upload_file.py +++ b/.opencode/skills/dataset/create_dataset/scripts/upload_file.py @@ -6,8 +6,8 @@ import sys import time import httpx +from common.config import API_BASE_URL -API_BASE_URL = "http://172.20.32.121:31213" DEFAULT_SIZE = 10 * 1024 * 1024 # 10MB def compute_md5(file_path: str) -> str: diff --git a/test/test_dataset.py b/test/test_dataset.py index 5626df8..e29bb2e 100644 --- a/test/test_dataset.py +++ b/test/test_dataset.py @@ -10,6 +10,7 @@ from tools.dataset_mcp_server import ( login, add_dataset, get_asset_icon, + get_data_types, upload_chunk, add_version, update_dataset, @@ -74,6 +75,7 @@ async def main(): test_cases = [ ("查询数据集分类", get_asset_icon, {"token": token, **test_data["get_asset_icon"]}), + ("获取可用数据类型", get_data_types, {"token": token}), ("查询数据集列表", query_datasets, {"token": token, **test_data["query_datasets"]}), ] diff --git a/tools/app_deploy_mcp_server.py b/tools/app_deploy_mcp_server.py index c051f1f..c9f8f51 100644 --- a/tools/app_deploy_mcp_server.py +++ b/tools/app_deploy_mcp_server.py @@ -10,7 +10,7 @@ def load_config(): """加载配置""" config_path = os.path.join(os.path.dirname(__file__), "config.json") default_config = { - "API_BASE_URL": "http://172.20.32.121:31213" + "API_BASE_URL": "https://www.ai4mats.com" } try: diff --git a/tools/dataset_mcp_server.py b/tools/dataset_mcp_server.py index 945da4e..9acd761 100644 --- a/tools/dataset_mcp_server.py +++ b/tools/dataset_mcp_server.py @@ -6,7 +6,7 @@ import json def load_config(): config_path = os.path.join(os.path.dirname(__file__), "../config/config.json") default_config = { - "DATASET_API_BASE_URL": "http://172.20.32.121:31213", + "DATASET_API_BASE_URL": "https://www.ai4mats.com", "DATASET_DEFAULT_USERNAME": "fanshuai", "DATASET_DEFAULT_PASSWORD": "h1n2x3j4y5@", "MCP_TRANSPORT": "stdio" @@ -150,7 +150,7 @@ async def get_asset_icon( - size: 每页数量 (默认: 10000) - category_id: 分类ID (默认: 1) - 返回: 数据集分类列表。 + 返回: 数据集分类列表,包含一级分类和二级分类信息。 """ api_url = f"{API_BASE_URL}/api/mmp/assetIcon" @@ -175,6 +175,55 @@ async def get_asset_icon( except Exception as e: return f"查询数据集分类时发生未知错误: {str(e)}" +@mcp.tool() +async def get_data_types(token: str) -> str: + """ + 获取可用的数据集类型列表 + + 参数说明: + - token: 访问令牌 + + 返回: 可用的数据类型列表,格式为[{"id": 138, "name": "通用数据"}, ...] + """ + try: + asset_icon_result = await get_asset_icon(token) + asset_icon_data = json.loads(asset_icon_result) + + if asset_icon_data.get("code") != 200: + return f"获取数据集分类失败: {asset_icon_data.get('msg', '未知错误')}" + + data = asset_icon_data.get("data", []) + data_types = [] + + for category in data: + second_list = category.get("second_asset_icon_list", []) + if second_list: + for item in second_list: + data_types.append({ + "id": item.get("id"), + "name": item.get("name"), + "parent_id": item.get("parent_id"), + "path": item.get("path") + }) + else: + data_types.append({ + "id": category.get("id"), + "name": category.get("name"), + "parent_id": category.get("parent_id"), + "path": category.get("path") + }) + + return json.dumps({ + "code": 200, + "msg": "操作成功", + "data": data_types + }, indent=2, ensure_ascii=False) + + except json.JSONDecodeError as e: + return f"解析数据集分类失败: {str(e)}" + except Exception as e: + return f"获取数据类型列表时发生未知错误: {str(e)}" + @mcp.tool() async def upload_chunk( token: str,