AccessLens — 시각 장애인용 랜드리드, Gemma 4 온디바이스 구동
출처: Dev.to
이 글은 Gemma 4 Challenge: Build with Gemma 4에 제출된 작품입니다.
AccessLens는 안드로이드 앱으로, 란야드에 걸어 착용하는 Pixel 8을 시각 장애인 및 저시력 사용자를 위한 지속적인 시각 통역기로 변환합니다. 후면 카메라가 앞을 바라보고, 골전도 헤드폰을 통해 소리를 전달하면, 휴대폰이 세상을 설명하고 기억합니다.
기존 시각 보조 앱(Be My Eyes, Seeing AI, Envision)의 문제점은 화면에 묶여 있고, 상태를 유지하지 않으며, 클라우드에 의존한다는 점입니다. 시각 장애인은 소리를 통해 주변을 파악합니다. 화면을 들어 올리고, 터치하고, 데이터 센터가 응답하기를 기다리는 앱은 그 신호 흐름을 방해합니다. AccessLens는 다음 세 가지 축에서 다릅니다.
-
착용형, 손에 들지 않음 – 두 개의 물리 버튼으로 모든 동작을 제어합니다.
- Volume Up → 앞에 있는 텍스트를 그대로 읽어줍니다.
- Volume Down → 오늘 초반과 최근 며칠 동안의 기억을 바탕으로 방을 설명합니다.
- 자이로스코프 기반 SettleTrigger 가 사용자가 걸음걸이를 멈출 때 자동으로 설명을 제공합니다.
-
며칠·주 단위의 지속 메모리 – 모든 제스처는
SessionEvent로 SQLCipher 데이터베이스에 기록됩니다. 야간에 Gemma 4 워커가 매일을DailySummary로 압축하고, 일요일에는WeeklyMemory로 합칩니다. 롱프레스 시 해당 기록을 Gemma 호출에 삽입해, 모델이 특정 아파트·특정 날짜에 대한 세계 모델을 갖게 됩니다. -
100 % 온디바이스 – 이미지, 오디오, 임베딩, 위치 정보가 휴대폰을 떠나지 않습니다. SQLCipher + Android KeyStore (AES‑256‑GCM 로 감싸는 SecureRandom DB 키) 로 정적 데이터를 모두 보호합니다. 첫 실행 시 SelfTest 가 잘못된 키로 프로브 DB를 열어 읽기가 실패하는지 확인하고, 암호화가 정상임을 보고합니다.
얼굴 인식은 MediaPipe FaceLandmarker 로 등록된 사람당 192‑차원 L2 정규화 랜드마크 벡터를 생성합니다. 식별 시 코사인 유사도 매치를 통해 이름만 Gemma 프롬프트에 삽입하므로, Gemma 가 얼굴 이미지나 임베딩을 직접 보지는 않습니다(코드 리뷰로 검증됨).
세 가지 제스처, 세 가지 목표 지연 시간(Pixel 8, Tensor G3):
- SINGLE ≤ 14 초 전체 흐름
- DOUBLE 텍스트 길이에 비례
- LONG 메모리 검색 추가
음성 채우기 문구(“보고 있어요…”, “아직 보고 있어요…”)가 프리필 공백을 메워 사용자는 정적이 아닌 진행 소리를 듣게 됩니다. 모델을 한 번 푸시한 뒤에는 비행기 모드에서도 모든 기능이 동작합니다.
코드
/
AccessLens
AccessLens
An always-on, on-device visual interpreter for blind and low-vision users — built for the DEV.to "Build with Gemma 4" challenge.
Pitch
란야드에 걸어 착용하는 휴대폰이 사용자의 **‘눈’**이 됩니다. 후면 카메라가 항상 켜져 있고, 자이로스코프가 움직임을 감시합니다. 사용자가 걸음걸이를 멈추면 AccessLens 가 앞에 있는 것을 설명합니다. 얼굴이 등록된 친구가 화면에 들어오면 이름을 알려줍니다. 앞의 텍스트를 읽고 싶으면 Volume Up, 방을 더 자세히 설명받고 싶으면 Volume Down 를 누릅니다. 블루투스 골전도 헤드폰을 통해 오디오를 전달하므로 귀는 자유롭게 주변을 들을 수 있습니다.
AccessLens 가 Be My Eyes, Seeing AI, Envision 같은 기존 앱과 차별되는 점은 지속적인 온디바이스 메모리와 100 % 온디바이스 추론입니다. 기존 도구들은 무상태이며 클라우드에 의존합니다. AccessLens 는 Gemma 4 E2B 를 LiteRT‑LM 로 로컬에서 실행하고, 모든 데이터를 암호화합니다.
Apache 2.0 라이선스. 레포지토리에는 전체 Kotlin/Compose 소스, 암호화 셀프‑테스트, 야간 압축 WorkManager 작업, 그리고 여섯 가지 개인정보 보호 불변성을 각각 구현한 파일에 대한 README 가 포함되어 있습니다.
LiteRT‑LM API 를 처음 배울 때 참고한 구현: google-ai-edge/gallery — 적용된 패턴은 inference/LiteRtLmRuntime.kt 에 인라인으로 주석 처리했습니다.
모델: Gemma 4 E2B
- Gemma 4 E2B (
litert-community/gemma-4-E2B-it-litert-lm, 약 2.59 GB int4) 를 서비스 시작 시 한 번 로드하고, Vision 어댑터를 위해Backend.GPU()로 실행합니다. - E2B 를 선택한 이유 세 가지:
- 멀티모달을 하나의 모델 로 온디바이스에서 처리. 이미지 입력은
Content.ImageBytes, 텍스트는Content.Text로 순차 전달(갤러리의 “정확한 마지막 토큰” 주석 참고). 하나의Engine.generate호출만 필요합니다. 별도의 비전 인코더·디코더나 두 번째 모델이 없어 메모리·지연 예산에 맞습니다. - RAM 적합성 – Pixel 8 의 8 GB RAM 안에서 MediaPipe FaceLandmarker, CameraX 파이프라인, Compose UI 와 함께 동작해 OOM 없이 실행됩니다. E4B 로 실험했지만, 한 문장 장면 설명 시 지연이 두 배가 되어 실시간 사용에 부적합했습니다. 향후 LONG‑press 분기에서 한 줄만 바꾸면 E4B 로 교체 가능하도록 설계했습니다.
- 야간 메모리 압축 – 03:00에 실행되는
CompressionWorker가 Gemma 를 JSON 모드로 호출해 하루치SessionEvent를DailySummary로, 일요일엔WeeklyMemory로 압축합니다. 이는 “파란 머그는 내 것”과 “오늘 파란 머그를 봤다”를 구분하고, 중복 관찰을 제거하는 실제 LLM 작업이며, 네트워크 없이 수행됩니다. Tensor G3 에서는 하루당 1분 미만으로 처리됩니다.
- 멀티모달을 하나의 모델 로 온디바이스에서 처리. 이미지 입력은
제작 과정에서 발견한 두 가지 프로덕션 이슈
- LiteRT‑LM Android 아티팩트는 반드시
0.12.0이상이어야 합니다.0.11.0은 Tensor G3 에서vision_litert_compiled_model_executor.cc:273에서 비전 초기화에 실패합니다. - AndroidManifest에
libOpenCL.so,libOpenCL-car.so,libOpenCL-pixel.so선언이 필요합니다(android:required="false"). 선언이 없