583 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			583 lines
		
	
	
		
			19 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						||
 * Copyright 2025 coze-dev Authors
 | 
						||
 *
 | 
						||
 * 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 service
 | 
						||
 | 
						||
import (
 | 
						||
	"bytes"
 | 
						||
	"context"
 | 
						||
	"fmt"
 | 
						||
	"os"
 | 
						||
	"testing"
 | 
						||
	"time"
 | 
						||
 | 
						||
	"github.com/apache/rocketmq-client-go/v2/primitive"
 | 
						||
	"github.com/cloudwego/eino/schema"
 | 
						||
	"github.com/milvus-io/milvus/client/v2/milvusclient"
 | 
						||
	"github.com/stretchr/testify/assert"
 | 
						||
	"github.com/stretchr/testify/suite"
 | 
						||
	"gorm.io/gorm"
 | 
						||
 | 
						||
	knowledgeModel "github.com/coze-dev/coze-studio/backend/api/model/crossdomain/knowledge"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/domain/knowledge/entity"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/domain/knowledge/internal/convert"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/domain/knowledge/internal/dal/model"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/contract/document"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/contract/document/nl2sql"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/contract/document/parser"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/contract/document/searchstore"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/contract/storage"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/cache/redis"
 | 
						||
	sses "github.com/coze-dev/coze-studio/backend/infra/impl/document/searchstore/elasticsearch"
 | 
						||
	ssmilvus "github.com/coze-dev/coze-studio/backend/infra/impl/document/searchstore/milvus"
 | 
						||
	hembed "github.com/coze-dev/coze-studio/backend/infra/impl/embedding/http"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/es"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/eventbus"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/idgen"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/mysql"
 | 
						||
	rdbservice "github.com/coze-dev/coze-studio/backend/infra/impl/rdb"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/infra/impl/storage/minio"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/pkg/lang/ptr"
 | 
						||
	"github.com/coze-dev/coze-studio/backend/types/consts"
 | 
						||
)
 | 
						||
 | 
						||
func TestKnowledgeSuite(t *testing.T) {
 | 
						||
	if os.Getenv("TEST_KNOWLEDGE_INTEGRATION") != "true" {
 | 
						||
		return
 | 
						||
	}
 | 
						||
 | 
						||
	suite.Run(t, new(KnowledgeTestSuite))
 | 
						||
}
 | 
						||
 | 
						||
type KnowledgeTestSuite struct {
 | 
						||
	suite.Suite
 | 
						||
	handler eventbus.ConsumerHandler
 | 
						||
 | 
						||
	ctx     context.Context
 | 
						||
	uid     int64
 | 
						||
	spaceID int64
 | 
						||
 | 
						||
	db      *gorm.DB
 | 
						||
	es      es.Client
 | 
						||
	st      storage.Storage
 | 
						||
	svc     *knowledgeSVC
 | 
						||
	eventCh chan *eventbus.Message
 | 
						||
 | 
						||
	startTime int64
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) SetupSuite() {
 | 
						||
	ctx := context.Background()
 | 
						||
	var (
 | 
						||
		rmqEndpoint = "127.0.0.1:9876"
 | 
						||
		embEndpoint = "http://127.0.0.1:6543"
 | 
						||
		// esCertPath    = os.Getenv("ES_CA_CERT_PATH")
 | 
						||
		// esAddr = os.Getenv("ES_ADDR")
 | 
						||
		// esUsername    = os.Getenv("ES_USERNAME")
 | 
						||
		// esPassword    = os.Getenv("ES_PASSWORD")
 | 
						||
		milvusAddr    = os.Getenv("MILVUS_ADDR")
 | 
						||
		_             = os.Getenv("MYSQL_DSN")
 | 
						||
		_             = os.Getenv("REDIS_ADDR")
 | 
						||
		minioEndpoint = os.Getenv(consts.MinIOEndpoint)
 | 
						||
		minioAK       = os.Getenv(consts.MinIOAK)
 | 
						||
		minioSK       = os.Getenv(consts.MinIOSK)
 | 
						||
	)
 | 
						||
 | 
						||
	db, err := mysql.New()
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	cacheCli := redis.New()
 | 
						||
	idGenSVC, err := idgen.New(cacheCli)
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	tosClient, err := minio.New(ctx,
 | 
						||
		minioEndpoint,
 | 
						||
		minioAK,
 | 
						||
		minioSK,
 | 
						||
		"bucket2",
 | 
						||
		false,
 | 
						||
	)
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	rdbService := rdbservice.NewService(db, idGenSVC)
 | 
						||
 | 
						||
	knowledgeProducer, err := eventbus.NewProducer(rmqEndpoint, consts.RMQTopicKnowledge, consts.RMQConsumeGroupKnowledge, 2)
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	var mgrs []searchstore.Manager
 | 
						||
	// cert, err := os.ReadFile(esCertPath)
 | 
						||
	// if err != nil {
 | 
						||
	//	panic(err)
 | 
						||
	// }
 | 
						||
 | 
						||
	knowledgeES, err := es.New()
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	mgrs = append(mgrs, sses.NewManager(&sses.ManagerConfig{Client: knowledgeES}))
 | 
						||
 | 
						||
	mc, err := milvusclient.New(ctx, &milvusclient.ClientConfig{
 | 
						||
		Address: milvusAddr,
 | 
						||
	})
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	emb, err := hembed.NewEmbedding(embEndpoint, 1024, 1)
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	mvs, err := ssmilvus.NewManager(&ssmilvus.ManagerConfig{
 | 
						||
		Client:       mc,
 | 
						||
		Embedding:    emb,
 | 
						||
		EnableHybrid: ptr.Of(true),
 | 
						||
	})
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
	mgrs = append(mgrs, mvs)
 | 
						||
 | 
						||
	// ctrl := gomock.NewController(suite.T())
 | 
						||
 | 
						||
	var knowledgeEventHandler eventbus.ConsumerHandler
 | 
						||
	knowledgeDomainSVC, knowledgeEventHandler := NewKnowledgeSVC(&KnowledgeSVCConfig{
 | 
						||
		DB:                  db,
 | 
						||
		IDGen:               idGenSVC,
 | 
						||
		RDB:                 rdbService,
 | 
						||
		Producer:            knowledgeProducer,
 | 
						||
		SearchStoreManagers: mgrs,
 | 
						||
		ParseManager:        nil, // default builtin
 | 
						||
		Storage:             tosClient,
 | 
						||
		Rewriter:            nil,
 | 
						||
		Reranker:            nil, // default rrf
 | 
						||
		EnableCompactTable:  ptr.Of(true),
 | 
						||
	})
 | 
						||
 | 
						||
	suite.handler = knowledgeEventHandler
 | 
						||
 | 
						||
	err = eventbus.DefaultSVC().RegisterConsumer(rmqEndpoint, consts.RMQTopicKnowledge, consts.RMQConsumeGroupKnowledge, suite)
 | 
						||
	if err != nil {
 | 
						||
		panic(err)
 | 
						||
	}
 | 
						||
 | 
						||
	suite.ctx = context.Background()
 | 
						||
	suite.uid = 111
 | 
						||
	suite.spaceID = 222
 | 
						||
	suite.db = db
 | 
						||
	suite.es = knowledgeES
 | 
						||
	suite.st = tosClient
 | 
						||
	suite.svc = knowledgeDomainSVC.(*knowledgeSVC)
 | 
						||
	suite.eventCh = make(chan *eventbus.Message, 50)
 | 
						||
 | 
						||
	suite.startTime = time.Now().UnixMilli() - 1000
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) HandleMessage(ctx context.Context, msg *eventbus.Message) error {
 | 
						||
	if ext, ok := primitive.GetConsumerCtx(ctx); ok {
 | 
						||
		if ext.Msgs[0].StoreTimestamp < suite.startTime {
 | 
						||
			fmt.Printf("[KnowledgeTestSuite][HandleMessage] skip msg, store_ms=%v, body=%v\n",
 | 
						||
				ext.Msgs[0].StoreTimestamp, string(msg.Body))
 | 
						||
			return nil
 | 
						||
		}
 | 
						||
	}
 | 
						||
 | 
						||
	defer func() {
 | 
						||
		suite.eventCh <- msg
 | 
						||
	}()
 | 
						||
 | 
						||
	return suite.handler.HandleMessage(ctx, msg)
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TestSkip() {
 | 
						||
	time.Sleep(time.Second * 5)
 | 
						||
	suite.clearDB()
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) SetupTest() {
 | 
						||
	// suite.clearDB()
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TearDownSuite() {
 | 
						||
	// suite.clearDB()
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) clearDB() {
 | 
						||
	db := suite.db
 | 
						||
	db.WithContext(suite.ctx).Table((&model.Knowledge{}).TableName()).Where("1=1").Delete([]struct{}{})
 | 
						||
	db.WithContext(suite.ctx).Table((&model.KnowledgeDocument{}).TableName()).Where("1=1").Delete([]struct{}{})
 | 
						||
	db.WithContext(suite.ctx).Table((&model.KnowledgeDocumentSlice{}).TableName()).Where("1=1").Delete([]struct{}{})
 | 
						||
	fmt.Println("[KnowledgeTestSuite] clear done")
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TestTextKnowledge() {
 | 
						||
	createReq := CreateKnowledgeRequest{
 | 
						||
		Name:        "test_knowledge",
 | 
						||
		Description: "test_description",
 | 
						||
		IconUri:     "test_icon_uri",
 | 
						||
		CreatorID:   suite.uid,
 | 
						||
		SpaceID:     suite.spaceID,
 | 
						||
		AppID:       0,
 | 
						||
		FormatType:  knowledgeModel.DocumentTypeText,
 | 
						||
	}
 | 
						||
	createResp, err := suite.svc.CreateKnowledge(suite.ctx, &createReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createResp)
 | 
						||
	updateReq := UpdateKnowledgeRequest{
 | 
						||
		KnowledgeID: createResp.KnowledgeID,
 | 
						||
		Name:        ptr.Of("test_new_name"),
 | 
						||
		Description: ptr.Of("test_new_description"),
 | 
						||
	}
 | 
						||
	err = suite.svc.UpdateKnowledge(suite.ctx, &updateReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
 | 
						||
	mGetResp, err := suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		IDs: []int64{createResp.KnowledgeID},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(1), mGetResp.Total)
 | 
						||
	fmt.Printf("%+v\n", mGetResp)
 | 
						||
 | 
						||
	mGetResp, err = suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		SpaceID: ptr.Of(suite.spaceID),
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(1), mGetResp.Total)
 | 
						||
	fmt.Printf("%+v\n", mGetResp)
 | 
						||
 | 
						||
	mGetResp, err = suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		IDs: []int64{887766},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(0), mGetResp.Total)
 | 
						||
	err = suite.svc.DeleteKnowledge(suite.ctx, &DeleteKnowledgeRequest{
 | 
						||
		KnowledgeID: createResp.KnowledgeID,
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TestTextDocument() {
 | 
						||
	suite.clearDB()
 | 
						||
	createReq := CreateKnowledgeRequest{
 | 
						||
		Name:        "test_knowledge",
 | 
						||
		Description: "test_description",
 | 
						||
		IconUri:     "test_icon_uri",
 | 
						||
		CreatorID:   suite.uid,
 | 
						||
		SpaceID:     suite.spaceID,
 | 
						||
		AppID:       0,
 | 
						||
		FormatType:  knowledgeModel.DocumentTypeText,
 | 
						||
	}
 | 
						||
 | 
						||
	key := fmt.Sprintf("test_text_document_key:%d:%s", time.Now().Unix(), "test.md")
 | 
						||
	b := []byte(`1. Eiffel Tower: Located in Paris, France, it is one of the most famous landmarks in the world, designed by Gustave Eiffel and built in 1889.
 | 
						||
2. The Great Wall: Located in China, it is one of the Seven Wonders of the World, built from the Qin Dynasty to the Ming Dynasty, with a total length of over 20000 kilometers.
 | 
						||
3. Grand Canyon National Park: Located in Arizona, USA, it is famous for its deep canyons and magnificent scenery, which are cut by the Colorado River.
 | 
						||
4. The Colosseum: Located in Rome, Italy, built between 70-80 AD, it was the largest circular arena in the ancient Roman Empire.
 | 
						||
5. Taj Mahal: Located in Agra, India, it was completed by Mughal Emperor Shah Jahan in 1653 to commemorate his wife and is one of the New Seven Wonders of the World.
 | 
						||
6. Sydney Opera House: Located in Sydney Harbour, Australia, it is one of the most iconic buildings of the 20th century, renowned for its unique sailboat design.
 | 
						||
7. Louvre Museum: Located in Paris, France, it is one of the largest museums in the world with a rich collection, including Leonardo da Vinci's Mona Lisa and Greece's Venus de Milo.
 | 
						||
8. Niagara Falls: located at the border of the United States and Canada, consisting of three main waterfalls, its spectacular scenery attracts millions of tourists every year.
 | 
						||
9. St. Sophia Cathedral: located in Istanbul, Türkiye, originally built in 537 A.D., it used to be an Orthodox cathedral and mosque, and now it is a museum.
 | 
						||
10. Machu Picchu: an ancient Inca site located on the plateau of the Andes Mountains in Peru, one of the New Seven Wonders of the World, with an altitude of over 2400 meters.`)
 | 
						||
	assert.NoError(suite.T(), suite.st.PutObject(suite.ctx, key, b))
 | 
						||
	url, err := suite.st.GetObjectUrl(suite.ctx, key)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Println(url)
 | 
						||
 | 
						||
	createdKnowledge, err := suite.svc.CreateKnowledge(suite.ctx, &createReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createdKnowledge)
 | 
						||
 | 
						||
	createdDocs, err := suite.svc.CreateDocument(suite.ctx, &CreateDocumentRequest{
 | 
						||
		Documents: []*entity.Document{
 | 
						||
			{
 | 
						||
				Info: knowledgeModel.Info{
 | 
						||
					ID:          0,
 | 
						||
					Name:        "test.md",
 | 
						||
					Description: "test description",
 | 
						||
					CreatorID:   suite.uid,
 | 
						||
					SpaceID:     suite.spaceID,
 | 
						||
				},
 | 
						||
				KnowledgeID:   createdKnowledge.KnowledgeID,
 | 
						||
				Type:          knowledgeModel.DocumentTypeText,
 | 
						||
				URI:           key,
 | 
						||
				URL:           url,
 | 
						||
				Size:          0,
 | 
						||
				SliceCount:    0,
 | 
						||
				CharCount:     0,
 | 
						||
				FileExtension: parser.FileExtensionMarkdown,
 | 
						||
				Status:        entity.DocumentStatusUploading,
 | 
						||
				StatusMsg:     "",
 | 
						||
				Hits:          0,
 | 
						||
				Source:        entity.DocumentSourceLocal,
 | 
						||
				ParsingStrategy: &entity.ParsingStrategy{
 | 
						||
					ExtractImage: false,
 | 
						||
					ExtractTable: false,
 | 
						||
					ImageOCR:     false,
 | 
						||
				},
 | 
						||
				ChunkingStrategy: &entity.ChunkingStrategy{
 | 
						||
					ChunkType:       parser.ChunkTypeCustom,
 | 
						||
					ChunkSize:       1000,
 | 
						||
					Separator:       "\n",
 | 
						||
					Overlap:         0,
 | 
						||
					TrimSpace:       true,
 | 
						||
					TrimURLAndEmail: true,
 | 
						||
					MaxDepth:        0,
 | 
						||
					SaveTitle:       false,
 | 
						||
				},
 | 
						||
				TableInfo: entity.TableInfo{},
 | 
						||
				IsAppend:  false,
 | 
						||
			},
 | 
						||
		},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createdDocs)
 | 
						||
 | 
						||
	<-suite.eventCh // index documents
 | 
						||
	<-suite.eventCh // index document
 | 
						||
	time.Sleep(time.Second * 10)
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TestTableKnowledge() {
 | 
						||
	createReq := CreateKnowledgeRequest{
 | 
						||
		Name:        "test_knowledge",
 | 
						||
		Description: "test_description",
 | 
						||
		IconUri:     "test_icon_uri",
 | 
						||
		CreatorID:   suite.uid,
 | 
						||
		SpaceID:     suite.spaceID,
 | 
						||
		AppID:       0,
 | 
						||
		FormatType:  knowledgeModel.DocumentTypeTable,
 | 
						||
	}
 | 
						||
	createResp, err := suite.svc.CreateKnowledge(suite.ctx, &createReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createResp)
 | 
						||
	updateReq := UpdateKnowledgeRequest{
 | 
						||
		KnowledgeID: createResp.KnowledgeID,
 | 
						||
		Name:        ptr.Of("test_new_name"),
 | 
						||
		Description: ptr.Of("test_new_description"),
 | 
						||
	}
 | 
						||
	err = suite.svc.UpdateKnowledge(suite.ctx, &updateReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
 | 
						||
	mgetResp, err := suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		IDs: []int64{createResp.KnowledgeID},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(1), mgetResp.Total)
 | 
						||
	fmt.Printf("%+v\n", mgetResp)
 | 
						||
 | 
						||
	mgetResp, err = suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		SpaceID: ptr.Of(suite.spaceID),
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(1), mgetResp.Total)
 | 
						||
	fmt.Printf("%+v\n", mgetResp)
 | 
						||
 | 
						||
	mgetResp, err = suite.svc.ListKnowledge(suite.ctx, &ListKnowledgeRequest{
 | 
						||
		IDs: []int64{887766},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	assert.Equal(suite.T(), int64(0), mgetResp.Total)
 | 
						||
 | 
						||
	err = suite.svc.DeleteKnowledge(suite.ctx, &DeleteKnowledgeRequest{
 | 
						||
		KnowledgeID: createResp.KnowledgeID,
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
}
 | 
						||
 | 
						||
func (suite *KnowledgeTestSuite) TestTableDocument() {
 | 
						||
	suite.clearDB()
 | 
						||
	createReq := CreateKnowledgeRequest{
 | 
						||
		Name:        "test_knowledge",
 | 
						||
		Description: "test_description",
 | 
						||
		IconUri:     "test_icon_uri",
 | 
						||
		CreatorID:   suite.uid,
 | 
						||
		SpaceID:     suite.spaceID,
 | 
						||
		AppID:       0,
 | 
						||
		FormatType:  knowledgeModel.DocumentTypeTable,
 | 
						||
	}
 | 
						||
 | 
						||
	key := fmt.Sprintf("test_table_document_key:%d:%s", time.Now().Unix(), "test.json")
 | 
						||
	b := []byte(`[
 | 
						||
    {
 | 
						||
        "department": "心血管科",
 | 
						||
        "title": "高血压患者能吃党参吗?",
 | 
						||
        "question": "我有高血压这两天女婿来的时候给我拿了些党参泡水喝,您好高血压可以吃党参吗?",
 | 
						||
        "answer": "高血压病人可以口服党参的。党参有降血脂,降血压的作用,可以彻底消除血液中的垃圾,从而对冠心病以及心血管疾病的患者都有一定的稳定预防工作作用,因此平时口服党参能远离三高的危害。另外党参除了益气养血,降低中枢神经作用,调整消化系统功能,健脾补肺的功能。感谢您的进行咨询,期望我的解释对你有所帮助。"
 | 
						||
    },
 | 
						||
    {
 | 
						||
        "department": "消化科",
 | 
						||
        "title": "哪家医院能治胃反流",
 | 
						||
        "question": "烧心,打隔,咳嗽低烧,以有4年多",
 | 
						||
        "answer": "建议你用奥美拉唑同时,加用吗丁啉或莫沙必利或援生力维,另外还可以加用达喜片"
 | 
						||
    }
 | 
						||
]`)
 | 
						||
	assert.NoError(suite.T(), suite.st.PutObject(suite.ctx, key, b))
 | 
						||
	url, err := suite.st.GetObjectUrl(suite.ctx, key)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Println(url)
 | 
						||
 | 
						||
	createdKnowledge, err := suite.svc.CreateKnowledge(suite.ctx, &createReq)
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createdKnowledge)
 | 
						||
 | 
						||
	rawDoc := &entity.Document{
 | 
						||
		Info: knowledgeModel.Info{
 | 
						||
			ID:          0,
 | 
						||
			Name:        "test.json",
 | 
						||
			Description: "test json",
 | 
						||
			CreatorID:   suite.uid,
 | 
						||
			SpaceID:     suite.spaceID,
 | 
						||
		},
 | 
						||
		KnowledgeID:   createdKnowledge.KnowledgeID,
 | 
						||
		Type:          knowledgeModel.DocumentTypeTable,
 | 
						||
		URI:           key,
 | 
						||
		URL:           url,
 | 
						||
		Size:          0,
 | 
						||
		SliceCount:    0,
 | 
						||
		CharCount:     0,
 | 
						||
		FileExtension: parser.FileExtensionJSON,
 | 
						||
		Status:        entity.DocumentStatusUploading,
 | 
						||
		StatusMsg:     "",
 | 
						||
		Hits:          0,
 | 
						||
		Source:        entity.DocumentSourceLocal,
 | 
						||
		ParsingStrategy: &entity.ParsingStrategy{
 | 
						||
			SheetID:       0,
 | 
						||
			HeaderLine:    0,
 | 
						||
			DataStartLine: 1,
 | 
						||
			RowsCount:     2,
 | 
						||
		},
 | 
						||
		ChunkingStrategy: &entity.ChunkingStrategy{
 | 
						||
			ChunkType:       parser.ChunkTypeCustom,
 | 
						||
			ChunkSize:       1000,
 | 
						||
			Separator:       "\n",
 | 
						||
			Overlap:         0,
 | 
						||
			TrimSpace:       true,
 | 
						||
			TrimURLAndEmail: true,
 | 
						||
			MaxDepth:        0,
 | 
						||
			SaveTitle:       false,
 | 
						||
		},
 | 
						||
		TableInfo: entity.TableInfo{},
 | 
						||
		IsAppend:  false,
 | 
						||
	}
 | 
						||
 | 
						||
	p, err := suite.svc.parseManager.GetParser(convert.DocumentToParseConfig(rawDoc))
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
 | 
						||
	parseResult, err := p.Parse(suite.ctx, bytes.NewReader(b))
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	cols := parseResult[0].MetaData[document.MetaDataKeyColumns].([]*document.Column)
 | 
						||
	createCols := make([]*entity.TableColumn, 0, len(cols))
 | 
						||
	for i, col := range cols {
 | 
						||
		createCols = append(createCols, &entity.TableColumn{
 | 
						||
			ID:          col.ID,
 | 
						||
			Name:        col.Name,
 | 
						||
			Type:        col.Type,
 | 
						||
			Description: col.Description,
 | 
						||
			Indexing:    !col.Nullable,
 | 
						||
			Sequence:    int64(i),
 | 
						||
		})
 | 
						||
	}
 | 
						||
	rawDoc.TableInfo = entity.TableInfo{
 | 
						||
		Columns: createCols,
 | 
						||
	}
 | 
						||
 | 
						||
	createdDocs, err := suite.svc.CreateDocument(suite.ctx, &CreateDocumentRequest{Documents: []*entity.Document{rawDoc}})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Printf("%+v\n", createdDocs)
 | 
						||
 | 
						||
	<-suite.eventCh // index documents
 | 
						||
	<-suite.eventCh // index document
 | 
						||
	time.Sleep(time.Second * 10)
 | 
						||
}
 | 
						||
 | 
						||
// call TestTextKnowledge and comment out SetupTest before using this
 | 
						||
func (suite *KnowledgeTestSuite) TestDocRetrieve() {
 | 
						||
	knowledgeIDs := []int64{7504983031996743680}
 | 
						||
	docIDs := []int64{7504983394833399808}
 | 
						||
 | 
						||
	slices, err := suite.svc.Retrieve(suite.ctx, &RetrieveRequest{
 | 
						||
		Query:        "tower",
 | 
						||
		ChatHistory:  nil,
 | 
						||
		KnowledgeIDs: knowledgeIDs,
 | 
						||
		DocumentIDs:  docIDs,
 | 
						||
		Strategy: &entity.RetrievalStrategy{
 | 
						||
			TopK:               ptr.Of(int64(3)),
 | 
						||
			MinScore:           nil,
 | 
						||
			MaxTokens:          nil,
 | 
						||
			SelectType:         knowledgeModel.SelectTypeAuto,
 | 
						||
			SearchType:         knowledgeModel.SearchTypeHybrid,
 | 
						||
			EnableQueryRewrite: false,
 | 
						||
			EnableRerank:       true,
 | 
						||
			EnableNL2SQL:       true,
 | 
						||
		},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Println(slices)
 | 
						||
}
 | 
						||
 | 
						||
// call TestTextKnowledge and comment out SetupTest before using this
 | 
						||
func (suite *KnowledgeTestSuite) TestTableRetrieve() {
 | 
						||
	knowledgeIDs := []int64{7506054446447591424}
 | 
						||
	docIDs := []int64{7506054481226760192}
 | 
						||
	suite.svc.nl2Sql = &mockNL2SQL{tableName: "table_7506054481281286144"}
 | 
						||
 | 
						||
	slices, err := suite.svc.Retrieve(suite.ctx, &RetrieveRequest{
 | 
						||
		Query:        "hello",
 | 
						||
		ChatHistory:  nil,
 | 
						||
		KnowledgeIDs: knowledgeIDs,
 | 
						||
		DocumentIDs:  docIDs,
 | 
						||
		Strategy: &entity.RetrievalStrategy{
 | 
						||
			TopK:               ptr.Of(int64(3)),
 | 
						||
			MinScore:           nil,
 | 
						||
			MaxTokens:          nil,
 | 
						||
			SelectType:         knowledgeModel.SelectTypeAuto,
 | 
						||
			SearchType:         knowledgeModel.SearchTypeHybrid,
 | 
						||
			EnableQueryRewrite: true,
 | 
						||
			EnableRerank:       true,
 | 
						||
			EnableNL2SQL:       true,
 | 
						||
		},
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	fmt.Println(slices)
 | 
						||
}
 | 
						||
 | 
						||
// call TestTextKnowledge and comment out SetupTest before using this
 | 
						||
func (suite *KnowledgeTestSuite) TestTextKnowledgeDelete() {
 | 
						||
	err := suite.svc.DeleteKnowledge(suite.ctx, &DeleteKnowledgeRequest{
 | 
						||
		KnowledgeID: 7501599196214984704,
 | 
						||
	})
 | 
						||
	assert.NoError(suite.T(), err)
 | 
						||
	<-suite.eventCh // delete document
 | 
						||
}
 | 
						||
 | 
						||
type mockNL2SQL struct {
 | 
						||
	tableName string
 | 
						||
}
 | 
						||
 | 
						||
func (m *mockNL2SQL) NL2SQL(ctx context.Context, messages []*schema.Message, tables []*document.TableSchema, opts ...nl2sql.Option) (sql string, err error) {
 | 
						||
	return fmt.Sprintf("select * from %s", m.tableName), nil
 | 
						||
}
 |