diff --git a/internal/api/handler.go b/internal/api/handler.go index af720a7..3200b26 100644 --- a/internal/api/handler.go +++ b/internal/api/handler.go @@ -260,6 +260,26 @@ func (h *Handler) StartPaperIngest(c *gin.Context) { c.JSON(http.StatusAccepted, job) } +func (h *Handler) ReindexPaper(c *gin.Context) { + id := strings.TrimSpace(c.Param("id")) + if id == "" { + writeError(c, http.StatusBadRequest, errors.New("id is required")) + return + } + + optCtx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + if err := h.ingest.ReindexPaper(optCtx, id); err != nil { + writeError(c, http.StatusInternalServerError, err) + return + } + c.JSON(http.StatusOK, gin.H{ + "paper_id": id, + "status": "reindexed", + }) +} + func (h *Handler) GetTask(c *gin.Context) { id := c.Param("id") diff --git a/internal/api/router.go b/internal/api/router.go index a34f6cb..f4d43e8 100644 --- a/internal/api/router.go +++ b/internal/api/router.go @@ -49,7 +49,7 @@ func NewRouter(opts RouterOptions) http.Handler { papers.GET("/:id/download", h.DownloadPaper) papers.GET("/:id/chunks", h.ListPaperChunks) papers.POST("/:id/ingest", h.StartPaperIngest) - papers.POST("/:id/reindex") + papers.POST("/:id/reindex", h.ReindexPaper) } tasks := v1.Group("/tasks") diff --git a/internal/ingest/service.go b/internal/ingest/service.go index 4aaf71b..9fd8150 100644 --- a/internal/ingest/service.go +++ b/internal/ingest/service.go @@ -250,3 +250,35 @@ func parsedMarkdown(paper domain.Paper, doc docparser.Document) string { return b.String() } + +func (s *Service) ReindexPaper(ctx context.Context, paperID string) error { + if s.search == nil { + return fmt.Errorf("search backend is not initialized") + } + + paperID = strings.TrimSpace(paperID) + if paperID == "" { + return fmt.Errorf("paperID cannot be empty") + } + + // get chunks + chunks, err := s.chunks.ListByPaperID(ctx, paperID) + if err != nil { + return fmt.Errorf("get chunks by paperID: %w", err) + } + + if len(chunks) == 0 { + return fmt.Errorf("paper %s has no chunks", paperID) + } + + // delete first, update next + if err := s.search.DeleteByPaperID(ctx, paperID); err != nil { + return fmt.Errorf("delete chunks by paperID: %w", err) + } + + if err := s.search.IndexChunks(ctx, chunks); err != nil { + return fmt.Errorf("replace chunks by paperID: %w", err) + } + + return nil +}