要求写一个AI问诊网站的详细方案,包括UML建模、项目文件结构、以及完整源代码。并用Markdown和Mermaid来建立文档。需要前后端分离:前端用HTML/CSS/JS,后端用Python,调用“火山引擎”的DeepSeek。但火山引擎有提供DeepSeek模型的API吗?是的,火山引擎的方舟平台提供了DeepSeek模型的API。所以将使用火山引擎DeepSeek API。

需要实现的功能:用户在前端填写表单(问诊信息),提交给后端,后端调用AI进行多轮回答(可能意味着与AI进行多轮对话以收集信息,然后生成诊断报告?),最后给出固定格式的报告打印。

用户只需要简单进行项目选择填写。这意味着前端可能是简单的表单,包含一些病症描述、症状选择等。

要提供完整的项目搭建过程,包括云服务器部署。但源代码部分,需要提供前端的HTML、CSS、JavaScript文件,后端的Python文件(如Flask或FastAPI)。并说明如何部署。

需求中要求用UML建模,并用Mermaid画出。可以在文档中嵌入Mermaid图,如用例图、类图(如果是后端的话,但后端主要是API调用,可能没有复杂的类)、时序图(展示前后端交互以及调用AI的过程)、部署图等。

项目结构组织:建议如下:


ai_consultation/
├── backend/
│   ├── app.py                # Flask/FastAPI主应用
│   ├── requirements.txt      # Python依赖
│   ├── config.py             # 配置(API密钥等)
│   └── ...
├── frontend/
│   ├── index.html            # 主页面
│   ├── css/
│   │   └── style.css
│   ├── js/
│   │   └── script.js
│   └── ...
└── README.md                 # 项目说明

后端需要调用火山引擎DeepSeek API。需要注册火山引擎账号,获取API密钥和模型Endpoint。在config.py中配置。

前端表单需要包含什么?既然是问诊,需要年龄、性别、主诉、症状描述、持续时间、既往病史等。也可以提供一些选项让用户选择,比如症状列表(头痛、发烧等),用户要求“只需要简单进行项目选择填写”,所以可以用下拉框、单选框、复选框等简化输入。

后端接收到表单数据后,需要构造一个提示词给AI,模拟医生问诊的多轮对话。但真正的多轮对话需要维护状态。可以简化:后端根据用户提交的信息,构造一个初始消息给AI,然后AI可能会返回一些追问,后端再根据用户的回答(但用户只提交了一次表单,没有多轮交互)?这可能不符合“多轮回答”的要求。或许需要前端与AI进行多轮对话,但用户描述是“用户在前端应用程序中填写,填完之后发送给后端应用程序,后端调用AI进行多轮回答”。这可能意味着用户一次性填写所有信息,然后后端模拟AI进行多轮问答来生成诊断?或者后端调用AI进行多次交互,但用户已经提供了所有信息,所以后端可以模拟多轮对话(比如让AI扮演医生,根据用户提供的信息进行问诊,然后输出一段对话和诊断)。我们可以这样做:后端构造一个提示,让AI以医生的身份,根据用户提供的症状信息,进行多轮问诊(模拟问答),并最终给出诊断建议和报告。然后后端将AI生成的报告返回给前端。前端可以显示报告并提供打印功能。

或者更简单的:后端将用户信息发给AI,要求AI生成诊断报告,并返回固定格式的报告。这样就不需要多轮了。但题目明确要求“多轮回答”,所以尽量体现多轮。

可以这样设计:用户填写基本信息后,后端与AI进行多轮对话,模拟医生逐步提问和患者回答的过程。但患者的所有信息已经提供,所以需要设计一个对话生成方式:让AI基于已有信息,生成一系列问答对,最终生成诊断。但这样不是真正的交互,而是模拟多轮。用户期望的是真正的多轮对话,但那样需要前端与后端多次交互,比较复杂。考虑到“实现简单”和“用户只需要简单进行项目选择填写”,倾向于一次性填写,后端模拟多轮对话生成报告。

为了满足“多轮回答”,可以让后端构造一个提示,要求AI模拟多轮问诊过程,并输出一个包含多轮对话和最终诊断的报告。这样在报告中会包含多个问答回合。

报告格式可以是文本,也可以是结构化的JSON,然后前端显示。打印功能可以通过浏览器的window.print实现。

所以整体流程:

  1. 用户在前端填写表单(姓名、年龄、性别、症状描述、持续时间、既往病史等)。

  2. 点击提交,前端通过AJAX POST请求将数据发送到后端API(如/consult)。

  3. 后端接收数据,调用火山引擎DeepSeek API,构造提示词,获取AI生成的报告。

  4. 后端解析AI返回的内容,返回给前端。

  5. 前端显示报告,并提供“打印报告”按钮,调用window.print。

需要确保AI返回的内容格式固定。可以通过提示词要求AI以特定格式输出,例如包含“【问诊过程】”和“【诊断建议】”等部分。

后端使用Flask或FastAPI。选择Flask因为简单。

现在开始写详细方案文档,包括UML图,然后提供源代码。

注意:要求“用UML建模并提供具体详尽深入的方案,用Markdown,mermind建立文档”。所以要在Markdown中嵌入Mermaid代码块,渲染UML图。

可以在文档中包括:

  • 用例图:展示用户与系统的交互。

  • 类图:后端可能用到的类(如Config、AIService等),但可以简单。

  • 时序图:展示用户前端操作、后端、API之间的交互。

  • 部署图:展示云服务器部署架构。

然后提供项目结构说明。

源代码部分:提供完整的文件内容。

最后,说明如何部署到云服务器。

需要确保使用火山引擎API的细节。因为这里没有实际的API密钥,所以代码中需要用户自行配置。在代码中会留出位置。

现在开始撰写回答。

AI问诊网站:详细设计方案与实现

1. 项目概述

本项目是一个基于Web的AI问诊系统,用户在前端填写基本信息(症状、病史等),后端调用火山引擎DeepSeek API进行多轮模拟问诊,生成结构化报告并支持打印。项目采用前后端分离架构,前端使用HTML/CSS/JavaScript,后端使用Python(Flask框架),部署于云服务器。

2. 功能需求

  • 前端:提供表单供用户输入个人信息和症状描述,提交后显示AI生成的问诊报告,并支持报告打印。
  • 后端:接收前端数据,构造提示词调用DeepSeek API,返回固定格式的报告。
  • AI集成:利用火山引擎DeepSeek模型进行多轮问答模拟,生成诊断建议。

3. 技术选型

  • 前端:HTML5、CSS3、JavaScript(原生,无框架)
  • 后端:Python 3.8+、Flask、Requests库
  • AI服务:火山引擎DeepSeek API(需注册获取Access Key和Endpoint)
  • 部署:云服务器(如阿里云、腾讯云),Ubuntu 20.04,Nginx + Gunicorn

4. UML建模

4.1 用例图

用户

填写问诊表单

查看报告

打印报告

系统

提交表单数据

后端调用AI

返回报告

4.2 类图(后端简化)

uses

reads

Config

+API_KEY: str

+API_URL: str

+MODEL: str

AIService

+generate_report(user_data: dict) : : str

-_call_api(prompt: str) : : str

FlaskApp

+app: Flask

+routes()

4.3 时序图

火山引擎API Flask后端 前端页面 用户 火山引擎API Flask后端 前端页面 用户 填写表单并提交 POST /consult (表单数据) 构造提示词 发送HTTP请求(含API密钥) 返回AI生成文本 解析格式化为报告 返回JSON(含报告) 显示报告 点击打印按钮 调用浏览器打印

4.4 部署图

渲染错误: Mermaid 渲染失败: Parse error on line 7: ...r(用户浏览器) --> Nginx: HTTP/HTTPS Flask -----------------------^ Expecting 'SEMI', 'NEWLINE', 'EOF', 'AMP', 'START_LINK', 'LINK', 'LINK_ID', got 'NODE_STRING'

5. 项目文件结构

ai_consultation/
├── backend/
│   ├── app.py                # Flask主程序
│   ├── config.py             # 配置文件(API密钥等)
│   ├── ai_service.py          # AI调用封装
│   ├── requirements.txt       # 依赖列表
│   └── utils.py               # 辅助函数(如报告解析)
├── frontend/
│   ├── index.html             # 主页面
│   ├── css/
│   │   └── style.css          # 样式表
│   ├── js/
│   │   └── script.js          # 前端交互逻辑
│   └── assets/                # 静态资源(如图标)
├── README.md                   # 项目说明
└── deploy/                     # 部署相关配置(可选)
    └── nginx.conf

6. 详细实现

6.1 后端实现

6.1.1 config.py
import os

class Config:
    # 火山引擎API配置(请替换为实际值)
    API_KEY = "your-volcano-api-key"
    API_URL = "https://ark.cn-beijing.volces.com/api/v3/chat/completions"  # 示例地址
    MODEL = "deepseek-r1"  # 模型名称,根据火山引擎实际命名
    TIMEOUT = 60
6.1.2 ai_service.py
import requests
import json
from config import Config

class AIService:
    @staticmethod
    def generate_report(user_data):
        """
        调用DeepSeek API生成问诊报告
        :param user_data: 前端提交的字典,包含姓名、年龄、性别、症状描述等
        :return: 生成的报告文本
        """
        prompt = AIService._build_prompt(user_data)
        response_text = AIService._call_api(prompt)
        return AIService._format_report(response_text)

    @staticmethod
    def _build_prompt(data):
        """
        构造提示词,要求AI模拟多轮问诊并输出报告
        """
        name = data.get('name', '患者')
        age = data.get('age', '未知')
        gender = data.get('gender', '未知')
        symptoms = data.get('symptoms', '未描述')
        duration = data.get('duration', '未知')
        history = data.get('history', '无')
        additional = data.get('additional', '')

        prompt = f"""你是一位经验丰富的全科医生,请根据以下患者信息进行多轮问诊模拟,并最终给出诊断建议和报告。
要求:
1. 模拟至少三轮问答(医生提问和患者回答),基于已有信息合理展开。
2. 最后输出【诊断建议】部分,包括可能的疾病、进一步检查建议和初步处理意见。
3. 输出格式清晰,包含【问诊过程】和【诊断建议】两个主要部分。

患者信息:
姓名:{name}
年龄:{age}
性别:{gender}
主诉症状:{symptoms}
症状持续时间:{duration}
既往病史:{history}
其他补充:{additional}

请开始模拟问诊:"""
        return prompt

    @staticmethod
    def _call_api(prompt):
        """
        发送请求到火山引擎DeepSeek API
        """
        headers = {
            "Authorization": f"Bearer {Config.API_KEY}",
            "Content-Type": "application/json"
        }
        payload = {
            "model": Config.MODEL,
            "messages": [
                {"role": "system", "content": "你是一位专业、耐心的医生。"},
                {"role": "user", "content": prompt}
            ],
            "temperature": 0.7,
            "max_tokens": 2000
        }
        try:
            response = requests.post(
                Config.API_URL,
                headers=headers,
                json=payload,
                timeout=Config.TIMEOUT
            )
            response.raise_for_status()
            result = response.json()
            # 假设返回格式为 { "choices": [ { "message": { "content": "..." } } ] }
            return result['choices'][0]['message']['content']
        except Exception as e:
            return f"AI调用失败: {str(e)}"

    @staticmethod
    def _format_report(raw_text):
        """
        对AI返回文本进行后处理(如需结构化可在此扩展)
        目前直接返回原始文本,但可确保包含必要的标题
        """
        # 确保报告包含预期格式
        if "【问诊过程】" not in raw_text and "【诊断建议】" not in raw_text:
            raw_text = "【问诊过程】\n" + raw_text + "\n\n【诊断建议】\n(AI未能按格式生成)"
        return raw_text
6.1.3 app.py
from flask import Flask, request, jsonify
from flask_cors import CORS  # 处理跨域
from ai_service import AIService

app = Flask(__name__)
CORS(app)  # 允许所有跨域请求,生产环境应限制

