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
d5222743
authored
Jun 09, 2025
by
Apple\Apple
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'origin/alpha' into alpha
parents
3fd16678
6d90b2f3
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
75 additions
and
7 deletions
+75
-7
relay/channel/gemini/dto.go
+53
-0
relay/channel/gemini/relay-gemini.go
+16
-1
relay/channel/mistral/text.go
+1
-1
web/src/components/table/ChannelsTable.js
+4
-4
web/src/helpers/render.js
+1
-1
No files found.
relay/channel/gemini/dto.go
View file @
d5222743
package
gemini
package
gemini
import
"encoding/json"
type
GeminiChatRequest
struct
{
type
GeminiChatRequest
struct
{
Contents
[]
GeminiChatContent
`json:"contents"`
Contents
[]
GeminiChatContent
`json:"contents"`
SafetySettings
[]
GeminiChatSafetySettings
`json:"safetySettings,omitempty"`
SafetySettings
[]
GeminiChatSafetySettings
`json:"safetySettings,omitempty"`
...
@@ -22,6 +24,30 @@ type GeminiInlineData struct {
...
@@ -22,6 +24,30 @@ type GeminiInlineData struct {
Data
string
`json:"data"`
Data
string
`json:"data"`
}
}
// UnmarshalJSON custom unmarshaler for GeminiInlineData to support snake_case and camelCase for MimeType
func
(
g
*
GeminiInlineData
)
UnmarshalJSON
(
data
[]
byte
)
error
{
type
Alias
GeminiInlineData
// Use type alias to avoid recursion
var
aux
struct
{
Alias
MimeTypeSnake
string
`json:"mime_type"`
}
if
err
:=
json
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
return
err
}
*
g
=
GeminiInlineData
(
aux
.
Alias
)
// Copy other fields if any in future
// Prioritize snake_case if present
if
aux
.
MimeTypeSnake
!=
""
{
g
.
MimeType
=
aux
.
MimeTypeSnake
}
else
if
aux
.
MimeType
!=
""
{
// Fallback to camelCase from Alias
g
.
MimeType
=
aux
.
MimeType
}
// g.Data would be populated by aux.Alias.Data
return
nil
}
type
FunctionCall
struct
{
type
FunctionCall
struct
{
FunctionName
string
`json:"name"`
FunctionName
string
`json:"name"`
Arguments
any
`json:"args"`
Arguments
any
`json:"args"`
...
@@ -58,6 +84,33 @@ type GeminiPart struct {
...
@@ -58,6 +84,33 @@ type GeminiPart struct {
CodeExecutionResult
*
GeminiPartCodeExecutionResult
`json:"codeExecutionResult,omitempty"`
CodeExecutionResult
*
GeminiPartCodeExecutionResult
`json:"codeExecutionResult,omitempty"`
}
}
// UnmarshalJSON custom unmarshaler for GeminiPart to support snake_case and camelCase for InlineData
func
(
p
*
GeminiPart
)
UnmarshalJSON
(
data
[]
byte
)
error
{
// Alias to avoid recursion during unmarshalling
type
Alias
GeminiPart
var
aux
struct
{
Alias
InlineDataSnake
*
GeminiInlineData
`json:"inline_data,omitempty"`
// snake_case variant
}
if
err
:=
json
.
Unmarshal
(
data
,
&
aux
);
err
!=
nil
{
return
err
}
// Assign fields from alias
*
p
=
GeminiPart
(
aux
.
Alias
)
// Prioritize snake_case for InlineData if present
if
aux
.
InlineDataSnake
!=
nil
{
p
.
InlineData
=
aux
.
InlineDataSnake
}
else
if
aux
.
InlineData
!=
nil
{
// Fallback to camelCase from Alias
p
.
InlineData
=
aux
.
InlineData
}
// Other fields like Text, FunctionCall etc. are already populated via aux.Alias
return
nil
}
type
GeminiChatContent
struct
{
type
GeminiChatContent
struct
{
Role
string
`json:"role,omitempty"`
Role
string
`json:"role,omitempty"`
Parts
[]
GeminiPart
`json:"parts"`
Parts
[]
GeminiPart
`json:"parts"`
...
...
relay/channel/gemini/relay-gemini.go
View file @
d5222743
...
@@ -205,7 +205,22 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
...
@@ -205,7 +205,22 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest, info *relaycommon
}
else
if
val
,
exists
:=
tool_call_ids
[
message
.
ToolCallId
];
exists
{
}
else
if
val
,
exists
:=
tool_call_ids
[
message
.
ToolCallId
];
exists
{
name
=
val
name
=
val
}
}
contentMap
:=
common
.
StrToMap
(
message
.
StringContent
())
var
contentMap
map
[
string
]
interface
{}
contentStr
:=
message
.
StringContent
()
// 1. 尝试解析为 JSON 对象
if
err
:=
json
.
Unmarshal
([]
byte
(
contentStr
),
&
contentMap
);
err
!=
nil
{
// 2. 如果失败,尝试解析为 JSON 数组
var
contentSlice
[]
interface
{}
if
err
:=
json
.
Unmarshal
([]
byte
(
contentStr
),
&
contentSlice
);
err
==
nil
{
// 如果是数组,包装成对象
contentMap
=
map
[
string
]
interface
{}{
"result"
:
contentSlice
}
}
else
{
// 3. 如果再次失败,作为纯文本处理
contentMap
=
map
[
string
]
interface
{}{
"content"
:
contentStr
}
}
}
functionResp
:=
&
FunctionResponse
{
functionResp
:=
&
FunctionResponse
{
Name
:
name
,
Name
:
name
,
Response
:
contentMap
,
Response
:
contentMap
,
...
...
relay/channel/mistral/text.go
View file @
d5222743
...
@@ -47,7 +47,7 @@ func requestOpenAI2Mistral(request *dto.GeneralOpenAIRequest) *dto.GeneralOpenAI
...
@@ -47,7 +47,7 @@ func requestOpenAI2Mistral(request *dto.GeneralOpenAIRequest) *dto.GeneralOpenAI
}
}
mediaMessages
:=
message
.
ParseContent
()
mediaMessages
:=
message
.
ParseContent
()
if
message
.
Role
==
"assistant"
&&
message
.
ToolCalls
!=
nil
&&
message
.
Content
!=
"null
"
{
if
message
.
Role
==
"assistant"
&&
message
.
ToolCalls
!=
nil
&&
message
.
Content
==
"
"
{
mediaMessages
=
[]
dto
.
MediaContent
{}
mediaMessages
=
[]
dto
.
MediaContent
{}
}
}
for
j
,
mediaMessage
:=
range
mediaMessages
{
for
j
,
mediaMessage
:=
range
mediaMessages
{
...
...
web/src/components/table/ChannelsTable.js
View file @
d5222743
...
@@ -6,9 +6,9 @@ import {
...
@@ -6,9 +6,9 @@ import {
showSuccess
,
showSuccess
,
timestamp2string
,
timestamp2string
,
renderGroup
,
renderGroup
,
renderNumberWithPoint
,
renderQuota
,
renderQuota
,
getChannelIcon
getChannelIcon
,
renderQuotaWithAmount
}
from
'../../helpers/index.js'
;
}
from
'../../helpers/index.js'
;
import
{
import
{
...
@@ -256,7 +256,7 @@ const ChannelsTable = () => {
...
@@ -256,7 +256,7 @@ const ChannelsTable = () => {
{
renderQuota
(
record
.
used_quota
)}
{
renderQuota
(
record
.
used_quota
)}
<
/Tag
>
<
/Tag
>
<
/Tooltip
>
<
/Tooltip
>
<
Tooltip
content
=
{
t
(
'剩余额度'
)
+
record
.
balance
+
t
(
',点击更新'
)}
>
<
Tooltip
content
=
{
t
(
'剩余额度
$
'
)
+
record
.
balance
+
t
(
',点击更新'
)}
>
<
Tag
<
Tag
color
=
'white'
color
=
'white'
type
=
'ghost'
type
=
'ghost'
...
@@ -265,7 +265,7 @@ const ChannelsTable = () => {
...
@@ -265,7 +265,7 @@ const ChannelsTable = () => {
prefixIcon
=
{
<
Coins
size
=
{
14
}
/>
}
prefixIcon
=
{
<
Coins
size
=
{
14
}
/>
}
onClick
=
{()
=>
updateChannelBalance
(
record
)}
onClick
=
{()
=>
updateChannelBalance
(
record
)}
>
>
$
{
renderNumberWithPoi
nt
(
record
.
balance
)}
{
renderQuotaWithAmou
nt
(
record
.
balance
)}
<
/Tag
>
<
/Tag
>
<
/Tooltip
>
<
/Tooltip
>
<
/Space
>
<
/Space
>
...
...
web/src/helpers/render.js
View file @
d5222743
...
@@ -854,7 +854,7 @@ export function renderQuotaWithAmount(amount) {
...
@@ -854,7 +854,7 @@ export function renderQuotaWithAmount(amount) {
if
(
displayInCurrency
)
{
if
(
displayInCurrency
)
{
return
'$'
+
amount
;
return
'$'
+
amount
;
}
else
{
}
else
{
return
render
UnitWithQuota
(
amount
);
return
render
Number
(
renderUnitWithQuota
(
amount
)
);
}
}
}
}
...
...
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