Skip to content
Toggle navigation
P
Projects
G
Groups
S
Snippets
Help
phsl
/
new-api
This project
Loading...
Sign in
Toggle navigation
Go to a project
Project
Repository
Issues
0
Merge Requests
0
Pipelines
Wiki
Snippets
Members
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Commit
1d343c79
authored
Mar 08, 2024
by
Calcium-Ion
Committed by
GitHub
Mar 08, 2024
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #103 from Calcium-Ion/dev
feat: support Claude 3
parents
a361c5c0
14714164
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
258 additions
and
74 deletions
+258
-74
common/image.go
+4
-3
dto/text_request.go
+8
-6
dto/text_response.go
+6
-0
relay/channel/claude/adaptor.go
+9
-11
relay/channel/claude/constants.go
+1
-1
relay/channel/claude/dto.go
+50
-11
relay/channel/claude/relay-claude.go
+167
-40
service/token_counter.go
+1
-1
web/src/pages/Channel/EditChannel.js
+1
-1
web/src/pages/TopUp/index.js
+11
-0
No files found.
common/image.go
View file @
1d343c79
...
...
@@ -12,7 +12,7 @@ import (
"strings"
)
func
DecodeBase64ImageData
(
base64String
string
)
(
image
.
Config
,
string
,
error
)
{
func
DecodeBase64ImageData
(
base64String
string
)
(
image
.
Config
,
string
,
string
,
error
)
{
// 去除base64数据的URL前缀(如果有)
if
idx
:=
strings
.
Index
(
base64String
,
","
);
idx
!=
-
1
{
base64String
=
base64String
[
idx
+
1
:
]
...
...
@@ -22,13 +22,13 @@ func DecodeBase64ImageData(base64String string) (image.Config, string, error) {
decodedData
,
err
:=
base64
.
StdEncoding
.
DecodeString
(
base64String
)
if
err
!=
nil
{
fmt
.
Println
(
"Error: Failed to decode base64 string"
)
return
image
.
Config
{},
""
,
err
return
image
.
Config
{},
""
,
""
,
err
}
// 创建一个bytes.Buffer用于存储解码后的数据
reader
:=
bytes
.
NewReader
(
decodedData
)
config
,
format
,
err
:=
getImageConfig
(
reader
)
return
config
,
format
,
err
return
config
,
format
,
base64String
,
err
}
func
IsImageUrl
(
url
string
)
(
bool
,
error
)
{
...
...
@@ -42,6 +42,7 @@ func IsImageUrl(url string) (bool, error) {
return
true
,
nil
}
// GetImageFromUrl 获取图片的类型和base64编码的数据
func
GetImageFromUrl
(
url
string
)
(
mimeType
string
,
data
string
,
err
error
)
{
isImage
,
err
:=
IsImageUrl
(
url
)
if
!
isImage
{
...
...
dto/text_request.go
View file @
1d343c79
...
...
@@ -82,6 +82,14 @@ func (m Message) StringContent() string {
return
string
(
m
.
Content
)
}
func
(
m
Message
)
IsStringContent
()
bool
{
var
stringContent
string
if
err
:=
json
.
Unmarshal
(
m
.
Content
,
&
stringContent
);
err
==
nil
{
return
true
}
return
false
}
func
(
m
Message
)
ParseContent
()
[]
MediaMessage
{
var
contentList
[]
MediaMessage
var
stringContent
string
...
...
@@ -130,9 +138,3 @@ func (m Message) ParseContent() []MediaMessage {
return
nil
}
type
Usage
struct
{
PromptTokens
int
`json:"prompt_tokens"`
CompletionTokens
int
`json:"completion_tokens"`
TotalTokens
int
`json:"total_tokens"`
}
dto/text_response.go
View file @
1d343c79
...
...
@@ -61,3 +61,9 @@ type CompletionsStreamResponse struct {
FinishReason
string
`json:"finish_reason"`
}
`json:"choices"`
}
type
Usage
struct
{
PromptTokens
int
`json:"prompt_tokens"`
CompletionTokens
int
`json:"completion_tokens"`
TotalTokens
int
`json:"total_tokens"`
}
relay/channel/claude/adaptor.go
View file @
1d343c79
...
...
@@ -6,10 +6,10 @@ import (
"github.com/gin-gonic/gin"
"io"
"net/http"
"one-api/common"
"one-api/dto"
"one-api/relay/channel"
relaycommon
"one-api/relay/common"
"one-api/service"
"strings"
)
...
...
@@ -50,15 +50,15 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Request, info *re
}
func
(
a
*
Adaptor
)
ConvertRequest
(
c
*
gin
.
Context
,
relayMode
int
,
request
*
dto
.
GeneralOpenAIRequest
)
(
any
,
error
)
{
common
.
SysLog
(
fmt
.
Sprintf
(
"Request mode: %d"
,
a
.
RequestMode
))
if
request
==
nil
{
return
nil
,
errors
.
New
(
"request is nil"
)
}
//if a.RequestMode == RequestModeCompletion {
// return requestOpenAI2ClaudeComplete(*request), nil
//} else {
// return requestOpenAI2ClaudeMessage(*request), nil
//}
return
request
,
nil
if
a
.
RequestMode
==
RequestModeCompletion
{
return
requestOpenAI2ClaudeComplete
(
*
request
),
nil
}
else
{
return
requestOpenAI2ClaudeMessage
(
*
request
)
}
}
func
(
a
*
Adaptor
)
DoRequest
(
c
*
gin
.
Context
,
info
*
relaycommon
.
RelayInfo
,
requestBody
io
.
Reader
)
(
*
http
.
Response
,
error
)
{
...
...
@@ -67,11 +67,9 @@ func (a *Adaptor) DoRequest(c *gin.Context, info *relaycommon.RelayInfo, request
func
(
a
*
Adaptor
)
DoResponse
(
c
*
gin
.
Context
,
resp
*
http
.
Response
,
info
*
relaycommon
.
RelayInfo
)
(
usage
*
dto
.
Usage
,
err
*
dto
.
OpenAIErrorWithStatusCode
)
{
if
info
.
IsStream
{
var
responseText
string
err
,
responseText
=
claudeStreamHandler
(
c
,
resp
)
usage
=
service
.
ResponseText2Usage
(
responseText
,
info
.
UpstreamModelName
,
info
.
PromptTokens
)
err
,
usage
=
claudeStreamHandler
(
a
.
RequestMode
,
info
.
UpstreamModelName
,
info
.
PromptTokens
,
c
,
resp
)
}
else
{
err
,
usage
=
claudeHandler
(
c
,
resp
,
info
.
PromptTokens
,
info
.
UpstreamModelName
)
err
,
usage
=
claudeHandler
(
a
.
RequestMode
,
c
,
resp
,
info
.
PromptTokens
,
info
.
UpstreamModelName
)
}
return
}
...
...
relay/channel/claude/constants.go
View file @
1d343c79
package
claude
var
ModelList
=
[]
string
{
"claude-instant-1"
,
"claude-2"
,
"claude-2.0"
,
"claude-2.1"
,
"claude-instant-1"
,
"claude-2"
,
"claude-2.0"
,
"claude-2.1"
,
"claude-3-sonnet-20240229"
,
"claude-3-opus-20240229"
,
}
var
ChannelName
=
"claude"
relay/channel/claude/dto.go
View file @
1d343c79
...
...
@@ -4,14 +4,36 @@ type ClaudeMetadata struct {
UserId
string
`json:"user_id"`
}
type
ClaudeMediaMessage
struct
{
Type
string
`json:"type"`
Text
string
`json:"text,omitempty"`
Source
*
ClaudeMessageSource
`json:"source,omitempty"`
Usage
*
ClaudeUsage
`json:"usage,omitempty"`
StopReason
*
string
`json:"stop_reason,omitempty"`
}
type
ClaudeMessageSource
struct
{
Type
string
`json:"type"`
MediaType
string
`json:"media_type"`
Data
string
`json:"data"`
}
type
ClaudeMessage
struct
{
Role
string
`json:"role"`
Content
any
`json:"content"`
}
type
ClaudeRequest
struct
{
Model
string
`json:"model"`
Prompt
string
`json:"prompt"`
MaxTokensToSample
uint
`json:"max_tokens_to_sample"`
StopSequences
[]
string
`json:"stop_sequences,omitempty"`
Temperature
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
Model
string
`json:"model"`
Prompt
string
`json:"prompt,omitempty"`
System
string
`json:"system,omitempty"`
Messages
[]
ClaudeMessage
`json:"messages,omitempty"`
MaxTokensToSample
uint
`json:"max_tokens_to_sample,omitempty"`
MaxTokens
uint
`json:"max_tokens,omitempty"`
StopSequences
[]
string
`json:"stop_sequences,omitempty"`
Temperature
float64
`json:"temperature,omitempty"`
TopP
float64
`json:"top_p,omitempty"`
TopK
int
`json:"top_k,omitempty"`
//ClaudeMetadata `json:"metadata,omitempty"`
Stream
bool
`json:"stream,omitempty"`
}
...
...
@@ -22,8 +44,25 @@ type ClaudeError struct {
}
type
ClaudeResponse
struct
{
Completion
string
`json:"completion"`
StopReason
string
`json:"stop_reason"`
Model
string
`json:"model"`
Error
ClaudeError
`json:"error"`
Id
string
`json:"id"`
Type
string
`json:"type"`
Content
[]
ClaudeMediaMessage
`json:"content"`
Completion
string
`json:"completion"`
StopReason
string
`json:"stop_reason"`
Model
string
`json:"model"`
Error
ClaudeError
`json:"error"`
Usage
ClaudeUsage
`json:"usage"`
Index
int
`json:"index"`
// stream only
Delta
*
ClaudeMediaMessage
`json:"delta"`
// stream only
Message
*
ClaudeResponse
`json:"message"`
// stream only: message_start
}
//type ClaudeResponseChoice struct {
// Index int `json:"index"`
// Type string `json:"type"`
//}
type
ClaudeUsage
struct
{
InputTokens
int
`json:"input_tokens"`
OutputTokens
int
`json:"output_tokens"`
}
relay/channel/claude/relay-claude.go
View file @
1d343c79
This diff is collapsed.
Click to expand it.
service/token_counter.go
View file @
1d343c79
...
...
@@ -74,7 +74,7 @@ func getImageToken(imageUrl *dto.MessageImageUrl) (int, error) {
config
,
format
,
err
=
common
.
DecodeUrlImageData
(
imageUrl
.
Url
)
}
else
{
common
.
SysLog
(
fmt
.
Sprintf
(
"decoding image"
))
config
,
format
,
err
=
common
.
DecodeBase64ImageData
(
imageUrl
.
Url
)
config
,
format
,
_
,
err
=
common
.
DecodeBase64ImageData
(
imageUrl
.
Url
)
}
if
err
!=
nil
{
return
0
,
err
...
...
web/src/pages/Channel/EditChannel.js
View file @
1d343c79
...
...
@@ -63,7 +63,7 @@ const EditChannel = (props) => {
let
localModels
=
[];
switch
(
value
)
{
case
14
:
localModels
=
[
'claude-instant-1'
,
'claude-2'
];
localModels
=
[
"claude-instant-1"
,
"claude-2"
,
"claude-2.0"
,
"claude-2.1"
,
"claude-3-sonnet-20240229"
,
"claude-3-opus-20240229"
];
break
;
case
11
:
localModels
=
[
'PaLM-2'
];
...
...
web/src/pages/TopUp/index.js
View file @
1d343c79
...
...
@@ -3,6 +3,8 @@ import {API, isMobile, showError, showInfo, showSuccess} from '../../helpers';
import
{
renderNumber
,
renderQuota
}
from
'../../helpers/render'
;
import
{
Col
,
Layout
,
Row
,
Typography
,
Card
,
Button
,
Form
,
Divider
,
Space
,
Modal
}
from
"@douyinfe/semi-ui"
;
import
Title
from
"@douyinfe/semi-ui/lib/es/typography/title"
;
import
Text
from
'@douyinfe/semi-ui/lib/es/typography/text'
;
import
{
Link
}
from
'react-router-dom'
;
const
TopUp
=
()
=>
{
const
[
redemptionCode
,
setRedemptionCode
]
=
useState
(
''
);
...
...
@@ -290,6 +292,15 @@ const TopUp = () => {
<
/Space
>
<
/Form
>
<
/div
>
<
div
style
=
{{
display
:
'flex'
,
justifyContent
:
'right'
}}
>
<
Text
>
<
Link
onClick
=
{
async
()
=>
{
window
.
location
.
href
=
'/topup/history'
}
}
>
充值记录
<
/Link
>
<
/Text
>
<
/div
>
<
/Card
>
<
/div
>
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment