merge upstream

Signed-off-by: wozulong <>
This commit is contained in:
wozulong 2024-08-01 15:12:54 +08:00
commit 918690701d
18 changed files with 184 additions and 89 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ upload
build build
*.db-journal *.db-journal
logs logs
web/dist

View File

@ -0,0 +1,32 @@
package common
import (
"errors"
"net/smtp"
)
type outlookAuth struct {
username, password string
}
func LoginAuth(username, password string) smtp.Auth {
return &outlookAuth{username, password}
}
func (a *outlookAuth) Start(_ *smtp.ServerInfo) (string, []byte, error) {
return "LOGIN", []byte{}, nil
}
func (a *outlookAuth) Next(fromServer []byte, more bool) ([]byte, error) {
if more {
switch string(fromServer) {
case "Username:":
return []byte(a.username), nil
case "Password:":
return []byte(a.password), nil
default:
return nil, errors.New("unknown fromServer")
}
}
return nil, nil
}

View File

@ -62,6 +62,9 @@ func SendEmail(subject string, receiver string, content string) error {
if err != nil { if err != nil {
return err return err
} }
} else if strings.HasSuffix(SMTPAccount, "outlook.com") {
auth = LoginAuth(SMTPAccount, SMTPToken)
err = smtp.SendMail(addr, auth, SMTPAccount, to, mail)
} else { } else {
err = smtp.SendMail(addr, auth, SMTPAccount, to, mail) err = smtp.SendMail(addr, auth, SMTPAccount, to, mail)
} }

View File

