欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

atomgit仓库地址: https://gitcode.com/feng8403000/mingshu_ai


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、系统概述

命枢AI生命体征分析系统是一款基于Electron框架构建的跨平台健康管理应用,融合了人工智能技术与可视化对战引擎,为用户提供沉浸式的健康数据分析体验。系统采用三栏布局设计,左侧管理外源性因素,中央展示免疫细胞与病原体的实时对战,右侧呈现用户生命体征数据。

二、架构设计

2.1 整体架构

┌─────────────────────────────────────────────────────────────────┐
│                      命枢AI生命体征分析系统                       │
├───────────────────┬───────────────────┬───────────────────────┤
│   左侧面板         │   中央对战面板    │   右侧生命体征面板      │
│  外源性因素管理    │   Canvas动画引擎  │   健康数据分析        │
├───────────────────┼───────────────────┼───────────────────────┤
│  • 症状诊断模块    │  • 实时动画渲染    │  • 面部分析模块        │
│  • 病毒/细菌/饮食  │  • 碰撞检测系统    │  • 健康信息表单        │
│  • 药物管理系统    │  • 战斗日志系统    │  • 身体机能指标        │
└───────────────────┴───────────────────┴───────────────────────┘
            │                    │                       │
            ▼                    ▼                       ▼
┌─────────────────────────────────────────────────────────────────┐
│                        AI服务层                                │
│   ┌──────────────┐  ┌──────────────┐  ┌──────────────┐        │
│   │ 症状诊断AI   │  │ 面部分析AI   │  │ 健康建议AI   │        │
│   └──────────────┘  └──────────────┘  └──────────────┘        │
└─────────────────────────────────────────────────────────────────┘

2.2 技术栈

层级 技术 说明
框架 Electron 跨平台桌面应用框架
前端 HTML5 + CSS3 + JavaScript 原生Web技术栈
渲染 Canvas 2D 实时动画渲染引擎
AI服务 DeepSeek-V3 / Qwen3.5 大语言模型API
样式 CSS3动画 + Flexbox 响应式布局

三、核心功能模块详解

3.1 面部分析模块

面部分析模块是系统的核心入口之一,允许用户上传面部照片进行AI健康评估。

核心代码实现:

async function analyzeUploadedImage() {
    if (!uploadedImageData) {
        alert('请先上传图片');
        return;
    }
    
    const resultDiv = document.getElementById('faceAnalysisResult');
    resultDiv.innerHTML = '<span style="color: #f39c12;">🤖 AI正在分析图片...</span>';
    
    const base64Data = uploadedImageData.split(',')[1];
    
    const prompt = `请分析这张人脸照片,判断这个人的:
    1. 大致年龄(根据皮肤状态、皱纹等判断)
    2. 当前的健康状态(根据面色、皮肤光泽度、精神状态等判断)
    3. 可能的疲劳程度或压力状态
    
    请以JSON格式返回,包含以下字段:
    {"estimatedAge": 估算年龄(数字), "apparentAge": 外表年龄描述, 
     "healthStatus": 健康状态描述, "fatigueLevel": 疲劳程度(0-100), 
     "stressLevel": 压力程度(0-100), "skinCondition": 皮肤状况描述, 
     "overallAssessment": 综合评估, "recommendations": 改善建议}`;

    const response = await fetch(API_URL, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Authorization': 'Bearer ' + API_KEY
        },
        body: JSON.stringify({
            model: 'Qwen/Qwen3.5-35B-A3B',
            messages: [{
                role: 'user',
                content: [
                    { type: 'image_url', image_url: { url: 'data:image/jpeg;base64,' + base64Data } },
                    { type: 'text', text: prompt }
                ]
            }],
            stream: true,
            max_tokens: 1024,
            temperature: 0.7
        })
    });
    
    // 流式响应处理
    const reader = response.body.getReader();
    const decoder = new TextDecoder('utf-8');
    let fullContent = '';
    
    while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        const chunk = decoder.decode(value, { stream: true });
        const lines = chunk.split('\n');
        
        for (const line of lines) {
            if (!line.startsWith('data:')) continue;
            if (line.trim() === 'data:[DONE]') continue;
            
            try {
                const jsonStr = line.replace(/^data:\s*/, '').trim();
                if (jsonStr) {
                    const parsed = JSON.parse(jsonStr);
                    if (parsed.choices && parsed.choices[0]) {
                        if (parsed.choices[0].delta && parsed.choices[0].delta.content) {
                            fullContent += parsed.choices[0].delta.content;
                        }
                    }
                }
            } catch (e) {
                console.warn('SSE解析错误:', e);
            }
        }
    }
    
    // 解析结果并展示
    const jsonMatch = fullContent.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
        try {
            const data = JSON.parse(jsonMatch[0]);
            displayFaceAnalysis(data);
        } catch (e) {
            resultDiv.innerHTML = '<span style="color: #e74c3c;">解析结果失败: ' + e.message + '</span>';
        }
    }
}

