基于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>

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8 升级之路:主干网络嵌入 SCINet,优化黑暗环境目标检测

文章目录 引言1. 低照度图像检测的挑战1.1 低照度环境对目标检测的影响1.2 传统解决方案的局限性2. SCINet网络原理2.1 SCINet核心思想2.2 网络架构3. YOLOv8与SCINet的集成方案3.1 总体架构设计3.2 关键集成代码3.3 训练策略4. 实验结果与分析4.1 实验设置4.2 性能对比4.3 可视…

所有的Linux桌面环境

Linux操作系统提供了多种桌面环境&#xff0c;每种都有其独特的特点和适用场景。以下是一些常见的Linux桌面环境&#xff1a; 轻量级桌面环境 Xfce&#xff1a;广泛使用的轻量级桌面环境&#xff0c;适合资源有限的设备。Xfce 4.18带来了性能改进和新功能&#xff0c;如Thuna…

@component、@bean、@Configuration的区别

详细解析Spring框架中这三个最核心、也最容易混淆的注解&#xff1a;Component、Bean和Configuration。 为了快速理解&#xff0c;我们先看一个总结性的表格&#xff1a; 注解应用级别作用使用场景Component类级别将类标识为Spring组件&#xff0c;让Spring自动扫描并创建实例…

Android多媒体——音/视同步数据处理(二十)

在多媒体播放过程中,音频数据的处理不仅要保证其解码和输出的连续性,还需要与视频帧保持时间上的严格对齐,以实现良好的观看体验。Android 多媒体框架中的 NuPlayerRenderer 是负责最终渲染音视频数据的核心组件之一。 一、Audio数据处理 NuPlayerRenderer 是 Android 原生…

MYSQL 使用命令mysqldump备份数据库的时候需要用户具备什么权限

背景 之前都是使用数据库root用户备份数据库&#xff0c;没有权限问题&#xff0c;今天使用一个数据库基本用户备份数据库&#xff0c;提示一直没有权限&#xff0c;提示的很明显 mysqldump: Error: Access denied; you need (at least one of) the PROCESS privilege(s) for …

WebRTC源码线程-1

1、概述 本篇主要是简单介绍WebRTC中的线程&#xff0c;WebRTC源码对线程做了很多的封装。 1.1 WebRTC中线程的种类 1.1.1 信令线程 用于与应用层的交互&#xff0c;比如创建offer&#xff0c;answer&#xff0c;candidate等绝大多数的操作 1.1.2 工作线程 负责内部的处理逻辑&…

spring:使用标签xml静态工厂方法获取bean

在spring可以直接通过配置文件获取bean对象&#xff0c;如果获取的bean对象还有若干设置&#xff0c;需要自动完成&#xff0c;可以通过工厂方法获取bean对象。 静态工厂类&#xff0c;其中InterfaceUserDao和InterfaceUserService都是自定义的接口&#xff0c;可以自己替换。…

linux 用户态时间性能优化工具perf/strace/gdb/varlind/gprof

1. perf top -g或者top分析卡顿(cpu占用比较高的函数) gdb 是 GNU 调试器,可以用于分析程序的时间性能。虽然 info time 不是直接用于性能分析的命令,但 gdb 提供了与时间相关的功能,例如通过 timer 命令设置计时器或通过 info proc 查看进程的时间信息。 #include <…

客户端和服务器已成功建立 TCP 连接【输出解析】

文章目录 图片**1. 连接状态解析****第一条记录&#xff08;服务器监听&#xff09;****第二条记录&#xff08;客户端 → 服务器&#xff09;****第三条记录&#xff08;服务器 → 客户端&#xff09;** **2. 关键概念澄清****(1) 0.0.0.0 的含义****(2) 端口号的分配规则** *…

Win系统下的Linux系统——WSL 使用手册

我们在复现一些项目的时候&#xff0c;有些依赖包只能在 linux 环境下使用&#xff0c;还不打算使用远程服务器&#xff0c;那么此时我们可以使用 WSL 创建一个 ubutu 系统&#xff0c;在这个系统里创建虚拟环境、下载依赖包。然后&#xff0c;我们就可以在 windows 下的 vscod…

