Implements the OQ-1 follow-up to #215 v0.2.0: replace the placeholder GemmaLlmService stub with a real flutter_gemma 0.16.5 backend driving Gemma 4 E2B (litert-community/gemma-4-E2B-it-litert-lm, 2.41GB). Highlights: - GemmaLlmService.load → FlutterGemma.initialize + installModel.fromFile + getActiveModel; idempotent + FileSystemException on missing file. - generateStructured uses Gemma 4 native function calling via createChat(tools: [Tool(...)], toolChoice: required). Stream parsed by collectFunctionCall — first FCR wins, ParallelFCR first-call wins, TextResponse/ThinkingResponse skipped, errors sanitized to prevent prompt leakage. - main.dart wires _LazyLlmService adapter that resolves to GemmaLlmService when ModelLifecycle reports ready, MockLlmService otherwise. - ai_providers.dart pins real model URL + SHA-256 (181938...39a63c). - F2 hardening: ModelLifecycle.purge wraps each delete + meta remove in try/catch so a single OS-level flake cannot block opt-out. - Android: INTERNET / FOREGROUND_SERVICE / POST_NOTIFICATIONS permissions + R8 proguard-rules.pro keeping MediaPipe / LiteRT / TFLite / protobuf JNI entry points (release builds otherwise crash on first inference). Design-First: fn-gemma_llm_service.md updated to v2 — §C (_appendSchemaInstruction) deprecated after reading flutter_gemma 0.16.5 source (Gemma 4 SDK injects tool declarations via template; prompt-side append would double-wrap). Tests: - 10 new unit tests for collectFunctionCall covering all 8 fn-spec cases + 2 ParallelFunctionCallResponse paths. - All 81 existing tests still pass. - flutter analyze: 0 issues. Refs #218 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
5.5 KiB
AI 도움 켜기·끄기 (사용자 가이드)
적용 버전: v0.2.0 이상 · Redmine #215 · 관련 레퍼런스: docs/reference/215-ai-frame-suggest.md
life-helper 는 사용자가 입력한 자유 문장(예: "술 끊고 싶어")을 Huberman 프로토콜 기반 L2/L3 프레임 문장으로 변환해주는 단말 내 AI 보조를 제공합니다. 모든 처리는 단말에서만 일어나며, 입력 텍스트는 외부로 전송되지 않습니다.
누구를 위한 가이드인가
- 새 습관을 추가할 때 "어떻게 표현하면 좋을지" 막막한 사용자.
- AI 기능을 켜기 전에 데이터/저장공간/배터리 영향을 미리 확인하고 싶은 사용자.
핵심 원칙
- 기본 OFF. AI 기능은 사용자가 명시적으로 켜야 동작합니다.
- 단말 처리. 입력 텍스트는 단말 밖으로 나가지 않습니다.
- 수동 입력 100% 유지. AI 가 꺼져 있거나 모델 다운로드가 안 되어 있어도, "프레임 문구" 입력란에 직접 작성하는 경로는 항상 살아있습니다.
AI 도움 켜기
- 하단 탭에서 설정 진입.
- "AI 도움 켜기" 토글 탭.
- 동의 다이얼로그가 뜹니다:
- 파일 크기 ≈ 2.4GB (Gemma 4 E2B Q4_0 모델 — 단말에 한 번만 다운로드)
- WiFi 연결 권장 (셀룰러 대역폭 절약)
- 모든 처리는 단말 — 입력 텍스트 외부 송출 없음
- "동의하고 다운로드" 탭 → 백그라운드 다운로드 시작.
다운로드 진행 화면
설정 화면 "AI 도움" 섹션 아래에 진행 상태가 표시됩니다:
| 상태 | 표시 | 가능한 조작 |
|---|---|---|
| 다운로드 중 | 진행률 % + 받은 용량 | 일시정지 버튼 |
| 일시정지됨 | 마지막 진행률 | 재개 버튼 (이어받기) |
| 실패 | 한국어 안내 메시지 (네트워크/서버/손상별) | 다시 시도 버튼 |
| 준비 완료 | "준비 완료" 라벨 + 받은 용량 | (조작 없음 — 사용 가능) |
다운로드 도중 앱을 강제 종료해도 다음 실행 시 같은 자리에서 이어받습니다 (HTTP Range 기반).
다운로드 실패 시 한국어 안내
| 화면 메시지 | 의미 | 권장 조치 |
|---|---|---|
| "네트워크 연결을 확인하고 다시 시도해주세요." | 일시적 끊김 | WiFi 확인 후 [다시 시도] |
| "서버 응답이 올바르지 않습니다. 잠시 후 다시 시도해주세요." | 서버 측 문제 | 시간 두고 [다시 시도] |
| "다운로드가 중단되었어요. 다시 시도하면 이어받습니다." | 스트림 중단 | [다시 시도] — 받은 데이터는 보존 |
| "파일이 손상되었어요. 다시 시도하면 처음부터 받습니다." | 무결성 검증 실패 | [다시 시도] — 자동으로 처음부터 |
AI 사용하기
- 새 습관 화면 진입.
- "제목" 에 자유 문장 입력 (예: "술 끊고 싶어").
- "프레임 문구" 입력란 아래 ✨ AI 제안 버튼 탭.
- AI 도움이 꺼져 있으면 버튼이 보이지 않습니다.
- AI 도움은 켜졌지만 모델 다운로드가 아직 완료되지 않았다면 버튼은 비활성 상태로 보이고 "AI 도움을 먼저 켜주세요" 툴팁이 표시됩니다.
- 다이얼로그에 후보가 최대 3개 표시됩니다 (L2 조건부 긍정 2개 + L3 정체성 1개 권장).
- 마음에 드는 후보 카드 탭 → "프레임 문구" 입력란이 자동으로 채워지고 프레임 레벨이 자동 선택됩니다.
- 저장.
후보가 없거나 마음에 안 들 때
- "더 구체적으로 입력해주시면 더 좋은 제안을 드릴 수 있어요" 메시지가 보이면 제목을 더 명확히 작성한 뒤 [다시 시도].
- 제안을 받지 못해도 프레임 문구를 직접 입력하셔도 괜찮습니다.
AI 도움 끄기
- 설정 → "AI 도움 켜기" 토글 OFF.
- 확인 다이얼로그:
- 모델 파일이 단말에서 즉시 삭제 됩니다.
- 약 2.4GB 의 저장공간이 확보됩니다.
- 다시 켜면 다시 다운로드해야 합니다.
- "끄고 삭제" 탭 → "공간 확보됨 2469 MB" 토스트.
진행 중인 다운로드가 있어도 깔끔히 중단되고, .tmp 임시 파일까지 함께 삭제됩니다.
자주 묻는 질문
Q. 입력 텍스트가 외부로 나가나요? A. 아니요. 단말 내 추론만 사용합니다. 다운로드는 모델 파일을 받을 때 한 번만 발생합니다.
Q. AI 가 만들어준 문장이 마음에 안 들면? A. 직접 입력란을 고쳐 쓰면 됩니다. AI 제안은 채우기 도우미일 뿐, 저장 시점 검증(L0/L1 금지 등)은 변하지 않습니다.
Q. 모델 파일이 너무 큽니다. A. 언제든 끌 수 있고, 끄면 즉시 삭제됩니다. 다시 켜면 다시 받아야 한다는 점만 유의하세요.
Q. v0.2.0 에서 다운로드가 항상 실패합니다. A. v0.2.0 은 모델 URL 이 미확정 (OQ-1) 인 상태로 출시되어, 실제 다운로드는 의도된 graceful 실패 경로로 안내됩니다. v0.3.0 부터 실 Gemma 4 E2B 모델 (HuggingFace) 다운로드가 활성화되었습니다. 그동안 수동 입력 경로는 정상 동작합니다.
관련 문서
- 설계서: docs/design/215-gemma-frame-suggest/
- 결정 기록: docs/adr/0003-on-device-llm-gemma.md
- API 레퍼런스: docs/reference/215-ai-frame-suggest.md
- 변경 이력: CHANGELOG.md