Просмотр исходного кода

Merge pull request #1268 from QuantumNous/alpha

fix: gemini relay empty response
Calcium-Ion 8 месяцев назад
Родитель
Сommit
6a5a839d4d
6 измененных файлов с 264 добавлено и 119 удалено
  1. 19 9
      controller/channel.go
  2. 9 0
      model/main.go
  3. 19 2
      model/utils.go
  4. 0 13
      relay/channel/gemini/relay-gemini-native.go
  5. 15 0
      relay/relay-gemini.go
  6. 202 95
      web/src/pages/TopUp/index.js

+ 19 - 9
controller/channel.go

@@ -102,14 +102,14 @@ func GetAllChannels(c *gin.Context) {
 	typeCounts, _ := model.CountChannelsGroupByType()
 
 	c.JSON(http.StatusOK, gin.H{
-		"success":     true,
-		"message":     "",
-		"data":        gin.H{
-			"items":         channelData,
-			"total":         total,
-			"page":          p,
-			"page_size":     pageSize,
-			"type_counts":   typeCounts,
+		"success": true,
+		"message": "",
+		"data": gin.H{
+			"items":       channelData,
+			"total":       total,
+			"page":        p,
+			"page_size":   pageSize,
+			"type_counts": typeCounts,
 		},
 	})
 	return
@@ -237,10 +237,20 @@ func SearchChannels(c *gin.Context) {
 		}
 		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{
 		"success": true,
 		"message": "",
-		"data":    channelData,
+		"data": gin.H{
+			"items":       channelData,
+			"type_counts": typeCounts,
+		},
 	})
 	return
 }

+ 9 - 0
model/main.go

@@ -46,6 +46,15 @@ func initCol() {
 			logGroupCol = commonGroupCol
 			logKeyCol = commonKeyCol
 		}
+	} else {
+		// LOG_SQL_DSN 为空时,日志数据库与主数据库相同
+		if common.UsingPostgreSQL {
+			logGroupCol = `"group"`
+			logKeyCol = `"key"`
+		} else {
+			logGroupCol = commonGroupCol
+			logKeyCol = commonKeyCol
+		}
 	}
 	// log sql type and database type
 	common.SysLog("Using Log SQL Type: " + common.LogSqlType)

+ 19 - 2
model/utils.go

@@ -2,11 +2,12 @@ package model
 
 import (
 	"errors"
-	"github.com/bytedance/gopkg/util/gopool"
-	"gorm.io/gorm"
 	"one-api/common"
 	"sync"
 	"time"
+
+	"github.com/bytedance/gopkg/util/gopool"
+	"gorm.io/gorm"
 )
 
 const (
@@ -48,6 +49,22 @@ func addNewRecord(type_ int, id int, value int) {
 }
 
 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")
 	for i := 0; i < BatchUpdateTypeCount; i++ {
 		batchUpdateLocks[i].Lock()

+ 0 - 13
relay/channel/gemini/relay-gemini-native.go

@@ -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)
 	}
 
