diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index a305434..16d4202 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -420,6 +420,128 @@ OPENAI_MODEL=gpt-4o-mini --- +--- + +## πŸ€– PAAI μ‹œμŠ€ν…œ (처방 AI 뢄석) + +### κ°œμš” + +**PAAI (Prescription AI Analysis)**λŠ” 처방 μ ‘μˆ˜ μ‹œ μžλ™μœΌλ‘œ AI 뢄석을 μˆ˜ν–‰ν•˜κ³ , +뢄석 κ²°κ³Όλ₯Ό 영수증 ν”„λ¦°ν„°λ‘œ 좜λ ₯ν•˜λŠ” μ‹œμŠ€ν…œμž…λ‹ˆλ‹€. + +### μ•„ν‚€ν…μ²˜ + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ PAAI μ‹œμŠ€ν…œ 흐름 β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ POS μ ‘μˆ˜ │────►│ PM_PRES_LOG │────►│ Trigger Module β”‚ +β”‚ (μ²˜λ°©μž…λ ₯) β”‚ β”‚ (MSSQL) β”‚ β”‚ (폴링 감지) β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ + β”‚ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ WebSocket μ•Œλ¦Ό β”‚ β”‚ PAAI 뢄석 μš”μ²­ β”‚ + β”‚ (ws://8765) β”‚ β”‚ Flask API β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + β–Ό β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ ν”„λ‘ νŠΈμ—”λ“œ β”‚ β”‚ Claude API β”‚ + β”‚ pmr.html β”‚ β”‚ (뢄석 μˆ˜ν–‰) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ β”‚ + │◄─────────────────────────────── + β”‚ analysis_completed 이벀트 + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ μžλ™ 인쇄 β”‚ + β”‚ ESC/POS ν”„λ¦°ν„° β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +### ꡬ성 μš”μ†Œ + +| λͺ¨λ“ˆ | μœ„μΉ˜ | μ—­ν•  | +|------|------|------| +| **Trigger Module** | `prescription-trigger/prescription_trigger.py` | PM_PRES_LOG 폴링, 처방 감지, 뢄석 μš”μ²­ | +| **WebSocket Server** | Trigger λ‚΄μž₯ (port 8765) | ν”„λ‘ νŠΈμ—”λ“œμ— μ‹€μ‹œκ°„ 이벀트 전솑 | +| **PAAI API** | `backend/pmr_api.py` | 뢄석 μš”μ²­ 처리, Claude API 호좜, κ²°κ³Ό μ €μž₯ | +| **ν”„λ‘ νŠΈμ—”λ“œ** | `backend/templates/pmr.html` | μ‘°μ œκ΄€λ¦¬ UI, μžλ™μΈμ‡„ ν† κΈ€ | +| **ν”„λ¦°ν„° λͺ¨λ“ˆ** | `backend/paai_printer.py` | ESC/POS 영수증 ν”„λ¦°ν„° 좜λ ₯ | + +### WebSocket 이벀트 + +| 이벀트 | λ°©ν–₯ | μ„€λͺ… | +|--------|------|------| +| `prescription_detected` | Server β†’ Client | μƒˆ 처방 감지됨 | +| `analysis_started` | Server β†’ Client | AI 뢄석 μ‹œμž‘ | +| `analysis_completed` | Server β†’ Client | 뢄석 μ™„λ£Œ (κ²°κ³Ό 포함) | +| `analysis_failed` | Server β†’ Client | 뢄석 μ‹€νŒ¨ (μ—λŸ¬ 포함) | + +### μžλ™ 인쇄 흐름 + +```javascript +// 1. WebSocket으둜 analysis_completed μˆ˜μ‹  +ws.onmessage = (event) => { + const data = JSON.parse(event.data); + if (data.event === 'analysis_completed') { + // 2. μžλ™μΈμ‡„ ON μƒνƒœλ©΄ 인쇄 + if (window.autoPrintEnabled) { + printPaaiResult(data.pre_serial, data.patient_name, data); + } + } +}; + +// 3. 인쇄 API 호좜 +POST /pmr/api/paai/print +{ + "pre_serial": "20260305000099", + "patient_name": "홍길동", + "result": { "analysis": {...}, "kims_summary": {...} } +} + +// 4. ESC/POS ν”„λ¦°ν„°λ‘œ 좜λ ₯ +``` + +### 쀑볡 λ°©μ§€ + +```javascript +// window.printedSerials (Set) 으둜 쀑볡 인쇄 λ°©μ§€ +if (window.printedSerials.has(preSerial)) { + console.log('[AutoPrint] 이미 인쇄됨, μŠ€ν‚΅:', preSerial); + return; +} +window.printedSerials.add(preSerial); // μš”μ²­ 전에 μΆ”κ°€ (race condition λ°©μ§€) +``` + +### μžλ™ μž¬μ‹œλ„ + +| μ‹œλ„ | λŒ€κΈ° μ‹œκ°„ | μƒνƒœ | +|------|----------|------| +| 1회차 | - | 졜초 μ‹œλ„ | +| 2회차 | 2초 | 첫 번째 μž¬μ‹œλ„ | +| 3회차 | 4초 | 두 번째 μž¬μ‹œλ„ | +| μ‹€νŒ¨ | - | `analysis_failed` 이벀트 λ°œμ†‘ | + +### 둜그 파일 + +| 파일 | μœ„μΉ˜ | λ‚΄μš© | +|------|------|------| +| `print_history.log` | `backend/logs/` | 인쇄 성곡/μ‹€νŒ¨ 기둝 | +| `analysis_failures.log` | `prescription-trigger/logs/` | 뢄석 μ‹€νŒ¨ 상세 기둝 | +| `paai_logs.db` | `backend/db/` | 뢄석 κ²°κ³Ό SQLite μ €μž₯ | + +### κ΄€λ ¨ λ¬Έμ„œ + +- `docs/PAAI_AUTO_PRINT_TROUBLESHOOTING.md` - μžλ™μΈμ‡„ νŠΈλŸ¬λΈ”μŠˆνŒ… κ°€μ΄λ“œ + +--- + ## πŸ“ 버전 이λ ₯ | λ‚ μ§œ | 버전 | λ³€κ²½ λ‚΄μš© | @@ -427,6 +549,8 @@ OPENAI_MODEL=gpt-4o-mini | 2026-02-28 | 1.0 | 초기 μ•„ν‚€ν…μ²˜ λ¬Έμ„œ μž‘μ„± | | | | 동물약 AI 챗봇 μΆ”κ°€ | | | | ν”Œλ‘œνŒ… 챗봇 UI κ΅¬ν˜„ | +| 2026-03-05 | 1.1 | PAAI μ‹œμŠ€ν…œ μ•„ν‚€ν…μ²˜ μΆ”κ°€ | +| | | μžλ™μΈμ‡„, WebSocket, μž¬μ‹œλ„ 둜직 | ---