mirror of
https://github.com/coaidev/coai.git
synced 2025-05-19 13:00:14 +09:00
feat: support for channel configuration proxy (#101)
This commit is contained in:
parent
9323abb318
commit
e037276387
@ -42,6 +42,7 @@ var channelFactories = map[string]adaptercommon.FactoryCreator{
|
|||||||
|
|
||||||
func createChatRequest(conf globals.ChannelConfig, props *adaptercommon.ChatProps, hook globals.Hook) error {
|
func createChatRequest(conf globals.ChannelConfig, props *adaptercommon.ChatProps, hook globals.Hook) error {
|
||||||
props.Model = conf.GetModelReflect(props.OriginalModel)
|
props.Model = conf.GetModelReflect(props.OriginalModel)
|
||||||
|
props.Proxy = conf.GetProxy()
|
||||||
|
|
||||||
factoryType := conf.GetType()
|
factoryType := conf.GetType()
|
||||||
if factory, ok := channelFactories[factoryType]; ok {
|
if factory, ok := channelFactories[factoryType]; ok {
|
||||||
|
@ -66,6 +66,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
c.GetChatEndpoint(props),
|
c.GetChatEndpoint(props),
|
||||||
c.GetHeader(),
|
c.GetHeader(),
|
||||||
c.GetChatBody(props, false),
|
c.GetChatBody(props, false),
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
@ -108,7 +109,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
}
|
}
|
||||||
return callback(partial)
|
return callback(partial)
|
||||||
},
|
},
|
||||||
})
|
}, props.Proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if form := processChatErrorResponse(err.Body); form != nil {
|
if form := processChatErrorResponse(err.Body); form != nil {
|
||||||
|
@ -12,6 +12,7 @@ type ImageProps struct {
|
|||||||
Model string
|
Model string
|
||||||
Prompt string
|
Prompt string
|
||||||
Size ImageSize
|
Size ImageSize
|
||||||
|
Proxy globals.ProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) GetImageEndpoint(model string) string {
|
func (c *ChatInstance) GetImageEndpoint(model string) string {
|
||||||
@ -31,7 +32,7 @@ func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, error) {
|
|||||||
ImageSize512,
|
ImageSize512,
|
||||||
),
|
),
|
||||||
N: 1,
|
N: 1,
|
||||||
})
|
}, props.Proxy)
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
return "", fmt.Errorf("openai error: %s", err.Error())
|
return "", fmt.Errorf("openai error: %s", err.Error())
|
||||||
}
|
}
|
||||||
@ -51,6 +52,7 @@ func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (string, erro
|
|||||||
url, err := c.CreateImageRequest(ImageProps{
|
url, err := c.CreateImageRequest(ImageProps{
|
||||||
Model: props.Model,
|
Model: props.Model,
|
||||||
Prompt: c.GetLatestPrompt(props),
|
Prompt: c.GetLatestPrompt(props),
|
||||||
|
Proxy: props.Proxy,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "safety") {
|
if strings.Contains(err.Error(), "safety") {
|
||||||
|
@ -48,6 +48,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
c.GetChatEndpoint(),
|
c.GetChatEndpoint(),
|
||||||
c.GetHeader(),
|
c.GetHeader(),
|
||||||
c.GetChatBody(props, false),
|
c.GetChatBody(props, false),
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
@ -77,7 +78,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
}
|
}
|
||||||
return callback(partial)
|
return callback(partial)
|
||||||
},
|
},
|
||||||
})
|
}, props.Proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if form := processChatErrorResponse(err.Body); form != nil {
|
if form := processChatErrorResponse(err.Body); form != nil {
|
||||||
|
@ -11,18 +11,19 @@ import (
|
|||||||
const defaultTokens = 2500
|
const defaultTokens = 2500
|
||||||
|
|
||||||
func (c *ChatInstance) GetChatEndpoint() string {
|
func (c *ChatInstance) GetChatEndpoint() string {
|
||||||
return fmt.Sprintf("%s/v1/complete", c.GetEndpoint())
|
return fmt.Sprintf("%s/v1/messages", c.GetEndpoint())
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) GetChatHeaders() map[string]string {
|
func (c *ChatInstance) GetChatHeaders() map[string]string {
|
||||||
return map[string]string{
|
return map[string]string{
|
||||||
"content-type": "application/json",
|
"content-type": "application/json",
|
||||||
"accept": "application/json",
|
"anthropic-version": "2023-06-01",
|
||||||
"x-api-key": c.GetApiKey(),
|
"x-api-key": c.GetApiKey(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) ConvertMessage(message []globals.Message) string {
|
// ConvertCompletionMessage converts the completion message to anthropic complete format (deprecated)
|
||||||
|
func (c *ChatInstance) ConvertCompletionMessage(message []globals.Message) string {
|
||||||
mapper := map[string]string{
|
mapper := map[string]string{
|
||||||
globals.System: "Assistant",
|
globals.System: "Assistant",
|
||||||
globals.User: "Human",
|
globals.User: "Human",
|
||||||
@ -54,19 +55,19 @@ func (c *ChatInstance) GetTokens(props *adaptercommon.ChatProps) int {
|
|||||||
|
|
||||||
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) *ChatBody {
|
func (c *ChatInstance) GetChatBody(props *adaptercommon.ChatProps, stream bool) *ChatBody {
|
||||||
return &ChatBody{
|
return &ChatBody{
|
||||||
Prompt: c.ConvertMessage(props.Message),
|
Messages: props.Message,
|
||||||
MaxTokensToSample: c.GetTokens(props),
|
MaxTokens: c.GetTokens(props),
|
||||||
Model: props.Model,
|
Model: props.Model,
|
||||||
Stream: stream,
|
Stream: stream,
|
||||||
Temperature: props.Temperature,
|
Temperature: props.Temperature,
|
||||||
TopP: props.TopP,
|
TopP: props.TopP,
|
||||||
TopK: props.TopK,
|
TopK: props.TopK,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateChatRequest is the request for anthropic claude
|
// CreateChatRequest is the request for anthropic claude
|
||||||
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
|
func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string, error) {
|
||||||
data, err := utils.Post(c.GetChatEndpoint(), c.GetChatHeaders(), c.GetChatBody(props, false))
|
data, err := utils.Post(c.GetChatEndpoint(), c.GetChatHeaders(), c.GetChatBody(props, false), props.Proxy)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("claude error: %s", err.Error())
|
return "", fmt.Errorf("claude error: %s", err.Error())
|
||||||
}
|
}
|
||||||
@ -126,5 +127,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, h
|
|||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
},
|
||||||
|
props.Proxy,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,16 @@
|
|||||||
package claude
|
package claude
|
||||||
|
|
||||||
|
import "chat/globals"
|
||||||
|
|
||||||
// ChatBody is the request body for anthropic claude
|
// ChatBody is the request body for anthropic claude
|
||||||
type ChatBody struct {
|
type ChatBody struct {
|
||||||
Prompt string `json:"prompt"`
|
Messages []globals.Message `json:"messages"`
|
||||||
MaxTokensToSample int `json:"max_tokens_to_sample"`
|
MaxTokens int `json:"max_tokens"`
|
||||||
Model string `json:"model"`
|
Model string `json:"model"`
|
||||||
Stream bool `json:"stream"`
|
Stream bool `json:"stream"`
|
||||||
Temperature *float32 `json:"temperature,omitempty"`
|
Temperature *float32 `json:"temperature,omitempty"`
|
||||||
TopP *float32 `json:"top_p,omitempty"`
|
TopP *float32 `json:"top_p,omitempty"`
|
||||||
TopK *int `json:"top_k,omitempty"`
|
TopK *int `json:"top_k,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChatResponse is the native http request and stream response for anthropic claude
|
// ChatResponse is the native http request and stream response for anthropic claude
|
||||||
|
@ -9,6 +9,8 @@ type RequestProps struct {
|
|||||||
MaxRetries *int
|
MaxRetries *int
|
||||||
Current int
|
Current int
|
||||||
Group string
|
Group string
|
||||||
|
|
||||||
|
Proxy globals.ProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type ChatProps struct {
|
type ChatProps struct {
|
||||||
|
@ -127,5 +127,6 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package midjourney
|
package midjourney
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"chat/globals"
|
||||||
"chat/utils"
|
"chat/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
@ -29,11 +30,12 @@ func (c *ChatInstance) GetChangeRequest(action string, task string, index *int)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) CreateImagineRequest(prompt string) (*CommonResponse, error) {
|
func (c *ChatInstance) CreateImagineRequest(proxy globals.ProxyConfig, prompt string) (*CommonResponse, error) {
|
||||||
content, err := utils.PostRaw(
|
content, err := utils.PostRaw(
|
||||||
c.GetImagineEndpoint(),
|
c.GetImagineEndpoint(),
|
||||||
c.GetMidjourneyHeaders(),
|
c.GetMidjourneyHeaders(),
|
||||||
c.GetImagineRequest(prompt),
|
c.GetImagineRequest(prompt),
|
||||||
|
proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,11 +49,12 @@ func (c *ChatInstance) CreateImagineRequest(prompt string) (*CommonResponse, err
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) CreateChangeRequest(action string, task string, index *int) (*CommonResponse, error) {
|
func (c *ChatInstance) CreateChangeRequest(proxy globals.ProxyConfig, action string, task string, index *int) (*CommonResponse, error) {
|
||||||
res, err := utils.Post(
|
res, err := utils.Post(
|
||||||
c.GetChangeEndpoint(),
|
c.GetChangeEndpoint(),
|
||||||
c.GetMidjourneyHeaders(),
|
c.GetMidjourneyHeaders(),
|
||||||
c.GetChangeRequest(action, task, index),
|
c.GetChangeRequest(action, task, index),
|
||||||
|
proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -95,7 +95,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
|
|
||||||
var begin bool
|
var begin bool
|
||||||
|
|
||||||
form, err := c.CreateStreamTask(action, prompt, func(form *StorageForm, progress int) error {
|
form, err := c.CreateStreamTask(props, action, prompt, func(form *StorageForm, progress int) error {
|
||||||
if progress == -1 {
|
if progress == -1 {
|
||||||
// ping event
|
// ping event
|
||||||
return callback(&globals.Chunk{Content: ""})
|
return callback(&globals.Chunk{Content: ""})
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
package midjourney
|
package midjourney
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
adaptercommon "chat/adapter/common"
|
||||||
|
"chat/globals"
|
||||||
"chat/utils"
|
"chat/utils"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
@ -66,21 +68,21 @@ func (c *ChatInstance) ExtractCommand(input string) (task string, index *int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) CreateRequest(action string, prompt string) (*CommonResponse, error) {
|
func (c *ChatInstance) CreateRequest(proxy globals.ProxyConfig, action string, prompt string) (*CommonResponse, error) {
|
||||||
switch action {
|
switch action {
|
||||||
case ImagineCommand:
|
case ImagineCommand:
|
||||||
return c.CreateImagineRequest(prompt)
|
return c.CreateImagineRequest(proxy, prompt)
|
||||||
case VariationCommand, UpscaleCommand, RerollCommand:
|
case VariationCommand, UpscaleCommand, RerollCommand:
|
||||||
task, index := c.ExtractCommand(prompt)
|
task, index := c.ExtractCommand(prompt)
|
||||||
|
|
||||||
return c.CreateChangeRequest(c.GetAction(action), task, index)
|
return c.CreateChangeRequest(proxy, c.GetAction(action), task, index)
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("unknown action: %s", action)
|
return nil, fmt.Errorf("unknown action: %s", action)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) CreateStreamTask(action string, prompt string, hook func(form *StorageForm, progress int) error) (*StorageForm, error) {
|
func (c *ChatInstance) CreateStreamTask(props *adaptercommon.ChatProps, action string, prompt string, hook func(form *StorageForm, progress int) error) (*StorageForm, error) {
|
||||||
res, err := c.CreateRequest(action, prompt)
|
res, err := c.CreateRequest(props.Proxy, action, prompt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
c.GetChatEndpoint(props),
|
c.GetChatEndpoint(props),
|
||||||
c.GetHeader(),
|
c.GetHeader(),
|
||||||
c.GetChatBody(props, false),
|
c.GetChatBody(props, false),
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
@ -120,7 +121,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
}
|
}
|
||||||
return callback(partial)
|
return callback(partial)
|
||||||
},
|
},
|
||||||
})
|
}, props.Proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if form := processChatErrorResponse(err.Body); form != nil {
|
if form := processChatErrorResponse(err.Body); form != nil {
|
||||||
|
@ -12,6 +12,7 @@ type ImageProps struct {
|
|||||||
Model string
|
Model string
|
||||||
Prompt string
|
Prompt string
|
||||||
Size ImageSize
|
Size ImageSize
|
||||||
|
Proxy globals.ProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChatInstance) GetImageEndpoint() string {
|
func (c *ChatInstance) GetImageEndpoint() string {
|
||||||
@ -31,7 +32,7 @@ func (c *ChatInstance) CreateImageRequest(props ImageProps) (string, error) {
|
|||||||
ImageSize512,
|
ImageSize512,
|
||||||
),
|
),
|
||||||
N: 1,
|
N: 1,
|
||||||
})
|
}, props.Proxy)
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
return "", fmt.Errorf(err.Error())
|
return "", fmt.Errorf(err.Error())
|
||||||
}
|
}
|
||||||
@ -51,6 +52,7 @@ func (c *ChatInstance) CreateImage(props *adaptercommon.ChatProps) (string, erro
|
|||||||
original, err := c.CreateImageRequest(ImageProps{
|
original, err := c.CreateImageRequest(ImageProps{
|
||||||
Model: props.Model,
|
Model: props.Model,
|
||||||
Prompt: c.GetLatestPrompt(props),
|
Prompt: c.GetLatestPrompt(props),
|
||||||
|
Proxy: props.Proxy,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if strings.Contains(err.Error(), "safety") {
|
if strings.Contains(err.Error(), "safety") {
|
||||||
|
@ -93,7 +93,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
if props.Model == globals.ChatBison001 {
|
if props.Model == globals.ChatBison001 {
|
||||||
data, err := utils.Post(uri, map[string]string{
|
data, err := utils.Post(uri, map[string]string{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}, c.GetPalm2ChatBody(props))
|
}, c.GetPalm2ChatBody(props), props.Proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("palm2 error: %s", err.Error())
|
return "", fmt.Errorf("palm2 error: %s", err.Error())
|
||||||
@ -103,7 +103,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
|
|
||||||
data, err := utils.Post(uri, map[string]string{
|
data, err := utils.Post(uri, map[string]string{
|
||||||
"Content-Type": "application/json",
|
"Content-Type": "application/json",
|
||||||
}, c.GetGeminiChatBody(props))
|
}, c.GetGeminiChatBody(props), props.Proxy)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("gemini error: %s", err.Error())
|
return "", fmt.Errorf("gemini error: %s", err.Error())
|
||||||
|
@ -51,6 +51,7 @@ func (c *ChatInstance) CreateChatRequest(props *adaptercommon.ChatProps) (string
|
|||||||
c.GetChatEndpoint(),
|
c.GetChatEndpoint(),
|
||||||
c.GetHeader(),
|
c.GetHeader(),
|
||||||
c.GetChatBody(props, false),
|
c.GetChatBody(props, false),
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil || res == nil {
|
if err != nil || res == nil {
|
||||||
@ -100,6 +101,7 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, c
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -69,5 +69,6 @@ func (c *ChatInstance) CreateStreamChatRequest(props *adaptercommon.ChatProps, h
|
|||||||
data = strings.TrimPrefix(data, "data:")
|
data = strings.TrimPrefix(data, "data:")
|
||||||
return hook(&globals.Chunk{Content: data})
|
return hook(&globals.Chunk{Content: data})
|
||||||
},
|
},
|
||||||
|
props.Proxy,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,24 @@ export type Channel = {
|
|||||||
mapper: string;
|
mapper: string;
|
||||||
state: boolean;
|
state: boolean;
|
||||||
group?: string[];
|
group?: string[];
|
||||||
|
proxy?: {
|
||||||
|
proxy: string;
|
||||||
|
proxy_type: number;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export enum proxyType {
|
||||||
|
NoneProxy = 0,
|
||||||
|
HttpProxy = 1,
|
||||||
|
HttpsProxy = 2,
|
||||||
|
Socks5Proxy = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProxyTypes: Record<number, string> = {
|
||||||
|
[proxyType.NoneProxy]: "None Proxy",
|
||||||
|
[proxyType.HttpProxy]: "HTTP Proxy",
|
||||||
|
[proxyType.HttpsProxy]: "HTTPS Proxy",
|
||||||
|
[proxyType.Socks5Proxy]: "SOCKS5 Proxy",
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ChannelInfo = {
|
export type ChannelInfo = {
|
||||||
@ -133,7 +151,16 @@ export const ChannelInfos: Record<string, ChannelInfo> = {
|
|||||||
claude: {
|
claude: {
|
||||||
endpoint: "https://api.anthropic.com",
|
endpoint: "https://api.anthropic.com",
|
||||||
format: "<x-api-key>",
|
format: "<x-api-key>",
|
||||||
models: ["claude-instant-1", "claude-2", "claude-2.1"],
|
description:
|
||||||
|
"> Anthropic Claude 密钥格式为 **x-api-key**,Anthropic 对请求 IP 地域有限制,可能出现 **Request not allowed** 的错误,请尝试更换 IP 或者使用代理。\n",
|
||||||
|
models: [
|
||||||
|
"claude-instant-1.2",
|
||||||
|
"claude-2",
|
||||||
|
"claude-2.1",
|
||||||
|
"claude-3-opus-20240229",
|
||||||
|
"claude-3-sonnet-20240229",
|
||||||
|
"claude-3-haiku-20240307",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
slack: {
|
slack: {
|
||||||
endpoint: "your-channel",
|
endpoint: "your-channel",
|
||||||
|
@ -40,6 +40,10 @@ export const modelColorMapper: Record<string, string> = {
|
|||||||
"claude-2": "orange-400",
|
"claude-2": "orange-400",
|
||||||
"claude-2.1": "orange-400",
|
"claude-2.1": "orange-400",
|
||||||
"claude-2-100k": "orange-400",
|
"claude-2-100k": "orange-400",
|
||||||
|
"claude-instant-1.2": "orange-400",
|
||||||
|
"claude-3-opus-20240229": "orange-400",
|
||||||
|
"claude-3-sonnet-20240229": "orange-400",
|
||||||
|
"claude-3-haiku-20240307": "orange-400",
|
||||||
|
|
||||||
"spark-desk-v1.5": "blue-400",
|
"spark-desk-v1.5": "blue-400",
|
||||||
"spark-desk-v2": "blue-400",
|
"spark-desk-v2": "blue-400",
|
||||||
|
@ -88,6 +88,7 @@ export const pricing: PricingDataset = [
|
|||||||
"claude-1.2",
|
"claude-1.2",
|
||||||
"claude-1.3",
|
"claude-1.3",
|
||||||
"claude-instant",
|
"claude-instant",
|
||||||
|
"claude-instant-1.2",
|
||||||
"claude-slack",
|
"claude-slack",
|
||||||
],
|
],
|
||||||
input: 0.0008,
|
input: 0.0008,
|
||||||
|
@ -91,7 +91,7 @@ strong {
|
|||||||
|
|
||||||
.flex-dialog {
|
.flex-dialog {
|
||||||
border-radius: var(--radius) !important;
|
border-radius: var(--radius) !important;
|
||||||
max-height: calc(95vh - 2rem) !important;
|
max-height: calc(95% - 2rem) !important;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
@ -128,7 +128,7 @@ strong {
|
|||||||
|
|
||||||
.fixed-dialog {
|
.fixed-dialog {
|
||||||
border-radius: var(--radius) !important;
|
border-radius: var(--radius) !important;
|
||||||
max-height: calc(95vh - 2rem) !important;
|
max-height: calc(95% - 2rem) !important;
|
||||||
min-height: 60vh;
|
min-height: 60vh;
|
||||||
overflow-x: hidden;
|
overflow-x: hidden;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
|
@ -237,6 +237,7 @@
|
|||||||
border: 1px solid var(--assistant-border);
|
border: 1px solid var(--assistant-border);
|
||||||
border-radius: var(--radius);
|
border-radius: var(--radius);
|
||||||
margin: 0.25rem 0;
|
margin: 0.25rem 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
.grow {
|
.grow {
|
||||||
min-width: 0.75rem;
|
min-width: 0.75rem;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
.share-table {
|
.share-table {
|
||||||
max-width: 85vw;
|
width: 100%;
|
||||||
height: max-content;
|
height: max-content;
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,10 @@ const initialState: Channel = {
|
|||||||
mapper: "",
|
mapper: "",
|
||||||
state: true,
|
state: true,
|
||||||
group: [],
|
group: [],
|
||||||
|
proxy: {
|
||||||
|
proxy: "",
|
||||||
|
proxy_type: 0,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function reducer(state: Channel, action: any): Channel {
|
function reducer(state: Channel, action: any): Channel {
|
||||||
@ -77,6 +81,22 @@ function reducer(state: Channel, action: any): Channel {
|
|||||||
};
|
};
|
||||||
case "set-group":
|
case "set-group":
|
||||||
return { ...state, group: action.value };
|
return { ...state, group: action.value };
|
||||||
|
case "set-proxy":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
proxy: {
|
||||||
|
proxy: action.value as string,
|
||||||
|
proxy_type: state?.proxy?.proxy_type || 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
case "set-proxy-type":
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
proxy: {
|
||||||
|
proxy: state?.proxy?.proxy || "",
|
||||||
|
proxy_type: action.value as number,
|
||||||
|
},
|
||||||
|
};
|
||||||
case "set":
|
case "set":
|
||||||
return { ...state, ...action.value };
|
return { ...state, ...action.value };
|
||||||
default:
|
default:
|
||||||
|
@ -13,9 +13,11 @@ import {
|
|||||||
channelGroups,
|
channelGroups,
|
||||||
ChannelTypes,
|
ChannelTypes,
|
||||||
getChannelInfo,
|
getChannelInfo,
|
||||||
|
proxyType,
|
||||||
|
ProxyTypes,
|
||||||
} from "@/admin/channel.ts";
|
} from "@/admin/channel.ts";
|
||||||
import { CommonResponse, toastState } from "@/api/common.ts";
|
import { CommonResponse, toastState } from "@/api/common.ts";
|
||||||
import { Textarea } from "@/components/ui/textarea.tsx";
|
import { FlexibleTextarea, Textarea } from "@/components/ui/textarea.tsx";
|
||||||
import { NumberInput } from "@/components/ui/number-input.tsx";
|
import { NumberInput } from "@/components/ui/number-input.tsx";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { useTranslation } from "react-i18next";
|
import { useTranslation } from "react-i18next";
|
||||||
@ -44,6 +46,7 @@ import { useEffectAsync } from "@/utils/hook.ts";
|
|||||||
import Paragraph, {
|
import Paragraph, {
|
||||||
ParagraphDescription,
|
ParagraphDescription,
|
||||||
ParagraphItem,
|
ParagraphItem,
|
||||||
|
ParagraphSpace,
|
||||||
} from "@/components/Paragraph.tsx";
|
} from "@/components/Paragraph.tsx";
|
||||||
import { MultiCombobox } from "@/components/ui/multi-combobox.tsx";
|
import { MultiCombobox } from "@/components/ui/multi-combobox.tsx";
|
||||||
import { useChannelModels } from "@/admin/hook.tsx";
|
import { useChannelModels } from "@/admin/hook.tsx";
|
||||||
@ -116,6 +119,14 @@ function handler(data: Channel): Channel {
|
|||||||
data.group = data.group
|
data.group = data.group
|
||||||
? data.group.filter((group) => group.trim() !== "")
|
? data.group.filter((group) => group.trim() !== "")
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
if (
|
||||||
|
data.proxy &&
|
||||||
|
data.proxy.proxy.trim() === "" &&
|
||||||
|
data.proxy.proxy_type !== 0
|
||||||
|
) {
|
||||||
|
data.proxy.proxy_type = 0;
|
||||||
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,7 +372,8 @@ function ChannelEditor({
|
|||||||
{t("admin.channels.mapper")}
|
{t("admin.channels.mapper")}
|
||||||
<Tips content={t("admin.channels.mapper-tip")} />
|
<Tips content={t("admin.channels.mapper-tip")} />
|
||||||
</div>
|
</div>
|
||||||
<Textarea
|
<FlexibleTextarea
|
||||||
|
rows={5}
|
||||||
value={edit.mapper}
|
value={edit.mapper}
|
||||||
placeholder={t("admin.channels.mapper-placeholder")}
|
placeholder={t("admin.channels.mapper-placeholder")}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
@ -394,6 +406,56 @@ function ChannelEditor({
|
|||||||
<ParagraphDescription>
|
<ParagraphDescription>
|
||||||
{t("admin.channels.group-desc")}
|
{t("admin.channels.group-desc")}
|
||||||
</ParagraphDescription>
|
</ParagraphDescription>
|
||||||
|
<ParagraphSpace />
|
||||||
|
<ParagraphItem>
|
||||||
|
<div className={`channel-row column-layout`}>
|
||||||
|
<div className={`channel-content`}>
|
||||||
|
{t("admin.channels.proxy-type")}
|
||||||
|
</div>
|
||||||
|
<Select
|
||||||
|
value={(edit.proxy?.proxy_type || 0).toString()}
|
||||||
|
onValueChange={(value: string) =>
|
||||||
|
dispatch({ type: "set-proxy-type", value: parseInt(value) })
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<SelectTrigger>
|
||||||
|
<SelectValue />
|
||||||
|
</SelectTrigger>
|
||||||
|
<SelectContent>
|
||||||
|
<SelectGroup>
|
||||||
|
<SelectItem value={"0"}>
|
||||||
|
{ProxyTypes[proxyType.NoneProxy]}
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={"1"}>
|
||||||
|
{ProxyTypes[proxyType.HttpProxy]}
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={"2"}>
|
||||||
|
{ProxyTypes[proxyType.HttpsProxy]}
|
||||||
|
</SelectItem>
|
||||||
|
<SelectItem value={"3"}>
|
||||||
|
{ProxyTypes[proxyType.Socks5Proxy]}
|
||||||
|
</SelectItem>
|
||||||
|
</SelectGroup>
|
||||||
|
</SelectContent>
|
||||||
|
</Select>
|
||||||
|
</div>
|
||||||
|
</ParagraphItem>
|
||||||
|
<ParagraphItem>
|
||||||
|
<div className={`channel-content`}>
|
||||||
|
{t("admin.channels.proxy-endpoint")}
|
||||||
|
</div>
|
||||||
|
<Input
|
||||||
|
value={edit.proxy?.proxy || ""}
|
||||||
|
placeholder={t("admin.channels.proxy-endpoint-placeholder")}
|
||||||
|
onChange={(e) =>
|
||||||
|
dispatch({ type: "set-proxy", value: e.target.value })
|
||||||
|
}
|
||||||
|
disabled={edit.proxy?.proxy_type === 0}
|
||||||
|
/>
|
||||||
|
</ParagraphItem>
|
||||||
|
<ParagraphDescription>
|
||||||
|
{t("admin.channels.proxy-desc")}
|
||||||
|
</ParagraphDescription>
|
||||||
</Paragraph>
|
</Paragraph>
|
||||||
</div>
|
</div>
|
||||||
<div className={`mt-4 flex flex-row w-full h-max pr-2 items-center`}>
|
<div className={`mt-4 flex flex-row w-full h-max pr-2 items-center`}>
|
||||||
|
@ -100,6 +100,7 @@ function SyncDialog({ dispatch, open, setOpen }: SyncDialogProps) {
|
|||||||
mapper: "",
|
mapper: "",
|
||||||
state: true,
|
state: true,
|
||||||
group: [],
|
group: [],
|
||||||
|
proxy: { proxy: "", proxy_type: 0 },
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch({ type: "set", value: data });
|
dispatch({ type: "set", value: data });
|
||||||
|
@ -32,7 +32,7 @@ function QuotaExceededForm({
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`flex flex-col items-center w-[40vw] max-w-[320px] py-2`}>
|
<div className={`flex flex-col items-center min-w-[40vw] p-2`}>
|
||||||
<img src={appLogo} alt={""} className={`w-16 h-16 m-6 inline-block`} />
|
<img src={appLogo} alt={""} className={`w-16 h-16 m-6 inline-block`} />
|
||||||
<div
|
<div
|
||||||
className={`prompt-row flex flex-row w-full items-center justify-center px-4 py-2`}
|
className={`prompt-row flex flex-row w-full items-center justify-center px-4 py-2`}
|
||||||
|
@ -31,12 +31,12 @@ export interface FlexibleTextareaProps extends TextareaProps {
|
|||||||
const FlexibleTextarea = React.forwardRef<
|
const FlexibleTextarea = React.forwardRef<
|
||||||
HTMLTextAreaElement,
|
HTMLTextAreaElement,
|
||||||
FlexibleTextareaProps
|
FlexibleTextareaProps
|
||||||
>(({ rows = 1, className, ...props }, ref) => {
|
>(({ rows = 1, minRows, className, ...props }, ref) => {
|
||||||
const lines = useMemo(() => {
|
const lines = useMemo(() => {
|
||||||
const value = props.value?.toString() || "";
|
const value = props.value?.toString() || "";
|
||||||
const count = value.split("\n").length + 1;
|
const count = value.split("\n").length + 1;
|
||||||
return Math.max(rows, count);
|
return Math.max(rows, count, minRows || 1);
|
||||||
}, [props.value]);
|
}, [props.value, rows, minRows]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Textarea
|
<Textarea
|
||||||
|
@ -14,7 +14,6 @@ import {
|
|||||||
Dialog,
|
Dialog,
|
||||||
DialogContent,
|
DialogContent,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogFooter,
|
|
||||||
DialogHeader,
|
DialogHeader,
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
} from "@/components/ui/dialog.tsx";
|
} from "@/components/ui/dialog.tsx";
|
||||||
@ -26,7 +25,7 @@ import {
|
|||||||
TableHeader,
|
TableHeader,
|
||||||
TableRow,
|
TableRow,
|
||||||
} from "@/components/ui/table.tsx";
|
} from "@/components/ui/table.tsx";
|
||||||
import { closeDialog, setDialog } from "@/store/sharing.ts";
|
import { setDialog } from "@/store/sharing.ts";
|
||||||
import { Button } from "@/components/ui/button.tsx";
|
import { Button } from "@/components/ui/button.tsx";
|
||||||
import { useMemo } from "react";
|
import { useMemo } from "react";
|
||||||
import { Eye, MoreHorizontal, Trash2 } from "lucide-react";
|
import { Eye, MoreHorizontal, Trash2 } from "lucide-react";
|
||||||
@ -60,7 +59,9 @@ function ShareTable({ data }: ShareTableProps) {
|
|||||||
<TableHeader>
|
<TableHeader>
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>ID</TableHead>
|
<TableHead>ID</TableHead>
|
||||||
<TableHead>{t("share.name")}</TableHead>
|
<TableHead className={`whitespace-nowrap`}>
|
||||||
|
{t("share.name")}
|
||||||
|
</TableHead>
|
||||||
<TableHead>{t("share.time")}</TableHead>
|
<TableHead>{t("share.time")}</TableHead>
|
||||||
<TableHead>{t("share.action")}</TableHead>
|
<TableHead>{t("share.action")}</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@ -69,7 +70,7 @@ function ShareTable({ data }: ShareTableProps) {
|
|||||||
{data.map((row, idx) => (
|
{data.map((row, idx) => (
|
||||||
<TableRow key={idx}>
|
<TableRow key={idx}>
|
||||||
<TableCell>{row.conversation_id}</TableCell>
|
<TableCell>{row.conversation_id}</TableCell>
|
||||||
<TableCell>{row.name}</TableCell>
|
<TableCell className={`whitespace-nowrap`}>{row.name}</TableCell>
|
||||||
<TableCell className={`whitespace-nowrap`}>{time[idx]}</TableCell>
|
<TableCell className={`whitespace-nowrap`}>{time[idx]}</TableCell>
|
||||||
<TableCell>
|
<TableCell>
|
||||||
<DropdownMenu>
|
<DropdownMenu>
|
||||||
@ -146,11 +147,6 @@ function ShareManagementDialog() {
|
|||||||
</DialogDescription>
|
</DialogDescription>
|
||||||
)}
|
)}
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
<DialogFooter>
|
|
||||||
<Button variant={`outline`} onClick={() => dispatch(closeDialog())}>
|
|
||||||
{t("close")}
|
|
||||||
</Button>
|
|
||||||
</DialogFooter>
|
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
@ -629,7 +629,11 @@
|
|||||||
"standard": "标准版订阅用户",
|
"standard": "标准版订阅用户",
|
||||||
"pro": "专业版订阅用户",
|
"pro": "专业版订阅用户",
|
||||||
"admin": "管理员用户"
|
"admin": "管理员用户"
|
||||||
}
|
},
|
||||||
|
"proxy-type": "代理类型",
|
||||||
|
"proxy-endpoint": "代理地址",
|
||||||
|
"proxy-endpoint-placeholder": "请输入正向代理地址,如:socks5://example.com:1080",
|
||||||
|
"proxy-desc": "正向代理,支持 HTTP/HTTPS/SOCKS5 代理 (反向代理请填写接入点, 非特殊情况无需设置正向代理)"
|
||||||
},
|
},
|
||||||
"charge": {
|
"charge": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
@ -457,7 +457,11 @@
|
|||||||
"sync-success": "Sync successfully.",
|
"sync-success": "Sync successfully.",
|
||||||
"sync-success-prompt": "{{length}} models were added from upstream synchronization.",
|
"sync-success-prompt": "{{length}} models were added from upstream synchronization.",
|
||||||
"upstream-endpoint-placeholder": "Please enter the upstream OpenAI address, e.g. https://api.openai.com",
|
"upstream-endpoint-placeholder": "Please enter the upstream OpenAI address, e.g. https://api.openai.com",
|
||||||
"sync-secret-placeholder": "Please enter API key for upstream channel"
|
"sync-secret-placeholder": "Please enter API key for upstream channel",
|
||||||
|
"proxy-type": "Delegate Type",
|
||||||
|
"proxy-endpoint": "proxy address",
|
||||||
|
"proxy-endpoint-placeholder": "Please enter forward proxy address, ex: socks5://example.com: 1080",
|
||||||
|
"proxy-desc": "Forward proxy, supports HTTP/HTTPS/SOCKS5 proxy (reverse proxy please fill in the access point, no need to set forward proxy in non-special cases)"
|
||||||
},
|
},
|
||||||
"charge": {
|
"charge": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
@ -457,7 +457,11 @@
|
|||||||
"sync-success": "同期成功",
|
"sync-success": "同期成功",
|
||||||
"sync-success-prompt": "{{length}}モデルがアップストリーム同期から追加されました。",
|
"sync-success-prompt": "{{length}}モデルがアップストリーム同期から追加されました。",
|
||||||
"upstream-endpoint-placeholder": "上流のOpenAIアドレスを入力してください。例: https://api.openai.com",
|
"upstream-endpoint-placeholder": "上流のOpenAIアドレスを入力してください。例: https://api.openai.com",
|
||||||
"sync-secret-placeholder": "アップストリームチャネルのAPIキーを入力してください"
|
"sync-secret-placeholder": "アップストリームチャネルのAPIキーを入力してください",
|
||||||
|
"proxy-type": "プロキシのタイプ",
|
||||||
|
"proxy-endpoint": "プロキシアドレス",
|
||||||
|
"proxy-endpoint-placeholder": "転送プロキシアドレスを入力してください。例: socks 5 :// example.com: 1080",
|
||||||
|
"proxy-desc": "フォワードプロキシ、HTTP/HTTPS/SOCKS 5プロキシをサポート(リバースプロキシはアクセスポイントに記入してください。特別な場合以外はフォワードプロキシを設定する必要はありません)"
|
||||||
},
|
},
|
||||||
"charge": {
|
"charge": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
@ -457,7 +457,11 @@
|
|||||||
"sync-success": "Успешная синхронизация",
|
"sync-success": "Успешная синхронизация",
|
||||||
"sync-success-prompt": "{{length}} модели были добавлены из синхронизации восходящего потока.",
|
"sync-success-prompt": "{{length}} модели были добавлены из синхронизации восходящего потока.",
|
||||||
"upstream-endpoint-placeholder": "Введите вышестоящий адрес OpenAI, например, https://api.openai.com",
|
"upstream-endpoint-placeholder": "Введите вышестоящий адрес OpenAI, например, https://api.openai.com",
|
||||||
"sync-secret-placeholder": "Пожалуйста, введите ключ API для восходящего канала"
|
"sync-secret-placeholder": "Пожалуйста, введите ключ API для восходящего канала",
|
||||||
|
"proxy-type": "Тип прокси- сервера",
|
||||||
|
"proxy-endpoint": "Адрес прокси-сервера",
|
||||||
|
"proxy-endpoint-placeholder": "Введите адрес прямого прокси-сервера, например: socks5://example.com: 1080",
|
||||||
|
"proxy-desc": "Прямой прокси-сервер, поддерживает HTTP/HTTPS/Socks5 прокси-сервер (обратный прокси-сервер, пожалуйста, заполните точку доступа, нет необходимости устанавливать прокси-сервер в неспециальных случаях)"
|
||||||
},
|
},
|
||||||
"charge": {
|
"charge": {
|
||||||
"id": "ID",
|
"id": "ID",
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package channel
|
package channel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"chat/globals"
|
||||||
"chat/utils"
|
"chat/utils"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
@ -174,6 +175,10 @@ func (c *Channel) GetGroup() []string {
|
|||||||
return c.Group
|
return c.Group
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Channel) GetProxy() globals.ProxyConfig {
|
||||||
|
return c.Proxy
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Channel) IsHitGroup(group string) bool {
|
func (c *Channel) IsHitGroup(group string) bool {
|
||||||
if len(c.GetGroup()) == 0 {
|
if len(c.GetGroup()) == 0 {
|
||||||
return true
|
return true
|
||||||
|
@ -1,22 +1,27 @@
|
|||||||
package channel
|
package channel
|
||||||
|
|
||||||
|
import (
|
||||||
|
"chat/globals"
|
||||||
|
)
|
||||||
|
|
||||||
type Channel struct {
|
type Channel struct {
|
||||||
Id int `json:"id" mapstructure:"id"`
|
Id int `json:"id" mapstructure:"id"`
|
||||||
Name string `json:"name" mapstructure:"name"`
|
Name string `json:"name" mapstructure:"name"`
|
||||||
Type string `json:"type" mapstructure:"type"`
|
Type string `json:"type" mapstructure:"type"`
|
||||||
Priority int `json:"priority" mapstructure:"priority"`
|
Priority int `json:"priority" mapstructure:"priority"`
|
||||||
Weight int `json:"weight" mapstructure:"weight"`
|
Weight int `json:"weight" mapstructure:"weight"`
|
||||||
Models []string `json:"models" mapstructure:"models"`
|
Models []string `json:"models" mapstructure:"models"`
|
||||||
Retry int `json:"retry" mapstructure:"retry"`
|
Retry int `json:"retry" mapstructure:"retry"`
|
||||||
Secret string `json:"secret" mapstructure:"secret"`
|
Secret string `json:"secret" mapstructure:"secret"`
|
||||||
Endpoint string `json:"endpoint" mapstructure:"endpoint"`
|
Endpoint string `json:"endpoint" mapstructure:"endpoint"`
|
||||||
Mapper string `json:"mapper" mapstructure:"mapper"`
|
Mapper string `json:"mapper" mapstructure:"mapper"`
|
||||||
State bool `json:"state" mapstructure:"state"`
|
State bool `json:"state" mapstructure:"state"`
|
||||||
Group []string `json:"group" mapstructure:"group"`
|
Group []string `json:"group" mapstructure:"group"`
|
||||||
Reflect *map[string]string `json:"-"`
|
Proxy globals.ProxyConfig `json:"proxy" mapstructure:"proxy"`
|
||||||
HitModels *[]string `json:"-"`
|
Reflect *map[string]string `json:"-"`
|
||||||
ExcludeModels *[]string `json:"-"`
|
HitModels *[]string `json:"-"`
|
||||||
CurrentSecret *string `json:"-"`
|
ExcludeModels *[]string `json:"-"`
|
||||||
|
CurrentSecret *string `json:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Sequence []*Channel
|
type Sequence []*Channel
|
||||||
|
@ -41,3 +41,10 @@ const (
|
|||||||
ProType = "pro" // pro subscription
|
ProType = "pro" // pro subscription
|
||||||
AdminType = "admin"
|
AdminType = "admin"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
NoneProxyType = iota
|
||||||
|
HttpProxyType
|
||||||
|
HttpsProxyType
|
||||||
|
Socks5ProxyType
|
||||||
|
)
|
||||||
|
@ -11,6 +11,7 @@ type ChannelConfig interface {
|
|||||||
GetEndpoint() string
|
GetEndpoint() string
|
||||||
ProcessError(err error) error
|
ProcessError(err error) error
|
||||||
GetId() int
|
GetId() int
|
||||||
|
GetProxy() ProxyConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthLike interface {
|
type AuthLike interface {
|
||||||
|
@ -45,3 +45,8 @@ type ListModelsItem struct {
|
|||||||
Created int64 `json:"created"`
|
Created int64 `json:"created"`
|
||||||
OwnedBy string `json:"owned_by"`
|
OwnedBy string `json:"owned_by"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ProxyConfig struct {
|
||||||
|
ProxyType int `json:"proxy_type" mapstructure:"proxytype"`
|
||||||
|
Proxy string `json:"proxy" mapstructure:"proxy"`
|
||||||
|
}
|
||||||
|
75
utils/net.go
75
utils/net.go
@ -3,11 +3,15 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"chat/globals"
|
"chat/globals"
|
||||||
|
"context"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/goccy/go-json"
|
"github.com/goccy/go-json"
|
||||||
|
"golang.org/x/net/proxy"
|
||||||
"io"
|
"io"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -15,13 +19,52 @@ import (
|
|||||||
|
|
||||||
var maxTimeout = 30 * time.Minute
|
var maxTimeout = 30 * time.Minute
|
||||||
|
|
||||||
func newClient() *http.Client {
|
func newClient(c []globals.ProxyConfig) *http.Client {
|
||||||
return &http.Client{
|
client := &http.Client{
|
||||||
Timeout: maxTimeout,
|
Timeout: maxTimeout,
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c) == 0 {
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
config := c[0]
|
||||||
|
if config.ProxyType == globals.NoneProxyType {
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
if config.ProxyType == globals.HttpProxyType || config.ProxyType == globals.HttpsProxyType {
|
||||||
|
proxyUrl, err := url.Parse(config.Proxy)
|
||||||
|
if err != nil {
|
||||||
|
globals.Warn(fmt.Sprintf("failed to parse proxy url: %s", err))
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
client.Transport = &http.Transport{
|
||||||
|
Proxy: http.ProxyURL(proxyUrl),
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
} else if config.ProxyType == globals.Socks5ProxyType {
|
||||||
|
dialer, err := proxy.SOCKS5("tcp", config.Proxy, nil, proxy.Direct)
|
||||||
|
if err != nil {
|
||||||
|
globals.Warn(fmt.Sprintf("failed to create socks5 proxy: %s", err))
|
||||||
|
return client
|
||||||
|
}
|
||||||
|
|
||||||
|
dialContext := func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||||
|
return dialer.Dial(network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
client.Transport = &http.Transport{
|
||||||
|
DialContext: dialContext,
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
globals.Debug(fmt.Sprintf("[proxy] configured proxy: %s", config.Proxy))
|
||||||
|
return client
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillHeaders(req *http.Request, headers map[string]string) {
|
func fillHeaders(req *http.Request, headers map[string]string) {
|
||||||
@ -30,14 +73,14 @@ func fillHeaders(req *http.Request, headers map[string]string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Http(uri string, method string, ptr interface{}, headers map[string]string, body io.Reader) (err error) {
|
func Http(uri string, method string, ptr interface{}, headers map[string]string, body io.Reader, config []globals.ProxyConfig) (err error) {
|
||||||
req, err := http.NewRequest(method, uri, body)
|
req, err := http.NewRequest(method, uri, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
fillHeaders(req, headers)
|
fillHeaders(req, headers)
|
||||||
|
|
||||||
client := newClient()
|
client := newClient(config)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -51,14 +94,14 @@ func Http(uri string, method string, ptr interface{}, headers map[string]string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func HttpRaw(uri string, method string, headers map[string]string, body io.Reader) (data []byte, err error) {
|
func HttpRaw(uri string, method string, headers map[string]string, body io.Reader, config []globals.ProxyConfig) (data []byte, err error) {
|
||||||
req, err := http.NewRequest(method, uri, body)
|
req, err := http.NewRequest(method, uri, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fillHeaders(req, headers)
|
fillHeaders(req, headers)
|
||||||
|
|
||||||
client := newClient()
|
client := newClient(config)
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -72,26 +115,26 @@ func HttpRaw(uri string, method string, headers map[string]string, body io.Reade
|
|||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Get(uri string, headers map[string]string) (data interface{}, err error) {
|
func Get(uri string, headers map[string]string, config ...globals.ProxyConfig) (data interface{}, err error) {
|
||||||
err = Http(uri, http.MethodGet, &data, headers, nil)
|
err = Http(uri, http.MethodGet, &data, headers, nil, config)
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetRaw(uri string, headers map[string]string) (data string, err error) {
|
func GetRaw(uri string, headers map[string]string, config ...globals.ProxyConfig) (data string, err error) {
|
||||||
buffer, err := HttpRaw(uri, http.MethodGet, headers, nil)
|
buffer, err := HttpRaw(uri, http.MethodGet, headers, nil, config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return string(buffer), nil
|
return string(buffer), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Post(uri string, headers map[string]string, body interface{}) (data interface{}, err error) {
|
func Post(uri string, headers map[string]string, body interface{}, config ...globals.ProxyConfig) (data interface{}, err error) {
|
||||||
err = Http(uri, http.MethodPost, &data, headers, ConvertBody(body))
|
err = Http(uri, http.MethodPost, &data, headers, ConvertBody(body), config)
|
||||||
return data, err
|
return data, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostRaw(uri string, headers map[string]string, body interface{}) (data string, err error) {
|
func PostRaw(uri string, headers map[string]string, body interface{}, config ...globals.ProxyConfig) (data string, err error) {
|
||||||
buffer, err := HttpRaw(uri, http.MethodPost, headers, ConvertBody(body))
|
buffer, err := HttpRaw(uri, http.MethodPost, headers, ConvertBody(body), config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@ -105,7 +148,7 @@ func ConvertBody(body interface{}) (form io.Reader) {
|
|||||||
return form
|
return form
|
||||||
}
|
}
|
||||||
|
|
||||||
func EventSource(method string, uri string, headers map[string]string, body interface{}, callback func(string) error) error {
|
func EventSource(method string, uri string, headers map[string]string, body interface{}, callback func(string) error, config ...globals.ProxyConfig) error {
|
||||||
// panic recovery
|
// panic recovery
|
||||||
defer func() {
|
defer func() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
@ -116,7 +159,7 @@ func EventSource(method string, uri string, headers map[string]string, body inte
|
|||||||
|
|
||||||
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
|
||||||
|
|
||||||
client := newClient()
|
client := newClient(config)
|
||||||
req, err := http.NewRequest(method, uri, ConvertBody(body))
|
req, err := http.NewRequest(method, uri, ConvertBody(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -36,7 +36,7 @@ func getErrorBody(resp *http.Response) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func EventScanner(props *EventScannerProps) *EventScannerError {
|
func EventScanner(props *EventScannerProps, config ...globals.ProxyConfig) *EventScannerError {
|
||||||
// panic recovery
|
// panic recovery
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -45,7 +45,7 @@ func EventScanner(props *EventScannerProps) *EventScannerError {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
client := newClient()
|
client := newClient(config)
|
||||||
req, err := http.NewRequest(props.Method, props.Uri, ConvertBody(props.Body))
|
req, err := http.NewRequest(props.Method, props.Uri, ConvertBody(props.Body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &EventScannerError{Error: err}
|
return &EventScannerError{Error: err}
|
||||||
|
Loading…
Reference in New Issue
Block a user