- Rearranged and updated API endpoints for collections, including adding GetCollections and adjusting the order of operations for better clarity. - Enhanced segment management by introducing new endpoints for segment scores, weights, and votes, along with async operations for adding and updating segments. - Improved error handling for missing document IDs in segment-related functions, ensuring robust validation. - Streamlined response structures to include document and segment IDs in relevant endpoints, enhancing the API's usability.
356 lines
9.6 KiB
Go
356 lines
9.6 KiB
Go
package kb
|
|
|
|
import (
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/yaoapp/yao/openapi/response"
|
|
)
|
|
|
|
// Vote Management Handlers
|
|
|
|
// ScrollVotes scrolls votes with iterator-style pagination for a specific segment
|
|
func ScrollVotes(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Parse query parameters for scroll options
|
|
options := map[string]interface{}{
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"limit": 100, // Default limit
|
|
}
|
|
|
|
// Parse limit (default: 100)
|
|
if limitStr := c.Query("limit"); limitStr != "" {
|
|
if limit, err := strconv.Atoi(limitStr); err == nil && limit > 0 {
|
|
options["limit"] = limit
|
|
}
|
|
}
|
|
|
|
// Parse scroll_id parameter for continuing pagination
|
|
if scrollID := strings.TrimSpace(c.Query("scroll_id")); scrollID != "" {
|
|
options["scroll_id"] = scrollID
|
|
}
|
|
|
|
// Parse order_by parameter
|
|
if orderBy := strings.TrimSpace(c.Query("order_by")); orderBy != "" {
|
|
orderByFields := strings.Split(orderBy, ",")
|
|
// Trim spaces from each field
|
|
for i, field := range orderByFields {
|
|
orderByFields[i] = strings.TrimSpace(field)
|
|
}
|
|
options["order_by"] = orderByFields
|
|
}
|
|
|
|
// Parse filter parameters
|
|
filter := make(map[string]interface{})
|
|
if voteType := c.Query("vote_type"); voteType != "" {
|
|
filter["vote_type"] = voteType
|
|
}
|
|
if userID := c.Query("user_id"); userID != "" {
|
|
filter["user_id"] = userID
|
|
}
|
|
if len(filter) > 0 {
|
|
options["filter"] = filter
|
|
}
|
|
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement scroll votes logic with GraphRag or database
|
|
// TODO: Call kb.Instance.ScrollVotes(c.Request.Context(), segmentID, options)
|
|
|
|
// Return mock response for now
|
|
result := gin.H{
|
|
"votes": []interface{}{},
|
|
"scroll_id": nil,
|
|
"has_more": false,
|
|
"total": 0,
|
|
"options": options,
|
|
}
|
|
|
|
response.RespondWithSuccess(c, response.StatusOK, result)
|
|
}
|
|
|
|
// GetVotes gets votes for a specific segment (simple list, no pagination)
|
|
func GetVotes(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Parse basic filter parameters
|
|
filter := make(map[string]interface{})
|
|
if voteType := c.Query("vote_type"); voteType != "" {
|
|
filter["vote_type"] = voteType
|
|
}
|
|
if userID := c.Query("user_id"); userID != "" {
|
|
filter["user_id"] = userID
|
|
}
|
|
|
|
// Parse limit parameter (optional, for basic limiting without pagination)
|
|
var limit int
|
|
if limitStr := c.Query("limit"); limitStr != "" {
|
|
if l, err := strconv.Atoi(limitStr); err == nil && l > 0 {
|
|
limit = l
|
|
}
|
|
}
|
|
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement get votes logic (simple query without pagination)
|
|
// TODO: Call kb.Instance.GetVotes(c.Request.Context(), segmentID, filter, limit)
|
|
|
|
// Return mock response for now
|
|
result := gin.H{
|
|
"votes": []interface{}{},
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"total": 0,
|
|
}
|
|
|
|
if len(filter) > 0 {
|
|
result["filter"] = filter
|
|
}
|
|
if limit > 0 {
|
|
result["limit"] = limit
|
|
}
|
|
|
|
response.RespondWithSuccess(c, response.StatusOK, result)
|
|
}
|
|
|
|
// GetVote gets a specific vote by ID
|
|
func GetVote(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract voteID from URL path
|
|
voteID := c.Param("voteID")
|
|
if voteID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Vote ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement get vote detail logic
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"vote": nil,
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"vote_id": voteID,
|
|
})
|
|
}
|
|
|
|
// AddVotes adds new votes to a segment
|
|
func AddVotes(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement add vote logic
|
|
c.JSON(http.StatusOK, gin.H{
|
|
"message": "Vote added successfully",
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"vote_id": "placeholder-vote-id",
|
|
})
|
|
}
|
|
|
|
// UpdateVotes updates votes in batch
|
|
func UpdateVotes(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Parse vote_ids from query parameter or request body
|
|
var voteIDs []string
|
|
|
|
// Try query parameter first (comma-separated)
|
|
if voteIDsParam := strings.TrimSpace(c.Query("vote_ids")); voteIDsParam != "" {
|
|
voteIDs = strings.Split(voteIDsParam, ",")
|
|
for i, id := range voteIDs {
|
|
voteIDs[i] = strings.TrimSpace(id)
|
|
}
|
|
}
|
|
|
|
// TODO: Also support request body with vote data for batch updates
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement batch update vote logic
|
|
|
|
result := gin.H{
|
|
"message": "Votes updated successfully",
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"updated_count": len(voteIDs),
|
|
}
|
|
|
|
if len(voteIDs) > 0 {
|
|
result["vote_ids"] = voteIDs
|
|
}
|
|
|
|
response.RespondWithSuccess(c, response.StatusOK, result)
|
|
}
|
|
|
|
// RemoveVotes removes votes from a segment in batch
|
|
func RemoveVotes(c *gin.Context) {
|
|
// Extract docID from URL path
|
|
docID := c.Param("docID")
|
|
if docID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Document ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Extract segmentID from URL path
|
|
segmentID := c.Param("segmentID")
|
|
if segmentID == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "Segment ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Parse vote_ids from query parameter (comma-separated)
|
|
voteIDsParam := strings.TrimSpace(c.Query("vote_ids"))
|
|
if voteIDsParam == "" {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "vote_ids query parameter is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// Split comma-separated vote IDs
|
|
voteIDs := strings.Split(voteIDsParam, ",")
|
|
var validVoteIDs []string
|
|
for _, id := range voteIDs {
|
|
id = strings.TrimSpace(id)
|
|
if id != "" {
|
|
validVoteIDs = append(validVoteIDs, id)
|
|
}
|
|
}
|
|
|
|
if len(validVoteIDs) == 0 {
|
|
errorResp := &response.ErrorResponse{
|
|
Code: response.ErrInvalidRequest.Code,
|
|
ErrorDescription: "At least one valid vote ID is required",
|
|
}
|
|
response.RespondWithError(c, response.StatusBadRequest, errorResp)
|
|
return
|
|
}
|
|
|
|
// TODO: Implement document permission validation for docID
|
|
// TODO: Implement batch remove vote logic
|
|
|
|
result := gin.H{
|
|
"message": "Votes removed successfully",
|
|
"document_id": docID,
|
|
"segment_id": segmentID,
|
|
"vote_ids": validVoteIDs,
|
|
"removed_count": len(validVoteIDs),
|
|
}
|
|
|
|
response.RespondWithSuccess(c, response.StatusOK, result)
|
|
}
|