102 lines
2.9 KiB
Go
102 lines
2.9 KiB
Go
package inbox
|
|
|
|
import (
|
|
"errors"
|
|
|
|
"gorm.io/gorm"
|
|
"senlinai-agent/backend/internal/models"
|
|
)
|
|
|
|
type CaptureInput struct {
|
|
ProjectID uint
|
|
UserID uint
|
|
SourceType string
|
|
Title string
|
|
Body string
|
|
}
|
|
|
|
type Suggestion struct {
|
|
Kind string `json:"kind"`
|
|
Title string `json:"title"`
|
|
Body string `json:"body"`
|
|
}
|
|
|
|
type Analyzer interface {
|
|
Analyze(item models.SenlinAgentInboxItem, userID uint) ([]Suggestion, error)
|
|
}
|
|
|
|
type StaticAnalyzer struct {
|
|
Suggestions []Suggestion
|
|
}
|
|
|
|
func (a StaticAnalyzer) Analyze(item models.SenlinAgentInboxItem, userID uint) ([]Suggestion, error) {
|
|
return a.Suggestions, nil
|
|
}
|
|
|
|
type Service struct {
|
|
analyzer Analyzer
|
|
}
|
|
|
|
func NewService(analyzer Analyzer) *Service {
|
|
return &Service{analyzer: analyzer}
|
|
}
|
|
|
|
func (s *Service) Capture(input CaptureInput) (*models.SenlinAgentInboxItem, error) {
|
|
if input.ProjectID == 0 || input.UserID == 0 {
|
|
return nil, errors.New("project and user are required")
|
|
}
|
|
if input.SourceType == "" {
|
|
return nil, errors.New("source type is required")
|
|
}
|
|
item := &models.SenlinAgentInboxItem{
|
|
ProjectID: input.ProjectID,
|
|
CreatedBy: input.UserID,
|
|
SourceType: input.SourceType,
|
|
Title: input.Title,
|
|
Body: input.Body,
|
|
Status: "open",
|
|
}
|
|
return item, models.DBService.Create(item).Error
|
|
}
|
|
|
|
func (s *Service) Analyze(itemID uint, userID uint) ([]Suggestion, error) {
|
|
var item models.SenlinAgentInboxItem
|
|
if err := models.DBService.First(&item, itemID).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
if s.analyzer == nil {
|
|
return []Suggestion{}, nil
|
|
}
|
|
return s.analyzer.Analyze(item, userID)
|
|
}
|
|
|
|
func (s *Service) Confirm(itemID uint, selected []Suggestion) error {
|
|
return models.DBService.Transaction(func(tx *gorm.DB) error {
|
|
var item models.SenlinAgentInboxItem
|
|
if err := tx.First(&item, itemID).Error; err != nil {
|
|
return err
|
|
}
|
|
sourceInboxItemID := item.ID
|
|
// Inbox 建议只有在用户确认后才创建正式对象,并把来源 ID 写入每个对象以保留可追溯性。
|
|
for _, suggestion := range selected {
|
|
switch suggestion.Kind {
|
|
case "task":
|
|
if err := tx.Create(&models.SenlinAgentTask{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, SourceInboxItemID: &sourceInboxItemID, Title: suggestion.Title, Description: suggestion.Body}).Error; err != nil {
|
|
return err
|
|
}
|
|
case "note":
|
|
if err := tx.Create(&models.SenlinAgentNote{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, SourceInboxItemID: &sourceInboxItemID, Title: suggestion.Title, Markdown: suggestion.Body}).Error; err != nil {
|
|
return err
|
|
}
|
|
case "source":
|
|
if err := tx.Create(&models.SenlinAgentSource{ProjectID: item.ProjectID, CreatedBy: item.CreatedBy, SourceInboxItemID: &sourceInboxItemID, Kind: "link", Title: suggestion.Title, ContentText: suggestion.Body}).Error; err != nil {
|
|
return err
|
|
}
|
|
default:
|
|
return errors.New("unsupported suggestion kind")
|
|
}
|
|
}
|
|
return tx.Model(&item).Update("status", "processed").Error
|
|
})
|
|
}
|