@@ -448,41 +448,12 @@ func (s *ConversationService) SendMessage(userID, conversationID uint, req *requ
|
||||
global.GVA_LOG.Info(fmt.Sprintf("替换了 {{getvar::}} 变量"))
|
||||
}
|
||||
|
||||
// 提取 <Status_block> 和 <maintext>,保护它们不被正则脚本修改
|
||||
statusBlock, contentWithoutStatus := regexService.ExtractStatusBlock(displayContent)
|
||||
maintext, contentWithoutMaintext := regexService.ExtractMaintext(contentWithoutStatus)
|
||||
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[状态栏] 提取到 Status_block 长度: %d, maintext 长度: %d", len(statusBlock), len(maintext)))
|
||||
if len(statusBlock) > 0 {
|
||||
previewLen := len(statusBlock)
|
||||
if previewLen > 100 {
|
||||
previewLen = 100
|
||||
}
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[状态栏] Status_block 内容预览: %s", statusBlock[:previewLen]))
|
||||
}
|
||||
|
||||
// 应用显示阶段的正则脚本 (Placement 3) - 只处理剩余内容
|
||||
finalProcessedContent := contentWithoutMaintext
|
||||
displayScripts, err2 := regexService.GetScriptsForPlacement(userID, 3, &conversation.CharacterID, nil)
|
||||
if err2 == nil && len(displayScripts) > 0 {
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[状态栏] 应用正则脚本前的内容长度: %d", len(finalProcessedContent)))
|
||||
finalProcessedContent = regexService.ExecuteScripts(displayScripts, finalProcessedContent, userName, character.Name)
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[状态栏] 应用了 %d 个显示阶段正则脚本,处理后内容长度: %d", len(displayScripts), len(finalProcessedContent)))
|
||||
}
|
||||
|
||||
// 重新组装内容:maintext + Status_block + 处理后的内容
|
||||
finalContent := finalProcessedContent
|
||||
if maintext != "" {
|
||||
finalContent = "<maintext>" + maintext + "</maintext>\n\n" + finalContent
|
||||
}
|
||||
if statusBlock != "" {
|
||||
finalContent = finalContent + "\n\n<Status_block>\n" + statusBlock + "\n</Status_block>"
|
||||
}
|
||||
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[状态栏] 最终返回内容长度: %d", len(finalContent)))
|
||||
// 注意:此时 displayContent 中的 <Status_block> 已经被 Placement 1 正则脚本
|
||||
// 替换成了包含 YAML 数据的 HTML 模板,所以不需要再提取和保护
|
||||
// 直接返回给前端即可
|
||||
|
||||
resp := response.ToMessageResponse(&assistantMessage)
|
||||
resp.Content = finalContent // 使用处理后的显示内容
|
||||
resp.Content = displayContent // 使用处理后的显示内容
|
||||
return &resp, nil
|
||||
}
|
||||
|
||||
@@ -632,10 +603,32 @@ func (s *ConversationService) callAIService(conversation app.Conversation, chara
|
||||
}
|
||||
global.GVA_LOG.Info(fmt.Sprintf("========== AI返回的完整内容 ==========\n%s\n==========================================", aiResponse))
|
||||
|
||||
// 【重要】不再应用 Placement 1 正则脚本,保留 AI 原始回复
|
||||
// 让 SendMessage 函数来提取和保护 <Status_block> 和 <maintext>
|
||||
// 前端会负责渲染这些标签
|
||||
global.GVA_LOG.Info("[AI回复] 保留原始内容,不应用输出阶段正则脚本")
|
||||
// 应用输出阶段的正则脚本 (Placement 1)
|
||||
// 这里会把 <Status_block> 替换成 HTML 模板,并注入 YAML 数据
|
||||
var regexService RegexScriptService
|
||||
global.GVA_LOG.Info(fmt.Sprintf("查询输出阶段正则脚本: userID=%d, placement=1, charID=%d", conversation.UserID, conversation.CharacterID))
|
||||
outputScripts, err := regexService.GetScriptsForPlacement(conversation.UserID, 1, &conversation.CharacterID, nil)
|
||||
if err != nil {
|
||||
global.GVA_LOG.Error(fmt.Sprintf("查询输出阶段正则脚本失败: %v", err))
|
||||
} else {
|
||||
global.GVA_LOG.Info(fmt.Sprintf("找到 %d 个输出阶段正则脚本", len(outputScripts)))
|
||||
if len(outputScripts) > 0 {
|
||||
// 获取用户信息
|
||||
var user app.AppUser
|
||||
err = global.GVA_DB.Where("id = ?", conversation.UserID).First(&user).Error
|
||||
userName := ""
|
||||
if err == nil {
|
||||
userName = user.Username
|
||||
if userName == "" {
|
||||
userName = user.NickName
|
||||
}
|
||||
}
|
||||
|
||||
originalResponse := aiResponse
|
||||
aiResponse = regexService.ExecuteScripts(outputScripts, aiResponse, userName, character.Name)
|
||||
global.GVA_LOG.Info(fmt.Sprintf("应用了 %d 个输出阶段正则脚本,原始长度: %d, 处理后长度: %d", len(outputScripts), len(originalResponse), len(aiResponse)))
|
||||
}
|
||||
}
|
||||
|
||||
return aiResponse, nil
|
||||
}
|
||||
|
||||
@@ -222,7 +222,13 @@ func (s *RegexScriptService) ExecuteScript(script *app.RegexScript, text string,
|
||||
global.GVA_LOG.Warn("正则表达式编译失败", zap.String("pattern", script.FindRegex), zap.Error(err))
|
||||
return text, err
|
||||
}
|
||||
result = re.ReplaceAllString(result, script.ReplaceWith)
|
||||
|
||||
// 特殊处理:如果正则匹配 <Status_block>,需要提取 YAML 并注入到 HTML 模板中
|
||||
if strings.Contains(script.FindRegex, "Status_block") {
|
||||
result = s.replaceStatusBlockWithHTML(result, script.ReplaceWith, re)
|
||||
} else {
|
||||
result = re.ReplaceAllString(result, script.ReplaceWith)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 修剪字符串
|
||||
@@ -237,6 +243,35 @@ func (s *RegexScriptService) ExecuteScript(script *app.RegexScript, text string,
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// replaceStatusBlockWithHTML 替换 <Status_block> 为 HTML 模板,并注入 YAML 数据
|
||||
func (s *RegexScriptService) replaceStatusBlockWithHTML(text string, htmlTemplate string, statusBlockRegex *regexp.Regexp) string {
|
||||
return statusBlockRegex.ReplaceAllStringFunc(text, func(match string) string {
|
||||
// 提取 YAML 数据
|
||||
yamlRegex := regexp.MustCompile(`<Status_block>\s*([\s\S]*?)\s*</Status_block>`)
|
||||
yamlMatches := yamlRegex.FindStringSubmatch(match)
|
||||
|
||||
if len(yamlMatches) < 2 {
|
||||
global.GVA_LOG.Warn("无法提取 Status_block 中的 YAML 数据")
|
||||
return match
|
||||
}
|
||||
|
||||
yamlData := strings.TrimSpace(yamlMatches[1])
|
||||
|
||||
// 在 HTML 模板中查找 <script id="yaml-data-source" type="text/yaml"></script>
|
||||
// 并将 YAML 数据注入其中
|
||||
injectedHTML := strings.Replace(
|
||||
htmlTemplate,
|
||||
`<script id="yaml-data-source" type="text/yaml"></script>`,
|
||||
fmt.Sprintf(`<script id="yaml-data-source" type="text/yaml">%s</script>`, yamlData),
|
||||
1,
|
||||
)
|
||||
|
||||
global.GVA_LOG.Info(fmt.Sprintf("[正则脚本] 已将 Status_block YAML 数据注入到 HTML 模板,YAML 长度: %d", len(yamlData)))
|
||||
|
||||
return injectedHTML
|
||||
})
|
||||
}
|
||||
|
||||
// substituteMacros 替换宏变量
|
||||
func (s *RegexScriptService) substituteMacros(text string, userName string, charName string) string {
|
||||
result := text
|
||||
|
||||
Reference in New Issue
Block a user