mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-10 21:55:42 +08:00
Fix Tag weight should be greater than 0 (#16657)
This commit is contained in:
@@ -76,10 +76,10 @@ def validate_tag_features(raw):
|
||||
if not key:
|
||||
raise ValueError("keys must be non-empty strings")
|
||||
if isinstance(value, bool) or not isinstance(value, (int, float)):
|
||||
raise ValueError("values must be finite numbers")
|
||||
raise ValueError("values must be finite numbers greater than 0")
|
||||
numeric = float(value)
|
||||
if not math.isfinite(numeric):
|
||||
raise ValueError("values must be finite numbers")
|
||||
if not math.isfinite(numeric) or numeric <= 0:
|
||||
raise ValueError("values must be finite numbers greater than 0")
|
||||
cleaned[key] = numeric
|
||||
|
||||
return cleaned
|
||||
|
||||
@@ -719,6 +719,19 @@ func (h *ChunkHandler) UpdateChunk(c *gin.Context) {
|
||||
|
||||
err := h.chunkService.UpdateChunk(&req, user.ID)
|
||||
if err != nil {
|
||||
var coded interface {
|
||||
Code() common.ErrorCode
|
||||
}
|
||||
if errors.As(err, &coded) {
|
||||
switch coded.Code() {
|
||||
case common.CodeArgumentError, common.CodeBadRequest, common.CodeDataError:
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"code": coded.Code(),
|
||||
"message": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
}
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"code": 500,
|
||||
"message": err.Error(),
|
||||
|
||||
@@ -27,6 +27,19 @@ type mockChunkSvc struct {
|
||||
stopParsingFn func(userID, datasetID string, req service.StopParsingRequest) (*service.StopParsingResponse, common.ErrorCode, error)
|
||||
}
|
||||
|
||||
type codedTestError struct {
|
||||
code common.ErrorCode
|
||||
msg string
|
||||
}
|
||||
|
||||
func (e codedTestError) Error() string {
|
||||
return e.msg
|
||||
}
|
||||
|
||||
func (e codedTestError) Code() common.ErrorCode {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (m *mockChunkSvc) RetrievalTest(req *service.RetrievalTestRequest, userID string) (*service.RetrievalTestResponse, error) {
|
||||
if m.retrievalTestFn != nil {
|
||||
return m.retrievalTestFn(req, userID)
|
||||
@@ -276,6 +289,25 @@ func TestChunkHandlerUpdateChunkUsesPathIDs(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestChunkHandlerUpdateChunkValidationErrorIsBadRequest(t *testing.T) {
|
||||
mock := &mockChunkSvc{}
|
||||
r, h := setupChunkHandlerWithUser("user-1", mock)
|
||||
r.PATCH("/api/v1/datasets/:dataset_id/documents/:document_id/chunks/:chunk_id", h.UpdateChunk)
|
||||
|
||||
mock.updateChunkFn = func(req *service.UpdateChunkRequest, userID string) error {
|
||||
return codedTestError{code: common.CodeArgumentError, msg: "`tag_feas` values must be finite numbers greater than 0"}
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodPatch, "/api/v1/datasets/kb-1/documents/doc-1/chunks/chunk-1", strings.NewReader(`{"tag_feas":{"tag":0}}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
r.ServeHTTP(w, req)
|
||||
|
||||
if w.Code != http.StatusBadRequest {
|
||||
t.Fatalf("status = %d, body = %s", w.Code, w.Body.String())
|
||||
}
|
||||
}
|
||||
|
||||
func TestChunkRetrieval_EmptyQuestion(t *testing.T) {
|
||||
r, _ := setupChunkRetrievalTest("user1")
|
||||
|
||||
|
||||
@@ -1682,7 +1682,11 @@ func (s *ChunkService) UpdateChunk(req *service.UpdateChunkRequest, userID strin
|
||||
|
||||
// Tag features
|
||||
if req.TagFeas != nil {
|
||||
d["tag_feas"] = req.TagFeas
|
||||
tagFeas, err := validateTagFeatures(req.TagFeas)
|
||||
if err != nil {
|
||||
return updateChunkError{code: common.CodeArgumentError, message: "`tag_feas` " + err.Error()}
|
||||
}
|
||||
d["tag_feas"] = tagFeas
|
||||
}
|
||||
|
||||
// Always include id
|
||||
@@ -1932,6 +1936,19 @@ type addChunkError struct {
|
||||
message string
|
||||
}
|
||||
|
||||
type updateChunkError struct {
|
||||
code common.ErrorCode
|
||||
message string
|
||||
}
|
||||
|
||||
func (e updateChunkError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e updateChunkError) Code() common.ErrorCode {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func (e addChunkError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
@@ -1953,27 +1970,42 @@ func validateTagFeatures(raw interface{}) (map[string]float64, error) {
|
||||
}
|
||||
switch typed := value.(type) {
|
||||
case float64:
|
||||
if math.IsNaN(typed) || math.IsInf(typed, 0) {
|
||||
return nil, fmt.Errorf("values must be finite numbers")
|
||||
if math.IsNaN(typed) || math.IsInf(typed, 0) || typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = typed
|
||||
case float32:
|
||||
if math.IsNaN(float64(typed)) || math.IsInf(float64(typed), 0) {
|
||||
return nil, fmt.Errorf("values must be finite numbers")
|
||||
if math.IsNaN(float64(typed)) || math.IsInf(float64(typed), 0) || typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
case int:
|
||||
if typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
case int8:
|
||||
if typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
case int16:
|
||||
if typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
case int32:
|
||||
if typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
case int64:
|
||||
if typed <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = float64(typed)
|
||||
default:
|
||||
return nil, fmt.Errorf("values must be finite numbers")
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
}
|
||||
return cleaned, nil
|
||||
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math"
|
||||
"ragflow/internal/common"
|
||||
"ragflow/internal/engine/redis"
|
||||
"ragflow/internal/entity"
|
||||
@@ -636,7 +637,11 @@ func (s *ChunkService) UpdateChunk(req *UpdateChunkRequest, userID string) error
|
||||
|
||||
// Tag features
|
||||
if req.TagFeas != nil {
|
||||
d["tag_feas"] = req.TagFeas
|
||||
tagFeas, err := validateUpdateTagFeatures(req.TagFeas)
|
||||
if err != nil {
|
||||
return updateChunkError{code: common.CodeArgumentError, message: "`tag_feas` " + err.Error()}
|
||||
}
|
||||
d["tag_feas"] = tagFeas
|
||||
}
|
||||
|
||||
// Always include id
|
||||
@@ -655,6 +660,57 @@ func (s *ChunkService) UpdateChunk(req *UpdateChunkRequest, userID string) error
|
||||
return nil
|
||||
}
|
||||
|
||||
type updateChunkError struct {
|
||||
code common.ErrorCode
|
||||
message string
|
||||
}
|
||||
|
||||
func (e updateChunkError) Error() string {
|
||||
return e.message
|
||||
}
|
||||
|
||||
func (e updateChunkError) Code() common.ErrorCode {
|
||||
return e.code
|
||||
}
|
||||
|
||||
func validateUpdateTagFeatures(raw interface{}) (map[string]float64, error) {
|
||||
parsed, ok := raw.(map[string]interface{})
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("must be an object mapping string tags to finite numeric scores greater than 0")
|
||||
}
|
||||
cleaned := make(map[string]float64, len(parsed))
|
||||
for key, value := range parsed {
|
||||
key = strings.TrimSpace(key)
|
||||
if key == "" {
|
||||
return nil, fmt.Errorf("keys must be non-empty strings")
|
||||
}
|
||||
var numeric float64
|
||||
switch typed := value.(type) {
|
||||
case float64:
|
||||
numeric = typed
|
||||
case float32:
|
||||
numeric = float64(typed)
|
||||
case int:
|
||||
numeric = float64(typed)
|
||||
case int8:
|
||||
numeric = float64(typed)
|
||||
case int16:
|
||||
numeric = float64(typed)
|
||||
case int32:
|
||||
numeric = float64(typed)
|
||||
case int64:
|
||||
numeric = float64(typed)
|
||||
default:
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
if math.IsNaN(numeric) || math.IsInf(numeric, 0) || numeric <= 0 {
|
||||
return nil, fmt.Errorf("values must be finite numbers greater than 0")
|
||||
}
|
||||
cleaned[key] = numeric
|
||||
}
|
||||
return cleaned, nil
|
||||
}
|
||||
|
||||
// RemoveChunksRequest request for removing chunks
|
||||
type RemoveChunksRequest struct {
|
||||
DocID string `json:"doc_id"`
|
||||
|
||||
@@ -107,7 +107,7 @@ export const TagFeatureItem = () => {
|
||||
'knowledgeConfiguration.frequency',
|
||||
)}
|
||||
max={10}
|
||||
min={0}
|
||||
min={1}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -125,7 +125,7 @@ export const TagFeatureItem = () => {
|
||||
<Button
|
||||
variant="dashed"
|
||||
className="w-full flex items-center justify-center gap-2"
|
||||
onClick={() => append({ tag: '', frequency: 0 })}
|
||||
onClick={() => append({ tag: '', frequency: 1 })}
|
||||
>
|
||||
<Plus size={16} />
|
||||
{t('knowledgeConfiguration.addTag')}
|
||||
|
||||
@@ -107,7 +107,7 @@ export const TagFeatureItem = () => {
|
||||
'knowledgeConfiguration.frequency',
|
||||
)}
|
||||
max={10}
|
||||
min={0}
|
||||
min={1}
|
||||
/>
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
@@ -125,7 +125,7 @@ export const TagFeatureItem = () => {
|
||||
<Button
|
||||
variant="dashed"
|
||||
className="w-full flex items-center justify-center gap-2"
|
||||
onClick={() => append({ tag: '', frequency: 0 })}
|
||||
onClick={() => append({ tag: '', frequency: 1 })}
|
||||
>
|
||||
<Plus size={16} />
|
||||
{t('knowledgeConfiguration.addTag')}
|
||||
|
||||
Reference in New Issue
Block a user