Compare commits

...

7 Commits
0.5.2 ... 0.5.4

Author SHA1 Message Date
ckt1031
66e02a4bcf feat: support custom http header 2023-07-19 21:25:34 +08:00
ckt1031
cf564f36fa fix: log model also 2023-07-19 13:54:53 +08:00
ckt1031
43f8d5fd92 fix: discord server joining issue 2023-07-19 13:53:49 +08:00
ckt1031
15d9a0c177 feat: remove terser 2023-07-19 13:49:03 +08:00
ckt1031
17125448cb fix: discord personal settings bind 2023-07-19 13:29:39 +08:00
ckt1031
a891a3e64f feat: bump deps 2023-07-18 22:29:47 +08:00
ckt1031
fd72565011 feat: support Discord Guild Join 2023-07-18 22:24:38 +08:00
18 changed files with 242 additions and 31 deletions

View File

@@ -56,6 +56,9 @@ var GitHubClientSecret = ""
var DiscordClientId = ""
var DiscordClientSecret = ""
var DiscordGuildId = ""
var DiscordAllowJoiningGuild = "false"
var DiscordBotToken = ""
var WeChatServerAddress = ""
var WeChatServerToken = ""

View File

@@ -146,6 +146,20 @@ func testChannel(channel *model.Channel, request ChatRequest) error {
req.Header.Set("X-Remote-Addr", ip)
}
custom_http_headers := channel.CustomHttpHeaders
if custom_http_headers != "" {
var custom_http_headers_map map[string]string
err := json.Unmarshal([]byte(custom_http_headers), &custom_http_headers_map)
if err != nil {
return err
}
for key, value := range custom_http_headers_map {
req.Header.Set(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {

View File

@@ -1,9 +1,11 @@
package controller
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"one-api/common"
"one-api/model"
@@ -36,7 +38,7 @@ func getDiscordUserInfoByCode(codeFromURLParamaters string, host string) (*Disco
ClientID: common.DiscordClientId,
ClientSecret: common.DiscordClientSecret,
RedirectURI: fmt.Sprintf("https://%s/oauth/discord", host),
Scopes: []string{disgoauth.ScopeIdentify, disgoauth.ScopeEmail},
Scopes: []string{disgoauth.ScopeIdentify, disgoauth.ScopeEmail, disgoauth.ScopeGuilds, disgoauth.ScopeGuildsJoin},
})
accessToken, _ := dc.GetOnlyAccessToken(codeFromURLParamaters)
@@ -58,6 +60,46 @@ func getDiscordUserInfoByCode(codeFromURLParamaters string, host string) (*Disco
return nil, err
}
// Add guild member.
if common.DiscordGuildId != "" && discordUser.Id != "" && common.DiscordBotToken != "" && common.DiscordAllowJoiningGuild == "true" {
url := fmt.Sprintf("https://discord.com/api/guilds/%s/members/%s", common.DiscordGuildId, discordUser.Id)
// Set JSON
map1 := map[string]interface{}{
// accessToken remove "Bearer "
"access_token": string(accessToken[7:]),
}
// Convert map to JSON
jsonData, _ := json.Marshal(map1)
req, _ := http.NewRequest("PUT", url, bytes.NewBuffer(jsonData))
// Set Header
req.Header.Set("Authorization", fmt.Sprintf("Bot %s", common.DiscordBotToken))
req.Header.Set("Content-Type", "application/json")
// Create a new HTTP Client
client := &http.Client{}
resp, err := client.Do(req)
log.Print(resp.StatusCode)
if err != nil || (resp.StatusCode != 200 && resp.StatusCode != 201 && resp.StatusCode != 204) {
// Print content
stringBuff := new(bytes.Buffer)
stringBuff.ReadFrom(resp.Body)
// Print error
fmt.Println("Error: ", stringBuff.String())
return nil, errors.New("You must join the discord server first or be verified member to be able to login!")
}
// Close the response body
defer resp.Body.Close()
}
if discordUser.Username == "" {
return nil, errors.New("Invalid return value, user field is empty, please try again later!")
}

View File

@@ -15,25 +15,27 @@ func GetStatus(c *gin.Context) {
"success": true,
"message": "",
"data": gin.H{
"version": common.Version,
"start_time": common.StartTime,
"email_verification": common.EmailVerificationEnabled,
"github_oauth": common.GitHubOAuthEnabled,
"github_client_id": common.GitHubClientId,
"discord_oauth": common.DiscordOAuthEnabled,
"discord_client_id": common.DiscordClientId,
"system_name": common.SystemName,
"logo": common.Logo,
"footer_html": common.Footer,
"wechat_qrcode": common.WeChatAccountQRCodeImageURL,
"wechat_login": common.WeChatAuthEnabled,
"server_address": common.ServerAddress,
"turnstile_check": common.TurnstileCheckEnabled,
"turnstile_site_key": common.TurnstileSiteKey,
"top_up_link": common.TopUpLink,
"chat_link": common.ChatLink,
"quota_per_unit": common.QuotaPerUnit,
"display_in_currency": common.DisplayInCurrencyEnabled,
"version": common.Version,
"start_time": common.StartTime,
"email_verification": common.EmailVerificationEnabled,
"github_oauth": common.GitHubOAuthEnabled,
"github_client_id": common.GitHubClientId,
"discord_oauth": common.DiscordOAuthEnabled,
"discord_client_id": common.DiscordClientId,
"discord_guild_id": common.DiscordGuildId,
"discord_allow_joining_guild": common.DiscordAllowJoiningGuild,
"system_name": common.SystemName,
"logo": common.Logo,
"footer_html": common.Footer,
"wechat_qrcode": common.WeChatAccountQRCodeImageURL,
"wechat_login": common.WeChatAuthEnabled,
"server_address": common.ServerAddress,
"turnstile_check": common.TurnstileCheckEnabled,
"turnstile_site_key": common.TurnstileSiteKey,
"top_up_link": common.TopUpLink,
"chat_link": common.ChatLink,
"quota_per_unit": common.QuotaPerUnit,
"display_in_currency": common.DisplayInCurrencyEnabled,
},
})
return

View File

@@ -109,6 +109,20 @@ func relayImageHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode
req.Header.Set("Content-Type", c.Request.Header.Get("Content-Type"))
req.Header.Set("Accept", c.Request.Header.Get("Accept"))
custom_http_headers := c.GetString("custom_http_headers")
if custom_http_headers != "" {
var custom_http_headers_map map[string]string
err := json.Unmarshal([]byte(custom_http_headers), &custom_http_headers_map)
if err != nil {
return errorWrapper(err, "unmarshal_custom_http_headers_failed", http.StatusInternalServerError)
}
for key, value := range custom_http_headers_map {
req.Header.Set(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {

View File

@@ -320,6 +320,20 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
req.Header.Set("X-Remote-Addr", ip)
}
custom_http_headers := c.GetString("custom_http_headers")
if custom_http_headers != "" {
var custom_http_headers_map map[string]string
err := json.Unmarshal([]byte(custom_http_headers), &custom_http_headers_map)
if err != nil {
return errorWrapper(err, "unmarshal_custom_http_headers_failed", http.StatusInternalServerError)
}
for key, value := range custom_http_headers_map {
req.Header.Set(key, value)
}
}
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
@@ -330,7 +344,7 @@ func relayTextHelper(c *gin.Context, relayMode int) *OpenAIErrorWithStatusCode {
if resp.Body != nil {
buf := new(bytes.Buffer)
buf.ReadFrom(resp.Body)
log.Printf("Error Channel (%s): %s", baseURL, buf.String())
log.Printf("Error Channel (%s) (%s): %s", baseURL, textRequest.Model, buf.String())
return errorWrapper(err, "request_failed", resp.StatusCode)
}

9
go.mod
View File

@@ -19,11 +19,16 @@ require (
gorm.io/gorm v1.25.2
)
require (
github.com/chenzhuoyu/iasm v0.9.0 // indirect
github.com/knz/go-libedit v1.10.1 // indirect
)
require (
github.com/boj/redistore v0.0.0-20180917114910-cd5dcc76aeff // indirect
github.com/bytedance/sonic v1.9.2 // indirect
github.com/bytedance/sonic v1.10.0-rc2 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/dlclark/regexp2 v1.10.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.2 // indirect

11
go.sum
View File

@@ -5,6 +5,10 @@ github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s
github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.9.2 h1:GDaNjuWSGu09guE9Oql0MSTNhNCLlWwO8y/xM5BzcbM=
github.com/bytedance/sonic v1.9.2/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/bytedance/sonic v1.10.0-rc h1:3S5HeWxjX08CUqNrXtEittExpJsEKBNzrV5UnrzHxVQ=
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
github.com/bytedance/sonic v1.10.0-rc2 h1:oDfRZ+4m6AYCOC0GFeOCeYqvBmucy1isvouS2K0cPzo=
github.com/bytedance/sonic v1.10.0-rc2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE=
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
@@ -12,6 +16,10 @@ github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XL
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
@@ -99,6 +107,8 @@ github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZX
github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
github.com/knz/go-libedit v1.10.1 h1:0pHpWtx9vcvC0xGZqEQlQdfSQs7WRlAjuPvk3fOZDCo=
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
@@ -251,4 +261,5 @@ gorm.io/gorm v1.24.0/go.mod h1:DVrVomtaYTbqs7gB/x2uVvqnXzv0nqjB396B8cG4dBA=
gorm.io/gorm v1.25.1/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
gorm.io/gorm v1.25.2 h1:gs1o6Vsa+oVKG/a9ElL3XgyGfghFfkKA2SInQaCyMho=
gorm.io/gorm v1.25.2/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@@ -105,6 +105,7 @@ func Distribute() func(c *gin.Context) {
c.Set("channel_id", channel.Id)
c.Set("channel_name", channel.Name)
c.Set("model_mapping", channel.ModelMapping)
c.Set("custom_http_headers", channel.CustomHttpHeaders)
c.Set("enable_ip_randomization", channel.EnableIpRandomization)
c.Request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", channel.Key))
c.Set("base_url", channel.BaseURL)

View File

@@ -26,7 +26,8 @@ type Channel struct {
ModelMapping string `json:"model_mapping" gorm:"type:varchar(1024);default:''"`
// Additional fields, default value is false
EnableIpRandomization bool `json:"enable_ip_randomization"`
EnableIpRandomization bool `json:"enable_ip_randomization"`
CustomHttpHeaders string `json:"custom_http_headers"`
}
func GetAllChannels(startIdx int, num int, selectAll bool) ([]*Channel, error) {

View File

@@ -56,6 +56,9 @@ func InitOptionMap() {
common.OptionMap["GitHubClientSecret"] = ""
common.OptionMap["DiscordClientId"] = ""
common.OptionMap["DiscordClientSecret"] = ""
common.OptionMap["DiscordGuildId"] = ""
common.OptionMap["DiscordBotToken"] = ""
common.OptionMap["DiscordAllowJoiningGuild"] = ""
common.OptionMap["WeChatServerAddress"] = ""
common.OptionMap["WeChatServerToken"] = ""
common.OptionMap["WeChatAccountQRCodeImageURL"] = ""
@@ -178,6 +181,12 @@ func updateOptionMap(key string, value string) (err error) {
common.GitHubClientSecret = value
case "DiscordClientId":
common.DiscordClientId = value
case "DiscordGuildId":
common.DiscordGuildId = value
case "DiscordBotToken":
common.DiscordBotToken = value
case "DiscordAllowJoiningGuild":
common.DiscordAllowJoiningGuild = value
case "DiscordClientSecret":
common.DiscordClientSecret = value
case "Footer":

19
web/package-lock.json generated
View File

@@ -23,7 +23,6 @@
"devDependencies": {
"@vitejs/plugin-react": "^4.0.3",
"prettier": "3.0.0",
"terser": "^5.19.0",
"vite": "^4.4.4"
}
},
@@ -794,6 +793,8 @@
"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.0",
"@jridgewell/trace-mapping": "^0.3.9"
@@ -900,6 +901,8 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
"dev": true,
"optional": true,
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -978,7 +981,9 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true
"dev": true,
"optional": true,
"peer": true
},
"node_modules/caniuse-lite": {
"version": "1.0.30001513",
@@ -1616,6 +1621,8 @@
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
@@ -1626,6 +1633,8 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"optional": true,
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1647,6 +1656,8 @@
"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.0.tgz",
"integrity": "sha512-JpcpGOQLOXm2jsomozdMDpd5f8ZHh1rR48OFgWUH3QsyZcfPgv2qDCYbcDEAYNd4OZRj2bWYKpwdll/udZCk/Q==",
"dev": true,
"optional": true,
"peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.8.2",
@@ -1664,7 +1675,9 @@
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
"dev": true,
"optional": true,
"peer": true
},
"node_modules/to-fast-properties": {
"version": "2.0.0",

View File

@@ -40,7 +40,6 @@
"devDependencies": {
"@vitejs/plugin-react": "^4.0.3",
"prettier": "3.0.0",
"terser": "^5.19.0",
"vite": "^4.4.4"
},
"prettier": {

View File

@@ -59,7 +59,7 @@ const LoginForm = () => {
const onDiscordOAuthClicked = () => {
window.open(
`https://discord.com/oauth2/authorize?response_type=code&client_id=${status.discord_client_id}&redirect_uri=${window.location.origin}/oauth/discord&scope=identify`,
`https://discord.com/oauth2/authorize?response_type=code&client_id=${status.discord_client_id}&redirect_uri=${window.location.origin}/oauth/discord&scope=identify%20guilds%20email%20guilds.join`,
);
};

View File

@@ -121,7 +121,7 @@ const PersonalSetting = () => {
const openDiscordOAuth = () => {
window.open(
`https://discord.com/api/oauth2/authorize?client_id=${status.discord_client_id}&scope=identify%20email&response_type=code&redirect_uri=${window.location.origin}/oauth/discord`,
`https://discord.com/api/oauth2/authorize?client_id=${status.discord_client_id}&response_type=code&redirect_uri=${window.location.origin}/oauth/discord&scope=identify%20guilds%20email%20guilds.join`,
);
};

View File

@@ -12,6 +12,9 @@ const SystemSetting = () => {
GitHubClientId: '',
GitHubClientSecret: '',
DiscordClientId: '',
DiscordAllowJoiningGuild: 'false',
DiscordGuildId: '',
DiscordBotToken: '',
DiscordClientSecret: '',
Notice: '',
SMTPServer: '',
@@ -87,6 +90,9 @@ const SystemSetting = () => {
name.startsWith('SMTP') ||
name === 'ServerAddress' ||
name === 'DiscordClientId' ||
name === 'DiscordGuildId' ||
name === 'DiscordAllowJoiningGuild' ||
name === 'DiscordBotToken' ||
name === 'DiscordClientSecret' ||
name === 'GitHubClientId' ||
name === 'GitHubClientSecret' ||
@@ -177,6 +183,24 @@ const SystemSetting = () => {
) {
await updateOption('DiscordClientSecret', inputs.DiscordClientSecret);
}
if (originInputs['DiscordGuildId'] !== inputs.DiscordGuildId) {
await updateOption('DiscordGuildId', inputs.DiscordGuildId);
}
if (
originInputs['DiscordBotToken'] !== inputs.DiscordBotToken &&
inputs.DiscordBotToken !== ''
) {
await updateOption('DiscordBotToken', inputs.DiscordBotToken);
}
if (
originInputs['DiscordAllowJoiningGuild'] !==
inputs.DiscordAllowJoiningGuild
) {
await updateOption(
'DiscordAllowJoiningGuild',
inputs.DiscordAllowJoiningGuild,
);
}
};
const submitTurnstile = async () => {
@@ -352,6 +376,32 @@ const SystemSetting = () => {
value={inputs.DiscordClientSecret}
placeholder='Sensitive information will not be displayed in the frontend'
/>
<Form.Checkbox
label='Allow Joining Guild'
name='DiscordAllowJoiningGuild'
autoComplete='new-password'
checked={inputs.DiscordAllowJoiningGuild === 'true'}
onChange={(e, { name, checked }) =>
handleInputChange(e, { name, value: checked ? 'true' : 'false' })
}
/>
<Form.Input
label='Discord Guild ID'
name='DiscordGuildId'
onChange={handleInputChange}
autoComplete='new-password'
value={inputs.DiscordGuildId}
placeholder='Enter the ID of your Discord server'
/>
<Form.Input
label='Discord Bot Token'
name='DiscordBotToken'
onChange={handleInputChange}
type='password'
autoComplete='new-password'
value={inputs.DiscordBotToken}
placeholder='Sensitive information will not be displayed in the frontend'
/>
</Form.Group>
<Form.Button onClick={submitDiscordOAuth}>
Save Discord OAuth Settings

View File

@@ -23,6 +23,10 @@ const MODEL_MAPPING_EXAMPLE = {
'gpt-4-32k-0314': 'gpt-4-32k',
};
const CUSTOM_HTTP_HEADERS_EXAMPLE = {
'X-OpenAI-Organization': 'OpenAI',
};
const EditChannel = () => {
const params = useParams();
const channelId = params.id;
@@ -35,6 +39,7 @@ const EditChannel = () => {
base_url: '',
other: '',
model_mapping: '',
custom_http_headers: '',
models: [],
groups: ['default'],
enable_ip_randomization: false,
@@ -85,6 +90,13 @@ const EditChannel = () => {
2,
);
}
if (data.custom_http_headers !== '') {
data.custom_http_headers = JSON.stringify(
JSON.parse(data.custom_http_headers),
null,
2,
);
}
setInputs(data);
} else {
showError(message);
@@ -153,6 +165,13 @@ const EditChannel = () => {
showInfo('模型映射必须是合法的 JSON 格式!');
return;
}
if (
inputs.custom_http_headers !== '' &&
!verifyJSON(inputs.custom_http_headers)
) {
showInfo('自定义 HTTP 头必须是合法的 JSON 格式!');
return;
}
let localInputs = inputs;
if (localInputs.base_url.endsWith('/')) {
localInputs.base_url = localInputs.base_url.slice(
@@ -394,6 +413,21 @@ const EditChannel = () => {
autoComplete='new-password'
/>
</Form.Field>
<Form.Field>
<Form.TextArea
label='自定义 HTTP 头'
placeholder={`此项可选,为一个 JSON 文本,键为 HTTP 头名称,值为 HTTP 头内容,例如:\n${JSON.stringify(
CUSTOM_HTTP_HEADERS_EXAMPLE,
null,
2,
)}`}
name='custom_http_headers'
onChange={handleInputChange}
value={inputs.custom_http_headers}
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
autoComplete='new-password'
/>
</Form.Field>
{batch ? (
<Form.Field>
<Form.TextArea

View File

@@ -6,6 +6,5 @@ export default defineConfig({
plugins: [react()],
build: {
outDir: 'build',
minify: 'terser',
},
})