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
d97d50b1
authored
May 13, 2023
by
JustSong
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: Azure API supported without verification (#48, #57)
parent
17f17142
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
73 additions
and
120 deletions
+73
-120
controller/relay.go
+21
-7
middleware/distributor.go
+1
-1
web/src/App.js
+1
-2
web/src/pages/Channel/AddChannel.js
+0
-95
web/src/pages/Channel/EditChannel.js
+50
-15
No files found.
controller/relay.go
View file @
d97d50b1
...
@@ -68,12 +68,8 @@ func relayHelper(c *gin.Context) error {
...
@@ -68,12 +68,8 @@ func relayHelper(c *gin.Context) error {
channelType
:=
c
.
GetInt
(
"channel"
)
channelType
:=
c
.
GetInt
(
"channel"
)
tokenId
:=
c
.
GetInt
(
"token_id"
)
tokenId
:=
c
.
GetInt
(
"token_id"
)
consumeQuota
:=
c
.
GetBool
(
"consume_quota"
)
consumeQuota
:=
c
.
GetBool
(
"consume_quota"
)
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
if
channelType
==
common
.
ChannelTypeCustom
{
baseURL
=
c
.
GetString
(
"base_url"
)
}
var
textRequest
TextRequest
var
textRequest
TextRequest
if
consumeQuota
{
if
consumeQuota
||
channelType
==
common
.
ChannelTypeAzure
{
requestBody
,
err
:=
io
.
ReadAll
(
c
.
Request
.
Body
)
requestBody
,
err
:=
io
.
ReadAll
(
c
.
Request
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
...
@@ -89,12 +85,30 @@ func relayHelper(c *gin.Context) error {
...
@@ -89,12 +85,30 @@ func relayHelper(c *gin.Context) error {
// Reset request body
// Reset request body
c
.
Request
.
Body
=
io
.
NopCloser
(
bytes
.
NewBuffer
(
requestBody
))
c
.
Request
.
Body
=
io
.
NopCloser
(
bytes
.
NewBuffer
(
requestBody
))
}
}
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
requestURL
:=
c
.
Request
.
URL
.
String
()
requestURL
:=
c
.
Request
.
URL
.
String
()
req
,
err
:=
http
.
NewRequest
(
c
.
Request
.
Method
,
fmt
.
Sprintf
(
"%s%s"
,
baseURL
,
requestURL
),
c
.
Request
.
Body
)
if
channelType
==
common
.
ChannelTypeCustom
{
baseURL
=
c
.
GetString
(
"base_url"
)
}
fullRequestURL
:=
fmt
.
Sprintf
(
"%s%s"
,
baseURL
,
requestURL
)
if
channelType
==
common
.
ChannelTypeAzure
{
// https://learn.microsoft.com/en-us/azure/cognitive-services/openai/chatgpt-quickstart?pivots=rest-api&tabs=command-line#rest-api
baseURL
=
c
.
GetString
(
"base_url"
)
task
:=
strings
.
TrimPrefix
(
requestURL
,
"/v1/"
)
model_
:=
textRequest
.
Model
fullRequestURL
=
fmt
.
Sprintf
(
"%s/openai/deployments/%s/%s"
,
baseURL
,
model_
,
task
)
}
req
,
err
:=
http
.
NewRequest
(
c
.
Request
.
Method
,
fullRequestURL
,
c
.
Request
.
Body
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
req
.
Header
.
Set
(
"Authorization"
,
c
.
Request
.
Header
.
Get
(
"Authorization"
))
if
channelType
==
common
.
ChannelTypeAzure
{
key
:=
c
.
Request
.
Header
.
Get
(
"Authorization"
)
key
=
strings
.
TrimPrefix
(
key
,
"Bearer "
)
req
.
Header
.
Set
(
"api-key"
,
key
)
}
else
{
req
.
Header
.
Set
(
"Authorization"
,
c
.
Request
.
Header
.
Get
(
"Authorization"
))
}
req
.
Header
.
Set
(
"Content-Type"
,
c
.
Request
.
Header
.
Get
(
"Content-Type"
))
req
.
Header
.
Set
(
"Content-Type"
,
c
.
Request
.
Header
.
Get
(
"Content-Type"
))
req
.
Header
.
Set
(
"Accept"
,
c
.
Request
.
Header
.
Get
(
"Accept"
))
req
.
Header
.
Set
(
"Accept"
,
c
.
Request
.
Header
.
Get
(
"Accept"
))
req
.
Header
.
Set
(
"Connection"
,
c
.
Request
.
Header
.
Get
(
"Connection"
))
req
.
Header
.
Set
(
"Connection"
,
c
.
Request
.
Header
.
Get
(
"Connection"
))
...
...
middleware/distributor.go
View file @
d97d50b1
...
@@ -63,7 +63,7 @@ func Distribute() func(c *gin.Context) {
...
@@ -63,7 +63,7 @@ func Distribute() func(c *gin.Context) {
}
}
c
.
Set
(
"channel"
,
channel
.
Type
)
c
.
Set
(
"channel"
,
channel
.
Type
)
c
.
Request
.
Header
.
Set
(
"Authorization"
,
fmt
.
Sprintf
(
"Bearer %s"
,
channel
.
Key
))
c
.
Request
.
Header
.
Set
(
"Authorization"
,
fmt
.
Sprintf
(
"Bearer %s"
,
channel
.
Key
))
if
channel
.
Type
==
common
.
ChannelTypeCustom
{
if
channel
.
Type
==
common
.
ChannelTypeCustom
||
channel
.
Type
==
common
.
ChannelTypeAzure
{
c
.
Set
(
"base_url"
,
channel
.
BaseURL
)
c
.
Set
(
"base_url"
,
channel
.
BaseURL
)
}
}
c
.
Next
()
c
.
Next
()
...
...
web/src/App.js
View file @
d97d50b1
...
@@ -19,7 +19,6 @@ import Channel from './pages/Channel';
...
@@ -19,7 +19,6 @@ import Channel from './pages/Channel';
import
Token
from
'./pages/Token'
;
import
Token
from
'./pages/Token'
;
import
EditToken
from
'./pages/Token/EditToken'
;
import
EditToken
from
'./pages/Token/EditToken'
;
import
EditChannel
from
'./pages/Channel/EditChannel'
;
import
EditChannel
from
'./pages/Channel/EditChannel'
;
import
AddChannel
from
'./pages/Channel/AddChannel'
;
import
Redemption
from
'./pages/Redemption'
;
import
Redemption
from
'./pages/Redemption'
;
import
EditRedemption
from
'./pages/Redemption/EditRedemption'
;
import
EditRedemption
from
'./pages/Redemption/EditRedemption'
;
...
@@ -93,7 +92,7 @@ function App() {
...
@@ -93,7 +92,7 @@ function App() {
path
=
'/channel/add'
path
=
'/channel/add'
element
=
{
element
=
{
<
Suspense
fallback
=
{
<
Loading
><
/Loading>}
>
<
Suspense
fallback
=
{
<
Loading
><
/Loading>}
>
<
Add
Channel
/>
<
Edit
Channel
/>
<
/Suspense
>
<
/Suspense
>
}
}
/
>
/
>
...
...
web/src/pages/Channel/AddChannel.js
deleted
100644 → 0
View file @
17f17142
import
React
,
{
useState
}
from
'react'
;
import
{
Button
,
Form
,
Header
,
Segment
}
from
'semantic-ui-react'
;
import
{
API
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
CHANNEL_OPTIONS
}
from
'../../constants'
;
const
AddChannel
=
()
=>
{
const
originInputs
=
{
name
:
''
,
type
:
1
,
key
:
''
,
base_url
:
''
,
};
const
[
inputs
,
setInputs
]
=
useState
(
originInputs
);
const
{
name
,
type
,
key
}
=
inputs
;
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
};
const
submit
=
async
()
=>
{
if
(
inputs
.
name
===
''
||
inputs
.
key
===
''
)
return
;
if
(
inputs
.
base_url
.
endsWith
(
'/'
))
{
inputs
.
base_url
=
inputs
.
base_url
.
slice
(
0
,
inputs
.
base_url
.
length
-
1
);
}
const
res
=
await
API
.
post
(
`/api/channel/`
,
inputs
);
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
showSuccess
(
'渠道创建成功!'
);
setInputs
(
originInputs
);
}
else
{
showError
(
message
);
}
};
return
(
<>
<
Segment
>
<
Header
as
=
'h3'
>
创建新的渠道
<
/Header
>
<
Form
autoComplete
=
'new-password'
>
<
Form
.
Field
>
<
Form
.
Select
label
=
'类型'
name
=
'type'
options
=
{
CHANNEL_OPTIONS
}
value
=
{
inputs
.
type
}
onChange
=
{
handleInputChange
}
/
>
<
/Form.Field
>
{
type
===
8
&&
(
<
Form
.
Field
>
<
Form
.
Input
label
=
'Base URL'
name
=
'base_url'
placeholder
=
{
'请输入自定义渠道的 Base URL,例如:https://openai.justsong.cn'
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
base_url
}
autoComplete
=
'new-password'
/>
<
/Form.Field
>
)
}
<
Form
.
Field
>
<
Form
.
Input
label
=
'名称'
name
=
'name'
placeholder
=
{
'请输入名称'
}
onChange
=
{
handleInputChange
}
value
=
{
name
}
autoComplete
=
'new-password'
required
/>
<
/Form.Field
>
<
Form
.
Field
>
<
Form
.
Input
label
=
'密钥'
name
=
'key'
placeholder
=
{
'请输入密钥'
}
onChange
=
{
handleInputChange
}
value
=
{
key
}
// type='password'
autoComplete
=
'new-password'
required
/>
<
/Form.Field
>
<
Button
type
=
{
'submit'
}
onClick
=
{
submit
}
>
提交
<
/Button
>
<
/Form
>
<
/Segment
>
<
/
>
);
};
export
default
AddChannel
;
web/src/pages/Channel/EditChannel.js
View file @
d97d50b1
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
React
,
{
useEffect
,
useState
}
from
'react'
;
import
{
Button
,
Form
,
Header
,
Segment
}
from
'semantic-ui-react'
;
import
{
Button
,
Form
,
Header
,
Message
,
Segment
}
from
'semantic-ui-react'
;
import
{
useParams
}
from
'react-router-dom'
;
import
{
useParams
}
from
'react-router-dom'
;
import
{
API
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
API
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
CHANNEL_OPTIONS
}
from
'../../constants'
;
import
{
CHANNEL_OPTIONS
}
from
'../../constants'
;
...
@@ -7,13 +7,15 @@ import { CHANNEL_OPTIONS } from '../../constants';
...
@@ -7,13 +7,15 @@ import { CHANNEL_OPTIONS } from '../../constants';
const
EditChannel
=
()
=>
{
const
EditChannel
=
()
=>
{
const
params
=
useParams
();
const
params
=
useParams
();
const
channelId
=
params
.
id
;
const
channelId
=
params
.
id
;
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
isEdit
=
channelId
!==
undefined
;
const
[
inputs
,
setInputs
]
=
useState
({
const
[
loading
,
setLoading
]
=
useState
(
isEdit
);
const
originInputs
=
{
name
:
''
,
name
:
''
,
key
:
''
,
type
:
1
,
type
:
1
,
base_url
:
''
,
key
:
''
,
});
base_url
:
''
};
const
[
inputs
,
setInputs
]
=
useState
(
originInputs
);
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
};
};
...
@@ -30,17 +32,31 @@ const EditChannel = () => {
...
@@ -30,17 +32,31 @@ const EditChannel = () => {
setLoading
(
false
);
setLoading
(
false
);
};
};
useEffect
(()
=>
{
useEffect
(()
=>
{
loadChannel
().
then
();
if
(
isEdit
)
{
loadChannel
().
then
();
}
},
[]);
},
[]);
const
submit
=
async
()
=>
{
const
submit
=
async
()
=>
{
if
(
inputs
.
base_url
.
endsWith
(
'/'
))
{
if
(
!
isEdit
&&
(
inputs
.
name
===
''
||
inputs
.
key
===
''
))
return
;
inputs
.
base_url
=
inputs
.
base_url
.
slice
(
0
,
inputs
.
base_url
.
length
-
1
);
let
localInputs
=
inputs
;
if
(
localInputs
.
base_url
.
endsWith
(
'/'
))
{
localInputs
.
base_url
=
localInputs
.
base_url
.
slice
(
0
,
localInputs
.
base_url
.
length
-
1
);
}
let
res
;
if
(
isEdit
)
{
res
=
await
API
.
put
(
`/api/channel/`
,
{
...
localInputs
,
id
:
parseInt
(
channelId
)
});
}
else
{
res
=
await
API
.
post
(
`/api/channel/`
,
localInputs
);
}
}
let
res
=
await
API
.
put
(
`/api/channel/`
,
{
...
inputs
,
id
:
parseInt
(
channelId
)
});
const
{
success
,
message
}
=
res
.
data
;
const
{
success
,
message
}
=
res
.
data
;
if
(
success
)
{
if
(
success
)
{
showSuccess
(
'渠道更新成功!'
);
if
(
isEdit
)
{
showSuccess
(
'渠道更新成功!'
);
}
else
{
showSuccess
(
'渠道创建成功!'
);
setInputs
(
originInputs
);
}
}
else
{
}
else
{
showError
(
message
);
showError
(
message
);
}
}
...
@@ -49,7 +65,7 @@ const EditChannel = () => {
...
@@ -49,7 +65,7 @@ const EditChannel = () => {
return
(
return
(
<>
<>
<
Segment
loading
=
{
loading
}
>
<
Segment
loading
=
{
loading
}
>
<
Header
as
=
'h3'
>
更新渠道信息
<
/Header
>
<
Header
as
=
'h3'
>
{
isEdit
?
'更新渠道信息'
:
'创建新的渠道'
}
<
/Header
>
<
Form
autoComplete
=
'new-password'
>
<
Form
autoComplete
=
'new-password'
>
<
Form
.
Field
>
<
Form
.
Field
>
<
Form
.
Select
<
Form
.
Select
...
@@ -61,12 +77,31 @@ const EditChannel = () => {
...
@@ -61,12 +77,31 @@ const EditChannel = () => {
/
>
/
>
<
/Form.Field
>
<
/Form.Field
>
{
{
inputs
.
type
===
3
&&
(
<>
<
Message
>
注意,创建资源时,部署名称必须和
OpenAI
官方的模型名称保持一致,因为
One
API
会把请求体中的
model
参数替换为你的部署名称。
<
/Message
>
<
Form
.
Field
>
<
Form
.
Input
label
=
'AZURE_OPENAI_ENDPOINT'
name
=
'base_url'
placeholder
=
{
'请输入 AZURE_OPENAI_ENDPOINT,例如:https://docs-test-001.openai.azure.com'
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
base_url
}
autoComplete
=
'new-password'
/>
<
/Form.Field
>
<
/
>
)
}
{
inputs
.
type
===
8
&&
(
inputs
.
type
===
8
&&
(
<
Form
.
Field
>
<
Form
.
Field
>
<
Form
.
Input
<
Form
.
Input
label
=
'Base URL'
label
=
'Base URL'
name
=
'base_url'
name
=
'base_url'
placeholder
=
{
'请输入
新的
自定义渠道的 Base URL,例如:https://openai.justsong.cn'
}
placeholder
=
{
'请输入自定义渠道的 Base URL,例如:https://openai.justsong.cn'
}
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
base_url
}
value
=
{
inputs
.
base_url
}
autoComplete
=
'new-password'
autoComplete
=
'new-password'
...
@@ -78,7 +113,7 @@ const EditChannel = () => {
...
@@ -78,7 +113,7 @@ const EditChannel = () => {
<
Form
.
Input
<
Form
.
Input
label
=
'名称'
label
=
'名称'
name
=
'name'
name
=
'name'
placeholder
=
{
'请输入
新的
名称'
}
placeholder
=
{
'请输入名称'
}
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
name
}
value
=
{
inputs
.
name
}
autoComplete
=
'new-password'
autoComplete
=
'new-password'
...
@@ -88,7 +123,7 @@ const EditChannel = () => {
...
@@ -88,7 +123,7 @@ const EditChannel = () => {
<
Form
.
Input
<
Form
.
Input
label
=
'密钥'
label
=
'密钥'
name
=
'key'
name
=
'key'
placeholder
=
{
'请输入
新的
密钥'
}
placeholder
=
{
'请输入密钥'
}
onChange
=
{
handleInputChange
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
key
}
value
=
{
inputs
.
key
}
// type='password'
// type='password'
...
...
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