Initial commit
This commit is contained in:
184
server/service/system/ai_workflow_session.go
Normal file
184
server/service/system/ai_workflow_session.go
Normal file
@@ -0,0 +1,184 @@
|
||||
package system
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"github.com/flipped-aurora/gin-vue-admin/server/global"
|
||||
system "github.com/flipped-aurora/gin-vue-admin/server/model/system"
|
||||
systemReq "github.com/flipped-aurora/gin-vue-admin/server/model/system/request"
|
||||
systemResp "github.com/flipped-aurora/gin-vue-admin/server/model/system/response"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type aiWorkflowSession struct{}
|
||||
|
||||
var AIWorkflowSessionServiceApp = new(aiWorkflowSession)
|
||||
|
||||
func (s *aiWorkflowSession) Save(ctx context.Context, userID uint, info systemReq.SysAIWorkflowSessionUpsert) (session system.SysAIWorkflowSession, err error) {
|
||||
if userID == 0 {
|
||||
return session, errors.New("用户未登录")
|
||||
}
|
||||
if info.Tab != "analysis" && info.Tab != "workflow" {
|
||||
return session, errors.New("不支持的会话类型")
|
||||
}
|
||||
|
||||
db := global.GVA_DB.WithContext(ctx)
|
||||
if info.ID != 0 {
|
||||
err = db.Where("id = ? AND user_id = ?", info.ID, userID).First(&session).Error
|
||||
if err != nil {
|
||||
return session, err
|
||||
}
|
||||
}
|
||||
|
||||
session.UserID = userID
|
||||
session.Tab = info.Tab
|
||||
session.Title = truncateText(firstNonEmpty(strings.TrimSpace(info.Title), s.titleFromMessages(info.Messages), s.titleFromForm(info)), 255)
|
||||
session.Summary = strings.TrimSpace(firstNonEmpty(info.Summary, s.summaryFromResult(info.ResultData)))
|
||||
session.ConversationID = strings.TrimSpace(info.ConversationID)
|
||||
session.MessageID = strings.TrimSpace(info.MessageID)
|
||||
session.Settings = cloneJSONMap(info.Settings)
|
||||
session.FormData = cloneJSONMap(info.FormData)
|
||||
session.ResultData = cloneJSONMap(info.ResultData)
|
||||
session.Messages = sanitizeMessages(info.Messages)
|
||||
session.CurrentNodeID = strings.TrimSpace(info.CurrentNodeID)
|
||||
if session.CurrentNodeID == "" {
|
||||
session.CurrentNodeID = lastAssistantMessageID(session.Messages)
|
||||
}
|
||||
|
||||
if session.ID == 0 {
|
||||
err = db.Create(&session).Error
|
||||
return session, err
|
||||
}
|
||||
err = db.Save(&session).Error
|
||||
return session, err
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) GetList(ctx context.Context, userID uint, info systemReq.SysAIWorkflowSessionSearch) (list []systemResp.SysAIWorkflowSessionListItem, total int64, err error) {
|
||||
db := global.GVA_DB.WithContext(ctx).Model(&system.SysAIWorkflowSession{}).Where("user_id = ?", userID)
|
||||
if tab := strings.TrimSpace(info.Tab); tab != "" {
|
||||
db = db.Where("tab = ?", tab)
|
||||
}
|
||||
if keyword := strings.TrimSpace(info.Keyword); keyword != "" {
|
||||
like := "%" + keyword + "%"
|
||||
db = db.Where("title LIKE ? OR summary LIKE ?", like, like)
|
||||
}
|
||||
|
||||
err = db.Count(&total).Error
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
err = db.Select("id", "created_at", "updated_at", "tab", "title", "summary", "conversation_id", "current_node_id").
|
||||
Scopes(info.Paginate()).
|
||||
Order("updated_at desc").
|
||||
Find(&list).Error
|
||||
return list, total, err
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) GetDetail(ctx context.Context, userID uint, id uint) (session system.SysAIWorkflowSession, err error) {
|
||||
err = global.GVA_DB.WithContext(ctx).Where("id = ? AND user_id = ?", id, userID).First(&session).Error
|
||||
return session, err
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) Delete(ctx context.Context, userID uint, id uint) error {
|
||||
result := global.GVA_DB.WithContext(ctx).Where("id = ? AND user_id = ?", id, userID).Delete(&system.SysAIWorkflowSession{})
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
}
|
||||
if result.RowsAffected == 0 {
|
||||
return gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) titleFromMessages(messages []system.AIWorkflowMessage) string {
|
||||
for _, item := range messages {
|
||||
if item.Role == "user" && strings.TrimSpace(item.Content) != "" {
|
||||
return strings.TrimSpace(item.Content)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) titleFromForm(info systemReq.SysAIWorkflowSessionUpsert) string {
|
||||
if info.Tab == "analysis" {
|
||||
if requirement, ok := info.FormData["requirement"].(string); ok {
|
||||
return strings.TrimSpace(requirement)
|
||||
}
|
||||
}
|
||||
if source, ok := info.FormData["source"].(string); ok {
|
||||
return strings.TrimSpace(source)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *aiWorkflowSession) summaryFromResult(resultData map[string]interface{}) string {
|
||||
if resultData == nil {
|
||||
return ""
|
||||
}
|
||||
if summary, ok := resultData["summary"].(string); ok {
|
||||
return strings.TrimSpace(summary)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func sanitizeMessages(messages []system.AIWorkflowMessage) []system.AIWorkflowMessage {
|
||||
if len(messages) == 0 {
|
||||
return []system.AIWorkflowMessage{}
|
||||
}
|
||||
result := make([]system.AIWorkflowMessage, 0, len(messages))
|
||||
for _, item := range messages {
|
||||
result = append(result, system.AIWorkflowMessage{
|
||||
ID: strings.TrimSpace(item.ID),
|
||||
Role: strings.TrimSpace(item.Role),
|
||||
Content: item.Content,
|
||||
Snapshot: cloneJSONMap(item.Snapshot),
|
||||
ConversationID: strings.TrimSpace(item.ConversationID),
|
||||
MessageID: strings.TrimSpace(item.MessageID),
|
||||
CreatedAt: strings.TrimSpace(item.CreatedAt),
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func cloneJSONMap(source map[string]interface{}) map[string]interface{} {
|
||||
if len(source) == 0 {
|
||||
return map[string]interface{}{}
|
||||
}
|
||||
target := make(map[string]interface{}, len(source))
|
||||
for key, value := range source {
|
||||
target[key] = value
|
||||
}
|
||||
return target
|
||||
}
|
||||
|
||||
func lastAssistantMessageID(messages []system.AIWorkflowMessage) string {
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
if messages[i].Role == "assistant" && strings.TrimSpace(messages[i].ID) != "" {
|
||||
return messages[i].ID
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func firstNonEmpty(values ...string) string {
|
||||
for _, value := range values {
|
||||
if strings.TrimSpace(value) != "" {
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func truncateText(value string, size int) string {
|
||||
if size <= 0 {
|
||||
return ""
|
||||
}
|
||||
runes := []rune(strings.TrimSpace(value))
|
||||
if len(runes) <= size {
|
||||
return string(runes)
|
||||
}
|
||||
return string(runes[:size])
|
||||
}
|
||||
Reference in New Issue
Block a user