当前位置: 首页 > article >正文

基于React + FastAPI + LangChain + 通义千问的智能医疗问答系统

📌 文章摘要:

本文详细介绍了如何在前端通过 Fetch 实现与 FastAPI 后端的 流式响应通信,并支持图文多模态数据上传。通过构建 multipart/form-data 请求,配合 ReadableStream 实时读取 AI 回复内容,实现类似 ChatGPT 的对话效果。同时提供完整的接口调用代码和 UI 展示逻辑,帮助开发者快速搭建自然流畅的 AI 医疗助手交互界面。

正常提问

经过RAG处理提问

项目简介

AI医疗助手是一个结合了最新人工智能技术的医疗问答系统,旨在为用户提供准确、专业的医疗咨询服务。系统采用前后端分离架构,前端使用React构建友好的用户界面,后端使用FastAPI提供高性能的API服务,并结合LangChain框架和通义千问大语言模型提供智能问答能力。本项目是本人用于学习LangChain框架的练手项目,后续会继续完善。

核心功能

  • 🩺 医疗问答:针对用户的医疗问题提供专业解答
  • 💬 实时对话:流式响应,打字机效果,提升用户体验
  • 🧠 上下文记忆:支持多轮对话,理解上下文信息
  • 📚 知识检索:基于RAG技术,从医疗知识库中检索相关信息
  • 🎨 美观界面:现代化的聊天UI,支持Markdown渲染
  • 🔄 对话记忆:自动保存对话历史,支持会话恢复

技术栈

前端

  • 框架:React 19 + TypeScript
  • 状态管理:React Hooks
  • 样式:CSS Modules
  • 网络请求:Fetch API(支持流式响应)
  • 组件
    • 自定义聊天界面
    • Markdown渲染 (react-markdown)
    • 弹窗组件
    • 消息提示 (react-hot-toast)

后端

  • 框架:FastAPI (Python)
  • AI框架:LangChain 0.3.0
  • 大语言模型:通义千问 (qwen-turbo/qwen-plus/qwen-max)
  • 向量数据库:Chroma
  • 文本嵌入:DashScope Embeddings
  • 流式响应:SSE (Server-Sent Events)
  • 文档处理:LangChain Text Splitters

系统架构

✅ 2. 核心功能组件代码展示

App.css

/* 基础布局样式 */.App {text-align: center;display: flex;flex-direction: column;height: 100vh;font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;background-color: #f8fbfd;
}/* 头部样式 */.App-header {background-color: #1e88e5;background-image: linear-gradient(135deg, #1e88e5 0%, #0d47a1 100%);min-height: 80px;display: flex;flex-direction: column;align-items: center;justify-content: center;color: white;box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);padding: 12px 20px;position: relative;
}.App-header::after {content: '';position: absolute;bottom: 0;left: 0;right: 0;height: 4px;background: linear-gradient(90deg, #29b6f6, #4fc3f7, #81d4fa);
}.logo-container {display: flex;align-items: center;gap: 10px;
}.logo-icon {font-size: 28px;
}.App-header h1 {margin: 0;font-size: 1.8rem;font-weight: 600;letter-spacing: 0.5px;
}.header-subtitle {font-size: 0.9rem;opacity: 0.9;margin-top: 4px;font-weight: 400;
}/* 主体内容样式 */main {flex-grow: 1;display: flex;flex-direction: column;max-width: 1100px;width: 100%;margin: 0 auto;padding: 0;position: relative;
}main>div {flex-grow: 1;height: 100%;border-radius: 12px;margin: 15px;overflow: hidden;box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);background-color: white;border: 1px solid #e0e6ed;
}/* 底部样式 */.App-footer {background-color: #f1f5f9;color: #64748b;font-size: 0.8rem;padding: 12px;text-align: center;border-top: 1px solid #e2e8f0;
}/* 响应式设计 */@media (max-width: 768px) {.App-header {padding: 10px;min-height: 60px;}.App-header h1 {font-size: 1.4rem;}.logo-icon {font-size: 24px;}main>div {margin: 8px;border-radius: 8px;}.header-subtitle {font-size: 0.8rem;}
}@media (max-width: 480px) {.App-header h1 {font-size: 1.2rem;}.logo-icon {font-size: 20px;}main>div {margin: 4px;border-radius: 6px;}.header-subtitle {display: none;}
}

MessageList.css

