음성 인터랙션 기반 AI 복약 보조 시스템
의약품 포장을 스캔하거나 설명서를 업로드한 뒤 음성 또는 텍스트로 자료에 근거한 답변을 받으세요.
English · 简体中文 · 繁體中文 · 日本語 · Español · Português · Русский · Français · Deutsch
MedVision-RAG는 시각장애인과 고령 사용자가 의약품 정보를 쉽게 이해할 수 있도록 돕는 시스템입니다. 의약품 포장지를 카메라로 촬영하거나 PDF/Word 문서를 업로드하면 다음과 같이 동작합니다:
- 텍스트 추출 — OCR(macOS Vision / Tesseract 폴백) 수행
- OCR 텍스트 정규화 — 유용한 문단 구조 유지
- 지식 베이스 구축 — 텍스트를 벡터화하여 ChromaDB에 저장
- 질의응답 — 적응형 RAG: 짧은 텍스트는 직접 컨텍스트 주입, 긴 텍스트는 벡터 유사도 검색
- 음성 출력 — edge-tts로 답변을 음성으로 읽어줌
웹 브라우저, 위챗 미니 프로그램, 그리고 채팅 로그와 분석을 모니터링하는 관리자 대시보드를 지원합니다.
- 사진: 의약품 포장지, 박스, 블리스터 팩 — 카메라로 직접 촬영
- PDF: 텍스트 기반 및 스캔 문서 자동 감지 후 이미지 렌더링하여 OCR 수행
- Word: 텍스트 및 표 추출; 텍스트가 부족하면 내장 이미지 OCR로 폴백
- HEIC/HEIF: iPhone 사진은 OCR 전 자동으로 JPEG 변환
- 짧은 텍스트 (< 1500자): 컨텍스트 스터핑 — 전체 문서를 LLM 프롬프트에 주입
- 긴 텍스트 (>= 1500자): 벡터 검색 — 청크 단위로 분할하여 ChromaDB에 저장하고, 상위 K개 관련 구간 검색
- 교차 약품 전환: 사용자가 다른 약품명을 언급하면 시스템이 자동으로 컨텍스트 전환
- 웹: 브라우저 내장 Speech Recognition API (제로 레이턴시, API 비용 없음)
- 미니 프로그램: Groq Whisper Large-V3로 음성 → 텍스트, edge-tts로 텍스트 → 음성
- 의료 용어 교정: LLM이 ASR 출력을 후처리하여 오인식된 약품명 수정
- 중단 가능한 재생: 음성 버튼을 누르면 진행 중인 TTS를 즉시 중단
- 키워드 감지:
risk_keywords.json에서 설정 가능한 위험 키워드 - 채팅 로그 감사: 모든 대화를 MySQL에 저장하여 검토 가능
- 이메일 알림: 위험 키워드 감지 시 자동 이메일 발송 (설정 가능)
- 관리자 대시보드: Streamlit 기반 실시간 모니터링, IP 화이트리스트 보호
- 고대비 UI (WCAG AA 준수)
- 큰 터치 영역 (48px 이상)
- 시각장애인을 위한 완전 음성 기반 워크플로우
- 중국어/영어 언어 전환 — AI 응답 및 TTS 음성 선택 동기화
┌─────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Web Front │────▶│ Java Backend │────▶│ Python AI │
│ :5174 │ │ Spring Boot │ │ FastAPI │
│ Vue 3 CDN │ │ :8080 │ │ :8001 │
└─────────────┘ │ │ │ │
│ - REST API │ │ - OCR (ocrmac) │
┌─────────────┐ │ - JPA / MySQL │ │ - ASR (Groq) │
│ WeChat │────▶│ - Auth / CORS │ │ - RAG (LangChain)│
│ Mini App │ │ - IP Whitelist │ │ - TTS (edge-tts) │
└─────────────┘ └────────┬─────────┘ │ - Risk Detection │
│ └────────┬──────────┘
▼ ▼
┌──────────────┐ ┌──────────────┐
│ MySQL 8 │ │ ChromaDB │
│ :3306 │ │ (local) │
└──────────────┘ └──────────────┘
| 의존성 | 버전 | 비고 |
|---|---|---|
| Python | 3.10+ | AI 서비스 런타임 |
| Java | 17+ | 비즈니스 백엔드 런타임 |
| Maven | 3.8+ | Java 빌드 도구 |
| MySQL | 8.0+ | 관계형 데이터 저장소 |
| macOS (권장) | 13+ | ocrmac이 Apple Vision 프레임워크를 사용하여 OCR 수행 |
Linux: 지원되지만 OCR에 Tesseract가 필요합니다.
apt install tesseract-ocr tesseract-ocr-chi-sim으로 설치한 후backend-ai/services/ocr.py를 수정하세요.
DeepSeek API Key가 필수이며, Groq API Key는 선택사항입니다 (위챗 미니 프로그램 음성 인식용).
DeepSeek API Key 발급 방법 (필수)
DeepSeek는 질의응답에 사용되는 LLM을 제공합니다.
- platform.deepseek.com에 접속
- 회원가입 또는 로그인
- 왼쪽 사이드바에서 API Keys로 이동
- Create API Key 클릭 후 이름 입력 (예: "MedVision")
- 키를 즉시 복사 (
sk-로 시작하며 다시 확인할 수 없음)
비용: 기본 모델 deepseek-v4-flash는 매우 저렴합니다. 하루 종일 개발 테스트해도 보통 $0.01 미만입니다.
Groq API Key 발급 방법 (선택 — 미니 프로그램 전용)
Groq는 LPU 하드웨어에서 Whisper Large-V3를 통해 빠른 음성 → 텍스트 변환을 제공합니다.
- console.groq.com에 접속
- GitHub 또는 Google 계정으로 가입
- 왼쪽 사이드바에서 API Keys로 이동
- Create API Key 클릭
- 키 복사 (
gsk-로 시작)
비용: 무료 플랜에 넉넉한 Whisper 사용량이 포함되어 있습니다. 웹 프론트엔드는 브라우저 내장 음성 API를 사용하므로 Groq 크레딧을 소비하지 않습니다 — 위챗 미니 프로그램만 Groq를 사용합니다.
git clone https://github.com/Ha1baraA11/MedVision_RAG.git
cd MedVision_RAGcp .env.example .env텍스트 편집기로 .env를 열어 필요한 값을 입력합니다:
# macOS
open -e .env
# VS Code
code .env| 변수 | 필수 | 설명 |
|---|---|---|
MYSQL_PASSWORD |
예 | MySQL root 비밀번호 |
DEEPSEEK_API_KEY |
예 | platform.deepseek.com에서 발급 |
DEEPSEEK_BASE_URL |
아니오 | 기본값: https://api.deepseek.com |
GROQ_API_KEY |
미니 프로그램용 | console.groq.com에서 발급 |
SMTP_SERVER |
아니오 | 위험 알림용 SMTP 서버 (예: smtp.qq.com) |
SMTP_PORT |
아니오 | SMTP 포트 (QQ 메일: 465) |
SMTP_USER |
아니오 | 발신자 이메일 주소 |
SMTP_PASSWORD |
아니오 | SMTP 인증 코드 (이메일 비밀번호와 다름) |
SMTP_RECEIVER |
아니오 | 수신자 이메일 주소 |
INTERNAL_TOKEN |
아니오 | Java ↔ Python 서비스 간 인증 토큰 |
참고:
MYSQL_PASSWORD는 시스템 시작에 반드시 필요한 유일한 자격 증명입니다. 나머지는 안전한 기본값이 설정되어 있거나 점진적 성능 저하로 처리됩니다.
QQ 메일 SMTP 인증 코드 발급 방법
- mail.qq.com 로그인 → 설정 → 계정
- POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV 서비스 항목 찾기
- IMAP/SMTP 서비스 활성화
- SMS 인증 절차를 거쳐 인증 코드 발급
- 이 코드(QQ 비밀번호가 아님)를
SMTP_PASSWORD로 사용
cd backend-ai
# 가상 환경 생성
python3 -m venv venv
# 활성화
source venv/bin/activate
# 의존성 설치 (최초 실행 시에만, 약 2분 소요)
pip install -r requirements.txt최초 실행 시 HuggingFace에서 bge-small-zh-v1.5 임베딩 모델(~90MB)을 다운로드합니다.
cd backend-java
# 의존성 다운로드 및 컴파일 (최초 실행 시에만, 약 3분 소요)
mvn clean install -DskipTestsmysql -u root -p < sql/init.sql생성되는 항목:
- 데이터베이스
medvision(UTF8MB4) - 테이블
medicines— 의약품 정보 및 전문 텍스트 - 테이블
chat_logs— 대화 이력 및 분석 데이터 - 테이블
admin_users— 관리자 계정
기본 관리자 계정(admin / admin)은 Java 백엔드가 처음 시작될 때 자동 생성됩니다.
대안: 이 단계를 건너뛰면 Spring Boot의
hibernate.ddl-auto=update설정에 따라 테이블이 자동 생성됩니다. SQL 스크립트는 명시적인 스키마 관리 및 프로덕션 배포용으로 제공됩니다.
./start_all.sh이 스크립트는 의존성 순서에 따라 모든 서비스를 시작하고, 각 서비스가 준비될 때까지 대기한 후 상태를 출력합니다. 로그는 backend-ai/service.log, backend-java/backend.log, dashboard.log에 기록됩니다.
터미널 1 — Python AI 서비스 (가장 느리므로 먼저 시작)
cd backend-ai
source venv/bin/activate
python main.py다음 메시지 확인: Uvicorn running on http://0.0.0.0:8001
최초 시작 시 임베딩 모델(
bge-small-zh-v1.5)이 다운로드되어 캐시됩니다. 이후 시작은 약 3초 소요됩니다.
터미널 2 — Java 백엔드
cd backend-java
mvn spring-boot:run다음 메시지 확인: Started MedVisionApplication in X.XXX seconds
Maven이 최초 실행 시 의존성을 다운로드합니다. 백엔드가 데이터베이스 테이블과 기본 관리자 계정을 자동 생성합니다.
터미널 3 — 웹 프론트엔드
cd frontend
python3 -m http.server 5174브라우저에서 http://localhost:5174 접속.
선택 — 관리자 대시보드
streamlit run admin_dashboard.py --server.port 8502http://localhost:8502 접속. 로그인: admin / admin.
./stop_all.sh또는 수동으로:
lsof -t -i:5174 -i:8080 -i:8001 -i:8502 | xargs kill -9- WeChat Developer Tools 다운로드 및 설치
- 도구를 열고 Import Project 클릭
frontend-wechat/디렉토리 선택- Test AppID 또는 게스트 모드 선택
frontend-wechat/config.js편집:
const API_CANDIDATES = [
'http://192.168.x.x:8080', // 컴퓨터의 LAN IP로 변경
];# macOS
ifconfig | grep "inet " | grep -v 127.0.0.1
# Windows
ipconfig | findstr "IPv4"- 스마트폰과 컴퓨터가 동일한 Wi-Fi 네트워크에 연결되어 있는지 확인
- WeChat Developer Tools에서 Debug on Device 클릭
- 스마트폰으로 QR 코드 스캔
- 연결 실패 시 확인 사항:
- 컴퓨터 방화벽이 포트
8080을 허용하는지 확인 config.js에 올바른 LAN IP가 설정되어 있는지 확인 (localhost가 아닌)- Java 백엔드가 실행 중인지 확인
- 컴퓨터 방화벽이 포트
backend-ai/core/config.py 편집:
llm = ChatOpenAI(
model="deepseek-v4-flash", # 여기서 모델 변경
api_key=API_KEY,
base_url=BASE_URL,
temperature=0.3 # 0.0 = 결정적, 1.0 = 창의적
)사용 가능한 DeepSeek 모델:
| 모델 | 속도 | 비용 | 용도 |
|---|---|---|---|
deepseek-v4-flash |
빠름 | 매우 저렴 | 개발, 데모 (기본값) |
deepseek-v4 |
보통 | 저렴 | 더 나은 품질의 답변 |
기본값은 ocrmac(macOS Vision)입니다. Linux에서 Tesseract로 전환하려면:
# 중국어 지원 Tesseract 설치
sudo apt install tesseract-ocr tesseract-ocr-chi-sim
# Python 래퍼 설치
pip install pytesseract그런 다음 backend-ai/services/ocr.py에서 ocrmac 대신 pytesseract를 사용하도록 수정합니다.
기본 모델은 BAAI/bge-small-zh-v1.5 (중국어 의료 텍스트 최적화, ~90MB)입니다. CPU에서 로컬 실행 — API 호출 불필요. 변경하려면:
# backend-ai/core/config.py
embedding_model = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-zh-v1.5", # 여기서 모델 변경
model_kwargs={"local_files_only": True, "device": "cpu"}
)최초 사용 시 HuggingFace에서 다운로드하려면
local_files_only를False로 변경하세요.
risk_keywords.json을 편집하여 트리거 단어를 추가하거나 제거합니다:
{
"keywords": ["overdose", "poisoning", "allergy", "contraindication", "side effect", "..."]
}설정된 키워드가 사용자 질문에 포함되면 시스템이 위험 이벤트를 기록하고 이메일 알림을 보낼 수 있습니다.
관리자 대시보드는 IP 화이트리스트로 접근을 제한합니다. backend-java/src/main/resources/application.properties에서 설정:
admin.security.enabled=true
admin.security.ip-whitelist=127.0.0.1,::1원격 접속 시 화이트리스트에 IP를 추가하세요.
임베딩 모델은 최초 다운로드 후 로컬에 캐시됩니다. 강제로 다시 다운로드하려면:
cd backend-ai
source venv/bin/activate
python -c "from langchain_huggingface import HuggingFaceEmbeddings; HuggingFaceEmbeddings(model_name='BAAI/bge-small-zh-v1.5')"| 메서드 | 경로 | 설명 |
|---|---|---|
GET |
/health |
헬스 체크 |
POST |
/ocr |
이미지/PDF/Word → 텍스트 추출 |
POST |
/chat |
RAG 질의응답 |
POST |
/transcribe |
음성 → 텍스트 (Groq Whisper) |
POST |
/analyze |
수동 텍스트 분석 |
GET |
/tts |
텍스트 → 음성 (edge-tts) |
GET |
/search |
의약품 이력 검색 |
| 메서드 | 경로 | 설명 |
|---|---|---|
GET |
/api/medicine/health |
헬스 체크 |
POST |
/api/medicine/recognize |
의약품 설명서 업로드 및 인식 |
POST |
/api/medicine/chat |
AI 서비스 채팅 프록시 |
GET |
/api/medicine/list |
저장된 의약품 목록 조회 |
GET |
/api/medicine/chat-logs |
채팅 로그 이력 (관리자) |
GET |
/api/medicine/analytics |
사용 분석 (관리자) |
POST |
/api/medicine/admin/login |
관리자 로그인 |
# Python 단위 테스트 (17개, 약 0.2초)
cd backend-ai
source venv/bin/activate
python -m pytest tests/ -v
# Java 단위 테스트 (6개)
cd backend-java
mvn test| 모듈 | 테스트 수 | 커버리지 |
|---|---|---|
check_risk_keywords |
6 | 히트, 캐시, 만료, 빈 입력 |
smart_rag_search |
4 | 짧은 텍스트, 긴 텍스트, 오류 폴백, 엣지 케이스 |
correct_medical_terms |
7 | 환각 필터, 블랙리스트, LLM 교정, 오류 폴백 |
MedicineController |
6 | REST 엔드포인트 MockMvc 테스트 |
MedVision-RAG/
├── frontend/ # Vue 3 CDN 단일 페이지 웹 앱
│ └── index.html # 완전한 프론트엔드 (848줄)
├── frontend-wechat/ # 위챗 미니 프로그램
│ ├── pages/index/ # 메인 페이지 (WXML + JS + WXSS)
│ ├── app.js # 앱 진입점
│ └── config.js # API 엔드포인트 설정
├── backend-java/ # Spring Boot 비즈니스 백엔드
│ ├── src/main/java/com/medvision/
│ │ ├── controller/ # REST 엔드포인트
│ │ ├── service/ # 비즈니스 로직
│ │ ├── entity/ # JPA 엔티티 (Medicine, ChatLog, AdminUser)
│ │ ├── repository/ # Spring Data JPA 리포지토리
│ │ └── config/ # 보안, CORS, IP 화이트리스트, 데이터 초기화
│ ├── src/test/ # MockMvc 테스트
│ └── pom.xml # Maven 의존성
├── backend-ai/ # FastAPI AI 서비스
│ ├── main.py # 라우트 진입점 (~250줄)
│ ├── core/
│ │ ├── config.py # 전역 싱글턴 (LLM, 임베딩, Groq 클라이언트)
│ │ ├── logging_config.py # 구조화된 로깅 + 추적 미들웨어
│ │ └── security.py # 내부 토큰 검증
│ ├── services/
│ │ ├── ocr.py # OCR (ocrmac + Tesseract 폴백)
│ │ ├── asr.py # 음성 인식 (Groq Whisper)
│ │ ├── rag.py # 적응형 RAG (컨텍스트 스터핑 + 벡터 검색)
│ │ ├── tts.py # 텍스트 → 음성 (edge-tts)
│ │ ├── risk.py # 위험 키워드 감지 + TTL 캐시
│ │ ├── email.py # 위험 알림 이메일 (비동기 스레드 풀)
│ │ ├── intent.py # 의도 분석 (현재 vs 과거 약품)
│ │ ├── search.py # 의약품 이력 검색
│ │ └── chat_model.py # 채팅 모델 전환
│ ├── models/
│ │ └── schemas.py # Pydantic 요청 모델
│ └── tests/ # pytest 단위 테스트
├── admin_dashboard.py # Streamlit 관리자 대시보드
├── risk_keywords.json # 위험 키워드 사전
├── sql/
│ └── init.sql # 데이터베이스 초기화 스크립트
├── Package-Insert_Test/ # 테스트용 샘플 의약품 설명서
├── .env.example # 환경 변수 템플릿
├── .gitignore # Git 무시 규칙
├── start_all.sh # 모든 서비스 원커맨드 시작
└── stop_all.sh # 모든 서비스 원커맨드 중지
No module named 'ocrmac'
ocrmac는 macOS Vision 프레임워크를 사용하며 macOS에서만 동작합니다. Linux에서는 Tesseract를 설치하세요:
sudo apt install tesseract-ocr tesseract-ocr-chi-sim
pip install pytesseract그런 다음 backend-ai/services/ocr.py에서 pytesseract를 사용하도록 수정합니다.
Java 백엔드 시작 시 Connection refused
MySQL이 실행 중이 아니거나 비밀번호가 잘못되었습니다.
# MySQL 상태 확인
mysql -u root -p -e "SELECT 1"
# .env 비밀번호가 MySQL root 비밀번호와 일치하는지 확인
cat .env | grep MYSQL_PASSWORDPython 시작 시 torchaudio 경고
VAD(Voice Activity Detection) 관련 비치명적 경고입니다. 시스템은 VAD 모드 없이 폴백되어 정상 동작합니다. 해결하려면: pip install torchaudio.
Maven 다운로드가 느린 경우
~/.m2/settings.xml에 미러를 추가합니다:
<mirrors>
<mirror>
<id>aliyun</id>
<mirrorOf>central</mirrorOf>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
</mirrors>브라우저에 빈 화면 표시
개발자 도구(F12) → Console 탭 확인. 흔한 원인:
- AI 서비스가 시작되지 않음 → 포트
8001확인 - Java 백엔드가 시작되지 않음 → 포트
8080확인 - CORS 오류 →
localhost:5174로 접속했는지 확인,file://로 접속하지 말 것
미니 프로그램이 백엔드에 연결되지 않음
- 스마트폰과 컴퓨터가 동일한 Wi-Fi 네트워크에 있는지 확인
config.js에 LAN IP가 설정되어 있는지 확인 (localhost또는127.0.0.1이 아닌)- 컴퓨터 방화벽이 포트
8080의 인바운드 연결을 허용하는지 확인 - 스마트폰 브라우저에서
http://YOUR_LAN_IP:8080/api/medicine/health접속 시도
음성 인식이 작동하지 않음 (웹)
브라우저는 마이크 접근에 HTTPS 또는 localhost를 요구합니다. http://localhost:5174로 접속했는지 확인하세요. LAN IP로는 접속할 수 없습니다.
음성 인식이 작동하지 않음 (미니 프로그램)
.env에 GROQ_API_KEY가 설정되어 있는지 확인하세요. .env 변경 후 Python AI 서비스를 재시작해야 합니다.
OCR이 "알 수 없는 약품"을 반환하거나 텍스트가 깨짐
- 사진이 선명하고 조명이 밝은지 확인
- 약품명이 이미지에 보여야 함
- PDF의 경우, 파일이 스캔 이미지(검색 불가능한 텍스트)인지 확인 — 시스템이 자동 감지하여 이미지 OCR을 사용합니다
데이터베이스 초기화 방법
mysql -u root -p -e "DROP DATABASE IF EXISTS medvision;"
mysql -u root -p < sql/init.sql그런 다음 Java 백엔드를 재시작하여 기본 관리자 계정을 다시 생성합니다.
관리자 비밀번호 변경 방법
관리자 대시보드(http://localhost:8502)에서 로그인 후 변경하거나, MySQL에서 직접 업데이트:
USE medvision;
UPDATE admin_users SET password_hash = '$2a$10$...' WHERE username = 'admin';BCrypt 해시는 온라인 도구 또는 Python으로 생성:
from passlib.hash import bcrypt
print(bcrypt.hash("your_new_password"))이 저장소에는 현재 라이선스 파일이 없습니다. 의도된 범위를 벗어나 배포하거나 재사용하기 전에 명시적인 라이선스를 추가하세요.
