프로젝트/EWHA 캡스톤 졸업프로젝트

[졸업프로젝트] handDoc_ 서비스 핵심 기능과 전체 아키텍처 설계

rngPwns 2025. 11. 18. 14:42

1. 핵심 기능

 

handDoc 서비스의 주요 기능은 다음과 같다.

 

   주요기능을 자세히 풀어 써 보자면 다음과 같다.

 

(1) 대면 진료 환경에서의 활용

     1-1. 환자의 수어 인식 및 번역: 환자가 사용하는 수어가 실시간으로 텍스트 변환되어 의사가 즉시 확인 가능

     1-2. 의사 음성 자막화: 의사의 음성이 자막화되어 환자에게 제공

     1-3. 진료 종료 후 요약 제공: 진료가 완료된 이후, 대화 내역과 함께 요약 제공.

 

(2) 비대면 진료 환경에서의 활용

   비대면 진료에서는 대면 진료 환경에서 제공하는 기능에 더해, 환자의 상태와 의사소통 방식에 따라 맞춤형 기능을 제공한다. 환자는 진료 신청 단계에서 수어 사용 여부 및 발화 가능 여부를 선택할 수 있으며, 이에 따라 진료 방식이 조정된다.

 

 

 

   신청단계는 (주민등록번호 입력 > 진료 시간 선택 > 기능 선택 > 증상 입력) 의 4단계이다.    

 

 

     2.1 환자의 수어 인식 및 번역: 수어 사용 환자의 경우, 실시간 수어 인식과 텍스트 변환을 통해 진료 참여가 가능하도록 지원

     2.2 의사 음성 자막화: 의사의 음성이 자막화되어 환자에게 제공

 

 

     2.3 음성을 활용할 수 있는 청각장애인을 위한 음성 텍스트화: 발음이 어눌한 청각장애인의 음성을 인식한 후 3가지 후보 문장을 제시하여, 환자가 본인의 의도와 가장 가까운 표현을 선택 가능

 

 

     2.4 진료 종료 후 요약 제공: 진료가 완료된 후에는 대화 내역과 함께 요약 제공

     2.5 진료 내역 조회: 진료 내역 탭에서는 진료 내역과 함께 대화 내용/요약 조회 가능

 

 

 

(3) handDoc 서비스 사용 병원 조회

     3.1 본 서비스를 사용하는 병원을 지도에 표시하여 운영시간 및 요일, 위치를 조회할 수 있는 기능 제공

 

 

+ 대면/비대면 진료 플로우차트이다.

 

 

 

2. 개발 구조

 

   다음으로 해당 기능들을 개발한 구조에 대해 설명해보려 한다.

   전체 시스템 아키텍처는 다음과 같다.

1) 프론트엔드(front-end)는 React 기반으로 구성되어 있으며, WebRTC 화상 통신, WebSocket 연결, 실시간 자막 출력 등의 사용자 인터페이스를 담당한다.

 

[기술 스택 / 선택 이유 ]

      ● React : 사용자 인터페이스 구축 - 컴포넌트 단위 UI 구성으로 진료 화면(채팅, WebRTC, 자막)을 독립적으로 관리하기 쉽다.

      ● Vite : 빠른 개발 서버와 번들링 환경 제공 - Webpack보다 빌드/Hot Reload가 매우 빠르고, 실시간 스트리밍 기능 개발에 유리하다.

      ● TypeScript : 정적 타입을 통한 안정적인 코드 작성 - 실시간 데이터(WebSocket/SDP 등) 타입 안전성을 확보할 수 있다.

      ● TailwindCSS : 유틸리티 기반 CSS 프레임워크로 빠른 스타일링 지원 - 의료 UI처럼 변형 많은 페이지를 빠르게 스타일링할 수 있다.

      ● Socket.IO : FastAPI와의 실시간 WebSocket 통신

      ● WebRTC : 환자-의사 간 화상 진료 구현 - 의료 서비스에서 필수인 저지연 화상 통신을 보장한다. 미디어는 직접 P2P로 가므로 서버 부하가 최소화되며, 백엔드는 signaling만 담당해서 운영 비용이 낮다.

 

      ● Axios : 백엔드와의 RESTful API 통신

      ● React Router : 라우팅 처리

      ● Vercel : 프론트 배포 - DN 자동 적용 → 화상 진료 UI 로딩 속도가 안정적이다.

  • WebSocket: 영상 프레임(30fps)을 HTTP로 보내면 지연·오버헤드가 심각하다. WebSocket은 연결이 유지된 상태에서 프레임을 연속으로 전송할 수 있다. → 실시간 전송 최적

 

 

