refactor(prompts-core): 重构代码结构和优化工具函数

This commit is contained in:
2026-06-10 14:51:25 +08:00
parent 1c1db7e30c
commit b69e7386e2
10 changed files with 164 additions and 432 deletions

View File

@@ -1,197 +1,81 @@
package util
import (
"encoding/json"
"fmt"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/util/gconv"
)
// ConvertToMessages 将原始数据转换为消息列表
func ConvertToMessages(raw any) []map[string]any {
if raw == nil {
return nil
}
j := gjson.New(raw)
messages := j.Get("messages")
if !messages.IsNil() {
return gconv.Maps(messages.Val())
}
return []map[string]any{j.Map()}
}
// FormToJSON 将表单数据转换为 JSON 字符串
func FormToJSON(form []map[string]any) string {
if form == nil {
return "[]"
}
b, _ := json.Marshal(form)
return string(b)
}
// UserFormToJSON 将用户表单数据转换为 JSON 字符串
func UserFormToJSON(form []map[string]any) string {
if form == nil {
return "{}"
}
b, _ := json.Marshal(form)
return string(b)
}
// MustMarshalToMap 将对象序列化为 map[string]any失败时返回空 map
func MustMarshalToMap(v any) map[string]any {
b, err := json.Marshal(v)
if err != nil {
return make(map[string]any)
}
var m map[string]any
json.Unmarshal(b, &m)
return m
}
// JSONPretty 将任意类型转为格式化的 JSON 字符串
func JSONPretty(v any) string {
if gv, ok := v.(*gvar.Var); ok {
v = gconv.Map(gv.String())
}
var tmp map[string]any
if err := gconv.Struct(v, &tmp); err != nil {
return gconv.String(v)
}
b, _ := json.Marshal(tmp)
return string(b)
}
// ParseJSONFieldFromGvar 专门处理 *gvar.Var 类型的 JSON 字段解析
func ParseJSONFieldFromGvar(source any, target any) {
if source == nil {
return
}
switch v := source.(type) {
case *gvar.Var:
if v.IsNil() {
return
}
// 尝试获取 map
if m := v.Map(); len(m) > 0 {
data, _ := json.Marshal(m)
json.Unmarshal(data, target)
return
}
// 尝试解析 JSON 字符串
str := v.String()
if str != "" && str != "<nil>" {
json.Unmarshal([]byte(str), target)
}
default:
// 其他类型走原来的逻辑
data, _ := json.Marshal(source)
json.Unmarshal(data, target)
}
}
// MergeConsult 将 consult 附件合并到模型生成的 messages 结构中
func MergeConsult(req map[string]any, messages map[string]any, extendMapping map[string]any) map[string]any {
if len(req) == 0 || len(messages) == 0 || len(extendMapping) == 0 {
return messages
}
// 1) 获取 consult 数组
consult := gconv.Interfaces(req["consult"])
if len(consult) == 0 {
return messages
}
// 2) 获取配置
targetPath := gconv.String(extendMapping["target_content_path"])
if targetPath == "" {
return messages
}
templates := gconv.Map(extendMapping["attachment_templates"])
if len(templates) == 0 {
if targetPath == "" || len(templates) == 0 {
return messages
}
// 3) 转为 gjson 操作
msgJson := gjson.New(messages)
// 固定:如果有 rounds 结构,路径替换为 rounds.0.{targetPath}
if arr := msgJson.Get("rounds.0").Array(); arr != nil {
// rounds 路径修正
if !msgJson.Get("rounds.0").IsNil() {
targetPath = "rounds.0." + targetPath
}
// 4) 遍历 consult按类型生成附件并追加
// 遍历追加
for _, item := range consult {
itemJson := gjson.New(item)
itemType := itemJson.Get("type").String()
if itemType == "" {
continue
}
// 查找对应模板
tmpl := gconv.Map(templates[itemType])
if len(tmpl) == 0 {
if itemType == "" || len(tmpl) == 0 {
continue
}
// 生成附件对象
attachment := buildAttachment(tmpl, itemJson.Get("url").String())
if attachment == nil {
continue
}
// 获取当前数组长度,用索引追加
arr := msgJson.Get(targetPath).Array()
idx := len(arr)
indexPath := fmt.Sprintf("%s.%d", targetPath, idx)
_ = msgJson.Set(indexPath, attachment)
idx := len(msgJson.Get(targetPath).Array())
_ = msgJson.Set(fmt.Sprintf("%s.%d", targetPath, idx), attachment)
}
return msgJson.Map()
}
// buildAttachment 根据模板和用户数据生成附件对象
func buildAttachment(tmpl map[string]any, url string) map[string]any {
typ := gconv.String(tmpl["type"])
if typ == "" || url == "" {
return nil
}
// 深拷贝 body 并填充 url
body := gconv.Map(tmpl["body"])
bodyJson := gjson.New(body)
bodyJson = fillEmpty(bodyJson, url)
fillEmptyInPlace(body, url)
return map[string]any{
"type": typ,
typ: bodyJson.Map(),
typ: body,
}
}
// fillEmpty 递归查找空字符串并替换
func fillEmpty(j *gjson.Json, value string) *gjson.Json {
m := j.Map()
func fillEmptyInPlace(m map[string]any, value string) {
for k, v := range m {
switch vv := v.(type) {
case string:
if vv == "" {
_ = j.Set(k, value)
m[k] = value
}
case map[string]any:
_ = j.Set(k, fillEmpty(gjson.New(vv), value).Map())
fillEmptyInPlace(vv, value)
}
}
return j
}

View File

@@ -4,6 +4,7 @@ import (
"strings"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/util/gconv"
)
// ReverseMap 映射 payload 到 mapping
@@ -20,80 +21,37 @@ func ReverseMap(mapping map[string]any, payload map[string]any) map[string]any {
return jsonObj.Map()
}
// ExtractUserText 从 messages map 中提取用户文本,返回标准的 user message 结构
// ExtractUserText 从 messages 中提取所有 user 文本
func ExtractUserText(messages map[string]any) map[string]any {
var texts []string
msgJson := gjson.New(messages)
// 1) rounds 结构:遍历每轮
if rounds, ok := messages["rounds"].([]any); ok {
for _, round := range rounds {
if rm, ok := round.(map[string]any); ok {
if msgs, ok := rm["messages"].([]any); ok {
texts = append(texts, extractTextFromRoleUser(msgs)...)
msgs := msgJson.Get("rounds.0.messages")
if msgs.IsNil() {
msgs = msgJson.Get("messages")
}
var texts []string
for _, m := range msgs.Array() {
msg := gjson.New(m)
if msg.Get("role").String() != "user" {
continue
}
content := msg.Get("content").Val()
switch c := content.(type) {
case string:
texts = append(texts, c)
case []any:
for _, item := range c {
if m, ok := item.(map[string]any); ok {
if t := gconv.String(m["text"]); t != "" {
texts = append(texts, t)
}
}
}
}
} else if msgs, ok := messages["messages"].([]any); ok {
// 2) messages 结构
texts = extractTextFromRoleUser(msgs)
}
// 3) 构建返回结构
return map[string]any{
"role": "user",
"content": strings.Join(texts, "\n"),
}
}
// extractTextFromRoleUser 从 messages 数组中提取所有 role=user 的文本
func extractTextFromRoleUser(msgs []any) []string {
var texts []string
for _, msg := range msgs {
m, ok := msg.(map[string]any)
if !ok {
continue
}
if role, _ := m["role"].(string); role != "user" {
continue
}
texts = append(texts, extractAllText(m["content"])...)
}
return texts
}
// extractAllText 从 content 中提取所有文本(递归,最大兼容)
func extractAllText(content any) []string {
switch c := content.(type) {
case string:
return []string{c}
case []any:
var texts []string
for _, item := range c {
m, ok := item.(map[string]any)
if !ok {
continue
}
if t, ok := m["text"].(string); ok && t != "" {
texts = append(texts, t)
continue
}
for _, v := range m {
texts = append(texts, extractAllText(v)...)
}
}
return texts
case map[string]any:
if t, ok := c["text"].(string); ok && t != "" {
return []string{t}
}
var texts []string
for _, v := range c {
texts = append(texts, extractAllText(v)...)
}
return texts
}
return nil
}