본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 07. 21:21

PuskesmasAI: 인도네시아 농촌 지역을 위한 오프라인 AI 트리아지(Triage) 앱 완성하기

요약

인도네시아 농촌 지역의 의료 격차를 해소하기 위해 개발된 오프라인 우선 AI 의료 트리아지 앱입니다. Gemma 4 E4B 모델을 온디바이스로 활용하여 인터넷 연결 없이도 환자 상태를 분류하고 조치 가이드를 제공합니다.

핵심 포인트

  • Gemma 4 E4B 모델을 활용한 완전한 온디바이스 AI 구현
  • 인터넷 연결이 불가능한 환경을 위한 PWA 및 로컬 우선 설계
  • IndexedDB를 통한 로컬 데이터 저장 및 연결 시 자동 동기화
  • 의료 데이터 프라이버시를 보호하는 Privacy by design 적용

이 게시물은 GitHub Finish-Up-A-Thon Challenge를 위한 제출물입니다.

내가 만든 것

PuskesmasAI는 인도네시아 농촌 지역의 보건 요원(kader)들에게 AI 기반의 의료 트리아지(Triage, 환자 분류) 기능을 제공하는 오프라인 우선 방식의 프로그레시브 웹 앱 (PWA)입니다. 최초 설정 이후에는 인터넷 연결이 전혀 필요하지 않습니다.

인도네시아는 인구 5,000명당 의사가 1명뿐이며, 이는 WHO가 권장하는 1:600 비율에 훨씬 못 미치는 수준입니다. 낙후된 3T 지역(Tertinggal, Terdepan, Terluar — 저개발, 최전방, 최외곽 지역)의 경우, 보건소의 45% 이상이 적절한 의료 인력이 부족합니다. 수백만 명의 유일한 일선 보건 자원인 비의료 자원봉사자 _kader_는 주변에 의사도 없고, 체계적인 가이드라인도 없으며, 인터넷조차 연결되지 않는 상황에서 트리아지(Triage) 결정을 내려야만 합니다.

PuskesmasAI는 이 문제를 해결합니다. _kader_가 인도네시아어로 된 간단한 양식을 통해 환자의 증상을 입력하면, 앱은 구조화된 AI 트리아지 결과인 **GREEN(녹색) / YELLOW(황색) / ORANGE(주황색) / RED(적색)**를 반환합니다. 여기에는 권장 조치, 가능한 질환, 위험 신호(Red flags), 그리고 자동 생성된 의뢰서가 포함됩니다. 환자 기록은 IndexedDB에 로컬로 저장되며, 연결이 복구되면 Puskesmas 대시보드로 동기화됩니다.

프론트엔드는 Next.js 14 (PWA) + Tailwind CSS로, 백엔드는 Python Flask로 구축되었으며, 온디바이스(On-device) AI 모델로는 **Gemma 4 E4B (Ollama를 통해 GGUF 양자화됨)**를 사용합니다 (~2.5GB, 클라우드 의존성 제로). 환자 데이터는 커뮤니티를 절대 벗어나지 않으며, 이는 설계 단계부터 프라이버시를 고려한 것입니다(Privacy by design).

이 프로젝트는 개인적으로 저에게 큰 의미가 있습니다. 저는 남술라웨시의 마카사르에 거주하고 있으며, 인도네시아 도시와 농촌 간의 의료 격차를 직접 목격하고 있습니다. PuskesmasAI는 AI가 가장 필요한 곳에 배치하려는 저의 시도입니다.

데모

🔗 Repository: https://github.com/jefribulomakassar/gemma4_good_hackathon

⚠️ 설계 단계부터 로컬 우선 (Local-first by design). PuskesmasAI는 완전히 온디바이스 (on-device)로 실행됩니다. Next.js 프론트엔드 (port 3000)와 Python Flask 백엔드 (port 5000)는 로컬 머신에서 각각 별도로 시작되며, Gemma 4 E4B는 Ollama를 통해 제공됩니다. 전체 목적이 오프라인 작동(클라우드 없음, 데이터가 기기를 벗어나지 않음)에 있기 때문에 호스팅된 데모는 존재하지 않습니다.

로컬에서 실행하는 방법:

# 터미널 1 — 백엔드 (Backend)
cd backend && pip install -r requirements.txt
ollama run gemma4:e4b
...

데모 시나리오:

휴대폰을 비행기 모드로 설정 → PuskesmasAI 실행 → 트리아지 (Triage) 정보 입력: 32세 여성, 증상: "3일간의 발열, 피부의 붉은 반점, 메스꺼움" → 분석 (Analyze) 탭 → 결과: 🟠 주황색 (ORANGE) 등급과 함께 조치 목록 및 의뢰 노트 표시 → WiFi 켜기 → 환자 기록이 대시보드로 자동 동기화 (auto-sync).

재기 스토리 (The Comeback Story)

이 프로젝트는 원래 Kaggle × Google DeepMind Gemma 4 Good Hackathon (Health & Sciences 트랙, 마감일: 2026년 5월 18일) 제출을 위해 시작되었습니다. 전체 컨셉, README, 아키텍처 다이어그램, 백엔드 보안 계층은 모두 준비되어 있었지만, 앱을 실제로 '작동'하게 만들 핵심 데이터 파일과 프론트엔드 컴포넌트를 완성하기 전에 시간이 부족했습니다.

