拍貼機系統 P!X 印一下

這是一套結合網站、美編與硬體控制的全自動拍貼機,專為活動現場、展覽或自助服務設計,讓使用者能輕鬆拍照、選擇模板並立即列印成品。系統整合軟硬體,流程自動化,並支援多種互動功能。 gitgub連結 🧩 系統原理與架構 本系統以 Python Flask 為後端主體,結合 Arduino 控制投幣與硬體訊號,並透過熱感應印表機完成現場列印。流程自動化,並以 ngrok 實現公網穿透,讓手機可即時上傳照片。 主要流程 投幣啟動:使用者投幣 40 元,投幣機將訊號傳給 Arduino,Arduino 透過序列埠(Serial)傳送 coin_ok 訊號給主機。 QRCode 產生與列印:主機收到訊號後,產生唯一 Token 與專屬上傳網址,並生成 QRCode 票券(含說明、Logo、簽名等),自動列印並切紙。 照片上傳與模板選擇:使用者掃描 QRCode,進入網頁上傳照片並選擇拍貼模板,支援即時預覽與互動。 列印成品:完成後自動將美編照片傳送至印表機列印,現場立即取件。 🔌 技術整合 Flask 網站系統:提供照片上傳、模板選擇、即時預覽與互動介面。 印表機控制:支援多台印表機(如 Xprinter、EPSON),可自動裁切。 Arduino 投幣與列印指令:硬體負責投幣偵測、列印流程控制與狀態回饋。 多種主題模板 + 圖層疊加處理:支援多款拍貼模板,並可自訂圖層與特效。 自動 QRCode 產生與票券設計:每次投幣自動產生專屬 QRCode,票券含說明、簽名、直橫排文字、Logo。 ngrok 公網穿透:自動啟動 ngrok,讓外部手機可連線上傳照片。 Token 防重複機制:每張票券唯一 Token,防止重複上傳與列印。 多執行緒與序列通訊:背景監控硬體訊號,並確保 Token 持久化與執行緒安全。 🛠️ 系統架構 前端:RWD 響應式網頁(HTML/CSS/JavaScript),支援手機掃描 QRCode 操作。 後端:Python Flask,負責 API、圖片處理、列印指令下發。 硬體:Arduino(投幣、訊號控制)、熱感應印表機、顯示模組。 通訊:USB/Serial 連接 Arduino 與印表機,HTTP 通訊前後端,ngrok 公網穿透。 ⚡ Arduino 與投幣機連接與偵測原理 投幣機:將投幣訊號(為用上拉電阻完成脈衝接收)連接至 Arduino 的數位輸入腳位。 Arduino 程式:偵測到投幣訊號時,透過 Serial(如 COM7, 9600 baud)傳送 coin_ok 字串給主機。 主機(Flask):背景執行緒持續監控 Serial 埠,收到 coin_ok 後自動產生 QRCode 並列印,並可回傳狀態訊息給 Arduino。 安全與防呆:主機會記錄已用 Token,防止重複上傳與列印,並於異常時自動復原。 連接示意圖 graph TD; A[投幣機] -- 投幣訊號 --> B(Arduino); B -- Serial (coin_ok) --> C[主機 (Flask)]; C -- QRCode 產生與列印 --> D[熱感應印表機]; D -- 列印完成 --> C; C -- 狀態回傳 --> B; B -- 控制訊號 --> A; 📂 主要檔案結構 . ├── app.py # Flask 主程式 ├── confing.py # 主程式調取的設定 ├── static/ # 前端網頁 │ ├── simulate_coin_page.html # 管理員頁面 │ ├── upload.html # 上傳照片頁面 ├── templates/ #裡面放不同模板 ├── qr_codes/ # 儲存產生的 QRCode 票券 ├── uploads/ # 儲存上傳的照片 🚀 特色與未來規劃 支援多模板、動態特效與自訂票券設計 可以增加雲端備份與下載功能 支援多語系介面 優化列印速度與美編演算法 增加現場狀態顯示與錯誤自動復原

July 26, 2025 · 1 分鐘 · 李柏毅

Selenium自動化技術學習 - 搶票系統架構

🎯 專案概述 這是一個基於 Selenium WebDriver 的網頁自動化技術學習專案。透過這個專案,我深入學習了現代網頁自動化技術,掌握了瀏覽器控制、元素定位、事件處理等核心技能。 注意: 本專案僅用於技術學習和研究目的,不提供完整程式碼開源。 🛠️ 技術架構 核心技術棧 Python 3.9+ - 主要開發語言 Selenium WebDriver - 瀏覽器自動化框架 ChromeDriver - Chrome瀏覽器驅動 BeautifulSoup4 - HTML解析 手動驗證碼處理 - 人工輸入驗證碼 系統架構設計 ┌─────────────────┐ │ 配置管理模組 │ │ - 設定檔讀取 │ │ - 參數驗證 │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 瀏覽器控制模組 │ │ - WebDriver │ │ - 頁面載入 │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 元素定位模組 │ │ - XPath/CSS │ │ - 元素等待 │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 事件處理模組 │ │ - 點擊事件 │ │ - 表單填寫 │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 驗證處理模組 │ │ - 手動輸入 │ │ - 安全驗證 │ └─────────────────┘ │ ▼ ┌─────────────────┐ │ 日誌記錄模組 │ │ - 操作記錄 │ │ - 錯誤處理 │ └─────────────────┘ 📚 學習重點 1. Selenium WebDriver 基礎 1 2 3 4 5 6 7 8 9 10 11 12 13 14 # 瀏覽器初始化 from selenium import webdriver from selenium.webdriver.chrome.service import Service from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 配置Chrome選項 chrome_options = webdriver.ChromeOptions() chrome_options.add_argument('--no-sandbox') chrome_options.add_argument('--disable-dev-shm-usage') # 初始化WebDriver driver = webdriver.Chrome(service=Service(chromedriver_path), options=chrome_options) 2. 元素定位技巧詳解 2.1 ID 定位(最優先使用) 1 2 3 4 5 6 7 8 9 # 優點:唯一性高,定位速度快 # 適用:有明確ID的元素 element = driver.find_element(By.ID, "username") element = driver.find_element(By.ID, "submit-button") # 實際範例:登入表單 username_input = driver.find_element(By.ID, "login-username") password_input = driver.find_element(By.ID, "login-password") login_button = driver.find_element(By.ID, "login-submit") 2.2 Name 定位 1 2 3 4 5 6 7 8 # 優點:語義化,易於理解 # 適用:表單元素 element = driver.find_element(By.NAME, "username") element = driver.find_element(By.NAME, "email") # 實際範例:搜尋框 search_input = driver.find_element(By.NAME, "q") search_button = driver.find_element(By.NAME, "search") 2.3 Class Name 定位 1 2 3 4 5 6 7 8 # 優點:可定位多個相同樣式的元素 # 適用:樣式化的元素 elements = driver.find_elements(By.CLASS_NAME, "btn-primary") element = driver.find_element(By.CLASS_NAME, "form-control") # 實際範例:按鈕群組 primary_buttons = driver.find_elements(By.CLASS_NAME, "btn-primary") secondary_buttons = driver.find_elements(By.CLASS_NAME, "btn-secondary") 2.4 Tag Name 定位 1 2 3 4 5 6 7 8 9 # 優點:可定位所有特定標籤 # 適用:需要遍歷所有同類元素 links = driver.find_elements(By.TAG_NAME, "a") inputs = driver.find_elements(By.TAG_NAME, "input") # 實際範例:獲取所有連結 all_links = driver.find_elements(By.TAG_NAME, "a") for link in all_links: print(link.text) 2.5 CSS Selector 定位(推薦) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 # 優點:語法簡潔,功能強大 # 適用:複雜的選擇器需求 # 基本選擇器 element = driver.find_element(By.CSS_SELECTOR, "input[type='text']") element = driver.find_element(By.CSS_SELECTOR, ".btn-primary") # 組合選擇器 element = driver.find_element(By.CSS_SELECTOR, "form.login-form input[type='submit']") element = driver.find_element(By.CSS_SELECTOR, "div.container > button.btn") # 實際範例:複雜表單 username = driver.find_element(By.CSS_SELECTOR, "form#loginForm input[name='username']") password = driver.find_element(By.CSS_SELECTOR, "form#loginForm input[type='password']") submit = driver.find_element(By.CSS_SELECTOR, "form#loginForm button[type='submit']") 2.6 XPath 定位(最靈活) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # 優點:功能最強大,可定位任何元素 # 適用:複雜的定位需求 # 絕對路徑 element = driver.find_element(By.XPATH, "/html/body/div[1]/form/input[1]") # 相對路徑 element = driver.find_element(By.XPATH, "//input[@name='username']") element = driver.find_element(By.XPATH, "//button[contains(text(),'登入')]") # 父元素定位 element = driver.find_element(By.XPATH, "//input[@id='username']/parent::div") # 實際範例:動態內容定位 # 定位包含特定文字的按鈕 login_button = driver.find_element(By.XPATH, "//button[contains(text(),'登入')]") # 定位特定屬性的元素 email_input = driver.find_element(By.XPATH, "//input[@type='email']") # 定位多個條件 submit_btn = driver.find_element(By.XPATH, "//button[@type='submit' and @class='btn-primary']") 2.7 定位策略總結 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 # 推薦的定位優先順序 def find_element_smart(driver, element_info): """ 智能元素定位策略 1. ID (最快) 2. Name (表單元素) 3. CSS Selector (複雜選擇) 4. XPath (最後選擇) """ try: # 優先使用ID if 'id' in element_info: return driver.find_element(By.ID, element_info['id']) except: pass try: # 其次使用Name if 'name' in element_info: return driver.find_element(By.NAME, element_info['name']) except: pass try: # 使用CSS Selector if 'css' in element_info: return driver.find_element(By.CSS_SELECTOR, element_info['css']) except: pass # 最後使用XPath if 'xpath' in element_info: return driver.find_element(By.XPATH, element_info['xpath']) raise Exception("Element not found") # 使用範例 element_info = { 'id': 'username', 'name': 'username', 'css': 'input[name="username"]', 'xpath': '//input[@name="username"]' } username_input = find_element_smart(driver, element_info) 3. 事件處理 1 2 3 4 5 6 7 8 9 10 11 # 點擊操作 element.click() # 輸入文字 element.clear() element.send_keys("text") # 下拉選單處理 from selenium.webdriver.support.ui import Select select = Select(driver.find_element(By.ID, "dropdown")) select.select_by_value("option_value") 4. 驗證碼處理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 # 手動輸入驗證碼 def handle_captcha_manual(driver): """ 手動處理驗證碼 1. 截圖驗證碼區域 2. 暫停程式等待人工輸入 3. 輸入驗證碼並提交 """ # 定位驗證碼輸入框 captcha_input = driver.find_element(By.ID, "captcha-input") # 暫停等待人工輸入 print("請查看驗證碼並手動輸入...") input("按Enter繼續...") # 獲取人工輸入的驗證碼 captcha_text = input("請輸入驗證碼: ") # 輸入驗證碼 captcha_input.clear() captcha_input.send_keys(captcha_text) return captcha_text # 使用範例 captcha_result = handle_captcha_manual(driver) print(f"驗證碼已輸入: {captcha_result}") 自動辨識驗證碼技術:如需了解更多關於自動驗證碼辨識技術,請聯絡 Boyce Work工作坊 了解更多。 ...

