Skip to content

feat: 대화 컨텍스트 압축본 전송 및 채팅 메시지·대댓글 연동 - #14

Draft
soyeonLee126 wants to merge 19 commits into
developfrom
feature/chat-messaging
Draft

feat: 대화 컨텍스트 압축본 전송 및 채팅 메시지·대댓글 연동#14
soyeonLee126 wants to merge 19 commits into
developfrom
feature/chat-messaging

Conversation

@soyeonLee126

Copy link
Copy Markdown
Collaborator

작업 개요

대화가 길어져도 서버가 캐릭터 답장을 만들 수 있도록, 클라이언트가 대화 컨텍스트 압축본을 만들어
메시지 전송에 함께 보낸다. 이 PR의 목적은 그 압축본(currentConversationSummary) 전송을 실제로
태워 보는 것이고, 압축본을 만들려면 대화 자체가 필요해서 채팅 전송·대댓글 경로도 함께 들어 있다.

압축본은 서버에 저장되지 않고 답장 생성 컨텍스트로만 쓰인다. 상한은 2000자다.

압축 전략은 다음과 같다.

  • 첫 발화 원문 + 확정 청크들 + 최근 3발화 원문
  • 첫 발화는 대화 주제를, 최근 3발화는 답장이 직접 이어받는 맥락을 붙들고 있어 원문으로 남긴다
  • 그 사이만 온디바이스 요약기(kobart)로 압축하고, 한 번 확정한 청크는 다시 요약하지 않는다(요약의 요약 방지)
  • 청크는 요약기 인코더 입력 한계인 512 토큰에 맞춰 끊는다

대화 종료와 감정 카드 생성은 diff가 커져서 별도 PR로 분리했다(feature/chat-card).

작업 유형

  • feat: 새 기능
  • fix: 버그 수정
  • refactor: 리팩토링 (동작 변경 없음)
  • build: 빌드/의존성 설정
  • chore: 기타 (문서, 설정 등)
  • test: 테스트 추가/수정

변경 사항

압축본 (이 PR의 핵심)

  • ConversationSummaryStore: 대화가 진행되는 동안 압축본을 증분으로 만든다. 청크 요약을 캐시해 같은 텍스트를 두 번 요약하지 않는다
  • UtteranceTokenCounter 포트와 KobartTokenCounter 구현: 청크 경계를 재려면 절단 없는 토크나이저가 필요해 요약용 인스턴스와 별도로 둔다
  • SaveMessageRequest.currentConversationSummary 추가. encodeDefaults = false라 없으면 필드가 아예 빠진다(conversationId 생략 = 새 채팅방)

채팅 전송·대댓글

  • POST /api/conversations/messages, GET /api/conversations/{id}/messages 연동
  • 도메인 계약(ConversationRepository, SendMessageUseCase, GetMessagesUseCase)과 채팅방 화면(Orbit MVI)
  • 캐릭터 댓글을 1~3초 랜덤 간격으로 순차 노출한다. 한 번에 다 뿌리면 채팅 느낌이 없어서 정책으로 뒀고, 첫 댓글은 서버 왕복이 곧 대기 시간이라 즉시 붙인다
  • 노출 중 새로 전송하면 남은 댓글을 한꺼번에 붙이고 시작한다(순서 뒤엉킴 방지)

debug 전용 게이팅

  • 채팅 화면은 debug 빌드에서만 진입할 수 있다. :feature:chatdebugImplementation으로 두고 src/debug·src/release에 같은 이름의 진입점을 둬서 release 소스셋에는 화면이 아예 포함되지 않는다
  • data·domain의 대화 코드는 release에도 남는다(화면만 제외)

기타

  • local.propertiesDEV_BASE_URL/PROD_BASE_URL이 없으면 빌드를 실패시킨다
  • AppResult.of가 코루틴 취소를 삼키던 문제 수정
  • 감정 집계를 순수 함수로 분리해 배치 분류와 증분 누적이 같은 코드를 쓰게 했다

관련 이슈

  • 없음

관련 작업 (Notion)

스크린샷 / 동작 화면

