캐릭터 챗봇 #338

Merged
klaus merged 119 commits from test into main 2025-09-10 06:08:47 +00:00
3 changed files with 36 additions and 6 deletions
Showing only changes of commit f2ca013b96 - Show all commits

View File

@ -2,6 +2,8 @@ package kr.co.vividnext.sodalive.chat.room.dto
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import com.fasterxml.jackson.annotation.JsonProperty
import kr.co.vividnext.sodalive.chat.character.CharacterType
import java.time.LocalDateTime
/**
* 채팅방 생성 요청 DTO
@ -24,7 +26,9 @@ data class ChatRoomListItemDto(
val chatRoomId: Long,
val title: String,
val imageUrl: String,
val lastMessagePreview: String?
val opponentType: String,
val lastMessagePreview: String?,
val lastMessageTimeLabel: String
)
/**
@ -40,10 +44,13 @@ data class ChatMessageItemDto(
/**
* 채팅방 목록 쿼리 DTO (레포지토리 투영용)
*/
data class ChatRoomListQueryDto(
val chatRoomId: Long,
val title: String,
val imagePath: String?
val imagePath: String?,
val characterType: CharacterType,
val lastActivityAt: LocalDateTime?
)
/**

View File

@ -40,7 +40,9 @@ interface ChatRoomRepository : JpaRepository<ChatRoom, Long> {
SELECT new kr.co.vividnext.sodalive.chat.room.dto.ChatRoomListQueryDto(
r.id,
r.title,
pc.character.imagePath
pc.character.imagePath,
pc.character.characterType,
COALESCE(MAX(m.createdAt), r.createdAt)
)
FROM ChatRoom r
JOIN r.participants p

View File

@ -199,18 +199,39 @@ class ChatRoomService(
val latest = messageRepository.findTopByChatRoomAndIsActiveTrueOrderByCreatedAtDesc(room)
val preview = latest?.message?.let { msg ->
if (msg.length <= 25) msg else msg.take(25) + "..."
if (msg.length <= 30) msg else msg.take(30) + "..."
}
val imageUrl = "$imageHost/${q.imagePath ?: "profile/default-profile.png"}"
val opponentType = q.characterType.name // Clone or Character
val time = latest?.createdAt ?: q.lastActivityAt
val timeLabel = formatRelativeTime(time)
ChatRoomListItemDto(
chatRoomId = q.chatRoomId,
title = q.title,
imageUrl = "$imageHost/${q.imagePath ?: "profile/default-profile.png"}",
lastMessagePreview = preview
imageUrl = imageUrl,
opponentType = opponentType,
lastMessagePreview = preview,
lastMessageTimeLabel = timeLabel
)
}
}
private fun formatRelativeTime(time: java.time.LocalDateTime?): String {
if (time == null) return ""
val now = java.time.LocalDateTime.now()
val duration = java.time.Duration.between(time, now)
val seconds = duration.seconds
if (seconds <= 60) return "방금"
val minutes = duration.toMinutes()
if (minutes < 60) return "${'$'}minutes분 전"
val hours = duration.toHours()
if (hours < 24) return "${'$'}hours시간 전"
// 그 외: 날짜 (yyyy-MM-dd)
return time.toLocalDate().toString()
}
@Transactional(readOnly = true)
fun isMyRoomSessionActive(member: Member, chatRoomId: Long): Boolean {
val room = chatRoomRepository.findById(chatRoomId).orElseThrow {