mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-05 16:23:43 +08:00
Compare commits
6 Commits
v0.6.10-al
...
v0.6.9
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36c8f4f15c | ||
|
|
45b51ea0ee | ||
|
|
7c8628bd95 | ||
|
|
6ab87f8a08 | ||
|
|
833fa7ad6f | ||
|
|
6eb0770a89 |
@@ -115,8 +115,8 @@ _✨ 通过标准的 OpenAI API 格式访问所有的大模型,开箱即用
|
||||
21. 支持 Cloudflare Turnstile 用户校验。
|
||||
22. 支持用户管理,支持**多种用户登录注册方式**:
|
||||
+ 邮箱登录注册(支持注册邮箱白名单)以及通过邮箱进行密码重置。
|
||||
+ 支持使用飞书进行授权登录。
|
||||
+ [GitHub 开放授权](https://github.com/settings/applications/new)。
|
||||
+ 支持[飞书授权登录](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/authen-v1/authorize/get)([这里有 One API 的实现细节阐述供参考](https://iamazing.cn/page/feishu-oauth-login))。
|
||||
+ 支持 [GitHub 授权登录](https://github.com/settings/applications/new)。
|
||||
+ 微信公众号授权(需要额外部署 [WeChat Server](https://github.com/songquanpeng/wechat-server))。
|
||||
23. 支持主题切换,设置环境变量 `THEME` 即可,默认为 `default`,欢迎 PR 更多主题,具体参考[此处](./web/README.md)。
|
||||
24. 配合 [Message Pusher](https://github.com/songquanpeng/message-pusher) 可将报警信息推送到多种 App 上。
|
||||
|
||||
@@ -20,4 +20,5 @@ const (
|
||||
BaseURL = "base_url"
|
||||
AvailableModels = "available_models"
|
||||
KeyRequestBody = "key_request_body"
|
||||
SystemPrompt = "system_prompt"
|
||||
)
|
||||
|
||||
@@ -40,7 +40,7 @@ func getLarkUserInfoByCode(code string) (*LarkUser, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
req, err := http.NewRequest("POST", "https://passport.feishu.cn/suite/passport/oauth/token", bytes.NewBuffer(jsonData))
|
||||
req, err := http.NewRequest("POST", "https://open.feishu.cn/open-apis/authen/v2/oauth/token", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@ func SetupContextForSelectedChannel(c *gin.Context, channel *model.Channel, mode
|
||||
c.Set(ctxkey.Channel, channel.Type)
|
||||
c.Set(ctxkey.ChannelId, channel.Id)
|
||||
c.Set(ctxkey.ChannelName, channel.Name)
|
||||
if channel.SystemPrompt != nil && *channel.SystemPrompt != "" {
|
||||
c.Set(ctxkey.SystemPrompt, *channel.SystemPrompt)
|
||||
}
|
||||
c.Set(ctxkey.ModelMapping, channel.GetModelMapping())
|
||||
c.Set(ctxkey.OriginalModel, modelName) // for retry
|
||||
c.Request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", channel.Key))
|
||||
|
||||
27
middleware/gzip.go
Normal file
27
middleware/gzip.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"compress/gzip"
|
||||
"github.com/gin-gonic/gin"
|
||||
"io"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GzipDecodeMiddleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if c.GetHeader("Content-Encoding") == "gzip" {
|
||||
gzipReader, err := gzip.NewReader(c.Request.Body)
|
||||
if err != nil {
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer gzipReader.Close()
|
||||
|
||||
// Replace the request body with the decompressed data
|
||||
c.Request.Body = io.NopCloser(gzipReader)
|
||||
}
|
||||
|
||||
// Continue processing the request
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ type Channel struct {
|
||||
ModelMapping *string `json:"model_mapping" gorm:"type:varchar(1024);default:''"`
|
||||
Priority *int64 `json:"priority" gorm:"bigint;default:0"`
|
||||
Config string `json:"config"`
|
||||
SystemPrompt *string `json:"system_prompt" gorm:"type:text"`
|
||||
}
|
||||
|
||||
type ChannelConfig struct {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package role
|
||||
|
||||
const (
|
||||
System = "system"
|
||||
Assistant = "assistant"
|
||||
)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/songquanpeng/one-api/relay/constant/role"
|
||||
"math"
|
||||
"net/http"
|
||||
"strings"
|
||||
@@ -90,7 +91,7 @@ func preConsumeQuota(ctx context.Context, textRequest *relaymodel.GeneralOpenAIR
|
||||
return preConsumedQuota, nil
|
||||
}
|
||||
|
||||
func postConsumeQuota(ctx context.Context, usage *relaymodel.Usage, meta *meta.Meta, textRequest *relaymodel.GeneralOpenAIRequest, ratio float64, preConsumedQuota int64, modelRatio float64, groupRatio float64) {
|
||||
func postConsumeQuota(ctx context.Context, usage *relaymodel.Usage, meta *meta.Meta, textRequest *relaymodel.GeneralOpenAIRequest, ratio float64, preConsumedQuota int64, modelRatio float64, groupRatio float64, systemPromptReset bool) {
|
||||
if usage == nil {
|
||||
logger.Error(ctx, "usage is nil, which is unexpected")
|
||||
return
|
||||
@@ -118,7 +119,11 @@ func postConsumeQuota(ctx context.Context, usage *relaymodel.Usage, meta *meta.M
|
||||
if err != nil {
|
||||
logger.Error(ctx, "error update user quota cache: "+err.Error())
|
||||
}
|
||||
logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f,补全倍率 %.2f", modelRatio, groupRatio, completionRatio)
|
||||
var extraLog string
|
||||
if systemPromptReset {
|
||||
extraLog = " (注意系统提示词已被重置)"
|
||||
}
|
||||
logContent := fmt.Sprintf("模型倍率 %.2f,分组倍率 %.2f,补全倍率 %.2f%s", modelRatio, groupRatio, completionRatio, extraLog)
|
||||
model.RecordConsumeLog(ctx, meta.UserId, meta.ChannelId, promptTokens, completionTokens, textRequest.Model, meta.TokenName, quota, logContent)
|
||||
model.UpdateUserUsedQuotaAndRequestCount(meta.UserId, quota)
|
||||
model.UpdateChannelUsedQuota(meta.ChannelId, quota)
|
||||
@@ -154,3 +159,23 @@ func isErrorHappened(meta *meta.Meta, resp *http.Response) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func setSystemPrompt(ctx context.Context, request *relaymodel.GeneralOpenAIRequest, prompt string) (reset bool) {
|
||||
if prompt == "" {
|
||||
return false
|
||||
}
|
||||
if len(request.Messages) == 0 {
|
||||
return false
|
||||
}
|
||||
if request.Messages[0].Role == role.System {
|
||||
request.Messages[0].Content = prompt
|
||||
logger.Infof(ctx, "rewrite system prompt")
|
||||
return true
|
||||
}
|
||||
request.Messages = append([]relaymodel.Message{{
|
||||
Role: role.System,
|
||||
Content: prompt,
|
||||
}}, request.Messages...)
|
||||
logger.Infof(ctx, "add system prompt")
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -36,6 +36,8 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
||||
meta.OriginModelName = textRequest.Model
|
||||
textRequest.Model, _ = getMappedModelName(textRequest.Model, meta.ModelMapping)
|
||||
meta.ActualModelName = textRequest.Model
|
||||
// set system prompt if not empty
|
||||
systemPromptReset := setSystemPrompt(ctx, textRequest, meta.SystemPrompt)
|
||||
// get model ratio & group ratio
|
||||
modelRatio := billingratio.GetModelRatio(textRequest.Model, meta.ChannelType)
|
||||
groupRatio := billingratio.GetGroupRatio(meta.Group)
|
||||
@@ -80,7 +82,7 @@ func RelayTextHelper(c *gin.Context) *model.ErrorWithStatusCode {
|
||||
return respErr
|
||||
}
|
||||
// post-consume quota
|
||||
go postConsumeQuota(ctx, usage, meta, textRequest, ratio, preConsumedQuota, modelRatio, groupRatio)
|
||||
go postConsumeQuota(ctx, usage, meta, textRequest, ratio, preConsumedQuota, modelRatio, groupRatio, systemPromptReset)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ type Meta struct {
|
||||
ActualModelName string
|
||||
RequestURLPath string
|
||||
PromptTokens int // only for DoResponse
|
||||
SystemPrompt string
|
||||
}
|
||||
|
||||
func GetByContext(c *gin.Context) *Meta {
|
||||
@@ -46,6 +47,7 @@ func GetByContext(c *gin.Context) *Meta {
|
||||
BaseURL: c.GetString(ctxkey.BaseURL),
|
||||
APIKey: strings.TrimPrefix(c.Request.Header.Get("Authorization"), "Bearer "),
|
||||
RequestURLPath: c.Request.URL.String(),
|
||||
SystemPrompt: c.GetString(ctxkey.SystemPrompt),
|
||||
}
|
||||
cfg, ok := c.Get(ctxkey.Config)
|
||||
if ok {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
func SetRelayRouter(router *gin.Engine) {
|
||||
router.Use(middleware.CORS())
|
||||
router.Use(middleware.GzipDecodeMiddleware())
|
||||
// https://platform.openai.com/docs/api-reference/introduction
|
||||
modelsRouter := router.Group("/v1/models")
|
||||
modelsRouter.Use(middleware.TokenAuth())
|
||||
|
||||
@@ -43,6 +43,7 @@ const EditChannel = (props) => {
|
||||
base_url: '',
|
||||
other: '',
|
||||
model_mapping: '',
|
||||
system_prompt: '',
|
||||
models: [],
|
||||
auto_ban: 1,
|
||||
groups: ['default']
|
||||
@@ -304,163 +305,163 @@ const EditChannel = (props) => {
|
||||
width={isMobile() ? '100%' : 600}
|
||||
>
|
||||
<Spin spinning={loading}>
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>类型:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
name='type'
|
||||
required
|
||||
optionList={CHANNEL_OPTIONS}
|
||||
value={inputs.type}
|
||||
onChange={value => handleInputChange('type', value)}
|
||||
style={{width: '50%'}}
|
||||
name='type'
|
||||
required
|
||||
optionList={CHANNEL_OPTIONS}
|
||||
value={inputs.type}
|
||||
onChange={value => handleInputChange('type', value)}
|
||||
style={{ width: '50%' }}
|
||||
/>
|
||||
{
|
||||
inputs.type === 3 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Banner type={"warning"} description={
|
||||
<>
|
||||
注意,<strong>模型部署名称必须和模型名称保持一致</strong>,因为 One API 会把请求体中的
|
||||
model
|
||||
参数替换为你的部署名称(模型名称中的点会被剔除),<a target='_blank'
|
||||
href='https://github.com/songquanpeng/one-api/issues/133?notification_referrer_id=NT_kwDOAmJSYrM2NjIwMzI3NDgyOjM5OTk4MDUw#issuecomment-1571602271'>图片演示</a>。
|
||||
</>
|
||||
}>
|
||||
</Banner>
|
||||
</div>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>AZURE_OPENAI_ENDPOINT:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='AZURE_OPENAI_ENDPOINT'
|
||||
name='azure_base_url'
|
||||
placeholder={'请输入 AZURE_OPENAI_ENDPOINT,例如:https://docs-test-001.openai.azure.com'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>默认 API 版本:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='默认 API 版本'
|
||||
name='azure_other'
|
||||
placeholder={'请输入默认 API 版本,例如:2024-03-01-preview,该配置可以被实际的请求查询参数所覆盖'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
inputs.type === 3 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Banner type={"warning"} description={
|
||||
<>
|
||||
注意,<strong>模型部署名称必须和模型名称保持一致</strong>,因为 One API 会把请求体中的
|
||||
model
|
||||
参数替换为你的部署名称(模型名称中的点会被剔除),<a target='_blank'
|
||||
href='https://github.com/songquanpeng/one-api/issues/133?notification_referrer_id=NT_kwDOAmJSYrM2NjIwMzI3NDgyOjM5OTk4MDUw#issuecomment-1571602271'>图片演示</a>。
|
||||
</>
|
||||
}>
|
||||
</Banner>
|
||||
</div>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>AZURE_OPENAI_ENDPOINT:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='AZURE_OPENAI_ENDPOINT'
|
||||
name='azure_base_url'
|
||||
placeholder={'请输入 AZURE_OPENAI_ENDPOINT,例如:https://docs-test-001.openai.azure.com'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>默认 API 版本:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='默认 API 版本'
|
||||
name='azure_other'
|
||||
placeholder={'请输入默认 API 版本,例如:2024-03-01-preview,该配置可以被实际的请求查询参数所覆盖'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type === 8 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>Base URL:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='base_url'
|
||||
placeholder={'请输入自定义渠道的 Base URL'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
inputs.type === 8 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>Base URL:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='base_url'
|
||||
placeholder={'请输入自定义渠道的 Base URL'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>名称:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
required
|
||||
name='name'
|
||||
placeholder={'请为渠道命名'}
|
||||
onChange={value => {
|
||||
handleInputChange('name', value)
|
||||
}}
|
||||
value={inputs.name}
|
||||
autoComplete='new-password'
|
||||
required
|
||||
name='name'
|
||||
placeholder={'请为渠道命名'}
|
||||
onChange={value => {
|
||||
handleInputChange('name', value)
|
||||
}}
|
||||
value={inputs.name}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>分组:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择可以使用该渠道的分组'}
|
||||
name='groups'
|
||||
required
|
||||
multiple
|
||||
selection
|
||||
allowAdditions
|
||||
additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'}
|
||||
onChange={value => {
|
||||
handleInputChange('groups', value)
|
||||
}}
|
||||
value={inputs.groups}
|
||||
autoComplete='new-password'
|
||||
optionList={groupOptions}
|
||||
placeholder={'请选择可以使用该渠道的分组'}
|
||||
name='groups'
|
||||
required
|
||||
multiple
|
||||
selection
|
||||
allowAdditions
|
||||
additionLabel={'请在系统设置页面编辑分组倍率以添加新的分组:'}
|
||||
onChange={value => {
|
||||
handleInputChange('groups', value)
|
||||
}}
|
||||
value={inputs.groups}
|
||||
autoComplete='new-password'
|
||||
optionList={groupOptions}
|
||||
/>
|
||||
{
|
||||
inputs.type === 18 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>模型版本:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='other'
|
||||
placeholder={'请输入星火大模型版本,注意是接口地址中的版本号,例如:v2.1'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
inputs.type === 18 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>模型版本:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='other'
|
||||
placeholder={'请输入星火大模型版本,注意是接口地址中的版本号,例如:v2.1'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type === 21 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>知识库 ID:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='知识库 ID'
|
||||
name='other'
|
||||
placeholder={'请输入知识库 ID,例如:123456'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
inputs.type === 21 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>知识库 ID:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='知识库 ID'
|
||||
name='other'
|
||||
placeholder={'请输入知识库 ID,例如:123456'}
|
||||
onChange={value => {
|
||||
handleInputChange('other', value)
|
||||
}}
|
||||
value={inputs.other}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>模型:</Typography.Text>
|
||||
</div>
|
||||
<Select
|
||||
placeholder={'请选择该渠道所支持的模型'}
|
||||
name='models'
|
||||
required
|
||||
multiple
|
||||
selection
|
||||
onChange={value => {
|
||||
handleInputChange('models', value)
|
||||
}}
|
||||
value={inputs.models}
|
||||
autoComplete='new-password'
|
||||
optionList={modelOptions}
|
||||
placeholder={'请选择该渠道所支持的模型'}
|
||||
name='models'
|
||||
required
|
||||
multiple
|
||||
selection
|
||||
onChange={value => {
|
||||
handleInputChange('models', value)
|
||||
}}
|
||||
value={inputs.models}
|
||||
autoComplete='new-password'
|
||||
optionList={modelOptions}
|
||||
/>
|
||||
<div style={{lineHeight: '40px', marginBottom: '12px'}}>
|
||||
<div style={{ lineHeight: '40px', marginBottom: '12px' }}>
|
||||
<Space>
|
||||
<Button type='primary' onClick={() => {
|
||||
handleInputChange('models', basicModels);
|
||||
@@ -473,28 +474,41 @@ const EditChannel = (props) => {
|
||||
}}>清除所有模型</Button>
|
||||
</Space>
|
||||
<Input
|
||||
addonAfter={
|
||||
<Button type='primary' onClick={addCustomModel}>填入</Button>
|
||||
}
|
||||
placeholder='输入自定义模型名称'
|
||||
value={customModel}
|
||||
onChange={(value) => {
|
||||
setCustomModel(value.trim());
|
||||
}}
|
||||
addonAfter={
|
||||
<Button type='primary' onClick={addCustomModel}>填入</Button>
|
||||
}
|
||||
placeholder='输入自定义模型名称'
|
||||
value={customModel}
|
||||
onChange={(value) => {
|
||||
setCustomModel(value.trim());
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>模型重定向:</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder={`此项可选,用于修改请求体中的模型名称,为一个 JSON 字符串,键为请求中模型名称,值为要替换的模型名称,例如:\n${JSON.stringify(MODEL_MAPPING_EXAMPLE, null, 2)}`}
|
||||
name='model_mapping'
|
||||
onChange={value => {
|
||||
handleInputChange('model_mapping', value)
|
||||
}}
|
||||
autosize
|
||||
value={inputs.model_mapping}
|
||||
autoComplete='new-password'
|
||||
placeholder={`此项可选,用于修改请求体中的模型名称,为一个 JSON 字符串,键为请求中模型名称,值为要替换的模型名称,例如:\n${JSON.stringify(MODEL_MAPPING_EXAMPLE, null, 2)}`}
|
||||
name='model_mapping'
|
||||
onChange={value => {
|
||||
handleInputChange('model_mapping', value)
|
||||
}}
|
||||
autosize
|
||||
value={inputs.model_mapping}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>系统提示词:</Typography.Text>
|
||||
</div>
|
||||
<TextArea
|
||||
placeholder={`此项可选,用于强制设置给定的系统提示词,请配合自定义模型 & 模型重定向使用,首先创建一个唯一的自定义模型名称并在上面填入,之后将该自定义模型重定向映射到该渠道一个原生支持的模型`}
|
||||
name='system_prompt'
|
||||
onChange={value => {
|
||||
handleInputChange('system_prompt', value)
|
||||
}}
|
||||
autosize
|
||||
value={inputs.system_prompt}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<Typography.Text style={{
|
||||
color: 'rgba(var(--semi-blue-5), 1)',
|
||||
@@ -507,116 +521,116 @@ const EditChannel = (props) => {
|
||||
}>
|
||||
填入模板
|
||||
</Typography.Text>
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>密钥:</Typography.Text>
|
||||
</div>
|
||||
{
|
||||
batch ?
|
||||
<TextArea
|
||||
label='密钥'
|
||||
name='key'
|
||||
required
|
||||
placeholder={'请输入密钥,一行一个'}
|
||||
onChange={value => {
|
||||
handleInputChange('key', value)
|
||||
}}
|
||||
value={inputs.key}
|
||||
style={{minHeight: 150, fontFamily: 'JetBrains Mono, Consolas'}}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
:
|
||||
<Input
|
||||
label='密钥'
|
||||
name='key'
|
||||
required
|
||||
placeholder={type2secretPrompt(inputs.type)}
|
||||
onChange={value => {
|
||||
handleInputChange('key', value)
|
||||
}}
|
||||
value={inputs.key}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
<TextArea
|
||||
label='密钥'
|
||||
name='key'
|
||||
required
|
||||
placeholder={'请输入密钥,一行一个'}
|
||||
onChange={value => {
|
||||
handleInputChange('key', value)
|
||||
}}
|
||||
value={inputs.key}
|
||||
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
:
|
||||
<Input
|
||||
label='密钥'
|
||||
name='key'
|
||||
required
|
||||
placeholder={type2secretPrompt(inputs.type)}
|
||||
onChange={value => {
|
||||
handleInputChange('key', value)
|
||||
}}
|
||||
value={inputs.key}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
}
|
||||
<div style={{marginTop: 10}}>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>组织:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='组织,可选,不填则为默认组织'
|
||||
name='openai_organization'
|
||||
placeholder='请输入组织org-xxx'
|
||||
onChange={value => {
|
||||
handleInputChange('openai_organization', value)
|
||||
}}
|
||||
value={inputs.openai_organization}
|
||||
label='组织,可选,不填则为默认组织'
|
||||
name='openai_organization'
|
||||
placeholder='请输入组织org-xxx'
|
||||
onChange={value => {
|
||||
handleInputChange('openai_organization', value)
|
||||
}}
|
||||
value={inputs.openai_organization}
|
||||
/>
|
||||
<div style={{marginTop: 10, display: 'flex'}}>
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
name='auto_ban'
|
||||
checked={autoBan}
|
||||
onChange={
|
||||
() => {
|
||||
setAutoBan(!autoBan);
|
||||
}
|
||||
}
|
||||
// onChange={handleInputChange}
|
||||
name='auto_ban'
|
||||
checked={autoBan}
|
||||
onChange={
|
||||
() => {
|
||||
setAutoBan(!autoBan);
|
||||
}
|
||||
}
|
||||
// onChange={handleInputChange}
|
||||
/>
|
||||
<Typography.Text
|
||||
strong>是否自动禁用(仅当自动禁用开启时有效),关闭后不会自动禁用该渠道:</Typography.Text>
|
||||
strong>是否自动禁用(仅当自动禁用开启时有效),关闭后不会自动禁用该渠道:</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
|
||||
{
|
||||
!isEdit && (
|
||||
<div style={{marginTop: 10, display: 'flex'}}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
checked={batch}
|
||||
label='批量创建'
|
||||
name='batch'
|
||||
onChange={() => setBatch(!batch)}
|
||||
/>
|
||||
<Typography.Text strong>批量创建</Typography.Text>
|
||||
</Space>
|
||||
!isEdit && (
|
||||
<div style={{ marginTop: 10, display: 'flex' }}>
|
||||
<Space>
|
||||
<Checkbox
|
||||
checked={batch}
|
||||
label='批量创建'
|
||||
name='batch'
|
||||
onChange={() => setBatch(!batch)}
|
||||
/>
|
||||
<Typography.Text strong>批量创建</Typography.Text>
|
||||
</Space>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type !== 3 && inputs.type !== 8 && inputs.type !== 22 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>代理:</Typography.Text>
|
||||
</div>
|
||||
)
|
||||
<Input
|
||||
label='代理'
|
||||
name='base_url'
|
||||
placeholder={'此项可选,用于通过代理站来进行 API 调用'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type !== 3 && inputs.type !== 8 && inputs.type !== 22 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>代理:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
label='代理'
|
||||
name='base_url'
|
||||
placeholder={'此项可选,用于通过代理站来进行 API 调用'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type === 22 && (
|
||||
<>
|
||||
<div style={{marginTop: 10}}>
|
||||
<Typography.Text strong>私有部署地址:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='base_url'
|
||||
placeholder={'请输入私有部署地址,格式为:https://fastgpt.run/api/openapi'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
inputs.type === 22 && (
|
||||
<>
|
||||
<div style={{ marginTop: 10 }}>
|
||||
<Typography.Text strong>私有部署地址:</Typography.Text>
|
||||
</div>
|
||||
<Input
|
||||
name='base_url'
|
||||
placeholder={'请输入私有部署地址,格式为:https://fastgpt.run/api/openapi'}
|
||||
onChange={value => {
|
||||
handleInputChange('base_url', value)
|
||||
}}
|
||||
value={inputs.base_url}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
</Spin>
|
||||
|
||||
@@ -95,7 +95,7 @@ export async function onLarkOAuthClicked(lark_client_id) {
|
||||
const state = await getOAuthState();
|
||||
if (!state) return;
|
||||
let redirect_uri = `${window.location.origin}/oauth/lark`;
|
||||
window.open(`https://open.feishu.cn/open-apis/authen/v1/index?redirect_uri=${redirect_uri}&app_id=${lark_client_id}&state=${state}`);
|
||||
window.open(`https://accounts.feishu.cn/open-apis/authen/v1/authorize?redirect_uri=${redirect_uri}&client_id=${lark_client_id}&state=${state}`);
|
||||
}
|
||||
|
||||
export async function onOidcClicked(auth_url, client_id, openInNewTab = false) {
|
||||
|
||||
@@ -595,6 +595,28 @@ const EditModal = ({ open, channelId, onCancel, onOk }) => {
|
||||
<FormHelperText id="helper-tex-channel-model_mapping-label"> {inputPrompt.model_mapping} </FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
<FormControl fullWidth error={Boolean(touched.system_prompt && errors.system_prompt)} sx={{ ...theme.typography.otherInput }}>
|
||||
{/* <InputLabel htmlFor="channel-model_mapping-label">{inputLabel.model_mapping}</InputLabel> */}
|
||||
<TextField
|
||||
multiline
|
||||
id="channel-system_prompt-label"
|
||||
label={inputLabel.system_prompt}
|
||||
value={values.system_prompt}
|
||||
name="system_prompt"
|
||||
onBlur={handleBlur}
|
||||
onChange={handleChange}
|
||||
aria-describedby="helper-text-channel-system_prompt-label"
|
||||
minRows={5}
|
||||
placeholder={inputPrompt.system_prompt}
|
||||
/>
|
||||
{touched.system_prompt && errors.system_prompt ? (
|
||||
<FormHelperText error id="helper-tex-channel-system_prompt-label">
|
||||
{errors.system_prompt}
|
||||
</FormHelperText>
|
||||
) : (
|
||||
<FormHelperText id="helper-tex-channel-system_prompt-label"> {inputPrompt.system_prompt} </FormHelperText>
|
||||
)}
|
||||
</FormControl>
|
||||
<DialogActions>
|
||||
<Button onClick={onCancel}>取消</Button>
|
||||
<Button disableElevation disabled={isSubmitting} type="submit" variant="contained" color="primary">
|
||||
|
||||
@@ -18,6 +18,7 @@ const defaultConfig = {
|
||||
other: '其他参数',
|
||||
models: '模型',
|
||||
model_mapping: '模型映射关系',
|
||||
system_prompt: '系统提示词',
|
||||
groups: '用户组',
|
||||
config: null
|
||||
},
|
||||
@@ -30,6 +31,7 @@ const defaultConfig = {
|
||||
models: '请选择该渠道所支持的模型',
|
||||
model_mapping:
|
||||
'请输入要修改的模型映射关系,格式为:api请求模型ID:实际转发给渠道的模型ID,使用JSON数组表示,例如:{"gpt-3.5": "gpt-35"}',
|
||||
system_prompt:"此项可选,用于强制设置给定的系统提示词,请配合自定义模型 & 模型重定向使用,首先创建一个唯一的自定义模型名称并在上面填入,之后将该自定义模型重定向映射到该渠道一个原生支持的模型此项可选,用于强制设置给定的系统提示词,请配合自定义模型 & 模型重定向使用,首先创建一个唯一的自定义模型名称并在上面填入,之后将该自定义模型重定向映射到该渠道一个原生支持的模型",
|
||||
groups: '请选择该渠道所支持的用户组',
|
||||
config: null
|
||||
},
|
||||
|
||||
0
web/build.sh
Normal file → Executable file
0
web/build.sh
Normal file → Executable file
@@ -43,6 +43,7 @@ const EditChannel = () => {
|
||||
base_url: '',
|
||||
other: '',
|
||||
model_mapping: '',
|
||||
system_prompt: '',
|
||||
models: [],
|
||||
groups: ['default']
|
||||
};
|
||||
@@ -425,7 +426,7 @@ const EditChannel = () => {
|
||||
)
|
||||
}
|
||||
{
|
||||
inputs.type !== 43 && (
|
||||
inputs.type !== 43 && (<>
|
||||
<Form.Field>
|
||||
<Form.TextArea
|
||||
label='模型重定向'
|
||||
@@ -437,6 +438,18 @@ const EditChannel = () => {
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</Form.Field>
|
||||
<Form.Field>
|
||||
<Form.TextArea
|
||||
label='系统提示词'
|
||||
placeholder={`此项可选,用于强制设置给定的系统提示词,请配合自定义模型 & 模型重定向使用,首先创建一个唯一的自定义模型名称并在上面填入,之后将该自定义模型重定向映射到该渠道一个原生支持的模型`}
|
||||
name='system_prompt'
|
||||
onChange={handleInputChange}
|
||||
value={inputs.system_prompt}
|
||||
style={{ minHeight: 150, fontFamily: 'JetBrains Mono, Consolas' }}
|
||||
autoComplete='new-password'
|
||||
/>
|
||||
</Form.Field>
|
||||
</>
|
||||
)
|
||||
}
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user