Files
X-Agents/server/internal/service/knowledge_service.go
DESKTOP-72TV0V4\caoxiaozhu dd4d4d54b8 feat: 新增 Knowledge 知识库后端服务
- 添加 Knowledge 实体定义
- 添加 Knowledge 仓储层
- 添加 Knowledge 服务层

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:56:24 +08:00

236 lines
5.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"mime/multipart"
"time"
"github.com/google/uuid"
"x-agents/server/internal/model"
"x-agents/server/internal/repository"
)
type KnowledgeService struct {
repo *repository.KnowledgeRepository
modelRepo *repository.ModelRepository
uploadService *UploadService
}
func NewKnowledgeService(repo *repository.KnowledgeRepository, modelRepo *repository.ModelRepository, uploadService *UploadService) *KnowledgeService {
return &KnowledgeService{
repo: repo,
modelRepo: modelRepo,
uploadService: uploadService,
}
}
// Create 创建知识库
func (s *KnowledgeService) Create(req model.CreateKnowledgeRequest) (*model.KnowledgeBase, error) {
// 验证 LLM 模型存在
if _, err := s.modelRepo.FindByID(req.LLMModelID); err != nil {
return nil, err
}
// 验证 Embedding 模型存在
if _, err := s.modelRepo.FindByID(req.EmbeddingModelID); err != nil {
return nil, err
}
kb := &model.KnowledgeBase{
ID: uuid.New().String(),
Name: req.Name,
Description: req.Description,
LLMModelID: req.LLMModelID,
EmbeddingModelID: req.EmbeddingModelID,
ParsingConfig: req.ParsingConfig,
Status: "active",
DocumentCount: 0,
ChunkCount: 0,
}
// 设置默认值
if kb.ParsingConfig.EnablePDF == false && kb.ParsingConfig.EnablePDF != true {
kb.ParsingConfig.EnablePDF = true
}
if kb.ParsingConfig.Pandoc == false && kb.ParsingConfig.Pandoc != true {
kb.ParsingConfig.Pandoc = true
}
if err := s.repo.Create(kb); err != nil {
return nil, err
}
return kb, nil
}
// List 获取知识库列表
func (s *KnowledgeService) List() ([]model.KnowledgeBase, error) {
return s.repo.FindAll()
}
// GetByID 获取知识库详情
func (s *KnowledgeService) GetByID(id string) (*model.KnowledgeBase, error) {
return s.repo.FindByID(id)
}
// Update 更新知识库
func (s *KnowledgeService) Update(id string, req model.UpdateKnowledgeRequest) error {
updates := make(map[string]interface{})
if req.Name != "" {
updates["name"] = req.Name
}
if req.Description != "" {
updates["description"] = req.Description
}
if req.LLMModelID != "" {
// 验证模型存在
if _, err := s.modelRepo.FindByID(req.LLMModelID); err != nil {
return err
}
updates["llm_model_id"] = req.LLMModelID
}
if req.EmbeddingModelID != "" {
// 验证模型存在
if _, err := s.modelRepo.FindByID(req.EmbeddingModelID); err != nil {
return err
}
updates["embedding_model_id"] = req.EmbeddingModelID
}
if req.ParsingConfig.Engine != "" {
updates["parsing_config"] = req.ParsingConfig
}
if req.Status != "" {
updates["status"] = req.Status
}
return s.repo.Update(id, updates)
}
// Delete 删除知识库
func (s *KnowledgeService) Delete(id string) error {
// 先删除关联的文档
if err := s.repo.DeleteDocumentsByKBID(id); err != nil {
return err
}
return s.repo.Delete(id)
}
// ListDocuments 获取知识库下的文档列表
func (s *KnowledgeService) ListDocuments(kbID string, status string) ([]model.KnowledgeDocument, error) {
return s.repo.FindDocumentsByKBID(kbID, status)
}
// UploadDocument 上传文档到知识库
func (s *KnowledgeService) UploadDocument(kbID string, file *multipart.FileHeader) (*model.KnowledgeDocument, error) {
// 验证知识库存在
_, err := s.repo.FindByID(kbID)
if err != nil {
return nil, err
}
// 上传文件
result, err := s.uploadService.Upload(file)
if err != nil {
return nil, err
}
if !result.Success {
return nil, nil
}
// 创建文档记录
doc := &model.KnowledgeDocument{
ID: uuid.New().String(),
KnowledgeBaseID: kbID,
Name: file.Filename,
FileKey: result.FileKey,
FileSize: file.Size,
Status: "parsing",
UploadedAt: time.Now(),
}
if err := s.repo.CreateDocument(doc); err != nil {
return nil, err
}
// 更新知识库文档数
s.updateDocumentCount(kbID)
return doc, nil
}
// DeleteDocument 删除文档
func (s *KnowledgeService) DeleteDocument(kbID, docID string) error {
// 验证文档存在
doc, err := s.repo.FindDocumentByID(docID)
if err != nil {
return err
}
if doc.KnowledgeBaseID != kbID {
return nil
}
// 删除文件
if doc.FileKey != "" {
s.uploadService.DeleteFile(doc.FileKey + getFileExt(doc.Name))
}
// 删除文档记录
if err := s.repo.DeleteDocument(docID); err != nil {
return err
}
// 更新知识库文档数
s.updateDocumentCount(kbID)
return nil
}
// ReparseDocument 重新解析文档
func (s *KnowledgeService) ReparseDocument(kbID, docID string) error {
// 验证文档存在
doc, err := s.repo.FindDocumentByID(docID)
if err != nil {
return err
}
if doc.KnowledgeBaseID != kbID {
return nil
}
// 重置状态为 parsing
return s.repo.UpdateDocument(docID, map[string]interface{}{"status": "parsing"})
}
// GetDocumentPreview 获取文档预览
func (s *KnowledgeService) GetDocumentPreview(kbID, docID string, page int) (*model.DocumentPreviewResponse, error) {
// 验证文档存在
doc, err := s.repo.FindDocumentByID(docID)
if err != nil {
return nil, err
}
if doc.KnowledgeBaseID != kbID {
return nil, nil
}
// 简单实现:返回文件 URL实际应由 Python 服务处理)
fileURL, err := s.uploadService.GetFileURL(doc.FileKey + getFileExt(doc.Name))
if err != nil {
return nil, err
}
return &model.DocumentPreviewResponse{
TotalPages: 1,
CurrentPage: page,
Content: fileURL,
}, nil
}
// updateDocumentCount 更新知识库文档数
func (s *KnowledgeService) updateDocumentCount(kbID string) {
count, _ := s.repo.CountDocumentsByKBID(kbID)
s.repo.Update(kbID, map[string]interface{}{"document_count": int(count)})
}
func getFileExt(filename string) string {
if len(filename) > 4 {
return filename[len(filename)-4:]
}
return ""
}