@ -3,6 +3,7 @@ package common
import ( import (
"encoding/json" "encoding/json"
"strings" "strings"
"sync"
) )
// from songquanpeng/one-api // from songquanpeng/one-api
@ -183,8 +184,14 @@ var defaultModelPrice = map[string]float64{
"swap_face": 0.05, "swap_face": 0.05,
} }
var modelPrice map[string]float64 = nil var (
var modelRatio map[string]float64 = nil modelPriceMap = make(map[string]float64)
modelPriceMapMutex = sync.RWMutex{}
)
var (
modelRatioMap map[string]float64 = nil
modelRatioMapMutex = sync.RWMutex{}
)
var CompletionRatio map[string]float64 = nil var CompletionRatio map[string]float64 = nil
var defaultCompletionRatio = map[string]float64{ var defaultCompletionRatio = map[string]float64{
@ -194,11 +201,18 @@ var defaultCompletionRatio = map[string]float64{
"gpt-4o-all": 2, "gpt-4o-all": 2,
} }
func ModelPrice2JSONString() string { func GetModelPriceMap() map[string]float64 {
if modelPrice == nil { modelPriceMapMutex.Lock()
modelPrice = defaultModelPrice defer modelPriceMapMutex.Unlock()
if modelPriceMap == nil {
modelPriceMap = defaultModelPrice
} }
jsonBytes, err := json.Marshal(modelPrice) return modelPriceMap
}
func ModelPrice2JSONString() string {
GetModelPriceMap()
jsonBytes, err := json.Marshal(modelPriceMap)
if err != nil { if err != nil {
SysError("error marshalling model price: " + err.Error()) SysError("error marshalling model price: " + err.Error())
} }
@ -206,21 +220,21 @@ func ModelPrice2JSONString() string {
} }
func UpdateModelPriceByJSONString(jsonStr string) error { func UpdateModelPriceByJSONString(jsonStr string) error {
modelPrice = make(map[string]float64) modelPriceMapMutex.Lock()
return json.Unmarshal([]byte(jsonStr), &modelPrice) defer modelPriceMapMutex.Unlock()
modelPriceMap = make(map[string]float64)
return json.Unmarshal([]byte(jsonStr), &modelPriceMap)
} }
// GetModelPrice 返回模型的价格,如果模型不存在则返回-1false // GetModelPrice 返回模型的价格,如果模型不存在则返回-1false
func GetModelPrice(name string, printErr bool) (float64, bool) { func GetModelPrice(name string, printErr bool) (float64, bool) {
if modelPrice == nil { GetModelPriceMap()
modelPrice = defaultModelPrice
}
if strings.HasPrefix(name, "gpt-4-gizmo") { if strings.HasPrefix(name, "gpt-4-gizmo") {
name = "gpt-4-gizmo-*" name = "gpt-4-gizmo-*"
} else if strings.HasPrefix(name, "g-") { } else if strings.HasPrefix(name, "g-") {
name = "g-*" name = "g-*"
} }
price, ok := modelPrice[name] price, ok := modelPriceMap[name]
if !ok { if !ok {
if printErr { if printErr {
SysError("model price not found: " + name) SysError("model price not found: " + name)
@ -230,18 +244,18 @@ func GetModelPrice(name string, printErr bool) (float64, bool) {
return price, true return price, true
} }
func GetModelPriceMap() map[string]float64 { func GetModelRatioMap() map[string]float64 {
if modelPrice == nil { modelRatioMapMutex.Lock()
modelPrice = defaultModelPrice defer modelRatioMapMutex.Unlock()
if modelRatioMap == nil {
modelRatioMap = defaultModelRatio
} }
return modelPrice return modelRatioMap
} }
func ModelRatio2JSONString() string { func ModelRatio2JSONString() string {
if modelRatio == nil { GetModelRatioMap()
modelRatio = defaultModelRatio jsonBytes, err := json.Marshal(modelRatioMap)
}
jsonBytes, err := json.Marshal(modelRatio)
if err != nil { if err != nil {
SysError("error marshalling model ratio: " + err.Error()) SysError("error marshalling model ratio: " + err.Error())
} }
@ -249,20 +263,20 @@ func ModelRatio2JSONString() string {
} }
func UpdateModelRatioByJSONString(jsonStr string) error { func UpdateModelRatioByJSONString(jsonStr string) error {
modelRatio = make(map[string]float64) modelRatioMapMutex.Lock()
return json.Unmarshal([]byte(jsonStr), &modelRatio) defer modelRatioMapMutex.Unlock()
modelRatioMap = make(map[string]float64)
return json.Unmarshal([]byte(jsonStr), &modelRatioMap)
} }
func GetModelRatio(name string) float64 { func GetModelRatio(name string) float64 {
if modelRatio == nil { GetModelRatioMap()
modelRatio = defaultModelRatio
}
if strings.HasPrefix(name, "gpt-4-gizmo") { if strings.HasPrefix(name, "gpt-4-gizmo") {
name = "gpt-4-gizmo-*" name = "gpt-4-gizmo-*"
} else if strings.HasPrefix(name, "g-") { } else if strings.HasPrefix(name, "g-") {
name = "g-*" name = "g-*"
} }
ratio, ok := modelRatio[name] ratio, ok := modelRatioMap[name]
if !ok { if !ok {
SysError("model ratio not found: " + name) SysError("model ratio not found: " + name)
return 30 return 30

View File

@ -43,12 +43,13 @@ func Relay(c *gin.Context) {
requestId := c.GetString(common.RequestIdKey) requestId := c.GetString(common.RequestIdKey)
channelId := c.GetInt("channel_id") channelId := c.GetInt("channel_id")
channelType := c.GetInt("channel_type") channelType := c.GetInt("channel_type")
channelName := c.GetString("channel_name")
group := c.GetString("group") group := c.GetString("group")
originalModel := c.GetString("original_model") originalModel := c.GetString("original_model")
openaiErr := relayHandler(c, relayMode) openaiErr := relayHandler(c, relayMode)
c.Set("use_channel", []string{fmt.Sprintf("%d", channelId)}) c.Set("use_channel", []string{fmt.Sprintf("%d", channelId)})
if openaiErr != nil { if openaiErr != nil {
go processChannelError(c, channelId, channelType, openaiErr) go processChannelError(c, channelId, channelType, channelName, openaiErr)
} else { } else {
retryTimes = 0 retryTimes = 0
} }
@ -60,7 +61,7 @@ func Relay(c *gin.Context) {
} }
channelId = channel.Id channelId = channel.Id
useChannel := c.GetStringSlice("use_channel") useChannel := c.GetStringSlice("use_channel")
useChannel = append(useChannel, fmt.Sprintf("%d", channelId)) useChannel = append(useChannel, fmt.Sprintf("%d", channel.Id))
c.Set("use_channel", useChannel) c.Set("use_channel", useChannel)
common.LogInfo(c.Request.Context(), fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, i)) common.LogInfo(c.Request.Context(), fmt.Sprintf("using channel #%d to retry (remain times %d)", channel.Id, i))
middleware.SetupContextForSelectedChannel(c, channel, originalModel) middleware.SetupContextForSelectedChannel(c, channel, originalModel)
@ -69,7 +70,7 @@ func Relay(c *gin.Context) {
c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody)) c.Request.Body = io.NopCloser(bytes.NewBuffer(requestBody))
openaiErr = relayHandler(c, relayMode) openaiErr = relayHandler(c, relayMode)
if openaiErr != nil { if openaiErr != nil {
go processChannelError(c, channelId, channel.Type, openaiErr) go processChannelError(c, channel.Id, channel.Type, channel.Name, openaiErr)
} }
} }
useChannel := c.GetStringSlice("use_channel") useChannel := c.GetStringSlice("use_channel")
@ -128,11 +129,10 @@ func shouldRetry(c *gin.Context, channelId int, openaiErr *dto.OpenAIErrorWithSt
return true return true
} }
func processChannelError(c *gin.Context, channelId int, channelType int, err *dto.OpenAIErrorWithStatusCode) { func processChannelError(c *gin.Context, channelId int, channelType int, channelName string, err *dto.OpenAIErrorWithStatusCode) {
autoBan := c.GetBool("auto_ban") autoBan := c.GetBool("auto_ban")
common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message)) common.LogError(c.Request.Context(), fmt.Sprintf("relay error (channel #%d, status code: %d): %s", channelId, err.StatusCode, err.Error.Message))
if service.ShouldDisableChannel(channelType, err) && autoBan { if service.ShouldDisableChannel(channelType, err) && autoBan {
channelName := c.GetString("channel_name")
service.DisableChannel(channelId, channelName, err.Error.Message) service.DisableChannel(channelId, channelName, err.Error.Message)
} }
} }

View File

@ -1,11 +1,13 @@
package middleware package middleware
import ( import (
"fmt"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"one-api/common" "one-api/common"
) )
func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) { func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) {
userId := c.GetInt("id")
c.JSON(statusCode, gin.H{ c.JSON(statusCode, gin.H{
"error": gin.H{ "error": gin.H{
"message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)), "message": common.MessageWithRequestId(message, c.GetString(common.RequestIdKey)),
@ -13,7 +15,7 @@ func abortWithOpenAiMessage(c *gin.Context, statusCode int, message string) {
}, },
}) })
c.Abort() c.Abort()
common.LogError(c.Request.Context(), message) common.LogError(c.Request.Context(), fmt.Sprintf("user %d | %s", userId, message))
} }
func abortWithMidjourneyMessage(c *gin.Context, statusCode int, code int, description string) { func abortWithMidjourneyMessage(c *gin.Context, statusCode int, code int, description string) {

View File

@ -100,8 +100,8 @@ func SearchChannels(keyword string, group string, model string) ([]*Channel, err
var whereClause string var whereClause string
var args []interface{} var args []interface{}
if group != "" { if group != "" {
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " LIKE ? AND " + modelsCol + " LIKE ?" whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + groupCol + " = ? AND " + modelsCol + " LIKE ?"
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+group+"%", "%"+model+"%") args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, group, "%"+model+"%")
} else { } else {
whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?" whereClause = "(id = ? OR name LIKE ? OR " + keyCol + " = ?) AND " + modelsCol + " LIKE ?"
args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%") args = append(args, common.String2Int(keyword), "%"+keyword+"%", keyword, "%"+model+"%")

View File

@ -222,9 +222,11 @@ func awsStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
} }
} }
service.Done(c) service.Done(c)
err = resp.Body.Close() if resp != nil {
if err != nil { err = resp.Body.Close()
return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil if err != nil {
return service.OpenAIErrorWrapperLocal(err, "close_response_body_failed", http.StatusInternalServerError), nil
}
} }
return nil, &usage return nil, &usage
} }

View File

@ -1,6 +1,7 @@
package cloudflare package cloudflare
var ModelList = []string{ var ModelList = []string{
"@cf/meta/llama-3.1-8b-instruct",
"@cf/meta/llama-2-7b-chat-fp16", "@cf/meta/llama-2-7b-chat-fp16",
"@cf/meta/llama-2-7b-chat-int8", "@cf/meta/llama-2-7b-chat-int8",
"@cf/mistral/mistral-7b-instruct-v0.1", "@cf/mistral/mistral-7b-instruct-v0.1",

View File

@ -53,7 +53,7 @@ func streamResponseDify2OpenAI(difyResponse DifyChunkChatCompletionResponse) *dt
choice.Delta.SetContentString("Workflow: " + difyResponse.Data.WorkflowId + "\n") choice.Delta.SetContentString("Workflow: " + difyResponse.Data.WorkflowId + "\n")
} else if constant.DifyDebug && difyResponse.Event == "node_started" { } else if constant.DifyDebug && difyResponse.Event == "node_started" {
choice.Delta.SetContentString("Node: " + difyResponse.Data.NodeId + "\n") choice.Delta.SetContentString("Node: " + difyResponse.Data.NodeId + "\n")
} else if difyResponse.Event == "message" { } else if difyResponse.Event == "message" || difyResponse.Event == "agent_message" {
choice.Delta.SetContentString(difyResponse.Answer) choice.Delta.SetContentString(difyResponse.Answer)
} }
response.Choices = append(response.Choices, choice) response.Choices = append(response.Choices, choice)

View File

@ -83,13 +83,28 @@ func CovertGemini2OpenAI(textRequest dto.GeneralOpenAIRequest) *GeminiChatReques
if imageNum > GeminiVisionMaxImageNum { if imageNum > GeminiVisionMaxImageNum {
continue continue
} }
mimeType, data, _ := common.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url) // 判断是否是url
parts = append(parts, GeminiPart{ if strings.HasPrefix(part.ImageUrl.(dto.MessageImageUrl).Url, "http") {
InlineData: &GeminiInlineData{ // 是url获取图片的类型和base64编码的数据
MimeType: mimeType, mimeType, data, _ := common.GetImageFromUrl(part.ImageUrl.(dto.MessageImageUrl).Url)
Data: data, parts = append(parts, GeminiPart{
}, InlineData: &GeminiInlineData{
}) MimeType: mimeType,
Data: data,
},
})
} else {
_, format, base64String, err := common.DecodeBase64ImageData(part.ImageUrl.(dto.MessageImageUrl).Url)
if err != nil {
continue
}
parts = append(parts, GeminiPart{
InlineData: &GeminiInlineData{
MimeType: "image/" + format,
Data: base64String,
},
})
}
} }
} }
content.Parts = parts content.Parts = parts

