명칭 변경: - decision-log.md Q6 확정: "분신"(가칭) → "와카뷰 (Ykavu)" — 焚身(분신자살) 동음이의 리스크도 있었고 메신저 브랜드로 부르기 무거웠음. Master가 최종 선택한 이름으로 변경(2026-07-31), 파생 문서(AGENTS.md/CLAUDE.md/PRD 등)· Flutter 앱 텍스트·web manifest/index.html·AndroidManifest 라벨까지 전부 반영 - ai-service: 본인확인 고정 문구(identity.py)·시스템 프롬프트(generation.py)도 갱신 — 새 이름 기준으로 "본인이야 와카뷰야?" 류 질문을 감지하도록 정규식도 같이 손봄(단순 문자열 치환만으론 어미 형태가 안 맞아서 테스트 추가/조정) - poc/tone-corpus/의 실험용 프롬프트는 의도적으로 그대로 둠(ai-service README에 이미 명시된 대로 프로덕션과 분리된 실험 도구) UI/UX: - mobile/lib/theme/app_theme.dart: 시드 컬러를 인디고/라벤더로 변경, 화면 전체에 깔리는 소프트 그라디언트(라이트: 라벤더→스카이→핑크 파스텔, 다크: 딥 인디고→ 네이비→플럼) + 카드/인풋/칩을 반투명 "글래스" 서피스로 전환 - mobile/lib/widgets/gradient_backdrop.dart(신규): MaterialApp.builder에 연결해 모든 화면에 자동으로 그라디언트 배경 적용 - mobile/lib/screens/splash_screen.dart(신규) + main.dart 재구성: 기존엔 session.restore()를 기다리는 동안 아무 것도 안 그려서 흰 화면/텍스트만 뜨는 구간이 있었음 — runApp을 먼저 하고 restore 동안 브랜드 스플래시가 뜨도록 변경 - chat_screen·autonomy_settings_screen·data_flow_screen의 커스텀 패널들도 글래스 스타일로 맞춤 BunsinApp -> YkavuApp (mobile/lib/main.dart, test/widget_test.dart 동기화) Flutter SDK가 없는 환경이라 flutter analyze/run으로 직접 컴파일 검증은 못했음 — 중괄호/괄호 균형과 기존에 검증된 API 패턴 위주로 신중하게 작성함. go test· pytest는 전부 통과. |
||
|---|---|---|
| .. | ||
| app | ||
| tests | ||
| README.md | ||
| pytest.ini | ||
| requirements-dev.txt | ||
| requirements.txt | ||
README.md
와카뷰 AI service (Python)
Phase 1 AI 서비스 (docs/roadmap.md Phase 1 §2.2). poc/tone-corpus/의 세 스크립트
(generate_draft.py·escalation_filter.py·retrieve_style.py)를 그대로 승격한 내부 API —
core-backend/(Go)가 이 서비스를 내부망 HTTP로 호출한다 (tech-design.md §8).
poc/tone-corpus/는 그대로 둔다 — 거긴 코퍼스 실험/블라인드 평가용 PoC 도구로 계속 쓰고,
여기 코드가 실제로 서비스에 쓰이는 "승격된" 버전이다. 두 곳의 로직은 지금 동일하지만, 앞으로
갈라질 수 있다(예: 여기는 프로덕션 안정성 위주로만 바뀌고, PoC 쪽은 계속 실험적으로 바뀌는 식).
실행
pip install -r requirements.txt
export GEMINI_API_KEY=... # 또는 이 디렉토리에 .env 파일
uvicorn app.main:app --reload --port 8001
테스트
pip install -r requirements-dev.txt
pytest tests/ -v
escalation_filter.py(SELFTEST_CASES 승격 + 추가 케이스)·retrieve_style.py(overlap이 recency를
항상 이긴다는 것, 동점일 때만 recency가 tie-break한다는 것)·generation.py(escalate/no_key/ok 세
경로, Gemini 호출은 mock)·main.py(/health·/escalate/check·/draft 전부)를 tests/의 정식
pytest 스위트로 승격함 (docs/roadmap.md Phase 1 §2.5). 이전엔 ad-hoc TestClient 스크립트로만
확인했던 것들.
API
POST /escalate/check
{ "text": "계좌번호 알려줄래?" }
응답: { "escalate": true, "reason": "금전" }
/draft와 별개로 존재하는 독립 하드게이트 엔드포인트 — core-backend가 트윈(자동발송) 메시지를
저장하기 직전에 이걸 직접 호출해서, /draft를 거치지 않은 발송 경로도 전부 이 게이트를 통과하게
만든다 (docs/roadmap.md Phase 1 §2.4, AGENTS.md 안전 불변식). TestClient로 금전/약속/감정
케이스와 비대상 텍스트 전부 확인함.
POST /draft
{
"context_lines": ["상대: 오늘 저녁에 뭐 먹을래?"],
"style_examples": ["ㅇㅇ 좋지", "나도 궁금하네ㅋㅋ"]
}
style_examples(직접 큐레이션) 또는 history(과거 발화 전체, 자동 검색 — k로 개수 조절) 중
정확히 하나만 넣는다. 둘 다 넣거나 둘 다 안 넣으면 422.
응답:
{ "status": "ok" | "escalate" | "no_key", "text": "..." }
ok:text는 생성된 답장 초안escalate:text는 에스컬레이션 사유 (금전/약속 확정/감정적으로 무거운 주제) — 이 경우 LLM은 호출되지 않는다 (escalation_filter.py가 하드 게이트)no_key:GEMINI_API_KEY가 없어서 실제 전송될 프롬프트만text에 담아 반환
TestClient로 style_examples/history 두 경로, 에스컬레이션 케이스, 검증 오류(422) 전부 확인함.
아직 없는 것
- 온디바이스 말투 이력 저장 (이건 클라이언트/코어 백엔드 쪽 책임 —
tech-design.md§2 참고) - 사후 알림 + 되돌리기 UI/전체 흐름 (코어 백엔드는 이제 에스컬레이션 시
escalation_logs에 기록은 하지만, 사용자에게 사후 알림을 띄우고 되돌리는 클라이언트 UX는 아직 — Flutter 쪽 작업)