fix: restore Claude file conversion and preserve stream status
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
package claude
|
package claude
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/QuantumNous/new-api/common"
|
"github.com/QuantumNous/new-api/common"
|
||||||
"github.com/QuantumNous/new-api/constant"
|
"github.com/QuantumNous/new-api/constant"
|
||||||
@@ -35,6 +37,21 @@ func stopReasonClaude2OpenAI(reason string) string {
|
|||||||
return reasonmap.ClaudeStopReasonToOpenAIFinishReason(reason)
|
return reasonmap.ClaudeStopReasonToOpenAIFinishReason(reason)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func inferClaudeFileMimeType(file *dto.MessageFile) string {
|
||||||
|
if file == nil || file.FileName == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
dot := strings.LastIndex(file.FileName, ".")
|
||||||
|
if dot == -1 || dot+1 >= len(file.FileName) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
mimeType := service.GetMimeTypeByExtension(file.FileName[dot+1:])
|
||||||
|
if mimeType == "application/octet-stream" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return mimeType
|
||||||
|
}
|
||||||
|
|
||||||
func maybeMarkClaudeRefusal(c *gin.Context, stopReason string) {
|
func maybeMarkClaudeRefusal(c *gin.Context, stopReason string) {
|
||||||
if c == nil {
|
if c == nil {
|
||||||
return
|
return
|
||||||
@@ -365,31 +382,59 @@ func RequestOpenAI2ClaudeMessage(c *gin.Context, textRequest dto.GeneralOpenAIRe
|
|||||||
text = "..."
|
text = "..."
|
||||||
}
|
}
|
||||||
claudeMessage.Content = text
|
claudeMessage.Content = text
|
||||||
} else {
|
} else {
|
||||||
claudeMediaMessages := make([]dto.ClaudeMediaMessage, 0)
|
claudeMediaMessages := make([]dto.ClaudeMediaMessage, 0)
|
||||||
for _, mediaMessage := range message.ParseContent() {
|
for _, mediaMessage := range message.ParseContent() {
|
||||||
switch mediaMessage.Type {
|
switch mediaMessage.Type {
|
||||||
case "text":
|
case "text":
|
||||||
if mediaMessage.Text != "" {
|
if mediaMessage.Text != "" {
|
||||||
claudeMediaMessages = append(claudeMediaMessages, dto.ClaudeMediaMessage{
|
claudeMediaMessages = append(claudeMediaMessages, dto.ClaudeMediaMessage{
|
||||||
Type: "text",
|
Type: "text",
|
||||||
Text: common.GetPointer[string](mediaMessage.Text),
|
Text: common.GetPointer[string](mediaMessage.Text),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
source := mediaMessage.ToFileSource()
|
var source types.FileSource
|
||||||
if source == nil {
|
if mediaMessage.Type == dto.ContentTypeFile {
|
||||||
continue
|
file := mediaMessage.GetFile()
|
||||||
}
|
if file == nil || file.FileData == "" {
|
||||||
base64Data, mimeType, err := service.GetBase64Data(c, source, "formatting image for Claude")
|
continue
|
||||||
if err != nil {
|
}
|
||||||
return nil, fmt.Errorf("get file data failed: %s", err.Error())
|
source = types.NewFileSourceFromData(file.FileData, inferClaudeFileMimeType(file))
|
||||||
}
|
} else {
|
||||||
claudeMediaMessage := dto.ClaudeMediaMessage{
|
source = mediaMessage.ToFileSource()
|
||||||
Source: &dto.ClaudeMessageSource{
|
}
|
||||||
Type: "base64",
|
if source == nil {
|
||||||
},
|
continue
|
||||||
}
|
}
|
||||||
|
base64Data, mimeType, err := service.GetBase64Data(c, source, "formatting image for Claude")
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("get file data failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
if mimeType == "text/plain" {
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(base64Data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("decode text file data failed: %s", err.Error())
|
||||||
|
}
|
||||||
|
if utf8.Valid(decoded) {
|
||||||
|
text := string(decoded)
|
||||||
|
if text != "" {
|
||||||
|
claudeMediaMessages = append(claudeMediaMessages, dto.ClaudeMediaMessage{
|
||||||
|
Type: "text",
|
||||||
|
Text: common.GetPointer[string](text),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if mimeType == "" || mimeType == "application/octet-stream" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
claudeMediaMessage := dto.ClaudeMediaMessage{
|
||||||
|
Source: &dto.ClaudeMessageSource{
|
||||||
|
Type: "base64",
|
||||||
|
},
|
||||||
|
}
|
||||||
if strings.HasPrefix(mimeType, "application/pdf") {
|
if strings.HasPrefix(mimeType, "application/pdf") {
|
||||||
claudeMediaMessage.Type = "document"
|
claudeMediaMessage.Type = "document"
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -40,8 +40,10 @@ func StreamScannerHandler(c *gin.Context, resp *http.Response, info *relaycommon
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 无条件新建 StreamStatus
|
// 保留调用方预先注入的 StreamStatus,避免覆盖已有错误/状态。
|
||||||
info.StreamStatus = relaycommon.NewStreamStatus()
|
if info.StreamStatus == nil {
|
||||||
|
info.StreamStatus = relaycommon.NewStreamStatus()
|
||||||
|
}
|
||||||
|
|
||||||
// 确保响应体总是被关闭
|
// 确保响应体总是被关闭
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|||||||
Reference in New Issue
Block a user