-	// 检查是否有候选响应
-	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)
 	usage := dto.Usage{
 		PromptTokens:     geminiResponse.UsageMetadata.PromptTokenCount,

+ 15 - 0
relay/relay-gemini.go

@@ -165,8 +165,23 @@ func GeminiHelper(c *gin.Context) (openaiErr *dto.OpenAIErrorWithStatusCode) {
 		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)
 	if openaiErr != nil {
+		service.ResetStatusCode(openaiErr, statusCodeMappingStr)
 		return openaiErr
 	}
 

+ 202 - 95
web/src/pages/TopUp/index.js

@@ -588,11 +588,10 @@ const TopUp = () => {
                         <Card
                           key={index}
                           onClick={() => selectPresetAmount(preset)}
-                          className={`cursor-pointer !rounded-2xl transition-all hover:shadow-md ${
-                            selectedPreset === preset.value
-                              ? 'border-blue-500'
-                              : 'border-gray-200 hover:border-gray-300'
-                          }`}
+                          className={`cursor-pointer !rounded-2xl transition-all hover:shadow-md ${selectedPreset === preset.value
+                            ? 'border-blue-500'
+                            : 'border-gray-200 hover:border-gray-300'
+                            }`}
                           bodyStyle={{ textAlign: 'center' }}
                         >
                           <div className='font-medium text-lg flex items-center justify-center mb-1'>
@@ -661,54 +660,139 @@ const TopUp = () => {
                       />
                     </div>
 
-                    <div className='grid grid-cols-1 sm:grid-cols-2 gap-4'>
-                      {/* <Button
-                        type='primary'
-                        onClick={() => preTopUp('zfb')}
-                        size='large'
-                        disabled={!enableOnlineTopUp}
-                        loading={paymentLoading && payWay === 'zfb'}
-                        icon={<SiAlipay size={18} />}
-                        style={{ height: '44px' }}
-                      >
-                        <span className='ml-2'>{t('支付宝')}</span>
-                      </Button>
-                      <Button
-                        type='primary'
-                        onClick={() => preTopUp('wx')}
-                        size='large'
-                        disabled={!enableOnlineTopUp}
-                        loading={paymentLoading && payWay === 'wx'}
-                        icon={<SiWechat size={18} />}
-                        style={{ height: '44px' }}
-                      >
-                        <span className='ml-2'>{t('微信')}</span>
-                      </Button> */}
-                      {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={18} />
-                            ) : payMethod.type === 'wx' ? (
-                              <SiWechat size={18} />
-                            ) : (
-                              <CreditCard size={18} />
-                            )
-                          }
-                          style={{
-                            height: '44px',
-                            color: payMethod.color,
-                          }}
-                        >
-                          <span className='ml-2'>{payMethod.name}</span>
-                        </Button>
-                      ))}
+                    <div>
+                      <Text strong className='block mb-3'>
+                        {t('选择支付方式')}
+                      </Text>
+                      {payMethods.length === 2 ? (
+                        <div className='grid grid-cols-1 sm:grid-cols-2 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>
+                      ) : payMethods.length === 3 ? (
+                        <div className='grid grid-cols-1 sm:grid-cols-3 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>
+                      ) : 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>
                 </>
@@ -941,48 +1025,71 @@ const TopUp = () => {
               />
             </div>
 
-            <div className='grid grid-cols-2 gap-4'>
-              {/* <Button
-                type='primary'
-                onClick={() => preTopUp('zfb')}
-                disabled={!enableOnlineTopUp}
-                loading={paymentLoading && payWay === 'zfb'}
-                icon={<SiAlipay size={18} />}
-              >
-                <span className='ml-2'>{t('支付宝')}</span>
-              </Button>
-              <Button
-                type='primary'
-                onClick={() => preTopUp('wx')}
-                disabled={!enableOnlineTopUp}
-                loading={paymentLoading && payWay === 'wx'}
-                icon={<SiWechat size={18} />}
-              >
-                <span className='ml-2'>{t('微信')}</span>
-              </Button> */}
-              {payMethods.map((payMethod) => (
-                <Button
-                  key={payMethod.type}
-                  type='primary'
-                  onClick={() => preTopUp(payMethod.type)}
-                  disabled={!enableOnlineTopUp}
-                  loading={paymentLoading && payWay === payMethod.type}
-                  icon={
-                    payMethod.type === 'zfb' ? (
-                      <SiAlipay size={18} />
-                    ) : payMethod.type === 'wx' ? (
-                      <SiWechat size={18} />
-                    ) : (
-                      <CreditCard size={18} />
-                    )
-                  }
-                  style={{
-                    color: payMethod.color,
-                  }}
-                >
-                  <span className='ml-2'>{payMethod.name}</span>
-                </Button>
-              ))}
+            <div>
+              {payMethods.length === 2 ? (
+                <div className='grid grid-cols-2 gap-3'>
+                  {payMethods.map((payMethod) => (
+                    <Button
+                      key={payMethod.type}
+                      type='primary'
+                      onClick={() => preTopUp(payMethod.type)}
+                      disabled={!enableOnlineTopUp}
+                      loading={paymentLoading && payWay === payMethod.type}
+                      icon={
+                        payMethod.type === 'zfb' ? (
+                          <SiAlipay size={16} />
+                        ) : payMethod.type === 'wx' ? (
+                          <SiWechat size={16} />
+                        ) : (
+                          <CreditCard size={16} />
+                        )
+                      }
+                      style={{
+                        color: payMethod.color,
+                      }}
+                      className='h-10'
+                    >
+                      <span className='ml-1'>{payMethod.name}</span>
+                    </Button>
+                  ))}
+                </div>
+              ) : (
+                <div className='grid grid-cols-4 gap-2'>
+                  {payMethods.map((payMethod) => (
+                    <Card
+                      key={payMethod.type}
+                      onClick={() => preTopUp(payMethod.type)}
+                      disabled={!enableOnlineTopUp}
+                      className={`cursor-pointer !rounded-xl p-0 transition-all ${paymentLoading && payWay === payMethod.type
+                        ? 'border-blue-400'
+                        : 'border-gray-200'
+                        }`}
+                      bodyStyle={{
+                        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>