July 10, 2025 · 4 分鐘 · 李柏毅

智慧音樂節拍偵測器 - AI 節奏訓練系統

🎯 專案概述 這是一款雙版本音樂節拍偵測與節拍器系統,包含 Python 終端版 和 Web 前端版,能夠透過麥克風錄音即時偵測使用者所敲打的節奏,自動計算出 BPM(每分鐘拍數),並播放對應節奏的節拍聲音,輔助音樂人訓練節奏感。 🌟 版本特色 版本 特色 適用場景 🐍 Python 終端版 CLI 介面、高精度計時、即時錄音偵測 開發者、音樂製作、快速原型 🌐 Web 前端版 美觀 UI、跨平台、即開即用、線上版本 一般使用者、線上教學、行動裝置 💡 核心功能詳解 🎙️ 智慧錄音偵測系統 即時音訊處理:使用 sounddevice 進行高品質錄音 峰值偵測演算法:透過 scipy.signal.find_peaks 精準識別拍點 自適應閾值:根據環境噪音自動調整偵測靈敏度 時間間隔分析:計算拍點間隔並轉換為 BPM 📊 BPM 計算引擎 1 2 3 4 5 6 # 核心計算邏輯 if len(peaks) > 1: first, last = peaks[0], peaks[-1] count = len(peaks) - 1 avg_interval = ((last - first) / fs) / count bpm = 60 / avg_interval 🔊 高精度節拍器播放 微秒級計時:使用 time.perf_counter() 確保播放穩定性 多執行緒播放:背景播放不影響主程式運作 自訂音效支援:可載入 WAV 格式的節拍音效 即時視覺回饋:播放時顯示音符符號 🎛️ 雙模式操作 錄音偵測模式:敲擊麥克風自動計算 BPM 手動設定模式:直接輸入 BPM 數值(支援 1-200 BPM) 🛠️ 技術架構詳解 Python 終端版技術棧 技術/套件 版本 用途 特色 sounddevice 最新版 音訊錄製與播放 低延遲、跨平台 numpy 1.21+ 音訊數據處理 高效能數值運算 scipy.signal 1.7+ 峰值偵測演算法 科學計算級精度 threading 內建 多執行緒播放 非阻塞式操作 time.perf_counter 內建 高精度計時 微秒級精度 Web 前端版技術棧 技術 用途 特色 HTML5 Audio API 音訊錄製與播放 瀏覽器原生支援 Web Audio API 即時音訊處理 低延遲處理 CSS3 動畫 視覺效果 流暢的 UI 動畫 JavaScript ES6+ 邏輯控制 現代化語法 Responsive Design 響應式設計 多裝置支援 📱 前端版本特色介紹 🎨 現代化 UI 設計 深色主題:專業音樂軟體風格 漸層背景:視覺層次豐富 動態效果:按鈕懸停、載入動畫 響應式佈局:支援桌面與行動裝置 🎵 進階功能 拖拽上傳:支援音效檔案上傳 即時 BPM 顯示:動態更新節奏數值 多種節奏模式:支援不同音符長度 視覺節拍器:動畫顯示節拍位置 🔧 技術亮點 1 2 3 4 // Web Audio API 音訊處理 const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const analyser = audioContext.createAnalyser(); const microphone = navigator.mediaDevices.getUserMedia({ audio: true }); 🚀 安裝與使用指南 Python 終端版安裝 1 2 3 4 5 # 安裝必要套件 pip install sounddevice numpy scipy # 執行程式 python 終端版.py Web 前端版使用 🌐 線上版本 立即體驗:智慧節拍器線上版 無需下載:直接在瀏覽器中使用 跨平台支援:支援桌面和行動裝置 📁 本地版本 開啟 smart_metronome.html 檔案 允許麥克風權限 選擇錄音偵測或手動輸入 BPM 開始使用節拍器 📊 效能表現 指標 Python 版 Web 版 延遲時間 < 5ms < 10ms BPM 精度 ±0.1 BPM ±0.5 BPM 記憶體使用 ~50MB ~20MB 啟動時間 2-3秒 即開即用 🧠 演算法原理 拍點偵測流程 graph TD A[音訊錄製] --> B[音量正規化] B --> C[峰值偵測] C --> D[時間間隔計算] D --> E[BPM 轉換] E --> F[節拍器播放] 核心演算法 音訊預處理:正規化音量至 0-1 範圍 閾值計算:mean + 2*std 自適應閾值 峰值搜尋:使用 find_peaks 找出拍點 間隔分析:計算拍點間平均時間 BPM 轉換:BPM = 60 / 平均間隔 🎯 應用場景 🎼 音樂教育 節奏訓練:幫助學生建立穩定的節奏感 速度練習:逐步提升演奏速度 拍子練習:訓練不同拍號的節奏 🎹 音樂製作 錄音輔助:提供精確的節拍參考 混音工具:確保音軌同步 現場演出:即時節奏控制 🎸 樂器練習 吉他練習:配合節拍器練習指法 鋼琴練習:訓練雙手協調 鼓手練習:提升節奏穩定性 🔮 未來發展規劃 短期目標 支援更多音效格式(MP3, OGG) 增加節奏模式(3/4, 6/8 拍) 加入節奏模式記憶功能 中期目標 機器學習優化 BPM 偵測 雲端同步設定 行動應用版本 長期目標 AI 節奏分析與建議 多樂器節奏訓練 社群功能與節奏分享 📽️ 功能展示影片 您的瀏覽器不支援 video 標籤。 🏗️ 程式架構概覽 Python 終端版架構 1 2 3 4 5 6 7 8 9 10 main() ├── 使用者選擇錄音 or 手動 BPM ├── record() 函數 │ ├── 音訊錄製 (sounddevice) │ ├── 峰值偵測 (scipy.signal) │ └── BPM 計算 └── start() 函數 ├── 高精度計時 (time.perf_counter) ├── 多執行緒播放 └── 視覺回饋 (♪ 符號) Web 前端版架構 1 2 3 4 5 6 7 HTML 結構 ├── 響應式 CSS 設計 ├── JavaScript 核心邏輯 │ ├── Web Audio API 處理 │ ├── 音訊分析引擎 │ └── UI 互動控制 └── 動態視覺效果 🤝 貢獻指南 歡迎提供你們的想法! ...

July 9, 2025 · 3 分鐘 · 李柏毅

APCS|三次應試的紀錄與反思

我把這次 APCS 的成績,當作一次誠實盤點:哪些做對、哪些只是運氣、哪些需要在日常慢慢補齊。 身在資源較少的環境,成績可喜,但更想保留一點謙虛與清醒。 ...

June 30, 2025 · 1 分鐘 · 李柏毅