feat: 集成Eino文档解析与嵌入功能

新增Eino相关依赖,支持docx、pdf、xlsx等格式的文档加载与解析,并集成了Dashscope嵌入模型。同时修复了部分DAO查询中的OmitEmpty配置。
This commit is contained in:
2026-03-28 18:24:15 +08:00
parent f85314f119
commit bcbe6eba78
8 changed files with 414 additions and 197 deletions

View File

@@ -86,7 +86,11 @@ func (d *BaseDataSource) Connect(ctx context.Context) error {
defer d.mu.Unlock()
// 构建客户端
d.client = ms.New(d.config.Host, ms.WithAPIKey(d.config.APIKey))
host := d.config.Host
if d.config.Port > 0 {
host = fmt.Sprintf("%s:%d", d.config.Host, d.config.Port)
}
d.client = ms.New(host, ms.WithAPIKey(d.config.APIKey))
// 测试连接
if err := d.healthCheck(ctx); err != nil {

View File

@@ -71,22 +71,97 @@ func (m *meilisearchDB) getDataSource() (DataSource, error) {
}
// getClient 获取 Meilisearch 客户端
func (m *meilisearchDB) getClient() (interface{ Index(string) interface{} }, error) {
func (m *meilisearchDB) getClient() (ms.ServiceManager, error) {
source, err := m.getDataSource()
if err != nil {
return nil, err
}
if c, ok := source.Client().(interface{ Index(string) interface{} }); ok {
if c, ok := source.Client().(ms.ServiceManager); ok {
return c, nil
}
return nil, fmt.Errorf("invalid client type")
}
// indexInterface 辅助函数获取index
func indexInterface(indexName string, client interface{ Index(string) interface{} }) interface{} {
func indexInterface(indexName string, client ms.ServiceManager) ms.IndexManager {
return client.Index(indexName)
}
// ensureIndexExists 确保索引存在,不存在则自动创建
// 同时会检查并更新 filterable attributes 设置
func (m *meilisearchDB) ensureIndexExists(client ms.ServiceManager, indexName string) error {
// 使用 Index 方法获取索引(不存在时不会报错)
idx := client.Index(indexName)
// 先获取索引信息,检查是否存在
_, err := idx.FetchInfo()
if err != nil {
// 索引不存在,创建索引并等待完成
task, err := client.CreateIndex(&ms.IndexConfig{
Uid: indexName,
PrimaryKey: "id",
})
if err != nil {
return err
}
// 等待索引创建完成最多等待10秒
if _, err = client.WaitForTask(task.TaskUID, 10*time.Second); err != nil {
return fmt.Errorf("等待索引创建失败: %w", err)
}
// 重新获取索引
idx = client.Index(indexName)
}
// 检查并更新 filterable attributes
settings, err := idx.GetSettings()
if err != nil {
return err
}
requiredFilterable := []string{"tenantId", "isDeleted", "datasetId", "creator", "updater"}
needUpdate := false
// 检查是否缺少必要的 filterable attributes
existingFilterable := make(map[string]bool)
for _, attr := range settings.FilterableAttributes {
existingFilterable[attr] = true
}
for _, attr := range requiredFilterable {
if !existingFilterable[attr] {
needUpdate = true
break
}
}
if needUpdate {
// 合并现有的 filterable attributes 和新增的
allFilterable := append(settings.FilterableAttributes, requiredFilterable...)
uniqueFilterable := make(map[string]bool)
var finalFilterable []string
for _, attr := range allFilterable {
if !uniqueFilterable[attr] {
uniqueFilterable[attr] = true
finalFilterable = append(finalFilterable, attr)
}
}
updateSettings := &ms.Settings{
FilterableAttributes: finalFilterable,
}
task, err := idx.UpdateSettings(updateSettings)
if err != nil {
return err
}
// 等待设置更新完成最多等待10秒
if _, err = client.WaitForTask(task.TaskUID, 10*time.Second); err != nil {
return fmt.Errorf("等待设置更新失败: %w", err)
}
}
return nil
}
// buildSearchRequest 构建搜索请求
func (m *meilisearchDB) buildSearchRequest(ctx context.Context, searchParams *SearchParams) (*ms.SearchRequest, error) {
user, err := utils.GetUserInfo(ctx)
@@ -154,13 +229,18 @@ func (m *meilisearchDB) buildSearchRequest(ctx context.Context, searchParams *Se
return req, nil
}
// Search 搜索文档
// Search 搜索文档(索引不存在时返回空结果)
func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams, indexName string, result interface{}) (total int64, err error) {
client, err := m.getClient()
if err != nil {
return 0, err
}
// 检查索引是否存在,不存在则返回空结果
if _, err = client.GetIndex(indexName); err != nil {
return 0, nil
}
// 构建搜索请求
req, err := m.buildSearchRequest(ctx, searchParams)
if err != nil {
@@ -201,14 +281,7 @@ func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams,
// 执行搜索
idx := indexInterface(indexName, client)
var searchResp *ms.SearchResponse
if i, ok := idx.(interface {
Search(string, *ms.SearchRequest) (*ms.SearchResponse, error)
}); ok {
searchResp, err = i.Search(searchParams.Query, req)
} else {
return 0, fmt.Errorf("index does not support Search method")
}
searchResp, err := idx.Search(searchParams.Query, req)
if err != nil {
return 0, err
}
@@ -261,13 +334,18 @@ func (m *meilisearchDB) Search(ctx context.Context, searchParams *SearchParams,
return
}
// Insert 插入文档
// Insert 插入文档(自动创建索引)
func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexName string) (taskUID int64, err error) {
c, err := m.getClient()
if err != nil {
return 0, err
}
// 确保索引存在
if err = m.ensureIndexExists(c, indexName); err != nil {
return 0, err
}
user, err := utils.GetUserInfo(ctx)
if err != nil {
return
@@ -308,14 +386,7 @@ func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexN
// 执行插入
documents := []map[string]interface{}{docMap}
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
AddDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
}); ok {
task, err = i.AddDocuments(documents, nil)
} else {
return 0, fmt.Errorf("index does not support AddDocuments method")
}
task, err := idx.AddDocuments(documents, nil)
if err != nil {
return 0, err
}
@@ -329,13 +400,18 @@ func (m *meilisearchDB) Insert(ctx context.Context, document interface{}, indexN
return task.TaskUID, nil
}
// InsertMany 批量插入文档
// InsertMany 批量插入文档(自动创建索引)
func (m *meilisearchDB) InsertMany(ctx context.Context, documents []interface{}, indexName string) (taskUID int64, err error) {
c, err := m.getClient()
if err != nil {
return 0, err
}
// 确保索引存在
if err = m.ensureIndexExists(c, indexName); err != nil {
return 0, err
}
user, err := utils.GetUserInfo(ctx)
if err != nil {
return 0, err
@@ -379,14 +455,7 @@ func (m *meilisearchDB) InsertMany(ctx context.Context, documents []interface{},
// 执行批量插入
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
AddDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
}); ok {
task, err = i.AddDocuments(docs, nil)
} else {
return 0, fmt.Errorf("index does not support AddDocuments method")
}
task, err := idx.AddDocuments(docs, nil)
if err != nil {
return 0, err
}
@@ -426,14 +495,7 @@ func (m *meilisearchDB) Update(ctx context.Context, document interface{}, indexN
// 执行更新
documents := []map[string]interface{}{docMap}
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
UpdateDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
}); ok {
task, err = i.UpdateDocuments(documents, nil)
} else {
return 0, fmt.Errorf("index does not support UpdateDocuments method")
}
task, err := idx.UpdateDocuments(documents, nil)
if err != nil {
return 0, err
}
@@ -456,14 +518,7 @@ func (m *meilisearchDB) Delete(ctx context.Context, id string, indexName string)
// 执行删除
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
DeleteDocument(string) (*ms.TaskInfo, error)
}); ok {
task, err = i.DeleteDocument(id)
} else {
return 0, fmt.Errorf("index does not support DeleteDocument method")
}
task, err := idx.DeleteDocument(id, nil)
if err != nil {
return 0, err
}
@@ -504,14 +559,7 @@ func (m *meilisearchDB) DeleteSoft(ctx context.Context, id string, indexName str
// 执行更新
documents := []map[string]interface{}{updateMap}
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
UpdateDocuments([]map[string]interface{}, interface{}) (*ms.TaskInfo, error)
}); ok {
task, err = i.UpdateDocuments(documents, nil)
} else {
return 0, fmt.Errorf("index does not support UpdateDocuments method")
}
task, err := idx.UpdateDocuments(documents, nil)
if err != nil {
return 0, err
}
@@ -552,13 +600,7 @@ func (m *meilisearchDB) Get(ctx context.Context, id string, indexName string, re
// 执行查询
var doc map[string]interface{}
idx := indexInterface(indexName, c)
if i, ok := idx.(interface {
GetDocument(string, interface{}) error
}); ok {
err = i.GetDocument(id, &doc)
} else {
return fmt.Errorf("index does not support GetDocument method")
}
err = idx.GetDocument(id, nil, &doc)
if err != nil {
return err
}
@@ -600,122 +642,7 @@ func (m *meilisearchDB) cleanCache(ctx context.Context, indexName string, tenant
return nil
}
// CreateIndex 创建索引
func (m *meilisearchDB) CreateIndex(ctx context.Context, indexConfig *IndexConfig) (taskUID int64, err error) {
client, err := m.getClient()
if err != nil {
return 0, err
}
indexSettings := &ms.IndexConfig{
Uid: indexConfig.UID,
PrimaryKey: indexConfig.PrimaryKey,
}
if c, ok := client.(interface {
CreateIndex(*ms.IndexConfig) (*ms.TaskInfo, error)
}); ok {
task, err := c.CreateIndex(indexSettings)
if err != nil {
return 0, err
}
return task.TaskUID, nil
}
return 0, fmt.Errorf("client does not support CreateIndex")
}
// DeleteIndex 删除索引
func (m *meilisearchDB) DeleteIndex(ctx context.Context, indexName string) (err error) {
client, err := m.getClient()
if err != nil {
return err
}
if c, ok := client.(interface{ DeleteIndex(string) error }); ok {
return c.DeleteIndex(indexName)
}
return fmt.Errorf("client does not support DeleteIndex")
}
// GetIndex 获取索引信息
func (m *meilisearchDB) GetIndex(ctx context.Context, indexName string) (interface{}, error) {
client, err := m.getClient()
if err != nil {
return nil, err
}
if c, ok := client.(interface {
GetIndex(string) (interface{}, error)
}); ok {
return c.GetIndex(indexName)
}
return nil, fmt.Errorf("client does not support GetIndex")
}
// GetIndexes 获取所有索引
func (m *meilisearchDB) GetIndexes(ctx context.Context) (interface{}, error) {
client, err := m.getClient()
if err != nil {
return nil, err
}
if c, ok := client.(interface {
GetIndexes(interface{}) (interface{}, error)
}); ok {
return c.GetIndexes(nil)
}
return nil, fmt.Errorf("client does not support GetIndexes")
}
// UpdateSettings 更新索引设置
func (m *meilisearchDB) UpdateSettings(ctx context.Context, indexName string, settings *ms.Settings) (taskUID int64, err error) {
c, err := m.getClient()
if err != nil {
return 0, err
}
idx := indexInterface(indexName, c)
var task *ms.TaskInfo
if i, ok := idx.(interface {
UpdateSettings(*ms.Settings) (*ms.TaskInfo, error)
}); ok {
task, err = i.UpdateSettings(settings)
} else {
return 0, fmt.Errorf("index does not support UpdateSettings method")
}
if err != nil {
return 0, err
}
return task.TaskUID, nil
}
// GetSettings 获取索引设置
func (m *meilisearchDB) GetSettings(ctx context.Context, indexName string) (*ms.Settings, error) {
c, err := m.getClient()
if err != nil {
return nil, err
}
idx := indexInterface(indexName, c)
var settings *ms.Settings
if i, ok := idx.(interface{ GetSettings() (*ms.Settings, error) }); ok {
settings, err = i.GetSettings()
} else {
return nil, fmt.Errorf("index does not support GetSettings method")
}
if err != nil {
return nil, err
}
return settings, nil
}
// GetClient 获取原始客户端(用于高级操作)
func (m *meilisearchDB) GetClient() (interface{ Index(string) interface{} }, error) {
func (m *meilisearchDB) GetClient() (ms.ServiceManager, error) {
return m.getClient()
}
// BuildUpdateData 构建更新数据
func BuildUpdateData(ctx context.Context, req interface{}) (map[string]interface{}, error) {
return gconv.Map(req), nil
}