|
|
|
|
@@ -2,13 +2,16 @@ package controller
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bytes"
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"io"
|
|
|
|
|
"math"
|
|
|
|
|
"mime/multipart"
|
|
|
|
|
"net/http"
|
|
|
|
|
"net/http/httptest"
|
|
|
|
|
"net/textproto"
|
|
|
|
|
"net/url"
|
|
|
|
|
"strconv"
|
|
|
|
|
"strings"
|
|
|
|
|
@@ -42,6 +45,56 @@ type testResult struct {
|
|
|
|
|
newAPIError *types.NewAPIError
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const imageEditTestPngBase64 = "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAusB9Wn7Zc8AAAAASUVORK5CYII="
|
|
|
|
|
|
|
|
|
|
func buildImageEditTestMultipartRequest(requestPath, model string) (*http.Request, error) {
|
|
|
|
|
var requestBody bytes.Buffer
|
|
|
|
|
writer := multipart.NewWriter(&requestBody)
|
|
|
|
|
|
|
|
|
|
if err := writer.WriteField("model", model); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := writer.WriteField("prompt", "edit this image"); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := writer.WriteField("size", "1024x1024"); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if err := writer.WriteField("n", "1"); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
imageBytes, err := base64.StdEncoding.DecodeString(imageEditTestPngBase64)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
header := make(textproto.MIMEHeader)
|
|
|
|
|
header.Set("Content-Disposition", `form-data; name="image"; filename="channel-test.png"`)
|
|
|
|
|
header.Set("Content-Type", "image/png")
|
|
|
|
|
part, err := writer.CreatePart(header)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
if _, err = part.Write(imageBytes); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if err = writer.Close(); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req := &http.Request{
|
|
|
|
|
Method: "POST",
|
|
|
|
|
URL: &url.URL{Path: requestPath},
|
|
|
|
|
Body: io.NopCloser(bytes.NewReader(requestBody.Bytes())),
|
|
|
|
|
Header: make(http.Header),
|
|
|
|
|
}
|
|
|
|
|
req.Header.Set("Content-Type", writer.FormDataContentType())
|
|
|
|
|
req.ContentLength = int64(requestBody.Len())
|
|
|
|
|
return req, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func normalizeChannelTestEndpoint(channel *model.Channel, modelName, endpointType string) string {
|
|
|
|
|
normalized := strings.TrimSpace(endpointType)
|
|
|
|
|
if normalized != "" {
|
|
|
|
|
@@ -153,6 +206,16 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
|
|
|
|
|
|
|
//c.Request.Header.Set("Authorization", "Bearer "+channel.Key)
|
|
|
|
|
c.Request.Header.Set("Content-Type", "application/json")
|
|
|
|
|
if requestPath == "/v1/images/edits" {
|
|
|
|
|
c.Request, err = buildImageEditTestMultipartRequest(requestPath, testModel)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: err,
|
|
|
|
|
newAPIError: types.NewError(err, types.ErrorCodeReadRequestBodyFailed),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
c.Set("channel", channel.Type)
|
|
|
|
|
c.Set("base_url", channel.GetBaseURL())
|
|
|
|
|
group, _ := model.GetUserGroup(1, false)
|
|
|
|
|
@@ -184,7 +247,7 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
|
|
relayFormat = types.RelayFormatGemini
|
|
|
|
|
case constant.EndpointTypeJinaRerank:
|
|
|
|
|
relayFormat = types.RelayFormatRerank
|
|
|
|
|
case constant.EndpointTypeImageGeneration:
|
|
|
|
|
case constant.EndpointTypeImageGeneration, constant.EndpointTypeImageEdit:
|
|
|
|
|
relayFormat = types.RelayFormatOpenAIImage
|
|
|
|
|
case constant.EndpointTypeEmbeddings:
|
|
|
|
|
relayFormat = types.RelayFormatEmbedding
|
|
|
|
|
@@ -200,6 +263,9 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
|
|
if c.Request.URL.Path == "/v1/images/generations" {
|
|
|
|
|
relayFormat = types.RelayFormatOpenAIImage
|
|
|
|
|
}
|
|
|
|
|
if c.Request.URL.Path == "/v1/images/edits" {
|
|
|
|
|
relayFormat = types.RelayFormatOpenAIImage
|
|
|
|
|
}
|
|
|
|
|
if c.Request.URL.Path == "/v1/messages" {
|
|
|
|
|
relayFormat = types.RelayFormatClaude
|
|
|
|
|
}
|
|
|
|
|
@@ -294,7 +360,7 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
|
|
newAPIError: types.NewError(errors.New("invalid embedding request type"), types.ErrorCodeConvertRequestFailed),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
case relayconstant.RelayModeImagesGenerations:
|
|
|
|
|
case relayconstant.RelayModeImagesGenerations, relayconstant.RelayModeImagesEdits:
|
|
|
|
|
// 图像生成请求 - request 已经是正确的类型
|
|
|
|
|
if imageReq, ok := request.(*dto.ImageRequest); ok {
|
|
|
|
|
convertedRequest, err = adaptor.ConvertImageRequest(c, info, *imageReq)
|
|
|
|
|
@@ -366,44 +432,53 @@ func testChannel(channel *model.Channel, testModel string, endpointType string,
|
|
|
|
|
newAPIError: types.NewError(err, types.ErrorCodeConvertRequestFailed),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
jsonData, err := common.Marshal(convertedRequest)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: err,
|
|
|
|
|
newAPIError: types.NewError(err, types.ErrorCodeJsonMarshalFailed),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//jsonData, err = relaycommon.RemoveDisabledFields(jsonData, info.ChannelOtherSettings)
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// return testResult{
|
|
|
|
|
// context: c,
|
|
|
|
|
// localErr: err,
|
|
|
|
|
// newAPIError: types.NewError(err, types.ErrorCodeConvertRequestFailed),
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
if len(info.ParamOverride) > 0 {
|
|
|
|
|
jsonData, err = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
|
|
|
|
|
if err != nil {
|
|
|
|
|
if fixedErr, ok := relaycommon.AsParamOverrideReturnError(err); ok {
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: fixedErr,
|
|
|
|
|
newAPIError: relaycommon.NewAPIErrorFromParamOverride(fixedErr),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var requestBody *bytes.Buffer
|
|
|
|
|
switch req := convertedRequest.(type) {
|
|
|
|
|
case *bytes.Buffer:
|
|
|
|
|
requestBody = bytes.NewBuffer(req.Bytes())
|
|
|
|
|
case bytes.Buffer:
|
|
|
|
|
requestBody = bytes.NewBuffer(req.Bytes())
|
|
|
|
|
default:
|
|
|
|
|
jsonData, marshalErr := common.Marshal(convertedRequest)
|
|
|
|
|
if marshalErr != nil {
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: err,
|
|
|
|
|
newAPIError: types.NewError(err, types.ErrorCodeChannelParamOverrideInvalid),
|
|
|
|
|
localErr: marshalErr,
|
|
|
|
|
newAPIError: types.NewError(marshalErr, types.ErrorCodeJsonMarshalFailed),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//jsonData, err = relaycommon.RemoveDisabledFields(jsonData, info.ChannelOtherSettings)
|
|
|
|
|
//if err != nil {
|
|
|
|
|
// return testResult{
|
|
|
|
|
// context: c,
|
|
|
|
|
// localErr: err,
|
|
|
|
|
// newAPIError: types.NewError(err, types.ErrorCodeConvertRequestFailed),
|
|
|
|
|
// }
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
if len(info.ParamOverride) > 0 {
|
|
|
|
|
jsonData, marshalErr = relaycommon.ApplyParamOverrideWithRelayInfo(jsonData, info)
|
|
|
|
|
if marshalErr != nil {
|
|
|
|
|
if fixedErr, ok := relaycommon.AsParamOverrideReturnError(marshalErr); ok {
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: fixedErr,
|
|
|
|
|
newAPIError: relaycommon.NewAPIErrorFromParamOverride(fixedErr),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return testResult{
|
|
|
|
|
context: c,
|
|
|
|
|
localErr: marshalErr,
|
|
|
|
|
newAPIError: types.NewError(marshalErr, types.ErrorCodeChannelParamOverrideInvalid),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestBody = bytes.NewBuffer(jsonData)
|
|
|
|
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(jsonData))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
requestBody := bytes.NewBuffer(jsonData)
|
|
|
|
|
c.Request.Body = io.NopCloser(bytes.NewBuffer(jsonData))
|
|
|
|
|
resp, err := adaptor.DoRequest(c, info, requestBody)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return testResult{
|
|
|
|
|
@@ -618,6 +693,14 @@ func buildTestRequest(model string, endpointType string, channel *model.Channel,
|
|
|
|
|
N: lo.ToPtr(uint(1)),
|
|
|
|
|
Size: "1024x1024",
|
|
|
|
|
}
|
|
|
|
|
case constant.EndpointTypeImageEdit:
|
|
|
|
|
// 返回 ImageRequest
|
|
|
|
|
return &dto.ImageRequest{
|
|
|
|
|
Model: model,
|
|
|
|
|
Prompt: "edit this image",
|
|
|
|
|
N: lo.ToPtr(uint(1)),
|
|
|
|
|
Size: "1024x1024",
|
|
|
|
|
}
|
|
|
|
|
case constant.EndpointTypeJinaRerank:
|
|
|
|
|
// 返回 RerankRequest
|
|
|
|
|
return &dto.RerankRequest{
|
|
|
|
|
|