Merge pull request #1268 from QuantumNous/alpha
fix: gemini relay empty response
This commit is contained in:
@@ -102,14 +102,14 @@ func GetAllChannels(c *gin.Context) {
|
|||||||
typeCounts, _ := model.CountChannelsGroupByType()
|
typeCounts, _ := model.CountChannelsGroupByType()
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "",
|
"message": "",
|
||||||
"data": gin.H{
|
"data": gin.H{
|
||||||
"items": channelData,
|
"items": channelData,
|
||||||
"total": total,
|
"total": total,
|
||||||
"page": p,
|
"page": p,
|
||||||
"page_size": pageSize,
|
"page_size": pageSize,
|
||||||
"type_counts": typeCounts,
|
"type_counts": typeCounts,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
@@ -237,10 +237,20 @@ func SearchChannels(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
channelData = channels
|
channelData = channels
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// calculate type counts for search results
|
||||||
|
typeCounts := make(map[int64]int64)
|
||||||
|
for _, channel := range channelData {
|
||||||
|
typeCounts[int64(channel.Type)]++
|
||||||
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
c.JSON(http.StatusOK, gin.H{
|
||||||
"success": true,
|
"success": true,
|
||||||
"message": "",
|
"message": "",
|
||||||
"data": channelData,
|
"data": gin.H{
|
||||||
|
"items": channelData,
|
||||||
|
"type_counts": typeCounts,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,6 +46,15 @@ func initCol() {
|
|||||||
logGroupCol = commonGroupCol
|
logGroupCol = commonGroupCol
|
||||||
logKeyCol = commonKeyCol
|
logKeyCol = commonKeyCol
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// LOG_SQL_DSN 为空时,日志数据库与主数据库相同
|
||||||
|
if common.UsingPostgreSQL {
|
||||||
|
logGroupCol = `"group"`
|
||||||
|
logKeyCol = `"key"`
|
||||||
|
} else {
|
||||||
|
logGroupCol = commonGroupCol
|
||||||
|
logKeyCol = commonKeyCol
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// log sql type and database type
|
// log sql type and database type
|
||||||
common.SysLog("Using Log SQL Type: " + common.LogSqlType)
|
common.SysLog("Using Log SQL Type: " + common.LogSqlType)
|
||||||
|
|||||||
@@ -2,11 +2,12 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/bytedance/gopkg/util/gopool"
|
|
||||||
"gorm.io/gorm"
|
|
||||||
"one-api/common"
|
"one-api/common"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/bytedance/gopkg/util/gopool"
|
||||||
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -48,6 +49,22 @@ func addNewRecord(type_ int, id int, value int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func batchUpdate() {
|
func batchUpdate() {
|
||||||
|
// check if there's any data to update
|
||||||
|
hasData := false
|
||||||
|
for i := 0; i < BatchUpdateTypeCount; i++ {
|
||||||
|
batchUpdateLocks[i].Lock()
|
||||||
|
if len(batchUpdateStores[i]) > 0 {
|
||||||
|
hasData = true
|
||||||
|
batchUpdateLocks[i].Unlock()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
batchUpdateLocks[i].Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !hasData {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
common.SysLog("batch update started")
|
common.SysLog("batch update started")
|
||||||
for i := 0; i < BatchUpdateTypeCount; i++ {
|
for i := 0; i < BatchUpdateTypeCount; i++ {
|
||||||
batchUpdateLocks[i].Lock()
|
batchUpdateLocks[i].Lock()
|
||||||
|
|||||||
@@ -35,19 +35,6 @@ func GeminiTextGenerationHandler(c *gin.Context, resp *http.Response, info *rela
|
|||||||
return nil, service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError)
|
return nil, service.OpenAIErrorWrapper(err, "unmarshal_response_body_failed", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否有候选响应
|
|
||||||
if len(geminiResponse.Candidates) == 0 {
|
|
||||||
return nil, &dto.OpenAIErrorWithStatusCode{
|
|
||||||
Error: dto.OpenAIError{
|
|
||||||
Message: "No candidates returned",
|
|
||||||
Type: "server_error",
|
|
||||||
Param: "",
|
|
||||||
Code: 500,
|
|
||||||
},
|
|
||||||
StatusCode: resp.StatusCode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 计算使用量(基于 UsageMetadata)
|
// 计算使用量(基于 UsageMetadata)
|
||||||
usage := dto.Usage{
|
usage := dto.Usage{
|
||||||
PromptTokens: geminiResponse.UsageMetadata.PromptTokenCount,
|
PromptTokens: geminiResponse.UsageMetadata.PromptTokenCount,
|
||||||
|
|||||||
@@ -165,8 +165,23 @@ func GeminiHelper(c *gin.Context) (openaiErr *dto.OpenAIErrorWithStatusCode) {
|
|||||||
return service.OpenAIErrorWrapperLocal(err, "do_request_failed", http.StatusInternalServerError)
|
return service.OpenAIErrorWrapperLocal(err, "do_request_failed", http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statusCodeMappingStr := c.GetString("status_code_mapping")
|
||||||
|
|
||||||
|
var httpResp *http.Response
|
||||||
|
if resp != nil {
|
||||||
|
httpResp = resp.(*http.Response)
|
||||||
|
relayInfo.IsStream = relayInfo.IsStream || strings.HasPrefix(httpResp.Header.Get("Content-Type"), "text/event-stream")
|
||||||
|
if httpResp.StatusCode != http.StatusOK {
|
||||||
|
openaiErr = service.RelayErrorHandler(httpResp, false)
|
||||||
|
// reset status code 重置状态码
|
||||||
|
service.ResetStatusCode(openaiErr, statusCodeMappingStr)
|
||||||
|
return openaiErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
usage, openaiErr := adaptor.DoResponse(c, resp.(*http.Response), relayInfo)
|
usage, openaiErr := adaptor.DoResponse(c, resp.(*http.Response), relayInfo)
|
||||||
if openaiErr != nil {
|
if openaiErr != nil {
|
||||||
|
service.ResetStatusCode(openaiErr, statusCodeMappingStr)
|
||||||
return openaiErr
|
return openaiErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -588,11 +588,10 @@ const TopUp = () => {
|
|||||||
<Card
|
<Card
|
||||||
key={index}
|
key={index}
|
||||||
onClick={() => selectPresetAmount(preset)}
|
onClick={() => selectPresetAmount(preset)}
|
||||||
className={`cursor-pointer !rounded-2xl transition-all hover:shadow-md ${
|
className={`cursor-pointer !rounded-2xl transition-all hover:shadow-md ${selectedPreset === preset.value
|
||||||
selectedPreset === preset.value
|
? 'border-blue-500'
|
||||||
? 'border-blue-500'
|
: 'border-gray-200 hover:border-gray-300'
|
||||||
: 'border-gray-200 hover:border-gray-300'
|
}`}
|
||||||
}`}
|
|
||||||
bodyStyle={{ textAlign: 'center' }}
|
bodyStyle={{ textAlign: 'center' }}
|
||||||
>
|
>
|
||||||
<div className='font-medium text-lg flex items-center justify-center mb-1'>
|
<div className='font-medium text-lg flex items-center justify-center mb-1'>
|
||||||
@@ -661,54 +660,139 @@ const TopUp = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
|
<div>
|
||||||
{/* <Button
|
<Text strong className='block mb-3'>
|
||||||
type='primary'
|
{t('选择支付方式')}
|
||||||
onClick={() => preTopUp('zfb')}
|
</Text>
|
||||||
size='large'
|
{payMethods.length === 2 ? (
|
||||||
disabled={!enableOnlineTopUp}
|
<div className='grid grid-cols-1 sm:grid-cols-2 gap-3'>
|
||||||
loading={paymentLoading && payWay === 'zfb'}
|
{payMethods.map((payMethod) => (
|
||||||
icon={<SiAlipay size={18} />}
|
<Button
|
||||||
style={{ height: '44px' }}
|
key={payMethod.type}
|
||||||
>
|
type='primary'
|
||||||
<span className='ml-2'>{t('支付宝')}</span>
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
</Button>
|
size='large'
|
||||||
<Button
|
disabled={!enableOnlineTopUp}
|
||||||
type='primary'
|
loading={paymentLoading && payWay === payMethod.type}
|
||||||
onClick={() => preTopUp('wx')}
|
icon={
|
||||||
size='large'
|
payMethod.type === 'zfb' ? (
|
||||||
disabled={!enableOnlineTopUp}
|
<SiAlipay size={16} />
|
||||||
loading={paymentLoading && payWay === 'wx'}
|
) : payMethod.type === 'wx' ? (
|
||||||
icon={<SiWechat size={18} />}
|
<SiWechat size={16} />
|
||||||
style={{ height: '44px' }}
|
) : (
|
||||||
>
|
<CreditCard size={16} />
|
||||||
<span className='ml-2'>{t('微信')}</span>
|
)
|
||||||
</Button> */}
|
}
|
||||||
{payMethods.map((payMethod) => (
|
style={{
|
||||||
<Button
|
height: '40px',
|
||||||
key={payMethod.type}
|
color: payMethod.color,
|
||||||
type='primary'
|
}}
|
||||||
onClick={() => preTopUp(payMethod.type)}
|
className='transition-all hover:shadow-md w-full'
|
||||||
size='large'
|
>
|
||||||
disabled={!enableOnlineTopUp}
|
<span className='ml-1'>{payMethod.name}</span>
|
||||||
loading={paymentLoading && payWay === payMethod.type}
|
</Button>
|
||||||
icon={
|
))}
|
||||||
payMethod.type === 'zfb' ? (
|
</div>
|
||||||
<SiAlipay size={18} />
|
) : payMethods.length === 3 ? (
|
||||||
) : payMethod.type === 'wx' ? (
|
<div className='grid grid-cols-1 sm:grid-cols-3 gap-3'>
|
||||||
<SiWechat size={18} />
|
{payMethods.map((payMethod) => (
|
||||||
) : (
|
<Button
|
||||||
<CreditCard size={18} />
|
key={payMethod.type}
|
||||||
)
|
type='primary'
|
||||||
}
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
style={{
|
size='large'
|
||||||
height: '44px',
|
disabled={!enableOnlineTopUp}
|
||||||
color: payMethod.color,
|
loading={paymentLoading && payWay === payMethod.type}
|
||||||
}}
|
icon={
|
||||||
>
|
payMethod.type === 'zfb' ? (
|
||||||
<span className='ml-2'>{payMethod.name}</span>
|
<SiAlipay size={16} />
|
||||||
</Button>
|
) : payMethod.type === 'wx' ? (
|
||||||
))}
|
<SiWechat size={16} />
|
||||||
|
) : (
|
||||||
|
<CreditCard size={16} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
color: payMethod.color,
|
||||||
|
}}
|
||||||
|
className='transition-all hover:shadow-md w-full'
|
||||||
|
>
|
||||||
|
<span className='ml-1'>{payMethod.name}</span>
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : payMethods.length > 3 ? (
|
||||||
|
<div className='grid grid-cols-2 sm:grid-cols-4 gap-3'>
|
||||||
|
{payMethods.map((payMethod) => (
|
||||||
|
<Card
|
||||||
|
key={payMethod.type}
|
||||||
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
|
disabled={!enableOnlineTopUp}
|
||||||
|
className={`cursor-pointer !rounded-xl p-0 transition-all hover:shadow-md ${paymentLoading && payWay === payMethod.type
|
||||||
|
? 'border-blue-400'
|
||||||
|
: 'border-gray-200 hover:border-gray-300'
|
||||||
|
}`}
|
||||||
|
bodyStyle={{
|
||||||
|
padding: '10px',
|
||||||
|
textAlign: 'center',
|
||||||
|
opacity: !enableOnlineTopUp ? 0.5 : 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{paymentLoading && payWay === payMethod.type ? (
|
||||||
|
<div className='flex flex-col items-center justify-center h-full'>
|
||||||
|
<div className='mb-1'>
|
||||||
|
<div className='animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500'></div>
|
||||||
|
</div>
|
||||||
|
<div className='text-xs text-gray-500'>{t('处理中')}</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className='flex items-center justify-center mb-1'>
|
||||||
|
{payMethod.type === 'zfb' ? (
|
||||||
|
<SiAlipay size={20} color={payMethod.color} />
|
||||||
|
) : payMethod.type === 'wx' ? (
|
||||||
|
<SiWechat size={20} color={payMethod.color} />
|
||||||
|
) : (
|
||||||
|
<CreditCard size={20} color={payMethod.color} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='text-sm font-medium'>{payMethod.name}</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='grid grid-cols-1 gap-3'>
|
||||||
|
{payMethods.map((payMethod) => (
|
||||||
|
<Button
|
||||||
|
key={payMethod.type}
|
||||||
|
type='primary'
|
||||||
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
|
size='large'
|
||||||
|
disabled={!enableOnlineTopUp}
|
||||||
|
loading={paymentLoading && payWay === payMethod.type}
|
||||||
|
icon={
|
||||||
|
payMethod.type === 'zfb' ? (
|
||||||
|
<SiAlipay size={16} />
|
||||||
|
) : payMethod.type === 'wx' ? (
|
||||||
|
<SiWechat size={16} />
|
||||||
|
) : (
|
||||||
|
<CreditCard size={16} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
style={{
|
||||||
|
height: '40px',
|
||||||
|
color: payMethod.color,
|
||||||
|
}}
|
||||||
|
className='transition-all hover:shadow-md w-full'
|
||||||
|
>
|
||||||
|
<span className='ml-1'>{payMethod.name}</span>
|
||||||
|
</Button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@@ -941,48 +1025,71 @@ const TopUp = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className='grid grid-cols-2 gap-4'>
|
<div>
|
||||||
{/* <Button
|
{payMethods.length === 2 ? (
|
||||||
type='primary'
|
<div className='grid grid-cols-2 gap-3'>
|
||||||
onClick={() => preTopUp('zfb')}
|
{payMethods.map((payMethod) => (
|
||||||
disabled={!enableOnlineTopUp}
|
<Button
|
||||||
loading={paymentLoading && payWay === 'zfb'}
|
key={payMethod.type}
|
||||||
icon={<SiAlipay size={18} />}
|
type='primary'
|
||||||
>
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
<span className='ml-2'>{t('支付宝')}</span>
|
disabled={!enableOnlineTopUp}
|
||||||
</Button>
|
loading={paymentLoading && payWay === payMethod.type}
|
||||||
<Button
|
icon={
|
||||||
type='primary'
|
payMethod.type === 'zfb' ? (
|
||||||
onClick={() => preTopUp('wx')}
|
<SiAlipay size={16} />
|
||||||
disabled={!enableOnlineTopUp}
|
) : payMethod.type === 'wx' ? (
|
||||||
loading={paymentLoading && payWay === 'wx'}
|
<SiWechat size={16} />
|
||||||
icon={<SiWechat size={18} />}
|
) : (
|
||||||
>
|
<CreditCard size={16} />
|
||||||
<span className='ml-2'>{t('微信')}</span>
|
)
|
||||||
</Button> */}
|
}
|
||||||
{payMethods.map((payMethod) => (
|
style={{
|
||||||
<Button
|
color: payMethod.color,
|
||||||
key={payMethod.type}
|
}}
|
||||||
type='primary'
|
className='h-10'
|
||||||
onClick={() => preTopUp(payMethod.type)}
|
>
|
||||||
disabled={!enableOnlineTopUp}
|
<span className='ml-1'>{payMethod.name}</span>
|
||||||
loading={paymentLoading && payWay === payMethod.type}
|
</Button>
|
||||||
icon={
|
))}
|
||||||
payMethod.type === 'zfb' ? (
|
</div>
|
||||||
<SiAlipay size={18} />
|
) : (
|
||||||
) : payMethod.type === 'wx' ? (
|
<div className='grid grid-cols-4 gap-2'>
|
||||||
<SiWechat size={18} />
|
{payMethods.map((payMethod) => (
|
||||||
) : (
|
<Card
|
||||||
<CreditCard size={18} />
|
key={payMethod.type}
|
||||||
)
|
onClick={() => preTopUp(payMethod.type)}
|
||||||
}
|
disabled={!enableOnlineTopUp}
|
||||||
style={{
|
className={`cursor-pointer !rounded-xl p-0 transition-all ${paymentLoading && payWay === payMethod.type
|
||||||
color: payMethod.color,
|
? 'border-blue-400'
|
||||||
}}
|
: 'border-gray-200'
|
||||||
>
|
}`}
|
||||||
<span className='ml-2'>{payMethod.name}</span>
|
bodyStyle={{
|
||||||
</Button>
|
padding: '8px',
|
||||||
))}
|
textAlign: 'center',
|
||||||
|
opacity: !enableOnlineTopUp ? 0.5 : 1
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{paymentLoading && payWay === payMethod.type ? (
|
||||||
|
<div className='animate-spin rounded-full h-4 w-4 border-b-2 border-blue-500 mx-auto'></div>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<div className='flex justify-center'>
|
||||||
|
{payMethod.type === 'zfb' ? (
|
||||||
|
<SiAlipay size={18} color={payMethod.color} />
|
||||||
|
) : payMethod.type === 'wx' ? (
|
||||||
|
<SiWechat size={18} color={payMethod.color} />
|
||||||
|
) : (
|
||||||
|
<CreditCard size={18} color={payMethod.color} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='text-xs mt-1'>{payMethod.name}</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user