Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 

151 wiersze
3.8 KiB

  1. package relay
  2. import (
  3. "crypto/sha256"
  4. "encoding/hex"
  5. "strings"
  6. "github.com/QuantumNous/new-api/common"
  7. "github.com/QuantumNous/new-api/model"
  8. )
  9. const maxUpstreamRequestSnapshotBytes = 256 * 1024
  10. func buildUpstreamRequestSnapshot(raw []byte) *model.TaskUpstreamRequestSnapshot {
  11. if len(raw) == 0 {
  12. return nil
  13. }
  14. snapshot := &model.TaskUpstreamRequestSnapshot{
  15. RawBytes: len(raw),
  16. SHA256: sha256Hex(raw),
  17. }
  18. var body any
  19. if err := common.Unmarshal(raw, &body); err == nil {
  20. sanitized, redacted := sanitizeUpstreamRequestValue(body)
  21. snapshot.Body = sanitized
  22. snapshot.Redacted = redacted
  23. } else {
  24. snapshot.Body = map[string]any{
  25. "raw_preview": truncateStringToBytes(string(raw), maxUpstreamRequestSnapshotBytes/2),
  26. "format": "non_json",
  27. }
  28. snapshot.Truncated = len(raw) > maxUpstreamRequestSnapshotBytes/2
  29. }
  30. finalizeUpstreamRequestSnapshot(snapshot, raw)
  31. return snapshot
  32. }
  33. func BuildUpstreamRequestSnapshotForTask(raw []byte) *model.TaskUpstreamRequestSnapshot {
  34. return buildUpstreamRequestSnapshot(raw)
  35. }
  36. func sanitizeUpstreamRequestValue(value any) (any, bool) {
  37. switch v := value.(type) {
  38. case map[string]any:
  39. out := make(map[string]any, len(v))
  40. redacted := false
  41. for key, item := range v {
  42. sanitized, itemRedacted := sanitizeUpstreamRequestValue(item)
  43. out[key] = sanitized
  44. redacted = redacted || itemRedacted
  45. }
  46. return out, redacted
  47. case []any:
  48. out := make([]any, len(v))
  49. redacted := false
  50. for i, item := range v {
  51. sanitized, itemRedacted := sanitizeUpstreamRequestValue(item)
  52. out[i] = sanitized
  53. redacted = redacted || itemRedacted
  54. }
  55. return out, redacted
  56. case string:
  57. if mediaType, ok := parseBase64DataURI(v); ok {
  58. return map[string]any{
  59. "redacted": true,
  60. "kind": "data_uri",
  61. "media_type": mediaType,
  62. "bytes": len(v),
  63. "sha256": sha256Hex([]byte(v)),
  64. }, true
  65. }
  66. return v, false
  67. default:
  68. return value, false
  69. }
  70. }
  71. func parseBase64DataURI(value string) (string, bool) {
  72. lower := strings.ToLower(value)
  73. if !strings.HasPrefix(lower, "data:") {
  74. return "", false
  75. }
  76. marker := ";base64,"
  77. idx := strings.Index(lower, marker)
  78. if idx <= len("data:") {
  79. return "", false
  80. }
  81. mediaType := value[len("data:"):idx]
  82. if !strings.HasPrefix(strings.ToLower(mediaType), "image/") &&
  83. !strings.HasPrefix(strings.ToLower(mediaType), "audio/") &&
  84. !strings.HasPrefix(strings.ToLower(mediaType), "video/") {
  85. return "", false
  86. }
  87. return mediaType, true
  88. }
  89. func finalizeUpstreamRequestSnapshot(snapshot *model.TaskUpstreamRequestSnapshot, raw []byte) {
  90. updateStoredBytes(snapshot)
  91. if snapshot.StoredBytes <= maxUpstreamRequestSnapshotBytes {
  92. return
  93. }
  94. bodyBytes, err := common.Marshal(snapshot.Body)
  95. previewSource := raw
  96. if err == nil {
  97. previewSource = bodyBytes
  98. }
  99. snapshot.Body = map[string]any{
  100. "truncated_preview": truncateStringToBytes(string(previewSource), maxUpstreamRequestSnapshotBytes/2),
  101. }
  102. snapshot.Truncated = true
  103. updateStoredBytes(snapshot)
  104. for snapshot.StoredBytes > maxUpstreamRequestSnapshotBytes {
  105. body, _ := snapshot.Body.(map[string]any)
  106. preview, _ := body["truncated_preview"].(string)
  107. if len(preview) == 0 {
  108. break
  109. }
  110. body["truncated_preview"] = truncateStringToBytes(preview, len(preview)/2)
  111. snapshot.Body = body
  112. updateStoredBytes(snapshot)
  113. }
  114. }
  115. func updateStoredBytes(snapshot *model.TaskUpstreamRequestSnapshot) {
  116. for i := 0; i < 4; i++ {
  117. data, err := common.Marshal(snapshot)
  118. if err != nil {
  119. return
  120. }
  121. if snapshot.StoredBytes == len(data) {
  122. return
  123. }
  124. snapshot.StoredBytes = len(data)
  125. }
  126. }
  127. func truncateStringToBytes(value string, maxBytes int) string {
  128. if maxBytes <= 0 || len(value) <= maxBytes {
  129. return value
  130. }
  131. return value[:maxBytes]
  132. }
  133. func sha256Hex(data []byte) string {
  134. sum := sha256.Sum256(data)
  135. return hex.EncodeToString(sum[:])
  136. }