_이 글은 Hacktoberfest Open-Source AI Challenge Week 1: Touch Grass 제출물입니다.
제가 만든 것
야외로 휴식을 취하는 가장 어려운 부분은 종종 의사결정 피로(decision fatigue)입니다. 장소를 정하고, 날씨를 확인하고, 시간이 있는지 살펴봐야 하는데 결국 밖에 나가는 대신 휴대폰을 스크롤하게 됩니다.
이 저장소는 등산로에 칠해진 블레이즈 마커와 시간 예산 내에서 편안하게 즐길 수 있는 외출이라는 개념에서 따와 blaze-and-back이라고 불립니다. DEV에서는 Touch Grass Planner라는 이름으로 게시되었습니다.
Touch Grass Planner는 화면 사용 시간을 30초 미만으로 최소화하도록 설계된 로컬 우선 웹 앱입니다. 세 가지 간단한 입력을 제공하면, 어디로 가야 할지 제안하고 휴대폰을 내려놓게 합니다.
- 사용 가능한 시간(분) (15분에서 240분)
- 현재 에너지 수준 (낮음, 보통, 높음)
- 위치 (지리적 위치 버튼 또는 입력된 도시) — 그리고 선택적인 관심사 태그(조용함, 물, 전망, 녹지, 운동, 사진 촬영) 또는 사용자가 직접 입력한 분위기.
만약 특별히 생각해 둔 것이 없는 경우, 모델이 흥미로운 새로운 장소를 찾도록 탐색적 테마(예: 마이크로 어드벤처 또는 숨겨진 보석)를 주입하는 **
구축 과정 (How It Was Built)
공개 사항: 초기 프로젝트 스캐폴드(backend, tests, interface, documentation)는 2026-10-07에 Claude를 사용하여 생성되었으며 (53c3e4f). 이후 기능 개선 및 복원력 있는 프로덕션 기능은 Antigravity AI 코딩 에이전트를 사용하여 명확하고 검증된 커밋을 통해 반복적으로 구축되었습니다:
5aa15c7 — 날씨 및 장소 조회용 10분 인메모리 캐시 (조정된 좌표로 키 지정)
361c782 — Overpass API 일시적 오류(429, 502, 503, 504) 발생 시 무작위 지터(random jitter)를 적용한 정중한 지수 백오프 재시도
1011db0 — 로컬 외출 기록 API (GET /api/history, DELETE /api/history) 및 프런트엔드 관리
c5aa8a0 — 접근성 패스: 오류 및 제안을 위한 키보드 순서 및 프로그래밍 방식 포커스 관리
922e796 — 전역 Overpass 서버가 과부하될 경우 자동 OpenStreetMap Nominatim 폴백(fallback)
94dc1ba & 4a98bd0 — 사용자 지정 유형의 기분/활동 입력 및 최상위
- 규칙이 무엇을 가능하게 하는지 결정하고, 모델은 무엇이 좋은지를 결정합니다. 기상 위험(뇌우, 향후 3시간 동안 강우 확률 ≥ 60%, 풍속 ≥ 50 km/h, 극심한 온도), 어둠, 그리고 도보 시간이나 에너지 한도를 초과하는 여행은 모델을 호출하기 전에 코드로 필터링됩니다.
- 모델의 출력을 절대 신뢰하지 마십시오. Ollama이 반환하는 제안은 프롬프트에 제공된 명시적인 후보 목록과 대조하여 확인합니다. 환각(Hallucinated)된 장소 ID, 유효하지 않은 JSON, 또는 불가능한 지속 시간은 거부됩니다. 유효한 것이 남아있지 않거나 Ollama가 오프라인인 경우, 앱은 결정론적 규칙 기반 순위 지정으로 폴백하며 이를 명확하게 기록합니다.
테스트
pytest를 통해 47개의 자동 단위 및 통합 테스트가 실행됩니다. 이 테스트들은 기상 코드 파싱, 지리적 거칠기화(geographic coarsening), Overpass 응답 정제(sanitization), LLM JSON 유효성 검사, SQLite 히스토리 추적, 그리고 캐시 TTL 만료를 다룹니다. 모든 외부 서비스는 가짜 HTTP 전송체로 목킹되어 있어, 이 테스트 스위트는 네트워크 연결이나 실행 중인 모델 없이도 실행됩니다.
오픈 소스와 로컬 추론의 이유
개인 정보 보호(Privacy). 사용자의 프롬프트—사용 가능한 시간, 에너지 수준, 관심사, 최근 외출 장소, 그리고 후보 장소—는 오직 사용자 자신의 컴퓨터에 있는 로컬 Ollama 서버로만 전송됩니다. 기기에서 나가는 유일한 데이터는 날씨 및 지도 질의를 위해 Open-Meteo와 OpenStreetMap으로 전송되는 약 110m 단위로 반올림된 좌표입니다.
교체 가능한 모델(Swappable models). 환경 변수(OLLAMA_MODEL) 하나만 변경하면 모델을 교체할 수 있습니다. 공급업체 종속성(vendor lock-in)이 없고 요청당 비용도 없습니다.
API 비용 제로, 그리고 신호 없이 작동하는 카드. 로컬에서 실행하는 것은 쿼리당 비용이 들지 않습니다. 날씨 및 지도 조회에는 활성화된 인터넷 연결이 필요하지만 (완전히 오프라인은 아니지만 로컬 우선), 생성된 외출 카드는 독립적인 HTML 문서이며 비행기 모드에서도 연결성 없이 안정적으로 열립니다.
로컬 모델 비교
세 가지 고정 계획 시나리오(모델당 총 3회 호출)에 걸쳐 scripts/compare_models.py를 --runs 1 옵션으로 사용하여 벤치마킹합니다.
알려진 한계점
- 로컬 모델 지연 시간 (Local Model Latency):
gemma2:9b는 이 하드웨어에서 계획 요청당 약 28초가 소요됩니다.
- OpenStreetMap 커버리지: OpenStreetMap의 밀도는 지역별로 크게 다릅니다. 희소한 지역에서는 이름이 지정된 자연 지형을 적게 얻을 수 있습니다.
- 도보 시간 휴리스틱 (Walking Time Heuristics): 도보 시간은 직선 거리 × 1.3 (4.8 km/h 기준)를 사용하여 추정됩니다. 실제 지형 및 도로 배치는 다를 수 있습니다.
- 장소만 제공: 현재는 라이브 이벤트나 티켓이 필요한 행사보다는 물리적인 야외 공간을 제안합니다.
수상 부문
- Gemma 활용 최우수 (Best Use of Gemma):
gemma2:9b는 Ollama를 통해 완전히 온디바이스(on-device)로 실행되며, 클라우드 API 없이 오픈 데이터 후보를 분석하고 실용적인 야외 제안을 합성하는 의사 결정 엔진 역할을 합니다.
- GitHub Actions CI: 이 저장소는 푸시 및 풀 요청 시 모든 47개의 단위 테스트(unit test) 및 통합 테스트(integration test)를 검증하는 자동화된 테스트 워크플로우(
.github/workflows/ci.yml)를 구현하며, 제3자 자격 증명(third-party credentials)이 전혀 필요 없습니다.