.message-list {display: flex;flex-direction: column;padding: 1rem;overflow-y: auto;flex: 1;max-height: calc(100vh - 170px);
}.message {margin-bottom: 1rem;display: flex;flex-direction: column;max-width: 80%;
}.user-message {align-self: flex-end;
}.assistant-message {align-self: flex-start;
}.message-content {padding: 0.8rem;border-radius: 8px;box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}.user-message .message-content {background-color: #e3f2fd;color: #0d47a1;
}.assistant-message .message-content {background-color: #f5f5f5;color: #333;
}.message-header {display: flex;justify-content: space-between;margin-bottom: 0.5rem;font-size: 0.8rem;color: #666;
}.message-role {font-weight: bold;
}.message-time {font-size: 0.7rem;
}.message-text {white-space: pre-wrap;word-break: break-word;line-height: 1.5;
}.empty-messages {display: flex;flex-direction: column;align-items: center;justify-content: center;height: 100%;color: #9e9e9e;text-align: center;padding: 2rem;
}.empty-messages p {font-size: 1.1rem;margin-bottom: 1rem;
}

ChatInput.css


.chat-input-form {padding: 1rem;border-top: 1px solid #eaeaea;background-color: #fff;
}.input-container {display: flex;position: relative;
}.message-input {flex: 1;min-height: 60px;max-height: 200px;padding: 12px;border: 1px solid #ccc;border-radius: 8px;resize: vertical;font-family: inherit;font-size: 1rem;outline: none;transition: border-color 0.3s;
}.message-input:focus {border-color: #2196f3;
}.message-input:disabled {background-color: #f9f9f9;cursor: not-allowed;
}.send-button {margin-left: 10px;padding: 0 20px;height: 40px;align-self: flex-end;background-color: #2196f3;color: white;border: none;border-radius: 8px;cursor: pointer;font-weight: bold;transition: background-color 0.3s;
}.send-button:hover:not(:disabled) {background-color: #0d8bf2;
}.send-button:disabled {background-color: #cccccc;cursor: not-allowed;
}.input-help-text {margin-top: 0.5rem;font-size: 0.75rem;color: #757575;text-align: right;
}

ChatInterface.css

.chat-container {display: flex;flex-direction: column;/* height: 100vh; */width: 100%;max-height: 86vh;background-color: #f8fbfd;position: relative;overflow: hidden;
}/* 聊天历史区域 */.messages-container {flex: 1;overflow-y: auto;padding: 2rem;padding-bottom: 2rem;display: flex;flex-direction: column;gap: 1rem;scrollbar-width: thin;scrollbar-color: rgba(0, 0, 0, 0.2) transparent;scroll-behavior: smooth;background-image: linear-gradient(rgba(255, 255, 255, 0.8) 0%, rgba(255, 255, 255, 0.9) 100%), url('data:image/svg+xml;utf8,<svg width="100" height="100" viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><path d="M10 10h10v10H10zM30 10h10v10H30zM50 10h10v10H50zM70 10h10v10H70zM20 20h10v10H20zM40 20h10v10H40zM60 20h10v10H60zM80 20h10v10H80zM10 30h10v10H10zM30 30h10v10H30zM50 30h10v10H50zM70 30h10v10H70z" fill="%23E3F2FD" fill-opacity="0.1"/></svg>');
}/* 美化滚动条 */.messages-container::-webkit-scrollbar {width: 6px;
}.messages-container::-webkit-scrollbar-track {background: transparent;
}.messages-container::-webkit-scrollbar-thumb {background-color: rgba(0, 0, 0, 0.2);border-radius: 3px;
}.messages-container::-webkit-scrollbar-thumb:hover {background: #a1c4e4;
}/* 消息气泡容器 */.message {max-width: 85%;display: flex;flex-direction: column;position: relative;animation: fadeIn 0.3s ease-out;
}@keyframes fadeIn {from {opacity: 0;transform: translateY(10px);}to {opacity: 1;transform: translateY(0);}
}.message.user {align-self: flex-end;
}.message.assistant {align-self: flex-start;
}.message.system {align-self: center;max-width: 90%;margin: 8px 0;
}/* 消息气泡 */.message-bubble {padding: 14px 16px;border-radius: 18px;word-break: break-word;line-height: 1.5;position: relative;font-size: 15px;letter-spacing: 0.2px;transition: all 0.2s ease;text-align: left;
}/* 用户消息气泡 */.user .message-bubble {background-color: #0d6efd;color: white;border-bottom-right-radius: 4px;box-shadow: 0 2px 8px rgba(13, 110, 253, 0.2);
}/* 助手消息气泡 */.assistant .message-bubble {background-color: #e9f3ff;color: #0a2642;border-bottom-left-radius: 4px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);border-left: 3px solid #4dabf7;
}.assistant .message-bubble::before {content: '🩺';position: absolute;left: -30px;top: 2px;font-size: 16px;color: #4dabf7;background: white;width: 24px;height: 24px;border-radius: 50%;display: flex;align-items: center;justify-content: center;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}/* 系统消息气泡 */.system .message-bubble {background-color: #fff3cd;color: #856404;border-radius: 10px;border-left: 3px solid #ffc107;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}/* 消息信息 */.message-info {font-size: 12px;color: #8e8e93;margin-top: 4px;padding: 0 8px;display: flex;align-items: center;
}.user .message-info {justify-content: flex-end;
}/* 输入区域 */.input-container {flex-shrink: 0;padding: 1rem;background-color: white;border-top: 1px solid #e0e6ed;display: flex;gap: 10px;z-index: 100;position: sticky;bottom: 0;left: 0;right: 0;width: 100%;/* box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05); */
}.input-container::before {content: '';position: absolute;top: -20px;left: 0;right: 0;height: 20px;background: linear-gradient(to bottom, rgba(248, 251, 253, 0), rgba(248, 251, 253, 1));pointer-events: none;
}.input-container input {flex: 1;border: 1px solid #d1e3f8;padding: 12px 16px;border-radius: 24px;background-color: #f8fbfd;margin-right: 10px;font-size: 15px;outline: none;transition: all 0.2s ease;color: #0a2642;
}.input-container input:focus {border-color: #4dabf7;box-shadow: 0 0 0 3px rgba(77, 171, 247, 0.2);background-color: white;
}.input-container input::placeholder {color: #99b2cc;
}.input-container button {background-color: #0d6efd;color: white;border: none;border-radius: 24px;padding: 0 24px;font-weight: 600;cursor: pointer;transition: all 0.2s ease;display: flex;align-items: center;justify-content: center;height: 42px;
}.input-container button:hover:not(:disabled) {background-color: #0b5ed7;transform: translateY(-1px);box-shadow: 0 2px 5px rgba(11, 94, 215, 0.3);
}.input-container button:active:not(:disabled) {transform: translateY(0);box-shadow: none;
}.input-container button:disabled {background-color: #b9d7ff;cursor: not-allowed;
}/* 打字指示器动画 */.typing-indicator {display: inline-block;position: relative;width: 60px;height: 24px;
}.typing-indicator::before {content: "";position: absolute;width: 10px;height: 10px;border-radius: 50%;background-color: #4dabf7;left: 0;animation: typing-dot 1.4s infinite ease-in-out both;animation-delay: -0.32s;
}.typing-indicator::after {content: "";position: absolute;width: 10px;height: 10px;border-radius: 50%;background-color: #4dabf7;right: 0;animation: typing-dot 1.4s infinite ease-in-out both;animation-delay: 0s;
}.typing-indicator span {position: absolute;top: 0;width: 10px;height: 10px;border-radius: 50%;background-color: #4dabf7;left: 22px;animation: typing-dot 1.4s infinite ease-in-out both;animation-delay: -0.16s;
}@keyframes typing-dot {0%,80%,100% {transform: scale(0.7);opacity: 0.6;}40% {transform: scale(1);opacity: 1;}
}/* 响应式设计 */@media (max-width: 768px) {.message-bubble {padding: 12px 14px;font-size: 14px;}.assistant .message-bubble::before {display: none;}.input-container {padding: 12px;}.input-container input {padding: 10px 14px;}.input-container button {padding: 0 16px;height: 38px;}
}@media (max-width: 480px) {.messages-container {padding: 15px 10px;}.message {max-width: 90%;}.message-bubble {padding: 10px 12px;font-size: 14px;}.input-container input {padding: 10px 12px;}.input-container button {padding: 0 15px;font-size: 14px;}
}.chat-header {padding: 1rem;background-color: #2196f3;color: white;display: flex;justify-content: space-between;align-items: center;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);flex-shrink: 0;z-index: 10;
}.chat-header h1 {margin: 0;font-size: 1.5rem;font-weight: 500;
}.conversation-id {font-size: 0.8rem;opacity: 0.8;
}.error-message {padding: 0.8rem;margin: 0.5rem 1rem;background-color: #ffebee;color: #c62828;border-radius: 4px;font-size: 0.9rem;
}/* Markdown样式 */.markdown-content {margin: 0;line-height: 1.5;text-align: left;
}.markdown-content p,
.markdown-content ul,
.markdown-content ol,
.markdown-content h1,
.markdown-content h2,
.markdown-content h3,
.markdown-content h4,
.markdown-content h5,
.markdown-content h6 {text-align: left;
}.markdown-content p {margin: 0 0 0.8em;
}.markdown-content p:last-child {margin-bottom: 0;
}.markdown-content h1,
.markdown-content h2,
.markdown-content h3,
.markdown-content h4,
.markdown-content h5,
.markdown-content h6 {margin-top: 1em;margin-bottom: 0.5em;font-weight: 600;line-height: 1.25;color: #003366;
}.markdown-content h1 {font-size: 1.5em;
}.markdown-content h2 {font-size: 1.3em;
}.markdown-content h3 {font-size: 1.1em;
}.markdown-content ul,
.markdown-content ol {margin-top: 0;margin-bottom: 1em;padding-left: 2em;
}.markdown-content li {margin: 0.3em 0;
}.markdown-content a {color: #0d6efd;text-decoration: none;
}.markdown-content a:hover {text-decoration: underline;
}.markdown-content blockquote {margin: 0.8em 0;padding: 0 1em;color: #0d47a1;border-left: 3px solid #90caf9;background-color: rgba(144, 202, 249, 0.1);
}.markdown-content code {font-family: monospace;padding: 0.2em 0.4em;margin: 0;font-size: 85%;border-radius: 3px;background-color: rgba(0, 0, 0, 0.05);color: #d32f2f;
}.markdown-content pre {margin: 0.8em 0;padding: 0.8em;overflow: auto;background-color: #f1f5f9;border-radius: 4px;
}.markdown-content pre code {padding: 0;background-color: transparent;color: #0a2642;
}.markdown-content table {border-collapse: collapse;width: 100%;margin: 1em 0;
}.markdown-content table th,
.markdown-content table td {padding: 6px 12px;border: 1px solid #e0e6ed;text-align: left;
}.markdown-content table th {background-color: rgba(77, 171, 247, 0.1);font-weight: 600;
}.markdown-content table tr:nth-child(even) {background-color: rgba(244, 247, 250, 0.7);
}.markdown-content img {max-width: 100%;height: auto;border-radius: 4px;margin: 0.5em 0;
}.markdown-content hr {height: 1px;margin: 1em 0;background-color: #e0e6ed;border: none;
}/* 医疗相关样式 */.markdown-content .highlight-warning {background-color: #fff3cd;padding: 8px 12px;border-radius: 4px;border-left: 3px solid #ffc107;margin: 0.8em 0;
}.markdown-content .highlight-info {background-color: #e9f3ff;padding: 8px 12px;border-radius: 4px;border-left: 3px solid #4dabf7;margin: 0.8em 0;
}/* 医疗专业术语 */.markdown-content .medical-term {border-bottom: 1px dashed #4dabf7;
}/* 响应式样式 */@media (max-width: 768px) {.markdown-content h1 {font-size: 1.3em;}.markdown-content h2 {font-size: 1.2em;}.markdown-content h3 {font-size: 1.1em;}.markdown-content pre {padding: 0.6em;}.markdown-content blockquote {padding: 0 0.8em;}
}/* 添加头部样式 */.header {display: flex;justify-content: space-between;align-items: center;padding: 15px 20px;background-color: #f0f8ff;border-bottom: 1px solid #e0e6ed;
}.title {font-size: 1.5rem;font-weight: 600;color: #003366;
}.actions {display: flex;gap: 12px;
}/* 流式响应开关样式 */.stream-toggle {display: flex;align-items: center;
}.toggle-label {display: flex;align-items: center;cursor: pointer;font-size: 0.9rem;color: #444;
}.toggle-label input[type="checkbox"] {margin-right: 6px;width: 16px;height: 16px;cursor: pointer;
}.toggle-label input[type="checkbox"]:disabled {opacity: 0.5;cursor: not-allowed;
}.toggle-label input[type="checkbox"]:checked+span {color: #0078d7;font-weight: 500;
}/* 消息图片样式 */.message-image-container {margin-bottom: 8px;max-width: 100%;
}.message-image {max-width: 100%;max-height: 300px;border-radius: 8px;cursor: pointer;
}/* 图片预览区域 */.image-preview-container {margin: 0 16px;padding: 8px;position: relative;display: inline-block;max-width: 150px;margin-bottom: 8px;
}.image-preview {width: 100%;max-height: 150px;object-fit: contain;border-radius: 8px;border: 1px solid #e1e1e1;
}.clear-image-button {position: absolute;top: 0;right: 0;width: 24px;height: 24px;border-radius: 50%;background-color: rgba(0, 0, 0, 0.5);color: white;border: none;font-size: 16px;display: flex;align-items: center;justify-content: center;cursor: pointer;
}.clear-image-button:hover {background-color: rgba(0, 0, 0, 0.7);
}/* 输入区域样式 */.input-container {display: flex;padding: 12px 16px;border-top: 1px solid #e1e1e1;background-color: #f9f9f9;align-items: center;
}.input-container input[type="text"] {flex: 1;padding: 10px 16px;border: 1px solid #d1d1d1;border-radius: 20px;font-size: 16px;outline: none;transition: border 0.3s;
}.input-container input[type="text"]:focus {border-color: #4a89dc;
}.input-container input[type="text"].with-image {border-color: #4a89dc;background-color: #f0f7ff;
}/* 图片上传按钮 */.image-upload-button {width: 38px;height: 38px;border-radius: 50%;background-color: #f0f0f0;border: 1px solid #d1d1d1;margin-right: 10px;cursor: pointer;display: flex;align-items: center;justify-content: center;padding: 0;
}.image-upload-button svg {fill: #5a5a5a;width: 20px;height: 20px;
}.image-upload-button:hover {background-color: #e3e3e3;
}.image-upload-button:disabled {opacity: 0.5;cursor: not-allowed;
}/* 发送按钮 */.send-button {margin-left: 10px;padding: 10px 20px;background-color: #4a89dc;color: white;border: none;border-radius: 20px;font-weight: 500;cursor: pointer;transition: background-color 0.3s;
}.send-button:hover {background-color: #3a79d2;
}.send-button:disabled {opacity: 0.5;cursor: not-allowed;
}/* 流式响应开关 */.stream-toggle {display: flex;align-items: center;margin-right: 10px;
}.toggle-label {display: flex;align-items: center;cursor: pointer;font-size: 14px;color: #666;
}.toggle-label input {margin-right: 6px;
}/* 响应式设计调整 */@media (max-width: 600px) {.image-upload-button {width: 34px;height: 34px;}.image-upload-button svg {width: 18px;height: 18px;}.send-button {padding: 8px 12px;font-size: 14px;}
}

