기능설계 표본 ① — 실벗 · 원챗 · DeepSeek 3자 연동의 핵심
| 항목 | 내용 |
|---|---|
| 기능 ID | FEAT-ARI-CHAT |
| 연결 시스템 | 마스터 PART2 아리엔진 · 시스템② 놀이 · ⑧ 정서존엄 |
| 한 줄 정의 | 어르신이 말을 걸면(또는 아리가 먼저 걸면), 아바타가 음성·표정으로 대화하고 기억한다 |
| 관련 액터 | PWA실벗서버원챗DeepSeek |
| 계층 | 이 문서의 섹션 |
|---|---|
| ① UI | 화면 명세 (대화 화면 SCR-ARI-01) |
| ② Flow | 대화 상태 머신 + 먼저 말걸기 트리거 |
| ③ Data | chat_sessions / chat_messages / ari_memory DDL |
| ④ API | 대화 송수신 · 기억 · 먼저말걸기 엔드포인트 |
| ⑤ Seq | STT→실벗→DeepSeek→원챗→TTS 시퀀스 + 폴백 |
| ⑥ Comp | 프론트/백엔드 컴포넌트·서비스 구조 |
| ⑦ Test | 검수 체크리스트 (개발 완료 판정 기준) |
| 요소 | 사양 · 동작 |
|---|---|
| 아바타 영역(상단 50%) | 원챗 아바타 렌더(말할 때 입모양·표정 변화). 유휴 시 미소·눈깜빡임 idle 모션 |
| 자막(아바타 하단) | 아리 발화 텍스트를 큰 글씨(28px+)로 동시 표시(난청 대비) |
| 대화 말풍선 리스트 | 최근 대화 스크롤. 어르신=오른쪽, 아리=왼쪽. 글씨 크기 사용자 설정 반영 |
| 🎤 큰 마이크 버튼 | 화면 하단 중앙 대형 원형. 누르고 말하기(PTT) 또는 탭 토글. 녹음 중 파형 애니메이션 |
| ⌨️ 텍스트 입력(보조) | 마이크 옆 작은 키보드 아이콘. 음성이 어려운 분 대비 |
| 🔊 다시듣기 버튼 | 아리 마지막 말 다시 음성 재생 |
| 접근성 | 최소 폰트 28px, 터치 영역 ≥ 64px, 명도대비 AA, 음성 우선 |
| 상태 | 아바타 | 마이크 버튼 | 자막 |
|---|---|---|---|
| idle(대기) | 미소·눈깜빡임 | 🎤 "눌러서 말하기" | 이전 대화 |
| listening(듣는중) | 고개 끄덕·경청 표정 | 🔴 파형 애니메이션 | (실시간 STT 미리보기) |
| thinking(생각중) | 잠깐 위 보는 모션 | 비활성 + 점점점… | "음… 생각하고 있어요" |
| speaking(말하는중) | 입모양·표정 동기화 | 비활성 | 발화 텍스트 실시간 |
| error(오류) | 갸웃 표정 | 🎤 재시도 | "잘 못 들었어요. 다시 말씀해 주실래요?" |
| 전이 | 트리거 | 예외 |
|---|---|---|
| idle→listening | 마이크 버튼 탭 / "아리야" 호출어 | 마이크 권한 거부 → 안내+텍스트 입력 유도 |
| listening→thinking | 발화 종료(무음 1.5s) 또는 버튼 해제 | STT 빈 결과 → error("다시 말씀해 주실래요?") |
| thinking→speaking | 실벗 서버 응답 수신(SSE) | LLM/원챗 타임아웃 → 폴백 응답으로 speaking |
| speaking→idle | TTS 재생 완료 | 사용자가 새로 말하면 즉시 listening(인터럽트) |
마스터 PART2 "먼저 말 건다" 원칙의 구현. 서버 스케줄러가 조건 충족 시 원챗 발송 API로 푸시.
| 트리거 | 조건 | 발화 예 |
|---|---|---|
| 아침 안부 | 매일 기상시간대(프로필) 첫 활동 or 08:00 | "순자님, 좋은 아침이에요. 잘 주무셨어요?" |
| 복약 알림 | medications 스케줄 시각 | "혈압약 드실 시간이에요. 제가 같이 셀게요." |
| 무응답 안부 | N시간 무활동(SOS 임계 미만) | "오늘 조용하시네요. 뭐 하고 계세요?" |
| 어제 이어가기 | 전일 대화 키워드 기억 | "어제 무릎 아프다 하셨는데 좀 어떠세요?" |
기존 p25의 chat_sessions·chat_messages 재활용 + 아리 장기기억 ari_memory 신설.
ari_memory가 "기억하는 AI"를 만드는 핵심. 대화 종료 시 LLM이 중요 정보를 추출해 여기에 저장하고, 다음 대화 시 프롬프트에 주입한다.| M | 경로 | 설명 |
|---|---|---|
| POST | /api/v1/ai/chat | 발화 전송 → 아리 응답 스트리밍(SSE) |
| GET | /api/v1/ai/sessions/{id}/messages | 대화 이력 조회(페이지네이션) |
| POST | /api/v1/ai/proactive/check | (스케줄러용) 먼저말걸기 조건 평가·발송 |
| GET | /api/v1/ai/memory | 아리 기억 조회(가족 공유범위 적용) |
UPSTREAM_LLM/UPSTREAM_ONECHAT이 아니라, 사용자에겐 폴백 응답을 done으로 정상 전달(아래 ⑤ 참조). 어르신이 "고장"을 느끼지 않게 한다.한 번의 대화가 4개 액터를 거치는 전체 흐름.
POST /ai/chattoken 중계audio_url + 아바타 wss 토큰 수신done 전송ari_memory upsert (다음 대화에서 "기억")| 장애 지점 | 폴백 동작 |
|---|---|
| DeepSeek 타임아웃 | 사전 정의 안전 응답("제가 잠깐 멍했네요. 다시 말씀해 주실래요?") + 재시도 큐 |
| 원챗 렌더 실패 | 아바타 없이 자막 + 브라우저 TTS로 대체(대화 자체는 지속) |
| 네트워크 끊김 | 오프라인 안내 + 마지막 입력 로컬 보관 후 복구 시 자동 전송 |
| 모듈 | 책임 |
|---|---|
AriPromptBuilder | 관계의 핵심. 기억·프로필·페르소나·안전가드를 조합해 "순자님만의 아리" 프롬프트 생성 |
OneChatService | 원챗 API 추상화. 장애 시 폴백 신호 반환(컨트롤러가 자막+브라우저TTS로 전환) |
ProactiveScheduler | cron 주기 실행 → 트리거 평가 → 원챗 발송. 존엄 가드(빈도 제한) 적용 |
d02 SOS는 같은 틀에 생명 안전·상태머신·3주체 알림을 더해 설계합니다.개발 완료 판정 기준. 이 체크리스트를 모두 통과해야 "아리 대화" 기능이 완성된 것으로 본다. (QA 검수표 겸용)
| ID | 시나리오 | 기대 결과 |
|---|---|---|
| T-01 | 🎤 마이크 버튼 누르고 "오늘 날씨 좋네" 발화 | STT 인식 → 아리 답변 음성+자막 출력, 아바타 입모양 동기화 |
| T-02 | 텍스트 입력창에 직접 타이핑 후 전송 | STT 없이도 동일하게 답변 생성·출력 |
| T-03 | "다시듣기" 버튼 탭 | 직전 아리 답변이 다시 음성 재생 |
| T-04 | 대화 종료 후 같은 회원이 다음날 재접속 | 이전 대화의 핵심(ari_memory)이 프롬프트에 주입되어 "어제 ~하셨죠?" 식 회상 |
| T-05 | 아침 9시 (먼저 말걸기 트리거) | 아리가 먼저 안부 인사 발송(원챗) — 존엄 가드 빈도 제한 준수 |
| ID | 시나리오 | 기대 결과 |
|---|---|---|
| T-06 | 브라우저 마이크 권한 거부 | 음성 비활성·안내문구 노출, 텍스트 입력으로 자동 폴백 (기능 중단 없음) |
| T-07 | DeepSeek LLM 502/타임아웃 | UPSTREAM_LLM 정형 응답 + 어르신용 문구("잠시 후 다시 말씀해 주세요") |
| T-08 | 원챗 아바타 API 장애 | 아바타 폴백 → 자막 + 브라우저 TTS로 대화 계속 (OneChatService 폴백 신호) |
| T-09 | JWT 만료 상태로 /ai/chat 호출 | AUTH_EXPIRED(401) → 토큰 재발급/재로그인 유도 |
| T-10 | 네트워크 끊김 (SSE 중단) | 마지막 수신분까지 표시 + 재연결 안내, 중복 메시지 저장 없음 |
| T-11 | 부정 발화·위기 신호("죽고싶어") 감지 | 안전가드 발동 → 정서 지지 응답 + (설정 시) 보호자/상담 안내 트리거 |
FEAT-ARI-CHAT 개발 완료. 특히 T-06·T-07·T-08(폴백 3종)은 어르신 경험상 필수 — 어떤 외부 장애에도 대화가 끊기지 않아야 한다.