Files
ds2api/internal/promptcompat/file_refs.go
2026-04-26 06:58:20 +08:00

95 lines
2.6 KiB
Go

package promptcompat
import "strings"
func CollectOpenAIRefFileIDs(req map[string]any) []string {
if len(req) == 0 {
return nil
}
out := make([]string, 0, 4)
seen := map[string]struct{}{}
for _, key := range []string{
"ref_file_ids",
"file_ids",
"attachments",
"messages",
"input",
} {
raw := req[key]
if raw == nil {
continue
}
// Skip top-level strings for 'messages' and 'input' as they are likely plain text content,
// not file IDs. String file IDs are expected in 'ref_file_ids' or 'file_ids'.
if key == "messages" || key == "input" {
if _, ok := raw.(string); ok {
continue
}
}
appendOpenAIRefFileIDs(&out, seen, raw)
}
if len(out) == 0 {
return nil
}
return out
}
func appendOpenAIRefFileIDs(out *[]string, seen map[string]struct{}, raw any) {
switch x := raw.(type) {
case string:
addOpenAIRefFileID(out, seen, x)
case []string:
for _, item := range x {
addOpenAIRefFileID(out, seen, item)
}
case []any:
for _, item := range x {
appendOpenAIRefFileIDs(out, seen, item)
}
case map[string]any:
if fileID := strings.TrimSpace(asString(x["file_id"])); fileID != "" {
addOpenAIRefFileID(out, seen, fileID)
}
if strings.Contains(strings.ToLower(strings.TrimSpace(asString(x["type"]))), "file") {
if fileID := strings.TrimSpace(asString(x["id"])); fileID != "" {
addOpenAIRefFileID(out, seen, fileID)
}
}
if fileMap, ok := x["file"].(map[string]any); ok {
if fileID := strings.TrimSpace(asString(fileMap["file_id"])); fileID != "" {
addOpenAIRefFileID(out, seen, fileID)
}
if fileID := strings.TrimSpace(asString(fileMap["id"])); fileID != "" {
addOpenAIRefFileID(out, seen, fileID)
}
}
// Recurse into potential containers. Note: we do NOT recurse into 'content' or 'input'
// if they are plain strings (handled by the top-level switch), but they are usually
// nested inside the map branch anyway.
// To be safe, we only recurse into these known container keys.
for _, key := range []string{"ref_file_ids", "file_ids", "attachments", "messages", "input", "content", "files", "items", "data", "source"} {
if nested, ok := x[key]; ok {
// If it's a message content that is a string, we must NOT treat it as an ID.
if key == "content" || key == "input" {
if _, ok := nested.(string); ok {
continue
}
}
appendOpenAIRefFileIDs(out, seen, nested)
}
}
}
}
func addOpenAIRefFileID(out *[]string, seen map[string]struct{}, fileID string) {
fileID = strings.TrimSpace(fileID)
if fileID == "" {
return
}
if _, ok := seen[fileID]; ok {
return
}
seen[fileID] = struct{}{}
*out = append(*out, fileID)
}