View File

@ -3,14 +3,18 @@ package ollama
import "one-api/dto" import "one-api/dto"
type OllamaRequest struct { type OllamaRequest struct {
Model string `json:"model,omitempty"` Model string `json:"model,omitempty"`
Messages []dto.Message `json:"messages,omitempty"` Messages []dto.Message `json:"messages,omitempty"`
Stream bool `json:"stream,omitempty"` Stream bool `json:"stream,omitempty"`
Temperature float64 `json:"temperature,omitempty"` Temperature float64 `json:"temperature,omitempty"`
Seed float64 `json:"seed,omitempty"` Seed float64 `json:"seed,omitempty"`
Topp float64 `json:"top_p,omitempty"` Topp float64 `json:"top_p,omitempty"`
TopK int `json:"top_k,omitempty"` TopK int `json:"top_k,omitempty"`
Stop any `json:"stop,omitempty"` Stop any `json:"stop,omitempty"`
Tools []dto.ToolCall `json:"tools,omitempty"`
ResponseFormat *dto.ResponseFormat `json:"response_format,omitempty"`
FrequencyPenalty float64 `json:"frequency_penalty,omitempty"`
PresencePenalty float64 `json:"presence_penalty,omitempty"`
} }
type OllamaEmbeddingRequest struct { type OllamaEmbeddingRequest struct {
@ -21,6 +25,3 @@ type OllamaEmbeddingRequest struct {
type OllamaEmbeddingResponse struct { type OllamaEmbeddingResponse struct {
Embedding []float64 `json:"embedding,omitempty"` Embedding []float64 `json:"embedding,omitempty"`
} }
//type OllamaOptions struct {
//}

View File

@ -28,14 +28,18 @@ func requestOpenAI2Ollama(request dto.GeneralOpenAIRequest) *OllamaRequest {
Stop, _ = request.Stop.([]string) Stop, _ = request.Stop.([]string)
} }
return &OllamaRequest{ return &OllamaRequest{
Model: request.Model, Model: request.Model,
Messages: messages, Messages: messages,
Stream: request.Stream, Stream: request.Stream,
Temperature: request.Temperature, Temperature: request.Temperature,
Seed: request.Seed, Seed: request.Seed,
Topp: request.TopP, Topp: request.TopP,
TopK: request.TopK, TopK: request.TopK,
Stop: Stop, Stop: Stop,
Tools: request.Tools,
ResponseFormat: request.ResponseFormat,
FrequencyPenalty: request.FrequencyPenalty,
PresencePenalty: request.PresencePenalty,
} }
} }