2) 백엔드(back-end)는 Spring Boot 기반의 백엔드 서버로, 사용자 인증, WebRTC 시그널링, 데이터 관리 등의 기능을 담당한다.

 

[기술 스택 / 선택 이유 ]

      ● 프레임워크 : Spring Boot, Spring Data JPA -인증/인가(Spring Security) 구성이 편하다 → 의료 서비스 특성상 필수이므로, JPA 기반으로 Reservation–Telemed–Summary의 RDB 스키마 구현이 용이하다. 또 WebRTC signaling 서버 구축에 적합한 MVC 구조를 제공한다.

 

 

      ● 인증 : Spring Security, OAuth 2.0

      ● 배포 : AWS EC2, Docker, Nginx, AWS RDS, MongoDB Atlas

      ● CI/CD : Github Actions

      ● 데이터베이스 : MySQL, MongoDB

      ● 외부 API : OpenAI API, Naver CLOVA Speech-to-Text API, 공공데이터 포털 API

 

3) 수어 인식 AI 는 FastAPI 기반으로 실시간 WebSocket 통신을 처리하며, 프론트엔드로부터 영상 프레임을 수신한 후, 수어 인식 모델을 통해 결과를 반환한다.

 

[기술 스택 / 선택 이유 ]

      ● PyTorch : 사전 학습된 수어 인식 모델 로드 및 추론

      ● MediaPipe : 영상에서 수어 키포인트 추출

      ● OpenCV : 비디오 프레임 처리

      ● Python : 전체 로직 구현 기반 언어

      ● FastAPI : 모델의 추론 결과를 반환하는 API 서버 - WebSocket 처리 성능이 Node.js 수준으로 빠르고 Python 모델과 바로 연동 가능하다. 또 AI 추론(PyTorch, Whisper)과의 연결이 자연스럽다.

 

      ● Uvicorn : FastAPI 실행 서버 - Uvicorn ASGI 기반이라 실시간 처리 지연이 적다.

 

4) 음성 인식 AI는 FastAPI 기반으로 음성 파일을 받아 파인튜닝된 Whisper 모델을 통해 텍스트로 결과를 반환한다.

 

[기술 스택]

     ● Hugging Face Transformers : 오디오 데이터를 모델 입력 피처(feature)로 전처리

     ● Librosa : 업로드된 음성 파일 로드 및 리샘플링

      ● Python : 전체 로직 구현 기반 언어

      ● FastAPI : 모델의 추론 결과를 반환하는 API 서버

      ● Uvicorn : FastAPI 실행 서버

 

(5) 인프라 (infrastructure)

   AWS EC2 1대에 Docker를 설치하고, 그 위에 Nginx와 3개의 애플리케이션을 컨테이너로 실행하는 구조이다.

Nginx (리버스 프록시, 웹 서버) 클라이언트에서 오는 모든 요청을 이 Nginx가 먼저 받는다. Nginx는 요청된 주소를 보고 트래픽을 올바른 Docker 컨테이너로 라우팅하는 역할을 한다. - SSL termination 수행(HTTPS 필요). /api, /ws, /ai-sign, /ai-voice 각각 트래픽 라우팅을 쉽게 설정할 수 있다.

 

 

     ● SSL/TLS 암호화: Nginx는 클라이언트와 Nginx 사이의 모든 통신을 암호화하여, 중간에서 데이터를 가로챌 수 없도록 안전하게 보호

     ● Docker (컨테이너화): 3개의 서로 다른 애플리케이션을 격리된 환경에서 실행시킵니다. 이를 통해 서로 다른 개발 환경과 의존성을 가진 서버들이 한 대의 EC2에서 충돌 없이 동시에 운영 가능 - FastAPI / Spring / Whisper 서버를 한 EC2에서 격리 실행 가능.

     ● 데이터베이스: AWS RDS (MySQL)와 MongoDB Atlas를 활용하여 데이터베이스 구축

