新增第 4.1.5 節:進階爬蟲模組設計 主要內容: - Scrapy 框架整合規格(擴充新聞來源用) - 通用爬蟲架構設計原則 - 多層級選擇器備用機制 - Pipeline 資料處理管線(CSV + Database) - 資料庫表結構(articles, tags, article_tags) - 錯誤處理與效能最佳化 - 執行測試與除錯技巧 - 新增新聞來源的標準步驟 技術規格: - Scrapy >= 2.11.0 - PyMySQL >= 1.1.0 - python-dateutil >= 2.8.2 - 支援多來源整合(source 欄位) - Context Manager 確保交易完整性 - 標籤快取機制提升效能 這個設計可作為擴充其他新聞來源的通用範本。 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
22 KiB
每日報導 APP 功能規格書 (Functional Specification) 文件版本 1.3 建立日期 2024-11-24 最後更新 2024-12-04 專案名稱 每日報導 APP 專案類型 內部工具
-
專案概述 1.1 專案目標 建立一套企業內部新聞彙整與分析系統,協助市場分析專員有效率地蒐集、篩選並彙整產業新聞,透過 AI 自動摘要功能產出綜合分析報告,供內部讀者訂閱閱讀。 1.2 用戶故事 用戶故事 A:市場分析專員 身為市場分析專員,我需要一個方法來縮短每天用關鍵字查找各大網站新聞的過程,因為目前耗用太多時間。 用戶故事 B:讀者 身為讀者,我需要一個方法來針對市場分析專員所提供的資料進行分析,因為目前耗用太多時間。 1.3 預估使用者規模 角色 人數 說明 系統管理員 1-2 位 負責系統設定與維護 市場分析專員 1 位 負責新聞篩選與發布 讀者 40 位 訂閱並閱讀報告
-
系統架構 2.1 部署環境 • 部署方式:地端部署(1Panel 管理介面) • 前端平台:Web 優先,支援行動裝置響應式設計 • 系統語言:繁體中文 / 英文雙語介面 • 語言切換:用戶手動選擇(右上角切換)+ 系統自動偵測瀏覽器語言 • 內容翻譯:摘要內容支援自動翻譯(新聞內容不翻譯) 2.2 技術架構 • 前端框架:HTML + Vanilla JavaScript(輕量化實作) • 前端通訊:RESTful API • 後端框架:FastAPI (Python 3.11+,已支援 Python 3.13) • 資料庫:MySQL 8.0 / SQLite(開發環境) • 資料庫 ORM:SQLAlchemy 2.0+(連線池管理) • 快取系統:Redis(選用) • 任務佇列:APScheduler(輕量化排程) • LLM 整合:支援 Google Gemini API / OpenAI API / Ollama 地端模型 • 認證整合:JWT + AD/LDAP 驗證 + 本地帳號 • 版本控制:Git + Gitea(https://gitea.theaken.com)
-
角色與權限 角色 權限範圍 系統管理員 LLM 設定、AD 整合、群組管理、用戶管理、系統設定 市場分析專員 新聞抓取管理、篩選編輯、報告發布、群組內容設定 讀者 訂閱群組、閱讀報告、留言討論、個人收藏、匯出 PDF
-
功能需求 4.1 新聞抓取模組 4.1.1 新聞來源 來源 登入方式 抓取內容 Digitimes 帳號密碼登入(付費訂閱) 全文擷取 經濟日報 公開網頁爬取 全文擷取 工商時報 公開網頁爬取 全文擷取
4.1.2 抓取技術 • 爬蟲框架:httpx + BeautifulSoup4(輕量化爬蟲) • HTML 解析:lxml 6.0+(Python 3.13 相容) • 登入狀態管理:維持 session,定期檢查有效性,使用 Cookie 持久化 • 去重機制:比對標題 + 發布時間,避免重複抓取 • 新聞欄位提取:標題(必填)、正文內容(必填)、發布時間(必填) • 錯誤重試:使用 tenacity 實作自動重試機制
4.1.3 抓取排程 • 定時抓取:每日 08:00 執行 • 抓取範圍:即時累積至當日的新聞 • 資料存儲:建立新聞資料庫供日後查詢 • 處理方式:使用 APScheduler 進行背景任務排程 • 並發控制:使用 asyncio 提升抓取效率
4.1.4 異常處理
- 系統自動重試(最多 3 次,間隔 5 分鐘)
- 部分成功的新聞先處理,失敗的稍後重試
- 重試失敗後通知系統管理員
- 專員可透過介面手動觸發重新抓取
4.1.5 進階爬蟲模組設計(擴充新聞來源用)
本節說明如何擴充新的新聞來源,以 Scrapy 框架實作進階爬蟲模組。
技術堆疊(Scrapy 方案) • 爬蟲框架:Scrapy >= 2.11.0 • Item 適配器:itemadapter >= 0.7.0 • 資料庫連接:PyMySQL >= 1.1.0 • 日期解析:python-dateutil >= 2.8.2 • 環境變數:python-dotenv >= 1.0.0
爬蟲核心設計原則 • Spider:定義爬蟲名稱、允許網域、起始 URL • 測試模式:支援參數控制(不追蹤分頁、指定單一 URL) • 多層級選擇器:優先 > 備用 > 最後手段,提升容錯性 • 連結過濾:跳過 JavaScript、錨點、非目標頁面
列表頁解析策略 • 多層級選擇器備用機制 • 連結提取優先順序設計 • 連結過濾規則(JavaScript、錨點、非文章頁) • 智慧型分頁處理
文章頁解析邏輯 • 標題提取:多層選擇器備用 • 作者提取:CSS 選擇器 > meta 標籤 • 發布日期:CSS 選擇器 > meta 標籤 • 摘要提取:CSS 選擇器 > meta description • 分類提取:CSS 選擇器或從 URL 推斷 • 標籤提取:多種選擇器支援 • 付費文章檢測:檢查付費牆標記(.paywall, .premium 等) • 內容提取:僅非付費文章,多層選擇器備用
通用資料模型(ArticleItem) • title:文章標題(必填,最大 500 字元) • url:文章完整 URL(必填,唯一識別) • author:作者名稱 • publish_date:發布日期 • summary:文章摘要 • is_paywalled:是否為付費文章(0/1) • category:文章分類 • tags:標籤列表 • content:文章內容(僅免費文章) • source:新聞來源(用於多來源整合)
Pipeline 資料處理管線
- CsvExportPipeline(優先級 300)
- 本地備份:CSV 檔案儲存
- 編碼格式:UTF-8
- 即使資料庫失敗仍可保存資料
- DatabasePipeline(優先級 400)
- 資料表:articles, tags, article_tags
- Context Manager:確保交易完整性
- 標籤快取機制:減少資料庫查詢
- 日期解析:支援多種格式
- 去重機制:URL 唯一性檢查
- 更新邏輯:已存在則更新,不存在則新增
錯誤處理機制 • 選擇器失敗:多層備用選擇器,逐層嘗試 • 資料庫錯誤:捕獲例外,記錄日誌,繼續處理 • 連線失敗:警告但不中斷爬蟲執行 • 日誌記錄:使用 Python logging 模組
Settings 爬蟲設定 • ROBOTSTXT_OBEY:True(遵守 robots.txt) • DOWNLOAD_DELAY:1-3 秒(請求間隔,依網站調整) • FEED_EXPORT_ENCODING:utf-8 • Twisted Reactor:AsyncioSelectorReactor
執行與測試 • 基本執行:scrapy crawl <spider_name> • 測試模式:scrapy crawl <spider_name> -a test_mode=true • 指定 URL:scrapy crawl <spider_name> -a start_url="https://..." • 輸出檔案:scrapy crawl <spider_name> -o output.json • 除錯模式:scrapy crawl <spider_name> --loglevel=DEBUG • Shell 測試:scrapy shell "https://..."
除錯技巧 • scrapy shell:測試選擇器 • Chrome DevTools:分析網頁結構 • robots.txt 檢查:確認爬取規則 • 日誌分析:追蹤錯誤原因
效能最佳化建議 • 標籤快取:啟動時載入所有標籤到記憶體 • HTTP 快取:減少重複請求(選用) • AutoThrottle:自動調整請求速率(選用) • Context Manager:確保資料庫連線正確關閉 • 並發控制:CONCURRENT_REQUESTS 設定
資料庫表結構 articles 表:
- id, title, url (UNIQUE), author, publish_date, summary
- is_paywalled, category, content, source
- crawled_at, created_at, updated_at
tags 表:
- id, name (UNIQUE), created_at
article_tags 關聯表:
- id, article_id (FK), tag_id (FK)
- UNIQUE(article_id, tag_id)
新增新聞來源步驟
- 建立新的 Spider(繼承 scrapy.Spider)
- 定義 start_urls 與 allowed_domains
- 實作 parse() 解析列表頁
- 實作 parse_article() 解析文章頁
- 測試選擇器與資料提取
- 調整 DOWNLOAD_DELAY 避免被封鎖
- 加入 Pipeline 進行資料儲存
4.2 關鍵字群組管理 4.2.1 群組分類方式 • 依產業別分群:半導體、面板、車用電子...等 • 依議題分群:政策法規、市場趨勢...等 4.2.2 群組設定項目 • 群組名稱與描述 • 關鍵字清單(可新增、編輯、刪除) • AI 摘要背景資訊設定 • AI 摘要方向設定(每個群組獨立設定) 4.2.3 群組與報告關係 一份報告 = 一個群組的彙整內容
4.3 AI 摘要模組 本系統整合多種大型語言模型 (LLM) 服務,提供靈活的 AI 摘要能力,系統管理員可依據需求切換不同的 LLM 提供者。 4.3.1 支援的 LLM 提供者 提供者 類型 建議模型 適用場景 Google Gemini 雲端 API gemini-1.5-pro 長文本分析、多語言 OpenAI 雲端 API gpt-4o / gpt-4o-mini 通用摘要、高品質輸出 Ollama 地端部署 llama3 / qwen2 / gemma2 資料不外流、離線使用
4.3.2 Google Gemini API 整合規格 API 端點 • Base URL: https://generativelanguage.googleapis.com/v1beta • 認證方式: API Key (透過 URL 參數或 Header) 支援模型 • gemini-1.5-pro: 最高品質,支援 100 萬 tokens 上下文 • gemini-1.5-flash: 快速回應,適合即時摘要 • gemini-1.0-pro: 穩定版本,成本較低 請求格式 POST /v1beta/models/{model}:generateContent Content-Type: application/json 設定參數 參數 預設值 說明 temperature 0.7 控制輸出隨機性 (0-1) maxOutputTokens 2048 最大輸出 token 數 topP 0.95 nucleus sampling 參數 topK 40 top-k sampling 參數
4.3.3 OpenAI API 整合規格 API 端點 • Base URL: https://api.openai.com/v1 • 認證方式: Bearer Token (Authorization Header) 支援模型 • gpt-4o: 最新多模態模型,高品質輸出 • gpt-4o-mini: 輕量版本,成本效益高 • gpt-4-turbo: 128K 上下文,適合長文 請求格式 POST /v1/chat/completions Content-Type: application/json 設定參數 參數 預設值 說明 temperature 0.7 控制輸出隨機性 (0-2) max_tokens 2048 最大輸出 token 數 top_p 1.0 nucleus sampling 參數 frequency_penalty 0 重複懲罰 (-2 至 2) presence_penalty 0 新話題懲罰 (-2 至 2)
4.3.4 Ollama API 整合規格(地端部署) API 端點 • Base URL: http://localhost:11434 (可自訂) • 認證方式: 無需認證(建議內網部署) 支援模型(需預先下載) • llama3:8b / llama3:70b: Meta 開源模型,繁中支援佳 • qwen2:7b / qwen2:72b: 阿里巴巴模型,中文最佳化 • gemma2:9b / gemma2:27b: Google 開源模型 • mistral:7b: 歐洲開源模型,效能優異 請求格式 POST /api/generate 或 POST /api/chat Content-Type: application/json 設定參數 參數 預設值 說明 temperature 0.7 控制輸出隨機性 (0-1) num_predict 2048 最大輸出 token 數 top_p 0.9 nucleus sampling 參數 top_k 40 top-k sampling 參數 stream false 是否串流輸出 硬體需求建議 模型規模 最低記憶體 建議配置 7B-8B 參數 8GB RAM 16GB RAM + GPU 8GB 13B-27B 參數 16GB RAM 32GB RAM + GPU 16GB 70B+ 參數 64GB RAM 128GB RAM + GPU 48GB+
4.3.5 LLM 設定管理介面 管理員設定功能 • 選擇 LLM 提供者(下拉選單切換) • 設定 API Key(加密儲存於資料庫) • 選擇使用的模型版本 • 設定 Ollama 端點 URL(地端部署時) • 調整生成參數(temperature, max_tokens 等) • 連線測試功能(顯示回應時間) 全系統統一設定 LLM 設定由系統管理員統一配置,所有群組共用相同的模型與參數,確保輸出品質一致性。
4.3.6 摘要處理邏輯 多篇新聞合併策略 • 全部合併成一段綜合分析(無數量限制) • 當新聞內容超過模型 token 限制時,先進行初步摘要再送 LLM • 背景資訊與摘要方向放在 user prompt 開頭傳遞給 LLM • 處理方式:串行處理(一個接一個群組依序產生摘要)
摘要輸出格式 • 多篇相關新聞合併產出一段綜合分析 • 純文字格式,適合閱讀與匯出 • 每個群組可設定專屬的背景資訊與摘要方向
4.3.7 錯誤處理與備援 • API 呼叫失敗時自動重試(最多 3 次) • 摘要失敗時通知專員手動處理 • 記錄錯誤日誌供管理員查看 • 支援設定備援 LLM 提供者(未來擴充)
4.4 報告發布模組(專員端) 4.4.1 篩選介面功能 • 勾選/排除特定新聞 • 可手動編輯 AI 摘要內容 • 預覽發布前報告呈現 4.4.2 發布規則 • 發布時間:工作日 09:00 前必須發出 • 工作日定義:週一至週五(排除假日),使用台灣行事曆 API 判斷 • 逾時處理:延遲發布時通知讀者 • 已發布報告:專員可以撤回(標記為已撤回),但不可修改內容
4.4.3 通知機制 Email 通知規格 • Email 內容:報告標題、發布日期、AI 摘要內容、線上閱讀連結 • Email 樣式:響應式 HTML(支援手機閱讀) • 發送策略:批次發送(每批 10 封) • 失敗處理:記錄失敗日誌、通知系統管理員
4.5 讀者端功能 4.5.1 訂閱管理 • 讀者可自行訂閱感興趣的群組 • 一位讀者可訂閱多個群組報告 4.5.2 閱讀介面 • 響應式設計,支援手機閱讀 • 報告瀏覽與歷史查詢 4.5.3 互動功能 • 留言功能:同群組讀者皆可見(討論性質) • 留言審核:關鍵字過濾後自動審核 • 收藏功能:個人收藏清單(未來擴充) • 標註功能:個人筆記用途(未來擴充)
4.5.4 匯出功能 PDF 匯出規格 • 生成技術:WeasyPrint 67.0+ • PDF 內容:公司 Logo、報告標題、發布日期、AI 摘要內容、相關新聞列表(標題 + 連結)、頁首頁尾文字 • PDF 樣式:固定樣式(不可自訂) • 權限:專員與讀者皆有權限匯出 • 中文字型:支援繁體中文顯示
4.6 系統管理模組 4.6.1 用戶管理 • AD/LDAP 整合:僅驗證帳密 • 支援非 AD 帳號(外部顧問、實習生等) • 角色指派與權限管理 4.6.2 LLM 設定 • 提供者選擇:Google Gemini / OpenAI / Ollama • API 金鑰管理:儲存在環境變數(加密儲存) • 加密金鑰輪換:每 3 個月定期輪換 • 模型版本選擇 • Ollama 端點設定(地端部署) • 連線測試與回應時間顯示
4.6.3 PDF 模板設定 • 可上傳公司 Logo • 自訂頁首頁尾文字 • 固定樣式模板(不可自訂)
-
每日工作流程 時間 執行者 動作 08:00 系統 自動抓取各新聞來源當日累積新聞 08:00 系統 依關鍵字群組分類新聞並呼叫 LLM 產生 AI 摘要 08:30 專員 登入系統審核新聞,勾選/排除、編輯摘要 09:00 前 專員 確認無誤後發布報告 09:00 系統 發送 Email 通知給已訂閱該群組的讀者 全天 讀者 登入閱讀、留言、收藏、匯出 PDF
-
非功能性需求 6.1 效能需求 • 新聞抓取完成時間:30 分鐘內(含 AI 摘要) • 頁面載入時間:3 秒內 • 同時在線用戶:至少 50 人 • LLM 摘要回應時間:單次請求 30 秒內 • 快取策略:使用 Redis 快取提升查詢效能(選用) • 資料庫連線:使用 SQLAlchemy 2.0+ 連線池管理 • 異步處理:使用 asyncio 提升 I/O 密集型操作效能
6.2 資料保留政策 • 報告與新聞資料保留期限:60 天 • 操作日誌保留期限:60 天 • 過期資料自動清理機制
6.3 可用性需求 • 系統可用性:工作日 07:00-22:00 需正常運作 • 備份策略:每日增量備份 • 任務處理:使用 APScheduler 進行排程任務處理 • 郵件發送:使用 aiosmtplib 5.0+ 進行異步郵件發送
6.4 安全性需求 • 身份認證:JWT Token + python-jose 3.5+(支援 cryptography) • 密碼加密:使用 passlib + bcrypt 5.0+ 進行密碼雜湊 • AD/LDAP 整合:使用 ldap3 2.9+ 進行企業帳號驗證 • HTTPS 加密傳輸 • API Key 加密儲存(AES-256),儲存在環境變數 • 加密金鑰輪換:每 3 個月定期輪換 • 操作日誌記錄:記錄用戶登入/登出、新聞抓取記錄、AI 摘要產生記錄、報告發布記錄、系統錯誤記錄、API 呼叫記錄
6.5 監控與告警 • 系統健康檢查 • 新聞抓取失敗告警 • AI 摘要失敗告警 • 資料庫連線異常告警 • 系統效能監控
- LLM 成本估算 以下為各 LLM 提供者的預估成本(以每日 50 篇新聞、每篇 1000 字計算): 提供者 輸入成本 輸出成本 每月估算 Google Gemini $0.00025/1K tokens $0.0005/1K tokens 約 $5-15 OpenAI GPT-4o $0.005/1K tokens $0.015/1K tokens 約 $30-60 OpenAI GPT-4o-mini $0.00015/1K tokens $0.0006/1K tokens 約 $3-8 Ollama (地端) 免費 免費 僅硬體成本
- 實際成本依使用量而異,建議先以小量測試確認
- 資料庫設計 8.1 主要資料表 • users(用戶表):儲存用戶基本資訊與角色 • groups(群組表):儲存關鍵字群組設定 • keywords(關鍵字表):儲存各群組的關鍵字清單 • news(新聞表):儲存抓取的新聞內容 • reports(報告表):儲存每日產出的報告 • report_news(報告新聞關聯表):多對多關聯表,記錄報告與新聞的對應關係 • comments(留言表):儲存讀者留言 • llm_settings(LLM 設定表):儲存 LLM 提供者與參數設定 • system_logs(系統日誌表):儲存系統操作與錯誤日誌 • user_group_subscriptions(用戶群組訂閱表):記錄用戶訂閱的群組(多對多關係)
8.2 關聯關係 • 報告與新聞:多對多關係(一篇新聞可出現在多份報告),透過 report_news 關聯表 • 群組與報告:一對一關係(一份報告對應一個群組) • 用戶與群組:多對多關係(用戶可訂閱多個群組),透過 user_group_subscriptions 關聯表
8.3 索引策略 • 新聞標題索引:優化新聞查詢效能 • 新聞發布時間索引:優化時間範圍查詢 • 群組關鍵字索引:優化關鍵字匹配效能 • 用戶訂閱關係索引:優化訂閱查詢效能 • 報告發布時間索引:優化報告歷史查詢
- 環境變數配置 所有敏感資訊與連線設定均透過環境變數管理,確保安全性與彈性。
9.1 資料庫連線(已確認) • DB_HOST:mysql.theaken.com • DB_PORT:33306 • DB_NAME:db_A101 • DB_USER:A101 • DB_PASSWORD:Aa123456 • 連線狀態:✅ 測試連線正常
9.2 Redis 連線(必填) • REDIS_HOST:Redis 主機位址(預設:localhost) • REDIS_PORT:Redis 埠號(預設:6379) • REDIS_PASSWORD:Redis 密碼(如有) • REDIS_DB:Redis 資料庫編號(預設:0)
9.3 Celery 設定(必填) • CELERY_BROKER_URL:訊息佇列 URL(格式:redis://[password@]host:port/db 或 amqp://user:password@host:port/vhost) • CELERY_RESULT_BACKEND:結果儲存位置(通常與 broker 相同)
9.4 SMTP 設定(必填) • SMTP_HOST:SMTP 伺服器位址 • SMTP_PORT:SMTP 埠號(預設:587) • SMTP_USERNAME:SMTP 帳號 • SMTP_PASSWORD:SMTP 密碼 • SMTP_FROM_EMAIL:寄件者 Email • SMTP_FROM_NAME:寄件者名稱(預設:每日報導系統) • SMTP_USE_TLS:是否使用 TLS(預設:True)
9.5 AD/LDAP 設定(選填)
• LDAP_SERVER:LDAP 伺服器位址
• LDAP_PORT:LDAP 埠號(預設:389)
• LDAP_BASE_DN:LDAP Base DN
• LDAP_BIND_DN:LDAP 綁定 DN(如有)
• LDAP_BIND_PASSWORD:LDAP 綁定密碼(如有)
• LDAP_USER_SEARCH_FILTER:用戶搜尋過濾器(預設:(sAMAccountName={username}))
9.6 LLM API Keys(選填,依選擇的提供者設定) • GEMINI_API_KEY:Google Gemini API Key • OPENAI_API_KEY:OpenAI API Key • OLLAMA_ENDPOINT:Ollama 端點 URL(預設:http://localhost:11434)
9.7 Digitimes 帳號(必填) • DIGITIMES_USERNAME:Digitimes 登入帳號 • DIGITIMES_PASSWORD:Digitimes 登入密碼
9.8 應用程式設定(必填) • SECRET_KEY:應用程式密鑰(用於加密,建議至少 32 字元) • JWT_SECRET_KEY:JWT 簽章密鑰(建議至少 32 字元) • APP_ENV:環境(development/staging/production) • DEBUG:除錯模式(預設:False,生產環境必須為 False)
9.9 環境變數管理方式
• 開發環境:使用 .env 檔案(不納入版本控制)
• 生產環境:使用 1Panel 環境變數設定介面
• 敏感資訊:API Keys、密碼等均加密儲存
• 加密方式:AES-256 加密,加密金鑰儲存在環境變數中
- 附錄 10.1 名詞定義 名詞 定義 群組 依產業別或議題分類的關鍵字集合,作為新聞分類與報告產出的單位 報告 針對單一群組,彙整相關新聞並產出 AI 綜合摘要的每日產出物 專員 市場分析專員,負責新聞篩選、編輯與發布工作 讀者 訂閱並閱讀報告的內部用戶 LLM Large Language Model,大型語言模型,用於產生 AI 摘要 Ollama 開源的本地 LLM 執行框架,可在企業內部部署運行
10.2 待確認事項
- Digitimes 帳號憑證管理方式 → 已確認:管理者設定
- 經濟日報、工商時報爬蟲策略 → 已確認:請求間隔 3-5 秒
- PDF Logo → 已確認:開放上傳選項
- Email 發送服務 → 已確認:SMTP
- LLM 提供者 → 已確認:Google Gemini / OpenAI / Ollama 三選一
10.3 版本更新記錄
版本 1.3 (2024-12-04) 更新內容: • 技術架構更新
- 前端改為輕量化實作(HTML + Vanilla JavaScript)
- 後端支援 Python 3.13
- SQLAlchemy 升級至 2.0+
- 任務排程改用 APScheduler(輕量化)
- 新增 Gitea 版本控制系統資訊
• 套件版本更新
- lxml 升級至 6.0+(Python 3.13 相容)
- WeasyPrint 升級至 67.0+
- httpx + BeautifulSoup4 取代 Scrapy(基礎爬蟲)
- aiosmtplib 升級至 5.0+
- python-jose 升級至 3.5+
- bcrypt 升級至 5.0+
- ldap3 2.9+
• 新增進階爬蟲模組設計(4.1.5 節)
- Scrapy 框架整合規格
- 通用爬蟲架構設計(擴充新聞來源用)
- Pipeline 資料處理管線
- 多層級選擇器備用機制
- 資料庫表結構設計
- 錯誤處理與效能最佳化
- 新增新聞來源步驟說明
• 功能優化
- 新增 asyncio 並發控制
- 使用 tenacity 實作錯誤重試機制
- 改善安全性需求描述
- 優化 PDF 中文字型支援
- 新增 source 欄位支援多來源整合
版本 1.2 (2025-01-27) • 初始版本規格定義 • 完成基本功能需求規劃
版本 1.1 (2024-11-24) • 專案啟動 • 初步需求收集
— 文件結束 —