添加完整项目文件
包含Go API项目的所有源代码、配置文件、Docker配置、文档和前端资源 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
21
types/channel_error.go
Normal file
21
types/channel_error.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package types
|
||||
|
||||
type ChannelError struct {
|
||||
ChannelId int `json:"channel_id"`
|
||||
ChannelType int `json:"channel_type"`
|
||||
ChannelName string `json:"channel_name"`
|
||||
IsMultiKey bool `json:"is_multi_key"`
|
||||
AutoBan bool `json:"auto_ban"`
|
||||
UsingKey string `json:"using_key"`
|
||||
}
|
||||
|
||||
func NewChannelError(channelId int, channelType int, channelName string, isMultiKey bool, usingKey string, autoBan bool) *ChannelError {
|
||||
return &ChannelError{
|
||||
ChannelId: channelId,
|
||||
ChannelType: channelType,
|
||||
ChannelName: channelName,
|
||||
IsMultiKey: isMultiKey,
|
||||
AutoBan: autoBan,
|
||||
UsingKey: usingKey,
|
||||
}
|
||||
}
|
||||
210
types/error.go
Normal file
210
types/error.go
Normal file
@@ -0,0 +1,210 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type OpenAIError struct {
|
||||
Message string `json:"message"`
|
||||
Type string `json:"type"`
|
||||
Param string `json:"param"`
|
||||
Code any `json:"code"`
|
||||
}
|
||||
|
||||
type ClaudeError struct {
|
||||
Message string `json:"message,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
type ErrorType string
|
||||
|
||||
const (
|
||||
ErrorTypeNewAPIError ErrorType = "new_api_error"
|
||||
ErrorTypeOpenAIError ErrorType = "openai_error"
|
||||
ErrorTypeClaudeError ErrorType = "claude_error"
|
||||
ErrorTypeMidjourneyError ErrorType = "midjourney_error"
|
||||
ErrorTypeGeminiError ErrorType = "gemini_error"
|
||||
ErrorTypeRerankError ErrorType = "rerank_error"
|
||||
)
|
||||
|
||||
type ErrorCode string
|
||||
|
||||
const (
|
||||
ErrorCodeInvalidRequest ErrorCode = "invalid_request"
|
||||
ErrorCodeSensitiveWordsDetected ErrorCode = "sensitive_words_detected"
|
||||
|
||||
// new api error
|
||||
ErrorCodeCountTokenFailed ErrorCode = "count_token_failed"
|
||||
ErrorCodeModelPriceError ErrorCode = "model_price_error"
|
||||
ErrorCodeInvalidApiType ErrorCode = "invalid_api_type"
|
||||
ErrorCodeJsonMarshalFailed ErrorCode = "json_marshal_failed"
|
||||
ErrorCodeDoRequestFailed ErrorCode = "do_request_failed"
|
||||
ErrorCodeGetChannelFailed ErrorCode = "get_channel_failed"
|
||||
|
||||
// channel error
|
||||
ErrorCodeChannelNoAvailableKey ErrorCode = "channel:no_available_key"
|
||||
ErrorCodeChannelParamOverrideInvalid ErrorCode = "channel:param_override_invalid"
|
||||
ErrorCodeChannelModelMappedError ErrorCode = "channel:model_mapped_error"
|
||||
ErrorCodeChannelAwsClientError ErrorCode = "channel:aws_client_error"
|
||||
ErrorCodeChannelInvalidKey ErrorCode = "channel:invalid_key"
|
||||
ErrorCodeChannelResponseTimeExceeded ErrorCode = "channel:response_time_exceeded"
|
||||
|
||||
// client request error
|
||||
ErrorCodeReadRequestBodyFailed ErrorCode = "read_request_body_failed"
|
||||
ErrorCodeConvertRequestFailed ErrorCode = "convert_request_failed"
|
||||
ErrorCodeAccessDenied ErrorCode = "access_denied"
|
||||
|
||||
// response error
|
||||
ErrorCodeReadResponseBodyFailed ErrorCode = "read_response_body_failed"
|
||||
ErrorCodeBadResponseStatusCode ErrorCode = "bad_response_status_code"
|
||||
ErrorCodeBadResponse ErrorCode = "bad_response"
|
||||
ErrorCodeBadResponseBody ErrorCode = "bad_response_body"
|
||||
|
||||
// sql error
|
||||
ErrorCodeQueryDataError ErrorCode = "query_data_error"
|
||||
ErrorCodeUpdateDataError ErrorCode = "update_data_error"
|
||||
|
||||
// quota error
|
||||
ErrorCodeInsufficientUserQuota ErrorCode = "insufficient_user_quota"
|
||||
ErrorCodePreConsumeTokenQuotaFailed ErrorCode = "pre_consume_token_quota_failed"
|
||||
)
|
||||
|
||||
type NewAPIError struct {
|
||||
Err error
|
||||
RelayError any
|
||||
ErrorType ErrorType
|
||||
errorCode ErrorCode
|
||||
StatusCode int
|
||||
}
|
||||
|
||||
func (e *NewAPIError) GetErrorCode() ErrorCode {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
return e.errorCode
|
||||
}
|
||||
|
||||
func (e *NewAPIError) Error() string {
|
||||
if e == nil {
|
||||
return ""
|
||||
}
|
||||
if e.Err == nil {
|
||||
// fallback message when underlying error is missing
|
||||
return string(e.errorCode)
|
||||
}
|
||||
return e.Err.Error()
|
||||
}
|
||||
|
||||
func (e *NewAPIError) SetMessage(message string) {
|
||||
e.Err = errors.New(message)
|
||||
}
|
||||
|
||||
func (e *NewAPIError) ToOpenAIError() OpenAIError {
|
||||
switch e.ErrorType {
|
||||
case ErrorTypeOpenAIError:
|
||||
return e.RelayError.(OpenAIError)
|
||||
case ErrorTypeClaudeError:
|
||||
claudeError := e.RelayError.(ClaudeError)
|
||||
return OpenAIError{
|
||||
Message: e.Error(),
|
||||
Type: claudeError.Type,
|
||||
Param: "",
|
||||
Code: e.errorCode,
|
||||
}
|
||||
default:
|
||||
return OpenAIError{
|
||||
Message: e.Error(),
|
||||
Type: string(e.ErrorType),
|
||||
Param: "",
|
||||
Code: e.errorCode,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *NewAPIError) ToClaudeError() ClaudeError {
|
||||
switch e.ErrorType {
|
||||
case ErrorTypeOpenAIError:
|
||||
openAIError := e.RelayError.(OpenAIError)
|
||||
return ClaudeError{
|
||||
Message: e.Error(),
|
||||
Type: fmt.Sprintf("%v", openAIError.Code),
|
||||
}
|
||||
case ErrorTypeClaudeError:
|
||||
return e.RelayError.(ClaudeError)
|
||||
default:
|
||||
return ClaudeError{
|
||||
Message: e.Error(),
|
||||
Type: string(e.ErrorType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewError(err error, errorCode ErrorCode) *NewAPIError {
|
||||
return &NewAPIError{
|
||||
Err: err,
|
||||
RelayError: nil,
|
||||
ErrorType: ErrorTypeNewAPIError,
|
||||
StatusCode: http.StatusInternalServerError,
|
||||
errorCode: errorCode,
|
||||
}
|
||||
}
|
||||
|
||||
func NewOpenAIError(err error, errorCode ErrorCode, statusCode int) *NewAPIError {
|
||||
openaiError := OpenAIError{
|
||||
Message: err.Error(),
|
||||
Type: string(errorCode),
|
||||
}
|
||||
return WithOpenAIError(openaiError, statusCode)
|
||||
}
|
||||
|
||||
func NewErrorWithStatusCode(err error, errorCode ErrorCode, statusCode int) *NewAPIError {
|
||||
return &NewAPIError{
|
||||
Err: err,
|
||||
RelayError: nil,
|
||||
ErrorType: ErrorTypeNewAPIError,
|
||||
StatusCode: statusCode,
|
||||
errorCode: errorCode,
|
||||
}
|
||||
}
|
||||
|
||||
func WithOpenAIError(openAIError OpenAIError, statusCode int) *NewAPIError {
|
||||
code, ok := openAIError.Code.(string)
|
||||
if !ok {
|
||||
code = fmt.Sprintf("%v", openAIError.Code)
|
||||
}
|
||||
return &NewAPIError{
|
||||
RelayError: openAIError,
|
||||
ErrorType: ErrorTypeOpenAIError,
|
||||
StatusCode: statusCode,
|
||||
Err: errors.New(openAIError.Message),
|
||||
errorCode: ErrorCode(code),
|
||||
}
|
||||
}
|
||||
|
||||
func WithClaudeError(claudeError ClaudeError, statusCode int) *NewAPIError {
|
||||
return &NewAPIError{
|
||||
RelayError: claudeError,
|
||||
ErrorType: ErrorTypeClaudeError,
|
||||
StatusCode: statusCode,
|
||||
Err: errors.New(claudeError.Message),
|
||||
errorCode: ErrorCode(claudeError.Type),
|
||||
}
|
||||
}
|
||||
|
||||
func IsChannelError(err *NewAPIError) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
return strings.HasPrefix(string(err.errorCode), "channel:")
|
||||
}
|
||||
|
||||
func IsLocalError(err *NewAPIError) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return err.ErrorType == ErrorTypeNewAPIError
|
||||
}
|
||||
42
types/set.go
Normal file
42
types/set.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package types
|
||||
|
||||
type Set[T comparable] struct {
|
||||
items map[T]struct{}
|
||||
}
|
||||
|
||||
// NewSet 创建并返回一个新的 Set
|
||||
func NewSet[T comparable]() *Set[T] {
|
||||
return &Set[T]{
|
||||
items: make(map[T]struct{}),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Set[T]) Add(item T) {
|
||||
s.items[item] = struct{}{}
|
||||
}
|
||||
|
||||
// Remove 从 Set 中移除一个元素
|
||||
func (s *Set[T]) Remove(item T) {
|
||||
delete(s.items, item)
|
||||
}
|
||||
|
||||
// Contains 检查 Set 是否包含某个元素
|
||||
func (s *Set[T]) Contains(item T) bool {
|
||||
_, exists := s.items[item]
|
||||
return exists
|
||||
}
|
||||
|
||||
// Len 返回 Set 中元素的数量
|
||||
func (s *Set[T]) Len() int {
|
||||
return len(s.items)
|
||||
}
|
||||
|
||||
// Items 返回 Set 中所有元素组成的切片
|
||||
// 注意:由于 map 的无序性,返回的切片元素顺序是随机的
|
||||
func (s *Set[T]) Items() []T {
|
||||
items := make([]T, 0, s.Len())
|
||||
for item := range s.items {
|
||||
items = append(items, item)
|
||||
}
|
||||
return items
|
||||
}
|
||||
Reference in New Issue
Block a user