@app.route('/consult', methods=['POST'])
def consult():
    """
    接收前端表单数据,调用AI生成报告,返回JSON
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({'error': '无效的请求数据'}), 400

        # 调用AI服务
        report = AIService.generate_report(data)
        return jsonify({'success': True, 'report': report})
    except Exception as e:
        return jsonify({'error': str(e)}), 500

@app.route('/health', methods=['GET'])
def health():
    return jsonify({'status': 'ok'})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)  # debug模式仅开发使用
6.1.4 requirements.txt
Flask==2.3.3
flask-cors==4.0.0
requests==2.31.0
gunicorn==21.2.0  # 生产环境用

6.2 前端实现

6.2.1 index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>AI问诊助手</title>
    <link rel="stylesheet" href="css/style.css">
</head>
<body>
    <div class="container">
        <header>
            <h1>智能问诊系统</h1>
            <p>请填写以下信息,AI将为您模拟多轮问诊并生成报告</p>
        </header>
        <main>
            <form id="consultForm">
                <div class="form-group">
                    <label for="name">姓名:</label>
                    <input type="text" id="name" name="name" required>
                </div>
                <div class="form-row">
                    <div class="form-group half">
                        <label for="age">年龄:</label>
                        <input type="number" id="age" name="age" required>
                    </div>
                    <div class="form-group half">
                        <label for="gender">性别:</label>
                        <select id="gender" name="gender" required>
                            <option value="">请选择</option>
                            <option value=""></option>
                            <option value=""></option>
                        </select>
                    </div>
                </div>
                <div class="form-group">
                    <label for="symptoms">主要症状:</label>
                    <textarea id="symptoms" name="symptoms" rows="3" placeholder="请详细描述您的不适" required></textarea>
                </div>
                <div class="form-group">
                    <label for="duration">症状持续时间:</label>
                    <input type="text" id="duration" name="duration" placeholder="例如:3天、一周" required>
                </div>
                <div class="form-group">
                    <label for="history">既往病史(如有):</label>
                    <textarea id="history" name="history" rows="2" placeholder="例如:高血压、糖尿病等"></textarea>
                </div>
                <div class="form-group">
                    <label for="additional">补充信息(可选):</label>
                    <textarea id="additional" name="additional" rows="2" placeholder="其他您想说明的情况"></textarea>
                </div>
                <button type="submit" id="submitBtn">提交问诊</button>
            </form>

            <div id="reportSection" class="hidden">
                <h2>问诊报告</h2>
                <div id="reportContent" class="report-content"></div>
                <button id="printBtn" onclick="window.print()">打印报告</button>
            </div>
            <div id="loading" class="hidden">正在生成报告,请稍候...</div>
        </main>
    </div>
    <script src="js/script.js"></script>
</body>
</html>
6.2.2 css/style.css
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

body {
    font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
    background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
    min-height: 100vh;
    padding: 20px;
}

.container {
    max-width: 800px;
    margin: 0 auto;
    background: white;
    border-radius: 15px;
    box-shadow: 0 10px 30px rgba(0,0,0,0.1);
    padding: 30px;
}

header {
    text-align: center;
    margin-bottom: 30px;
}

header h1 {
    color: #2c3e50;
    margin-bottom: 10px;
}

header p {
    color: #7f8c8d;
}

.form-group {
    margin-bottom: 20px;
}

.form-row {
    display: flex;
    gap: 20px;
}

.form-group.half {
    flex: 1;
}

label {
    display: block;
    margin-bottom: 5px;
    font-weight: 600;
    color: #34495e;
}

input, select, textarea {
    width: 100%;
    padding: 10px 12px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 16px;
    transition: border 0.3s;
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: #3498db;
}

button {
    background-color: #3498db;
    color: white;
    border: none;
    padding: 14px 25px;
    font-size: 16px;
    border-radius: 8px;
    cursor: pointer;
    transition: background 0.3s;
    width: 100%;
    font-weight: 600;
}

button:hover {
    background-color: #2980b9;
}

#reportSection {
    margin-top: 40px;
    border-top: 2px solid #ecf0f1;
    padding-top: 20px;
}

.report-content {
    background: #f8f9fa;
    padding: 20px;
    border-radius: 10px;
    margin: 20px 0;
    white-space: pre-wrap;
    line-height: 1.6;
    font-family: 'Georgia', serif;
    max-height: 500px;
    overflow-y: auto;
}

.hidden {
    display: none;
}

#loading {
    text-align: center;
    padding: 30px;
    font-size: 18px;
    color: #3498db;
}

/* 打印样式 */
@media print {
    body * {
        visibility: hidden;
    }
    #reportSection, #reportSection * {
        visibility: visible;
    }
    #reportSection {
        position: absolute;
        left: 0;
        top: 0;
        width: 100%;
        border: none;
    }
    button, form, header p, #submitBtn, #printBtn {
        display: none;
    }
}
6.2.3 js/script.js
document.getElementById('consultForm').addEventListener('submit', async (e) => {
    e.preventDefault();

    // 收集表单数据
    const formData = {
        name: document.getElementById('name').value.trim(),
        age: document.getElementById('age').value.trim(),
        gender: document.getElementById('gender').value,
        symptoms: document.getElementById('symptoms').value.trim(),
        duration: document.getElementById('duration').value.trim(),
        history: document.getElementById('history').value.trim() || '无',
        additional: document.getElementById('additional').value.trim() || '无'
    };

    // 显示加载中
    document.getElementById('loading').classList.remove('hidden');
    document.getElementById('reportSection').classList.add('hidden');
    document.getElementById('submitBtn').disabled = true;

    try {
        // 发送请求到后端
        const response = await fetch('http://localhost:5000/consult', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json'
            },
            body: JSON.stringify(formData)
        });

        const result = await response.json();

        if (result.success) {
            // 显示报告
            document.getElementById('reportContent').innerText = result.report;
            document.getElementById('reportSection').classList.remove('hidden');
        } else {
            alert('生成报告失败:' + (result.error || '未知错误'));
        }
    } catch (error) {
        alert('网络错误,请检查后端服务是否运行。' + error.message);
    } finally {
        document.getElementById('loading').classList.add('hidden');
        document.getElementById('submitBtn').disabled = false;
    }
});

7. 部署说明

7.1 云服务器准备

  • 购买一台云服务器(如Ubuntu 20.04 LTS),开放端口80(HTTP)和5000(可选,但生产环境用Nginx反向代理)。
  • SSH登录服务器,更新系统:sudo apt update && sudo apt upgrade -y

7.2 安装Python环境

sudo apt install python3-pip python3-venv nginx -y

7.3 上传项目代码

可以使用scp或git clone。假设代码放在/var/www/ai_consultation

7.4 配置后端

cd /var/www/ai_consultation/backend
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

测试运行:python app.py,确保能正常启动。

7.5 使用Gunicorn运行

gunicorn -w 4 -b 127.0.0.1:5000 app:app &

(最好使用systemd管理进程,此处简化)

7.6 配置Nginx反向代理

创建配置文件 /etc/nginx/sites-available/ai_consultation

server {
    listen 80;
    server_name your_domain_or_ip;

    location / {
        root /var/www/ai_consultation/frontend;
        index index.html;
        try_files $uri $uri/ /index.html;
    }

    location /consult {
        proxy_pass http://127.0.0.1:5000/consult;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }

    location /health {
        proxy_pass http://127.0.0.1:5000/health;
    }
}

启用配置:

sudo ln -s /etc/nginx/sites-available/ai_consultation /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

7.7 修改前端请求地址

前端script.js中的fetch应改为服务器域名或IP(例如/consult),使用相对路径(通过Nginx代理)。

7.8 配置API密钥

config.py中填写正确的火山引擎API密钥和URL。

7.9 防火墙设置

确保云服务器安全组允许80端口访问。

8. 盈利模式建议

  • 广告收入:在页面中嵌入医疗相关广告。
  • 付费报告:基础报告免费,详细定制报告收费。
  • 会员订阅:提供无限次问诊、历史记录保存等高级功能。
  • 医生对接:将AI生成的报告转给真实医生审核,收取咨询费。

9. 总结

本项目实现了一个简单的AI问诊网站,通过火山引擎DeepSeek模型模拟多轮问诊并生成报告。前后端分离,易于扩展和维护。部署到云服务器后,可对外提供服务。注意合规性,医疗信息需遵循相关法律法规,建议添加免责声明。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