2026-07-20 09:48:24 +08:00
package document
import (
"context"
"errors"
"fmt"
"math"
"path/filepath"
"ragflow/internal/service"
"strconv"
"strings"
"ragflow/internal/common"
"ragflow/internal/dao"
"ragflow/internal/entity"
pipelinepkg "ragflow/internal/ingestion/pipeline"
"ragflow/internal/tokenizer"
"go.uber.org/zap"
)
2026-07-24 16:47:12 +08:00
func ( s * DocumentService ) BatchUpdateDocumentStatus ( ctx context . Context , userID , datasetID , status string , documentIDs [ ] string ) ( map [ string ] interface { } , common . ErrorCode , error ) {
2026-07-27 10:20:16 +08:00
kb , err := s . kbDAO . GetByIDAndTenantID ( ctx , dao . DB , datasetID , userID )
2026-07-20 09:48:24 +08:00
if err != nil {
2026-07-28 19:05:59 +08:00
return nil , common . CodeDataError , fmt . Errorf ( "you don't own the dataset" )
2026-07-20 09:48:24 +08:00
}
statusInt , convErr := strconv . Atoi ( status )
if convErr != nil {
return nil , common . CodeArgumentError , fmt . Errorf ( "invalid status: %s" , status )
}
result := make ( map [ string ] interface { } , len ( documentIDs ) )
hasError := false
2026-07-24 16:47:12 +08:00
documents , err := s . documentDAO . GetByIDs ( ctx , dao . DB , documentIDs )
2026-07-20 09:48:24 +08:00
if err != nil {
return nil , common . CodeServerError , fmt . Errorf ( "failed to fetch documents: %w" , err )
}
documentByID := make ( map [ string ] * entity . Document , len ( documents ) )
for _ , doc := range documents {
documentByID [ doc . ID ] = doc
}
for _ , docID := range documentIDs {
doc , ok := documentByID [ docID ]
if ! ok {
result [ docID ] = map [ string ] string { "error" : "Document not found" }
hasError = true
continue
}
if doc . KbID != datasetID {
result [ docID ] = map [ string ] string { "error" : "Document not found in this dataset." }
hasError = true
continue
}
currentStatus := ""
if doc . Status != nil {
currentStatus = * doc . Status
}
if currentStatus == status {
result [ docID ] = map [ string ] string { "status" : status }
continue
}
previousStatus := interface { } ( nil )
if doc . Status != nil {
previousStatus = * doc . Status
}
2026-07-24 16:47:12 +08:00
if err = s . documentDAO . UpdateByID ( ctx , dao . DB , docID , map [ string ] interface { } { "status" : status } ) ; err != nil {
2026-07-20 09:48:24 +08:00
result [ docID ] = map [ string ] string { "error" : "Database error (Document update)!" }
hasError = true
continue
}
if doc . ChunkNum > 0 {
if s . docEngine == nil {
2026-07-24 16:47:12 +08:00
_ = s . documentDAO . UpdateByID ( ctx , dao . DB , docID , map [ string ] interface { } { "status" : previousStatus } )
2026-07-20 09:48:24 +08:00
result [ docID ] = map [ string ] string { "error" : "Document store update failed: document engine not initialized" }
hasError = true
continue
}
err := s . docEngine . UpdateChunks (
context . Background ( ) ,
map [ string ] interface { } { "doc_id" : docID } ,
map [ string ] interface { } { "available_int" : statusInt } ,
fmt . Sprintf ( "ragflow_%s" , kb . TenantID ) ,
doc . KbID ,
)
if err != nil {
2026-07-24 16:47:12 +08:00
_ = s . documentDAO . UpdateByID ( ctx , dao . DB , docID , map [ string ] interface { } { "status" : previousStatus } )
2026-07-20 09:48:24 +08:00
msg := err . Error ( )
if strings . Contains ( msg , "3022" ) {
result [ docID ] = map [ string ] string { "error" : "Document store table missing." }
} else {
result [ docID ] = map [ string ] string { "error" : "Document store update failed: " + msg }
}
hasError = true
continue
}
}
result [ docID ] = map [ string ] string { "status" : status }
}
if hasError {
2026-07-24 16:47:12 +08:00
return result , common . CodeServerError , fmt . Errorf ( "partial failure" )
2026-07-20 09:48:24 +08:00
}
return result , common . CodeSuccess , nil
}
2026-07-24 16:47:12 +08:00
func ( s * DocumentService ) UpdateDatasetDocument ( ctx context . Context , userID , datasetID , documentID string , req * UpdateDatasetDocumentRequest , present map [ string ] bool ) ( * UpdateDatasetDocumentResponse , common . ErrorCode , error ) {
2026-07-20 09:48:24 +08:00
tenantID := userID
2026-07-27 10:20:16 +08:00
kb , err := s . kbDAO . GetByIDAndTenantID ( ctx , dao . DB , datasetID , tenantID )
2026-07-20 09:48:24 +08:00
if err != nil {
if dao . IsNotFoundErr ( err ) {
2026-07-28 19:05:59 +08:00
return nil , common . CodeDataError , errors . New ( "you don't own the dataset" )
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
return nil , common . CodeDataError , errors . New ( "can't find this dataset" )
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
doc , err := s . documentDAO . GetByDocumentIDAndDatasetID ( ctx , dao . DB , documentID , datasetID )
2026-07-20 09:48:24 +08:00
if err != nil {
if dao . IsNotFoundErr ( err ) {
2026-07-28 19:05:59 +08:00
return nil , common . CodeDataError , errors . New ( "the dataset doesn't own the document" )
2026-07-20 09:48:24 +08:00
}
return nil , common . CodeServerError , err
}
2026-07-24 16:47:12 +08:00
if code , err := s . validateDatasetDocumentUpdate ( ctx , datasetID , documentID , userID , doc , req , present ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , code , err
}
if present [ "meta_fields" ] {
2026-07-24 16:47:12 +08:00
if err = s . replaceDocumentMetadata ( ctx , documentID , req . MetaFields ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , common . CodeDataError , err
}
}
if present [ "name" ] && req . Name != nil && ( doc . Name == nil || * req . Name != * doc . Name ) {
2026-07-24 16:47:12 +08:00
if err = s . updateDocumentNameOnly ( ctx , doc , kb . TenantID , * req . Name ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , common . CodeDataError , err
}
}
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
// Resolve the effective parse mode once: parse_type is authoritative when
// present, otherwise inherit the dataset's current mode. Both the
// parser_config cleaning and the reparse targeting derive from this single
// resolution so they can never disagree. (See service.ResolveParseMode.)
isPipeline , effParserID , effPipelineID := service . ResolveParseMode (
req . ParseType , req . ParserID , req . PipelineID ,
service . ParseModeState { ParserID : kb . ParserID , PipelineID : kb . PipelineID } )
2026-07-20 09:48:24 +08:00
if present [ "parser_config" ] && req . ParserConfig != nil {
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
// Normalize "pages" ranges before persistence. Invalid ranges are
// rejected (fail-fast) — the request is aborted with a clear error.
2026-07-24 16:47:12 +08:00
if err = pipelinepkg . NormalizeParserConfigPages ( req . ParserConfig ) ; err != nil {
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
return nil , common . CodeDataError , err
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
var dslJSON [ ] byte
2026-07-28 19:05:59 +08:00
dslJSON , err = service . LoadPipelineDSL ( ctx , isPipeline , effParserID , effPipelineID )
2026-07-20 09:48:24 +08:00
if err != nil {
common . Warn ( "cleanAndUpdateDocumentParserConfig: failed to load DSL, falling back to merge" ,
zap . Error ( err ) )
2026-07-24 16:47:12 +08:00
if err = s . updateDocumentParserConfig ( ctx , doc . ID , req . ParserConfig ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , common . CodeDataError , err
}
} else {
2026-07-24 16:47:12 +08:00
cleaned := pipelinepkg . BuildParserConfig ( dslJSON , req . ParserConfig )
if err = s . documentDAO . UpdateByID ( ctx , dao . DB , doc . ID , map [ string ] interface { } {
2026-07-20 09:48:24 +08:00
"parser_config" : cleaned ,
} ) ; err != nil {
return nil , common . CodeDataError , err
}
}
}
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
// Apply parser_id / pipeline_id changes. parse_type is validated earlier
// (in validateDatasetDocumentUpdate); reparse only fires when parse_type
// explicitly selects a mode. The mode direction comes from the same
// isPipeline resolution above.
var reparseParserID , reparsePipelineID * string
if req . ParseType != nil {
switch {
case ! isPipeline : // BuiltIn
if present [ "parser_id" ] && req . ParserID != nil {
if p := strings . TrimSpace ( * req . ParserID ) ; p != "" {
reparseParserID = & p
}
2026-07-20 09:48:24 +08:00
}
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
// Drop any prior canvas so the worker falls back to the builtin template.
2026-07-20 09:48:24 +08:00
empty := ""
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
reparsePipelineID = & empty
case isPipeline : // Pipeline
if present [ "pipeline_id" ] && req . PipelineID != nil {
reparsePipelineID = req . PipelineID
2026-07-20 09:48:24 +08:00
}
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
} else if present [ "chunk_method" ] && req . ChunkMethod != nil {
// chunk_method is the public alias for a direct parser change; it does
// not require parse_type (mirrors Python's update_chunk_method).
if p := strings . TrimSpace ( * req . ChunkMethod ) ; ! strings . EqualFold ( p , doc . ParserID ) {
reparseParserID = & p
empty := ""
reparsePipelineID = & empty
} else if doc . PipelineID != nil && * doc . PipelineID != "" {
empty := ""
reparsePipelineID = & empty
}
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
}
if reparseParserID != nil || reparsePipelineID != nil {
2026-07-24 16:47:12 +08:00
if err = s . resetDocumentForReparse ( ctx , doc , kb . TenantID , reparseParserID , reparsePipelineID ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , common . CodeDataError , err
}
}
if present [ "enabled" ] && req . Enabled != nil {
2026-07-24 16:47:12 +08:00
if err = s . updateDocumentStatusOnly ( ctx , doc , kb , * req . Enabled ) ; err != nil {
2026-07-20 09:48:24 +08:00
return nil , common . CodeServerError , err
}
}
2026-07-24 16:47:12 +08:00
updatedDoc , err := s . documentDAO . GetByID ( ctx , dao . DB , doc . ID )
2026-07-20 09:48:24 +08:00
if err != nil {
if dao . IsNotFoundErr ( err ) {
2026-07-24 16:47:12 +08:00
return nil , common . CodeDataError , fmt . Errorf ( "can not get document by id:%s" , doc . ID )
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
return nil , common . CodeDataError , errors . New ( "database operation failed" )
2026-07-20 09:48:24 +08:00
}
metaFields := map [ string ] interface { } { }
if s . docEngine != nil && s . metadataSvc != nil {
2026-07-24 16:47:12 +08:00
metaFields , _ = s . GetDocumentMetadataByID ( ctx , updatedDoc . ID )
2026-07-20 09:48:24 +08:00
}
return s . toUpdateDatasetDocumentResponse ( updatedDoc , metaFields ) , common . CodeSuccess , nil
}
2026-07-24 16:47:12 +08:00
func ( s * DocumentService ) validateDatasetDocumentUpdate ( ctx context . Context , datasetID , documentID , userID string , doc * entity . Document , req * UpdateDatasetDocumentRequest , present map [ string ] bool ) ( common . ErrorCode , error ) {
2026-07-20 09:48:24 +08:00
if req == nil {
2026-07-24 16:47:12 +08:00
return common . CodeDataError , errors . New ( "invalid request payload" )
2026-07-20 09:48:24 +08:00
}
if present [ "chunk_count" ] && req . ChunkCount != nil && * req . ChunkCount != 0 && * req . ChunkCount != doc . ChunkNum {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeDataError , errors . New ( "Can't change `chunk_count`." )
2026-07-20 09:48:24 +08:00
}
if present [ "token_count" ] && req . TokenCount != nil && * req . TokenCount != 0 && * req . TokenCount != doc . TokenNum {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeDataError , errors . New ( "Can't change `token_count`." )
2026-07-20 09:48:24 +08:00
}
2026-07-20 20:02:41 +08:00
if present [ "progress" ] && req . Progress != nil {
if * req . Progress > 1 {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeDataError , fmt . Errorf ( "Field: <progress> - Message: <Input should be less than or equal to 1> - Value: <%s>" , pythonFloatRepr ( * req . Progress ) )
2026-07-20 20:02:41 +08:00
}
if * req . Progress != 0 && math . Abs ( * req . Progress - doc . Progress ) > 1e-9 {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeDataError , errors . New ( "Can't change `progress`." )
2026-07-20 20:02:41 +08:00
}
2026-07-20 09:48:24 +08:00
}
if present [ "enabled" ] {
if req . Enabled == nil || ( * req . Enabled != 0 && * req . Enabled != 1 ) {
return common . CodeDataError , errors . New ( "`enabled` value invalid, only accept 0 or 1" )
}
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
if present [ "chunk_method" ] {
if req . ChunkMethod == nil || strings . TrimSpace ( * req . ChunkMethod ) == "" {
return common . CodeDataError , errors . New ( "`chunk_method` (empty string) is not valid" )
}
cm := strings . TrimSpace ( * req . ChunkMethod )
if ! validDocumentChunkMethods [ cm ] {
return common . CodeDataError , fmt . Errorf ( "Field: <chunk_method> - Message: <`chunk_method` %s doesn't exist> - Value: <%s>" , cm , cm )
}
if ( doc . Type == "visual" && cm != "picture" ) || ( isPresentationFile ( doc . Name ) && cm != "presentation" ) {
return common . CodeDataError , errors . New ( "not supported yet" )
}
}
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
if present [ "parse_type" ] || present [ "parser_id" ] || present [ "pipeline_id" ] {
isBuiltin , _ , err := service . ValidateParseTypeMode ( req . ParseType , req . ParserID , req . PipelineID )
if err != nil {
return common . CodeDataError , err
}
// The parser_id type constraint (visual/presentation) only applies in
// builtin mode — in pipeline mode parser_id is not applicable.
if isBuiltin && present [ "parser_id" ] && req . ParserID != nil {
parserID := strings . TrimSpace ( * req . ParserID )
if ( doc . Type == "visual" && parserID != "picture" ) || ( isPresentationFile ( doc . Name ) && parserID != "presentation" ) {
2026-07-24 16:47:12 +08:00
return common . CodeDataError , errors . New ( "not supported yet" )
feat: parser pages range and parse type validation for dataset/document (#17293)
## Summary
Adds page-range parsing support to the Go-native pipeline path and
introduces strict `parse_type` validation for both dataset and document
update endpoints.
## What changed
### Pages range parsing
- **`internal/utility/pdf_pages.go`** — `NormalizePDFPages`: normalizes
raw page ranges (list of `[from,to]` 1-indexed inclusive ranges) into
sorted, merged, deduplicated `[][]int`. Invalid ranges are dropped.
- **`internal/ingestion/pipeline/pdf_pages.go`** —
`NormalizeParserConfigPages`: walks any parser_config map and normalizes
`"pages"` values under every component → filetype setup, so the
persisted config always carries clean, merged ranges.
- **`internal/deepdoc/parser/pdf/parser.go`** — integrates
`resolvePagesToProcess` to filter parsed PDF pages by the configured
ranges.
- Pipeline integration (parser pages):
`internal/parser/parser/pdf_parser_common.go`, `chunk_process.go`, plus
associated e2e and unit tests.
### Parse type validation (shared logic)
- **`internal/service/parser_mode.go`** (new) — `ValidateParseTypeMode`:
shared function that validates `parse_type` (1=BuiltIn/parser_id,
2=Pipeline/pipeline_id) and ensures the corresponding field is present.
Used by both dataset and document update endpoints.
- **`internal/service/dataset/crud.go`** / `update.go` — replaces inline
`isPipelineMode`/`isBuiltinMode` computation with the shared
`service.ValidateParseTypeMode`.
- **`internal/service/document/document_dataset_update.go`** — adds
strict `parse_type` validation in `validateDatasetDocumentUpdate`,
simplifies the reparse logic to a two-way switch (isBuiltin/isPipeline)
now that parse_type is always valid.
- **`internal/service/document/document.go`** — adds `ParseType` field
to `UpdateDatasetDocumentRequest`.
- **`internal/service/document/document_dataset_update.go`** —
`updateDocumentParserConfig` fallback path when DSL loading fails.
- **`internal/service/parser_mode_test.go`** (new) — test coverage for
nil, invalid, and missing-field scenarios.
### Frontend
- **`web/src/interfaces/request/document.ts`** — adds `parseType` to
`IChangeParserRequestBody`.
- **`web/src/hooks/use-document-request.ts`** —
`useSetDocumentPipelineParser` sends `parse_type` in the PATCH payload.
- **`web/src/pages/dataset/dataset/use-change-document-parser.ts`** —
Go/Python branching for the document parser config dialog.
-
**`web/src/components/document-pipeline-dialog/use-document-pipeline-form.ts`**
— `buildSubmitData` returns `parseType` (bugfix: was dropped from the
return value).
### Test changes
- **Removed**: 2 tests that verified the old "mutually exclusive" error
(replaced by `ValidateParseTypeMode` coverage).
- **Modified**: 6 tests across document and dataset packages to include
`ParseType` in request structs.
- **Added**: new e2e tests for pages parsing (`pages_e2e_test.go`,
`pdf_parser_pages_e2e_test.go`) and unit tests for `NormalizePDFPages`,
`NormalizeParserConfigPages`, `resolvePagesToProcess`.
## Backward compatibility
- The `parse_type` field is **required** when `parser_id` or
`pipeline_id` is sent. This changes the contract for both dataset and
document PATCH endpoints, but aligns the Go backend with the existing
frontend behavior (the frontend already sends `parse_type`). Callers
that omit `parse_type` when updating parser/pipeline selections will
receive a clear error message.
- Existing callers that only update fields like `name`, `enabled`, or
`meta_fields` are unaffected.
- Test updates ensure all known call sites are compliant.
2026-07-23 19:57:27 +08:00
}
2026-07-20 09:48:24 +08:00
}
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
if present [ "name" ] {
// An explicit null name is a type error, not an unset field.
if req . Name == nil {
return common . CodeDataError , errors . New ( "Field: <name> - Message: <Input should be a valid string> - Value: <None>" )
}
if code , err := s . validateDocumentName ( ctx , doc , * req . Name ) ; err != nil {
return code , err
2026-07-20 09:48:24 +08:00
}
}
if present [ "meta_fields" ] {
if err := validateMetaFields ( req . MetaFields ) ; err != nil {
return common . CodeDataError , err
}
}
return common . CodeSuccess , nil
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
// validateDocumentName mirrors Python's validate_document_name: length check
// (101), then extension check (101), then duplicate check (102).
func ( s * DocumentService ) validateDocumentName ( ctx context . Context , doc * entity . Document , newName string ) ( common . ErrorCode , error ) {
2026-07-20 09:48:24 +08:00
if len ( [ ] byte ( newName ) ) > 255 {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeArgumentError , errors . New ( "File name must be 255 bytes or less." )
2026-07-20 09:48:24 +08:00
}
oldName := ""
if doc . Name != nil {
oldName = * doc . Name
}
if strings . ToLower ( filepath . Ext ( newName ) ) != strings . ToLower ( filepath . Ext ( oldName ) ) {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeArgumentError , errors . New ( "The extension of file can't be changed" )
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
docs , err := s . documentDAO . GetByNameAndKBID ( ctx , dao . DB , newName , doc . KbID )
2026-07-20 09:48:24 +08:00
if err != nil {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeServerError , err
2026-07-20 09:48:24 +08:00
}
for _ , d := range docs {
if d . ID != doc . ID && d . Name != nil && * d . Name == newName {
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeDataError , errors . New ( "Duplicated document name in the same dataset." )
2026-07-20 09:48:24 +08:00
}
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return common . CodeSuccess , nil
2026-07-20 09:48:24 +08:00
}
func isPresentationFile ( name * string ) bool {
if name == nil {
return false
}
ext := strings . ToLower ( filepath . Ext ( * name ) )
return ext == ".ppt" || ext == ".pptx" || ext == ".pages"
}
func validateMetaFields ( meta map [ string ] any ) error {
if meta == nil {
return nil
}
for _ , v := range meta {
switch typed := v . ( type ) {
case string , float64 , int , int64 , float32 :
continue
case [ ] any :
for _ , item := range typed {
switch item . ( type ) {
case string , float64 , int , int64 , float32 :
continue
default :
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return fmt . Errorf ( "Field: <meta_fields> - Message: <The type is not supported in list: %s> - Value: <%s>" , pyRepr ( typed ) , pyRepr ( map [ string ] interface { } ( meta ) ) )
2026-07-20 09:48:24 +08:00
}
}
default :
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
return fmt . Errorf ( "Field: <meta_fields> - Message: <The type is not supported: %s> - Value: <%s>" , pyRepr ( v ) , pyRepr ( map [ string ] interface { } ( meta ) ) )
2026-07-20 09:48:24 +08:00
}
}
return nil
}
2026-07-24 16:47:12 +08:00
func ( s * DocumentService ) updateDocumentNameOnly ( ctx context . Context , doc * entity . Document , tenantID , newName string ) error {
if err := s . documentDAO . UpdateByID ( ctx , dao . DB , doc . ID , map [ string ] interface { } { "name" : newName } ) ; err != nil {
return errors . New ( "database error (Document rename)" )
2026-07-20 09:48:24 +08:00
}
2026-07-24 22:00:09 +08:00
mappings , err := s . file2DocumentDAO . GetByDocumentID ( ctx , dao . DB , doc . ID )
2026-07-20 09:48:24 +08:00
if err == nil && len ( mappings ) > 0 && mappings [ 0 ] . FileID != nil && s . fileDAO != nil {
2026-07-24 20:19:41 +08:00
err = s . fileDAO . UpdateByID ( ctx , dao . DB , * mappings [ 0 ] . FileID , map [ string ] interface { } { "name" : newName } )
if err != nil {
return fmt . Errorf ( "file rename failed after document rename: %w" , err )
}
2026-07-20 09:48:24 +08:00
}
if s . docEngine == nil {
return nil
}
titleTks , _ := tokenizer . Tokenize ( newName )
titleSmTks , _ := tokenizer . FineGrainedTokenize ( titleTks )
indexName := fmt . Sprintf ( "ragflow_%s" , tenantID )
return s . docEngine . UpdateChunks (
context . Background ( ) ,
map [ string ] interface { } { "doc_id" : doc . ID } ,
map [ string ] interface { } {
"docnm_kwd" : newName ,
"title_tks" : titleTks ,
"title_sm_tks" : titleSmTks ,
} ,
indexName ,
doc . KbID ,
)
}
2026-07-24 16:47:12 +08:00
func ( s * DocumentService ) updateDocumentParserConfig ( ctx context . Context , documentID string , config map [ string ] any ) error {
2026-07-20 09:48:24 +08:00
if len ( config ) == 0 {
return nil
}
2026-07-24 16:47:12 +08:00
doc , err := s . documentDAO . GetByID ( ctx , dao . DB , documentID )
2026-07-20 09:48:24 +08:00
if err != nil {
2026-07-24 16:47:12 +08:00
return fmt . Errorf ( "document(%s) not found" , documentID )
2026-07-20 09:48:24 +08:00
}
2026-07-24 16:47:12 +08:00
merged := common . DeepMergeMaps ( doc . ParserConfig , config )
2026-07-20 09:48:24 +08:00
if _ , ok := config [ "raptor" ] ; ! ok {
delete ( merged , "raptor" )
}
2026-07-24 16:47:12 +08:00
return s . documentDAO . UpdateByID ( ctx , dao . DB , documentID , map [ string ] interface { } {
2026-07-20 09:48:24 +08:00
"parser_config" : entity . JSONMap ( merged ) ,
} )
}
func ( s * DocumentService ) toUpdateDatasetDocumentResponse ( doc * entity . Document , metaFields map [ string ] interface { } ) * UpdateDatasetDocumentResponse {
if metaFields == nil {
metaFields = map [ string ] interface { } { }
}
return & UpdateDatasetDocumentResponse {
ID : doc . ID ,
Thumbnail : doc . Thumbnail ,
DatasetID : doc . KbID ,
ParserID : doc . ParserID ,
PipelineID : doc . PipelineID ,
2026-07-24 16:47:12 +08:00
ParserConfig : doc . ParserConfig ,
2026-07-20 09:48:24 +08:00
SourceType : doc . SourceType ,
Type : doc . Type ,
CreatedBy : doc . CreatedBy ,
Name : doc . Name ,
Location : doc . Location ,
Size : doc . Size ,
TokenCount : doc . TokenNum ,
ChunkCount : doc . ChunkNum ,
Progress : doc . Progress ,
ProgressMsg : doc . ProgressMsg ,
ProcessBeginAt : doc . ProcessBeginAt ,
ProcessDuration : doc . ProcessDuration ,
ContentHash : doc . ContentHash ,
MetaFields : metaFields ,
Suffix : doc . Suffix ,
Run : mapDocumentRunStatus ( doc . Run ) ,
Status : doc . Status ,
CreateTime : doc . CreateTime ,
CreateDate : doc . CreateDate ,
UpdateTime : doc . UpdateTime ,
UpdateDate : doc . UpdateDate ,
}
}
func mapDocumentRunStatus ( run * string ) string {
if run == nil {
return "UNSTART"
}
switch * run {
case string ( entity . TaskStatusRunning ) :
return "RUNNING"
case string ( entity . TaskStatusCancel ) :
return "CANCEL"
case string ( entity . TaskStatusDone ) :
return "DONE"
case string ( entity . TaskStatusFail ) :
return "FAIL"
default :
return "UNSTART"
}
}
Test: release Go-proxy RESTful contract tests verified passing in Go mode (#17468)
### Summary
Aligns Go and Python error codes/messages so both backends honor the
same RESTful API contract, removing implementation-specific error leaks
(MySQL errors, `ValueError`, `AttributeError`, Gin validator format) in
favor of clean business error codes.
**Chat list** — invalid `orderby` now returns code 101 (was: raw Python
`AttributeError` code 100); invalid `page`/`page_size` values fall back
to defaults (was: raw `ValueError`/`ProgrammingError` code 100).
**Dataset create/update/delete** — adds UUID validation (101),
extra-field rejection (101), duplicate-id detection (101), content-type
/ JSON-syntax / object-shape checks (101), and "lacks permission" for
nonexistent datasets (IDOR). Create auto-deduplicates dataset names.
Pagerank updates tolerate a missing ES index. List response includes
`parser_config` and `pagerank`.
**Session list/update** — adds filtering, sorting, and pagination
support. Empty payloads are valid no-ops. Authorization errors map to
code 109.
**Chunk list** — doc object uses Python key names (`chunk_count`,
`dataset_id`, `chunk_method`, run text status). Add validates list
element types.
**Document update** — adds `chunk_method` alias, pydantic-style Field
error messages, metadata index auto-create with refresh, and "These
documents do not belong to dataset" messages. List validates
`metadata_condition` and reports ownership errors for unmatched name/id
filters.
**Search completion** — `kb_ids` ownership failure returns code 102
instead of 109.
Released 31 contract tests from `GO_ONLY_SKIPS` (all verified passing on
both Go and Python backends with real LLM keys).
2026-07-30 19:58:49 +08:00
// validDocumentChunkMethods mirrors Python's UpdateDocumentReq chunk_method set.
var validDocumentChunkMethods = map [ string ] bool {
"naive" : true , "manual" : true , "qa" : true , "table" : true , "paper" : true ,
"book" : true , "laws" : true , "presentation" : true , "picture" : true ,
"one" : true , "knowledge_graph" : true , "email" : true , "tag" : true ,
}
// pythonFloatRepr formats a float the way Python's str()/repr() does:
// integral floats keep a trailing ".0".
func pythonFloatRepr ( v float64 ) string {
if v == math . Trunc ( v ) {
return fmt . Sprintf ( "%.1f" , v )
}
return strconv . FormatFloat ( v , 'g' , - 1 , 64 )
}
// pyRepr renders a decoded JSON value the way Python's repr() does, for
// pydantic-style "Field: <f> - Message: <m> - Value: <v>" contract messages.
func pyRepr ( v interface { } ) string {
switch typed := v . ( type ) {
case nil :
return "None"
case string :
return "'" + strings . ReplaceAll ( typed , "'" , "\\'" ) + "'"
case bool :
if typed {
return "True"
}
return "False"
case float64 :
if typed == math . Trunc ( typed ) {
return strconv . FormatInt ( int64 ( typed ) , 10 )
}
return strconv . FormatFloat ( typed , 'g' , - 1 , 64 )
case float32 :
return pyRepr ( float64 ( typed ) )
case int :
return strconv . Itoa ( typed )
case int64 :
return strconv . FormatInt ( typed , 10 )
case [ ] interface { } :
parts := make ( [ ] string , len ( typed ) )
for i , item := range typed {
parts [ i ] = pyRepr ( item )
}
return "[" + strings . Join ( parts , ", " ) + "]"
case map [ string ] interface { } :
parts := make ( [ ] string , 0 , len ( typed ) )
for k , item := range typed {
parts = append ( parts , pyRepr ( k ) + ": " + pyRepr ( item ) )
}
return "{" + strings . Join ( parts , ", " ) + "}"
}
return fmt . Sprintf ( "%v" , v )
}