电脑同时连接内网和外网的方法,附外网连接局域网的操作设置

对于工作一般都设置在内网网段中&#xff0c;而同时由于需求需要连接外网&#xff0c;一般只能通过内网和外网的不断切换进行设置&#xff0c;如果可以同时连接内网和外网会更加便利&#xff0c;同时连接内网和外网方法具体如下。 一、电脑怎么弄可以同时连接内网和外网&#…

C++11:原子操作与内存顺序:从理论到实践的无锁并发实现

文章目录 0.简介1.并发编程需要保证的特性2.原子操作2.1 原子操作的特性 3.内存顺序3.1 顺序一致性3.2 释放-获取&#xff08;Release-Acquire)3.3 宽松顺序&#xff08;Relaxed)3.4 内存顺序 4.无锁并发5. 使用建议 0.简介 在并发编程中&#xff0c;原子性、可见性和有序性是…

oracle 归档日志与RECOVERY_FILE_DEST 视图

1. RECOVERY_FILE_DEST 视图的作用 RECOVERY_FILE_DEST 是 Oracle 数据库用于 管理快速恢复区&#xff08;Fast Recovery Area, FRA&#xff09; 的一个视图。FRA 是 Oracle 提供的一种集中存储恢复相关文件&#xff08;如归档日志、备份文件、闪回日志等&#xff09;的区域。…

零基础玩转物联网-串口转以太网模块如何快速实现与MQTT服务器通信

目录 1 前言 2 环境搭建 2.1 硬件准备 2.2 软件准备 2.3 驱动检查 3 MQTT服务器通信配置与交互 3.1 硬件连接 3.2 开启MQTT服务器 3.3 打开配置工具读取基本信息 3.4 填写连接参数进行连接 3.5 通信测试 4 总结 1 前言 MQTT&#xff1a;全称为消息队列遥测传输协议&#xff08;…

六、Sqoop 导出

作者&#xff1a;IvanCodes 日期&#xff1a;2025年6月7日 专栏&#xff1a;Sqoop教程 Apache Sqoop 不仅擅长从关系型数据库 (RDBMS) 向 Hadoop (HDFS, Hive, HBase) 导入数据&#xff0c;同样也强大地支持反向操作——将存储在 Hadoop 中的数据导出 (Export) 回关系型数据库。…

数据结构-如果将堆结构应用到TOP-K问题上会怎样?

数据结构的应用-如何用堆解决TOP-K问题 前言一、TOP-K问题是什么&#xff1f;二、如何用堆解决TOP-K问题1.怎么建堆&#xff0c;建大堆还是小堆&#xff1f;2.代码实现 总结 前言 本篇文章进行如何用堆结构解决TOP-K问题的讲解 一、TOP-K问题是什么&#xff1f; TOP-k问题&am…

Elasticsearch的索引

正向索引和倒排索引 什么是正向索引&#xff1f; 传统的数据库采用正向索引&#xff0c;如MySQL将表中的id创建索引&#xff0c;正向索引在进行不是id为索引进行搜索的时候&#xff0c;会逐条进行查询&#xff0c;比方说 上图的表格&#xff0c;数据库进行逐条查询&#xff0c;…

分散电站,集中掌控,安科瑞光伏云平台助力企业绿色转型

本项目位于香港全境共计52个分布式光伏站&#xff0c;总装机容量8.6MW。发电模式自发自用&#xff0c;余电上网&#xff0c;逆变器采用阳光电源SG100CX、SG20RT等12种型号共计103台&#xff0c;其余型号共计15台。每个站点均配置气象站。 项目采用AcrelCloud-1200分布式光伏运…

开发记录:修复一些Bug,并实现两个功能

开发记录&#xff1a; &#x1f4cb; 工作概述 到今天主要完成了AI阅读助手的两大核心功能&#xff1a;前情提要和名词解释&#xff0c;并对相关交互体验进行了优化。通过流式SSE技术实现了实时AI内容生成&#xff0c;大幅提升了用户体验。 &#x1f3af; 主要完成功能 1…

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…