DB를 두 가지로 나눠서 병행한 이유는 다음과 같다.

 

MySQL (예약/진료/요약 데이터):

  • 관계형 구조가 명확한 의료 도메인에 적합.
  • 트랜잭션·무결성 보장이 필요(예약, 시간대 충돌 등).

MongoDB (대화 로그):

  • 실시간 텍스트가 초당 다량 생성 → RDB로 넣으면 병목 발생.
  • 로그성 데이터는 스키마 없이 확장성이 더 중요해 NoSQL이 최적.

 

   React로 개발된 클라이언트 애플리케이션은 Vercel을 통해 별도로 배포된다. Vercel은 글로벌 CDN(콘텐츠 전송 네트워크)을 제공하여, 사용자가 전 세계 어디에서나 빠르고 안정적으로 UI에 접근할 수 있게 한다. Vercel에서 실행되는 React앱은 axios나 WebSocket을 통해 백엔드 서버의 Nginx로 API 요청을 보내 데이터를 주고받는다.

 

3. 주요 기능 구현 흐름

   이제 주요 기능의 구현 흐름을 설명해보겠다.

 

 

(1) 환자의 수어 텍스트화

   프론트엔드에서는 사용자의 웹 브라우저에서 카메라를 활성화해 실시간 영상 스트림을 받아오고, 이를 일정 주기마다 프레임 단위로 캡처한다. 캡처된 프레임은 WebSocket을 통해 FastAPI 서버로 연속해서 전송된다.
   WebSocket은 연결을 한 번 맺으면 유지되는 특성을 갖기 때문에, 매 요청마다 새 연결을 만들 필요가 없고 영상 프레임을 끊김 없이 전달할 수 있는 실시간 통로 역할을 한다.

   FastAPI 서버는 이 WebSocket 스트림을 통해 들어오는 프레임을 순차적으로 받아 처리한다. 프레임이 수신되는 즉시 Mediapipe Holistic을 적용해 손, 상반신 동작에 대한 키포인트(landmarks)를 추출한다. 추출된 키포인트는 30프레임 단위의 시퀀스로 누적해 Bi-LSTM 기반 수어 인식 모델에 입력된다.
   모델은 이 시퀀스 데이터를 시간적 흐름까지 고려하여 분석한 뒤, 최종적으로 해당 동작을 의미하는 텍스트로 변환한다.

 

 

(2) 의사의 음성 텍스트화

   프론트엔드는 진료 중 의사의 음성 데이터를 녹음한다. 녹음된 음성 파일은 axios를 통해 백엔드 서버로 전송된다. 백엔드에서는 Nginx를 거쳐 이 음성 데이터를 수신하고, 전달받은 음성 파일을 Naver CLOVA Speech-to-Text API로 전달하여 텍스트 변환을 요청한다. 변환된 텍스트 결과를 반환하면, 백엔드 서버는 이 텍스트 데이터를 받아 클라이언트로 전송한다.

 

 

