feat:knowlegde base api

This commit is contained in:
Rama Priyanto 2026-01-14 08:29:35 +07:00
parent c8ed293819
commit 00e3502c2d
16 changed files with 2267 additions and 0 deletions

View File

@ -0,0 +1,25 @@
package entity
import (
"time"
)
type KnowledgeBase struct {
ID uint `json:"id" gorm:"primaryKey;type:int4;autoIncrement"`
AgentId *string `json:"agent_id" gorm:"type:varchar"`
AgentName *string `json:"agent_name" gorm:"type:varchar"`
CreatedById uint `json:"created_by_id" gorm:"type:int4;not null"`
Status int `json:"status" gorm:"type:int4;default:0"` // 0=wating,1=approved,2=reject
Title *string `json:"title" gorm:"type:varchar"`
FileJournalUrl *string `json:"file_journal_url" gorm:"type:varchar"`
FileAudioUrl *string `json:"file_audio_url" gorm:"type:varchar"`
FileVideoUrl *string `json:"file_video_url" gorm:"type:varchar"`
IsActive bool `json:"is_active" gorm:"type:bool;default:true"`
CreatedAt time.Time `json:"created_at" gorm:"default:now()"`
UpdatedAt time.Time `json:"updated_at" gorm:"default:now()"`
}

View File

@ -0,0 +1,17 @@
package controller
import (
knowledgeBaseSvc "narasi-ahli-be/app/module/knowledge_base/service"
)
type Controller struct {
KnowledgeBase KnowledgeBaseControllerInterface
}
func NewController(
knowledgeBaseService knowledgeBaseSvc.KnowledgeBaseServiceInterface,
) *Controller {
return &Controller{
KnowledgeBase: NewKnowledgeBaseController(knowledgeBaseService),
}
}

View File

@ -0,0 +1,241 @@
package controller
import (
"narasi-ahli-be/app/module/knowledge_base/request"
"narasi-ahli-be/app/module/knowledge_base/service"
"narasi-ahli-be/utils/paginator"
utilRes "narasi-ahli-be/utils/response"
utilVal "narasi-ahli-be/utils/validator"
"strconv"
"github.com/gofiber/fiber/v2"
)
type KnowledgeBaseController struct {
KnowledgeBaseService service.KnowledgeBaseServiceInterface
}
type KnowledgeBaseControllerInterface interface {
All(c *fiber.Ctx) error
Show(c *fiber.Ctx) error
Create(c *fiber.Ctx) error
Update(c *fiber.Ctx) error
Delete(c *fiber.Ctx) error
Viewer(c *fiber.Ctx) error
UpdateStatus(c *fiber.Ctx) error
}
func NewKnowledgeBaseController(svc service.KnowledgeBaseServiceInterface) KnowledgeBaseControllerInterface {
return &KnowledgeBaseController{
KnowledgeBaseService: svc,
}
}
// @Summary Get all KnowledgeBase
// @Description API for getting all KnowledgeBase
// @Tags Knowledge Base
// @Security Bearer
// @Param agentId query string false "Agent ID"
// @Param title query string false "Search title"
// @Param status query int false "Status (0=draft,1=published,2=archived)"
// @Param createdById query int false "Created By ID"
// @Param isActive query bool false "Is active"
// @Param page query int false "Page"
// @Param limit query int false "Limit"
// @Success 200 {object} response.Response
// @Router /knowledge-base [get]
func (ctl *KnowledgeBaseController) All(c *fiber.Ctx) error {
paginate, err := paginator.Paginate(c)
if err != nil {
return err
}
reqContext := request.KnowledgeBaseQueryRequestContext{
AgentId: c.Query("agentId"),
Title: c.Query("title"),
Status: c.Query("status"),
IsActive: c.Query("isActive"),
CreatedById: c.Query("createdById"),
}
req := reqContext.ToParamRequest()
req.Pagination = paginate
data, paging, err := ctl.KnowledgeBaseService.All(req)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase list successfully retrieved"},
Data: data,
Meta: paging,
})
}
// @Summary Get one KnowledgeBase
// @Description API for getting one KnowledgeBase
// @Tags Knowledge Base
// @Security Bearer
// @Param id path int true "KnowledgeBase ID"
// @Success 200 {object} response.Response
// @Router /knowledge-base/{id} [get]
func (ctl *KnowledgeBaseController) Show(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
data, err := ctl.KnowledgeBaseService.Show(uint(id))
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase successfully retrieved"},
Data: data,
})
}
// @Summary Create KnowledgeBase
// @Description API for creating KnowledgeBase with upload file
// @Tags Knowledge Base
// @Security Bearer
// @Accept multipart/form-data
// @Produce json
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
//
// @Param agentId formData string true "Agent ID"
// @Param agentName formData string true "Agent Name"
// @Param createdById formData int true "Created By ID"
// @Param status formData int true "Status (integer)"
// @Param title formData string true "Title"
//
// @Param fileJournal formData file false "Upload Journal File"
// @Param fileAudio formData file false "Upload Audio File"
// @Param fileVideo formData file false "Upload Video File"
//
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /knowledge-base [post]
func (ctl *KnowledgeBaseController) Create(c *fiber.Ctx) error {
data, err := ctl.KnowledgeBaseService.Create(c)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase successfully created"},
Data: data,
})
}
// Viewer KnowledgeBase
// @Summary Viewer KnowledgeBase
// @Description API for Viewer KnowledgeBase
// @Tags Knowledge Base
// @Security Bearer
// @Param filename path string true "KnowledgeBase File Name"
// @Success 200 {object} response.Response
// @Failure 400 {object} response.BadRequestError
// @Failure 401 {object} response.UnauthorizedError
// @Failure 500 {object} response.InternalServerError
// @Router /knowledge-base/viewer/{filename} [get]
func (ctl *KnowledgeBaseController) Viewer(c *fiber.Ctx) error {
return ctl.KnowledgeBaseService.Viewer(c)
}
// @Summary Update KnowledgeBase
// @Description API for updating KnowledgeBase
// @Tags Knowledge Base
// @Security Bearer
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param payload body request.KnowledgeBaseUpdateRequest true "Required payload"
// @Param id path int true "KnowledgeBase ID"
// @Success 200 {object} response.Response
// @Router /knowledge-base/{id} [put]
func (ctl *KnowledgeBaseController) Update(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
req := new(request.KnowledgeBaseUpdateRequest)
if err := utilVal.ParseAndValidate(c, req); err != nil {
return err
}
data, err := ctl.KnowledgeBaseService.Update(uint(id), *req)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase successfully updated"},
Data: data,
})
}
// @Summary Delete KnowledgeBase
// @Description API for deleting KnowledgeBase (soft delete)
// @Tags Knowledge Base
// @Security Bearer
// @Param X-Csrf-Token header string true "Insert the X-Csrf-Token"
// @Param id path int true "KnowledgeBase ID"
// @Success 200 {object} response.Response
// @Router /knowledge-base/{id} [delete]
func (ctl *KnowledgeBaseController) Delete(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
err = ctl.KnowledgeBaseService.Delete(uint(id))
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase successfully deleted"},
})
}
// @Summary Update KnowledgeBase Status
// @Description API untuk update status KnowledgeBase
// @Tags Knowledge Base
// @Security Bearer
// @Param id path int true "KnowledgeBase ID"
// @Param payload body request.KnowledgeBaseUpdateStatusRequest true "Required payload"
// @Success 200 {object} response.Response
// @Router /knowledge-base/{id}/status [patch]
func (ctl *KnowledgeBaseController) UpdateStatus(c *fiber.Ctx) error {
id, err := strconv.ParseUint(c.Params("id"), 10, 0)
if err != nil {
return err
}
req := new(request.KnowledgeBaseUpdateStatusRequest)
if err := utilVal.ParseAndValidate(c, req); err != nil {
return err
}
data, err := ctl.KnowledgeBaseService.UpdateStatus(uint(id), req.Status)
if err != nil {
return err
}
return utilRes.Resp(c, utilRes.Response{
Success: true,
Messages: utilRes.Messages{"KnowledgeBase status successfully updated"},
Data: data,
})
}

View File

@ -0,0 +1,56 @@
package knowledge_base
import (
"narasi-ahli-be/app/module/knowledge_base/controller"
"narasi-ahli-be/app/module/knowledge_base/repository"
"narasi-ahli-be/app/module/knowledge_base/service"
"github.com/gofiber/fiber/v2"
"go.uber.org/fx"
)
// struct of KnowledgeBaseRouter
type KnowledgeBaseRouter struct {
App fiber.Router
Controller *controller.Controller
}
// register bulky of KnowledgeBase module
var NewKnowledgeBaseModule = fx.Options(
// register repository of KnowledgeBase module
fx.Provide(repository.NewKnowledgeBaseRepository),
// register service of KnowledgeBase module
fx.Provide(service.NewKnowledgeBaseService),
// register controller of KnowledgeBase module
fx.Provide(controller.NewController),
// register router of KnowledgeBase module
fx.Provide(NewKnowledgeBaseRouter),
)
// init KnowledgeBaseRouter
func NewKnowledgeBaseRouter(fiber *fiber.App, controller *controller.Controller) *KnowledgeBaseRouter {
return &KnowledgeBaseRouter{
App: fiber,
Controller: controller,
}
}
// register routes of KnowledgeBase module
func (r *KnowledgeBaseRouter) RegisterKnowledgeBaseRoutes() {
kbController := r.Controller.KnowledgeBase
r.App.Route("/knowledge-base", func(router fiber.Router) {
router.Get("/", kbController.All)
router.Get("/:id", kbController.Show)
router.Post("/", kbController.Create)
router.Put("/:id", kbController.Update)
router.Delete("/:id", kbController.Delete)
router.Get("/viewer/:filename", kbController.Viewer)
router.Patch("/:id/status", kbController.UpdateStatus)
})
}

View File

@ -0,0 +1,31 @@
package mapper
import (
"narasi-ahli-be/app/database/entity"
res "narasi-ahli-be/app/module/knowledge_base/response"
)
func KnowledgeBaseResponseMapper(kb *entity.KnowledgeBase, host string) (out *res.KnowledgeBaseResponse) {
if kb == nil {
return nil
}
out = &res.KnowledgeBaseResponse{
ID: kb.ID,
AgentId: kb.AgentId,
AgentName: kb.AgentName,
CreatedById: kb.CreatedById,
Title: kb.Title,
Status: kb.Status,
FileJournalUrl: kb.FileJournalUrl,
FileAudioUrl: kb.FileAudioUrl,
FileVideoUrl: kb.FileVideoUrl,
IsActive: kb.IsActive,
CreatedAt: kb.CreatedAt,
UpdatedAt: kb.UpdatedAt,
}
return out
}

View File

@ -0,0 +1,146 @@
package repository
import (
"fmt"
"narasi-ahli-be/app/database"
"narasi-ahli-be/app/database/entity"
"narasi-ahli-be/app/module/knowledge_base/request"
"narasi-ahli-be/utils/paginator"
utilSvc "narasi-ahli-be/utils/service"
"strings"
)
type KnowledgeBaseRepository struct {
DB *database.Database
}
// interface
type KnowledgeBaseRepositoryInterface interface {
GetAll(req request.KnowledgeBaseQueryRequest) (data []*entity.KnowledgeBase, paging paginator.Pagination, err error)
FindOne(id uint) (data *entity.KnowledgeBase, err error)
FindByFilename(filename string) (data *entity.KnowledgeBase, fileType string, err error)
Create(data *entity.KnowledgeBase) (err error)
Update(id uint, data *entity.KnowledgeBase) (err error)
Delete(id uint) (err error)
}
func NewKnowledgeBaseRepository(db *database.Database) KnowledgeBaseRepositoryInterface {
return &KnowledgeBaseRepository{
DB: db,
}
}
func (r *KnowledgeBaseRepository) GetAll(req request.KnowledgeBaseQueryRequest) (data []*entity.KnowledgeBase, paging paginator.Pagination, err error) {
var count int64
query := r.DB.DB.Model(&entity.KnowledgeBase{})
query = query.Where("is_active = ?", true)
if req.AgentId != nil && *req.AgentId != "" {
query = query.Where("agent_id = ?", *req.AgentId)
}
if req.CreatedById != nil && *req.CreatedById > 0 {
query = query.Where("created_by_id = ?", *req.CreatedById)
}
if req.Title != nil && strings.TrimSpace(*req.Title) != "" {
title := strings.ToLower(strings.TrimSpace(*req.Title))
query = query.Where("LOWER(title) LIKE ?", "%"+title+"%")
}
if req.Status != nil {
query = query.Where("status = ?", *req.Status)
}
if req.IsActive != nil {
query = query.Where("is_active = ?", *req.IsActive)
}
query.Count(&count)
if req.Pagination != nil && req.Pagination.SortBy != "" {
direction := "ASC"
if strings.ToLower(req.Pagination.Sort) == "desc" {
direction = "DESC"
}
query = query.Order(fmt.Sprintf("%s %s", req.Pagination.SortBy, direction))
} else {
query = query.Order("created_at DESC")
}
if req.Pagination == nil {
req.Pagination = &paginator.Pagination{}
}
req.Pagination.Count = count
req.Pagination = paginator.Paging(req.Pagination)
err = query.
Offset(req.Pagination.Offset).
Limit(req.Pagination.Limit).
Find(&data).Error
if err != nil {
return nil, paging, err
}
paging = *req.Pagination
return data, paging, nil
}
func (r *KnowledgeBaseRepository) FindOne(id uint) (data *entity.KnowledgeBase, err error) {
query := r.DB.DB.Model(&entity.KnowledgeBase{})
if err := query.Where("id = ? AND is_active = ?", id, true).First(&data).Error; err != nil {
return nil, err
}
return data, nil
}
func (r *KnowledgeBaseRepository) Create(data *entity.KnowledgeBase) (err error) {
return r.DB.DB.Create(data).Error
}
func (r *KnowledgeBaseRepository) Update(id uint, data *entity.KnowledgeBase) (err error) {
updateMap, err := utilSvc.StructToMap(data)
if err != nil {
return err
}
return r.DB.DB.Model(&entity.KnowledgeBase{}).
Where("id = ?", id).
Updates(updateMap).
Error
}
func (r *KnowledgeBaseRepository) Delete(id uint) (err error) {
return r.DB.DB.Delete(&entity.KnowledgeBase{}, id).Error
}
func (r *KnowledgeBaseRepository) FindByFilename(filename string) (data *entity.KnowledgeBase, fileType string, err error) {
query := r.DB.DB.Model(&entity.KnowledgeBase{}).Where("is_active = ?", true)
// cari berdasarkan url yang mengandung filename
like := "%" + filename
// journal
var kb entity.KnowledgeBase
if err := query.Where("file_journal_url LIKE ?", like).First(&kb).Error; err == nil {
return &kb, "journal", nil
}
// audio
if err := query.Where("file_audio_url LIKE ?", like).First(&kb).Error; err == nil {
return &kb, "audio", nil
}
// video
if err := query.Where("file_video_url LIKE ?", like).First(&kb).Error; err == nil {
return &kb, "video", nil
}
return nil, "", fmt.Errorf("file not found")
}

View File

@ -0,0 +1,125 @@
package request
import (
"narasi-ahli-be/app/database/entity"
"narasi-ahli-be/utils/paginator"
"strconv"
"time"
)
type KnowledgeBaseGeneric interface {
ToEntity() *entity.KnowledgeBase
}
type KnowledgeBaseQueryRequest struct {
AgentId *string `json:"agentId"`
Title *string `json:"title"`
Status *int `json:"status"`
IsActive *bool `json:"isActive"`
CreatedById *uint `json:"createdById"`
Pagination *paginator.Pagination `json:"pagination"`
}
type KnowledgeBaseUpdateStatusRequest struct {
Status int `json:"status" validate:"required"`
}
type KnowledgeBaseCreateRequest struct {
AgentId *string `form:"agentId" validate:"required"`
AgentName *string `form:"agentName" validate:"required"`
CreatedById uint `form:"createdById" validate:"required"`
Title *string `form:"title" validate:"required"`
Status int `form:"status" validate:"required"`
}
func (req KnowledgeBaseCreateRequest) ToEntity() *entity.KnowledgeBase {
kb := &entity.KnowledgeBase{
AgentId: req.AgentId,
AgentName: req.AgentName,
CreatedById: req.CreatedById,
Title: req.Title,
Status: req.Status,
}
return kb
}
type KnowledgeBaseUpdateRequest struct {
ID uint `json:"id" validate:"required"`
AgentId *string `json:"agentId" validate:"required"`
AgentName *string `json:"agentName" validate:"required"`
Title *string `json:"title" validate:"required"`
Status int `json:"status" validate:"required"`
FileJournalUrl *string `json:"fileJournalUrl"`
FileAudioUrl *string `json:"fileAudioUrl"`
FileVideoUrl *string `json:"fileVideoUrl"`
IsActive *bool `json:"isActive"`
}
func (req KnowledgeBaseUpdateRequest) ToEntity() *entity.KnowledgeBase {
kb := &entity.KnowledgeBase{
ID: req.ID,
AgentId: req.AgentId,
AgentName: req.AgentName,
Title: req.Title,
Status: req.Status,
FileJournalUrl: req.FileJournalUrl,
FileAudioUrl: req.FileAudioUrl,
FileVideoUrl: req.FileVideoUrl,
UpdatedAt: time.Now(),
}
if req.IsActive != nil {
kb.IsActive = *req.IsActive
}
return kb
}
type KnowledgeBaseQueryRequestContext struct {
AgentId string `json:"agentId"`
Title string `json:"title"`
Status string `json:"status"`
IsActive string `json:"isActive"`
CreatedById string `json:"createdById"`
}
func (req KnowledgeBaseQueryRequestContext) ToParamRequest() KnowledgeBaseQueryRequest {
var request KnowledgeBaseQueryRequest
if agentId := req.AgentId; agentId != "" {
request.AgentId = &agentId
}
if title := req.Title; title != "" {
request.Title = &title
}
if statusStr := req.Status; statusStr != "" {
status, err := strconv.Atoi(statusStr)
if err == nil {
request.Status = &status
}
}
if isActiveStr := req.IsActive; isActiveStr != "" {
isActive, err := strconv.ParseBool(isActiveStr)
if err == nil {
request.IsActive = &isActive
}
}
if createdByIdStr := req.CreatedById; createdByIdStr != "" {
id64, err := strconv.ParseUint(createdByIdStr, 10, 32)
if err == nil {
uid := uint(id64)
request.CreatedById = &uid
}
}
return request
}

