chatMed开发日志博客(持续更新中)

目录

1. 项目概述

2. 开发人员团队

3. 大致需求

4. 开发内容

4.1. 前端开发

4.1.1: 前端页面开发

4.1.2: 登录机制以及路由守卫的开发

4.1.3: 文件上传机制和保存机制

4.1.4: 消息传递机制'

4.2. 线程池开发

4.3. 在线调试


1. 项目概述

 搭建一个基于深度学习的分析平台, 使研究人员能够使用先进的深度学习架构, 来进行多模态医学影像的分析. 在完成模型多模态交互的同时, 为医护人员提供快捷便利的医学影响参考平台, 减轻医生的工作压力.

本项目采用人机交互设计原则和用户体验研究,设计了直观、简洁、易用的界面,并提供了个性化的用户操作,以增强医生和患则对系统的接受度和使用意愿。


本项目能处理多种不同模态的医学影像数据,如MRI、CT、X光等,以及临床数据,如患者的病史、症状等。有效地整合不同模态的信息,提取更丰富和准确的特征,进一步提高诊断和治疗的效果。


本项目通过多轮对话交互提供更有效的医学影像分析结果,支持病灶分割、疾病分类、病变检测以及疾病进展监测,为医生和患者提供了更好的医疗服务。


本项目能够解决百姓日常生活中大多数的医学问答、健康科普、健康管理等相关问题,采用自然语言处理技术和深度学习算法,通过大模型训练方法,形成人工智能“医生大脑”。

2. 开发人员团队

5人(tg, wyx, wyt, cjy, xpk), 分别负责开发, 测试以及产品设计等等工作.

3. 大致需求

搭建一个基于深度学习的分析平台, 使研究人员能够使用先进的深度学习架构, 来进行多模态医学影像的分析.

4. 开发内容

4.1. 前端开发

前端使用react架构实现开发, 最终预计在服务器环境上完成部署, 下方的目录顺序并非实际开发顺序, 每个部分均有所更新.

4.1.1: 前端页面开发

前端页面使用react开发, 采用组件式开发模式:

分成如图所示的多个界面, 最终效果如图所示:

内部功能如图所示:

4.1.2: 登录机制以及路由守卫的开发

首先先创建一个组件用来保存登录状态并将状态传递给下方的每一个组件, 在组件包括了跟组件

import { createContext, useState } from 'react';

export const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [isLoggedIn, setIsLoggedIn] = useState(false);
  const [session, setSession]=useState('')
  const [email, setUserEmail]=useState('')

  const login = () => {
    setIsLoggedIn(true);
  };

  const logout = () => {
    setIsLoggedIn(false);
  };

  return (
    //传递数据为登录信息, 登入和登出操作, 会话id, 用户邮箱, 以及对应的修改操作
    <AuthContext.Provider value={{ isLoggedIn,login, logout,session,email,setUserEmail, setSession }}>
      {children} 
    </AuthContext.Provider>
  );
};

 将组件状态传递给下方的每一个组件

import logo from './logo.svg';
import './App.css';
import Home from './pages/home';
import { BrowserRouter, Routes,Route } from 'react-router-dom';
import Login from './pages/login';
import About from './pages/about';
import { AuthProvider } from './Auth';
import ProtectedRouter from './components/ProtectRouter';
import Chat from './pages/chat';
import Register from './pages/register';

function App() {
  return (
    <AuthProvider>{/*根组件用来传递状态和登录信息*/}
      <BrowserRouter>
        <Routes>
          <Route path='/' element={<Home/>} />
          <Route path='/login' element={<Login/>} />
          <Route path='/register' element={<Register/>} />
          <Route path='/chat' element={<ProtectedRouter Component={()=><Chat/>}/>}/>
          <Route path='/about' element={<ProtectedRouter Component={()=><About/>}/>}/>
        </Routes>
      </BrowserRouter>
    </AuthProvider>
  );
}

export default App;

在一些需要登录的路由上创建一个路由守卫组件, 该组件会检测到用户是否正在登录状态, 如果不是, 则会强制跳转到登录界面. 

import { useContext } from 'react';
import { Navigate } from 'react-router-dom';
import { BrowserRouter, Routes,Route } from 'react-router-dom';
import About from '../pages/about';
import { AuthContext } from '../Auth';

const ProtectedRouter = ({Component}) => { //传进来的对象以及其他的属性

  const { isLoggedIn } = useContext(AuthContext); //检查登录状态
  return (
        isLoggedIn ?  <Component/> :  <Navigate to={{ pathname: '/login' }} /> //如果已经登录了, 就展示情况
  );
};

export default ProtectedRouter;

4.1.3: 文件上传机制和保存机制

在最开始的时候尝试过使用单独组件封装的方式来实现文件的上传,

import { Upload, message } from 'antd';
import React from 'react';

function getBase64(img, callback) {
  const reader = new FileReader();
  reader.addEventListener('load', () => callback(reader.result));
  reader.readAsDataURL(img);
}

function beforeUpload(file) {
  const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
  if (!isJpgOrPng) {
    message.error('You can only upload JPG/PNG file!');
  }
  const isLt2M = file.size / 1024 / 1024 < 2;
  if (!isLt2M) {
    message.error('Image must smaller than 2MB!');
  }
  return isJpgOrPng && isLt2M;
}

class Avatar extends React.Component {
  state = {
    loading: false,
  };

  handleChange = info => {
    if (info.file.status === 'uploading') {
      this.setState({ loading: true });
      return;
    }
    if (info.file.status === 'done') {
      // Get this url from response in real world.
      getBase64(info.file.originFileObj, imageUrl =>
        this.setState({
          imageUrl,
          loading: false,
        }),
      );
    }
  };

  render() {
    const uploadButton = (
      <div>
        <div className="ant-upload-text">Upload</div>
      </div>
    );
    const { imageUrl } = this.state;
    return (
      <Upload
        name="avatar"
        listType="picture-card"
        className="avatar-uploader"
        showUploadList={false}
        action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
        beforeUpload={beforeUpload}
        onChange={this.handleChange}
      >
        {imageUrl ? <img src={imageUrl} alt="avatar" style={{ width: '100%' }} /> : uploadButton}
      </Upload>
    );
  }
}

export default Avatar 

 但是后续出现了很多问题, 所以改用原生来实现提交

 {(!imgUploaded) 
                      &&
                      //自定义一个文件输入框
                      <button style={{
                          border: 'solid 5px #284B63',
                          borderRadius: 100,
                          height: 60,
                          width: '100%',
                          color:'#284B63',
                          fontSize:20,
                          fontWeight: 700,
                          marginBottom:20

                      }} onClick={()=>chooseFile()}>choose File</button>
                  }
                  {/*文件上传按钮, 隐藏原始的文件输入, 然后自定义一个*/}
                  <input type="file" id="fileInput" accept="*" style={{margin:10,display:'none'}}/>
                  {/*图片展示*/}
                  {hasImg && <div  style={{height:256,width:256,justifyContent:'center',alignContent:'center'}}>
                    <img id="previewImage" alt="Preview" style={
                      imgUploaded?
                      {
                        height:256,
                        width:256
                        }
                      :
                      {
                        height:218,
                        width:218
                        }
                    }></img>
                  </div>}
                  {/*文件发送到后端的按钮*/}
                  {hasImg && (!imgUploaded) && <button onClick={()=>sendImage()} style={{
                          border: 'solid 5px #284B63',
                          borderRadius: 100,
                          height: 60,
                          width: '100%',
                          color:'#284B63',
                          color:'#284B63',
                          fontSize:20,
                          fontWeight: 700,
                          marginTop:20
                  }}>
                    Init dialog
                  </button>}
                </div>

 为了修改原有的ui按钮, 我们将原本的提交机制给隐藏, 再通过js进行点击事件的模拟触发, 最终实现图片的上传和展示, 图片的命名方式为img+会话id

//文件上传对象
    const fileInput = document.getElementById('fileInput');  
    //设置监听对象
    fileInput.addEventListener('change', (event) => {  
        const file = event.target.files[0];  
        const previewImage = document.getElementById('previewImage'); 
        if (file) {  
            if (file.type.startsWith('image/')) { 
              setHasImg(true)  
              const reader = new FileReader();  

              reader.onload = (e) => {  
                  // 读取完成后,数据URL会作为结果  
                  previewImage.src = e.target.result;  
              };  
                // 以Data URL的形式读取文件  
                reader.readAsDataURL(file);  
            } else {  
                alert('please choose a image file!');  
            }  
          }
        })

4.1.4: 消息传递机制'

消息传递大致为以下三种

指令序号内容
0启动对话并将会话id传递给前后端
1停止会话
2正常的通讯消息
3传递图片

前端的websocket数据监听

    const wsMessageHandler = (message) => {
      const data = jsonToObject(message.data);
      if (data.type === 0){ //后端返回一个登录状态
        setId(data.id); 
        setSession(data.id) //设置登录状态,知道会话id
      }
      else if (data.type === 1) {
        console.log('当前问诊已经结束');
      }
      else if (data.type === 2) {
        console.log('模型消息回复为', String(data.message));
        appendList(String(data.message)) //是这个的问题, 强制刷新消息
        setDialogShow(false)
      }
      else if (data.type === 3) {
        console.log('图片的存储地点为', data.url);
      }
    };

 后端ws数据监听

if(conn){                       //如果链接对象已经创建
            work=conn.worker            //获取线程链接

            if(data.type===2) {         //发送到ws的指令为2, 则把数据传下去
                work.postMessage(data)

            }else if(data.type===1){    //接收到1指令
                console.log('会话'+data.id+'已经停止')
                work.postMessage(data)  //向线程发送停止信息
                workers.delete(data.id) //从线程队列中删除会话

            }else if(data.type===3){    
                // 将Base64编码的字符串转换为Buffer
                const imageBuffer = Buffer.from(data.data.split(';base64,').pop(), 'base64');
                // 指定要保存图像的文件路径和文件名
                const imagePath = './imgs/img'+data.id+'.png';
                // 将图像数据写入文件
                fs.writeFile(imagePath, imageBuffer, (err) => {
                    if (err) {console.error('Error saving image:', err); return; }
                });
                // 将图片的保存地址传递给子进程
                work.postMessage({...data,url:imagePath})
            }
        }

后端监听子线程的消息

worker.on('message', (message) => {
        console.log(message)
        conn=workers.get(message.id)
        if(message.type===2){
            conn.getWebSocket().send(objectToJson(message))
        }else if(message.type===1){
            workers.delete(message.id) //从维护队列中删除
            conn.getWebSocket().send(objectToJson(message)) //将数据发送给前端
        }else if(message.type===3){
            conn.getWebSocket().send(objectToJson(message)) //将数据发送给前端
        }
    })

4.2. 线程池开发

为了更好的实现用户的隔离和资源管理, 我们使用线程池的方式来实现前端-后端-模型的交互, 再开始阶段, 我们使用脚本来代替模型的功能

# 导入模块
import sys
import time

# 循环接收用户输入并进行对话,直到接收到指令退出
# 模拟的是一个模型的功能
time.sleep(5)
sys.stdout.buffer.write("你好".encode('utf-8'))
while True:
    # 接收用户输入, 这里是一个组合方法
    user_input = input() 

    # 如果用户输入指令 "exit",则退出循环
    if user_input.strip() == "exit":
        print("Exiting conversation...")
        break

    # 模拟数据的发送
    time.sleep(5)

    # python的回答, 也就是我们所需要的诊断内容, 果然是把这一句直接ASCII化了
    sys.stdout.buffer.write("模型输出".encode('utf-8'))

后端主页代码

const WebSocket = require('ws');
const { Worker } = require('worker_threads');
const {jsonToObject,objectToJson,generateUniqueId}=require('./tool.js')
const fs = require('fs');

// 创建 WebSocket 服务器, 该服务器监听的是3001端口
const wss = new WebSocket.Server({ port: 3001 });

//链接类,id, 和前端的链接ws, 和后端的链接worker
class Connection {
    constructor(id, ws, worker) {
        this.id = id;
        this.ws = ws;
        this.worker = worker;
    }
    getId() {  return this.id;  }
    getWebSocket() {   return this.ws;  }
    getWorker() { return this.worker;}
    setWebSocket(ws) {  this.ws = ws;}
    setWorker(worker) { this.worker = worker;}
}

//进程管理对象队列(映射)
const workers=new Map();


// 监听每次创建一个新的链接, 就会
// 创建一个ws对象并且设置监听器
// 将其加入队列中
wss.on('connection', (ws) => {
    //创建id
    const id=generateUniqueId()
    
    //生成链接对象并且创建监听
    ws.addEventListener('open', () => {
        console.log('WebSocket connection established');
    });
    //监听前端的信息
    ws.addEventListener('message', (event) => { 
        data=jsonToObject(event.data)
        conn=workers.get(data.id)   //先判断该会话是否还存在, 如果不存在就不需要什么反应
        if(conn){                       //如果链接对象已经创建
            work=conn.worker            //获取线程链接

            if(data.type===2) {         //发送到ws的指令为2, 则把数据传下去
                work.postMessage(data)

            }else if(data.type===1){    //接收到1指令
                console.log('会话'+data.id+'已经停止')
                work.postMessage(data)  //向线程发送停止信息
                workers.delete(data.id) //从线程队列中删除会话

            }else if(data.type===3){    
                // 将Base64编码的字符串转换为Buffer
                const imageBuffer = Buffer.from(data.data.split(';base64,').pop(), 'base64');
                // 指定要保存图像的文件路径和文件名
                const imagePath = './imgs/img'+data.id+'.png';
                // 将图像数据写入文件
                fs.writeFile(imagePath, imageBuffer, (err) => {
                    if (err) {console.error('Error saving image:', err); return; }
                });
                // 将图片的保存地址传递给子进程
                work.postMessage({...data,url:imagePath})
            }
        }
    });

    //将id, 链接对象和子线程组合存储, 其中ws代表前端, worker代表后端线程
    ws.addEventListener('error', (error) => {
        console.error('WebSocket error:', error);
    });
    ws.addEventListener('close', () => {   //监听到链接关闭以后
        console.log('用户页面已经关闭')     //将ws直接删除掉
        conn=workers.get(id)   
        if(conn){              
            workers.delete(id)
        }
    });

    // 创建子线程
    const worker=new Worker('./worker.js')
    // 监听来自子线程的消息
    worker.on('message', (message) => {
        console.log(message)
        conn=workers.get(message.id)
        if(message.type===2){
            conn.getWebSocket().send(objectToJson(message))
        }else if(message.type===1){
            workers.delete(message.id) //从维护队列中删除
            conn.getWebSocket().send(objectToJson(message)) //将数据发送给前端
        }else if(message.type===3){
            conn.getWebSocket().send(objectToJson(message)) //将数据发送给前端
        }
    })

    //前端链接, 线程链接, 以及id存储起来
    workers.set(id, new Connection(id,ws,worker))

    //发送给前端id信息
    ws.send(objectToJson({type:0,id:id}))
    //发送给子线程id信息
    worker.postMessage(objectToJson({type:0, id:id}))
    
    console.log('新增会话用户, 当前会话数目为', workers.size)

});

子线程管理代码

// worker.js
const { parentPort } = require('worker_threads');
const {jsonToObject,objectToJson}=require('./tool');
const { spawn } = require('child_process');

/*
主线程会根据worker.js中的代码创建一个子线程
创建子线程的同时, 启动一个python服务, 该服务在启动的时候, 就把图片数据和第一个prompt传递过去
*/

//问诊状态
let inquiried=false
//图片地址
let imgUrl=''
// python脚本执行对象
let  pythonProcess;
//会议id
let id;


//开启问诊状态,参数为图片的地址
//传递的msg就是图片的地址================================================================
const startInquriy=(msg)=>{
    //启动模型,
    pythonProcess = spawn('python', ['./foot.py', msg, '请你帮我诊断这张图片' ], {   
        stdio: ['pipe', 'pipe', 'pipe'] ,
        encoding: 'utf-8'
    });
    //为模型增加一个输出监听, 从此会开始监听模型的输出
    pythonProcess.stdout.on('data', (data) => {
        if(!inquiried){
            //如果检测到这是第一次输出, 则开启问诊状态
            inquiried=true
            //先进行响应3,告知前端图片地址在什么地方
            parentPort.postMessage({type:3, id:id, url:msg})
        }
        //响应2, 告知前端模型的意见
        // 将Buffer对象转换为十六进制字符串,并使用正则表达式替换掉空格
        const hexString = data.toString('hex').replace(/ /g, '');
        console.log(Buffer.from(hexString, 'hex'))
        // 将十六进制字符串转换为实际的字符串
        const str = Buffer.from(hexString, 'hex').toString('utf-8');
        console.log(str)
        parentPort.postMessage({type:2, id:id, message:str})
    });
}

// 向 Python 脚本发送数据, 参数为发送的数据
const sendDataToPython = (data) => {
    pythonProcess.stdin.write(data + '\n'); // 在每条消息末尾加上换行符
};


// 监听主线程发送的消息
parentPort.on('message', (message) => {
    data=message
    //0指令, 给线程分一个id
    if(data.type===0){
        id = data.id;
    }
    //1指令, 线程停止
    else if(data.type===1){
        if(inquiried){ 
            //停止python脚本
            sendDataToPython('exit');
            //停止线程
            process.exit()

        }
    }
    //2指令, 发来数据, 传回数据
    else if(data.type===2){
        //输入数据, 这个data.message其实就是前端传入进来的话
       if(inquiried){ 
            sendDataToPython(data.message);
        }
    }
    //3指令, 开启对话
    else if(data.type===3){
        //输入图片, 并且确认开启python脚本
        imgUrl = data.url
        id = data.id
        startInquriy(data.url);
    }
});



4.3. 在线调试

在线调试的过程中遇到cors跨域的问题, 解决方案是使用http-server的包进行本地服务器建立并且运行, 在目录下进入启动http-server指令

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/665184.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

深度学习设计模式之装饰器模式

文章目录 前言一、介绍二、详细分析1.核心组成2.实现步骤3.代码示例4.优缺点优点缺点 5.使用场景 总结 前言 装饰器模式属于结构型模式&#xff0c;又叫包装设计模式&#xff0c;动态的将责任添加到对象上。 一、介绍 装饰器模式又叫包装设计模式&#xff0c;为现有的类的一个…

docker基本操作命令(3)

目录 1.Docker服务管理命令&#xff1a; 启动&#xff1a;systemctl start docker 停止&#xff1a;systemctl stop docker 重启&#xff1a;systemctl restart docker 开机自启&#xff1a;systemctl enable docker 查看docker版本&#xff1a; 2.镜像常用管理命令&…

5.31——进军MYSQL

目录 简略版&#xff1a; 详解版&#xff1a; 一. myaql概述&#xff1a; 数据库&#xff1a; 数据库管理系统&#xff1a; SQL&#xff1a; 二. masql的安装&#xff1a; 启动与停止&#xff1a; 1. MYSQL提供的命令行工具 2. windows提供的命令行工具 三.数据模…

【Word】调整列表符号与后续文本的间距

1. 默认的列表格式&#xff1a; 2. 修改间距&#xff1a; ************************************************** 分割线 ************************************************************ 3. 效果

微型导轨在自动化制造中有哪些优势?

微型导轨在自动化制造中发挥重要作用&#xff0c;能够满足自动化设备制造中对精度要求较高的工艺环节。适用于自动装配线、自动检测设备和机器人操作等环节&#xff0c;推动了行业的进步与发展。那么&#xff0c;微型导轨在使用中有哪些优势呢&#xff1f; 1、精度高和稳定性强…

华为S5700交换机版本升级步骤

在用一台华为交换机。由于需要做目的镜像接口&#xff0c;在配置过程中超过一个双向流量观察口就会报错。从官方文档查到可以升级版本解决。记录一下升级过程。 首先确定设备型号S5700-28C-EI&#xff0c;版本&#xff1a; s5700ei-v100r005c01spc100。一定仔细阅读官方文档。明…

美国RAKsmart海外大带宽服务器的显著特点

美国RAKsmart海外大带宽服务器在当前的互联网服务领域中备受瞩目&#xff0c;其显著特点主要体现在以下几个方面&#xff1a; 高带宽资源&#xff1a;RAKsmart服务器拥有充足的带宽资源&#xff0c;最低提供100M独享带宽&#xff0c;并支持升级至G口、10G口大带宽方案。这种高带…

CPU基本接口实验

一、实验目的与要求 1.通过 I/O 控制小灯闪烁的过程&#xff1b;在 CC2530 节点板上运行自己的程序。 2.了解 CC2530 片内 ADC 工作过程&#xff1b;能正确配置 CC2530 片内 ADC 让其正确工作。 3.&#xff08;选做&#xff09;如何捕获一个外部中断和 CC2530 捕获外部中断后的…

再度“痛失”TOP5的小米手机,能否接好这碗AI“大活水”?

国产手机终端需求持续修复&#xff0c;国产品牌商是最大受益者。 近日&#xff0c;中国信通院发布2024年4月国内手机市场运行分析报告。报告显示&#xff0c;今年4月&#xff0c;国内市场手机出货量同比增长了28.8%。按品牌来看&#xff0c;国产品牌手机4月出货量占同期手机出…

音视频开发—H265相关概念和压缩原理详解(GOP、宏块、帧内压缩、帧间压缩)

文章目录 1.什么是GOP&#xff1f;1.1 GOP介绍1.2.GOP中I帧/B帧/P帧1.3.I帧和IDR的区别联系I帧&#xff08;Intra Frame&#xff09;IDR帧&#xff08;Instantaneous Decoding Refresh Frame&#xff09;区别总结 1.4 帧与分组的关系1.5 SPS与PPSSPS&#xff08;Sequence Param…

js四舍五入和计算精度问题处理

js四舍五入和计算精度问题处理 目录 js四舍五入和计算精度问题处理错误计算方法示例代码 js中加减乘除&#xff0c;部分数据会存在计算不准确。 错误计算 我使用的是big.js&#xff0c;基于big.js库封装了下工具方法&#xff0c;当然也可以用其他库&#xff0c;如mathjs/bignu…

HackTheBox-Machines--Sense

Popcorn 测试过程 1 信息收集 服务器开启80、443端口 80端口 访问 80 跳转到 443 – https://10.129.196.51/ &#xff0c;该页面是 pfSense 登录界面&#xff0c;默认密码是&#xff1a; admin/pfSense&#xff0c;使用默认账号密码登录失败 目录扫描 ./gobuster dir -u htt…

安卓六种页面加载优化方案对比总结

根据工作经验&#xff0c;笔者提炼了六种页面加载优化方式&#xff0c;按照业务与非业务&#xff0c;将六种加载方式分为两类&#xff1a; 业务类 控制业务与UI的执行顺序、控制多业务之间的执行顺序 ①预加载&#xff1a;是指在进入页面之前&#xff0c;提前获得页面所需得数据…

emp.dll文件丢失要怎么解决?荒野大镖客emp.dll修复方法分享

软件运行过程中经常遇到各种技术问题&#xff0c;其中之一就是动态链接库&#xff08;DLL&#xff09;文件丢失的现象。DLL文件是Windows操作系统中一个重要的组件&#xff0c;它包含运行多个应用程序所需要的代码和数据。因此&#xff0c;一个丢失的DLL文件&#xff0c;如“em…

uniapp 添加字体ttf

效果图如下 一、逻辑概述 在uniapp中使用字体&#xff0c;一共分成两种情况&#xff0c;一种是普通vue页面&#xff0c;一种是nvue页面引入字体。。 1.vue页面引入字体需要如下步骤 1. 先选择下载一种字体&#xff1a;字体格式一般为 ttf后缀名 黄凯桦律师手写体免费下载和在线…

JVM优化之垃圾收集器

JVM优化之垃圾收集器 Serial收集器Parallel Scavenge收集器ParNew收集器 如果说垃圾收集算法是内存回收的方法论&#xff0c;那么垃圾收集器就是内存回收的具体实现。 没有最好的垃圾收集器&#xff0c;只有根据具体应用场景选择适合自己的垃圾收集器。 Serial收集器 #使用方…

代码审计(工具Fortify 、Seay审计系统安装及漏洞验证)

源代码审计 代码安全测试简介 代码安全测试是从安全的角度对代码进行的安全测试评估。&#xff08;白盒测试&#xff1b;可看到源代码&#xff09; 结合丰富的安全知识、编程经验、测试技术&#xff0c;利用静态分析和人工审核的方法寻找代码在架构和编码上的安全缺陷&#xf…

如何安装使用秋叶comfyui整合包,手把手详细教程(文末附安装包)

B 站的秋叶大佬在 1 月份就已经发布了 comfy ui 的整合包。用户将压缩包下载后&#xff0c;能够一键启动 comfy ui。其便利性与之前的 webui 整合包如出一辙。然而在整合包下载完成后&#xff0c;新手或许会遭遇插件以及模型缺失的情况&#xff0c;同时也不清楚该如何运行工作流…

HackTheBox-Machines--Popcorn

文章目录 0x01 端口扫描0x02 测试思路2.1 80端口测试 0x03 /torrent 目录文件上传测试0x04 权限提升 Popcorn 测试过程 0x01 端口扫描 (base) gryphonwsdl ~ %nmap -sC -sV 10.129.138.22 Starting Nmap 7.94 ( https://nmap.org ) at 2024-05-28 14:22 CST Nmap scan report …

用任务监听RTOS各任务的运行状态

使用rtos时内存对于单片机来说总是非常抠搜的。 任务分配多了浪费&#xff0c;少了跑不动。 最近看到这个监听任务还是很好用的。 废话不多说。开始操作 第一步在配置文件中打开这几个宏 #define configUSE_TRACE_FACILITY 1 /*为1时启用可视化跟踪调试*/ #define conf…