체크리스트

  • base 브랜치가 develop으로 설정되어 있다
  • 로컬 빌드 및 실행을 확인했다
  • 커밋 메시지가 컨벤션(feat:, fix: 등)을 따른다
  • 불필요한 로그/주석/디버그 코드를 제거했다
  • 리뷰어가 이해할 수 있도록 설명을 작성했다

테스트

단위 테스트 70개 통과, detekt 통과.

실기기(SM-S911N) 검증. 새 방에서 3번 전송하며 요청 본문을 그대로 확인했다.

전송 요청 본문
1차 {"content":"today was rough at work"}
2차 {"content":"...","conversationId":33,"currentConversationSummary":"today was rough at work"}
3차 {"content":"...","conversationId":33,"currentConversationSummary":"today was rough at work the team lead dumped extra work on me"}
  • 첫 전송에는 conversationId와 압축본이 본문에서 빠지고, 2차부터 압축본이 누적된다
  • 순차 노출 간격 실측: 1.07 ~ 3.47초 (스크린샷 샘플링 오버헤드 포함)
  • 캐릭터 6종 매핑 확인: JOY→기쁨, WARM→다정, ANGER→분노, ANXIETY→불안, GRUMPY→까칠, QUIRKY→엉뚱
  • release APK dex 검사로 채팅 화면 미포함 확인

리뷰 요청 사항

압축 전략을 중점적으로 봐주면 좋겠다.

  • 첫 발화 + 최근 3발화를 원문으로 남기는 선택이 답장 품질에 맞는지
  • 청크 경계를 512 토큰으로 끊는 것과, 요약이 실패했을 때 원문으로 확정하는 처리
  • 상한 초과 시 오래된 청크부터 버리는 우선순위

아직 확인이 필요한 것

  • 서버의 압축본 상한 2000이 문자 수인지 바이트인지. 바이트면 한글 UTF-8 3바이트라 현재 검증(문자 수 기준)이 부족하다
  • 채팅 목록이 아직 더미라 항상 새 방으로 열린다. 그래서 재진입 복원 경로(서버 발화로 압축본을 다시 채우는 코드)는 단위 테스트로만 덮여 있다

…ging

# Conflicts:
#	.github/workflows/ci.yml
#	data/build.gradle.kts
#	data/src/main/java/com/gamss/android/data/di/NetworkModule.kt
#	data/src/main/java/com/gamss/android/data/di/RepositoryModule.kt
#	domain/build.gradle.kts
#	domain/src/main/kotlin/com/gamss/android/domain/card/GenerateCardInputUseCase.kt
#	domain/src/main/kotlin/com/gamss/android/domain/emotion/ClassifyUserEmotionUseCase.kt
#	domain/src/main/kotlin/com/gamss/android/domain/summary/SummarizeDiaryUseCase.kt
서버 error.code 가 보존되어 이미 종료된 방과 이미 만들어진 카드를
HTTP 상태 대신 코드로 구분한다.
feature/chat-card 브랜치에 보존했다. 이 브랜치는 메시지 전송과
컨텍스트 압축본 전송에 집중한다.
압축본 = 첫 발화 원문 + 확정 청크 요약들 + 최근 3턴 원문.
청크는 512 토큰을 채울 때 한 번만 요약하고 캐시해 같은 텍스트를
다시 요약하지 않는다. 토큰 측정은 절단 없는 토크나이저를 따로 쓴다.
요약기 입력 한계(512 토큰)를 넘긴 뒤 요약해 청크마다 마지막 발화가 절단되던 문제를
넘기기 전에 확정하도록 바꿨다. 요약이 실패하면 청크를 원문으로 확정해 재시도가 누적되지
않게 했고, 상한 초과 시 첫 발화와 최근 발화를 남기고 오래된 청크부터 버린다.

압축 실패가 전송·조회를 막지 않도록 요약·토큰 계산 실패를 격리하고 취소만 다시 던진다.
orbit intent 가 네트워크 응답 스레드에서 재개되므로 상태 변이를 Mutex 로 직렬화하고,
온디바이스 요약이 화면 갱신을 막지 않게 압축 갱신을 reduce 뒤로 옮겼다.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant