diff --git a/app/module/knowledge_base/mapper/knowledge_base.mapper.go b/app/module/knowledge_base/mapper/knowledge_base.mapper.go index 1b7d6da..6d99cea 100644 --- a/app/module/knowledge_base/mapper/knowledge_base.mapper.go +++ b/app/module/knowledge_base/mapper/knowledge_base.mapper.go @@ -9,6 +9,7 @@ func KnowledgeBaseResponseMapper(kb *entity.KnowledgeBase, host string) (out *re if kb == nil { return nil } + out = &res.KnowledgeBaseResponse{ ID: kb.ID, diff --git a/app/module/knowledge_base/repository/knowledge_base.repository.go b/app/module/knowledge_base/repository/knowledge_base.repository.go index d29bea0..73f4c25 100644 --- a/app/module/knowledge_base/repository/knowledge_base.repository.go +++ b/app/module/knowledge_base/repository/knowledge_base.repository.go @@ -118,31 +118,26 @@ 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) +func (r *KnowledgeBaseRepository) FindByFilename(filename string) (*entity.KnowledgeBase, string, error) { - // 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 + + if err := r.DB.DB.Where("file_journal_url LIKE ?", "%"+filename).First(&kb).Error; err == nil { + return &kb, *kb.FileJournalUrl, nil } - // audio - if err := query.Where("file_audio_url LIKE ?", like).First(&kb).Error; err == nil { - return &kb, "audio", nil + if err := r.DB.DB.Where("file_audio_url LIKE ?", "%"+filename).First(&kb).Error; err == nil { + return &kb, *kb.FileAudioUrl, nil } - // video - if err := query.Where("file_video_url LIKE ?", like).First(&kb).Error; err == nil { - return &kb, "video", nil + if err := r.DB.DB.Where("file_video_url LIKE ?", "%"+filename).First(&kb).Error; err == nil { + return &kb, *kb.FileVideoUrl, nil } return nil, "", fmt.Errorf("file not found") } + func (r *KnowledgeBaseRepository) UpdateDocumentId(id uint, documentId int) error { return r.DB.DB.Model(&entity.KnowledgeBase{}). Where("id = ?", id). diff --git a/app/module/knowledge_base/service/knowledge_base.service.go b/app/module/knowledge_base/service/knowledge_base.service.go index e5d555f..109330e 100644 --- a/app/module/knowledge_base/service/knowledge_base.service.go +++ b/app/module/knowledge_base/service/knowledge_base.service.go @@ -3,7 +3,6 @@ package service import ( "context" "fmt" - "io" "mime" "mime/multipart" "narasi-ahli-be/app/module/knowledge_base/mapper" @@ -64,7 +63,6 @@ func (s *KnowledgeBaseService) uploadFileToMinio( minioClient *minio.Client, bucketName string, agentId string, - folder string, fileHeader *multipart.FileHeader, ) (*string, error) { @@ -87,10 +85,10 @@ func (s *KnowledgeBaseService) uploadFileToMinio( now := time.Now() newFilename := fmt.Sprintf("%s_%d%s", filenameWithoutExt, now.UnixNano(), ext) + // ⭐ INI PATH ASLI MINIO objectName := fmt.Sprintf( - "knowledge-base/%s/%s/%s", + "knowledge-base/%s/%s", agentId, - folder, newFilename, ) @@ -100,15 +98,19 @@ func (s *KnowledgeBaseService) uploadFileToMinio( objectName, src, fileHeader.Size, - minio.PutObjectOptions{}, + minio.PutObjectOptions{ + ContentType: fileHeader.Header.Get("Content-Type"), + }, ) if err != nil { return nil, err } - return &newFilename, nil + // ⭐ KEMBALIKAN OBJECT PATH + return &objectName, nil } + func (s *KnowledgeBaseService) All(req request.KnowledgeBaseQueryRequest) (data []*response.KnowledgeBaseResponse, paging paginator.Pagination, err error) { results, paging, err := s.Repo.GetAll(req) @@ -134,52 +136,55 @@ func getFileExtension(filename string) string { return parts[len(parts)-1] } -func (s *KnowledgeBaseService) Viewer(c *fiber.Ctx) (err error) { +func (s *KnowledgeBaseService) Viewer(c *fiber.Ctx) error { filename := c.Params("filename") - result, folder, err := s.Repo.FindByFilename(filename) + _, objectName, err := s.Repo.FindByFilename(filename) if err != nil { - return err + return c.Status(404).SendString("file not found") } 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(), - }) + return c.Status(500).SendString(err.Error()) } - fileContent, err := minioClient.GetObject(ctx, bucketName, objectName, minio.GetObjectOptions{}) + opts := minio.GetObjectOptions{} + + // support video streaming + if rangeHeader := c.Get("Range"); rangeHeader != "" { + opts.Set("Range", rangeHeader) + c.Status(fiber.StatusPartialContent) + c.Set("Accept-Ranges", "bytes") + } + + object, err := minioClient.GetObject(ctx, bucketName, objectName, opts) if err != nil { - return err + return c.Status(404).SendString("file not found") } - defer fileContent.Close() + defer object.Close() - contentType := mime.TypeByExtension("." + getFileExtension(objectName)) + stat, err := object.Stat() + if err != nil { + return c.Status(404).SendString("file not found") + } + + contentType := stat.ContentType if contentType == "" { - contentType = "application/octet-stream" + contentType = mime.TypeByExtension(filepath.Ext(objectName)) } + c.Set("Content-Type", contentType) + c.Set("Content-Disposition", "inline") - if _, err := io.Copy(c.Response().BodyWriter(), fileContent); err != nil { - return err - } - - return nil + return c.SendStream(object) } + + func (s *KnowledgeBaseService) Show(id uint) (data *response.KnowledgeBaseResponse, err error) { result, err := s.Repo.FindOne(id) if err != nil { @@ -218,35 +223,18 @@ func (s *KnowledgeBaseService) Create(c *fiber.Ctx) (data *response.KnowledgeBas 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 - } + journalPath, _ := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, fileJournal) +audioPath, _ := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, fileAudio) +videoPath, _ := s.uploadFileToMinio(ctx, minioClient, bucketName, *req.AgentId, fileVideo) - entity := req.ToEntity() +entity := req.ToEntity() - viewerBase := s.Cfg.App.Domain + "/knowledge-base/viewer/" +entity.FileJournalUrl = journalPath +entity.FileAudioUrl = audioPath +entity.FileVideoUrl = videoPath - 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