✅ 3. API 接口调用代码(Fetch 流式响应)

在本项目中,我们通过 FastAPI 搭建了一个支持多模态聊天(图文)和图生图的 AI 医疗助手系统。前端使用 Fetch 实现与后端的流式响应通信,实现了更自然的人机交互体验。

本文将聚焦于前端调用后端接口的 流式响应实现方式,并结合项目的接口说明,展示完整的调用代码和注意事项。

🧠 为什么选择流式响应?

传统的 HTTP 请求是在服务端处理完所有数据后一次性返回,而 流式响应(Streaming Response) 能够实现像 ChatGPT 一样 “字一个一个地出来”,提高用户体验。

流式的技术基础:

  • 服务端使用 yieldStreamingResponse 分块发送数据;

  • 客户端使用 Fetch + ReadableStream 实现逐块接收并展示内容。

🛠️ 后端接口回顾

POST /api/chat/multimodal
Content-Type: multipart/form-data
Form fields:
- conversation_id: string
- text: string
- image: file (optional)Response: 流式返回 AI 回复内容

📜 前端 Fetch 调用示例(流式读取)

const controller = new AbortController(); // 用于中止请求
const signal = controller.signal;async function chatWithAI({ conversationId, inputText, imageFile }) {const formData = new FormData();formData.append("conversation_id", conversationId);formData.append("text", inputText);if (imageFile) {formData.append("image", imageFile);}const response = await fetch("http://localhost:8000/api/chat/multimodal", {method: "POST",body: formData,signal,});if (!response.ok) {throw new Error("请求失败: " + response.statusText);}const reader = response.body.getReader();const decoder = new TextDecoder("utf-8");let resultText = "";while (true) {const { value, done } = await reader.read();if (done) break;const chunk = decoder.decode(value, { stream: true });resultText += chunk;// 你可以在此处逐步展示文本(如更新 chat UI)appendToChatUI(chunk);}return resultText;
}

📦 UI 使用场景示例

<input type="file" id="imageInput" />
<input type="text" id="textInput" placeholder="请输入咨询内容" />
<button onclick="handleSubmit()">发送</button>
<div id="chatBox"></div><script>async function handleSubmit() {const imageInput = document.getElementById("imageInput").files[0];const text = document.getElementById("textInput").value;const chatBox = document.getElementById("chatBox");chatBox.innerHTML += "<div class='user-msg'>" + text + "</div>";try {await chatWithAI({conversationId: "user-session-123",inputText: text,imageFile: imageInput});} catch (err) {console.error("请求失败", err);}}function appendToChatUI(textChunk) {let botMsg = document.querySelector(".bot-msg:last-child");if (!botMsg || botMsg.getAttribute("finished")) {botMsg = document.createElement("div");botMsg.className = "bot-msg";document.getElementById("chatBox").appendChild(botMsg);}botMsg.innerText += textChunk;}
</script>

相关文章:

基于React + FastAPI + LangChain + 通义千问的智能医疗问答系统

&#x1f4cc; 文章摘要&#xff1a; 本文详细介绍了如何在前端通过 Fetch 实现与 FastAPI 后端的 流式响应通信&#xff0c;并支持图文多模态数据上传。通过构建 multipart/form-data 请求&#xff0c;配合 ReadableStream 实时读取 AI 回复内容&#xff0c;实现类似 ChatGPT…...

C# 中替换多层级数据的 Id 和 ParentId,保持主从或父子关系不变

在C#中替换多层级数据的Id和ParentId&#xff0c;同时保持父子关系不变&#xff0c;可以通过以下步骤实现&#xff1a; 创建旧Id到新Id的映射&#xff1a;遍历所有节点&#xff0c;为每个旧Id生成唯一的新Id&#xff0c;并存储在字典中。 替换节点的Id和ParentId&#xff1a;…...

Scade 语言概念 - 方程(equation)

在 Scade 6 程序中自定义算子(Operator)的定义、或数据流定义(data_def)的内容中&#xff0c;包含一种基本的语言结构&#xff1a;方程(equation)(注1)。在本篇中&#xff0c;将叙述 Scade 语言方程的文法形式&#xff0c;以及作用。 注1: 对 Scade 中的 equation, 或 equation…...

PG 分区表的缺陷

简介 好久没发文&#xff0c;是最近我实在不知道写点啥。随着国产化进程&#xff0c;很多 oracle 都在进行迁移&#xff0c;最近遇到了一个分区表迁移之后唯一性的问题。oracle 数据库中创建主键或者唯一索引&#xff0c;不需要引用分区键&#xff0c;但是 PG 就不行&#xff…...

从Copilot到Agent,AI Coding是如何进化的?

编程原本是一项具有一定门槛的技能&#xff0c;但借助 AI Coding 产品&#xff0c;新手也能写出可运行的代码&#xff0c;非专业人员如业务分析师、产品经理&#xff0c;也能在 AI 帮助下直接生成简单应用。 这一演变对软件产业产生了深远影响。当 AI 逐步参与代码生成、调试乃…...

Qt(part 2)1、Qwindow(菜单栏,工具栏,状态栏),铆接部件,核心部件 ,2、添加资源文件 3、对话框

1、Qwindow tips&#xff1a;1&#xff0c;首先为什么创建出的对象基本都是指针形式&#xff0c;个人觉得是对象树的原因&#xff08;自动释放内存&#xff09;&#xff0c;指针来访问成员函数->的形式。2&#xff0c;菜单栏只能一个的&#xff0c;放窗口基本Set&#xff0c…...

【图片识别Excel】批量提取图片中的文字,图片设置识别区域,识别后将文字提取并保存Excel表格,基于WPF和OCR识别的应用

应用场景 在办公自动化、文档处理、数据录入等场景中&#xff0c;经常需要从大量图片中提取文字信息。例如&#xff1a; 批量处理扫描的表单、合同、发票等文档从图片集中提取特定区域的文字数据将纸质资料快速转换为电子文本并整理归档 通过设置识别区域&#xff0c;可以精…...

深入理解 Java 多线程:原理剖析与实战指南

深入理解 Java 多线程&#xff1a;原理剖析与实战指南 一、引言 在现代软件开发中&#xff0c;多线程编程已经成为提升应用性能与响应能力的重要手段。Java 作为一门成熟的编程语言&#xff0c;自 JDK 1.0 起就提供了对多线程的原生支持。本文将深入剖析 Java 多线程的底层原…...

Qt/C++学习系列之Excel使用记录

Qt/C学习系列之Excel使用记录 前言The process was ended forcefully.解决方式断点查语句问题 总结 前言 在项目中解析条目达50多条&#xff0c;并且都需要将对应的结果进行显示。为了将结果显示的更加清晰&#xff0c;考虑采用QTableWidget进行表格设置&#xff0c;而在使用过…...

跳转指令四维全解:从【call/jmp 】的时空法则到内存迷宫导航术

一、核心概念&#xff1a;代码世界的空间定位法则 在汇编世界里&#xff0c;我们可以把内存想象成一栋巨大的图书馆&#xff1a; CS&#xff08;代码段寄存器&#xff09; 楼层编号 IP&#xff08;指令指针&#xff09; 房间编号 当前执行位置 CS:IP&#xff08;如3楼201…...

LabVIEW实时系统数据监控与本地存储

基于LabVIEW Real-Time 模块&#xff0c;面向工业自动化、嵌入式测控等场景&#xff0c;提供实时数据采集、监控与本地存储的完整实现路径。通过分层任务调度、TDMS 文件格式应用及跨平台兼容性设计&#xff0c;确保系统在实时性、可靠性与数据管理效率间达到平衡。文中以 Comp…...

从 Revit 到 3DTiles:GISBox RVT 切片器如何让建筑图元在 Web 端展示

在GIS&#xff08;地理信息系统&#xff09;行业蓬勃发展的当下&#xff0c;数据处理与展示的效率和精准度成为关键。GISBox作为一款功能强大的一站式三维GIS数据编辑、转换、发布平台&#xff0c;凭借其独特的“RVT切片器”功能&#xff0c;在RVT图元处理方面也有着不俗的表现…...

Appium+python自动化(十二)- Android UIAutomator

Android团队在4.1版本&#xff08;API 16&#xff09;中推出了一款全新的UI自动化测试工具UiAutomator&#xff0c;用来帮助开发人员更有效率的完成App的Debug工作&#xff0c;同时对于测试人员也是一大福音&#xff0c;为什么这么说呢&#xff1f; UiAutomator提供了以下两种…...

在C语言中使用UUID作为AES加密密钥

在C语言中使用UUID作为AES加密密钥 编译依赖安装示例代码编译和运行关键点说明![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0df1f1d803cd40688f6d58a9d0e1f1d9.png)注意事项编译依赖安装 运行环境位centos8 Linux 4.18.0-348.7.1.el8_5.x86_64 #1 SMP Wed Dec …...

Nginx+Tomcat负载均衡集群

目录 一、Tomcat 基础与单节点部署 &#xff08;一&#xff09;Tomcat 概述 &#xff08;二&#xff09;单节点部署案例 1. 案例环境 2. 实施准备 3. 安装 JDK 4. 查看 JDK 安装情况 5. 安装配置 Tomcat 6. 启动 Tomcat 7. 访问测试 8. 关闭 Tomcat &#xff08;三…...

QQ邮箱发送验证码(Springboot)

一、邮箱发送服务准备 在qq邮箱的设置中选择账号下开启服务。 开启时可能会有短信验证&#xff0c;开启后显示验证码之类的一串英文&#xff0c;复制保存起来&#xff0c;在配置文件中会使用到。 二、后端依赖及配置 依赖 在pom.yml文件中添加相关依赖&#xff0c;redis的…...

Python Copilot【代码辅助工具】 简介

粉丝爱买鳕鱼肠深海鳕鱼肉鱼肉香肠盼盼麦香鸡味块卡乐比&#xff08;Calbee&#xff09;薯条三兄弟 独立小包美丽雅 奶茶杯一次性饮料杯好时kisses多口味巧克力糖老金磨方【黑金系列】黑芝麻丸郑新初网红郑新初烤鲜牛肉干超人毛球修剪器去球器剃毛器衣服去毛器优惠券宁之春 红黑…...

如何写高效的Prompt?

概述 提示词(Prompt)的质量将直接影响模型生成结果的质量&#xff0c;所以精心设计一个让大模型能够理解并有效回复的提示词是至关重要的。本文内容自论文中获取&#xff1a;https://arxiv.org/pdf/2312.16171 介绍了5类共计26条提示词书写原则。 书写原则 类别原则备注快速…...

【EF Core】 EF Core并发控制:乐观锁与悲观锁的应用

文章目录 前言一、并发的风险二、EF Core中的并发控制方式2.1 开放式并发&#xff08;乐观锁&#xff09;2.1.1 应用程序管理的属性并发令牌2.1.2 数据库生成的并发令牌 2.2 悲观锁 总结 前言 实际的生产环境中&#xff0c;我们经常能遇到数据库由多个应用程序同时使用。每个程…...

WaytoAGI东京大会开启AI全球化新对话:技术无国界,合作促创新

全球AI专家齐聚东京&#xff0c;一场关于技术无国界的对话正在进行。 2025年6月7日&#xff0c;一场备受瞩目的AI盛会——“WaytoAGI全球AI大会东京站”在日本东京樱美林大学新宿校区正式拉开帷幕。这场为期两天的会议&#xff08;6月7日至8日&#xff09;由国内最大的AI开源知…...

Harmony核心:动态方法修补与.NET游戏Mod开发

一、Harmony的核心定位与设计哲学 Harmony是一个运行时动态方法修补库&#xff0c;专为修改已编译的.NET/Mono应用程序而设计&#xff0c;尤其适用于游戏Mod开发。其核心创新在于&#xff1a; 非破坏性修改&#xff1a;保留原始方法完整性&#xff0c;避免直接替换或覆盖。多…...

AI系统应用开发工程师

以下是对AI系统应用开发与运维岗位的梳理整合&#xff0c;从企业、岗位、任务、能力等维度进行分类呈现&#xff0c;便于清晰对比两者的工作侧重&#xff1a; 一、代表性企业对比 分类企业名称应用开发方向中移系统集成有限公司、科大讯飞河北科技有限公司、华为技术服务有限…...

Qt Test功能及架构

Qt Test 是 Qt 框架中的单元测试模块&#xff0c;在 Qt 6.0 中提供了全面的测试功能。 一、主要功能 核心功能 1. 单元测试框架 提供完整的单元测试基础设施 支持测试用例、测试套件的组织和执行 包含断言宏和测试结果收集 2. 测试类型支持 单元测试&#xff1a;对单个函…...

图像处理、图像分析和图像理解的定义、联系与区别

1. 定义 图像处理&#xff08;Image Processing&#xff09; 图像处理是低层操作&#xff0c;主要针对像素级的图像数据进行加工&#xff0c;目的是改善图像质量或为后续分析做准备。 典型任务&#xff1a;去噪、增强&#xff08;如对比度调整&#xff09;、锐化、边缘检测、图…...

【Java开发日记】说一说 SpringBoot 中 CommandLineRunner

目录 1、CommandLineRunner SpringBoot中CommandLineRunner的作用 简单例子 多个类实现CommandLineRunner接口执行顺序的保证 通过实现Ordered接口实现控制执行顺序 通过Order注解实现控制执行顺序 Order 作用 2、ApplicationRunner 3、传递参数 4、源码跟踪 run()方…...

全面理解 Linux 内核性能问题:分类、实战与调优策略

在 Linux 系统&#xff08;特别是嵌入式或服务器环境&#xff09;中&#xff0c;性能问题往往错综复杂、表象多变。只有对常见性能问题进行系统归类、理解其症状与根源&#xff0c;才能有效定位和解决。本文将围绕八大类核心性能问题&#xff0c;结合实战示例&#xff0c;逐类分…...

算法-多条件排序

1、数对排序的使用 pair<ll,ll> a[31];//cmp为比较规则 ll cmp(pair<ll,ll>a,pair<ll,ll>b){if(a.first!b.first)return a.first>b.first;else return a.second<b.second; }//按照比较规则进行排序 sort(a1,a31,cmp); 2、具体例题 输入样例&#xff1…...

DelayQueue、ScheduledThreadPoolExecutor 和 PriorityBlockingQueue :怎么利用堆实现定时任务

DelayQueue DelayQueue 的最大亮点&#xff1a; 并不是简单全局锁的“单调队列”实现&#xff0c;而是用Leader-Follower 模式极大减少了线程唤醒的开销。插入与唤醒、等待与 leader 变更&#xff0c;都通过巧妙的锁和条件变量组合完成。 如果只关注“线程安全的优先队列全局…...

Kafka 消息模式实战:从简单队列到流处理(二)

四、Kafka 流处理实战 4.1 Kafka Streams 简介 Kafka Streams 是 Kafka 提供的流处理库&#xff0c;它为开发者提供了一套简洁而强大的 API&#xff0c;用于构建实时流处理应用程序。Kafka Streams 基于 Kafka 的高吞吐量、分布式和容错特性&#xff0c;能够处理大规模的实时…...

大数据(2) 大数据处理架构Hadoop

一、Hadoop简介 1.定义 Hadoop 是一个开源的分布式计算框架&#xff0c;由 Apache 基金会开发&#xff0c;用于处理海量数据&#xff0c;具备高可靠性、高扩展性和高容错性。它主要由两个核心模块组成&#xff1a; HDFS&#xff08;Hadoop Distributed File System&#xff09…...