View File

@ -0,0 +1,22 @@
package response
import "time"
type KnowledgeBaseResponse struct {
ID uint `json:"id"`
AgentId *string `json:"agentId"`
AgentName *string `json:"agentName"`
CreatedById uint `json:"createdById"`
Title *string `json:"title"`
Status int `json:"status"`
FileJournalUrl *string `json:"fileJournalUrl"`
FileAudioUrl *string `json:"fileAudioUrl"`
FileVideoUrl *string `json:"fileVideoUrl"`
IsActive bool `json:"isActive"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}

View File

@ -0,0 +1,69 @@
package service
import (
"context"
"io"
"time"
"github.com/minio/minio-go/v7"
"github.com/rs/zerolog"
)
// AsyncUploader menangani proses upload secara asynchronous
type UploadService interface {
UploadFile(ctx context.Context, minioClient *minio.Client, uploadID string, reader io.Reader, bucketName string, objectName string, size int64, contentType string) error
}
type uploadService struct {
uploadManager UploadManager
Log zerolog.Logger
}
func NewUploadService(uploadManager UploadManager, log zerolog.Logger) UploadService {
return &uploadService{
uploadManager: uploadManager,
Log: log,
}
}
func (u *uploadService) UploadFile(ctx context.Context, minioClient *minio.Client, uploadID string, reader io.Reader, bucketName string, objectName string, size int64, contentType string) error {
status := &UploadStatus{
FileName: objectName,
Size: size,
Progress: 0,
Status: "uploading",
ObjectName: objectName,
BucketName: bucketName,
StartTime: time.Now(),
}
u.uploadManager.Add(uploadID, status)
u.Log.Info().Str("timestamp", time.Now().
Format(time.RFC3339)).Str("Service:Resource", "UploadService::UploadFile").
Interface("add status", status).Msg("")
// Upload ke Minio
_, err := minioClient.PutObject(
ctx,
bucketName,
objectName,
reader,
size,
minio.PutObjectOptions{
ContentType: contentType,
PartSize: 10 * 1024 * 1024, // 10MB part size
},
)
if err != nil {
u.uploadManager.UpdateStatus(uploadID, "error", err)
u.Log.Info().Str("timestamp", time.Now().
Format(time.RFC3339)).Str("Service:Resource", "UploadService::UploadFile").
Interface("error when upload", err).Msg("")
}
u.uploadManager.UpdateStatus(uploadID, "completed", nil)
return nil
}

View File

@ -0,0 +1,337 @@
package service
import (
"context"
"fmt"
"io"
"mime"
"mime/multipart"
"narasi-ahli-be/app/module/knowledge_base/mapper"
"narasi-ahli-be/app/module/knowledge_base/repository"
"narasi-ahli-be/app/module/knowledge_base/request"
"narasi-ahli-be/app/module/knowledge_base/response"
config "narasi-ahli-be/config/config"
minioStorage "narasi-ahli-be/config/config"
"narasi-ahli-be/utils/paginator"
"path/filepath"
"strings"
"time"
"github.com/gofiber/fiber/v2"
"github.com/minio/minio-go/v7"
"github.com/rs/zerolog"
)
type KnowledgeBaseService struct {
Repo repository.KnowledgeBaseRepositoryInterface
Log zerolog.Logger
Cfg *config.Config
MinioStorage *minioStorage.MinioStorage
}
type KnowledgeBaseServiceInterface interface {
All(req request.KnowledgeBaseQueryRequest) (data []*response.KnowledgeBaseResponse, paging paginator.Pagination, err error)
Show(id uint) (data *response.KnowledgeBaseResponse, err error)
Create(c *fiber.Ctx) (data *response.KnowledgeBaseResponse, err error)
Update(id uint, req request.KnowledgeBaseUpdateRequest) (data *response.KnowledgeBaseResponse, err error)
Delete(id uint) error
Viewer(c *fiber.Ctx) error
UpdateStatus(id uint, status int) (data *response.KnowledgeBaseResponse, err error)
}
func NewKnowledgeBaseService(
repo repository.KnowledgeBaseRepositoryInterface,
log zerolog.Logger,
cfg *config.Config,
minioStorage *minioStorage.MinioStorage,
) KnowledgeBaseServiceInterface {
return &KnowledgeBaseService{
Repo: repo,
Log: log,
Cfg: cfg,
MinioStorage: minioStorage,
}
}
func (s *KnowledgeBaseService) uploadFileToMinio(
ctx context.Context,
minioClient *minio.Client,
bucketName string,
agentId string,
folder string,
fileHeader *multipart.FileHeader,
) (*string, error) {
if fileHeader == nil {
return nil, nil
}
src, err := fileHeader.Open()
if err != nil {
return nil, err
}
defer src.Close()
filename := filepath.Base(fileHeader.Filename)
filename = strings.ReplaceAll(filename, " ", "")
ext := filepath.Ext(filename)
filenameWithoutExt := strings.TrimSuffix(filename, ext)
now := time.Now()
newFilename := fmt.Sprintf("%s_%d%s", filenameWithoutExt, now.UnixNano(), ext)
objectName := fmt.Sprintf(
"knowledge-base/%s/%s/%s",
agentId,
folder,
newFilename,
)
_, err = minioClient.PutObject(
ctx,
bucketName,
objectName,
src,
fileHeader.Size,
minio.PutObjectOptions{},
)
if err != nil {
return nil, err
}
return &newFilename, nil
}
func (s *KnowledgeBaseService) All(req request.KnowledgeBaseQueryRequest) (data []*response.KnowledgeBaseResponse, paging paginator.Pagination, err error) {
results, paging, err := s.Repo.GetAll(req)
if err != nil {
return nil, paging, err
}
host := s.Cfg.App.Domain
for _, item := range results {
data = append(data, mapper.KnowledgeBaseResponseMapper(item, host))
}
return data, paging, nil
}
func getFileExtension(filename string) string {
parts := strings.Split(filename, ".")
if len(parts) == 1 || (len(parts) == 2 && parts[0] == "") {
return ""
}
return parts[len(parts)-1]
}
func (s *KnowledgeBaseService) Viewer(c *fiber.Ctx) (err error) {
filename := c.Params("filename")
result, folder, err := s.Repo.FindByFilename(filename)
if err != nil {
return err
}
ctx := context.Background()
bucketName := s.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
objectName := fmt.Sprintf("knowledge-base/%s/%s/%s", *result.AgentId, folder, filename)
s.Log.Info().
Str("timestamp", time.Now().Format(time.RFC3339)).
Str("Service:Resource", "KnowledgeBase:Viewer").
Interface("objectName", objectName).
Msg("")
minioClient, err := s.MinioStorage.ConnectMinio()
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": true,
"msg": err.Error(),
})
}
fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{})
if err != nil {
return err
}
defer fileContent.Close()
contentType := mime.TypeByExtension("." + getFileExtension(objectName))
if contentType == "" {
contentType = "application/octet-stream"
}
c.Set("Content-Type", contentType)
if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil {
return err
}
return nil
}
func (s *KnowledgeBaseService) Show(id uint) (data *response.KnowledgeBaseResponse, err error) {
result, err := s.Repo.FindOne(id)
if err != nil {
return nil, err
}
host := s.Cfg.App.Domain
return mapper.KnowledgeBaseResponseMapper(result, host), nil
}
func (s *KnowledgeBaseService) Create(c *fiber.Ctx) (data *response.KnowledgeBaseResponse, err error) {
req := new(request.KnowledgeBaseCreateRequest)
if err := c.BodyParser(req); err != nil {
return nil, err
}
if req.AgentId == nil || *req.AgentId == "" {
return nil, fiber.NewError(fiber.StatusBadRequest, "agentId is required")
}
if req.AgentName == nil || *req.AgentName == "" {
return nil, fiber.NewError(fiber.StatusBadRequest, "agentName is required")
}
if req.Title == nil || *req.Title == "" {
return nil, fiber.NewError(fiber.StatusBadRequest, "title is required")
}
fileJournal, _ := c.FormFile("fileJournal")
fileAudio, _ := c.FormFile("fileAudio")
fileVideo, _ := c.FormFile("fileVideo")
minioClient, err := s.MinioStorage.ConnectMinio()
if err != nil {
return nil, err
}
ctx := context.Background()
bucketName := s.MinioStorage.Cfg.ObjectStorage.MinioStorage.BucketName
journalFilename, err := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, "journal", fileJournal)
if err != nil {
return nil, err
}
audioFilename, err := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, "audio", fileAudio)
if err != nil {
return nil, err
}
videoFilename, err := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, "video", fileVideo)
if err != nil {
return nil, err
}
entity := req.ToEntity()
viewerBase := s.Cfg.App.Domain + "/knowledge-base/viewer/"
if journalFilename != nil {
journalUrl := viewerBase + *journalFilename
entity.FileJournalUrl = &journalUrl
}
if audioFilename != nil {
audioUrl := viewerBase + *audioFilename
entity.FileAudioUrl = &audioUrl
}
if videoFilename != nil {
videoUrl := viewerBase + *videoFilename
entity.FileVideoUrl = &videoUrl
}
if req.Status < 0 {
entity.Status = 0
}
err = s.Repo.Create(entity)
if err != nil {
return nil, err
}
result, err := s.Repo.FindOne(entity.ID)
if err != nil {
return nil, err
}
host := s.Cfg.App.Domain
return mapper.KnowledgeBaseResponseMapper(result, host), nil
}
func (s *KnowledgeBaseService) Update(id uint, req request.KnowledgeBaseUpdateRequest) (data *response.KnowledgeBaseResponse, err error) {
old, err := s.Repo.FindOne(id)
if err != nil {
return nil, err
}
old.AgentId = req.AgentId
old.AgentName = req.AgentName
old.Title = req.Title
old.Status = req.Status
old.FileJournalUrl = req.FileJournalUrl
old.FileAudioUrl = req.FileAudioUrl
old.FileVideoUrl = req.FileVideoUrl
if req.IsActive != nil {
old.IsActive = *req.IsActive
}
old.UpdatedAt = time.Now()
err = s.Repo.Update(id, old)
if err != nil {
return nil, err
}
updated, err := s.Repo.FindOne(id)
if err != nil {
return nil, err
}
host := s.Cfg.App.Domain
return mapper.KnowledgeBaseResponseMapper(updated, host), nil
}
func (s *KnowledgeBaseService) Delete(id uint) error {
result, err := s.Repo.FindOne(id)
if err != nil {
return err
}
result.IsActive = false
result.UpdatedAt = time.Now()
return s.Repo.Update(id, result)
}
func (s *KnowledgeBaseService) UpdateStatus(id uint, status int) (data *response.KnowledgeBaseResponse, err error) {
old, err := s.Repo.FindOne(id)
if err != nil {
return nil, err
}
old.Status = status
old.UpdatedAt = time.Now()
err = s.Repo.Update(id, old)
if err != nil {
return nil, err
}
updated, err := s.Repo.FindOne(id)
if err != nil {
return nil, err
}
host := s.Cfg.App.Domain
return mapper.KnowledgeBaseResponseMapper(updated, host), nil
}

View File

@ -0,0 +1,71 @@
package service
import (
"sync"
"time"
)
type UploadStatus struct {
FileName string `json:"fileName"`
Size int64 `json:"size"`
Progress int `json:"progress"`
Status string `json:"status"`
ObjectName string `json:"objectName"`
BucketName string `json:"bucketName"`
StartTime time.Time `json:"startTime"`
Error string `json:"error,omitempty"`
}
type UploadManager interface {
Add(uploadID string, status *UploadStatus)
UpdateProgress(uploadID string, progress int)
UpdateStatus(uploadID string, status string, err error)
Get(uploadID string) (*UploadStatus, bool)
}
type uploadManager struct {
uploads map[string]*UploadStatus
mutex sync.RWMutex
}
func NewUploadManager() UploadManager {
return &uploadManager{
uploads: make(map[string]*UploadStatus),
}
}
// Add menambahkan status upload baru
func (um *uploadManager) Add(uploadID string, status *UploadStatus) {
um.mutex.Lock()
defer um.mutex.Unlock()
um.uploads[uploadID] = status
}
// UpdateProgress memperbarui progress upload
func (um *uploadManager) UpdateProgress(uploadID string, progress int) {
um.mutex.Lock()
defer um.mutex.Unlock()
if status, exists := um.uploads[uploadID]; exists {
status.Progress = progress
}
}
// UpdateStatus memperbarui status upload
func (um *uploadManager) UpdateStatus(uploadID string, status string, err error) {
um.mutex.Lock()
defer um.mutex.Unlock()
if upload, exists := um.uploads[uploadID]; exists {
upload.Status = status
if err != nil {
upload.Error = err.Error()
}
}
}
// Get mendapatkan status upload berdasarkan ID
func (um *uploadManager) Get(uploadID string) (*UploadStatus, bool) {
um.mutex.RLock()
defer um.mutex.RUnlock()
status, exists := um.uploads[uploadID]
return status, exists
}

View File

@ -18,6 +18,7 @@ import (
"narasi-ahli-be/app/module/ebooks"
"narasi-ahli-be/app/module/education_history"
"narasi-ahli-be/app/module/feedbacks"
"narasi-ahli-be/app/module/knowledge_base"
"narasi-ahli-be/app/module/magazine_files"
"narasi-ahli-be/app/module/magazines"
"narasi-ahli-be/app/module/master_menus"
@ -44,6 +45,7 @@ type Router struct {
ActivityLogsRouter *activity_logs.ActivityLogsRouter
AdvertisementRouter *advertisement.AdvertisementRouter
AIChatRouter *ai_chat.AIChatRouter
KnowledgeBaseRouter *knowledge_base.KnowledgeBaseRouter
ArticleCategoriesRouter *article_categories.ArticleCategoriesRouter
ArticleCategoryDetailsRouter *article_category_details.ArticleCategoryDetailsRouter
ArticleFilesRouter *article_files.ArticleFilesRouter
@ -80,6 +82,7 @@ func NewRouter(
activityLogsRouter *activity_logs.ActivityLogsRouter,
advertisementRouter *advertisement.AdvertisementRouter,
aiChatRouter *ai_chat.AIChatRouter,
knowledgeBaseRouter *knowledge_base.KnowledgeBaseRouter,
articleCategoriesRouter *article_categories.ArticleCategoriesRouter,
articleCategoryDetailsRouter *article_category_details.ArticleCategoryDetailsRouter,
articleFilesRouter *article_files.ArticleFilesRouter,
@ -119,6 +122,7 @@ func NewRouter(
ArticleCommentsRouter: articleCommentsRouter,
ArticleApprovalsRouter: articleApprovalsRouter,
ArticlesRouter: articlesRouter,
KnowledgeBaseRouter: knowledgeBaseRouter,
ChatRouter: chatRouter,
CitiesRouter: citiesRouter,
CustomStaticPagesRouter: customStaticPagesRouter,
@ -162,6 +166,7 @@ func (r *Router) Register() {
r.ArticleApprovalsRouter.RegisterArticleApprovalsRoutes()
r.ArticlesRouter.RegisterArticlesRoutes()
r.ArticleCommentsRouter.RegisterArticleCommentsRoutes()
r.KnowledgeBaseRouter.RegisterKnowledgeBaseRoutes()
r.ChatRouter.RegisterChatRoutes()
r.CitiesRouter.RegisterCitiesRoutes()
r.CustomStaticPagesRouter.RegisterCustomStaticPagesRoutes()

View File

@ -10256,6 +10256,379 @@ const docTemplate = `{
}
}
},
"/knowledge-base": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for getting all KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Get all KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Agent ID",
"name": "agentId",
"in": "query"
},
{
"type": "string",
"description": "Search title",
"name": "title",
"in": "query"
},
{
"type": "integer",
"description": "Status (0=draft,1=published,2=archived)",
"name": "status",
"in": "query"
},
{
"type": "integer",
"description": "Created By ID",
"name": "createdById",
"in": "query"
},
{
"type": "boolean",
"description": "Is active",
"name": "isActive",
"in": "query"
},
{
"type": "integer",
"description": "Page",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "Limit",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"post": {
"security": [
{
"Bearer": []
}
],
"description": "API for creating KnowledgeBase with upload file",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
"Knowledge Base"
],
"summary": "Create KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"type": "string",
"description": "Agent ID",
"name": "agentId",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Agent Name",
"name": "agentName",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "Created By ID",
"name": "createdById",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "Status (integer)",
"name": "status",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Title",
"name": "title",
"in": "formData",
"required": true
},
{
"type": "file",
"description": "Upload Journal File",
"name": "fileJournal",
"in": "formData"
},
{
"type": "file",
"description": "Upload Audio File",
"name": "fileAudio",
"in": "formData"
},
{
"type": "file",
"description": "Upload Video File",
"name": "fileVideo",
"in": "formData"
}
],
"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"
}
}
}
}
},
"/knowledge-base/viewer/{filename}": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for Viewer KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Viewer KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "KnowledgeBase File Name",
"name": "filename",
"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"
}
}
}
}
},
"/knowledge-base/{id}": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for getting one KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Get one KnowledgeBase",
"parameters": [
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"put": {
"security": [
{
"Bearer": []
}
],
"description": "API for updating KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Update KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"description": "Required payload",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.KnowledgeBaseUpdateRequest"
}
},
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"delete": {
"security": [
{
"Bearer": []
}
],
"description": "API for deleting KnowledgeBase (soft delete)",
"tags": [
"Knowledge Base"
],
"summary": "Delete KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/knowledge-base/{id}/status": {
"patch": {
"security": [
{
"Bearer": []
}
],
"description": "API untuk update status KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Update KnowledgeBase Status",
"parameters": [
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Required payload",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.KnowledgeBaseUpdateStatusRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/magazine-files": {
"get": {
"security": [
@ -16630,6 +17003,56 @@ const docTemplate = `{
}
}
},
"request.KnowledgeBaseUpdateRequest": {
"type": "object",
"required": [
"agentId",
"agentName",
"id",
"status",
"title"
],
"properties": {
"agentId": {
"type": "string"
},
"agentName": {
"type": "string"
},
"fileAudioUrl": {
"type": "string"
},
"fileJournalUrl": {
"type": "string"
},
"fileVideoUrl": {
"type": "string"
},
"id": {
"type": "integer"
},
"isActive": {
"type": "boolean"
},
"status": {
"type": "integer"
},
"title": {
"type": "string"
}
}
},
"request.KnowledgeBaseUpdateStatusRequest": {
"type": "object",
"required": [
"status"
],
"properties": {
"status": {
"type": "integer"
}
}
},
"request.MagazinesCreateRequest": {
"type": "object",
"required": [

View File

@ -10245,6 +10245,379 @@
}
}
},
"/knowledge-base": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for getting all KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Get all KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Agent ID",
"name": "agentId",
"in": "query"
},
{
"type": "string",
"description": "Search title",
"name": "title",
"in": "query"
},
{
"type": "integer",
"description": "Status (0=draft,1=published,2=archived)",
"name": "status",
"in": "query"
},
{
"type": "integer",
"description": "Created By ID",
"name": "createdById",
"in": "query"
},
{
"type": "boolean",
"description": "Is active",
"name": "isActive",
"in": "query"
},
{
"type": "integer",
"description": "Page",
"name": "page",
"in": "query"
},
{
"type": "integer",
"description": "Limit",
"name": "limit",
"in": "query"
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"post": {
"security": [
{
"Bearer": []
}
],
"description": "API for creating KnowledgeBase with upload file",
"consumes": [
"multipart/form-data"
],
"produces": [
"application/json"
],
"tags": [
"Knowledge Base"
],
"summary": "Create KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"type": "string",
"description": "Agent ID",
"name": "agentId",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Agent Name",
"name": "agentName",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "Created By ID",
"name": "createdById",
"in": "formData",
"required": true
},
{
"type": "integer",
"description": "Status (integer)",
"name": "status",
"in": "formData",
"required": true
},
{
"type": "string",
"description": "Title",
"name": "title",
"in": "formData",
"required": true
},
{
"type": "file",
"description": "Upload Journal File",
"name": "fileJournal",
"in": "formData"
},
{
"type": "file",
"description": "Upload Audio File",
"name": "fileAudio",
"in": "formData"
},
{
"type": "file",
"description": "Upload Video File",
"name": "fileVideo",
"in": "formData"
}
],
"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"
}
}
}
}
},
"/knowledge-base/viewer/{filename}": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for Viewer KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Viewer KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "KnowledgeBase File Name",
"name": "filename",
"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"
}
}
}
}
},
"/knowledge-base/{id}": {
"get": {
"security": [
{
"Bearer": []
}
],
"description": "API for getting one KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Get one KnowledgeBase",
"parameters": [
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"put": {
"security": [
{
"Bearer": []
}
],
"description": "API for updating KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Update KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"description": "Required payload",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.KnowledgeBaseUpdateRequest"
}
},
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
},
"delete": {
"security": [
{
"Bearer": []
}
],
"description": "API for deleting KnowledgeBase (soft delete)",
"tags": [
"Knowledge Base"
],
"summary": "Delete KnowledgeBase",
"parameters": [
{
"type": "string",
"description": "Insert the X-Csrf-Token",
"name": "X-Csrf-Token",
"in": "header",
"required": true
},
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/knowledge-base/{id}/status": {
"patch": {
"security": [
{
"Bearer": []
}
],
"description": "API untuk update status KnowledgeBase",
"tags": [
"Knowledge Base"
],
"summary": "Update KnowledgeBase Status",
"parameters": [
{
"type": "integer",
"description": "KnowledgeBase ID",
"name": "id",
"in": "path",
"required": true
},
{
"description": "Required payload",
"name": "payload",
"in": "body",
"required": true,
"schema": {
"$ref": "#/definitions/request.KnowledgeBaseUpdateStatusRequest"
}
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/response.Response"
}
}
}
}
},
"/magazine-files": {
"get": {
"security": [
@ -16619,6 +16992,56 @@
}
}
},
"request.KnowledgeBaseUpdateRequest": {
"type": "object",
"required": [
"agentId",
"agentName",
"id",
"status",
"title"
],
"properties": {
"agentId": {
"type": "string"
},
"agentName": {
"type": "string"
},
"fileAudioUrl": {
"type": "string"
},
"fileJournalUrl": {
"type": "string"
},
"fileVideoUrl": {
"type": "string"
},
"id": {
"type": "integer"
},
"isActive": {
"type": "boolean"
},
"status": {
"type": "integer"
},
"title": {
"type": "string"
}
}
},
"request.KnowledgeBaseUpdateStatusRequest": {
"type": "object",
"required": [
"status"
],
"properties": {
"status": {
"type": "integer"
}
}
},
"request.MagazinesCreateRequest": {
"type": "object",
"required": [

View File

@ -812,6 +812,40 @@ definitions:
- id
- message
type: object
request.KnowledgeBaseUpdateRequest:
properties:
agentId:
type: string
agentName:
type: string
fileAudioUrl:
type: string
fileJournalUrl:
type: string
fileVideoUrl:
type: string
id:
type: integer
isActive:
type: boolean
status:
type: integer
title:
type: string
required:
- agentId
- agentName
- id
- status
- title
type: object
request.KnowledgeBaseUpdateStatusRequest:
properties:
status:
type: integer
required:
- status
type: object
request.MagazinesCreateRequest:
properties:
createdById:
@ -7930,6 +7964,246 @@ paths:
summary: FeedbackMonthlyStats Feedbacks
tags:
- Feedbacks
/knowledge-base:
get:
description: API for getting all KnowledgeBase
parameters:
- description: Agent ID
in: query
name: agentId
type: string
- description: Search title
in: query
name: title
type: string
- description: Status (0=draft,1=published,2=archived)
in: query
name: status
type: integer
- description: Created By ID
in: query
name: createdById
type: integer
- description: Is active
in: query
name: isActive
type: boolean
- description: Page
in: query
name: page
type: integer
- description: Limit
in: query
name: limit
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Get all KnowledgeBase
tags:
- Knowledge Base
post:
consumes:
- multipart/form-data
description: API for creating KnowledgeBase with upload file
parameters:
- description: Insert the X-Csrf-Token
in: header
name: X-Csrf-Token
required: true
type: string
- description: Agent ID
in: formData
name: agentId
required: true
type: string
- description: Agent Name
in: formData
name: agentName
required: true
type: string
- description: Created By ID
in: formData
name: createdById
required: true
type: integer
- description: Status (integer)
in: formData
name: status
required: true
type: integer
- description: Title
in: formData
name: title
required: true
type: string
- description: Upload Journal File
in: formData
name: fileJournal
type: file
- description: Upload Audio File
in: formData
name: fileAudio
type: file
- description: Upload Video File
in: formData
name: fileVideo
type: file
produces:
- application/json
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 KnowledgeBase
tags:
- Knowledge Base
/knowledge-base/{id}:
delete:
description: API for deleting KnowledgeBase (soft delete)
parameters:
- description: Insert the X-Csrf-Token
in: header
name: X-Csrf-Token
required: true
type: string
- description: KnowledgeBase ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Delete KnowledgeBase
tags:
- Knowledge Base
get:
description: API for getting one KnowledgeBase
parameters:
- description: KnowledgeBase ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Get one KnowledgeBase
tags:
- Knowledge Base
put:
description: API for updating KnowledgeBase
parameters:
- description: Insert the X-Csrf-Token
in: header
name: X-Csrf-Token
required: true
type: string
- description: Required payload
in: body
name: payload
required: true
schema:
$ref: '#/definitions/request.KnowledgeBaseUpdateRequest'
- description: KnowledgeBase ID
in: path
name: id
required: true
type: integer
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Update KnowledgeBase
tags:
- Knowledge Base
/knowledge-base/{id}/status:
patch:
description: API untuk update status KnowledgeBase
parameters:
- description: KnowledgeBase ID
in: path
name: id
required: true
type: integer
- description: Required payload
in: body
name: payload
required: true
schema:
$ref: '#/definitions/request.KnowledgeBaseUpdateStatusRequest'
responses:
"200":
description: OK
schema:
$ref: '#/definitions/response.Response'
security:
- Bearer: []
summary: Update KnowledgeBase Status
tags:
- Knowledge Base
/knowledge-base/viewer/{filename}:
get:
description: API for Viewer KnowledgeBase
parameters:
- description: KnowledgeBase File Name
in: path
name: filename
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: Viewer KnowledgeBase
tags:
- Knowledge Base
/magazine-files:
get:
description: API for getting all MagazineFiles

View File

@ -20,6 +20,7 @@ import (
"narasi-ahli-be/app/module/ebooks"
"narasi-ahli-be/app/module/education_history"
"narasi-ahli-be/app/module/feedbacks"
"narasi-ahli-be/app/module/knowledge_base"
"narasi-ahli-be/app/module/magazine_files"
"narasi-ahli-be/app/module/magazines"
"narasi-ahli-be/app/module/master_menus"
@ -70,6 +71,7 @@ func main() {
activity_logs.NewActivityLogsModule,
advertisement.NewAdvertisementModule,
ai_chat.NewAIChatModule,
knowledge_base.NewKnowledgeBaseModule,
article_categories.NewArticleCategoriesModule,
article_category_details.NewArticleCategoryDetailsModule,
article_files.NewArticleFilesModule,