refactor: remove Subject field from Conversation model and related logic, replace with CustomerName
This commit is contained in:
@@ -84,9 +84,6 @@ func buildAnalyzeConversationResult(conversation models.Conversation, messages [
|
||||
|
||||
func buildConversationSummary(conversation models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
||||
parts := make([]string, 0, 4)
|
||||
if strings.TrimSpace(conversation.Subject) != "" {
|
||||
parts = append(parts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||
}
|
||||
if input.ObservedIssue != "" {
|
||||
parts = append(parts, "当前问题:"+input.ObservedIssue)
|
||||
} else if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||
@@ -103,7 +100,6 @@ func buildConversationSummary(conversation models.Conversation, messages []model
|
||||
|
||||
func buildConversationCorpus(conversation models.Conversation, messages []models.Message, input AnalyzeConversationInput) string {
|
||||
parts := make([]string, 0, len(messages)+4)
|
||||
parts = append(parts, strings.TrimSpace(conversation.Subject))
|
||||
parts = append(parts, strings.TrimSpace(conversation.LastMessageSummary))
|
||||
parts = append(parts, input.Goal, input.ObservedIssue, input.AdditionalContext)
|
||||
for i := range messages {
|
||||
@@ -200,9 +196,6 @@ func recommendQuestions(intent string, signals []string, input AnalyzeConversati
|
||||
|
||||
func buildConversationAnalysisFacts(conversation models.Conversation, messages []models.Message) []string {
|
||||
facts := make([]string, 0, 4)
|
||||
if strings.TrimSpace(conversation.Subject) != "" {
|
||||
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||
}
|
||||
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
func TestBuildAnalyzeConversationResult_RecommendsHandoffForComplaint(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "用户投诉扣费异常",
|
||||
LastMessageSummary: "用户反馈被重复扣费,并要求人工处理",
|
||||
}
|
||||
messages := []models.Message{
|
||||
@@ -33,7 +32,6 @@ func TestBuildAnalyzeConversationResult_RecommendsHandoffForComplaint(t *testing
|
||||
|
||||
func TestBuildAnalyzeConversationResult_RecommendsPrepareTicket(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "订单无法支付",
|
||||
LastMessageSummary: "用户要求登记问题并尽快处理",
|
||||
}
|
||||
messages := []models.Message{
|
||||
|
||||
@@ -114,7 +114,7 @@ func (g *CreateTicketGraph) buildCreateRequest(argumentsInJSON string) (request.
|
||||
req.Priority = args.Priority
|
||||
req.Severity = args.Severity
|
||||
if req.Title == "" {
|
||||
req.Title = strings.TrimSpace(g.conversation.Subject)
|
||||
req.Title = strings.TrimSpace(g.conversation.LastMessageSummary)
|
||||
}
|
||||
if req.Description == "" {
|
||||
req.Description = strings.TrimSpace(g.conversation.LastMessageSummary)
|
||||
|
||||
@@ -100,8 +100,6 @@ func buildDraftTitle(conversation models.Conversation, input PrepareTicketDraftI
|
||||
return limitText(input.Title, 80)
|
||||
case input.Issue != "":
|
||||
return limitText(input.Issue, 80)
|
||||
case strings.TrimSpace(conversation.Subject) != "":
|
||||
return limitText(conversation.Subject, 80)
|
||||
case strings.TrimSpace(conversation.LastMessageSummary) != "":
|
||||
return limitText(conversation.LastMessageSummary, 80)
|
||||
default:
|
||||
@@ -144,9 +142,6 @@ func hasSufficientIssueContext(input PrepareTicketDraftInput, description string
|
||||
|
||||
func buildConversationFacts(conversation models.Conversation, messages []models.Message) []string {
|
||||
facts := make([]string, 0, 4)
|
||||
if strings.TrimSpace(conversation.Subject) != "" {
|
||||
facts = append(facts, "会话主题:"+strings.TrimSpace(conversation.Subject))
|
||||
}
|
||||
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||
facts = append(facts, "最近摘要:"+strings.TrimSpace(conversation.LastMessageSummary))
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
func TestBuildPrepareTicketDraftResult_UsesConversationFallbacks(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "企业微信登录异常",
|
||||
LastMessageSummary: "用户反馈企业微信扫码后页面空白,无法进入工作台",
|
||||
}
|
||||
messages := []models.Message{
|
||||
@@ -38,7 +37,6 @@ func TestBuildPrepareTicketDraftResult_UsesConversationFallbacks(t *testing.T) {
|
||||
|
||||
func TestBuildPrepareTicketDraftResult_ReadyWithExplicitIssue(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "订单支付失败",
|
||||
LastMessageSummary: "用户反馈连续支付失败",
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ import (
|
||||
|
||||
func TestTriageServiceRequestResult_PrepareTicket(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "支付失败需要登记工单",
|
||||
LastMessageSummary: "用户要求建单跟进支付失败问题",
|
||||
}
|
||||
messages := []models.Message{
|
||||
@@ -31,7 +30,6 @@ func TestTriageServiceRequestResult_PrepareTicket(t *testing.T) {
|
||||
|
||||
func TestTriageServiceRequestResult_Handoff(t *testing.T) {
|
||||
conversation := models.Conversation{
|
||||
Subject: "投诉转人工",
|
||||
LastMessageSummary: "用户要求人工处理扣费投诉",
|
||||
}
|
||||
messages := []models.Message{
|
||||
|
||||
@@ -19,7 +19,7 @@ func BuildConversation(item *models.Conversation) response.ConversationResponse
|
||||
AIAgentID: item.AIAgentID,
|
||||
ChannelID: item.ChannelID,
|
||||
CustomerID: item.CustomerID,
|
||||
Subject: item.Subject,
|
||||
CustomerName: buildConversationCustomerName(item.CustomerID),
|
||||
Status: item.Status,
|
||||
ServiceMode: item.ServiceMode,
|
||||
Priority: item.Priority,
|
||||
@@ -62,6 +62,16 @@ func BuildConversation(item *models.Conversation) response.ConversationResponse
|
||||
return ret
|
||||
}
|
||||
|
||||
func buildConversationCustomerName(customerID int64) string {
|
||||
if customerID <= 0 {
|
||||
return ""
|
||||
}
|
||||
if customer := services.CustomerService.Get(customerID); customer != nil {
|
||||
return strings.TrimSpace(customer.Name)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func BuildParticipantResponses(conversationID int64) []response.ConversationParticipantResponse {
|
||||
list := services.ConversationParticipantService.Find(sqls.NewCnd().Eq("conversation_id", conversationID).Asc("id"))
|
||||
if len(list) == 0 {
|
||||
|
||||
@@ -36,7 +36,7 @@ func (c *ConversationController) AnyList() *web.JsonResult {
|
||||
|
||||
if keyword, _ := params.Get(c.Ctx, "keyword"); strs.IsNotBlank(keyword) {
|
||||
keywordLike := "%" + strings.TrimSpace(keyword) + "%"
|
||||
cnd.Where("subject LIKE ? OR last_message_summary LIKE ?", keywordLike, keywordLike)
|
||||
cnd.Where("last_message_summary LIKE ? OR customer_id IN (SELECT id FROM t_customer WHERE name LIKE ?)", keywordLike, keywordLike)
|
||||
}
|
||||
|
||||
// 标签搜索
|
||||
|
||||
@@ -327,7 +327,6 @@ type Conversation struct {
|
||||
AIAgentID int64 `gorm:"type:bigint;not null;default:0;index"` // AIAgentID 为当前会话绑定的 AI Agent ID。
|
||||
ChannelID int64 `gorm:"type:bigint;not null;default:0;index"` // ChannelID 为该会话来源接入渠道ID。
|
||||
CustomerID int64 `gorm:"type:bigint;not null;default:0;index"` // CustomerID 为会话所属客户 ID。
|
||||
Subject string `gorm:"type:varchar(255);not null;default:''"` // Subject 为会话标题或摘要。
|
||||
Status enums.IMConversationStatus `gorm:"type:int;not null;default:1;index"` // Status 为会话状态,如待接入、处理中、已关闭。
|
||||
ServiceMode enums.IMConversationServiceMode `gorm:"type:int;not null;default:3;index"` // ServiceMode 为服务模式,如仅AI、仅人工、AI优先人工接管。
|
||||
Priority int `gorm:"type:int;not null;default:0;index"` // Priority 为会话优先级。
|
||||
|
||||
@@ -22,7 +22,7 @@ type ConversationResponse struct {
|
||||
AIAgentID int64 `json:"aiAgentId"`
|
||||
ChannelID int64 `json:"channelId"`
|
||||
CustomerID int64 `json:"customerId"`
|
||||
Subject string `json:"subject"`
|
||||
CustomerName string `json:"customerName"`
|
||||
Status enums.IMConversationStatus `json:"status"`
|
||||
ServiceMode enums.IMConversationServiceMode `json:"serviceMode"`
|
||||
Priority int `json:"priority"`
|
||||
|
||||
@@ -2,10 +2,7 @@ package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
|
||||
"cs-agent/internal/events"
|
||||
@@ -61,7 +58,8 @@ func (s *conversationService) ListConversations(userID int64, filter request.Age
|
||||
|
||||
if strs.IsNotBlank(keyword) {
|
||||
keyword = strings.TrimSpace(keyword)
|
||||
cnd.Where("subject LIKE ? OR last_message_summary LIKE ?", "%"+keyword+"%", "%"+keyword+"%")
|
||||
keywordLike := "%" + keyword + "%"
|
||||
cnd.Where("last_message_summary LIKE ? OR customer_id IN (SELECT id FROM t_customer WHERE name LIKE ?)", keywordLike, keywordLike)
|
||||
}
|
||||
|
||||
switch filter {
|
||||
@@ -103,8 +101,6 @@ func (s *conversationService) getLatestNotFinishedByCustomerID(db *gorm.DB, cust
|
||||
}
|
||||
|
||||
func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, channelID, aiAgentID int64) (*models.Conversation, error) {
|
||||
subject := s.buildDefaultSubject(externalInfo)
|
||||
|
||||
aiAgent := AIAgentService.Get(aiAgentID)
|
||||
if aiAgent == nil || aiAgent.Status != enums.StatusOk {
|
||||
return nil, errorsx.InvalidParam("AI Agent not found")
|
||||
@@ -127,7 +123,6 @@ func (s *conversationService) Create(externalInfo openidentity.ExternalInfo, cha
|
||||
AIAgentID: aiAgentID,
|
||||
ChannelID: channelID,
|
||||
CustomerID: customerID,
|
||||
Subject: subject,
|
||||
Status: s.resolveInitialStatus(aiAgent.ServiceMode),
|
||||
ServiceMode: aiAgent.ServiceMode,
|
||||
Priority: 0,
|
||||
@@ -667,7 +662,10 @@ func (s *conversationService) BuildConversationSummary(conversation *models.Conv
|
||||
if strings.TrimSpace(conversation.LastMessageSummary) != "" {
|
||||
return conversation.LastMessageSummary
|
||||
}
|
||||
return strings.TrimSpace(conversation.Subject)
|
||||
if customer := CustomerService.Get(conversation.CustomerID); customer != nil {
|
||||
return strings.TrimSpace(customer.Name)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *conversationService) canCloseConversation(conversation *models.Conversation, operator *dto.AuthPrincipal) bool {
|
||||
@@ -806,22 +804,6 @@ func (s *conversationService) canLinkConversationCustomer(conv *models.Conversat
|
||||
}
|
||||
}
|
||||
|
||||
func (s *conversationService) buildDefaultSubject(externalInfo openidentity.ExternalInfo) string {
|
||||
if strs.IsNotBlank(externalInfo.ExternalName) {
|
||||
return externalInfo.ExternalName
|
||||
}
|
||||
return fmt.Sprintf("访客%s", hashUUID(externalInfo.ExternalID))
|
||||
}
|
||||
|
||||
func hashUUID(uuid string) string {
|
||||
if uuid == "" {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
h := md5.Sum([]byte(uuid))
|
||||
return hex.EncodeToString(h[:])[:8]
|
||||
}
|
||||
|
||||
func (s *conversationService) resolveInitialStatus(serviceMode enums.IMConversationServiceMode) enums.IMConversationStatus {
|
||||
switch serviceMode {
|
||||
case enums.IMConversationServiceModeHumanOnly:
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"log/slog"
|
||||
|
||||
"cs-agent/internal/models"
|
||||
@@ -154,6 +156,15 @@ func buildExternalCustomerName(externalInfo openidentity.ExternalInfo) string {
|
||||
return "访客" + hashUUID(externalInfo.ExternalID)
|
||||
}
|
||||
|
||||
func hashUUID(uuid string) string {
|
||||
if uuid == "" {
|
||||
return "unknown"
|
||||
}
|
||||
|
||||
h := md5.Sum([]byte(uuid))
|
||||
return hex.EncodeToString(h[:])[:8]
|
||||
}
|
||||
|
||||
func (s *customerService) CreateCustomer(req request.CreateCustomerRequest, operator *dto.AuthPrincipal) (*models.Customer, error) {
|
||||
if operator == nil {
|
||||
return nil, errorsx.Unauthorized("未登录或登录已过期")
|
||||
|
||||
@@ -55,7 +55,7 @@ func buildConversationAssignedNotifyBody(conversation *models.Conversation, assi
|
||||
}
|
||||
lines := []string{
|
||||
fmt.Sprintf("会话ID: #%d", conversation.ID),
|
||||
fmt.Sprintf("会话主题: %s", strs.DefaultIfBlank(conversation.Subject, "-")),
|
||||
fmt.Sprintf("会话摘要: %s", strs.DefaultIfBlank(services.ConversationService.BuildConversationSummary(conversation), "-")),
|
||||
fmt.Sprintf("接入渠道: %s", resolveConversationChannelLabel(conversation)),
|
||||
fmt.Sprintf("当前状态: %s", enums.GetIMConversationStatusLabel(conversation.Status)),
|
||||
fmt.Sprintf("处理人: %s", resolveNotifyUserLabel(assigneeID)),
|
||||
|
||||
@@ -852,7 +852,7 @@ func (s *ticketService) CreateFromConversation(req request.CreateTicketFromConve
|
||||
}
|
||||
title := strings.TrimSpace(req.Title)
|
||||
if title == "" {
|
||||
title = strings.TrimSpace(conversation.Subject)
|
||||
title = ConversationService.BuildConversationSummary(conversation)
|
||||
}
|
||||
description := strings.TrimSpace(req.Description)
|
||||
if description == "" {
|
||||
|
||||
Reference in New Issue
Block a user