Merge remote-tracking branch 'origin/alpha' into alpha
This commit is contained in:
@@ -1,5 +1,7 @@
|
|||||||
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 {
|
|||||||
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 {
|
|||||||
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"`
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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 = () => {
|
|||||||
{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 = () => {
|
|||||||
prefixIcon={<Coins size={14} />}
|
prefixIcon={<Coins size={14} />}
|
||||||
onClick={() => updateChannelBalance(record)}
|
onClick={() => updateChannelBalance(record)}
|
||||||
>
|
>
|
||||||
${renderNumberWithPoint(record.balance)}
|
{renderQuotaWithAmount(record.balance)}
|
||||||
</Tag>
|
</Tag>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Space>
|
</Space>
|
||||||
|
|||||||
@@ -854,7 +854,7 @@ export function renderQuotaWithAmount(amount) {
|
|||||||
if (displayInCurrency) {
|
if (displayInCurrency) {
|
||||||
return '$' + amount;
|
return '$' + amount;
|
||||||
} else {
|
} else {
|
||||||
return renderUnitWithQuota(amount);
|
return renderNumber(renderUnitWithQuota(amount));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user