diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index fee9d6c..43a9166 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -30,4 +30,4 @@ deploy: services: - docker:dind script: - - curl --user $JENKINS_USER:$JENKINS_PWD http://38.47.180.165:8080/job/autodeploy-medols-be/build?token=autodeploymedols \ No newline at end of file + - curl --user $JENKINS_USER:$JENKINS_PWD http://38.47.180.165:8080/job/autodeploy-narasiahli-be/build?token=autodeploynarasiahli \ No newline at end of file diff --git a/CHAT_HISTORY_IMPLEMENTATION.md b/CHAT_HISTORY_IMPLEMENTATION.md new file mode 100644 index 0000000..ce1ad15 --- /dev/null +++ b/CHAT_HISTORY_IMPLEMENTATION.md @@ -0,0 +1,206 @@ +# Chat History Implementation + +This document describes the implementation of the chat history functionality based on the old web API code from the `plan/old` folder. + +## Overview + +The implementation includes: +1. **New Chat History Module**: A complete module for managing chat sessions and messages +2. **Updated AI Chat Module**: Enhanced with proper routing +3. **Database Entities**: New entities for chat sessions and messages +4. **API Endpoints**: RESTful endpoints for all chat history operations + +## New Files Created + +### Database Entities +- `app/database/entity/chat_sessions.entity.go` - Chat sessions entity +- `app/database/entity/chat_messages_new.entity.go` - Chat messages entity (renamed to avoid conflicts) + +### Chat History Module +- `app/module/chat_history/chat_history.module.go` - Module definition +- `app/module/chat_history/chat_history.router.go` - Router configuration +- `app/module/chat_history/request/chat_history.request.go` - Request DTOs +- `app/module/chat_history/response/chat_history.response.go` - Response DTOs +- `app/module/chat_history/mapper/chat_history.mapper.go` - Entity to response mappers +- `app/module/chat_history/repository/chat_history.repository.go` - Data access layer +- `app/module/chat_history/service/chat_history.service.go` - Business logic layer +- `app/module/chat_history/controller/chat_history.controller.go` - API controller + +### AI Chat Module Updates +- `app/module/ai_chat/ai_chat.router.go` - Router configuration for AI chat + +### Database Migration +- `migrations/001_create_chat_history_tables.sql` - SQL migration script +- `migrations/001_create_chat_history_tables.go` - Go migration script +- `scripts/migrate.go` - Migration runner script + +## API Endpoints + +### Chat History Endpoints + +#### Sessions +- `GET /chat-history/sessions` - Get user's chat sessions +- `GET /chat-history/sessions/{sessionId}` - Get specific session with messages +- `POST /chat-history/sessions` - Create new session +- `PUT /chat-history/sessions/{sessionId}` - Update session +- `DELETE /chat-history/sessions/{sessionId}` - Delete session + +#### Messages +- `GET /chat-history/sessions/{sessionId}/messages` - Get session messages +- `POST /chat-history/sessions/{sessionId}/messages` - Create message +- `PUT /chat-history/messages/{messageId}` - Update message +- `DELETE /chat-history/messages/{messageId}` - Delete message + +#### Combined Operations +- `POST /chat-history/save` - Save complete chat history (sessions + messages) + +### AI Chat Endpoints (Updated) +- `GET /ai-chat/sessions` - Get user's AI chat sessions +- `GET /ai-chat/sessions/{id}` - Get specific AI chat session +- `POST /ai-chat/sessions` - Create AI chat session +- `PUT /ai-chat/sessions/{id}` - Update AI chat session +- `DELETE /ai-chat/sessions/{id}` - Delete AI chat session +- `GET /ai-chat/sessions/{sessionId}/messages` - Get AI chat messages +- `POST /ai-chat/sessions/{sessionId}/messages` - Send AI chat message +- `PUT /ai-chat/sessions/{sessionId}/messages/{messageId}` - Update AI chat message +- `DELETE /ai-chat/sessions/{sessionId}/messages/{messageId}` - Delete AI chat message +- `GET /ai-chat/logs` - Get user's AI chat logs +- `GET /ai-chat/logs/{id}` - Get specific AI chat log + +## Database Schema + +### chat_sessions Table +```sql +CREATE TABLE chat_sessions ( + id SERIAL PRIMARY KEY, + session_id VARCHAR(255) NOT NULL UNIQUE, + user_id INTEGER NOT NULL, + agent_id VARCHAR(255) NOT NULL, + title VARCHAR(255) NOT NULL DEFAULT 'Chat Session', + message_count INTEGER DEFAULT 0, + status VARCHAR(50) DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +### chat_messages_new Table +```sql +CREATE TABLE chat_messages_new ( + id SERIAL PRIMARY KEY, + session_id VARCHAR(255) NOT NULL, + message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('user', 'assistant')), + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +## Key Features Implemented + +### 1. Session Management +- Create, read, update, delete chat sessions +- Session-based architecture with unique session IDs +- User ownership validation +- Message count tracking + +### 2. Message Management +- Create, read, update, delete messages within sessions +- Support for user and assistant message types +- Automatic message count updates +- Cascade deletion when sessions are deleted + +### 3. Combined Operations +- Save complete chat history in one operation +- Update existing sessions or create new ones +- Bulk message operations + +### 4. Security +- User authentication required for all operations +- User ownership validation for all resources +- Proper error handling and validation + +## Migration Instructions + +### 1. Run Database Migration +```bash +# Option 1: Run the Go migration script +go run scripts/migrate.go + +# Option 2: Run SQL migration manually +psql -d your_database -f migrations/001_create_chat_history_tables.sql +``` + +### 2. Update Application +The application has been updated to include: +- New modules in `main.go` +- Updated router configuration +- New API endpoints + +### 3. Test the Implementation +```bash +# Start the application +go run main.go + +# Test endpoints +curl -X GET "http://localhost:8080/chat-history/sessions" \ + -H "Authorization: Bearer YOUR_TOKEN" + +curl -X POST "http://localhost:8080/chat-history/save" \ + -H "Authorization: Bearer YOUR_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{ + "user_id": 1, + "agent_id": "agent-123", + "session_id": "session-456", + "title": "Test Chat", + "messages": [ + {"type": "user", "content": "Hello"}, + {"type": "assistant", "content": "Hi there!"} + ] + }' +``` + +## Differences from Old Code + +### Architecture Changes +- **Language**: Converted from TypeScript/JavaScript to Go +- **Framework**: Converted from Next.js API routes to Fiber (Go web framework) +- **Database**: Converted from SQLite to PostgreSQL (via GORM) +- **Structure**: Implemented clean architecture with repository, service, and controller layers + +### API Changes +- **Authentication**: Added Bearer token authentication +- **Validation**: Added comprehensive request validation +- **Error Handling**: Standardized error responses +- **Pagination**: Added pagination support for list endpoints + +### Database Changes +- **Schema**: Adapted SQLite schema to PostgreSQL +- **Relationships**: Added proper foreign key relationships +- **Indexes**: Added performance indexes +- **Constraints**: Added data validation constraints + +## Future Enhancements + +1. **Real-time Features**: Add WebSocket support for real-time chat +2. **File Attachments**: Support for file uploads in messages +3. **Message Search**: Full-text search across messages +4. **Analytics**: Chat analytics and reporting +5. **Export**: Export chat history to various formats +6. **Archiving**: Automatic archiving of old sessions + +## Troubleshooting + +### Common Issues + +1. **Migration Errors**: Ensure database connection is properly configured +2. **Authentication Errors**: Verify Bearer token is valid and user exists +3. **Validation Errors**: Check request payload matches expected schema +4. **Permission Errors**: Ensure user owns the resource being accessed + +### Debug Mode +Enable debug logging by setting the log level to debug in your configuration. + +## Support + +For issues or questions regarding this implementation, please refer to the application logs or contact the development team. diff --git a/app/database/entity/chat_messages_new.entity.go b/app/database/entity/chat_messages_new.entity.go new file mode 100644 index 0000000..06b9afe --- /dev/null +++ b/app/database/entity/chat_messages_new.entity.go @@ -0,0 +1,14 @@ +package entity + +import ( + "time" +) + +type ChatMessagesNew struct { + ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"` + SessionID string `json:"session_id" gorm:"type:varchar;not null;index"` + MessageType string `json:"message_type" gorm:"type:varchar;not null;check:message_type IN ('user', 'assistant')"` + Content string `json:"content" gorm:"type:text;not null"` + CreatedAt time.Time `json:"created_at" gorm:"default:now()"` + Session *ChatSessions `json:"session" gorm:"foreignKey:SessionID;references:SessionID"` +} diff --git a/app/database/entity/chat_sessions.entity.go b/app/database/entity/chat_sessions.entity.go new file mode 100644 index 0000000..2c29b5f --- /dev/null +++ b/app/database/entity/chat_sessions.entity.go @@ -0,0 +1,20 @@ +package entity + +import ( + "narasi-ahli-be/app/database/entity/users" + "time" +) + +type ChatSessions struct { + ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"` + SessionID string `json:"session_id" gorm:"type:varchar;not null;unique;index"` + UserID uint `json:"user_id" gorm:"type:int4;not null;index"` + AgentID string `json:"agent_id" gorm:"type:varchar;not null"` + Title string `json:"title" gorm:"type:varchar;not null"` + MessageCount int `json:"message_count" gorm:"type:int4;default:0"` + Status string `json:"status" gorm:"type:varchar;default:'active'"` + CreatedAt time.Time `json:"created_at" gorm:"default:now()"` + UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"` + User *users.Users `json:"user" gorm:"foreignKey:UserID;references:ID"` + Messages []ChatMessages `json:"messages" gorm:"foreignKey:SessionID;references:SessionID"` +} diff --git a/app/module/ai_chat/ai_chat.module.go b/app/module/ai_chat/ai_chat.module.go index 49ed067..8e5e70f 100644 --- a/app/module/ai_chat/ai_chat.module.go +++ b/app/module/ai_chat/ai_chat.module.go @@ -4,24 +4,62 @@ import ( "narasi-ahli-be/app/module/ai_chat/controller" "narasi-ahli-be/app/module/ai_chat/repository" "narasi-ahli-be/app/module/ai_chat/service" - usersRepository "narasi-ahli-be/app/module/users/repository" - "github.com/rs/zerolog" + "github.com/gofiber/fiber/v2" "go.uber.org/fx" ) -var Module = fx.Options( - fx.Provide( - repository.NewAIChatRepository, - service.NewAIChatService, - controller.NewAIChatController, - ), - fx.Invoke(func( - aiChatController controller.AIChatController, - usersRepo usersRepository.UsersRepository, - log zerolog.Logger, - ) { - log.Info().Msg("AI Chat module initialized successfully") - }), +// struct of AIChatRouter +type AIChatRouter struct { + App fiber.Router + Controller controller.AIChatController +} + +// register bulky of AI Chat module +var NewAIChatModule = fx.Options( + // register repository of AI Chat module + fx.Provide(repository.NewAIChatRepository), + + // register service of AI Chat module + fx.Provide(service.NewAIChatService), + + // register controller of AI Chat module + fx.Provide(controller.NewAIChatController), + + // register router of AI Chat module + fx.Provide(NewAIChatRouter), ) +// init AIChatRouter +func NewAIChatRouter(fiber *fiber.App, controller controller.AIChatController) *AIChatRouter { + return &AIChatRouter{ + App: fiber, + Controller: controller, + } +} + +// register routes of AI Chat module +func (_i *AIChatRouter) RegisterAIChatRoutes() { + // define controllers + aiChatController := _i.Controller + + // define routes + _i.App.Route("/ai-chat", func(router fiber.Router) { + // Sessions routes + router.Get("/sessions", aiChatController.GetUserSessions) + router.Get("/sessions/:id", aiChatController.GetSession) + router.Post("/sessions", aiChatController.CreateSession) + router.Put("/sessions/:id", aiChatController.UpdateSession) + router.Delete("/sessions/:id", aiChatController.DeleteSession) + + // Messages routes + router.Get("/sessions/:sessionId/messages", aiChatController.GetSessionMessages) + router.Post("/sessions/:sessionId/messages", aiChatController.SendMessage) + router.Put("/sessions/:sessionId/messages/:messageId", aiChatController.UpdateMessage) + router.Delete("/sessions/:sessionId/messages/:messageId", aiChatController.DeleteMessage) + + // Logs routes + router.Get("/logs", aiChatController.GetUserLogs) + router.Get("/logs/:id", aiChatController.GetLog) + }) +} diff --git a/app/module/chat_history/chat_history.module.go b/app/module/chat_history/chat_history.module.go new file mode 100644 index 0000000..a6cd25d --- /dev/null +++ b/app/module/chat_history/chat_history.module.go @@ -0,0 +1,64 @@ +package chat_history + +import ( + "narasi-ahli-be/app/module/chat_history/controller" + "narasi-ahli-be/app/module/chat_history/repository" + "narasi-ahli-be/app/module/chat_history/service" + + "github.com/gofiber/fiber/v2" + "go.uber.org/fx" +) + +// struct of ChatHistoryRouter +type ChatHistoryRouter struct { + App fiber.Router + Controller controller.ChatHistoryController +} + +// register bulky of Chat History module +var NewChatHistoryModule = fx.Options( + // register repository of Chat History module + fx.Provide(repository.NewChatHistoryRepository), + + // register service of Chat History module + fx.Provide(service.NewChatHistoryService), + + // register controller of Chat History module + fx.Provide(controller.NewChatHistoryController), + + // register router of Chat History module + fx.Provide(NewChatHistoryRouter), +) + +// init ChatHistoryRouter +func NewChatHistoryRouter(fiber *fiber.App, controller controller.ChatHistoryController) *ChatHistoryRouter { + return &ChatHistoryRouter{ + App: fiber, + Controller: controller, + } +} + +// register routes of Chat History module +func (_i *ChatHistoryRouter) RegisterChatHistoryRoutes() { + // define controllers + chatHistoryController := _i.Controller + + // define routes + _i.App.Route("/chat-history", func(router fiber.Router) { + // Sessions routes + router.Get("/sessions", chatHistoryController.GetUserSessions) + router.Get("/sessions/:sessionId", chatHistoryController.GetSession) + router.Post("/sessions", chatHistoryController.CreateSession) + router.Put("/sessions/:sessionId", chatHistoryController.UpdateSession) + router.Delete("/sessions/:sessionId", chatHistoryController.DeleteSession) + + // Messages routes + router.Get("/sessions/:sessionId/messages", chatHistoryController.GetSessionMessages) + router.Post("/sessions/:sessionId/messages", chatHistoryController.CreateMessage) + router.Put("/messages/:messageId", chatHistoryController.UpdateMessage) + router.Delete("/messages/:messageId", chatHistoryController.DeleteMessage) + + // Combined operations + router.Post("/save", chatHistoryController.SaveChatHistory) + }) +} diff --git a/app/module/chat_history/controller/chat_history.controller.go b/app/module/chat_history/controller/chat_history.controller.go new file mode 100644 index 0000000..1c0f7c5 --- /dev/null +++ b/app/module/chat_history/controller/chat_history.controller.go @@ -0,0 +1,424 @@ +package controller + +import ( + "narasi-ahli-be/app/module/chat_history/request" + "narasi-ahli-be/app/module/chat_history/service" + "narasi-ahli-be/utils/paginator" + utilRes "narasi-ahli-be/utils/response" + utilVal "narasi-ahli-be/utils/validator" + "strconv" + + "github.com/gofiber/fiber/v2" + "github.com/rs/zerolog" +) + +type chatHistoryController struct { + chatHistoryService service.ChatHistoryService + Log zerolog.Logger +} + +type ChatHistoryController interface { + // Chat History Sessions + GetUserSessions(c *fiber.Ctx) error + GetSession(c *fiber.Ctx) error + CreateSession(c *fiber.Ctx) error + UpdateSession(c *fiber.Ctx) error + DeleteSession(c *fiber.Ctx) error + + // Chat History Messages + GetSessionMessages(c *fiber.Ctx) error + CreateMessage(c *fiber.Ctx) error + UpdateMessage(c *fiber.Ctx) error + DeleteMessage(c *fiber.Ctx) error + + // Combined operations + SaveChatHistory(c *fiber.Ctx) error +} + +func NewChatHistoryController(chatHistoryService service.ChatHistoryService, log zerolog.Logger) ChatHistoryController { + return &chatHistoryController{ + chatHistoryService: chatHistoryService, + Log: log, + } +} + +// Get User Sessions +// @Summary Get user chat history sessions +// @Description API for getting all chat history sessions for authenticated user +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param req query request.ChatHistorySessionsQueryRequest false "query parameters" +// @Param req query paginator.Pagination false "pagination parameters" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions [get] +func (_i *chatHistoryController) GetUserSessions(c *fiber.Ctx) error { + paginate, err := paginator.Paginate(c) + if err != nil { + return err + } + + authHeader := c.Get("Authorization") + + reqContext := request.ChatHistorySessionsQueryRequestContext{ + AgentID: c.Query("agent_id"), + SessionID: c.Query("session_id"), + } + req := reqContext.ToParamRequest() + req.Pagination = paginate + + sessionsData, paging, err := _i.chatHistoryService.GetUserSessions(authHeader, req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history sessions successfully retrieved"}, + Data: sessionsData, + Meta: paging, + }) +} + +// Get Session +// @Summary Get one chat history session with messages +// @Description API for getting one chat history session with all its messages +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param sessionId path string true "Session ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions/{sessionId} [get] +func (_i *chatHistoryController) GetSession(c *fiber.Ctx) error { + sessionID := c.Params("sessionId") + if sessionID == "" { + return utilRes.Resp(c, utilRes.Response{ + Success: false, + Messages: utilRes.Messages{"Session ID is required"}, + }) + } + + authHeader := c.Get("Authorization") + + sessionData, err := _i.chatHistoryService.GetSession(authHeader, sessionID) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history session successfully retrieved"}, + Data: sessionData, + }) +} + +// Create Session +// @Summary Create chat history session +// @Description API for create chat history session +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param Authorization header string false "Insert your access token" default(Bearer ) +// @Param payload body request.ChatHistorySessionsCreateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions [post] +func (_i *chatHistoryController) CreateSession(c *fiber.Ctx) error { + req := new(request.ChatHistorySessionsCreateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + authHeader := c.Get("Authorization") + + dataResult, err := _i.chatHistoryService.CreateSession(authHeader, *req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history session successfully created"}, + Data: dataResult, + }) +} + +// Update Session +// @Summary Update chat history session +// @Description API for update chat history session +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param sessionId path string true "Session ID" +// @Param payload body request.ChatHistorySessionsUpdateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions/{sessionId} [put] +func (_i *chatHistoryController) UpdateSession(c *fiber.Ctx) error { + sessionID := c.Params("sessionId") + if sessionID == "" { + return utilRes.Resp(c, utilRes.Response{ + Success: false, + Messages: utilRes.Messages{"Session ID is required"}, + }) + } + + req := new(request.ChatHistorySessionsUpdateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + authHeader := c.Get("Authorization") + + err := _i.chatHistoryService.UpdateSession(authHeader, sessionID, *req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history session successfully updated"}, + }) +} + +// Delete Session +// @Summary Delete chat history session +// @Description API for delete chat history session +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param sessionId path string true "Session ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions/{sessionId} [delete] +func (_i *chatHistoryController) DeleteSession(c *fiber.Ctx) error { + sessionID := c.Params("sessionId") + if sessionID == "" { + return utilRes.Resp(c, utilRes.Response{ + Success: false, + Messages: utilRes.Messages{"Session ID is required"}, + }) + } + + authHeader := c.Get("Authorization") + + err := _i.chatHistoryService.DeleteSession(authHeader, sessionID) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history session successfully deleted"}, + }) +} + +// Get Session Messages +// @Summary Get chat history session messages +// @Description API for getting all messages in a chat history session +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param sessionId path string true "Session ID" +// @Param req query request.ChatHistoryMessagesQueryRequest false "query parameters" +// @Param req query paginator.Pagination false "pagination parameters" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions/{sessionId}/messages [get] +func (_i *chatHistoryController) GetSessionMessages(c *fiber.Ctx) error { + sessionID := c.Params("sessionId") + if sessionID == "" { + return utilRes.Resp(c, utilRes.Response{ + Success: false, + Messages: utilRes.Messages{"Session ID is required"}, + }) + } + + paginate, err := paginator.Paginate(c) + if err != nil { + return err + } + + authHeader := c.Get("Authorization") + + req := request.ChatHistoryMessagesQueryRequest{ + SessionID: sessionID, + Pagination: paginate, + } + + messagesData, paging, err := _i.chatHistoryService.GetSessionMessages(authHeader, sessionID, req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history messages successfully retrieved"}, + Data: messagesData, + Meta: paging, + }) +} + +// Create Message +// @Summary Create chat history message +// @Description API for creating a message in a chat history session +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param sessionId path string true "Session ID" +// @Param payload body request.ChatHistoryMessagesCreateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/sessions/{sessionId}/messages [post] +func (_i *chatHistoryController) CreateMessage(c *fiber.Ctx) error { + sessionID := c.Params("sessionId") + if sessionID == "" { + return utilRes.Resp(c, utilRes.Response{ + Success: false, + Messages: utilRes.Messages{"Session ID is required"}, + }) + } + + req := new(request.ChatHistoryMessagesCreateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + // Set session ID from URL parameter + req.SessionID = sessionID + + authHeader := c.Get("Authorization") + + dataResult, err := _i.chatHistoryService.CreateMessage(authHeader, *req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history message successfully created"}, + Data: dataResult, + }) +} + +// Update Message +// @Summary Update chat history message +// @Description API for update chat history message +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param messageId path int true "Message ID" +// @Param payload body request.ChatHistoryMessagesUpdateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/messages/{messageId} [put] +func (_i *chatHistoryController) UpdateMessage(c *fiber.Ctx) error { + messageId, err := strconv.ParseUint(c.Params("messageId"), 10, 0) + if err != nil { + return err + } + + req := new(request.ChatHistoryMessagesUpdateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + authHeader := c.Get("Authorization") + + if err := _i.chatHistoryService.UpdateMessage(authHeader, uint(messageId), *req); err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history message successfully updated"}, + }) +} + +// Delete Message +// @Summary Delete chat history message +// @Description API for delete chat history message +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param messageId path int true "Message ID" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/messages/{messageId} [delete] +func (_i *chatHistoryController) DeleteMessage(c *fiber.Ctx) error { + messageId, err := strconv.ParseUint(c.Params("messageId"), 10, 0) + if err != nil { + return err + } + + authHeader := c.Get("Authorization") + + if err := _i.chatHistoryService.DeleteMessage(authHeader, uint(messageId)); err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history message successfully deleted"}, + }) +} + +// Save Chat History +// @Summary Save chat history (sessions and messages) +// @Description API for saving complete chat history including sessions and messages +// @Tags Chat History +// @Security Bearer +// @Param X-Client-Key header string false "Insert the X-Client-Key" +// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token" +// @Param Authorization header string false "Insert your access token" default(Bearer ) +// @Param payload body request.ChatHistorySessionsCreateRequest true "Required payload" +// @Success 200 {object} response.Response +// @Failure 400 {object} response.BadRequestError +// @Failure 401 {object} response.UnauthorizedError +// @Failure 500 {object} response.InternalServerError +// @Router /chat-history/save [post] +func (_i *chatHistoryController) SaveChatHistory(c *fiber.Ctx) error { + req := new(request.ChatHistorySessionsCreateRequest) + if err := utilVal.ParseAndValidate(c, req); err != nil { + return err + } + + authHeader := c.Get("Authorization") + + dataResult, err := _i.chatHistoryService.SaveChatHistory(authHeader, *req) + if err != nil { + return err + } + + return utilRes.Resp(c, utilRes.Response{ + Success: true, + Messages: utilRes.Messages{"Chat history saved successfully"}, + Data: dataResult, + }) +} diff --git a/app/module/chat_history/mapper/chat_history.mapper.go b/app/module/chat_history/mapper/chat_history.mapper.go new file mode 100644 index 0000000..cd58606 --- /dev/null +++ b/app/module/chat_history/mapper/chat_history.mapper.go @@ -0,0 +1,77 @@ +package mapper + +import ( + "narasi-ahli-be/app/database/entity" + "narasi-ahli-be/app/module/chat_history/response" +) + +// Chat History Sessions Mapper +func ChatHistorySessionsResponseMapper(entity *entity.ChatSessions) *response.ChatHistorySessionsResponse { + if entity == nil { + return nil + } + + return &response.ChatHistorySessionsResponse{ + ID: entity.ID, + SessionID: entity.SessionID, + UserID: entity.UserID, + AgentID: entity.AgentID, + Title: entity.Title, + MessageCount: entity.MessageCount, + Status: entity.Status, + CreatedAt: entity.CreatedAt, + UpdatedAt: entity.UpdatedAt, + } +} + +// Chat History Messages Mapper +func ChatHistoryMessagesResponseMapper(entity *entity.ChatMessagesNew) *response.ChatHistoryMessagesResponse { + if entity == nil { + return nil + } + + return &response.ChatHistoryMessagesResponse{ + ID: entity.ID, + SessionID: entity.SessionID, + MessageType: entity.MessageType, + Content: entity.Content, + CreatedAt: entity.CreatedAt, + } +} + +// Chat History Session with Messages Mapper +func ChatHistorySessionWithMessagesResponseMapper(session *entity.ChatSessions, messages []*entity.ChatMessagesNew) *response.ChatHistorySessionWithMessagesResponse { + if session == nil { + return nil + } + + sessionResponse := ChatHistorySessionsResponseMapper(session) + + var messagesResponse []response.ChatHistoryMessagesResponse + for _, message := range messages { + if message != nil { + messagesResponse = append(messagesResponse, *ChatHistoryMessagesResponseMapper(message)) + } + } + + return &response.ChatHistorySessionWithMessagesResponse{ + Session: *sessionResponse, + Messages: messagesResponse, + } +} + +// Chat History List Mapper +func ChatHistoryListResponseMapper(sessions []*entity.ChatSessions) *response.ChatHistoryListResponse { + var sessionsResponse []response.ChatHistorySessionsResponse + + for _, session := range sessions { + if session != nil { + sessionsResponse = append(sessionsResponse, *ChatHistorySessionsResponseMapper(session)) + } + } + + return &response.ChatHistoryListResponse{ + Sessions: sessionsResponse, + Total: len(sessionsResponse), + } +} diff --git a/app/module/chat_history/repository/chat_history.repository.go b/app/module/chat_history/repository/chat_history.repository.go new file mode 100644 index 0000000..9c594ad --- /dev/null +++ b/app/module/chat_history/repository/chat_history.repository.go @@ -0,0 +1,159 @@ +package repository + +import ( + "narasi-ahli-be/app/database" + "narasi-ahli-be/app/database/entity" + "narasi-ahli-be/app/module/chat_history/request" + "narasi-ahli-be/utils/paginator" +) + +type chatHistoryRepository struct { + DB *database.Database +} + +type ChatHistoryRepository interface { + // Chat Sessions + GetUserSessions(userId uint, req request.ChatHistorySessionsQueryRequest) (sessions []*entity.ChatSessions, paging paginator.Pagination, err error) + FindSessionByID(id uint) (session *entity.ChatSessions, err error) + FindSessionBySessionID(sessionID string) (session *entity.ChatSessions, err error) + FindSessionByUserAndSessionID(userID uint, sessionID string) (session *entity.ChatSessions, err error) + CreateSession(session *entity.ChatSessions) (result *entity.ChatSessions, err error) + UpdateSession(sessionID string, session *entity.ChatSessions) (err error) + DeleteSession(sessionID string) (err error) + IncrementMessageCount(sessionID string) (err error) + + // Chat Messages + GetSessionMessages(sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*entity.ChatMessagesNew, paging paginator.Pagination, err error) + CreateMessage(message *entity.ChatMessagesNew) (result *entity.ChatMessagesNew, err error) + UpdateMessage(messageID uint, message *entity.ChatMessagesNew) (err error) + DeleteMessage(messageID uint) (err error) + DeleteMessagesBySessionID(sessionID string) (err error) + GetLastMessage(sessionID string) (message *entity.ChatMessagesNew, err error) +} + +func NewChatHistoryRepository(db *database.Database) ChatHistoryRepository { + return &chatHistoryRepository{ + DB: db, + } +} + +// Chat Sessions methods +func (_i *chatHistoryRepository) GetUserSessions(userId uint, req request.ChatHistorySessionsQueryRequest) (sessions []*entity.ChatSessions, paging paginator.Pagination, err error) { + query := _i.DB.DB.Where("user_id = ?", userId) + + // Apply filters + if req.AgentID != nil { + query = query.Where("agent_id = ?", *req.AgentID) + } + if req.SessionID != nil { + query = query.Where("session_id = ?", *req.SessionID) + } + + // Include user relationship + query = query.Preload("User") + + // Order by updated_at desc (most recent first) + query = query.Order("updated_at DESC") + + // Apply pagination + var count int64 + query.Count(&count) + req.Pagination.Count = count + req.Pagination = paginator.Paging(req.Pagination) + + err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&sessions).Error + paging = *req.Pagination + + return +} + +func (_i *chatHistoryRepository) FindSessionByID(id uint) (session *entity.ChatSessions, err error) { + err = _i.DB.DB.Where("id = ?", id).Preload("User").First(&session).Error + return +} + +func (_i *chatHistoryRepository) FindSessionBySessionID(sessionID string) (session *entity.ChatSessions, err error) { + err = _i.DB.DB.Where("session_id = ?", sessionID).Preload("User").First(&session).Error + return +} + +func (_i *chatHistoryRepository) FindSessionByUserAndSessionID(userID uint, sessionID string) (session *entity.ChatSessions, err error) { + err = _i.DB.DB.Where("user_id = ? AND session_id = ?", userID, sessionID).Preload("User").First(&session).Error + return +} + +func (_i *chatHistoryRepository) CreateSession(session *entity.ChatSessions) (result *entity.ChatSessions, err error) { + err = _i.DB.DB.Create(session).Error + if err != nil { + return nil, err + } + + // Reload with relationships + err = _i.DB.DB.Preload("User").First(&result, session.ID).Error + return +} + +func (_i *chatHistoryRepository) UpdateSession(sessionID string, session *entity.ChatSessions) (err error) { + err = _i.DB.DB.Where("session_id = ?", sessionID).Updates(session).Error + return +} + +func (_i *chatHistoryRepository) DeleteSession(sessionID string) (err error) { + err = _i.DB.DB.Where("session_id = ?", sessionID).Delete(&entity.ChatSessions{}).Error + return +} + +func (_i *chatHistoryRepository) IncrementMessageCount(sessionID string) (err error) { + err = _i.DB.DB.Exec("UPDATE chat_sessions SET message_count = message_count + 1 WHERE session_id = ?", sessionID).Error + return +} + +// Chat Messages methods +func (_i *chatHistoryRepository) GetSessionMessages(sessionID string, req request.ChatHistoryMessagesQueryRequest) (messages []*entity.ChatMessagesNew, paging paginator.Pagination, err error) { + query := _i.DB.DB.Where("session_id = ?", sessionID) + + // Order by created_at asc (oldest first for chat) + query = query.Order("created_at ASC") + + // Apply pagination + var count int64 + query.Count(&count) + req.Pagination.Count = count + req.Pagination = paginator.Paging(req.Pagination) + + err = query.Offset(req.Pagination.Offset).Limit(req.Pagination.Limit).Find(&messages).Error + paging = *req.Pagination + + return +} + +func (_i *chatHistoryRepository) CreateMessage(message *entity.ChatMessagesNew) (result *entity.ChatMessagesNew, err error) { + err = _i.DB.DB.Create(message).Error + if err != nil { + return nil, err + } + + // Reload + err = _i.DB.DB.First(&result, message.ID).Error + return +} + +func (_i *chatHistoryRepository) UpdateMessage(messageID uint, message *entity.ChatMessagesNew) (err error) { + err = _i.DB.DB.Model(&entity.ChatMessagesNew{}).Where("id = ?", messageID).Updates(message).Error + return +} + +func (_i *chatHistoryRepository) DeleteMessage(messageID uint) (err error) { + err = _i.DB.DB.Where("id = ?", messageID).Delete(&entity.ChatMessagesNew{}).Error + return +} + +func (_i *chatHistoryRepository) DeleteMessagesBySessionID(sessionID string) (err error) { + err = _i.DB.DB.Where("session_id = ?", sessionID).Delete(&entity.ChatMessagesNew{}).Error + return +} + +func (_i *chatHistoryRepository) GetLastMessage(sessionID string) (message *entity.ChatMessagesNew, err error) { + err = _i.DB.DB.Where("session_id = ?", sessionID).Order("created_at DESC").First(&message).Error + return +} diff --git a/app/module/chat_history/request/chat_history.request.go b/app/module/chat_history/request/chat_history.request.go new file mode 100644 index 0000000..f06b6d6 --- /dev/null +++ b/app/module/chat_history/request/chat_history.request.go @@ -0,0 +1,131 @@ +package request + +import ( + "narasi-ahli-be/app/database/entity" + "narasi-ahli-be/utils/paginator" +) + +// Chat History Sessions Request DTOs +type ChatHistorySessionsQueryRequest struct { + UserID *uint `json:"user_id"` + AgentID *string `json:"agent_id"` + SessionID *string `json:"session_id"` + Pagination *paginator.Pagination `json:"pagination"` +} + +type ChatHistorySessionsCreateRequest struct { + UserID uint `json:"user_id" validate:"required"` + AgentID string `json:"agent_id" validate:"required"` + SessionID string `json:"session_id" validate:"required"` + Title *string `json:"title"` + Messages []ChatMessageRequest `json:"messages"` +} + +type ChatMessageRequest struct { + Type string `json:"type" validate:"required,oneof=user assistant"` + Content string `json:"content" validate:"required"` +} + +func (req ChatHistorySessionsCreateRequest) ToEntity() *entity.ChatSessions { + title := "Chat Session" + if req.Title != nil { + title = *req.Title + } + + return &entity.ChatSessions{ + SessionID: req.SessionID, + UserID: req.UserID, + AgentID: req.AgentID, + Title: title, + MessageCount: len(req.Messages), + Status: "active", + } +} + +type ChatHistorySessionsUpdateRequest struct { + Title *string `json:"title"` + Status *string `json:"status" validate:"omitempty,oneof=active archived deleted"` +} + +func (req ChatHistorySessionsUpdateRequest) ToEntity() *entity.ChatSessions { + entity := &entity.ChatSessions{} + + if req.Title != nil { + entity.Title = *req.Title + } + if req.Status != nil { + entity.Status = *req.Status + } + + return entity +} + +// Chat History Messages Request DTOs +type ChatHistoryMessagesQueryRequest struct { + SessionID string `json:"session_id" validate:"required"` + Pagination *paginator.Pagination `json:"pagination"` +} + +type ChatHistoryMessagesCreateRequest struct { + SessionID string `json:"session_id" validate:"required"` + MessageType string `json:"message_type" validate:"required,oneof=user assistant"` + Content string `json:"content" validate:"required"` +} + +func (req ChatHistoryMessagesCreateRequest) ToEntity() *entity.ChatMessagesNew { + return &entity.ChatMessagesNew{ + SessionID: req.SessionID, + MessageType: req.MessageType, + Content: req.Content, + } +} + +type ChatHistoryMessagesUpdateRequest struct { + Content string `json:"content" validate:"required"` +} + +func (req ChatHistoryMessagesUpdateRequest) ToEntity() *entity.ChatMessagesNew { + return &entity.ChatMessagesNew{ + Content: req.Content, + } +} + +// Context Request DTOs for query parameters +type ChatHistorySessionsQueryRequestContext struct { + UserID string `json:"user_id"` + AgentID string `json:"agent_id"` + SessionID string `json:"session_id"` +} + +func (req ChatHistorySessionsQueryRequestContext) ToParamRequest() ChatHistorySessionsQueryRequest { + var request ChatHistorySessionsQueryRequest + + if userIDStr := req.UserID; userIDStr != "" { + // Parse user ID from string to uint + // This will be handled in the controller + } + + if agentID := req.AgentID; agentID != "" { + request.AgentID = &agentID + } + + if sessionID := req.SessionID; sessionID != "" { + request.SessionID = &sessionID + } + + return request +} + +type ChatHistoryMessagesQueryRequestContext struct { + SessionID string `json:"session_id"` +} + +func (req ChatHistoryMessagesQueryRequestContext) ToParamRequest() ChatHistoryMessagesQueryRequest { + var request ChatHistoryMessagesQueryRequest + + if sessionID := req.SessionID; sessionID != "" { + request.SessionID = sessionID + } + + return request +} diff --git a/app/module/chat_history/response/chat_history.response.go b/app/module/chat_history/response/chat_history.response.go new file mode 100644 index 0000000..0863b94 --- /dev/null +++ b/app/module/chat_history/response/chat_history.response.go @@ -0,0 +1,39 @@ +package response + +import ( + "time" +) + +// Chat History Sessions Response DTOs +type ChatHistorySessionsResponse struct { + ID uint `json:"id"` + SessionID string `json:"session_id"` + UserID uint `json:"user_id"` + AgentID string `json:"agent_id"` + Title string `json:"title"` + MessageCount int `json:"message_count"` + Status string `json:"status"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} + +// Chat History Messages Response DTOs +type ChatHistoryMessagesResponse struct { + ID uint `json:"id"` + SessionID string `json:"session_id"` + MessageType string `json:"message_type"` + Content string `json:"content"` + CreatedAt time.Time `json:"created_at"` +} + +// Combined Response for Session with Messages +type ChatHistorySessionWithMessagesResponse struct { + Session ChatHistorySessionsResponse `json:"session"` + Messages []ChatHistoryMessagesResponse `json:"messages"` +} + +// Chat History List Response +type ChatHistoryListResponse struct { + Sessions []ChatHistorySessionsResponse `json:"sessions"` + Total int `json:"total"` +} diff --git a/app/module/chat_history/service/chat_history.service.go b/app/module/chat_history/service/chat_history.service.go new file mode 100644 index 0000000..0caf1c8 --- /dev/null +++ b/app/module/chat_history/service/chat_history.service.go @@ -0,0 +1,317 @@ +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 +} diff --git a/app/router/api.go b/app/router/api.go index b2c4c4c..c640105 100644 --- a/app/router/api.go +++ b/app/router/api.go @@ -3,12 +3,14 @@ package router import ( "narasi-ahli-be/app/module/activity_logs" "narasi-ahli-be/app/module/advertisement" + "narasi-ahli-be/app/module/ai_chat" "narasi-ahli-be/app/module/article_approvals" "narasi-ahli-be/app/module/article_categories" "narasi-ahli-be/app/module/article_category_details" "narasi-ahli-be/app/module/article_comments" "narasi-ahli-be/app/module/article_files" "narasi-ahli-be/app/module/articles" + "narasi-ahli-be/app/module/chat_history" "narasi-ahli-be/app/module/cities" "narasi-ahli-be/app/module/custom_static_pages" "narasi-ahli-be/app/module/districts" @@ -39,12 +41,14 @@ type Router struct { ActivityLogsRouter *activity_logs.ActivityLogsRouter AdvertisementRouter *advertisement.AdvertisementRouter + AIChatRouter *ai_chat.AIChatRouter ArticleCategoriesRouter *article_categories.ArticleCategoriesRouter ArticleCategoryDetailsRouter *article_category_details.ArticleCategoryDetailsRouter ArticleFilesRouter *article_files.ArticleFilesRouter ArticleCommentsRouter *article_comments.ArticleCommentsRouter ArticleApprovalsRouter *article_approvals.ArticleApprovalsRouter ArticlesRouter *articles.ArticlesRouter + ChatHistoryRouter *chat_history.ChatHistoryRouter CitiesRouter *cities.CitiesRouter CustomStaticPagesRouter *custom_static_pages.CustomStaticPagesRouter DistrictsRouter *districts.DistrictsRouter @@ -70,12 +74,14 @@ func NewRouter( activityLogsRouter *activity_logs.ActivityLogsRouter, advertisementRouter *advertisement.AdvertisementRouter, + aiChatRouter *ai_chat.AIChatRouter, articleCategoriesRouter *article_categories.ArticleCategoriesRouter, articleCategoryDetailsRouter *article_category_details.ArticleCategoryDetailsRouter, articleFilesRouter *article_files.ArticleFilesRouter, articleCommentsRouter *article_comments.ArticleCommentsRouter, articleApprovalsRouter *article_approvals.ArticleApprovalsRouter, articlesRouter *articles.ArticlesRouter, + chatHistoryRouter *chat_history.ChatHistoryRouter, citiesRouter *cities.CitiesRouter, customStaticPagesRouter *custom_static_pages.CustomStaticPagesRouter, districtsRouter *districts.DistrictsRouter, @@ -99,12 +105,14 @@ func NewRouter( Cfg: cfg, ActivityLogsRouter: activityLogsRouter, AdvertisementRouter: advertisementRouter, + AIChatRouter: aiChatRouter, ArticleCategoriesRouter: articleCategoriesRouter, ArticleCategoryDetailsRouter: articleCategoryDetailsRouter, ArticleFilesRouter: articleFilesRouter, ArticleCommentsRouter: articleCommentsRouter, ArticleApprovalsRouter: articleApprovalsRouter, ArticlesRouter: articlesRouter, + ChatHistoryRouter: chatHistoryRouter, CitiesRouter: citiesRouter, CustomStaticPagesRouter: customStaticPagesRouter, DistrictsRouter: districtsRouter, @@ -138,12 +146,14 @@ func (r *Router) Register() { // Register routes of modules r.ActivityLogsRouter.RegisterActivityLogsRoutes() r.AdvertisementRouter.RegisterAdvertisementRoutes() + r.AIChatRouter.RegisterAIChatRoutes() r.ArticleCategoriesRouter.RegisterArticleCategoriesRoutes() r.ArticleCategoryDetailsRouter.RegisterArticleCategoryDetailsRoutes() r.ArticleFilesRouter.RegisterArticleFilesRoutes() r.ArticleApprovalsRouter.RegisterArticleApprovalsRoutes() r.ArticlesRouter.RegisterArticlesRoutes() r.ArticleCommentsRouter.RegisterArticleCommentsRoutes() + r.ChatHistoryRouter.RegisterChatHistoryRoutes() r.CitiesRouter.RegisterCitiesRoutes() r.CustomStaticPagesRouter.RegisterCustomStaticPagesRoutes() r.DistrictsRouter.RegisterDistrictsRoutes() diff --git a/docs/swagger/docs.go b/docs/swagger/docs.go index a22aed6..3a10467 100644 --- a/docs/swagger/docs.go +++ b/docs/swagger/docs.go @@ -1000,6 +1000,815 @@ const docTemplate = `{ } } }, + "/ai-chat/logs": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all AI chat logs for authenticated user", + "tags": [ + "AI Chat" + ], + "summary": "Get user AI chat logs", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "logType", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/logs/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one AI chat log", + "tags": [ + "AI Chat" + ], + "summary": "Get one AI chat log", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Log ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all AI chat sessions for authenticated user", + "tags": [ + "AI Chat" + ], + "summary": "Get user AI chat sessions", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for create AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Create AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatSessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Get one AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Update AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatSessionsUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Delete AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{sessionId}/messages": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all messages in an AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Get AI chat session messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "name": "sessionId", + "in": "query", + "required": true + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for sending a message to an AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Send message to AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatMessagesCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{sessionId}/messages/{messageId}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update AI chat message", + "tags": [ + "AI Chat" + ], + "summary": "Update AI chat message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatMessagesUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete AI chat message", + "tags": [ + "AI Chat" + ], + "summary": "Delete AI chat message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/article-approvals": { "get": { "security": [ @@ -3978,6 +4787,734 @@ const docTemplate = `{ } } }, + "/chat-history/messages/{messageId}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update chat history message", + "tags": [ + "Chat History" + ], + "summary": "Update chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistoryMessagesUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete chat history message", + "tags": [ + "Chat History" + ], + "summary": "Delete chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/save": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for saving complete chat history including sessions and messages", + "tags": [ + "Chat History" + ], + "summary": "Save chat history (sessions and messages)", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all chat history sessions for authenticated user", + "tags": [ + "Chat History" + ], + "summary": "Get user chat history sessions", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "agent_id", + "in": "query" + }, + { + "type": "string", + "name": "session_id", + "in": "query" + }, + { + "type": "integer", + "name": "user_id", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for create chat history session", + "tags": [ + "Chat History" + ], + "summary": "Create chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions/{sessionId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one chat history session with all its messages", + "tags": [ + "Chat History" + ], + "summary": "Get one chat history session with messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update chat history session", + "tags": [ + "Chat History" + ], + "summary": "Update chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete chat history session", + "tags": [ + "Chat History" + ], + "summary": "Delete chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions/{sessionId}/messages": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all messages in a chat history session", + "tags": [ + "Chat History" + ], + "summary": "Get chat history session messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "session_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for creating a message in a chat history session", + "tags": [ + "Chat History" + ], + "summary": "Create chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistoryMessagesCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/cities": { "get": { "security": [ @@ -11217,6 +12754,80 @@ const docTemplate = `{ } } }, + "request.AIChatMessagesCreateRequest": { + "type": "object", + "required": [ + "content", + "messageType", + "sessionId" + ], + "properties": { + "content": { + "type": "string", + "minLength": 1 + }, + "messageType": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "sessionId": { + "type": "integer" + } + } + }, + "request.AIChatMessagesUpdateRequest": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string", + "minLength": 1 + } + } + }, + "request.AIChatSessionsCreateRequest": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "agentId": { + "type": "string" + }, + "title": { + "type": "string", + "maxLength": 255, + "minLength": 2 + } + } + }, + "request.AIChatSessionsUpdateRequest": { + "type": "object", + "required": [ + "status", + "title" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "active", + "archived", + "deleted" + ] + }, + "title": { + "type": "string", + "maxLength": 255, + "minLength": 2 + } + } + }, "request.ActivityLogsCreateRequest": { "type": "object", "required": [ @@ -11651,6 +13262,103 @@ const docTemplate = `{ } } }, + "request.ChatHistoryMessagesCreateRequest": { + "type": "object", + "required": [ + "content", + "message_type", + "session_id" + ], + "properties": { + "content": { + "type": "string" + }, + "message_type": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "session_id": { + "type": "string" + } + } + }, + "request.ChatHistoryMessagesUpdateRequest": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string" + } + } + }, + "request.ChatHistorySessionsCreateRequest": { + "type": "object", + "required": [ + "agent_id", + "session_id", + "user_id" + ], + "properties": { + "agent_id": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/request.ChatMessageRequest" + } + }, + "session_id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "user_id": { + "type": "integer" + } + } + }, + "request.ChatHistorySessionsUpdateRequest": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "active", + "archived", + "deleted" + ] + }, + "title": { + "type": "string" + } + } + }, + "request.ChatMessageRequest": { + "type": "object", + "required": [ + "content", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + } + } + }, "request.CitiesCreateRequest": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.json b/docs/swagger/swagger.json index c8d412b..f64cd65 100644 --- a/docs/swagger/swagger.json +++ b/docs/swagger/swagger.json @@ -989,6 +989,815 @@ } } }, + "/ai-chat/logs": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all AI chat logs for authenticated user", + "tags": [ + "AI Chat" + ], + "summary": "Get user AI chat logs", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "logType", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/logs/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one AI chat log", + "tags": [ + "AI Chat" + ], + "summary": "Get one AI chat log", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Log ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all AI chat sessions for authenticated user", + "tags": [ + "AI Chat" + ], + "summary": "Get user AI chat sessions", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "status", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for create AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Create AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatSessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{id}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Get one AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Update AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatSessionsUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Delete AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "id", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{sessionId}/messages": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all messages in an AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Get AI chat session messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "name": "sessionId", + "in": "query", + "required": true + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for sending a message to an AI chat session", + "tags": [ + "AI Chat" + ], + "summary": "Send message to AI chat session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatMessagesCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/ai-chat/sessions/{sessionId}/messages/{messageId}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update AI chat message", + "tags": [ + "AI Chat" + ], + "summary": "Update AI chat message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.AIChatMessagesUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete AI chat message", + "tags": [ + "AI Chat" + ], + "summary": "Delete AI chat message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/article-approvals": { "get": { "security": [ @@ -3967,6 +4776,734 @@ } } }, + "/chat-history/messages/{messageId}": { + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update chat history message", + "tags": [ + "Chat History" + ], + "summary": "Update chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistoryMessagesUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete chat history message", + "tags": [ + "Chat History" + ], + "summary": "Delete chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "integer", + "description": "Message ID", + "name": "messageId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/save": { + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for saving complete chat history including sessions and messages", + "tags": [ + "Chat History" + ], + "summary": "Save chat history (sessions and messages)", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all chat history sessions for authenticated user", + "tags": [ + "Chat History" + ], + "summary": "Get user chat history sessions", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "name": "agent_id", + "in": "query" + }, + { + "type": "string", + "name": "session_id", + "in": "query" + }, + { + "type": "integer", + "name": "user_id", + "in": "query" + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for create chat history session", + "tags": [ + "Chat History" + ], + "summary": "Create chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "default": "Bearer \u003cAdd access token here\u003e", + "description": "Insert your access token", + "name": "Authorization", + "in": "header" + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions/{sessionId}": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting one chat history session with all its messages", + "tags": [ + "Chat History" + ], + "summary": "Get one chat history session with messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "put": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for update chat history session", + "tags": [ + "Chat History" + ], + "summary": "Update chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistorySessionsUpdateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "delete": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for delete chat history session", + "tags": [ + "Chat History" + ], + "summary": "Delete chat history session", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, + "/chat-history/sessions/{sessionId}/messages": { + "get": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for getting all messages in a chat history session", + "tags": [ + "Chat History" + ], + "summary": "Get chat history session messages", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "type": "string", + "name": "session_id", + "in": "query", + "required": true + }, + { + "type": "integer", + "name": "count", + "in": "query" + }, + { + "type": "integer", + "name": "limit", + "in": "query" + }, + { + "type": "integer", + "name": "nextPage", + "in": "query" + }, + { + "type": "integer", + "name": "page", + "in": "query" + }, + { + "type": "integer", + "name": "previousPage", + "in": "query" + }, + { + "type": "string", + "name": "sort", + "in": "query" + }, + { + "type": "string", + "name": "sortBy", + "in": "query" + }, + { + "type": "integer", + "name": "totalPage", + "in": "query" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + }, + "post": { + "security": [ + { + "Bearer": [] + } + ], + "description": "API for creating a message in a chat history session", + "tags": [ + "Chat History" + ], + "summary": "Create chat history message", + "parameters": [ + { + "type": "string", + "description": "Insert the X-Client-Key", + "name": "X-Client-Key", + "in": "header" + }, + { + "type": "string", + "description": "Insert the X-Csrf-Token", + "name": "X-Csrf-Token", + "in": "header", + "required": true + }, + { + "type": "string", + "description": "Session ID", + "name": "sessionId", + "in": "path", + "required": true + }, + { + "description": "Required payload", + "name": "payload", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/request.ChatHistoryMessagesCreateRequest" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/response.Response" + } + }, + "400": { + "description": "Bad Request", + "schema": { + "$ref": "#/definitions/response.BadRequestError" + } + }, + "401": { + "description": "Unauthorized", + "schema": { + "$ref": "#/definitions/response.UnauthorizedError" + } + }, + "500": { + "description": "Internal Server Error", + "schema": { + "$ref": "#/definitions/response.InternalServerError" + } + } + } + } + }, "/cities": { "get": { "security": [ @@ -11206,6 +12743,80 @@ } } }, + "request.AIChatMessagesCreateRequest": { + "type": "object", + "required": [ + "content", + "messageType", + "sessionId" + ], + "properties": { + "content": { + "type": "string", + "minLength": 1 + }, + "messageType": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "sessionId": { + "type": "integer" + } + } + }, + "request.AIChatMessagesUpdateRequest": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string", + "minLength": 1 + } + } + }, + "request.AIChatSessionsCreateRequest": { + "type": "object", + "required": [ + "title" + ], + "properties": { + "agentId": { + "type": "string" + }, + "title": { + "type": "string", + "maxLength": 255, + "minLength": 2 + } + } + }, + "request.AIChatSessionsUpdateRequest": { + "type": "object", + "required": [ + "status", + "title" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "active", + "archived", + "deleted" + ] + }, + "title": { + "type": "string", + "maxLength": 255, + "minLength": 2 + } + } + }, "request.ActivityLogsCreateRequest": { "type": "object", "required": [ @@ -11640,6 +13251,103 @@ } } }, + "request.ChatHistoryMessagesCreateRequest": { + "type": "object", + "required": [ + "content", + "message_type", + "session_id" + ], + "properties": { + "content": { + "type": "string" + }, + "message_type": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + }, + "session_id": { + "type": "string" + } + } + }, + "request.ChatHistoryMessagesUpdateRequest": { + "type": "object", + "required": [ + "content" + ], + "properties": { + "content": { + "type": "string" + } + } + }, + "request.ChatHistorySessionsCreateRequest": { + "type": "object", + "required": [ + "agent_id", + "session_id", + "user_id" + ], + "properties": { + "agent_id": { + "type": "string" + }, + "messages": { + "type": "array", + "items": { + "$ref": "#/definitions/request.ChatMessageRequest" + } + }, + "session_id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "user_id": { + "type": "integer" + } + } + }, + "request.ChatHistorySessionsUpdateRequest": { + "type": "object", + "properties": { + "status": { + "type": "string", + "enum": [ + "active", + "archived", + "deleted" + ] + }, + "title": { + "type": "string" + } + } + }, + "request.ChatMessageRequest": { + "type": "object", + "required": [ + "content", + "type" + ], + "properties": { + "content": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "user", + "assistant" + ] + } + } + }, "request.CitiesCreateRequest": { "type": "object", "required": [ diff --git a/docs/swagger/swagger.yaml b/docs/swagger/swagger.yaml index 55808d4..e11c1d0 100644 --- a/docs/swagger/swagger.yaml +++ b/docs/swagger/swagger.yaml @@ -18,6 +18,58 @@ definitions: totalPage: type: integer type: object + request.AIChatMessagesCreateRequest: + properties: + content: + minLength: 1 + type: string + messageType: + enum: + - user + - assistant + type: string + sessionId: + type: integer + required: + - content + - messageType + - sessionId + type: object + request.AIChatMessagesUpdateRequest: + properties: + content: + minLength: 1 + type: string + required: + - content + type: object + request.AIChatSessionsCreateRequest: + properties: + agentId: + type: string + title: + maxLength: 255 + minLength: 2 + type: string + required: + - title + type: object + request.AIChatSessionsUpdateRequest: + properties: + status: + enum: + - active + - archived + - deleted + type: string + title: + maxLength: 255 + minLength: 2 + type: string + required: + - status + - title + type: object request.ActivityLogsCreateRequest: properties: activityTypeId: @@ -316,6 +368,72 @@ definitions: - title - typeId type: object + request.ChatHistoryMessagesCreateRequest: + properties: + content: + type: string + message_type: + enum: + - user + - assistant + type: string + session_id: + type: string + required: + - content + - message_type + - session_id + type: object + request.ChatHistoryMessagesUpdateRequest: + properties: + content: + type: string + required: + - content + type: object + request.ChatHistorySessionsCreateRequest: + properties: + agent_id: + type: string + messages: + items: + $ref: '#/definitions/request.ChatMessageRequest' + type: array + session_id: + type: string + title: + type: string + user_id: + type: integer + required: + - agent_id + - session_id + - user_id + type: object + request.ChatHistorySessionsUpdateRequest: + properties: + status: + enum: + - active + - archived + - deleted + type: string + title: + type: string + type: object + request.ChatMessageRequest: + properties: + content: + type: string + type: + enum: + - user + - assistant + type: string + required: + - content + - type + type: object request.CitiesCreateRequest: properties: city_name: @@ -1657,6 +1775,522 @@ paths: summary: Viewer Advertisement tags: - Advertisement + /ai-chat/logs: + get: + description: API for getting all AI chat logs for authenticated user + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - in: query + name: logType + type: string + - in: query + name: count + type: integer + - in: query + name: limit + type: integer + - in: query + name: nextPage + type: integer + - in: query + name: page + type: integer + - in: query + name: previousPage + type: integer + - in: query + name: sort + type: string + - in: query + name: sortBy + type: string + - in: query + name: totalPage + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get user AI chat logs + tags: + - AI Chat + /ai-chat/logs/{id}: + get: + description: API for getting one AI chat log + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Log ID + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get one AI chat log + tags: + - AI Chat + /ai-chat/sessions: + get: + description: API for getting all AI chat sessions for authenticated user + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - in: query + name: status + type: string + - in: query + name: count + type: integer + - in: query + name: limit + type: integer + - in: query + name: nextPage + type: integer + - in: query + name: page + type: integer + - in: query + name: previousPage + type: integer + - in: query + name: sort + type: string + - in: query + name: sortBy + type: string + - in: query + name: totalPage + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get user AI chat sessions + tags: + - AI Chat + post: + description: API for create AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - default: Bearer + description: Insert your access token + in: header + name: Authorization + type: string + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.AIChatSessionsCreateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Create AI chat session + tags: + - AI Chat + /ai-chat/sessions/{id}: + delete: + description: API for delete AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Delete AI chat session + tags: + - AI Chat + get: + description: API for getting one AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Session ID + in: path + name: id + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get one AI chat session + tags: + - AI Chat + put: + description: API for update AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: id + required: true + type: integer + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.AIChatSessionsUpdateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Update AI chat session + tags: + - AI Chat + /ai-chat/sessions/{sessionId}/messages: + get: + description: API for getting all messages in an AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: integer + - in: query + name: sessionId + required: true + type: integer + - in: query + name: count + type: integer + - in: query + name: limit + type: integer + - in: query + name: nextPage + type: integer + - in: query + name: page + type: integer + - in: query + name: previousPage + type: integer + - in: query + name: sort + type: string + - in: query + name: sortBy + type: string + - in: query + name: totalPage + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get AI chat session messages + tags: + - AI Chat + post: + description: API for sending a message to an AI chat session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: integer + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.AIChatMessagesCreateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Send message to AI chat session + tags: + - AI Chat + /ai-chat/sessions/{sessionId}/messages/{messageId}: + delete: + description: API for delete AI chat message + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: integer + - description: Message ID + in: path + name: messageId + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Delete AI chat message + tags: + - AI Chat + put: + description: API for update AI chat message + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: integer + - description: Message ID + in: path + name: messageId + required: true + type: integer + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.AIChatMessagesUpdateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Update AI chat message + tags: + - AI Chat /article-approvals: get: description: API for getting all ArticleApprovals @@ -3556,6 +4190,472 @@ paths: summary: Viewer Articles Thumbnail tags: - Articles + /chat-history/messages/{messageId}: + delete: + description: API for delete chat history message + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Message ID + in: path + name: messageId + required: true + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Delete chat history message + tags: + - Chat History + put: + description: API for update chat history message + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Message ID + in: path + name: messageId + required: true + type: integer + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.ChatHistoryMessagesUpdateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Update chat history message + tags: + - Chat History + /chat-history/save: + post: + description: API for saving complete chat history including sessions and messages + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - default: Bearer + description: Insert your access token + in: header + name: Authorization + type: string + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.ChatHistorySessionsCreateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Save chat history (sessions and messages) + tags: + - Chat History + /chat-history/sessions: + get: + description: API for getting all chat history sessions for authenticated user + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - in: query + name: agent_id + type: string + - in: query + name: session_id + type: string + - in: query + name: user_id + type: integer + - in: query + name: count + type: integer + - in: query + name: limit + type: integer + - in: query + name: nextPage + type: integer + - in: query + name: page + type: integer + - in: query + name: previousPage + type: integer + - in: query + name: sort + type: string + - in: query + name: sortBy + type: string + - in: query + name: totalPage + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get user chat history sessions + tags: + - Chat History + post: + description: API for create chat history session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - default: Bearer + description: Insert your access token + in: header + name: Authorization + type: string + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.ChatHistorySessionsCreateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Create chat history session + tags: + - Chat History + /chat-history/sessions/{sessionId}: + delete: + description: API for delete chat history session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Delete chat history session + tags: + - Chat History + get: + description: API for getting one chat history session with all its messages + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: string + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get one chat history session with messages + tags: + - Chat History + put: + description: API for update chat history session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: string + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.ChatHistorySessionsUpdateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Update chat history session + tags: + - Chat History + /chat-history/sessions/{sessionId}/messages: + get: + description: API for getting all messages in a chat history session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: string + - in: query + name: session_id + required: true + type: string + - in: query + name: count + type: integer + - in: query + name: limit + type: integer + - in: query + name: nextPage + type: integer + - in: query + name: page + type: integer + - in: query + name: previousPage + type: integer + - in: query + name: sort + type: string + - in: query + name: sortBy + type: string + - in: query + name: totalPage + type: integer + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Get chat history session messages + tags: + - Chat History + post: + description: API for creating a message in a chat history session + parameters: + - description: Insert the X-Client-Key + in: header + name: X-Client-Key + type: string + - description: Insert the X-Csrf-Token + in: header + name: X-Csrf-Token + required: true + type: string + - description: Session ID + in: path + name: sessionId + required: true + type: string + - description: Required payload + in: body + name: payload + required: true + schema: + $ref: '#/definitions/request.ChatHistoryMessagesCreateRequest' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/response.Response' + "400": + description: Bad Request + schema: + $ref: '#/definitions/response.BadRequestError' + "401": + description: Unauthorized + schema: + $ref: '#/definitions/response.UnauthorizedError' + "500": + description: Internal Server Error + schema: + $ref: '#/definitions/response.InternalServerError' + security: + - Bearer: [] + summary: Create chat history message + tags: + - Chat History /cities: get: description: API for getting all Cities diff --git a/main.go b/main.go index 38533b1..a4a9e5a 100644 --- a/main.go +++ b/main.go @@ -5,12 +5,14 @@ import ( "narasi-ahli-be/app/middleware" "narasi-ahli-be/app/module/activity_logs" "narasi-ahli-be/app/module/advertisement" + "narasi-ahli-be/app/module/ai_chat" "narasi-ahli-be/app/module/article_approvals" "narasi-ahli-be/app/module/article_categories" "narasi-ahli-be/app/module/article_category_details" "narasi-ahli-be/app/module/article_comments" "narasi-ahli-be/app/module/article_files" "narasi-ahli-be/app/module/articles" + "narasi-ahli-be/app/module/chat_history" "narasi-ahli-be/app/module/cities" "narasi-ahli-be/app/module/custom_static_pages" "narasi-ahli-be/app/module/districts" @@ -65,12 +67,14 @@ func main() { // provide modules activity_logs.NewActivityLogsModule, advertisement.NewAdvertisementModule, + ai_chat.NewAIChatModule, article_categories.NewArticleCategoriesModule, article_category_details.NewArticleCategoryDetailsModule, article_files.NewArticleFilesModule, article_approvals.NewArticleApprovalsModule, articles.NewArticlesModule, article_comments.NewArticleCommentsModule, + chat_history.NewChatHistoryModule, cities.NewCitiesModule, custom_static_pages.NewCustomStaticPagesModule, districts.NewDistrictsModule, diff --git a/migrations/001_create_chat_history_tables.go b/migrations/001_create_chat_history_tables.go new file mode 100644 index 0000000..c76b361 --- /dev/null +++ b/migrations/001_create_chat_history_tables.go @@ -0,0 +1,28 @@ +package migrations + +import ( + "narasi-ahli-be/app/database" + "narasi-ahli-be/app/database/entity" +) + +// CreateChatHistoryTables creates the chat history tables +func CreateChatHistoryTables(db *database.Database) error { + // Auto-migrate the new entities + err := db.DB.AutoMigrate( + &entity.ChatSessions{}, + &entity.ChatMessagesNew{}, + ) + if err != nil { + return err + } + + // Create indexes manually if needed + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id ON chat_sessions (user_id)") + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_agent_id ON chat_sessions (agent_id)") + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_session_id ON chat_sessions (session_id)") + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_sessions_created_at ON chat_sessions (created_at)") + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_messages_new_session_id ON chat_messages_new (session_id)") + db.DB.Exec("CREATE INDEX IF NOT EXISTS idx_chat_messages_new_created_at ON chat_messages_new (created_at)") + + return nil +} diff --git a/migrations/001_create_chat_history_tables.sql b/migrations/001_create_chat_history_tables.sql new file mode 100644 index 0000000..155f9bd --- /dev/null +++ b/migrations/001_create_chat_history_tables.sql @@ -0,0 +1,53 @@ +-- Migration: Create Chat History Tables +-- Description: Create tables for chat history functionality based on the old web API structure +-- Date: 2024-01-01 + +-- Create chat_sessions table +CREATE TABLE IF NOT EXISTS chat_sessions ( + id SERIAL PRIMARY KEY, + session_id VARCHAR(255) NOT NULL UNIQUE, + user_id INTEGER NOT NULL, + agent_id VARCHAR(255) NOT NULL, + title VARCHAR(255) NOT NULL DEFAULT 'Chat Session', + message_count INTEGER DEFAULT 0, + status VARCHAR(50) DEFAULT 'active', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Create chat_messages_new table (to avoid conflict with existing chat_messages) +CREATE TABLE IF NOT EXISTS chat_messages_new ( + id SERIAL PRIMARY KEY, + session_id VARCHAR(255) NOT NULL, + message_type VARCHAR(50) NOT NULL CHECK (message_type IN ('user', 'assistant')), + content TEXT NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); + +-- Create indexes for better performance +CREATE INDEX IF NOT EXISTS idx_chat_sessions_user_id ON chat_sessions (user_id); +CREATE INDEX IF NOT EXISTS idx_chat_sessions_agent_id ON chat_sessions (agent_id); +CREATE INDEX IF NOT EXISTS idx_chat_sessions_session_id ON chat_sessions (session_id); +CREATE INDEX IF NOT EXISTS idx_chat_sessions_created_at ON chat_sessions (created_at); +CREATE INDEX IF NOT EXISTS idx_chat_messages_new_session_id ON chat_messages_new (session_id); +CREATE INDEX IF NOT EXISTS idx_chat_messages_new_created_at ON chat_messages_new (created_at); + +-- Add foreign key constraints +ALTER TABLE chat_sessions +ADD CONSTRAINT fk_chat_sessions_user_id +FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE; + +ALTER TABLE chat_messages_new +ADD CONSTRAINT fk_chat_messages_new_session_id +FOREIGN KEY (session_id) REFERENCES chat_sessions(session_id) ON DELETE CASCADE; + +-- Insert sample data (optional) +INSERT INTO chat_sessions (session_id, user_id, agent_id, title, message_count) +VALUES ('sample-session-123', 1, 'd04bbced-ae93-4fb3-a015-9472e4e5e539', 'Sample Chat Session', 2) +ON CONFLICT (session_id) DO NOTHING; + +INSERT INTO chat_messages_new (session_id, message_type, content) +VALUES + ('sample-session-123', 'user', 'Halo, ada yang bisa saya tanyakan?'), + ('sample-session-123', 'assistant', 'Halo! Tentu saja, saya siap membantu Anda dengan pertanyaan apapun.') +ON CONFLICT DO NOTHING; diff --git a/remove_client_id_entities.ps1 b/remove_client_id_entities.ps1 deleted file mode 100644 index 040837d..0000000 --- a/remove_client_id_entities.ps1 +++ /dev/null @@ -1,66 +0,0 @@ -# Script to remove client_id from all entity files -Write-Host "Starting client_id removal from entity files..." -ForegroundColor Green - -# List of entity files that have client_id -$entityFiles = @( - "app/database/entity/users/users.entity.go", - "app/database/entity/article_category_details/article_category_details.entity.go", - "app/database/entity/advertisement.entity.go", - "app/database/entity/activity_logs.entity.go", - "app/database/entity/articles.entity.go", - "app/database/entity/article_approvals.entity.go", - "app/database/entity/article_comments.entity.go", - "app/database/entity/audit_trails.entity.go", - "app/database/entity/article_files.entity.go", - "app/database/entity/article_categories.entity.go", - "app/database/entity/csrf_token_records.entity.go", - "app/database/entity/feedbacks.entity.go", - "app/database/entity/forgot_passwords.entity.go", - "app/database/entity/magazines.entity.go", - "app/database/entity/master_modules.entity.go", - "app/database/entity/one_time_passwords.entity.go", - "app/database/entity/magazine_files.entity.go", - "app/database/entity/master_menus.entity.go", - "app/database/entity/user_roles.entity.go", - "app/database/entity/subscription.entity.go", - "app/database/entity/user_levels.entity.go", - "app/database/entity/user_role_level_details.entity.go", - "app/database/entity/user_role_accesses.entity.go" -) - -$processedFiles = 0 -$totalFiles = $entityFiles.Count - -foreach ($filePath in $entityFiles) { - if (Test-Path $filePath) { - $processedFiles++ - Write-Progress -Activity "Processing entity files" -Status "Processing $([System.IO.Path]::GetFileName($filePath))" -PercentComplete (($processedFiles / $totalFiles) * 100) - - Write-Host "Processing: $filePath" -ForegroundColor Yellow - - $content = Get-Content $filePath -Raw - - # Remove ClientId field definitions - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*', '' - - # Remove ClientId field without json tag - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*', '' - - # Remove uuid import if no more uuid usage - if ($content -notmatch 'uuid\.') { - $content = $content -replace '"github\.com/google/uuid"\s*\n', '' - $content = $content -replace 'github\.com/google/uuid\s*\n', '' - } - - # Clean up extra empty lines - $content = $content -replace '\n\s*\n\s*\n', "`n`n" - - # Write back to file - Set-Content -Path $filePath -Value $content -NoNewline - } -} - -Write-Host "Entity client_id removal process completed!" -ForegroundColor Green -Write-Host "Processed $processedFiles entity files" -ForegroundColor Cyan diff --git a/remove_client_id_entities_v2.ps1 b/remove_client_id_entities_v2.ps1 deleted file mode 100644 index 0466d8c..0000000 --- a/remove_client_id_entities_v2.ps1 +++ /dev/null @@ -1,68 +0,0 @@ -# Enhanced script to remove client_id from entity files -Write-Host "Starting enhanced client_id removal from entity files..." -ForegroundColor Green - -# List of entity files that have client_id -$entityFiles = @( - "app/database/entity/users/users.entity.go", - "app/database/entity/article_category_details/article_category_details.entity.go", - "app/database/entity/advertisement.entity.go", - "app/database/entity/activity_logs.entity.go", - "app/database/entity/articles.entity.go", - "app/database/entity/article_approvals.entity.go", - "app/database/entity/article_comments.entity.go", - "app/database/entity/audit_trails.entity.go", - "app/database/entity/article_files.entity.go", - "app/database/entity/article_categories.entity.go", - "app/database/entity/csrf_token_records.entity.go", - "app/database/entity/feedbacks.entity.go", - "app/database/entity/forgot_passwords.entity.go", - "app/database/entity/magazines.entity.go", - "app/database/entity/master_modules.entity.go", - "app/database/entity/one_time_passwords.entity.go", - "app/database/entity/magazine_files.entity.go", - "app/database/entity/master_menus.entity.go", - "app/database/entity/user_roles.entity.go", - "app/database/entity/subscription.entity.go", - "app/database/entity/user_levels.entity.go", - "app/database/entity/user_role_level_details.entity.go", - "app/database/entity/user_role_accesses.entity.go" -) - -$processedFiles = 0 -$totalFiles = $entityFiles.Count - -foreach ($filePath in $entityFiles) { - if (Test-Path $filePath) { - $processedFiles++ - Write-Progress -Activity "Processing entity files" -Status "Processing $([System.IO.Path]::GetFileName($filePath))" -PercentComplete (($processedFiles / $totalFiles) * 100) - - Write-Host "Processing: $filePath" -ForegroundColor Yellow - - $content = Get-Content $filePath -Raw - - # More specific patterns to remove ClientId field - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*', '' - - # Remove ClientId field with different patterns - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*', '' - - # Remove uuid import if no more uuid usage - if ($content -notmatch 'uuid\.') { - $content = $content -replace '"github\.com/google/uuid"\s*\n', '' - $content = $content -replace 'github\.com/google/uuid\s*\n', '' - } - - # Clean up extra empty lines - $content = $content -replace '\n\s*\n\s*\n', "`n`n" - - # Write back to file - Set-Content -Path $filePath -Value $content -NoNewline - } -} - -Write-Host "Enhanced entity client_id removal process completed!" -ForegroundColor Green -Write-Host "Processed $processedFiles entity files" -ForegroundColor Cyan diff --git a/remove_client_id_final.ps1 b/remove_client_id_final.ps1 deleted file mode 100644 index a0c0ffd..0000000 --- a/remove_client_id_final.ps1 +++ /dev/null @@ -1,33 +0,0 @@ -# Final script to remove ClientId from all entity files -Write-Host "Final removal of ClientId from entity files..." -ForegroundColor Green - -# Get all .go files in entity directory -$entityFiles = Get-ChildItem -Path "app/database/entity" -Recurse -Filter "*.go" - -foreach ($file in $entityFiles) { - $content = Get-Content $file.FullName -Raw - - # Skip if file doesn't contain ClientId - if ($content -notmatch "ClientId") { - continue - } - - Write-Host "Processing: $($file.Name)" -ForegroundColor Yellow - - # Remove ClientId field with regex - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s+`json:"client_id"[^`]*`\s*', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*\n', '' - $content = $content -replace '\s*ClientId\s+\*uuid\.UUID\s*', '' - - # Remove uuid import if no more uuid usage - if ($content -notmatch 'uuid\.') { - $content = $content -replace '"github\.com/google/uuid"\s*\n', '' - $content = $content -replace 'github\.com/google/uuid\s*\n', '' - } - - # Write back to file - Set-Content -Path $file.FullName -Value $content -NoNewline -} - -Write-Host "Final ClientId removal completed!" -ForegroundColor Green diff --git a/remove_client_id_v2.ps1 b/remove_client_id_v2.ps1 deleted file mode 100644 index 0df826e..0000000 --- a/remove_client_id_v2.ps1 +++ /dev/null @@ -1,79 +0,0 @@ -# Enhanced script to remove client_id usage from remaining files -Write-Host "Starting enhanced client_id removal process..." -ForegroundColor Green - -# List of files that still have client_id usage -$problemFiles = @( - "app/module/custom_static_pages/repository/custom_static_pages.repository.go", - "app/module/article_files/repository/article_files.repository.go", - "app/module/article_comments/repository/article_comments.repository.go", - "app/module/article_categories/repository/article_categories.repository.go", - "app/module/articles/repository/articles.repository.go", - "app/module/advertisement/repository/advertisement.repository.go", - "app/module/activity_logs/repository/activity_logs.repository.go", - "app/module/users/service/users.service.go", - "app/module/subscription/repository/subscription.repository.go", - "app/module/subscription/controller/subscription.controller.go", - "app/module/subscription/service/subscription.service.go", - "app/module/magazines/controller/magazines.controller.go", - "app/module/magazines/repository/magazines.repository.go", - "app/module/magazines/service/magazines.service.go", - "app/module/users/controller/users.controller.go", - "app/module/feedbacks/service/feedbacks.service.go", - "app/module/feedbacks/repository/feedbacks.repository.go", - "app/module/feedbacks/controller/feedbacks.controller.go" -) - -foreach ($filePath in $problemFiles) { - if (Test-Path $filePath) { - Write-Host "Processing: $filePath" -ForegroundColor Yellow - - $content = Get-Content $filePath -Raw - - # More aggressive replacements - $content = $content -replace 'clientId \*uuid\.UUID,?\s*', '' - $content = $content -replace 'clientId \*uuid\.UUID\s*,?\s*', '' - $content = $content -replace 'clientId \*uuid\.UUID\s*', '' - - # Remove clientId assignments - $content = $content -replace 'clientId := middleware\.GetClientID\(c\)\s*\n\s*', '' - $content = $content -replace 'clientId := middleware\.GetClientID\(c\)', '' - - # Remove clientId from function calls - be more specific - $content = $content -replace '\(clientId,', '(' - $content = $content -replace ', clientId\)', ')' - $content = $content -replace '\(clientId\)', '()' - - # Remove client_id filters - $content = $content -replace 'if clientId != nil \{\s*\n\s*query = query\.Where\("client_id = \?", clientId\)\s*\n\s*\}', '' - $content = $content -replace 'if clientId != nil \{\s*\n\s*query\.Where\("client_id = \?", clientId\)\s*\n\s*\}', '' - - # Remove clientId logging - $content = $content -replace '_i\.Log\.Info\(\)\.Interface\("clientId", clientId\)\.Msg\(""\)\s*\n\s*', '' - - # Remove clientId comments - $content = $content -replace '// Add ClientId filter\s*\n', '' - $content = $content -replace '// Get ClientId from context\s*\n', '' - - # Clean up function signatures - $content = $content -replace ',\s*,', ',' - $content = $content -replace '\(\s*,', '(' - $content = $content -replace ',\s*\)', ')' - $content = $content -replace '\(\s*\)', '()' - - # Remove unused imports - if ($content -notmatch 'uuid\.') { - $content = $content -replace '"github\.com/google/uuid"\s*\n', '' - $content = $content -replace 'github\.com/google/uuid\s*\n', '' - } - - if ($content -notmatch 'middleware\.') { - $content = $content -replace '"narasi-ahli-be/app/middleware"\s*\n', '' - $content = $content -replace 'narasi-ahli-be/app/middleware\s*\n', '' - } - - # Write back to file - Set-Content -Path $filePath -Value $content -NoNewline - } -} - -Write-Host "Enhanced client ID removal process completed!" -ForegroundColor Green diff --git a/scripts/migrate.go b/scripts/migrate.go new file mode 100644 index 0000000..c1e529e --- /dev/null +++ b/scripts/migrate.go @@ -0,0 +1,38 @@ +package main + +import ( + "narasi-ahli-be/app/database" + "narasi-ahli-be/app/database/entity" + "narasi-ahli-be/migrations" + + "github.com/rs/zerolog" + "go.uber.org/fx" +) + +func main() { + fx.New( + fx.Provide(database.NewDatabase), + fx.Provide(func() zerolog.Logger { + return zerolog.Nop() + }), + fx.Invoke(func(db *database.Database) { + // Run migration + err := migrations.CreateChatHistoryTables(db) + if err != nil { + panic(err) + } + + // Also auto-migrate existing entities + err = db.DB.AutoMigrate( + &entity.AIChatSessions{}, + &entity.AIChatMessages{}, + &entity.AIChatLogs{}, + ) + if err != nil { + panic(err) + } + + println("Migration completed successfully!") + }), + ).Run() +}