diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6786de1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,228 @@ +# Dependencies +node_modules/ +__pycache__/ +*.pyc +*.pyo +*.pyd +.Python +env/ +venv/ +.venv/ +pip-log.txt +pip-delete-this-directory.txt + +# Build outputs +dist/ +build/ +*.egg-info/ +*.egg +.next/ +out/ + +# Environment variables +.env +.env.local +.env.development.local +.env.test.local +.env.production.local +*.env + +# IDE and editor files +.vscode/ +.idea/ +*.swp +*.swo +*~ +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Runtime data +pids/ +*.pid +*.seed +*.pid.lock + +# Coverage directory used by tools like istanbul +coverage/ +*.lcov + +# nyc test coverage +.nyc_output + +# Dependency directories +jspm_packages/ + +# Optional npm cache directory +.npm + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next + +# Nuxt.js build / generate output +.nuxt + +# Gatsby files +.cache/ +public + +# Storybook build outputs +.out +.storybook-out + +# Temporary folders +tmp/ +temp/ + +# Database files +*.db +*.sqlite +*.sqlite3 + +# Python specific +*.py[cod] +*$py.class +*.so +.Python +build/ +develop-eggs/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.whl +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Scrapy stuff +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +Pipfile.lock + +# PEP 582 +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Project specific +.claude/ +.ruff_cache/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..5e53668 --- /dev/null +++ b/README.md @@ -0,0 +1,121 @@ +# Interactive Mindmap + +基于 Next.js、FastAPI 和 SQLite 的交互式思维导图应用,支持通过腾讯云 AI Agent 对话生成思维导图。 + +## 项目结构 + +``` +mindmap/ +├── backend/ # FastAPI 后端 +│ ├── app/ +│ │ ├── main.py # 应用入口 +│ │ ├── config.py # 配置 +│ │ ├── database.py # 数据库 +│ │ ├── models.py # 数据模型 +│ │ ├── schemas.py # Pydantic schemas +│ │ └── routers/ +│ │ ├── mindmaps.py # 思维导图 CRUD API +│ │ └── chat.py # AI 对话代理 (SSE) +│ ├── data/ # SQLite 数据库文件 +│ ├── requirements.txt +│ └── .env.example +├── frontend/ # Next.js 前端 +│ ├── app/ +│ │ ├── page.tsx # 首页 +│ │ └── mindmap/ +│ │ ├── [id]/page.tsx # 思维导图详情页 +│ │ └── chat/page.tsx # AI 对话 + 思维导图页 +│ ├── components/ +│ │ ├── MindmapCanvas.tsx # 思维导图画布 +│ │ ├── MindmapNodeCard.tsx # 节点卡片 +│ │ ├── ChatPanel.tsx # 聊天面板 +│ │ └── CreateMindmapForm.tsx # 创建表单 +│ ├── lib/ +│ │ ├── api.ts # API 调用 +│ │ └── treeToGraph.ts # 树转图布局 +│ └── types/ +│ └── mindmap.ts # TypeScript 类型 +└── mind_prompt.md # AI Agent 系统提示词 +``` + +## 环境配置 + +### 后端 + +1. 安装依赖: + +```bash +cd backend +pip install -r requirements.txt +``` + +2. 配置环境变量: + +```bash +# 复制示例配置 +cp .env.example .env + +# 编辑 .env,填入腾讯云 AI Agent 的 bot_app_key +TENCENT_BOT_APP_KEY=your-key-here +``` + +3. 启动后端: + +```bash +TENCENT_BOT_APP_KEY=your-key-here uvicorn app.main:app --reload +``` + +### 前端 + +1. 安装依赖: + +```bash +cd frontend +npm install +``` + +2. 启动开发服务器: + +```bash +npm run dev +``` + +## 页面说明 + +### 首页 `/` + +输入主题创建思维导图(使用 mock 数据)。 + +### 思维导图详情 `/mindmap/[id]` + +查看已保存的思维导图,支持节点展开/收缩。 + +### AI 对话生成 `/mindmap/chat?sessionId=xxx` + +通过与腾讯云 AI Agent 对话生成思维导图: + +- **左侧**: 思维导图画布,初始为空,AI 返回有效数据后自动渲染 +- **右侧**: 聊天面板,支持实时 SSE 流式响应 + +URL 参数: +- `sessionId` (必填): 会话 ID,用于标识对话会话 + +## 数据流 + +``` +用户输入 → ChatPanel → POST /api/chat → 后端代理 → 腾讯云 SSE API + ↓ +画布更新 ← onMindmapUpdate ← JSON 解析 ← SSE 流式响应 ←─┘ +``` + +1. 用户在聊天面板输入消息 +2. 前端发送 POST 请求到后端 `/api/chat` +3. 后端将请求代理到腾讯云 AI Agent SSE 接口 +4. SSE 流式响应逐步返回到前端 +5. 前端解析 SSE 事件,逐步显示 AI 回复 +6. 当 AI 回复完成后,尝试从回复中提取思维导图 JSON +7. 如果提取成功,更新左侧画布 + +## AI Agent 配置 + +参见 [mind_prompt.md](./mind_prompt.md) 获取 AI Agent 的系统提示词配置。 diff --git a/help.md b/help.md new file mode 100644 index 0000000..6e459c5 --- /dev/null +++ b/help.md @@ -0,0 +1,176 @@ +# 思维导图工具使用说明 + +## 概述 + +本工具用于对接腾讯云智能体平台,实现思维导图的可视化展示和交互式对话。 + +## 工作流程 + +``` +腾讯云智能体平台 → 发送sessionID和思维导图JSON → 本系统存储并返回URL → 用户访问URL查看思维导图 → 点击节点触发AI对话 +``` + +## API 接口 + +### 1. 创建思维导图 + +**请求** + +``` +POST /api/mindmaps +Content-Type: application/json + +{ + "session_id": "腾讯云对话sessionID", + "mindmap_json": { + "id": "node_0", + "label": "机器学习", + "parent_id": null, + "level": 0, + "is_leaf": false, + "children": [ + { + "id": "node_1", + "label": "监督学习", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [] + } + ] + } +} +``` + +**响应** + +```json +{ + "id": 1, + "unique_id": "abc123xyz", + "session_id": "腾讯云对话sessionID", + "title": "机器学习", + "raw_json": "{...}", + "tree": {...}, + "url": "http://localhost:3000/mindmap/abc123xyz", + "created_at": "2026-03-20T12:00:00", + "updated_at": "2026-03-20T12:00:00" +} +``` + +**说明** +- `session_id`: 腾讯云智能体平台的对话sessionID,用于后续节点点击时的对话 +- `mindmap_json`: 思维导图的JSON数据,标题从根节点的`label`字段自动提取 +- `url`: 返回的唯一访问链接,可直接发送给用户 + +### 2. 获取思维导图 + +**请求** + +``` +GET /api/mindmaps/{unique_id} +``` + +**响应** + +与创建接口返回格式相同 + +### 3. 对话接口 + +**请求** + +``` +POST /api/chat +Content-Type: application/json + +{ + "session_id": "腾讯云对话sessionID", + "content": "帮我解释一下监督学习" +} +``` + +**响应** + +SSE流式响应,转发腾讯云智能体平台的对话结果 + +## 思维导图JSON格式 + +```json +{ + "id": "node_0", + "label": "根节点标题", + "parent_id": null, + "level": 0, + "is_leaf": false, + "children": [ + { + "id": "node_1", + "label": "子节点标题", + "parent_id": "node_0", + "level": 1, + "is_leaf": true, + "children": [] + } + ] +} +``` + +**字段说明** + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | string | 节点唯一标识 | +| `label` | string | 节点显示文本 | +| `parent_id` | string \| null | 父节点ID,根节点为null | +| `level` | number | 节点层级,根节点为0 | +| `is_leaf` | boolean | 是否为叶子节点 | +| `children` | array | 子节点数组 | + +## 前端交互 + +1. **查看思维导图**: 用户访问返回的URL即可查看思维导图 +2. **展开/折叠节点**: 点击有子节点的节点可展开或折叠 +3. **触发AI对话**: 点击任意节点,右侧聊天面板会自动显示并发送"帮我解释一下{节点内容}"到腾讯云智能体平台 +4. **继续对话**: 用户可在聊天面板中继续与AI对话 + +## 环境变量配置 + +后端 `.env` 文件: + +```env +# 腾讯云智能体平台 AppKey +# 获取方式:应用管理 → 找到运行中的应用 → 点击"调用" → 复制AppKey +BOT_APP_KEY=your-app-key-here + +# 前端基础URL(用于生成思维导图链接) +FRONTEND_BASE_URL=http://localhost:3000 +``` + +前端 `.env.local` 文件: + +```env +# 后端API地址 +NEXT_PUBLIC_API_BASE_URL=http://127.0.0.1:8000 +``` + +## 启动方式 + +### 后端 + +```bash +cd backend +pip install -r requirements.txt +uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 +``` + +### 前端 + +```bash +cd frontend +npm install +npm run dev +``` + +## 腾讯云智能体平台配置 + +在腾讯云智能体平台的系统提示词中,指导AI返回符合上述格式的思维导图JSON。参考 `mind_prompt.md` 文件中的示例提示词。 diff --git a/mind_prompt.md b/mind_prompt.md new file mode 100644 index 0000000..ffb1b68 --- /dev/null +++ b/mind_prompt.md @@ -0,0 +1,178 @@ +# 思维导图 AI Agent 系统提示词 + +将以下内容配置为腾讯云 AI Agent 的系统提示词(System Prompt): + +--- + +你是一个思维导图生成助手。当用户提出一个主题时,你需要生成一个结构化的思维导图 JSON 数据。 + +## 输出格式 + +你必须严格按照以下 JSON Schema 输出思维导图数据,不要包含任何额外的解释文字,只返回 JSON: + +```json +{ + "id": "node_0", + "label": "根节点标题", + "parent_id": null, + "level": 0, + "is_leaf": false, + "children": [ + { + "id": "node_1", + "label": "子节点标题", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [ + { + "id": "node_4", + "label": "叶子节点", + "parent_id": "node_1", + "level": 2, + "is_leaf": true, + "children": [] + } + ] + } + ] +} +``` + +## 字段说明 + +| 字段 | 类型 | 说明 | +|------|------|------| +| `id` | string | 节点唯一标识,格式为 `node_N`(N 从 0 开始递增) | +| `label` | string | 节点显示文本 | +| `parent_id` | string \| null | 父节点 ID,根节点为 null | +| `level` | number | 节点层级,根节点为 0 | +| `is_leaf` | boolean | 是否为叶子节点(无子节点时为 true) | +| `children` | array | 子节点数组,叶子节点为空数组 `[]` | + +## 规则 + +1. 根节点的 `label` 应为用户提出的主题 +2. 建议生成 3-5 个一级子节点 +3. 每个一级子节点下建议生成 2-4 个二级子节点 +4. 最多不超过 3 层(level 0, 1, 2) +5. **必须** 将整个 JSON 放在 ` ```json ``` ` 代码块内返回 +6. 除了 JSON 代码块外,不要输出任何其他文字 + +## 示例 + +用户输入:`机器学习` + +你应该返回: + +```json +{ + "id": "node_0", + "label": "机器学习", + "parent_id": null, + "level": 0, + "is_leaf": false, + "children": [ + { + "id": "node_1", + "label": "监督学习", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [ + { + "id": "node_5", + "label": "线性回归", + "parent_id": "node_1", + "level": 2, + "is_leaf": true, + "children": [] + }, + { + "id": "node_6", + "label": "决策树", + "parent_id": "node_1", + "level": 2, + "is_leaf": true, + "children": [] + } + ] + }, + { + "id": "node_2", + "label": "无监督学习", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [ + { + "id": "node_7", + "label": "聚类分析", + "parent_id": "node_2", + "level": 2, + "is_leaf": true, + "children": [] + }, + { + "id": "node_8", + "label": "降维", + "parent_id": "node_2", + "level": 2, + "is_leaf": true, + "children": [] + } + ] + }, + { + "id": "node_3", + "label": "强化学习", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [ + { + "id": "node_9", + "label": "Q-Learning", + "parent_id": "node_3", + "level": 2, + "is_leaf": true, + "children": [] + }, + { + "id": "node_10", + "label": "策略梯度", + "parent_id": "node_3", + "level": 2, + "is_leaf": true, + "children": [] + } + ] + }, + { + "id": "node_4", + "label": "深度学习", + "parent_id": "node_0", + "level": 1, + "is_leaf": false, + "children": [ + { + "id": "node_11", + "label": "卷积神经网络", + "parent_id": "node_4", + "level": 2, + "is_leaf": true, + "children": [] + }, + { + "id": "node_12", + "label": "循环神经网络", + "parent_id": "node_4", + "level": 2, + "is_leaf": true, + "children": [] + } + ] + } + ] +} +``` diff --git a/test_api.py b/test_api.py new file mode 100644 index 0000000..c6f0a5f --- /dev/null +++ b/test_api.py @@ -0,0 +1,155 @@ +import requests + +BASE_URL = "http://127.0.0.1:8000" + + +def test_create_mindmap(): + payload = { + "session_id": "test-session-123456", + "mindmap_json": { + "id": "node_0", + "label": "Python编程", + "parent_id": None, + "level": 0, + "is_leaf": False, + "children": [ + { + "id": "node_1", + "label": "基础语法", + "parent_id": "node_0", + "level": 1, + "is_leaf": False, + "children": [ + { + "id": "node_5", + "label": "变量与数据类型", + "parent_id": "node_1", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_6", + "label": "控制流程", + "parent_id": "node_1", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_7", + "label": "函数定义", + "parent_id": "node_1", + "level": 2, + "is_leaf": True, + "children": [], + }, + ], + }, + { + "id": "node_2", + "label": "面向对象", + "parent_id": "node_0", + "level": 1, + "is_leaf": False, + "children": [ + { + "id": "node_8", + "label": "类与对象", + "parent_id": "node_2", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_9", + "label": "继承与多态", + "parent_id": "node_2", + "level": 2, + "is_leaf": True, + "children": [], + }, + ], + }, + { + "id": "node_3", + "label": "常用库", + "parent_id": "node_0", + "level": 1, + "is_leaf": False, + "children": [ + { + "id": "node_10", + "label": "NumPy", + "parent_id": "node_3", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_11", + "label": "Pandas", + "parent_id": "node_3", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_12", + "label": "Requests", + "parent_id": "node_3", + "level": 2, + "is_leaf": True, + "children": [], + }, + ], + }, + { + "id": "node_4", + "label": "应用场景", + "parent_id": "node_0", + "level": 1, + "is_leaf": False, + "children": [ + { + "id": "node_13", + "label": "Web开发", + "parent_id": "node_4", + "level": 2, + "is_leaf": True, + "children": [], + }, + { + "id": "node_14", + "label": "数据分析", + "parent_id": "node_4", + "level": 2, + "is_leaf": True, + "children": [], + }, + ], + }, + ], + }, + } + + response = requests.post(f"{BASE_URL}/api/mindmaps", json=payload) + print("=== 创建思维导图 ===") + print(f"状态码: {response.status_code}") + result = response.json() + print(f"访问链接: {result['url']}") + print(f"标题: {result['title']}") + print(f"unique_id: {result['unique_id']}") + return result + + +def test_get_mindmap(unique_id): + response = requests.get(f"{BASE_URL}/api/mindmaps/{unique_id}") + print("\n=== 获取思维导图 ===") + print(f"状态码: {response.status_code}") + print(f"标题: {response.json()['title']}") + + +if __name__ == "__main__": + result = test_create_mindmap() + test_get_mindmap(result["unique_id"])