mirror of
https://github.com/songquanpeng/one-api.git
synced 2025-11-19 22:53:41 +08:00
- 修复JSON注入漏洞:使用json.Marshal()安全转义字符串内容 - 定义常量CHARS_PER_TOKEN替换硬编码的token估算数字4 - 处理UnmarshalJSON错误,避免静默失败并记录错误日志 - 定义常量替换硬编码的API端点路径,提高可维护性 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
116 lines
3.5 KiB
Go
116 lines
3.5 KiB
Go
package anthropic
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/songquanpeng/one-api/relay/adaptor"
|
|
"github.com/songquanpeng/one-api/relay/meta"
|
|
"github.com/songquanpeng/one-api/relay/model"
|
|
"github.com/songquanpeng/one-api/relay/relaymode"
|
|
)
|
|
|
|
const (
|
|
// NativeAnthropicEndpoint is the endpoint for native Anthropic API
|
|
NativeAnthropicEndpoint = "/v1/messages"
|
|
// ThirdPartyAnthropicEndpoint is the endpoint for third-party providers supporting Anthropic protocol
|
|
ThirdPartyAnthropicEndpoint = "/anthropic/v1/messages"
|
|
)
|
|
|
|
type Adaptor struct {
|
|
}
|
|
|
|
func (a *Adaptor) Init(meta *meta.Meta) {
|
|
|
|
}
|
|
|
|
func (a *Adaptor) GetRequestURL(meta *meta.Meta) (string, error) {
|
|
// For native Anthropic API
|
|
if strings.Contains(meta.BaseURL, "api.anthropic.com") {
|
|
return fmt.Sprintf("%s%s", meta.BaseURL, NativeAnthropicEndpoint), nil
|
|
}
|
|
|
|
// For third-party providers supporting Anthropic protocol (like DeepSeek)
|
|
// They typically expose the endpoint at /anthropic/v1/messages
|
|
baseURL := strings.TrimSuffix(meta.BaseURL, "/")
|
|
return fmt.Sprintf("%s%s", baseURL, ThirdPartyAnthropicEndpoint), nil
|
|
}
|
|
|
|
func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, meta *meta.Meta) error {
|
|
adaptor.SetupCommonRequestHeader(c, req, meta)
|
|
req.Header.Set("x-api-key", meta.APIKey)
|
|
anthropicVersion := c.Request.Header.Get("anthropic-version")
|
|
if anthropicVersion == "" {
|
|
anthropicVersion = "2023-06-01"
|
|
}
|
|
req.Header.Set("anthropic-version", anthropicVersion)
|
|
req.Header.Set("anthropic-beta", "messages-2023-12-15")
|
|
|
|
// https://x.com/alexalbert__/status/1812921642143900036
|
|
// claude-3-5-sonnet can support 8k context
|
|
if strings.HasPrefix(meta.ActualModelName, "claude-3-5-sonnet") {
|
|
req.Header.Set("anthropic-beta", "max-tokens-3-5-sonnet-2024-07-15")
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (a *Adaptor) ConvertRequest(c *gin.Context, relayMode int, request *model.GeneralOpenAIRequest) (any, error) {
|
|
if request == nil {
|
|
return nil, errors.New("request is nil")
|
|
}
|
|
|
|
// For native Anthropic protocol requests, return the request as-is (no conversion needed)
|
|
if relayMode == relaymode.AnthropicMessages {
|
|
// The request should already be in Anthropic format, so we pass it through
|
|
// This will be handled by the caller which already has the anthropic request
|
|
return request, nil
|
|
}
|
|
|
|
// For OpenAI to Anthropic conversion (existing functionality)
|
|
return ConvertRequest(*request), nil
|
|
}
|
|
|
|
func (a *Adaptor) ConvertImageRequest(request *model.ImageRequest) (any, error) {
|
|
if request == nil {
|
|
return nil, errors.New("request is nil")
|
|
}
|
|
return request, nil
|
|
}
|
|
|
|
func (a *Adaptor) DoRequest(c *gin.Context, meta *meta.Meta, requestBody io.Reader) (*http.Response, error) {
|
|
return adaptor.DoRequestHelper(a, c, meta, requestBody)
|
|
}
|
|
|
|
func (a *Adaptor) DoResponse(c *gin.Context, resp *http.Response, meta *meta.Meta) (usage *model.Usage, err *model.ErrorWithStatusCode) {
|
|
// For native Anthropic protocol requests, handle response directly without conversion
|
|
if meta.Mode == relaymode.AnthropicMessages {
|
|
if meta.IsStream {
|
|
err, usage = DirectStreamHandler(c, resp)
|
|
} else {
|
|
err, usage = DirectHandler(c, resp, meta.PromptTokens, meta.ActualModelName)
|
|
}
|
|
return
|
|
}
|
|
|
|
// For OpenAI to Anthropic conversion (existing functionality)
|
|
if meta.IsStream {
|
|
err, usage = StreamHandler(c, resp)
|
|
} else {
|
|
err, usage = Handler(c, resp, meta.PromptTokens, meta.ActualModelName)
|
|
}
|
|
return
|
|
}
|
|
|
|
func (a *Adaptor) GetModelList() []string {
|
|
return ModelList
|
|
}
|
|
|
|
func (a *Adaptor) GetChannelName() string {
|
|
return "anthropic"
|
|
}
|