关键技术点:

  1. 图片数据处理:将上传的图片转换为Base64编码,便于通过API传输
  2. 多模态AI调用:同时传递图片和文本提示,实现视觉-语言联合分析
  3. 流式响应处理:通过SSE(Server-Sent Events)实时接收AI分析结果
  4. JSON解析容错:针对AI返回格式不规范的情况进行多重解析尝试

3.2 健康信息表单与BMI计算

健康信息表单收集用户基本数据,并实时计算BMI和基础代谢率。

async function analyzeBody() {
    const age = document.getElementById('age').value;
    const gender = document.getElementById('gender').value;
    const height = document.getElementById('height').value;
    const weight = document.getElementById('weight').value;
    const exercise = document.getElementById('exercise').value;
    const sleep = document.getElementById('sleep').value;

    const statusEl = document.getElementById('rightAiStatus');
    const resultEl = document.getElementById('rightAiResult');

    statusEl.style.display = 'block';
    statusEl.className = 'ai-request-status loading';
    statusEl.textContent = 'AI分析中...';

    const prompt = `请分析以下人体健康数据并给出机体状态评估。现代人由于工作压力、不良生活习惯、环境污染等因素影响,真正完全健康的人非常少,大多数人处于亚健康状态。请根据以下数据给出客观评估:

年龄: ${age}岁,性别: ${gender === 'male' ? '男' : '女'},身高: ${height}cm,体重: ${weight}kg,运动频率: ${exercise === 'none' ? '几乎不运动' : exercise === 'light' ? '每周1-2次' : exercise === 'moderate' ? '每周3-4次' : '每周5次以上'},睡眠时间: ${sleep}小时/天。

请以JSON格式返回,包含以下字段:{"healthScore": 健康评分(0-100,普通人一般在40-75之间,完全健康90以上很少), "energyScore": 能量评分(0-100,普通人一般在35-70之间), "immuneScore": 免疫评分(0-100,普通人一般在40-80之间), "cardioScore": 心血管评分(0-100), "metabolicScore": 代谢评分(0-100), "bmi": BMI值, "bmr": 基础代谢率(kcal), "healthAdvice": "健康建议"}`;

    const result = await queryAI(prompt);

    if (result) {
        try {
            const jsonMatch = result.match(/\{[\s\S]*\}/);
            if (jsonMatch) {
                const data = JSON.parse(jsonMatch[0]);
                displayBodyAnalysis(data);
            } else {
                resultEl.textContent = 'AI分析: ' + result.substring(0, 100) + '...';
            }
            statusEl.className = 'ai-request-status success';
            statusEl.textContent = '分析完成';
            rightAiCompleted = true;
        } catch (e) {
            resultEl.textContent = 'AI分析: ' + result.substring(0, 100) + '...';
            statusEl.className = 'ai-request-status success';
            statusEl.textContent = '分析完成';
            rightAiCompleted = true;
        }
    } else {
        resultEl.textContent = 'AI分析失败,请重试';
        statusEl.className = 'ai-request-status error';
        statusEl.textContent = '分析失败';
        rightAiCompleted = false;
    }

    updateBattleButton();
    updateAnalysisStatus();
}

表单验证与计算逻辑:

字段 验证规则 计算方式
年龄 1-120岁 直接输入
身高 100-250cm 直接输入
体重 30-300kg 直接输入
BMI 自动计算 weight / (height/100)^2
BMR 自动计算 Mifflin-St Jeor公式

