mirror of
https://github.com/infiniflow/ragflow.git
synced 2026-07-28 03:38:11 +08:00
RAGFlow go API server (#13240)
# RAGFlow Go Implementation Plan 🚀 This repository tracks the progress of porting RAGFlow to Go. We'll implement core features and provide performance comparisons between Python and Go versions. ## Implementation Checklist - [x] User Management APIs - [x] Dataset Management Operations - [x] Retrieval Test - [x] Chat Management Operations - [x] Infinity Go SDK --------- Signed-off-by: Jin Hai <haijin.chn@gmail.com> Co-authored-by: Yingfeng Zhang <yingfeng.zhang@gmail.com>
This commit is contained in:
59
internal/engine/infinity/client.go
Normal file
59
internal/engine/infinity/client.go
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infinity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"ragflow/internal/server"
|
||||
)
|
||||
|
||||
// Engine Infinity engine implementation
|
||||
// Note: Infinity Go SDK is not yet available. This is a placeholder implementation.
|
||||
type infinityEngine struct {
|
||||
config *server.InfinityConfig
|
||||
}
|
||||
|
||||
// NewEngine creates an Infinity engine
|
||||
// Note: This is a placeholder implementation waiting for official Infinity Go SDK
|
||||
func NewEngine(cfg interface{}) (*infinityEngine, error) {
|
||||
infConfig, ok := cfg.(*server.InfinityConfig)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid infinity config type, expected *config.InfinityConfig")
|
||||
}
|
||||
|
||||
engine := &infinityEngine{
|
||||
config: infConfig,
|
||||
}
|
||||
|
||||
return engine, nil
|
||||
}
|
||||
|
||||
// Type returns the engine type
|
||||
func (e *infinityEngine) Type() string {
|
||||
return "infinity"
|
||||
}
|
||||
|
||||
// Ping health check
|
||||
func (e *infinityEngine) Ping(ctx context.Context) error {
|
||||
return fmt.Errorf("infinity engine not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// Close closes the connection
|
||||
func (e *infinityEngine) Close() error {
|
||||
return nil
|
||||
}
|
||||
47
internal/engine/infinity/document.go
Normal file
47
internal/engine/infinity/document.go
Normal file
@@ -0,0 +1,47 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infinity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// IndexDocument indexes a single document
|
||||
func (e *infinityEngine) IndexDocument(ctx context.Context, tableName, docID string, doc interface{}) error {
|
||||
return fmt.Errorf("infinity insert not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// BulkIndex indexes documents in bulk
|
||||
func (e *infinityEngine) BulkIndex(ctx context.Context, tableName string, docs []interface{}) (interface{}, error) {
|
||||
return nil, fmt.Errorf("infinity bulk insert not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// BulkResponse bulk operation response
|
||||
type BulkResponse struct {
|
||||
Inserted int
|
||||
}
|
||||
|
||||
// GetDocument gets a document
|
||||
func (e *infinityEngine) GetDocument(ctx context.Context, tableName, docID string) (interface{}, error) {
|
||||
return nil, fmt.Errorf("infinity get document not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// DeleteDocument deletes a document
|
||||
func (e *infinityEngine) DeleteDocument(ctx context.Context, tableName, docID string) error {
|
||||
return fmt.Errorf("infinity delete not implemented: waiting for official Go SDK")
|
||||
}
|
||||
37
internal/engine/infinity/index.go
Normal file
37
internal/engine/infinity/index.go
Normal file
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infinity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// CreateIndex creates a table/index
|
||||
func (e *infinityEngine) CreateIndex(ctx context.Context, indexName string, mapping interface{}) error {
|
||||
return fmt.Errorf("infinity create table not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// DeleteIndex deletes a table/index
|
||||
func (e *infinityEngine) DeleteIndex(ctx context.Context, indexName string) error {
|
||||
return fmt.Errorf("infinity drop table not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// IndexExists checks if table/index exists
|
||||
func (e *infinityEngine) IndexExists(ctx context.Context, indexName string) (bool, error) {
|
||||
return false, fmt.Errorf("infinity check table existence not implemented: waiting for official Go SDK")
|
||||
}
|
||||
205
internal/engine/infinity/search.go
Normal file
205
internal/engine/infinity/search.go
Normal file
@@ -0,0 +1,205 @@
|
||||
//
|
||||
// Copyright 2026 The InfiniFlow Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
package infinity
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"ragflow/internal/engine/types"
|
||||
)
|
||||
|
||||
// SearchRequest Infinity search request (legacy, kept for backward compatibility)
|
||||
type SearchRequest struct {
|
||||
TableName string
|
||||
ColumnNames []string
|
||||
MatchText *MatchTextExpr
|
||||
MatchDense *MatchDenseExpr
|
||||
Fusion *FusionExpr
|
||||
Offset int
|
||||
Limit int
|
||||
Filter map[string]interface{}
|
||||
}
|
||||
|
||||
// SearchResponse Infinity search response
|
||||
type SearchResponse struct {
|
||||
Rows []map[string]interface{}
|
||||
Total int64
|
||||
}
|
||||
|
||||
// MatchTextExpr text match expression
|
||||
type MatchTextExpr struct {
|
||||
Fields []string
|
||||
MatchingText string
|
||||
TopN int
|
||||
ExtraOptions map[string]interface{}
|
||||
}
|
||||
|
||||
// MatchDenseExpr vector match expression
|
||||
type MatchDenseExpr struct {
|
||||
VectorColumnName string
|
||||
EmbeddingData []float64
|
||||
EmbeddingDataType string
|
||||
DistanceType string
|
||||
TopN int
|
||||
ExtraOptions map[string]interface{}
|
||||
}
|
||||
|
||||
// FusionExpr fusion expression
|
||||
type FusionExpr struct {
|
||||
Method string
|
||||
TopN int
|
||||
Weights []float64
|
||||
FusionParams map[string]interface{}
|
||||
}
|
||||
|
||||
// Search executes search (supports both unified engine.SearchRequest and legacy SearchRequest)
|
||||
func (e *infinityEngine) Search(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
switch searchReq := req.(type) {
|
||||
case *types.SearchRequest:
|
||||
return e.searchUnified(ctx, searchReq)
|
||||
case *SearchRequest:
|
||||
return e.searchLegacy(ctx, searchReq)
|
||||
default:
|
||||
return nil, fmt.Errorf("invalid search request type: %T", req)
|
||||
}
|
||||
}
|
||||
|
||||
// searchUnified handles the unified engine.SearchRequest
|
||||
func (e *infinityEngine) searchUnified(ctx context.Context, req *types.SearchRequest) (*types.SearchResponse, error) {
|
||||
if len(req.IndexNames) == 0 {
|
||||
return nil, fmt.Errorf("index names cannot be empty")
|
||||
}
|
||||
|
||||
// For Infinity, we use the first index name as table name
|
||||
tableName := req.IndexNames[0]
|
||||
|
||||
// Get retrieval parameters with defaults
|
||||
similarityThreshold := req.SimilarityThreshold
|
||||
if similarityThreshold <= 0 {
|
||||
similarityThreshold = 0.1
|
||||
}
|
||||
|
||||
topK := req.TopK
|
||||
if topK <= 0 {
|
||||
topK = 1024
|
||||
}
|
||||
|
||||
vectorSimilarityWeight := req.VectorSimilarityWeight
|
||||
if vectorSimilarityWeight < 0 || vectorSimilarityWeight > 1 {
|
||||
vectorSimilarityWeight = 0.3
|
||||
}
|
||||
|
||||
pageSize := req.Size
|
||||
if pageSize <= 0 {
|
||||
pageSize = 30
|
||||
}
|
||||
|
||||
offset := (req.Page - 1) * pageSize
|
||||
if offset < 0 {
|
||||
offset = 0
|
||||
}
|
||||
|
||||
// Build search request
|
||||
searchReq := &SearchRequest{
|
||||
TableName: tableName,
|
||||
Limit: pageSize,
|
||||
Offset: offset,
|
||||
Filter: buildInfinityFilters(req.KbIDs, req.DocIDs),
|
||||
}
|
||||
|
||||
// Add text match (question is always required)
|
||||
searchReq.MatchText = &MatchTextExpr{
|
||||
Fields: []string{"title_tks", "content_ltks"},
|
||||
MatchingText: req.Question,
|
||||
TopN: topK,
|
||||
}
|
||||
|
||||
// Add vector match if vector is provided and not keyword-only mode
|
||||
if !req.KeywordOnly && len(req.Vector) > 0 {
|
||||
fieldName := buildInfinityVectorFieldName(req.Vector)
|
||||
searchReq.MatchDense = &MatchDenseExpr{
|
||||
VectorColumnName: fieldName,
|
||||
EmbeddingData: req.Vector,
|
||||
EmbeddingDataType: "float",
|
||||
DistanceType: "cosine",
|
||||
TopN: topK,
|
||||
ExtraOptions: map[string]interface{}{
|
||||
"similarity": similarityThreshold,
|
||||
},
|
||||
}
|
||||
// Infinity uses weighted_sum fusion with weights
|
||||
searchReq.Fusion = &FusionExpr{
|
||||
Method: "weighted_sum",
|
||||
TopN: topK,
|
||||
Weights: []float64{
|
||||
1.0 - vectorSimilarityWeight, // text weight
|
||||
vectorSimilarityWeight, // vector weight
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// Execute the actual search (would call Infinity SDK here)
|
||||
// For now, return not implemented
|
||||
return nil, fmt.Errorf("infinity search unified not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// searchLegacy handles the legacy infinity.SearchRequest (backward compatibility)
|
||||
func (e *infinityEngine) searchLegacy(ctx context.Context, req *SearchRequest) (*SearchResponse, error) {
|
||||
// This would contain the actual Infinity search implementation
|
||||
return nil, fmt.Errorf("infinity search legacy not implemented: waiting for official Go SDK")
|
||||
}
|
||||
|
||||
// buildInfinityFilters builds filter conditions for Infinity
|
||||
func buildInfinityFilters(kbIDs []string, docIDs []string) map[string]interface{} {
|
||||
filters := make(map[string]interface{})
|
||||
|
||||
// kb_id filter
|
||||
if len(kbIDs) > 0 {
|
||||
if len(kbIDs) == 1 {
|
||||
filters["kb_id"] = kbIDs[0]
|
||||
} else {
|
||||
filters["kb_id"] = kbIDs
|
||||
}
|
||||
}
|
||||
|
||||
// doc_id filter
|
||||
if len(docIDs) > 0 {
|
||||
if len(docIDs) == 1 {
|
||||
filters["doc_id"] = docIDs[0]
|
||||
} else {
|
||||
filters["doc_id"] = docIDs
|
||||
}
|
||||
}
|
||||
|
||||
// available_int filter (default to 1 for available chunks)
|
||||
filters["available_int"] = 1
|
||||
|
||||
return filters
|
||||
}
|
||||
|
||||
// buildInfinityVectorFieldName builds vector field name based on dimension
|
||||
func buildInfinityVectorFieldName(vector []float64) string {
|
||||
dimension := len(vector)
|
||||
var fieldBuilder strings.Builder
|
||||
fieldBuilder.WriteString("q_")
|
||||
fieldBuilder.WriteString(strconv.Itoa(dimension))
|
||||
fieldBuilder.WriteString("_vec")
|
||||
return fieldBuilder.String()
|
||||
}
|
||||
Reference in New Issue
Block a user