Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
269a1e12
authored
Jun 02, 2025
by
Apple\Apple
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/main' into ui/refactor
parents
36a9781d
c668362f
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
100 additions
and
47 deletions
+100
-47
relay/channel/gemini/relay-gemini.go
+97
-47
relay/relay-image.go
+3
-0
No files found.
relay/channel/gemini/relay-gemini.go
View file @
269a1e12
...
@@ -18,6 +18,24 @@ import (
...
@@ -18,6 +18,24 @@ import (
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin"
)
)
var
geminiSupportedMimeTypes
=
map
[
string
]
bool
{
"application/pdf"
:
true
,
"audio/mpeg"
:
true
,
"audio/mp3"
:
true
,
"audio/wav"
:
true
,
"image/png"
:
true
,
"image/jpeg"
:
true
,
"text/plain"
:
true
,
"video/mov"
:
true
,
"video/mpeg"
:
true
,
"video/mp4"
:
true
,
"video/mpg"
:
true
,
"video/avi"
:
true
,
"video/wmv"
:
true
,
"video/mpegps"
:
true
,
"video/flv"
:
true
,
}
// Setting safety to the lowest possible values since Gemini is already powerless enough
// Setting safety to the lowest possible values since Gemini is already powerless enough
func
CovertGemini2OpenAI
(
textRequest
dto
.
GeneralOpenAIRequest
,
info
*
relaycommon
.
RelayInfo
)
(
*
GeminiChatRequest
,
error
)
{
func
CovertGemini2OpenAI
(
textRequest
dto
.
GeneralOpenAIRequest
,
info
*
relaycommon
.
RelayInfo
)
(
*
GeminiChatRequest
,
error
)
{
...
@@ -215,14 +233,20 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
...
@@ -215,14 +233,20 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
}
}
// 判断是否是url
// 判断是否是url
if
strings
.
HasPrefix
(
part
.
GetImageMedia
()
.
Url
,
"http"
)
{
if
strings
.
HasPrefix
(
part
.
GetImageMedia
()
.
Url
,
"http"
)
{
// 是url,获取
图片
的类型和base64编码的数据
// 是url,获取
文件
的类型和base64编码的数据
fileData
,
err
:=
service
.
GetFileBase64FromUrl
(
part
.
GetImageMedia
()
.
Url
)
fileData
,
err
:=
service
.
GetFileBase64FromUrl
(
part
.
GetImageMedia
()
.
Url
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"get file base64 from url failed: %s"
,
err
.
Error
())
return
nil
,
fmt
.
Errorf
(
"get file base64 from url '%s' failed: %w"
,
part
.
GetImageMedia
()
.
Url
,
err
)
}
// 校验 MimeType 是否在 Gemini 支持的白名单中
if
_
,
ok
:=
geminiSupportedMimeTypes
[
strings
.
ToLower
(
fileData
.
MimeType
)];
!
ok
{
return
nil
,
fmt
.
Errorf
(
"MIME type '%s' from URL '%s' is not supported by Gemini. Supported types are: %v"
,
fileData
.
MimeType
,
part
.
GetImageMedia
()
.
Url
,
getSupportedMimeTypesList
())
}
}
parts
=
append
(
parts
,
GeminiPart
{
parts
=
append
(
parts
,
GeminiPart
{
InlineData
:
&
GeminiInlineData
{
InlineData
:
&
GeminiInlineData
{
MimeType
:
fileData
.
MimeType
,
MimeType
:
fileData
.
MimeType
,
// 使用原始的 MimeType,因为大小写可能对API有意义
Data
:
fileData
.
Base64Data
,
Data
:
fileData
.
Base64Data
,
},
},
})
})
...
@@ -291,22 +315,27 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
...
@@ -291,22 +315,27 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
return
&
geminiRequest
,
nil
return
&
geminiRequest
,
nil
}
}
// Helper function to get a list of supported MIME types for error messages
func
getSupportedMimeTypesList
()
[]
string
{
keys
:=
make
([]
string
,
0
,
len
(
geminiSupportedMimeTypes
))
for
k
:=
range
geminiSupportedMimeTypes
{
keys
=
append
(
keys
,
k
)
}
return
keys
}
// cleanFunctionParameters recursively removes unsupported fields from Gemini function parameters.
// cleanFunctionParameters recursively removes unsupported fields from Gemini function parameters.
func
cleanFunctionParameters
(
params
interface
{})
interface
{}
{
func
cleanFunctionParameters
(
params
interface
{})
interface
{}
{
if
params
==
nil
{
if
params
==
nil
{
return
nil
return
nil
}
}
paramMap
,
ok
:=
params
.
(
map
[
string
]
interface
{})
switch
v
:=
params
.
(
type
)
{
if
!
ok
{
case
map
[
string
]
interface
{}
:
// Not a map, return as is (e.g., could be an array or primitive)
return
params
}
// Create a copy to avoid modifying the original
// Create a copy to avoid modifying the original
cleanedMap
:=
make
(
map
[
string
]
interface
{})
cleanedMap
:=
make
(
map
[
string
]
interface
{})
for
k
,
v
:=
range
paramMap
{
for
k
,
val
:=
range
v
{
cleanedMap
[
k
]
=
v
cleanedMap
[
k
]
=
val
}
}
// Remove unsupported root-level fields
// Remove unsupported root-level fields
...
@@ -316,51 +345,25 @@ func cleanFunctionParameters(params interface{}) interface{} {
...
@@ -316,51 +345,25 @@ func cleanFunctionParameters(params interface{}) interface{} {
delete
(
cleanedMap
,
"$schema"
)
delete
(
cleanedMap
,
"$schema"
)
delete
(
cleanedMap
,
"additionalProperties"
)
delete
(
cleanedMap
,
"additionalProperties"
)
// Clean properties
if
props
,
ok
:=
cleanedMap
[
"properties"
]
.
(
map
[
string
]
interface
{});
ok
&&
props
!=
nil
{
cleanedProps
:=
make
(
map
[
string
]
interface
{})
for
propName
,
propValue
:=
range
props
{
propMap
,
ok
:=
propValue
.
(
map
[
string
]
interface
{})
if
!
ok
{
cleanedProps
[
propName
]
=
propValue
// Keep non-map properties
continue
}
// Create a copy of the property map
cleanedPropMap
:=
make
(
map
[
string
]
interface
{})
for
k
,
v
:=
range
propMap
{
cleanedPropMap
[
k
]
=
v
}
// Remove unsupported fields
delete
(
cleanedPropMap
,
"default"
)
delete
(
cleanedPropMap
,
"exclusiveMaximum"
)
delete
(
cleanedPropMap
,
"exclusiveMinimum"
)
delete
(
cleanedPropMap
,
"$schema"
)
delete
(
cleanedPropMap
,
"additionalProperties"
)
// Check and clean 'format' for string types
// Check and clean 'format' for string types
if
propType
,
typeExists
:=
cleanedProp
Map
[
"type"
]
.
(
string
);
typeExists
&&
propType
==
"string"
{
if
propType
,
typeExists
:=
cleaned
Map
[
"type"
]
.
(
string
);
typeExists
&&
propType
==
"string"
{
if
formatValue
,
formatExists
:=
cleanedProp
Map
[
"format"
]
.
(
string
);
formatExists
{
if
formatValue
,
formatExists
:=
cleaned
Map
[
"format"
]
.
(
string
);
formatExists
{
if
formatValue
!=
"enum"
&&
formatValue
!=
"date-time"
{
if
formatValue
!=
"enum"
&&
formatValue
!=
"date-time"
{
delete
(
cleanedProp
Map
,
"format"
)
delete
(
cleaned
Map
,
"format"
)
}
}
}
}
}
}
// Recursively clean nested properties within this property if it's an object/array
// Clean properties
// Check the type before recursing
if
props
,
ok
:=
cleanedMap
[
"properties"
]
.
(
map
[
string
]
interface
{});
ok
&&
props
!=
nil
{
if
propType
,
typeExists
:=
cleanedPropMap
[
"type"
]
.
(
string
);
typeExists
&&
(
propType
==
"object"
||
propType
==
"array"
)
{
cleanedProps
:=
make
(
map
[
string
]
interface
{})
cleanedProps
[
propName
]
=
cleanFunctionParameters
(
cleanedPropMap
)
for
propName
,
propValue
:=
range
props
{
}
else
{
cleanedProps
[
propName
]
=
cleanFunctionParameters
(
propValue
)
cleanedProps
[
propName
]
=
cleanedPropMap
// Assign the cleaned map back if not recursing
}
}
}
cleanedMap
[
"properties"
]
=
cleanedProps
cleanedMap
[
"properties"
]
=
cleanedProps
}
}
// Recursively clean items in arrays if needed (e.g., type: array, items: { ... })
// Recursively clean items in arrays
if
items
,
ok
:=
cleanedMap
[
"items"
]
.
(
map
[
string
]
interface
{});
ok
&&
items
!=
nil
{
if
items
,
ok
:=
cleanedMap
[
"items"
]
.
(
map
[
string
]
interface
{});
ok
&&
items
!=
nil
{
cleanedMap
[
"items"
]
=
cleanFunctionParameters
(
items
)
cleanedMap
[
"items"
]
=
cleanFunctionParameters
(
items
)
}
}
...
@@ -373,7 +376,7 @@ func cleanFunctionParameters(params interface{}) interface{} {
...
@@ -373,7 +376,7 @@ func cleanFunctionParameters(params interface{}) interface{} {
cleanedMap
[
"items"
]
=
cleanedItemsArray
cleanedMap
[
"items"
]
=
cleanedItemsArray
}
}
// Recursively clean other schema composition keywords if necessary
// Recursively clean other schema composition keywords
for
_
,
field
:=
range
[]
string
{
"allOf"
,
"anyOf"
,
"oneOf"
}
{
for
_
,
field
:=
range
[]
string
{
"allOf"
,
"anyOf"
,
"oneOf"
}
{
if
nested
,
ok
:=
cleanedMap
[
field
]
.
([]
interface
{});
ok
{
if
nested
,
ok
:=
cleanedMap
[
field
]
.
([]
interface
{});
ok
{
cleanedNested
:=
make
([]
interface
{},
len
(
nested
))
cleanedNested
:=
make
([]
interface
{},
len
(
nested
))
...
@@ -384,7 +387,54 @@ func cleanFunctionParameters(params interface{}) interface{} {
...
@@ -384,7 +387,54 @@ func cleanFunctionParameters(params interface{}) interface{} {
}
}
}
}
// Recursively clean patternProperties
if
patternProps
,
ok
:=
cleanedMap
[
"patternProperties"
]
.
(
map
[
string
]
interface
{});
ok
{
cleanedPatternProps
:=
make
(
map
[
string
]
interface
{})
for
pattern
,
schema
:=
range
patternProps
{
cleanedPatternProps
[
pattern
]
=
cleanFunctionParameters
(
schema
)
}
cleanedMap
[
"patternProperties"
]
=
cleanedPatternProps
}
// Recursively clean definitions
if
definitions
,
ok
:=
cleanedMap
[
"definitions"
]
.
(
map
[
string
]
interface
{});
ok
{
cleanedDefinitions
:=
make
(
map
[
string
]
interface
{})
for
defName
,
defSchema
:=
range
definitions
{
cleanedDefinitions
[
defName
]
=
cleanFunctionParameters
(
defSchema
)
}
cleanedMap
[
"definitions"
]
=
cleanedDefinitions
}
// Recursively clean $defs (newer JSON Schema draft)
if
defs
,
ok
:=
cleanedMap
[
"$defs"
]
.
(
map
[
string
]
interface
{});
ok
{
cleanedDefs
:=
make
(
map
[
string
]
interface
{})
for
defName
,
defSchema
:=
range
defs
{
cleanedDefs
[
defName
]
=
cleanFunctionParameters
(
defSchema
)
}
cleanedMap
[
"$defs"
]
=
cleanedDefs
}
// Clean conditional keywords
for
_
,
field
:=
range
[]
string
{
"if"
,
"then"
,
"else"
,
"not"
}
{
if
nested
,
ok
:=
cleanedMap
[
field
];
ok
{
cleanedMap
[
field
]
=
cleanFunctionParameters
(
nested
)
}
}
return
cleanedMap
return
cleanedMap
case
[]
interface
{}
:
// Handle arrays of schemas
cleanedArray
:=
make
([]
interface
{},
len
(
v
))
for
i
,
item
:=
range
v
{
cleanedArray
[
i
]
=
cleanFunctionParameters
(
item
)
}
return
cleanedArray
default
:
// Not a map or array, return as is (e.g., could be a primitive)
return
params
}
}
}
func
removeAdditionalPropertiesWithDepth
(
schema
interface
{},
depth
int
)
interface
{}
{
func
removeAdditionalPropertiesWithDepth
(
schema
interface
{},
depth
int
)
interface
{}
{
...
...
relay/relay-image.go
View file @
269a1e12
...
@@ -41,6 +41,9 @@ func getAndValidImageRequest(c *gin.Context, info *relaycommon.RelayInfo) (*dto.
...
@@ -41,6 +41,9 @@ func getAndValidImageRequest(c *gin.Context, info *relaycommon.RelayInfo) (*dto.
imageRequest
.
Quality
=
"standard"
imageRequest
.
Quality
=
"standard"
}
}
}
}
if
imageRequest
.
N
==
0
{
imageRequest
.
N
=
1
}
default
:
default
:
err
:=
common
.
UnmarshalBodyReusable
(
c
,
imageRequest
)
err
:=
common
.
UnmarshalBodyReusable
(
c
,
imageRequest
)
if
err
!=
nil
{
if
err
!=
nil
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment