基于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
繁體地址,請注明出處:http://hk.pswp.cn/news/909005.shtml
英文地址,請注明出處:http://en.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;給詞語畫"…