(3) 수어가 아닌 구음을 사용하는 환자의 음성 텍스트화

  프론트엔드는 환자의 음성을 녹음한 뒤, 이를 Axios 요청으로 백엔드에 전송한다. 음성 데이터는 Nginx를 거쳐 Whisper 모델이 탑재된 FastAPI 서버로 전달된다. FastAPI 서버는 청각장애인의 발화 특성을 반영해 파인튜닝된 Whisper 모델을 사용하며, 전달받은 음성을 텍스트로 변환해 프론트엔드로 반환한다.

   변환된 텍스트는 다시 OpenAI gpt-4o 모델에 입력돼, 사용자가 선택할 수 있는 세 가지 문장 후보로 재가공된다. 이 과정에는 프롬프팅 엔지니어링이 적용된다.

   시스템 프롬프트에서는 AI의 역할을 ‘환자의 발화를 의미 그대로 자연스럽게 정제하는 보조자’로 정의하고, 의미 보존, 과교정 금지, 보수적 접근 같은 핵심 규칙과 JSON 출력 형식을 강제한다.

   사용자 프롬프트에서는 Whisper가 생성한 원문을 주입해, ① 최소 수정(보수적 교정) 1개, ② 자연스럽게 표현한 문장 2개를 생성하도록 구체적인 지시를 내린다. 의미가 불확실한 경우에는 원문 유지 등을 통해 안정성을 확보한다.

   이 흐름을 통해 환자가 발화한 내용을 정확하게 텍스트로 변환하고, 보다 자연스러운 문장 후보까지 제공하여 진료 중 의사소통을 보완할 수 있다.

 

(4) WebRTC 화상 통화 연결

   WebRTC 연결이 이루어지기 위해서는 두 가지 통신 단계가 필요하다. 먼저, 실제 통화 전에 서로의 연결 정보를 주고받는 시그널링(Signaling) 단계가 있고, 이후 연결이 성립되면 실제 영상, 음성 데이터를 주고받는 P2P(Peer-to-Peer) 통신 단계가 이어진다.

   백엔드 서버는 이 중 시그널링만 담당한다. 의사와 환자 클라이언트가 서로의 SDP(Session Description Protocol)와 ICE Candidates(네트워크 후보 정보)를 교환할 수 있도록 중개하는 역할을 수행한다. 이 정보 교환이 완료되면 두 클라이언트는 서버를 거치지 않고 직접 P2P 연결을 수립한다.

   연결이 성사된 이후부터는 실제 영상, 음성 스트림은 모두 클라이언트 간에 직접 전달되며, 서버는 미디어 데이터 경로에 관여하지 않는다. 이를 통해 낮은 지연 시간과 안정적인 실시간 진료 환경을 확보할 수 있다.

 

(5) 진료 내용 요약

 

   진료 중 발생하는 의사–환자 간 대화는 모두 MongoDB에 저장된다. 진료가 종료되면, 이 전체 대화 기록을 OpenAI gpt-4o 모델에 입력하여 증상(symptom), 의사 소견(impression), 처방/계획(prescription)의 세 가지 핵심 항목으로 자동 요약한다.
일관되고 정확한 요약을 생성하기 위해 다음과 같은 프롬프팅 엔지니어링 전략을 적용했다.

 

1. 데이터 전처리

AI가 대화의 흐름을 인식하기 쉽도록, MongoDB에 저장된 로그를 [화자]: [메시지] ([시간]) 구조의 단일 문자열로 정규화한다. 이후 각 로그를 순서대로 이어붙여 하나의 긴 대화 원문 텍스트를 생성한다.

 

2. 시스템 프롬프트 설계

모델이 안정적으로 요약을 생성하도록 역할과 규칙을 명확하게 지정한다.

  • 역할 정의: AI는 '의무기록 요약 도우미'로 동작한다.
  • 출력 형태 강제: 응답은 설명 없이 JSON 객체 하나만 반환하도록 지시한다.
  • JSON 스키마 명확화: { symptom, impression, prescription } 세 가지 필드를 고정적으로 포함해야 한다.
  • 정보 추측 금지: 대화에 존재하지 않는 정보는 '없음'으로 기입하도록 설정해 허위 정보 생성(할루시네이션)을 방지한다.

3. 사용자 프롬프트 구성

모델이 실제 요약 작업을 수행할 수 있도록, 전처리된 전체 대화 텍스트를 '대화원문:\n'이라는 접두사와 함께 입력한다. 이를 통해 모델이 전체 맥락을 기반으로 세 가지 핵심 항목을 안정적으로 도출하도록 한다.

 

 

   수어번역, 음성교정을 위해 사용한 AI모델(Bi-LSTM, Whisper)의 학습과정/파인튜닝 및 세부사항은 다음 포스팅에서 다루기로 하겠다.