narasiahli-be/app/module/chat_history/service/chat_history.service.go

318 lines
9.9 KiB
Go

package service
import (
"errors"
"narasi-ahli-be/app/database/entity"
"narasi-ahli-be/app/module/chat_history/mapper"
"narasi-ahli-be/app/module/chat_history/repository"
"narasi-ahli-be/app/module/chat_history/request"
"narasi-ahli-be/app/module/chat_history/response"
usersRepository "narasi-ahli-be/app/module/users/repository"
"narasi-ahli-be/utils/paginator"
utilSvc "narasi-ahli-be/utils/service"
"github.com/rs/zerolog"
)
type chatHistoryService struct {
Repo repository.ChatHistoryRepository
UsersRepo usersRepository.UsersRepository
Log zerolog.Logger
}
type ChatHistoryService interface {
// Sessions
GetUserSessions(authToken string, req request.ChatHistorySessionsQueryRequest) (sessions []*response.ChatHistorySessionsResponse, paging paginator.Pagination, err error)
GetSession(authToken string, sessionID string) (session *response.ChatHistorySessionWithMessagesResponse, err error)
CreateSession(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error)
UpdateSession(authToken string, sessionID string, req request.ChatHistorySessionsUpdateRequest) (err error)
DeleteSession(authToken string, sessionID string) error
// Messages
GetSessionMessages(authToken string, sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*response.ChatHistoryMessagesResponse, paging paginator.Pagination, err error)
CreateMessage(authToken string, req request.ChatHistoryMessagesCreateRequest) (message *response.ChatHistoryMessagesResponse, err error)
UpdateMessage(authToken string, messageID uint, req request.ChatHistoryMessagesUpdateRequest) (err error)
DeleteMessage(authToken string, messageID uint) error
// Combined operations
SaveChatHistory(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error)
}
func NewChatHistoryService(repo repository.ChatHistoryRepository, usersRepo usersRepository.UsersRepository, log zerolog.Logger) ChatHistoryService {
return &chatHistoryService{
Repo: repo,
UsersRepo: usersRepo,
Log: log,
}
}
// Sessions methods
func (_i *chatHistoryService) GetUserSessions(authToken string, req request.ChatHistorySessionsQueryRequest) (sessions []*response.ChatHistorySessionsResponse, paging paginator.Pagination, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Set user ID from auth token
req.UserID = &userInfo.ID
results, paging, err := _i.Repo.GetUserSessions(userInfo.ID, req)
if err != nil {
return
}
for _, result := range results {
sessions = append(sessions, mapper.ChatHistorySessionsResponseMapper(result))
}
return
}
func (_i *chatHistoryService) GetSession(authToken string, sessionID string) (session *response.ChatHistorySessionWithMessagesResponse, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Verify session belongs to user
sessionEntity, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID)
if err != nil {
return nil, err
}
// Get messages for this session
messagesReq := request.ChatHistoryMessagesQueryRequest{
SessionID: sessionID,
Pagination: &paginator.Pagination{
Limit: 1000, // Get all messages for now
},
}
messages, _, err := _i.Repo.GetSessionMessages(sessionID, messagesReq)
if err != nil {
return nil, err
}
return mapper.ChatHistorySessionWithMessagesResponseMapper(sessionEntity, messages), nil
}
func (_i *chatHistoryService) CreateSession(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Set user ID from auth token
req.UserID = userInfo.ID
entity := req.ToEntity()
result, err := _i.Repo.CreateSession(entity)
if err != nil {
return nil, err
}
return mapper.ChatHistorySessionsResponseMapper(result), nil
}
func (_i *chatHistoryService) UpdateSession(authToken string, sessionID string, req request.ChatHistorySessionsUpdateRequest) (err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
_i.Log.Info().Interface("data", req).Msg("Updating chat history session")
// Check if session exists and belongs to user
existing, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID)
if err != nil {
return err
}
if existing == nil {
return errors.New("chat history session not found")
}
entity := req.ToEntity()
return _i.Repo.UpdateSession(sessionID, entity)
}
func (_i *chatHistoryService) DeleteSession(authToken string, sessionID string) error {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
_i.Log.Info().Uint("userId", userInfo.ID).Str("sessionId", sessionID).Msg("Deleting chat history session")
// Check if session exists and belongs to user
existing, err := _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID)
if err != nil {
return err
}
if existing == nil {
return errors.New("chat history session not found")
}
return _i.Repo.DeleteSession(sessionID)
}
// Messages methods
func (_i *chatHistoryService) GetSessionMessages(authToken string, sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*response.ChatHistoryMessagesResponse, paging paginator.Pagination, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Verify session belongs to user
_, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, sessionID)
if err != nil {
return nil, paginator.Pagination{}, err
}
results, paging, err := _i.Repo.GetSessionMessages(sessionID, req)
if err != nil {
return
}
for _, result := range results {
messages = append(messages, mapper.ChatHistoryMessagesResponseMapper(result))
}
return
}
func (_i *chatHistoryService) CreateMessage(authToken string, req request.ChatHistoryMessagesCreateRequest) (message *response.ChatHistoryMessagesResponse, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
_i.Log.Info().Interface("data", req).Msg("Creating chat history message")
// Verify session belongs to user
_, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, req.SessionID)
if err != nil {
return nil, err
}
entity := req.ToEntity()
result, err := _i.Repo.CreateMessage(entity)
if err != nil {
return nil, err
}
// Increment message count in session
err = _i.Repo.IncrementMessageCount(req.SessionID)
if err != nil {
_i.Log.Error().Err(err).Msg("Failed to increment message count")
}
return mapper.ChatHistoryMessagesResponseMapper(result), nil
}
func (_i *chatHistoryService) UpdateMessage(authToken string, messageID uint, req request.ChatHistoryMessagesUpdateRequest) (err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Get message to verify it belongs to user's session
messages, _, err := _i.Repo.GetSessionMessages("", request.ChatHistoryMessagesQueryRequest{})
if err != nil {
return err
}
// Find the specific message
var targetMessage *entity.ChatMessagesNew
for _, msg := range messages {
if msg.ID == messageID {
targetMessage = msg
break
}
}
if targetMessage == nil {
return errors.New("message not found")
}
// Verify session belongs to user
_, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, targetMessage.SessionID)
if err != nil {
return err
}
entity := req.ToEntity()
return _i.Repo.UpdateMessage(messageID, entity)
}
func (_i *chatHistoryService) DeleteMessage(authToken string, messageID uint) error {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
// Get message to verify it belongs to user's session
messages, _, err := _i.Repo.GetSessionMessages("", request.ChatHistoryMessagesQueryRequest{})
if err != nil {
return err
}
// Find the specific message
var targetMessage *entity.ChatMessagesNew
for _, msg := range messages {
if msg.ID == messageID {
targetMessage = msg
break
}
}
if targetMessage == nil {
return errors.New("message not found")
}
// Verify session belongs to user
_, err = _i.Repo.FindSessionByUserAndSessionID(userInfo.ID, targetMessage.SessionID)
if err != nil {
return err
}
return _i.Repo.DeleteMessage(messageID)
}
// Combined operations
func (_i *chatHistoryService) SaveChatHistory(authToken string, req request.ChatHistorySessionsCreateRequest) (session *response.ChatHistorySessionsResponse, err error) {
userInfo := utilSvc.GetUserInfo(_i.Log, _i.UsersRepo, authToken)
_i.Log.Info().Interface("data", req).Msg("Saving chat history")
// Set user ID from auth token
req.UserID = userInfo.ID
// Check if session already exists
existingSession, err := _i.Repo.FindSessionBySessionID(req.SessionID)
if err == nil && existingSession != nil {
// Update existing session
updateReq := request.ChatHistorySessionsUpdateRequest{
Title: req.Title,
}
err = _i.UpdateSession(authToken, req.SessionID, updateReq)
if err != nil {
return nil, err
}
// Delete existing messages
err = _i.Repo.DeleteMessagesBySessionID(req.SessionID)
if err != nil {
_i.Log.Error().Err(err).Msg("Failed to delete existing messages")
}
} else {
// Create new session
entity := req.ToEntity()
_, err = _i.Repo.CreateSession(entity)
if err != nil {
return nil, err
}
}
// Save messages if provided
if len(req.Messages) > 0 {
for _, msgReq := range req.Messages {
messageEntity := &entity.ChatMessagesNew{
SessionID: req.SessionID,
MessageType: msgReq.Type,
Content: msgReq.Content,
}
_, err = _i.Repo.CreateMessage(messageEntity)
if err != nil {
_i.Log.Error().Err(err).Msg("Failed to create message")
}
}
// Update message count
err = _i.Repo.UpdateSession(req.SessionID, &entity.ChatSessions{
MessageCount: len(req.Messages),
})
if err != nil {
_i.Log.Error().Err(err).Msg("Failed to update message count")
}
}
// Return the session
result, err := _i.Repo.FindSessionBySessionID(req.SessionID)
if err != nil {
return nil, err
}
return mapper.ChatHistorySessionsResponseMapper(result), nil
}