Merge remote-tracking branch 'origin/alpha' into alpha
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package gemini
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
type GeminiChatRequest struct {
|
||||
Contents []GeminiChatContent `json:"contents"`
|
||||
SafetySettings []GeminiChatSafetySettings `json:"safetySettings,omitempty"`
|
||||
@@ -22,6 +24,30 @@ type GeminiInlineData struct {
|
||||
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 {
|
||||
FunctionName string `json:"name"`
|
||||
Arguments any `json:"args"`
|
||||
@@ -58,6 +84,33 @@ type GeminiPart struct {
|
||||
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 {
|
||||
Role string `json:"role,omitempty"`
|
||||
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 {
|
||||
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{
|
||||
Name: name,
|
||||
Response: contentMap,
|
||||
|
||||
@@ -47,7 +47,7 @@ func requestOpenAI2Mistral(request *dto.GeneralOpenAIRequest) *dto.GeneralOpenAI
|
||||
}
|
||||
|
||||
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{}
|
||||
}
|
||||
for j, mediaMessage := range mediaMessages {
|
||||
|
||||
@@ -6,9 +6,9 @@ import {
|
||||
showSuccess,
|
||||
timestamp2string,
|
||||
renderGroup,
|
||||
renderNumberWithPoint,
|
||||
renderQuota,
|
||||
getChannelIcon
|
||||
getChannelIcon,
|
||||
renderQuotaWithAmount
|
||||
} from '../../helpers/index.js';
|
||||
|
||||
import {
|
||||
@@ -256,7 +256,7 @@ const ChannelsTable = () => {
|
||||
{renderQuota(record.used_quota)}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
<Tooltip content={t('剩余额度') + record.balance + t(',点击更新')}>
|
||||
<Tooltip content={t('剩余额度$') + record.balance + t(',点击更新')}>
|
||||
<Tag
|
||||
color='white'
|
||||
type='ghost'
|
||||
@@ -265,7 +265,7 @@ const ChannelsTable = () => {
|
||||
prefixIcon={<Coins size={14} />}
|
||||
onClick={() => updateChannelBalance(record)}
|
||||
>
|
||||
${renderNumberWithPoint(record.balance)}
|
||||
{renderQuotaWithAmount(record.balance)}
|
||||
</Tag>
|
||||
</Tooltip>
|
||||
</Space>
|
||||
|
||||
@@ -854,7 +854,7 @@ export function renderQuotaWithAmount(amount) {
|
||||
if (displayInCurrency) {
|
||||
return '$' + amount;
|
||||
} else {
|
||||
return renderUnitWithQuota(amount);
|
||||
return renderNumber(renderUnitWithQuota(amount));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user