Files
prompts-core/service/utils.go
2026-05-12 13:59:15 +08:00

338 lines
6.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package service
import (
"context"
"encoding/json"
"fmt"
"prompts-core/model/dto"
"sort"
"strings"
"github.com/gogf/gf/v2/container/gvar"
"github.com/gogf/gf/v2/frame/g"
)
// ============================================
// 工具函数
// ============================================
func getField(item map[string]any, fallback string) string {
if field := asString(item["field"]); field != "" {
return field
}
return fallback
}
func getLabel(item map[string]any) string {
return asString(item["label"])
}
func getValue(item map[string]any) any {
return item["value"]
}
func cloneWithValue(item map[string]any, value any) map[string]any {
cloned := make(map[string]any)
for k, v := range item {
cloned[k] = v
}
cloned["value"] = value
return cloned
}
func isSensitiveField(field string) bool {
f := strings.ToLower(field)
return f == "apikey" || f == "authorization"
}
func isAPIKeyField(field string) bool {
f := strings.ToLower(field)
return f == "apikey" || f == "authorization"
}
func isTextType(field, label string) bool {
f := strings.ToLower(field)
l := strings.ToLower(label)
return f == "prompt" || f == "text" ||
l == "提示词" || l == "文本内容" || l == "prompt" || l == "text"
}
func isDuplicate(userText, field, label string, value any) bool {
lowerText := strings.ToLower(userText)
if label != "" && strings.Contains(lowerText, strings.ToLower(label)) {
return true
}
if field != "" && strings.Contains(lowerText, strings.ToLower(field)) {
return true
}
// 检查值
if v := asString(value); v != "" && strings.Contains(lowerText, strings.ToLower(v)) {
return true
}
return false
}
func isEmptyValue(v any) bool {
if v == nil {
return true
}
if s, ok := v.(string); ok {
return strings.TrimSpace(s) == ""
}
return false
}
func isNilOrEmpty(v any) bool {
if v == nil {
return true
}
if s, ok := v.(string); ok {
return strings.TrimSpace(s) == ""
}
return false
}
func asString(v any) string {
switch t := v.(type) {
case string:
return t
default:
b, _ := json.Marshal(t)
return strings.Trim(string(b), "\"")
}
}
func formatValue(v any) string {
return strings.TrimSpace(asString(v))
}
func mapToText(m map[string]any) string {
if len(m) == 0 {
return ""
}
keys := sortedKeys(m)
var parts []string
for _, k := range keys {
if isNilOrEmpty(m[k]) {
continue
}
parts = append(parts, fmt.Sprintf("%s%s", k, formatValue(m[k])))
}
return strings.Join(parts, "")
}
func sortedKeys(m map[string]any) []string {
keys := make([]string, 0, len(m))
for k := range m {
keys = append(keys, k)
}
sort.Strings(keys)
return keys
}
func mustMarshal(v any) string {
b, err := json.Marshal(v)
if err != nil {
return "{}"
}
return string(b)
}
func formatTaskError(taskID, errMsg string) error {
if strings.TrimSpace(errMsg) == "" {
return fmt.Errorf("任务失败(taskId=%s)", taskID)
}
return fmt.Errorf("任务失败(taskId=%s): %s", taskID, errMsg)
}
func getIntConfig(ctx context.Context, key string, fallback int) int {
v := g.Cfg().MustGet(ctx, key)
if v.IsEmpty() {
return fallback
}
return v.Int()
}
// ============================================
// Schema 处理
// ============================================
func enrichSchemaWithValues(schema []any, values map[string]any) []any {
if len(schema) == 0 || len(values) == 0 {
return schema
}
result := make([]any, len(schema))
copy(result, schema)
for i, item := range result {
m, ok := item.(map[string]any)
if !ok {
continue
}
field := getField(m, "")
if field == "" {
continue
}
// 已有 value 则跳过
if _, hasValue := m["value"]; hasValue {
continue
}
// 补充 value
if v, exists := values[field]; exists {
m["value"] = v
result[i] = m
}
}
return result
}
// extractContentFromResponse 从模型完整响应中提取 content 字段
func extractContentFromResponse(text string) string {
// 尝试解析为完整的 choices 响应
var response struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
if err := json.Unmarshal([]byte(text), &response); err != nil {
return ""
}
if len(response.Choices) > 0 && response.Choices[0].Message.Content != "" {
return response.Choices[0].Message.Content
}
return ""
}
// ============================================
// 值提取
// ============================================
func extractSystemValues(req *dto.ComposeMessagesReq) map[string]any {
if req == nil {
return nil
}
values := make(map[string]any)
for _, value := range req.Form {
item, ok := value.(map[string]any)
if !ok || len(item) == 0 {
continue
}
field := getField(item, "")
if field == "" || isSensitiveField(field) {
continue
}
if v := getValue(item); !isNilOrEmpty(v) {
values[field] = v
}
}
return values
}
func extractModelKey(form map[string]any) string {
for _, value := range form {
item, ok := value.(map[string]any)
if !ok {
continue
}
field := getField(item, "")
if isAPIKeyField(field) {
key := strings.TrimSpace(asString(getValue(item)))
if key != "" {
if strings.Contains(key, ":") {
return key
}
return "Authorization:" + key
}
}
}
return ""
}
// ==================== 工具方法 ====================
// convertToMessages 将数据库 any 类型转换为 []Message
// 支持JSON字符串、[]byte、[]interface{}、以及 content 为字符串数组的格式
func (s *sessionService) convertToMessages(data any) []Message {
if data == nil {
return []Message{}
}
// 处理 *gvar.Var
if v, ok := data.(*gvar.Var); ok {
if v == nil || v.IsNil() || v.IsEmpty() {
return []Message{}
}
data = v.Val()
}
var rawList []any
switch v := data.(type) {
case string:
if err := json.Unmarshal([]byte(v), &rawList); err != nil {
g.Log().Warningf(context.Background(), "[会话] 解析JSON字符串失败 err=%v data=%.200s", err, v)
return []Message{}
}
case []byte:
if err := json.Unmarshal(v, &rawList); err != nil {
g.Log().Warningf(context.Background(), "[会话] 解析字节数组失败 err=%v", err)
return []Message{}
}
case []interface{}:
rawList = v
default:
b, _ := json.Marshal(v)
if err := json.Unmarshal(b, &rawList); err != nil {
g.Log().Warningf(context.Background(), "[会话] 解析未知类型失败 err=%v type=%T", err, v)
return []Message{}
}
}
// 转换每个元素为 Message
var messages []Message
for _, item := range rawList {
var msg Message
switch val := item.(type) {
case string:
if err := json.Unmarshal([]byte(val), &msg); err != nil {
g.Log().Warningf(context.Background(), "[会话] 解析消息元素失败 err=%v data=%s", err, val)
continue
}
case map[string]interface{}:
b, _ := json.Marshal(val)
json.Unmarshal(b, &msg)
default:
b, _ := json.Marshal(val)
json.Unmarshal(b, &msg)
}
messages = append(messages, msg)
}
if messages == nil {
messages = []Message{}
}
return messages
}