3.3 身体机能状态系统

身体机能状态系统通过可视化进度条展示用户的五项核心指标:

function updateBodyStats() {
    const immuneCells = objects.filter(o => o.team === 'immune' && o.health > 0);
    const factors = objects.filter(o => o.team === 'factor' && o.health > 0);
    
    // 计算总伤害
    let totalDamage = 0;
    factors.forEach(factor => {
        totalDamage += (factor.config.damage || 0) * (factor.health / factor.maxHealth);
    });
    
    // 更新健康值(受伤害影响)
    bodyStats.health = Math.max(0, Math.min(healthLimit, healthLimit - totalDamage * 0.05));
    
    // 更新能量值(免疫细胞消耗)
    const energyCost = immuneCells.length * 0.08;
    let energyRecovered = 0;
    if (factors.length === 0) {
        energyRecovered = bodyStats.health >= healthLimit * 0.95 ? 0.08 : 
                          bodyStats.health >= healthLimit * 0.8 ? 0.04 : 0.02;
    }
    bodyStats.energy = Math.max(0, Math.min(energyLimit, bodyStats.energy - energyCost + energyRecovered));
    
    // 更新免疫力(战斗时增强)
    const baseImmunity = 50;
    const targetImmunity = factors.length === 0 ? baseImmunity : 
                          Math.max(0, Math.min(100, baseImmunity + (immuneCells.length - 3) * 3));
    bodyStats.immunity = bodyStats.immunity + (targetImmunity - bodyStats.immunity) * 0.03;
    
    updateBodyStatsUI();
}

状态指标说明:

指标 含义 影响因素
健康值 整体健康状况 外源性因素伤害
能量值 身体能量储备 免疫细胞消耗、休息恢复
免疫力 免疫系统强度 免疫细胞数量、战斗状态
消化能力 消化系统功能 饮食因素处理
能量消耗/秒 实时消耗速率 免疫细胞总数

3.4 免疫细胞系统

免疫细胞是对抗外源性因素的核心力量,系统包含四种免疫细胞:

const immuneCellConfigs = {
    tcell: { 
        name: 'T细胞', health: 120, attack: 18, speed: 3.5, 
        color: '#00cec9', emoji: 'T', counterType: 'virus', 
        attackEffect: 'kill', splitRate: 0.003, splitInterval: 300, lifespan: 36000 
    },
    bcell: { 
        name: 'B细胞', health: 100, attack: 14, speed: 2.5, 
        color: '#f39c12', emoji: 'B', counterType: 'bacteria', 
        attackEffect: 'antibody', splitRate: 0.002, splitInterval: 400, lifespan: 28800 
    },
    macrophage: { 
        name: '巨噬细胞', health: 250, attack: 25, speed: 1.8, 
        color: '#a29bfe', emoji: 'M', counterType: 'bacteria', 
        attackEffect: 'phagocytosis', splitRate: 0.001, splitInterval: 600, lifespan: 43200 
    },
    neutrophil: { 
        name: '中性粒细胞', health: 80, attack: 20, speed: 4.5, 
        color: '#fd79a8', emoji: 'N', counterType: 'virus', 
        attackEffect: 'decompose', splitRate: 0.005, splitInterval: 200, lifespan: 21600 
    }
};

免疫细胞特性对比:

细胞类型 生命值 攻击力 速度 攻击特效 目标类型
T细胞 120 18 3.5 直接杀伤 病毒
B细胞 100 14 2.5 抗体攻击 细菌
巨噬细胞 250 25 1.8 吞噬 细菌
中性粒细胞 80 20 4.5 分解 病毒

四、AI服务集成架构

4.1 AI分析服务

系统集成了多个AI分析服务,每个服务针对特定场景进行优化:

const FaceHealthSkill = (function() {
    const API_URL = "https://api-ai.gitcode.com/v1/chat/completions";
    const API_KEY = "qBPRwKM_kHgbBjzzxvW9ws--";

    async function queryAI(prompt, imageData) {
        const response = await fetch(API_URL, {
            method: "POST",
            headers: {
                "Authorization": `Bearer ${API_KEY}`,
                "Content-Type": "application/json"
            },
            body: JSON.stringify({
                model: "deepseek-ai/DeepSeek-V3",
                messages: [{
                    role: "user",
                    content: prompt
                }],
                stream: false,
                max_tokens: 1024,
                temperature: 0.5,
                top_p: 0.95
            })
        });

        if (!response.ok) {
            throw new Error(`HTTP error! status: ${response.status}`);
        }

        const data = await response.json();
        if (data.choices && data.choices[0] && data.choices[0].message) {
            return data.choices[0].message.content;
        }
        return null;
    }

    function parseResponse(response) {
        try {
            let jsonStr = response.trim();
            const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
            if (codeBlockMatch) {
                jsonStr = codeBlockMatch[1];
            }

            const braceStart = jsonStr.indexOf('{');
            const braceEnd = jsonStr.lastIndexOf('}');
            
            if (braceStart === -1 || braceEnd === -1) {
                throw new Error('No valid JSON found');
            }
            
            jsonStr = jsonStr.substring(braceStart, braceEnd + 1);
            jsonStr = jsonStr.replace(/,\s*([}\]])/g, '$1');
            
            return JSON.parse(jsonStr);
        } catch (error) {
            console.error('Face Health Parse Error:', error.message);
            return generateFallbackResponse();
        }
    }

    function generateFallbackResponse() {
        return {
            complexion: '正常',
            signsOfFatigue: '否',
            hydrationLevel: '适中',
            overallHealth: '良好',
            skinElasticity: '良好',
            acneOrMarks: '无',
            darkCircles: '无',
            puffiness: '无',
            concerns: [],
            lifeQualityScore: 75,
            healthTips: ['保持良好生活习惯', '注意营养均衡', '保证充足睡眠']
        };
    }

    async function analyze(imageData) {
        const prompt = `你是一位专业的面部健康分析专家。请通过面部照片详细分析用户的健康状况,给出全面的健康评估。

图片数据已提供。

请以JSON格式返回详细的健康分析结果,包含以下所有字段:
- complexion: 肤色气色详细描述
- signsOfFatigue: 疲劳程度评估
- hydrationLevel: 皮肤水分状态评估
- overallHealth: 整体健康评估
- skinElasticity: 皮肤弹性
- acneOrMarks: 痘痘或痘印情况
- darkCircles: 黑眼圈情况
- puffiness: 面部浮肿情况
- concerns: 需要关注的健康问题列表
- lifeQualityScore: 生活质量评分
- healthTips: 个性化健康提示`;

        const response = await queryAI(prompt, imageData);
        
        if (!response) {
            return generateFallbackResponse();
        }

        try {
            const parsed = parseResponse(response);
            return sanitizeResponse(parsed);
        } catch (error) {
            return generateFallbackResponse();
        }
    }

    function sanitizeResponse(response) {
        const fallback = generateFallbackResponse();
        return {
            complexion: ensureString(response.complexion, fallback.complexion),
            signsOfFatigue: ensureString(response.signsOfFatigue, fallback.signsOfFatigue),
            hydrationLevel: ensureString(response.hydrationLevel, fallback.hydrationLevel),
            overallHealth: ensureString(response.overallHealth, fallback.overallHealth),
            skinElasticity: ensureString(response.skinElasticity, fallback.skinElasticity),
            acneOrMarks: ensureString(response.acneOrMarks, fallback.acneOrMarks),
            darkCircles: ensureString(response.darkCircles, fallback.darkCircles),
            puffiness: ensureString(response.puffiness, fallback.puffiness),
            concerns: ensureArray(response.concerns, fallback.concerns),
            lifeQualityScore: ensureNumber(response.lifeQualityScore, fallback.lifeQualityScore),
            healthTips: ensureArray(response.healthTips, fallback.healthTips)
        };
    }

    // ... 辅助函数

    return {
        analyze: analyze
    };
})();

4.2 AI响应解析策略

AI返回的数据格式可能不规范,系统采用多重容错策略:

