sequence_upload

2026-03-05




%% 機構設計整合部 AI Agent 系統 - 文件上傳與向量化流程時序圖
%% 渲染工具:https://mermaid.live / VS Code Mermaid Preview

sequenceDiagram
    autonumber

    actor User as 👤 使用者 (研發同仁/管理員)
    participant Browser as 🌐 瀏覽器 (React)
    participant API as ⚡ FastAPI
    participant Auth as 🔐 JWT 驗證
    participant BG as 🔄 背景任務 (BackgroundTask)
    participant Ingest as 📥 DocumentIngestionService
    participant PDF as 📄 PDFProcessor
    participant Chunker as ✂️ TextChunker
    participant Ollama as 🦙 Ollama Service\n(nomic-embed-text)
    participant Vision as 👁️ Ollama Vision\n(qwen2.5-vl:7b)
    participant PG as 🗄️ PostgreSQL + pgvector
    participant FS as 💾 File Storage\n(本機磁碟)
    participant Audit as 📋 稽核日誌

    %% ===================================================
    %% 路徑 A:單一文件上傳
    %% ===================================================
    rect rgb(230, 245, 255)
        Note over User,Audit: 📤 路徑 A:單一文件上傳 (POST /api/v1/documents/upload)

        User->>Browser: 選擇檔案 + 填寫 metadata\n(類別、標籤)
        Browser->>API: POST /api/v1/documents/upload\n(multipart/form-data)\nfile: <binary>\nmetadata: {category, tags}

        API->>Auth: 驗證 Bearer Token
        Auth-->>API: ✅ user_id

        API->>FS: 寫入原始檔案\nD:\storage\documents\{UUID}.pdf
        FS-->>API: 儲存成功,file_path

        API->>PG: INSERT INTO documents\n{filename, file_type, file_path, file_size,\n status="pending", uploaded_by=user_id}
        PG-->>API: document_id (UUID)

        API->>BG: add_background_task(\n  DocumentIngestionService.ingest_file,\n  document_id, file_path)
        Note over BG: 背景任務非同步執行\nAPI 立即回應 202

        API-->>Browser: 202 Accepted\n{document_id, status:"processing", job_id}
        Browser->>User: 顯示上傳成功,處理中...

        API->>Audit: 寫入稽核日誌\naction="upload", resource="document"
    end

    %% ===================================================
    %% 路徑 B:批次匯入
    %% ===================================================
    rect rgb(255, 245, 230)
        Note over User,Audit: 📦 路徑 B:批次匯入 (POST /api/v1/documents/batch-import)

        User->>Browser: 輸入伺服器本地資料夾路徑\nD:\cad_manuals\
        Browser->>API: POST /api/v1/documents/batch-import\n{source_path, file_extensions, metadata}

        API->>Auth: 驗證 Bearer Token(需 admin 角色)
        Auth-->>API: ✅ user_id, role="admin"

        API->>FS: 掃描目錄,列出所有符合副檔名的檔案
        FS-->>API: 檔案列表 [file1.pdf, file2.docx, ...]

        API->>PG: INSERT INTO batch_jobs\n{source_path, total_files=N, status="pending"}
        PG-->>API: job_id

        loop 每個檔案
            API->>PG: INSERT INTO documents (pending 狀態)
        end

        API->>BG: add_background_task(\n  DocumentIngestionService.ingest_batch,\n  job_id, file_list)
        API-->>Browser: 202 Accepted\n{job_id, total_files:N, status:"processing"}
        Browser->>User: 顯示批次任務進度條
    end

    %% ===================================================
    %% 核心向量化流程(A 和 B 共用)
    %% ===================================================
    rect rgb(240, 255, 240)
        Note over BG,PG: ⚙️ 核心向量化流程(背景任務執行,A 和 B 共用)

        BG->>PG: UPDATE documents SET status="processing"
        BG->>Ingest: ingest_file(document_id, file_path)

        %% ----- 依檔案類型分支處理 -----
        alt 檔案類型 == PDF
            Ingest->>PDF: process(pdf_path)

            PDF->>PDF: pymupdf4llm.to_markdown(pdf_path)\n擷取結構化文字 + 表格 → Markdown
            PDF->>PDF: fitz.open(pdf_path)\n取得所有內嵌圖片(get_images)

            loop 每張圖片
                PDF->>Vision: POST /api/chat\n{model: "qwen2.5-vl:7b",\n prompt: "詳細描述這張工程圖片的內容...",\n image: <base64>}
                Vision-->>PDF: 圖片文字描述\n"此為SolidWorks伸長特徵設定頁面,圖示顯示..."
                Note over PDF: 將描述以\n[圖片說明 第N頁 圖M]:\n{description}\n格式附加至 Markdown
            end

            PDF-->>Ingest: 完整 Markdown 文字\n(含圖片描述)

        else 檔案類型 == DOCX
            Ingest->>Ingest: python-docx 解析\n→ 純文字 + 表格
        else 檔案類型 == MD / TXT
            Ingest->>Ingest: 直接讀取文字內容
        else 檔案類型 == 圖片 (JPG/PNG)
            Ingest->>Vision: 視覺模型描述整張圖片
            Vision-->>Ingest: 圖片完整描述文字
        end

        %% ----- 文字分塊 -----
        Ingest->>Chunker: split(full_text)\nRecursiveCharacterTextSplitter\nchunk_size=512, chunk_overlap=64
        Chunker-->>Ingest: chunks = ["段落1...", "段落2...", ...]
        Note over Chunker: 分塊策略:\n優先在段落換行處切割\n保留 64 字元重疊避免語意割裂

        %% ----- 向量嵌入(批次處理)-----
        loop 每批 32 個 chunks
            Ingest->>Ollama: POST /api/embed\n{model: "nomic-embed-text",\n input: [chunk1, chunk2, ..., chunk32]}
            Ollama-->>Ingest: embeddings [[0.12,...], [0.34,...], ...]\n每個向量 768 維
        end

        %% ----- 批次寫入 PostgreSQL -----
        Ingest->>PG: COPY / batch INSERT INTO document_chunks\n{document_id, content, embedding (vector),\n chunk_index, page_number, chunk_type, metadata}
        PG-->>Ingest: 寫入成功,chunk_count

        %% ----- 更新文件狀態 -----
        Ingest->>PG: UPDATE documents\nSET status="completed",\n    chunk_count=N,\n    updated_at=NOW()
        PG-->>Ingest: ✅ 更新成功

        opt 批次任務(路徑 B)
            Ingest->>PG: UPDATE batch_jobs\nSET processed_files += 1\n(或 failed_files += 1 若失敗)
        end
    end

    %% ===================================================
    %% 錯誤處理
    %% ===================================================
    rect rgb(255, 235, 235)
        Note over Ingest,PG: ❌ 錯誤處理路徑

        alt 解析失敗(損壞/加密 PDF 等)
            Ingest->>PG: UPDATE documents\nSET status="failed",\n    metadata={error: "無法解析 PDF:檔案已加密"}
            opt 批次任務
                Ingest->>PG: UPDATE batch_jobs\nSET failed_files += 1,\n    error_log += {filename, reason}
            end
        else Ollama 服務不可用
            Ingest->>PG: UPDATE documents SET status="failed"\n{error: "Embedding 服務無法連線"}
            Note over Ingest: 重試機制:每隔 30 秒最多重試 3 次
        end
    end

    %% ===================================================
    %% 前端輪詢進度
    %% ===================================================
    rect rgb(248, 248, 255)
        Note over Browser,PG: 🔄 前端進度輪詢(每 3 秒)

        loop 任務未完成
            Browser->>API: GET /api/v1/documents/batch-jobs/{job_id}
            API->>PG: SELECT * FROM batch_jobs WHERE id=$1
            PG-->>API: {processed:10, total:23, failed:1, status:"processing"}
            API-->>Browser: 200 OK\n{progress_percent:43, processed:10, total:23}
            Browser->>User: 更新進度條 43%
        end

        Browser->>API: GET /api/v1/documents/batch-jobs/{job_id}
        API->>PG: 查詢
        PG-->>API: {status:"completed", processed:22, failed:1}
        API-->>Browser: 200 OK {status:"completed"}
        Browser->>User: ✅ 匯入完成!22 個成功,1 個失敗
    end

    Note over User,Audit: ✅ 文件已向量化完成\n後續對話的 RAG 檢索即可搜尋到此文件
 







Login to like - 0 Likes



Comments...


No Comments Yet...



Add Comment...



shumin

A graduated biotechnology engineer. Now is a software engineer


Latest Posts



Footer with Icons