Compare commits

...

9 Commits

Author SHA1 Message Date
JustSong
b204f6d82b docs: update README 2024-03-15 00:55:28 +08:00
JustSong
752639560f feat: able to use separated database for table logs 2024-03-15 00:30:15 +08:00
JustSong
996f4d99dd ci: fix ci 2024-03-14 23:53:25 +08:00
warjiang
ebfee3b46c feat: add support for private registry in docker-compose.yml (#1103) 2024-03-14 23:47:46 +08:00
dependabot[bot]
3e2e805d61 chore(deps): bump google.golang.org/protobuf from 1.30.0 to 1.33.0 (#1145)
Bumps google.golang.org/protobuf from 1.30.0 to 1.33.0.

---
updated-dependencies:
- dependency-name: google.golang.org/protobuf
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-03-14 23:46:17 +08:00
E.da
3edf7247c4 fix: fix theme berry copy (#1148)
调整berry主题页脚`label`表述
2024-03-14 23:45:50 +08:00
afafw
0926b6206b chore: update client name (#934) 2024-03-14 23:44:46 +08:00
JustSong
7cd57f3125 chore: update ratio for baidu embedding 2024-03-14 23:36:10 +08:00
Jguobao
66efabd5ae fix: fix baidu url check (#1143)
添加百度的另外3个向量模型【"bge-large-zh",
	"bge-large-en",
	"tao-8k",
】
2024-03-14 23:31:07 +08:00
18 changed files with 97 additions and 55 deletions

View File

@@ -24,7 +24,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- name: Save version info - name: Save version info

View File

@@ -24,7 +24,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- name: Save version info - name: Save version info

View File

@@ -25,7 +25,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- name: Save version info - name: Save version info

View File

@@ -24,7 +24,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:

View File

@@ -24,7 +24,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:

View File

@@ -27,7 +27,7 @@ jobs:
run: | run: |
REPO_URL=$(git config --get remote.origin.url) REPO_URL=$(git config --get remote.origin.url)
if [[ $REPO_URL == *"pro" ]]; then if [[ $REPO_URL == *"pro" ]]; then
exit 1 exit 0
fi fi
- uses: actions/setup-node@v3 - uses: actions/setup-node@v3
with: with:

View File

@@ -78,6 +78,9 @@ var ModelRatio = map[string]float64{
"ERNIE-Bot-4": 0.12 * RMB, // ¥0.12 / 1k tokens "ERNIE-Bot-4": 0.12 * RMB, // ¥0.12 / 1k tokens
"ERNIE-Bot-8k": 0.024 * RMB, "ERNIE-Bot-8k": 0.024 * RMB,
"Embedding-V1": 0.1429, // ¥0.002 / 1k tokens "Embedding-V1": 0.1429, // ¥0.002 / 1k tokens
"bge-large-zh": 0.002 * RMB,
"bge-large-en": 0.002 * RMB,
"bge-large-8k": 0.002 * RMB,
"PaLM-2": 1, "PaLM-2": 1,
"gemini-pro": 1, // $0.00025 / 1k characters -> $0.001 / 1k tokens "gemini-pro": 1, // $0.00025 / 1k characters -> $0.001 / 1k tokens
"gemini-pro-vision": 1, // $0.00025 / 1k characters -> $0.001 / 1k tokens "gemini-pro-vision": 1, // $0.00025 / 1k characters -> $0.001 / 1k tokens

View File

@@ -2,7 +2,7 @@ version: '3.4'
services: services:
one-api: one-api:
image: justsong/one-api:latest image: "${REGISTRY:-docker.io}/justsong/one-api:latest"
container_name: one-api container_name: one-api
restart: always restart: always
command: --log-dir /app/logs command: --log-dir /app/logs
@@ -29,12 +29,12 @@ services:
retries: 3 retries: 3
redis: redis:
image: redis:latest image: "${REGISTRY:-docker.io}/redis:latest"
container_name: redis container_name: redis
restart: always restart: always
db: db:
image: mysql:8.2.0 image: "${REGISTRY:-docker.io}/mysql:8.2.0"
restart: always restart: always
container_name: mysql container_name: mysql
volumes: volumes:

2
go.mod
View File

@@ -60,6 +60,6 @@ require (
golang.org/x/net v0.17.0 // indirect golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect golang.org/x/sys v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect golang.org/x/text v0.14.0 // indirect
google.golang.org/protobuf v1.30.0 // indirect google.golang.org/protobuf v1.33.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

4
go.sum
View File

@@ -177,8 +177,8 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IV
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

16
main.go
View File

@@ -30,11 +30,25 @@ func main() {
if config.DebugEnabled { if config.DebugEnabled {
logger.SysLog("running in debug mode") logger.SysLog("running in debug mode")
} }
var err error
// Initialize SQL Database // Initialize SQL Database
err := model.InitDB() model.DB, err = model.InitDB("SQL_DSN")
if err != nil { if err != nil {
logger.FatalLog("failed to initialize database: " + err.Error()) logger.FatalLog("failed to initialize database: " + err.Error())
} }
if os.Getenv("LOG_SQL_DSN") != "" {
logger.SysLog("using secondary database for table logs")
model.LOG_DB, err = model.InitDB("LOG_SQL_DSN")
if err != nil {
logger.FatalLog("failed to initialize secondary database: " + err.Error())
}
} else {
model.LOG_DB = model.DB
}
err = model.CreateRootAccountIfNeed()
if err != nil {
logger.FatalLog("database init error: " + err.Error())
}
defer func() { defer func() {
err := model.CloseDB() err := model.CloseDB()
if err != nil { if err != nil {

View File

@@ -45,7 +45,7 @@ func RecordLog(userId int, logType int, content string) {
Type: logType, Type: logType,
Content: content, Content: content,
} }
err := DB.Create(log).Error err := LOG_DB.Create(log).Error
if err != nil { if err != nil {
logger.SysError("failed to record log: " + err.Error()) logger.SysError("failed to record log: " + err.Error())
} }
@@ -69,7 +69,7 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke
Quota: int(quota), Quota: int(quota),
ChannelId: channelId, ChannelId: channelId,
} }
err := DB.Create(log).Error err := LOG_DB.Create(log).Error
if err != nil { if err != nil {
logger.Error(ctx, "failed to record log: "+err.Error()) logger.Error(ctx, "failed to record log: "+err.Error())
} }
@@ -78,9 +78,9 @@ func RecordConsumeLog(ctx context.Context, userId int, channelId int, promptToke
func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int) (logs []*Log, err error) { func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, startIdx int, num int, channel int) (logs []*Log, err error) {
var tx *gorm.DB var tx *gorm.DB
if logType == LogTypeUnknown { if logType == LogTypeUnknown {
tx = DB tx = LOG_DB
} else { } else {
tx = DB.Where("type = ?", logType) tx = LOG_DB.Where("type = ?", logType)
} }
if modelName != "" { if modelName != "" {
tx = tx.Where("model_name = ?", modelName) tx = tx.Where("model_name = ?", modelName)
@@ -107,9 +107,9 @@ func GetAllLogs(logType int, startTimestamp int64, endTimestamp int64, modelName
func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int64, modelName string, tokenName string, startIdx int, num int) (logs []*Log, err error) { func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int64, modelName string, tokenName string, startIdx int, num int) (logs []*Log, err error) {
var tx *gorm.DB var tx *gorm.DB
if logType == LogTypeUnknown { if logType == LogTypeUnknown {
tx = DB.Where("user_id = ?", userId) tx = LOG_DB.Where("user_id = ?", userId)
} else { } else {
tx = DB.Where("user_id = ? and type = ?", userId, logType) tx = LOG_DB.Where("user_id = ? and type = ?", userId, logType)
} }
if modelName != "" { if modelName != "" {
tx = tx.Where("model_name = ?", modelName) tx = tx.Where("model_name = ?", modelName)
@@ -128,17 +128,17 @@ func GetUserLogs(userId int, logType int, startTimestamp int64, endTimestamp int
} }
func SearchAllLogs(keyword string) (logs []*Log, err error) { func SearchAllLogs(keyword string) (logs []*Log, err error) {
err = DB.Where("type = ? or content LIKE ?", keyword, keyword+"%").Order("id desc").Limit(config.MaxRecentItems).Find(&logs).Error err = LOG_DB.Where("type = ? or content LIKE ?", keyword, keyword+"%").Order("id desc").Limit(config.MaxRecentItems).Find(&logs).Error
return logs, err return logs, err
} }
func SearchUserLogs(userId int, keyword string) (logs []*Log, err error) { func SearchUserLogs(userId int, keyword string) (logs []*Log, err error) {
err = DB.Where("user_id = ? and type = ?", userId, keyword).Order("id desc").Limit(config.MaxRecentItems).Omit("id").Find(&logs).Error err = LOG_DB.Where("user_id = ? and type = ?", userId, keyword).Order("id desc").Limit(config.MaxRecentItems).Omit("id").Find(&logs).Error
return logs, err return logs, err
} }
func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (quota int64) { func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string, channel int) (quota int64) {
tx := DB.Table("logs").Select("ifnull(sum(quota),0)") tx := LOG_DB.Table("logs").Select("ifnull(sum(quota),0)")
if username != "" { if username != "" {
tx = tx.Where("username = ?", username) tx = tx.Where("username = ?", username)
} }
@@ -162,7 +162,7 @@ func SumUsedQuota(logType int, startTimestamp int64, endTimestamp int64, modelNa
} }
func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) { func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelName string, username string, tokenName string) (token int) {
tx := DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)") tx := LOG_DB.Table("logs").Select("ifnull(sum(prompt_tokens),0) + ifnull(sum(completion_tokens),0)")
if username != "" { if username != "" {
tx = tx.Where("username = ?", username) tx = tx.Where("username = ?", username)
} }
@@ -183,7 +183,7 @@ func SumUsedToken(logType int, startTimestamp int64, endTimestamp int64, modelNa
} }
func DeleteOldLog(targetTimestamp int64) (int64, error) { func DeleteOldLog(targetTimestamp int64) (int64, error) {
result := DB.Where("created_at < ?", targetTimestamp).Delete(&Log{}) result := LOG_DB.Where("created_at < ?", targetTimestamp).Delete(&Log{})
return result.RowsAffected, result.Error return result.RowsAffected, result.Error
} }
@@ -207,7 +207,7 @@ func SearchLogsByDayAndModel(userId, start, end int) (LogStatistics []*LogStatis
groupSelect = "strftime('%Y-%m-%d', datetime(created_at, 'unixepoch')) as day" groupSelect = "strftime('%Y-%m-%d', datetime(created_at, 'unixepoch')) as day"
} }
err = DB.Raw(` err = LOG_DB.Raw(`
SELECT `+groupSelect+`, SELECT `+groupSelect+`,
model_name, count(1) as request_count, model_name, count(1) as request_count,
sum(quota) as quota, sum(quota) as quota,

View File

@@ -17,8 +17,9 @@ import (
) )
var DB *gorm.DB var DB *gorm.DB
var LOG_DB *gorm.DB
func createRootAccountIfNeed() error { func CreateRootAccountIfNeed() error {
var user User var user User
//if user.Status != util.UserStatusEnabled { //if user.Status != util.UserStatusEnabled {
if err := DB.First(&user).Error; err != nil { if err := DB.First(&user).Error; err != nil {
@@ -41,9 +42,9 @@ func createRootAccountIfNeed() error {
return nil return nil
} }
func chooseDB() (*gorm.DB, error) { func chooseDB(envName string) (*gorm.DB, error) {
if os.Getenv("SQL_DSN") != "" { if os.Getenv(envName) != "" {
dsn := os.Getenv("SQL_DSN") dsn := os.Getenv(envName)
if strings.HasPrefix(dsn, "postgres://") { if strings.HasPrefix(dsn, "postgres://") {
// Use PostgreSQL // Use PostgreSQL
logger.SysLog("using PostgreSQL as database") logger.SysLog("using PostgreSQL as database")
@@ -71,23 +72,22 @@ func chooseDB() (*gorm.DB, error) {
}) })
} }
func InitDB() (err error) { func InitDB(envName string) (db *gorm.DB, err error) {
db, err := chooseDB() db, err = chooseDB(envName)
if err == nil { if err == nil {
if config.DebugSQLEnabled { if config.DebugSQLEnabled {
db = db.Debug() db = db.Debug()
} }
DB = db sqlDB, err := db.DB()
sqlDB, err := DB.DB()
if err != nil { if err != nil {
return err return nil, err
} }
sqlDB.SetMaxIdleConns(env.Int("SQL_MAX_IDLE_CONNS", 100)) sqlDB.SetMaxIdleConns(env.Int("SQL_MAX_IDLE_CONNS", 100))
sqlDB.SetMaxOpenConns(env.Int("SQL_MAX_OPEN_CONNS", 1000)) sqlDB.SetMaxOpenConns(env.Int("SQL_MAX_OPEN_CONNS", 1000))
sqlDB.SetConnMaxLifetime(time.Second * time.Duration(env.Int("SQL_MAX_LIFETIME", 60))) sqlDB.SetConnMaxLifetime(time.Second * time.Duration(env.Int("SQL_MAX_LIFETIME", 60)))
if !config.IsMasterNode { if !config.IsMasterNode {
return nil return db, err
} }
if common.UsingMySQL { if common.UsingMySQL {
_, _ = sqlDB.Exec("DROP INDEX idx_channels_key ON channels;") // TODO: delete this line when most users have upgraded _, _ = sqlDB.Exec("DROP INDEX idx_channels_key ON channels;") // TODO: delete this line when most users have upgraded
@@ -95,46 +95,55 @@ func InitDB() (err error) {
logger.SysLog("database migration started") logger.SysLog("database migration started")
err = db.AutoMigrate(&Channel{}) err = db.AutoMigrate(&Channel{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&Token{}) err = db.AutoMigrate(&Token{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&User{}) err = db.AutoMigrate(&User{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&Option{}) err = db.AutoMigrate(&Option{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&Redemption{}) err = db.AutoMigrate(&Redemption{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&Ability{}) err = db.AutoMigrate(&Ability{})
if err != nil { if err != nil {
return err return nil, err
} }
err = db.AutoMigrate(&Log{}) err = db.AutoMigrate(&Log{})
if err != nil { if err != nil {
return err return nil, err
} }
logger.SysLog("database migrated") logger.SysLog("database migrated")
err = createRootAccountIfNeed() return db, err
return err
} else { } else {
logger.FatalLog(err) logger.FatalLog(err)
} }
return err return db, err
} }
func CloseDB() error { func closeDB(db *gorm.DB) error {
sqlDB, err := DB.DB() sqlDB, err := db.DB()
if err != nil { if err != nil {
return err return err
} }
err = sqlDB.Close() err = sqlDB.Close()
return err return err
} }
func CloseDB() error {
if LOG_DB != DB {
err := closeDB(LOG_DB)
if err != nil {
return err
}
}
return closeDB(DB)
}

View File

@@ -3,14 +3,15 @@ package baidu
import ( import (
"errors" "errors"
"fmt" "fmt"
"io"
"net/http"
"strings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/songquanpeng/one-api/relay/channel" "github.com/songquanpeng/one-api/relay/channel"
"github.com/songquanpeng/one-api/relay/constant" "github.com/songquanpeng/one-api/relay/constant"
"github.com/songquanpeng/one-api/relay/model" "github.com/songquanpeng/one-api/relay/model"
"github.com/songquanpeng/one-api/relay/util" "github.com/songquanpeng/one-api/relay/util"
"io"
"net/http"
"strings"
) )
type Adaptor struct { type Adaptor struct {
@@ -23,7 +24,13 @@ func (a *Adaptor) Init(meta *util.RelayMeta) {
func (a *Adaptor) GetRequestURL(meta *util.RelayMeta) (string, error) { func (a *Adaptor) GetRequestURL(meta *util.RelayMeta) (string, error) {
// https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t // https://cloud.baidu.com/doc/WENXINWORKSHOP/s/clntwmv7t
suffix := "chat/" suffix := "chat/"
if strings.HasPrefix("Embedding", meta.ActualModelName) { if strings.HasPrefix(meta.ActualModelName, "Embedding") {
suffix = "embeddings/"
}
if strings.HasPrefix(meta.ActualModelName, "bge-large") {
suffix = "embeddings/"
}
if strings.HasPrefix(meta.ActualModelName, "tao-8k") {
suffix = "embeddings/" suffix = "embeddings/"
} }
switch meta.ActualModelName { switch meta.ActualModelName {
@@ -45,6 +52,12 @@ func (a *Adaptor) GetRequestURL(meta *util.RelayMeta) (string, error) {
suffix += "bloomz_7b1" suffix += "bloomz_7b1"
case "Embedding-V1": case "Embedding-V1":
suffix += "embedding-v1" suffix += "embedding-v1"
case "bge-large-zh":
suffix += "bge_large_zh"
case "bge-large-en":
suffix += "bge_large_en"
case "tao-8k":
suffix += "tao_8k"
default: default:
suffix += meta.ActualModelName suffix += meta.ActualModelName
} }

View File

@@ -7,4 +7,7 @@ var ModelList = []string{
"ERNIE-Speed", "ERNIE-Speed",
"ERNIE-Bot-turbo", "ERNIE-Bot-turbo",
"Embedding-V1", "Embedding-V1",
"bge-large-zh",
"bge-large-en",
"tao-8k",
} }

View File

@@ -265,7 +265,7 @@ const OtherSetting = () => {
multiline multiline
maxRows={15} maxRows={15}
id="Footer" id="Footer"
label="公告" label="页脚"
value={inputs.Footer} value={inputs.Footer}
name="Footer" name="Footer"
onChange={handleInputChange} onChange={handleInputChange}

View File

@@ -31,7 +31,7 @@ const COPY_OPTIONS = [
url: 'https://chat.oneapi.pro/#/?settings={"key":"sk-{key}","url":"{serverAddress}"}', url: 'https://chat.oneapi.pro/#/?settings={"key":"sk-{key}","url":"{serverAddress}"}',
encode: false encode: false
}, },
{ key: 'ama', text: 'AMA 问天', url: 'ama://set-api-key?server={serverAddress}&key=sk-{key}', encode: true }, { key: 'ama', text: 'BotGem', url: 'ama://set-api-key?server={serverAddress}&key=sk-{key}', encode: true },
{ key: 'opencat', text: 'OpenCat', url: 'opencat://team/join?domain={serverAddress}&token=sk-{key}', encode: true } { key: 'opencat', text: 'OpenCat', url: 'opencat://team/join?domain={serverAddress}&token=sk-{key}', encode: true }
]; ];

View File

@@ -8,12 +8,12 @@ import { renderQuota } from '../helpers/render';
const COPY_OPTIONS = [ const COPY_OPTIONS = [
{ key: 'next', text: 'ChatGPT Next Web', value: 'next' }, { key: 'next', text: 'ChatGPT Next Web', value: 'next' },
{ key: 'ama', text: 'AMA 问天', value: 'ama' }, { key: 'ama', text: 'BotGem', value: 'ama' },
{ key: 'opencat', text: 'OpenCat', value: 'opencat' }, { key: 'opencat', text: 'OpenCat', value: 'opencat' },
]; ];
const OPEN_LINK_OPTIONS = [ const OPEN_LINK_OPTIONS = [
{ key: 'ama', text: 'AMA 问天', value: 'ama' }, { key: 'ama', text: 'BotGem', value: 'ama' },
{ key: 'opencat', text: 'OpenCat', value: 'opencat' }, { key: 'opencat', text: 'OpenCat', value: 'opencat' },
]; ];