Spaces:
Paused
Paused
kao0312 commited on
Commit ·
3dad4b0
1
Parent(s): 12aa997
fix: support multimodal image upload
Browse files- internal/chat.go +31 -30
- internal/models.go +33 -5
internal/chat.go
CHANGED
|
@@ -65,10 +65,35 @@ func makeUpstreamRequest(token string, messages []Message, model string) (*http.
|
|
| 65 |
autoWebSearch = false
|
| 66 |
}
|
| 67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 68 |
// 转换消息为上游格式
|
| 69 |
-
var upstreamMessages []map[string]
|
| 70 |
for _, msg := range messages {
|
| 71 |
-
upstreamMessages = append(upstreamMessages, msg.ToUpstreamMessage())
|
| 72 |
}
|
| 73 |
|
| 74 |
body := map[string]interface{}{
|
|
@@ -88,34 +113,10 @@ func makeUpstreamRequest(token string, messages []Message, model string) (*http.
|
|
| 88 |
"id": uuid.New().String(),
|
| 89 |
}
|
| 90 |
|
| 91 |
-
//
|
| 92 |
-
if len(
|
| 93 |
-
files
|
| 94 |
-
|
| 95 |
-
LogError("Failed to upload images: %v", err)
|
| 96 |
-
}
|
| 97 |
-
if len(files) > 0 {
|
| 98 |
-
// 设置 ref_user_msg_id
|
| 99 |
-
var filesData []map[string]interface{}
|
| 100 |
-
for _, f := range files {
|
| 101 |
-
fileMap := map[string]interface{}{
|
| 102 |
-
"type": f.Type,
|
| 103 |
-
"file": f.File,
|
| 104 |
-
"id": f.ID,
|
| 105 |
-
"url": f.URL,
|
| 106 |
-
"name": f.Name,
|
| 107 |
-
"status": f.Status,
|
| 108 |
-
"size": f.Size,
|
| 109 |
-
"error": f.Error,
|
| 110 |
-
"itemId": f.ItemID,
|
| 111 |
-
"media": f.Media,
|
| 112 |
-
"ref_user_msg_id": userMsgID,
|
| 113 |
-
}
|
| 114 |
-
filesData = append(filesData, fileMap)
|
| 115 |
-
}
|
| 116 |
-
body["files"] = filesData
|
| 117 |
-
body["current_user_message_id"] = userMsgID
|
| 118 |
-
}
|
| 119 |
}
|
| 120 |
|
| 121 |
bodyBytes, _ := json.Marshal(body)
|
|
|
|
| 65 |
autoWebSearch = false
|
| 66 |
}
|
| 67 |
|
| 68 |
+
// 上传图片并建立URL→FileID映射
|
| 69 |
+
urlToFileID := make(map[string]string)
|
| 70 |
+
var filesData []map[string]interface{}
|
| 71 |
+
if len(imageURLs) > 0 {
|
| 72 |
+
files, _ := UploadImages(token, imageURLs)
|
| 73 |
+
for i, f := range files {
|
| 74 |
+
if i < len(imageURLs) {
|
| 75 |
+
urlToFileID[imageURLs[i]] = f.ID
|
| 76 |
+
}
|
| 77 |
+
filesData = append(filesData, map[string]interface{}{
|
| 78 |
+
"type": f.Type,
|
| 79 |
+
"file": f.File,
|
| 80 |
+
"id": f.ID,
|
| 81 |
+
"url": f.URL,
|
| 82 |
+
"name": f.Name,
|
| 83 |
+
"status": f.Status,
|
| 84 |
+
"size": f.Size,
|
| 85 |
+
"error": f.Error,
|
| 86 |
+
"itemId": f.ItemID,
|
| 87 |
+
"media": f.Media,
|
| 88 |
+
"ref_user_msg_id": userMsgID,
|
| 89 |
+
})
|
| 90 |
+
}
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
// 转换消息为上游格式
|
| 94 |
+
var upstreamMessages []map[string]interface{}
|
| 95 |
for _, msg := range messages {
|
| 96 |
+
upstreamMessages = append(upstreamMessages, msg.ToUpstreamMessage(urlToFileID))
|
| 97 |
}
|
| 98 |
|
| 99 |
body := map[string]interface{}{
|
|
|
|
| 113 |
"id": uuid.New().String(),
|
| 114 |
}
|
| 115 |
|
| 116 |
+
// 添加files字段
|
| 117 |
+
if len(filesData) > 0 {
|
| 118 |
+
body["files"] = filesData
|
| 119 |
+
body["current_user_message_id"] = userMsgID
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 120 |
}
|
| 121 |
|
| 122 |
bodyBytes, _ := json.Marshal(body)
|
internal/models.go
CHANGED
|
@@ -111,12 +111,40 @@ func (m *Message) ParseContent() (text string, imageURLs []string) {
|
|
| 111 |
return text, imageURLs
|
| 112 |
}
|
| 113 |
|
| 114 |
-
// 转换为上游消息格式
|
| 115 |
-
func (m *Message) ToUpstreamMessage(
|
| 116 |
-
text,
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
"role": m.Role,
|
| 119 |
-
"content":
|
| 120 |
}
|
| 121 |
}
|
| 122 |
|
|
|
|
| 111 |
return text, imageURLs
|
| 112 |
}
|
| 113 |
|
| 114 |
+
// 转换为上游消息格式,支持多模态
|
| 115 |
+
func (m *Message) ToUpstreamMessage(urlToFileID map[string]string) map[string]interface{} {
|
| 116 |
+
text, imageURLs := m.ParseContent()
|
| 117 |
+
|
| 118 |
+
// 无图片,返回纯文本
|
| 119 |
+
if len(imageURLs) == 0 {
|
| 120 |
+
return map[string]interface{}{
|
| 121 |
+
"role": m.Role,
|
| 122 |
+
"content": text,
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
|
| 126 |
+
// 有图片,构建多模态内容
|
| 127 |
+
var content []interface{}
|
| 128 |
+
if text != "" {
|
| 129 |
+
content = append(content, map[string]interface{}{
|
| 130 |
+
"type": "text",
|
| 131 |
+
"text": text,
|
| 132 |
+
})
|
| 133 |
+
}
|
| 134 |
+
for _, imgURL := range imageURLs {
|
| 135 |
+
if fileID, ok := urlToFileID[imgURL]; ok {
|
| 136 |
+
content = append(content, map[string]interface{}{
|
| 137 |
+
"type": "image_url",
|
| 138 |
+
"image_url": map[string]interface{}{
|
| 139 |
+
"url": fileID,
|
| 140 |
+
},
|
| 141 |
+
})
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
return map[string]interface{}{
|
| 146 |
"role": m.Role,
|
| 147 |
+
"content": content,
|
| 148 |
}
|
| 149 |
}
|
| 150 |
|