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 {
channelType
:=
c
.
GetInt
(
"channel"
)
tokenId
:=
c
.
GetInt
(
"token_id"
)
consumeQuota
:=
c
.
GetBool
(
"consume_quota"
)
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
if
channelType
==
common
.
ChannelTypeCustom
{
baseURL
=
c
.
GetString
(
"base_url"
)
}
var
textRequest
TextRequest
if
consumeQuota
{
if
consumeQuota
||
channelType
==
common
.
ChannelTypeAzure
{
requestBody
,
err
:=
io
.
ReadAll
(
c
.
Request
.
Body
)
if
err
!=
nil
{
return
err
...
...
@@ -89,12 +85,30 @@ func relayHelper(c *gin.Context) error {
// Reset request body
c
.
Request
.
Body
=
io
.
NopCloser
(
bytes
.
NewBuffer
(
requestBody
))
}
baseURL
:=
common
.
ChannelBaseURLs
[
channelType
]
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
{
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
(
"Accept"
,
c
.
Request
.
Header
.
Get
(
"Accept"
))
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) {
}
c
.
Set
(
"channel"
,
channel
.
Type
)
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
.
Next
()
...
...
web/src/App.js
View file @
d97d50b1
...
...
@@ -19,7 +19,6 @@ import Channel from './pages/Channel';
import
Token
from
'./pages/Token'
;
import
EditToken
from
'./pages/Token/EditToken'
;
import
EditChannel
from
'./pages/Channel/EditChannel'
;
import
AddChannel
from
'./pages/Channel/AddChannel'
;
import
Redemption
from
'./pages/Redemption'
;
import
EditRedemption
from
'./pages/Redemption/EditRedemption'
;
...
...
@@ -93,7 +92,7 @@ function App() {
path
=
'/channel/add'
element
=
{
<
Suspense
fallback
=
{
<
Loading
><
/Loading>}
>
<
Add
Channel
/>
<
Edit
Channel
/>
<
/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
{
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
{
API
,
showError
,
showSuccess
}
from
'../../helpers'
;
import
{
CHANNEL_OPTIONS
}
from
'../../constants'
;
...
...
@@ -7,13 +7,15 @@ import { CHANNEL_OPTIONS } from '../../constants';
const
EditChannel
=
()
=>
{
const
params
=
useParams
();
const
channelId
=
params
.
id
;
const
[
loading
,
setLoading
]
=
useState
(
true
);
const
[
inputs
,
setInputs
]
=
useState
({
const
isEdit
=
channelId
!==
undefined
;
const
[
loading
,
setLoading
]
=
useState
(
isEdit
);
const
originInputs
=
{
name
:
''
,
key
:
''
,
type
:
1
,
base_url
:
''
,
});
key
:
''
,
base_url
:
''
};
const
[
inputs
,
setInputs
]
=
useState
(
originInputs
);
const
handleInputChange
=
(
e
,
{
name
,
value
})
=>
{
setInputs
((
inputs
)
=>
({
...
inputs
,
[
name
]:
value
}));
};
...
...
@@ -30,17 +32,31 @@ const EditChannel = () => {
setLoading
(
false
);
};
useEffect
(()
=>
{
loadChannel
().
then
();
if
(
isEdit
)
{
loadChannel
().
then
();
}
},
[]);
const
submit
=
async
()
=>
{
if
(
inputs
.
base_url
.
endsWith
(
'/'
))
{
inputs
.
base_url
=
inputs
.
base_url
.
slice
(
0
,
inputs
.
base_url
.
length
-
1
);
if
(
!
isEdit
&&
(
inputs
.
name
===
''
||
inputs
.
key
===
''
))
return
;
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
;
if
(
success
)
{
showSuccess
(
'渠道更新成功!'
);
if
(
isEdit
)
{
showSuccess
(
'渠道更新成功!'
);
}
else
{
showSuccess
(
'渠道创建成功!'
);
setInputs
(
originInputs
);
}
}
else
{
showError
(
message
);
}
...
...
@@ -49,7 +65,7 @@ const EditChannel = () => {
return
(
<>
<
Segment
loading
=
{
loading
}
>
<
Header
as
=
'h3'
>
更新渠道信息
<
/Header
>
<
Header
as
=
'h3'
>
{
isEdit
?
'更新渠道信息'
:
'创建新的渠道'
}
<
/Header
>
<
Form
autoComplete
=
'new-password'
>
<
Form
.
Field
>
<
Form
.
Select
...
...
@@ -61,12 +77,31 @@ const EditChannel = () => {
/
>
<
/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
&&
(
<
Form
.
Field
>
<
Form
.
Input
label
=
'Base URL'
name
=
'base_url'
placeholder
=
{
'请输入
新的
自定义渠道的 Base URL,例如:https://openai.justsong.cn'
}
placeholder
=
{
'请输入自定义渠道的 Base URL,例如:https://openai.justsong.cn'
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
base_url
}
autoComplete
=
'new-password'
...
...
@@ -78,7 +113,7 @@ const EditChannel = () => {
<
Form
.
Input
label
=
'名称'
name
=
'name'
placeholder
=
{
'请输入
新的
名称'
}
placeholder
=
{
'请输入名称'
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
name
}
autoComplete
=
'new-password'
...
...
@@ -88,7 +123,7 @@ const EditChannel = () => {
<
Form
.
Input
label
=
'密钥'
name
=
'key'
placeholder
=
{
'请输入
新的
密钥'
}
placeholder
=
{
'请输入密钥'
}
onChange
=
{
handleInputChange
}
value
=
{
inputs
.
key
}
// 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