View File

@ -22,7 +22,7 @@ import (
func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) { func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.RelayInfo) (*dto.OpenAIErrorWithStatusCode, *dto.Usage) {
containStreamUsage := false containStreamUsage := false
responseId := "" var responseId string
var createAt int64 = 0 var createAt int64 = 0
var systemFingerprint string var systemFingerprint string
model := info.UpstreamModelName model := info.UpstreamModelName
@ -86,7 +86,13 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
var lastStreamResponse dto.ChatCompletionsStreamResponse var lastStreamResponse dto.ChatCompletionsStreamResponse
err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse) err := json.Unmarshal(common.StringToByteSlice(lastStreamData), &lastStreamResponse)
if err == nil { if err == nil {
if lastStreamResponse.Usage != nil && service.ValidUsage(lastStreamResponse.Usage) { responseId = lastStreamResponse.Id
createAt = lastStreamResponse.Created
systemFingerprint = lastStreamResponse.GetSystemFingerprint()
model = lastStreamResponse.Model
if service.ValidUsage(lastStreamResponse.Usage) {
containStreamUsage = true
usage = lastStreamResponse.Usage
if !info.ShouldIncludeUsage { if !info.ShouldIncludeUsage {
shouldSendLastResp = false shouldSendLastResp = false
} }
@ -109,14 +115,9 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
var streamResponse dto.ChatCompletionsStreamResponse var streamResponse dto.ChatCompletionsStreamResponse
err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse) err := json.Unmarshal(common.StringToByteSlice(item), &streamResponse)
if err == nil { if err == nil {
responseId = streamResponse.Id //if service.ValidUsage(streamResponse.Usage) {
createAt = streamResponse.Created // usage = streamResponse.Usage
systemFingerprint = streamResponse.GetSystemFingerprint() //}
model = streamResponse.Model
if service.ValidUsage(streamResponse.Usage) {
usage = streamResponse.Usage
containStreamUsage = true
}
for _, choice := range streamResponse.Choices { for _, choice := range streamResponse.Choices {
responseTextBuilder.WriteString(choice.Delta.GetContentString()) responseTextBuilder.WriteString(choice.Delta.GetContentString())
if choice.Delta.ToolCalls != nil { if choice.Delta.ToolCalls != nil {
@ -133,14 +134,10 @@ func OaiStreamHandler(c *gin.Context, resp *http.Response, info *relaycommon.Rel
} }
} else { } else {
for _, streamResponse := range streamResponses { for _, streamResponse := range streamResponses {
responseId = streamResponse.Id //if service.ValidUsage(streamResponse.Usage) {
createAt = streamResponse.Created // usage = streamResponse.Usage
systemFingerprint = streamResponse.GetSystemFingerprint() // containStreamUsage = true
model = streamResponse.Model //}
if service.ValidUsage(streamResponse.Usage) {
usage = streamResponse.Usage
containStreamUsage = true
}
for _, choice := range streamResponse.Choices { for _, choice := range streamResponse.Choices {
responseTextBuilder.WriteString(choice.Delta.GetContentString()) responseTextBuilder.WriteString(choice.Delta.GetContentString())
if choice.Delta.ToolCalls != nil { if choice.Delta.ToolCalls != nil {

View File

@ -121,7 +121,8 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode {
} }
} }
quota := int(modelPrice*groupRatio*common.QuotaPerUnit*sizeRatio*qualityRatio) * imageRequest.N imageRatio := modelPrice * sizeRatio * qualityRatio * float64(imageRequest.N)
quota := int(imageRatio * groupRatio * common.QuotaPerUnit)
if userQuota-quota < 0 { if userQuota-quota < 0 {
return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden) return service.OpenAIErrorWrapperLocal(errors.New("user quota is not enough"), "insufficient_user_quota", http.StatusForbidden)
@ -180,7 +181,7 @@ func ImageHelper(c *gin.Context, relayMode int) *dto.OpenAIErrorWithStatusCode {
} }
logContent := fmt.Sprintf("大小 %s, 品质 %s", imageRequest.Size, quality) logContent := fmt.Sprintf("大小 %s, 品质 %s", imageRequest.Size, quality)
postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, modelPrice, true, logContent) postConsumeQuota(c, relayInfo, imageRequest.Model, usage, 0, 0, userQuota, 0, groupRatio, imageRatio, true, logContent)
return nil return nil
} }

View File

@ -1,7 +1,14 @@
import React, { useContext, useEffect, useState } from 'react'; import React, { useContext, useEffect, useState } from 'react';
import { Link, useNavigate, useSearchParams } from 'react-router-dom'; import { Link, useNavigate, useSearchParams } from 'react-router-dom';
import { UserContext } from '../context/User'; import { UserContext } from '../context/User';
import { API, getLogo, showError, showInfo, showSuccess } from '../helpers'; import {
API,
getLogo,
showError,
showInfo,
showSuccess,
updateAPI,
} from '../helpers';
import { onGitHubOAuthClicked, onLinuxDoOAuthClicked } from './utils'; import { onGitHubOAuthClicked, onLinuxDoOAuthClicked } from './utils';
import Turnstile from 'react-turnstile'; import Turnstile from 'react-turnstile';
import { import {
@ -102,6 +109,7 @@ const LoginForm = () => {
if (success) { if (success) {
userDispatch({ type: 'login', payload: data }); userDispatch({ type: 'login', payload: data });
setUserData(data); setUserData(data);
updateAPI();
showSuccess('登录成功!'); showSuccess('登录成功!');
if (username === 'root' && password === '123456') { if (username === 'root' && password === '123456') {
Modal.error({ Modal.error({

View File

@ -1,7 +1,7 @@
import { getUserIdFromLocalStorage, showError } from './utils'; import { getUserIdFromLocalStorage, showError } from './utils';
import axios from 'axios'; import axios from 'axios';
export const API = axios.create({ export let API = axios.create({
baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL
? import.meta.env.VITE_REACT_APP_SERVER_URL ? import.meta.env.VITE_REACT_APP_SERVER_URL
: '', : '',
@ -10,6 +10,17 @@ export const API = axios.create({
}, },
}); });
export function updateAPI() {
API = axios.create({
baseURL: import.meta.env.VITE_REACT_APP_SERVER_URL
? import.meta.env.VITE_REACT_APP_SERVER_URL
: '',
headers: {
'New-API-User': getUserIdFromLocalStorage(),
},
});
}
API.interceptors.response.use( API.interceptors.response.use(
(response) => response, (response) => response,
(error) => { (error) => {

View File

@ -1,11 +1,14 @@
import React from 'react'; import React from 'react';
import TokensTable from '../../components/TokensTable'; import TokensTable from '../../components/TokensTable';
import { Layout } from '@douyinfe/semi-ui'; import { Banner, Layout } from '@douyinfe/semi-ui';
const Token = () => ( const Token = () => (
<> <>
<Layout> <Layout>
<Layout.Header> <Layout.Header>
<h3>我的令牌</h3> <Banner
type='warning'
description='令牌无法精确控制使用额度,请勿直接将令牌分发给用户。'
/>
</Layout.Header> </Layout.Header>
<Layout.Content> <Layout.Content>
<TokensTable /> <TokensTable />