function parseAIResponse(response) {
    try {
        let jsonStr = response.trim();
        
        // 尝试提取代码块
        const codeBlockMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)\s*```/);
        if (codeBlockMatch) {
            jsonStr = codeBlockMatch[1];
        }
        
        // 提取JSON结构
        const braceStart = jsonStr.indexOf('{');
        const braceEnd = jsonStr.lastIndexOf('}');
        
        if (braceStart === -1 || braceEnd === -1) {
            console.error('未找到有效的JSON结构');
            return generateFallbackResponse();
        }
        
        jsonStr = jsonStr.substring(braceStart, braceEnd + 1);
        jsonStr = jsonStr.replace(/,\s*([}\]])/g, '$1');
        
        // 尝试修复可能的语法问题
        jsonStr = jsonStr
            .replace(/(['"])?([a-zA-Z0-9_]+)(['"])?:/g, '"$2":')
            .replace(/'/g, '"');
        
        return JSON.parse(jsonStr);
    } catch (e) {
        console.error('解析失败,使用默认数据:', e);
        return generateFallbackResponse();
    }
}

五、数据模型设计

5.1 外源性因素配置

const factorConfigs = {
    virus: {
        influenza: { 
            name: '流感病毒', damage: 4, speed: 3, resistance: 0.2, 
            color: '#ff6b6b', emoji: '🦠', 
            desc: '通过飞沫传播,引起呼吸道感染,症状包括发热、咳嗽、乏力等。',
            medicine: { name: '奥司他韦', efficacy: '92%', sideEffects: '恶心、呕吐、头痛', duration: 3600 },
            splitRate: 0.003, splitInterval: 400, lifespan: 43200 
        },
        coronavirus: { 
            name: '冠状病毒', damage: 5, speed: 2, resistance: 0.3, 
            color: '#c0392b', emoji: '🦠', 
            desc: '高度传染性病毒,可引起严重呼吸系统疾病。',
            medicine: { name: '瑞德西韦', efficacy: '85%', sideEffects: '肝功能异常、腹泻', duration: 4800 },
            splitRate: 0.002, splitInterval: 500, lifespan: 50400 
        },
        // ... 更多病毒配置
    },
    bacteria: { 
        'e-coli': { name: '大肠杆菌', damage: 4, speed: 0.8, resistance: 0.1, color: '#e17055', emoji: '🦟', desc: '常见肠道细菌...' },
        staph: { name: '金黄葡萄球菌', damage: 6, speed: 1.5, resistance: 0.18, color: '#d35400', emoji: '🦟', desc: '常见于皮肤表面...' },
        // ... 更多细菌配置
    },
    diet: { 
        'high-sugar': { name: '高糖食物', damage: 6, speed: 0.5, resistance: 0, color: '#fdcb6e', emoji: '🍬', desc: '过量摄入会导致血糖波动...' },
        'high-fat': { name: '高脂肪食物', damage: 8, speed: 0.5, resistance: 0, color: '#f39c12', emoji: '🍟', desc: '长期摄入会增加心血管疾病风险...' },
        // ... 更多饮食因素配置
    }
};

5.2 战斗对象类

class BattleObject {
    constructor(type, subtype, config, x, y, team, damageMultiplier = 1.0) {
        this.type = type;
        this.subtype = subtype;
        this.config = config;
        this.x = x;
        this.y = y;
        this.team = team;
        this.health = config.health || 100;
        this.maxHealth = this.health;
        this.attack = (config.attack || config.damage) * damageMultiplier;
        this.baseAttack = config.attack || config.damage;
        this.speed = config.speed;
        this.resistance = config.resistance || 0;
        this.color = config.color;
        this.emoji = config.emoji;
        this.size = team === 'factor' ? 15 + Math.random() * 10 : 12 + Math.random() * 8;
        this.target = null;
        this.attackTimer = 0;
        this.attackInterval = team === 'immune' ? 30 : 45;
        this.attackEffect = config.attackEffect || 'normal';
        
        // 分裂相关
        this.splitTimer = 0;
        this.splitRate = config.splitRate || 0;
        this.splitInterval = config.splitInterval || 0;
        
        // 药物效果
        this.medicineDuration = 0;
        this.hasMedicine = false;
        
        // 生命周期
        this.age = 0;
        this.lifespan = config.lifespan || 0;
        
        // 初始化运动方向
        if (team === 'immune') {
            this.vx = this.speed;
            this.vy = (Math.random() - 0.5) * this.speed;
        } else {
            this.vx = -this.speed;
            this.vy = (Math.random() - 0.5) * this.speed;
        }
    }

    update() {
        this.x += this.vx;
        this.y += this.vy;

        // 边界检测
        this.x = Math.max(BOUNDARY_PADDING + this.size, Math.min(canvasWidth - BOUNDARY_PADDING - this.size, this.x));
        this.y = Math.max(BOUNDARY_PADDING + this.size, Math.min(canvasHeight - BOUNDARY_PADDING - this.size, this.y));

        // 边界反弹
        if (this.x <= BOUNDARY_PADDING + this.size || this.x >= canvasWidth - BOUNDARY_PADDING - this.size) {
            this.vx *= -0.8;
        }
        if (this.y <= BOUNDARY_PADDING + this.size || this.y >= canvasHeight - BOUNDARY_PADDING - this.size) {
            this.vy *= -0.8;
        }

        // 寻找目标
        this.findTarget();

        // 追踪目标
        if (this.target && this.target.health > 0) {
            const dx = this.target.x - this.x;
            const dy = this.target.y - this.y;
            const dist = Math.sqrt(dx * dx + dy * dy);

            if (dist > this.size + this.target.size + 5) {
                const angle = Math.atan2(dy, dx);
                const speed = this.team === 'immune' ? this.speed : this.speed * 0.7;
                this.vx = Math.cos(angle) * speed;
                this.vy = Math.sin(angle) * speed;
            }
        }

        // 攻击计时
        this.attackTimer++;
        if (this.target && this.target.health > 0 && this.attackTimer >= this.attackInterval) {
            this.attackTimer = 0;
            this.performAttack();
        }

        // 随机运动扰动
        if (Math.random() < 0.01) {
            this.vy += (Math.random() - 0.5) * 0.3;
        }

        // 分裂逻辑
        if (this.splitInterval > 0 && this.health > this.maxHealth * 0.3) {
            this.splitTimer++;
            if (this.splitTimer >= this.splitInterval && Math.random() < this.splitRate) {
                this.split();
                this.splitTimer = 0;
            }
        }

        // 药物效果处理
        if (this.hasMedicine && this.team === 'factor') {
            this.medicineDuration--;
            const medicineDamage = this.maxHealth * 0.0072;
            this.health -= medicineDamage;
            
            if (this.medicineDuration <= 0) {
                this.hasMedicine = false;
            }
        }

        // 生命周期处理
        if (this.lifespan > 0) {
            this.age++;
            if (this.age >= this.lifespan) {
                this.health = 0;
            }
        }
    }

    findTarget() {
        this.target = null;
        let minDist = Infinity;

        for (const obj of objects) {
            if (obj.team === this.team || obj.health <= 0) continue;
            if (this.team === 'immune' && obj.type === 'diet') continue;

            const dx = obj.x - this.x;
            const dy = obj.y - this.y;
            const dist = Math.sqrt(dx * dx + dy * dy);

            if (dist < minDist && dist < 250) {
                minDist = dist;
                this.target = obj;
            }
        }
    }

    performAttack() {
        if (!this.target || this.target.health <= 0) return;

        const dx = this.target.x - this.x;
        const dy = this.target.y - this.y;
        const dist = Math.sqrt(dx * dx + dy * dy);

        const attackRange = this.size + this.target.size + 15;
        if (dist > attackRange) return;

        let baseDamage = this.attack;
        const resistance = this.target.resistance || 0;
        
        if (this.team === 'immune' && this.target.team === 'factor') {
            if (this.target.hasMedicine) {
                baseDamage *= 5.0;
            } else {
                baseDamage *= 1.2;
            }
        }
        
        const finalDamage = Math.floor(baseDamage * (1 - resistance) * (0.8 + Math.random() * 0.5));

        this.target.health = Math.max(0, this.target.health - finalDamage);
    }

    draw() {
        ctx.save();
        ctx.translate(this.x, this.y);

        // 绘制主体
        ctx.beginPath();
        ctx.arc(0, 0, this.size, 0, Math.PI * 2);
        ctx.fillStyle = this.team === 'immune' ? this.color + '40' : this.color + '30';
        ctx.fill();
        ctx.strokeStyle = this.color;
        ctx.lineWidth = 2;
        ctx.stroke();

        // 绘制emoji
        ctx.font = `${this.size}px Arial`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(this.emoji, 0, 0);

        // 绘制血条
        const barWidth = this.size * 1.5;
        const barHeight = 3;
        const barY = -this.size - 8;

        ctx.fillStyle = '#333';
        ctx.fillRect(-barWidth / 2, barY, barWidth, barHeight);

        const healthPercent = this.health / this.maxHealth;
        ctx.fillStyle = healthPercent > 0.5 ? '#00cec9' : healthPercent > 0.25 ? '#f39c12' : '#ff6b6b';
        ctx.fillRect(-barWidth / 2, barY, barWidth * healthPercent, barHeight);

        ctx.restore();
    }
}

六、渲染与动画系统

6.1 Canvas渲染引擎

function animate() {
    if (!battleRunning) return;

    // 更新所有对象
    objects = objects.filter(o => o.health > 0);
    objects.forEach(obj => {
        obj.update();
    });

    // 更新特效
    effects = effects.filter(e => e.frame < e.maxFrames);
    effects.forEach(effect => {
        effect.frame++;
    });

    // 渲染
    ctx.clearRect(0, 0, canvasWidth, canvasHeight);
    drawGrid();

    objects.forEach(obj => {
        obj.draw();
    });

    drawEffects();

    // 更新UI
    updateCounts();
    document.getElementById('battleRound').textContent = Math.floor(battleRound / 60);

    animationId = requestAnimationFrame(animate);
}

6.2 战斗特效系统

function drawEffects() {
    effects = effects.filter(e => e.frame < e.maxFrames);

    effects.forEach(effect => {
        const progress = effect.frame / effect.maxFrames;
        const alpha = 1 - progress;

        ctx.save();
        ctx.globalAlpha = alpha;

        switch (effect.type) {
            case 'phagocytosis':
                ctx.beginPath();
                ctx.arc(effect.x, effect.y, effect.damage * (1 - progress), 0, Math.PI * 2);
                ctx.strokeStyle = effect.color;
                ctx.lineWidth = 3 - progress * 2;
                ctx.stroke();

                for (let i = 0; i < 6; i++) {
                    const angle = (i / 6) * Math.PI * 2;
                    const dist = effect.damage * (0.5 + progress * 0.5);
                    ctx.beginPath();
                    ctx.arc(
                        effect.x + Math.cos(angle) * dist * (1 - progress),
                        effect.y + Math.sin(angle) * dist * (1 - progress),
                        3, 0, Math.PI * 2
                    );
                    ctx.fillStyle = effect.color;
                    ctx.fill();
                }
                break;

            case 'antibody':
                ctx.beginPath();
                ctx.moveTo(effect.attackerX, effect.attackerY);
                ctx.lineTo(effect.x, effect.y);
                ctx.strokeStyle = effect.color;
                ctx.setLineDash([5, 3]);
                ctx.stroke();
                ctx.setLineDash([]);
                break;

            case 'kill':
                ctx.beginPath();
                ctx.arc(effect.x, effect.y, effect.damage * progress, 0, Math.PI * 2);
                ctx.fillStyle = effect.color + '40';
                ctx.fill();
                break;
        }

        ctx.restore();
    });
}

七、状态管理与数据流

7.1 身体状态管理

let bodyStats = {
    health: 80,        // 健康值
    energy: 60,        // 能量值
    immunity: 50,      // 免疫力
    digestion: 70      // 消化能力
};

function updateBodyStatsUI() {
    document.getElementById('healthValue').textContent = Math.round(bodyStats.health);
    document.getElementById('energyValue').textContent = Math.round(bodyStats.energy);
    document.getElementById('immuneValue').textContent = Math.round(bodyStats.immunity);
    document.getElementById('digestionValue').textContent = Math.round(bodyStats.digestion);
    
    document.getElementById('healthBar').style.width = `${bodyStats.health}%`;
    document.getElementById('energyBar').style.width = `${bodyStats.energy}%`;
    document.getElementById('immuneBar').style.width = `${bodyStats.immunity}%`;
    document.getElementById('digestionBar').style.width = `${bodyStats.digestion}%`;
}

7.2 战斗统计系统

let battleStats = {
    virus: { count: 0, totalDamage: 0, killed: 0 },
    bacteria: { count: 0, totalDamage: 0, killed: 0 },
    diet: { count: 0, totalDamage: 0, killed: 0 },
    tcell: { killed: 0 },
    bcell: { killed: 0 },
    macrophage: { killed: 0 },
    neutrophil: { killed: 0 },
    medicine: { used: 0, totalDamage: 0, killed: 0 }
};

八、用户界面交互

8.1 图片上传与处理

function handleImageUpload(event) {
    const file = event.target.files[0];
    if (!file || !file.type.startsWith('image/')) {
        alert('请选择图片文件');
        return;
    }
    
    const reader = new FileReader();
    reader.onload = function(e) {
        uploadedImageData = e.target.result;
        
        const capturedImg = document.getElementById('capturedImage');
        capturedImg.src = uploadedImageData;
        capturedImg.style.display = 'block';
        
        document.getElementById('cameraPlaceholder').style.display = 'none';
        document.getElementById('uploadBtn').style.display = 'none';
        document.getElementById('analyzeBtn').style.display = 'inline-block';
        document.getElementById('resetBtn').style.display = 'inline-block';
        
        document.getElementById('faceAnalysisResult').innerHTML = '<span style="color: #888;">图片已上传,点击"开始分析"进行面部分析</span>';
    };
    reader.readAsDataURL(file);
}

8.2 症状标签选择

function addSymptom(symptom) {
    const input = document.getElementById('symptomInput');
    const currentValue = input.value.trim();
    if (currentValue) {
        input.value = currentValue + '、' + symptom;
    } else {
        input.value = symptom;
    }
}

九、系统优化与性能考量

9.1 性能优化策略

  1. 对象池管理:通过filter实时清理死亡对象
  2. requestAnimationFrame:使用浏览器原生动画API
  3. 批量渲染:合并绘制操作减少Canvas调用次数
  4. 流式AI响应:逐步接收和处理,避免阻塞UI

9.2 错误处理机制

async function queryAI(prompt) {
    try {
        const response = await fetch(API_URL, { /* ... */ });
        
        if (!response.ok) {
            const errorText = await response.text();
            throw new Error(`HTTP error! status: ${response.status}, message: ${errorText}`);
        }
        
        return await response.json();
    } catch (error) {
        console.error('AI请求失败:', error.message);
        return null;
    }
}

十、总结

命枢AI生命体征分析系统是一个集AI分析、实时动画、健康管理于一体的综合性应用。其核心价值在于:

  1. 创新的健康可视化:将抽象的免疫系统工作过程转化为直观的动画对战
  2. 多模态AI集成:结合图像识别和文本分析,提供全面的健康评估
  3. 数据驱动的决策:基于用户输入数据进行个性化健康分析
  4. 沉浸式体验:通过实时对战系统增强用户参与感和学习兴趣

系统架构清晰、代码模块化程度高,为后续功能扩展和性能优化提供了良好的基础。


附录:文件结构

d:\save\systemIso\electron-openharmony-vue3\
└── ohos_hap\
    └── web_engine\
        └── src\
            └── main\
                └── resources\
                    └── resfile\
                        └── resources\
                            └── app\
                                ├── index.html
                                ├── style.css
                                ├── main.js
                                └── js\
                                    ├── ai.js
                                    ├── ai_image.js
                                    ├── battle.js
                                    ├── config.js
                                    ├── face_health_skill.js
                                    ├── face_feature_skill.js
                                    ├── health_advice_skill.js
                                    ├── symptom_analysis_skill.js
                                    ├── question_diagnosis_skill.js
                                    ├── image_diagnosis_skill.js
                                    └── diagnosis_modal.js

欢迎加入开源鸿蒙PC社区:
https://harmonypc.csdn.net/

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