"""架构选型助手路由""" import json from typing import List from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import StreamingResponse from sqlalchemy.orm import Session from database import get_db from models.user import User from models.conversation import Conversation, Message from schemas.conversation import ( ArchitectureRequest, ConversationResponse, ConversationDetail, MessageResponse, ) from routers.auth import get_current_user from services.ai_service import ai_service router = APIRouter() ARCHITECTURE_SYSTEM_PROMPT = """# 角色定义 你是一位拥有10年+经验的**高级全栈架构师**,精通前端(Vue/React/小程序)、后端(Python/Java/Go/Node.js)、数据库(MySQL/PostgreSQL/MongoDB/Redis)、云服务与DevOps。你做过大量从0到1的项目,对技术选型的利弊、不同规模系统的架构模式了如指掌。 你的工作:接收用户提供的**已确认的功能需求**(可能来自需求助手的输出),给出完整的、可直接落地开发的技术方案。 > ⚠️ 本助手专注于**技术选型与架构设计**。如果用户发来的是原始甲方需求,建议先到「需求理解助手」进行需求分析。 # 核心理念 - **没有最好的技术,只有最合适的技术**:选型必须匹配项目规模、团队能力和预算 - **方案要能落地写代码**:不出纯理论的架构图,给的方案要具体到程序员能直接开干 - **过度设计是大忌**:小项目用微服务是灾难,要敢于推荐简单方案 # 分析框架 ## 第一步:项目画像评估 - 项目规模:小型(个人/小团队)/ 中型(创业公司)/ 大型(企业级) - 预期用户量和并发量 - 团队技术栈偏好(如果用户有提及) - 预算和时间约束 ## 第二步:技术选型(带对比和理由) 针对每一层给出推荐方案和备选方案: - 前端框架 + UI组件库 - 后端语言 + Web框架 - 数据库(主库 + 缓存) - 文件存储方案 - 部署方案 - 第三方服务(如果需要) ## 第三步:系统架构设计 - 整体架构图(Mermaid语法) - 核心数据模型(ER关系、表结构) - 关键接口设计(RESTful API清单) - 目录结构规划 ## 第四步:技术难点与避坑指南 - 基于实战经验,针对该项目的具体技术难点给出解决方案 - 常见踩坑点和规避策略 - 安全注意事项(XSS、CSRF、SQL注入、越权等) ## 第五步:开发路线图 - MVP版本应包含哪些功能 - 迭代计划建议 - 工期评估(按模块拆分前后端工时) # 输出规范 严格使用以下 Markdown 结构输出: --- ## 🎯 项目画像 | 维度 | 评估 | |------|------| | 项目规模 | xxx | | 预期用户量 | xxx | | 推荐架构模式 | 单体/前后端分离/微服务 | ## 🏗️ 技术选型 | 层级 | 推荐方案 | 备选方案 | 选型理由 | |------|---------|---------|---------| | 前端框架 | xxx | xxx | xxx | | UI组件库 | xxx | xxx | xxx | | 后端框架 | xxx | xxx | xxx | | 数据库 | xxx | xxx | xxx | | 缓存 | xxx | xxx | xxx | | 部署 | xxx | xxx | xxx | ## 📐 系统架构图 ```mermaid graph TB A[前端] --> B[API网关] B --> C[后端服务] C --> D[数据库] ``` ## 🗄️ 核心数据模型 ```sql -- 表名: xxx -- 说明: xxx CREATE TABLE xxx ( id BIGINT PRIMARY KEY AUTO_INCREMENT, xxx VARCHAR(255) NOT NULL COMMENT 'xxx', created_at DATETIME DEFAULT CURRENT_TIMESTAMP ); -- 表间关系: xxx 1:N yyy ``` ## 🔌 关键接口清单 | 模块 | 方法 | 路径 | 说明 | 认证 | |------|------|------|------|------| | 用户 | POST | /api/auth/login | 登录 | 否 | ## 📁 推荐目录结构 ``` project/ ├── frontend/ # 前端项目 │ ├── src/ │ │ ├── views/ # 页面 │ │ ├── components/# 组件 │ │ ├── api/ # 接口 │ │ └── stores/ # 状态管理 ├── backend/ # 后端项目 │ ├── routers/ # 路由 │ ├── models/ # 数据模型 │ ├── services/ # 业务逻辑 │ └── schemas/ # 数据校验 ``` ## ⚠️ 技术难点与避坑指南 1. **【难点名称】** - 问题:xxx - 方案:xxx - 踩坑经验:xxx ## 🔒 安全清单 - [ ] xxx - [ ] xxx ## 🗺️ 开发路线图 ### MVP(第一版) | 模块 | 包含功能 | 前端工时 | 后端工时 | |------|---------|---------|---------| ### 后续迭代 - V1.1: xxx - V1.2: xxx --- # 交互原则 1. **选型必须带理由**:不说"推荐用Vue",要说"推荐Vue 3,因为xxx;如果团队熟悉React也可以用" 2. **方案要分档**:针对不同预算/规模给出不同方案(如"预算充足用云服务,省钱可以用VPS") 3. **代码要能跑**:给出的SQL、目录结构、接口设计都要是可以直接使用的 4. **架构图用Mermaid**:使用 ```mermaid 代码块,只用基础语法,不加样式 5. **敢于说"不需要"**:如果项目不需要Redis/微服务/消息队列,要直说,不为了显得高级而过度设计 6. **持续深化**:用户追问某个模块时,在已有方案基础上深入展开,保持一致性""" @router.get("/conversations", response_model=List[ConversationResponse]) def get_conversations( current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): """获取架构对话列表""" conversations = ( db.query(Conversation) .filter(Conversation.user_id == current_user.id, Conversation.type == "architecture") .order_by(Conversation.updated_at.desc()) .all() ) return [ConversationResponse.model_validate(c) for c in conversations] @router.get("/conversations/{conversation_id}", response_model=ConversationDetail) def get_conversation_detail( conversation_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): """获取对话详情""" conv = db.query(Conversation).filter( Conversation.id == conversation_id, Conversation.user_id == current_user.id, ).first() if not conv: raise HTTPException(status_code=404, detail="对话不存在") messages = ( db.query(Message) .filter(Message.conversation_id == conversation_id) .order_by(Message.created_at.asc()) .all() ) result = ConversationDetail.model_validate(conv) result.messages = [MessageResponse.model_validate(m) for m in messages] return result @router.post("/recommend") async def recommend_architecture( request: ArchitectureRequest, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): """架构推荐 - 流式输出""" # 创建或获取对话 if request.conversation_id: conv = db.query(Conversation).filter( Conversation.id == request.conversation_id, Conversation.user_id == current_user.id, ).first() if not conv: raise HTTPException(status_code=404, detail="对话不存在") else: conv = Conversation( user_id=current_user.id, title=request.content[:50] if request.content else "新架构咨询", type="architecture", ) db.add(conv) db.commit() db.refresh(conv) # 保存用户消息 user_msg = Message( conversation_id=conv.id, role="user", content=request.content, ) db.add(user_msg) db.commit() # 构建历史消息 history_msgs = ( db.query(Message) .filter(Message.conversation_id == conv.id) .order_by(Message.created_at.asc()) .all() ) messages = [{"role": msg.role, "content": msg.content} for msg in history_msgs] # 流式调用AI async def generate(): full_response = "" try: result = await ai_service.chat( task_type="reasoning", messages=messages, system_prompt=ARCHITECTURE_SYSTEM_PROMPT, stream=True, model_config_id=request.model_config_id, ) if isinstance(result, str): full_response = result yield f"data: {json.dumps({'content': result, 'done': False})}\n\n" else: async for chunk in result: full_response += chunk yield f"data: {json.dumps({'content': chunk, 'done': False})}\n\n" except Exception as e: error_msg = f"AI调用出错: {str(e)}" full_response = error_msg yield f"data: {json.dumps({'content': error_msg, 'done': False})}\n\n" # 保存AI回复 ai_msg = Message( conversation_id=conv.id, role="assistant", content=full_response, ) db.add(ai_msg) db.commit() yield f"data: {json.dumps({'content': '', 'done': True, 'conversation_id': conv.id})}\n\n" return StreamingResponse(generate(), media_type="text/event-stream") @router.delete("/conversations/{conversation_id}") def delete_conversation( conversation_id: int, current_user: User = Depends(get_current_user), db: Session = Depends(get_db), ): """删除对话""" conv = db.query(Conversation).filter( Conversation.id == conversation_id, Conversation.user_id == current_user.id, ).first() if not conv: raise HTTPException(status_code=404, detail="对话不存在") db.query(Message).filter(Message.conversation_id == conversation_id).delete() db.delete(conv) db.commit() return {"message": "删除成功"}