이전 (원래 마감 시점에 존재했던 것):

  • ✅ 아키텍처 및 문제 정의가 포함된 전체 README
  • ✅ 6개의 보안 계층(JWT, HMAC, rate limiting, CORS, 프롬프트 인젝션 방어, 개인정보 보호 로그)을 갖춘 백엔드 Flask 앱
  • ✅ Next.js PWA 설정이 포함된 프론트엔드 구조
  • TriageResult.tsx, OfflineBanner.tsx, VoiceInput.tsx 컴포넌트
  • medical_kb.json 없음 — AI에게 의료 지식 베이스 (knowledge base)가 없었음
  • symptom_map.json 없음 — 증상과 질환 간의 매핑 정보가 없었음
  • drug_reference.json 없음 — 카데르 (kaders)를 위한 약물 용량 참조 정보가 없었음
  • SymptomForm.tsx 없음 — 주요 입력 양식이 누락됨
  • db.ts / sync.ts 없음 — 오프라인 저장소 및 동기화 기능이 구현되지 않음

**이후 (Finish-Up-A-Thon 기간 동안 추가된 것):

  • backend/data/medical_kb.json — 인도네시아 농촌 지역에서 가장 흔한 10가지 질병(뎅기열/DBD, 장티푸스, 말라리아, 급성 호흡기 감염(ARI/ISPA), 설사, 고혈압, 결핵, 영양실조, 콜레라, 자간전증)을 다루는 오프라인 의료 지식 베이스(medical knowledge base). 증상, 레드 플래그(red flags), 트리아지(triage) 단계 및 조치 사항을 포함하며, 모든 내용은 인도네시아어(Bahasa Indonesia)로 작성됨
  • backend/data/symptom_map.json — 인도네시아 구어체 키워드, 확률 가중치 및 자동 트리아지 에스컬레이션(escalation) 규칙이 포함된 32개 증상 그룹
  • backend/data/drug_reference.json — 인도네시아 국가 필수 의약품 목록(Formularium Nasional)을 기반으로 체중(kg)당 소아 용량, 금기 사항 및 카데르(kader, 지역 보건 요원)가 안전하게 사용할 수 있는 약물 분류를 포함한 10가지 필수 Puskesmas 의약품
  • frontend/src/components/SymptomForm.tsx — 증상 단축 버튼, 자동 임신 감지, 체온 표시기 및 양식 검증(form validation) 기능이 포함된 모바일 우선(mobile-first) 환자 접수 양식
  • frontend/src/lib/db.ts — 오프라인 환자 기록 저장을 위해 Dexie.js를 사용하는 IndexedDB 래퍼(wrapper)
  • frontend/src/lib/sync.ts — 연결이 복구될 때 대기 중인 기록을 Turso 클라우드로 업로드하는 자동 동기화(auto-sync) 모듈

변화: 잘 문서화된 스켈레톤(skeleton) 구조에서 진정으로 기능하는 오프라인 AI 트리아지(triage) 도구로의 진화.

GitHub Copilot 사용 경험

GitHub Copilot은 이 프로젝트를 완성하는 데 핵심적인 역할을 했습니다. 특히 수동으로 작성했다면 몇 시간이 걸렸을 데이터 집약적이고 보일러플레이트(boilerplate)가 많은 파일들을 처리하는 데 매우 유용했습니다.

**symptom_map.jsondrug_reference.json**은 로컬 설정 없이 github.dev 에디터에서 GitHub Copilot을 사용하여 완전히 생성되었습니다. 저장소(repository) 페이지에서 .을 눌러 github.dev를 열고, Ctrl+I를 눌러 인라인 프롬프트(inline prompts)를 호출하기만 하면 되었습니다. 저는 전체 파일 경로, 데이터 구조 요구 사항, 그리고 도메인 특화 컨텍스트(인도네시아 농촌 보건 상황, 국가 의약품 목록(Formularium Nasional) 제약 사항)를 제공했습니다. 결과는 정확하고 구조화가 잘 되어 있었으며, 제가 명시적으로 지정하지 않은 세부 사항들—예를 들어 인도네시아어 구어체 증상 용어(kejang/seizure에 대한 "step", rapid breathing에 대한 "ngos-ngosan") 및 카데르(kader, 지역 보건 요원)가 사용하기 안전한 적절한 약물 분류 단계—까지 포함되어 있었습니다.

**db.tssync.ts**는 기존 코드베이스와 일치하는 관용적인 TypeScript 및 Dexie.js 패턴을 사용하여 Copilot이 스캐폴딩(scaffolded)했습니다. 여기에는 업로드 상태를 추적하기 위한 synced 불리언(boolean) 필드와 동기화 로직 내의 navigator.onLine 확인 절차가 포함되었습니다. 한 시간 동안 작성해야 했을 보일러플레이트(boilerplate) 작업이 10분간의 집중적인 검토 및 개선 세션으로 바뀌었습니다.

배운 점: Copilot은 저장소 내의 정확한 파일 경로, 파일의 목적, 인지해야 할 관련 파일, 그리고 도메인 특화 제약 사항과 같은 전체 컨텍스트(context)를 제공할 때 가장 잘 작동합니다. 잘 만들어진 프롬프트 하나가 각 파일마다 몇 시간의 시간을 아껴주었습니다.

"최고의 AI는 가장 복잡한 AI가 아닙니다. 인터넷이 연결되지 않을 때조차, 그것을 가장 필요로 하는 사람들을 위해 작동하는 AI입니다."

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0