From 2f392b13c695a82c6dab0587bce09a04ccb55028 Mon Sep 17 00:00:00 2001 From: ws50529 Date: Wed, 20 May 2026 17:35:10 +0800 Subject: [PATCH] feat: fix CSV upload state and UI indicators to prevent duplicate processing --- README.md | 40 +++++++++++++++++++-------- dea/csv_processing.py | 20 ++++++++++++++ src/App.vue | 10 +++++-- src/app-options.js | 23 ++++++++++++++-- static/build/app.js | 6 ++-- tests/test_dea_api.py | 64 +++++++++++++++++++++++++++++-------------- 6 files changed, 124 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index c4c9563..efa001f 100644 --- a/README.md +++ b/README.md @@ -29,16 +29,12 @@ bash certs/generate_cert.sh 開啟: ```text -https://localhost:8000/ui/ +https://192.168.2.58:8000/ui/ ``` -若從其他主機連線,改用: +本專案固定從 FastAPI 提供的 HTTPS UI 使用。不要用 Vite dev server URL 測試 CSV 或 MCU 功能,否則 `/api/...` 可能會回 `Not Found`。 -```text -https://:8000/ui/ -``` - -自簽憑證會讓瀏覽器顯示安全性警告,需手動信任或選擇繼續前往。 +自簽憑證會讓瀏覽器顯示安全性警告,第一次開啟時需手動信任或選擇繼續前往。 ## Project Layout @@ -73,8 +69,10 @@ chirp_signal.csv CSV 上傳測試範例 CSV workflow: 1. 前端選擇 CSV。 -2. 前端呼叫 `POST /api/csv/upload`,後端將檔案暫存並回傳 `file_id`。 -3. 後續 `POST /api/filter` 與 `POST /api/filter/download` 使用 `file_id`,避免反覆傳大檔。 +2. 前端只讀取檔案前段內容建立欄位與 preview,避免為了 preview 把大型 CSV 全部載入瀏覽器記憶體。 +3. 前端呼叫 `POST /api/csv/upload`,後端將檔案暫存並回傳 `file_id`。 +4. 上傳完成前,filter 按鈕會保持 disabled,避免尚未取得 `file_id` 就送出處理。 +5. 後續 `POST /api/filter` 與 `POST /api/filter/download` 使用 `file_id`,避免反覆傳大檔。 CSV 預設暫存在: @@ -88,6 +86,12 @@ CSV 預設暫存在: DEA_TEMP_CSV_DIR=/path/to/csv-cache ``` +暫存 CSV 預設保留 24 小時。可用環境變數調整,設為 `0` 可停用清理: + +```bash +DEA_TEMP_CSV_TTL_SECONDS=86400 +``` + ## Usage ### Filter Design @@ -210,7 +214,11 @@ npm run build npm run dev ``` -目前 `vite.config.js` 保留 `main` 設定,不在 Vite 內設定 `/api` proxy。 +CSV 與 API 流程保留 `dev-v2` 的兩段式設計:先 upload 取得 `file_id`,再用 `file_id` filter 或 download。`vite.config.js` 仍保留 `main` 的 HTTPS deployment 設定,不在 Vite 內設定 `/api` proxy。因此 `npm run dev` 只適合檢查前端畫面;CSV upload、filter API、MCU API 請固定使用: + +```text +https://192.168.2.58:8000/ui/ +``` ### Backend @@ -309,9 +317,19 @@ HTTP responses 會加上 CSP、`Referrer-Policy`、`X-Content-Type-Options: nosn ## Troubleshooting +### CSV 上傳顯示 `Not Found` + +請確認目前網址是: + +```text +https://192.168.2.58:8000/ui/ +``` + +如果從 `http://localhost:5173` 或其他 Vite dev server URL 開啟,`/api/csv/upload` 會送到前端 dev server,而不是 FastAPI,因此會回 `Not Found`。 + ### 無法連線 MCU -1. 確認使用 HTTPS 或 localhost。 +1. 確認使用 `https://192.168.2.58:8000/ui/`。 2. 確認瀏覽器支援 Web Serial API。 3. 使用 Chrome 或 Edge。 4. 檢查 USB 線與 MCU 裝置狀態。 diff --git a/dea/csv_processing.py b/dea/csv_processing.py index 03083d6..ab689fb 100755 --- a/dea/csv_processing.py +++ b/dea/csv_processing.py @@ -3,6 +3,7 @@ import os import uuid import re import tempfile +import time import numpy as np import pandas as pd @@ -16,8 +17,26 @@ TEMP_CSV_DIR = os.environ.get( "DEA_TEMP_CSV_DIR", os.path.join(tempfile.gettempdir(), "diff-eq-analyzer-csv"), ) +TEMP_CSV_TTL_SECONDS = int(os.environ.get("DEA_TEMP_CSV_TTL_SECONDS", str(24 * 60 * 60))) os.makedirs(TEMP_CSV_DIR, exist_ok=True) + +def prune_expired_csv_uploads(now=None): + if TEMP_CSV_TTL_SECONDS <= 0: + return + os.makedirs(TEMP_CSV_DIR, exist_ok=True) + cutoff = (now or time.time()) - TEMP_CSV_TTL_SECONDS + for filename in os.listdir(TEMP_CSV_DIR): + if not filename.endswith(".csv"): + continue + path = os.path.join(TEMP_CSV_DIR, filename) + try: + if os.path.isfile(path) and os.path.getmtime(path) < cutoff: + os.remove(path) + except OSError: + pass + + def get_cached_file_path(file_id): if not re.match(r'^[0-9a-f\-]{36}$', file_id): raise HTTPException(status_code=400, detail="無效的檔案ID") @@ -36,6 +55,7 @@ def downsample_for_plot(index, original, filtered_float, filtered_fixed): async def save_csv_upload(file): + prune_expired_csv_uploads() filename = (file.filename or "").lower() if filename and not filename.endswith(".csv"): raise HTTPException(status_code=400, detail="請上傳 CSV 檔案") diff --git a/src/App.vue b/src/App.vue index a8c0c98..dd8d1c2 100644 --- a/src/App.vue +++ b/src/App.vue @@ -736,7 +736,11 @@ csvFile.name }} - {{ csvInfo.rows }} 筆 / {{ csvInfo.columns }} 欄 + {{ csvInfo.rowsLabel || csvInfo.rows }} 筆 / {{ csvInfo.columns }} 欄 + + + 上傳中... @@ -756,8 +760,8 @@