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
cf8b021b
authored
Aug 26, 2025
by
Sh1n3zZ
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
feat: vertex veo (#1450)
parent
f249cf9a
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
537 additions
and
15 deletions
+537
-15
common/database.go
+2
-1
controller/setup.go
+2
-1
controller/task_video.go
+39
-3
main.go
+2
-1
middleware/distributor.go
+1
-1
relay/channel/task/vertex/adaptor.go
+344
-0
relay/channel/vertex/adaptor.go
+1
-0
relay/channel/vertex/relay-vertex.go
+4
-1
relay/channel/vertex/service_account.go
+45
-2
relay/relay_adaptor.go
+5
-1
relay/relay_task.go
+92
-4
No files found.
common/database.go
View file @
cf8b021b
...
...
@@ -12,4 +12,4 @@ var LogSqlType = DatabaseTypeSQLite // Default to SQLite for logging SQL queries
var
UsingMySQL
=
false
var
UsingClickHouse
=
false
var
SQLitePath
=
"one-api.db?_busy_timeout=30000"
var
SQLitePath
=
"one-api.db?_busy_timeout=30000"
\ No newline at end of file
controller/setup.go
View file @
cf8b021b
...
...
@@ -178,4 +178,4 @@ func boolToString(b bool) string {
return
"true"
}
return
"false"
}
}
\ No newline at end of file
controller/task_video.go
View file @
cf8b021b
...
...
@@ -94,7 +94,7 @@ func updateVideoSingleTask(ctx context.Context, adaptor channel.TaskAdaptor, cha
}
else
if
taskResult
,
err
=
adaptor
.
ParseTaskResult
(
responseBody
);
err
!=
nil
{
return
fmt
.
Errorf
(
"parseTaskResult failed for task %s: %w"
,
taskId
,
err
)
}
else
{
task
.
Data
=
re
sponseBody
task
.
Data
=
re
dactVideoResponseBody
(
responseBody
)
}
now
:=
time
.
Now
()
.
Unix
()
...
...
@@ -113,11 +113,13 @@ func updateVideoSingleTask(ctx context.Context, adaptor channel.TaskAdaptor, cha
task
.
StartTime
=
now
}
case
model
.
TaskStatusSuccess
:
task
.
Progress
=
"100%"
task
.
Progress
=
"100%"
if
task
.
FinishTime
==
0
{
task
.
FinishTime
=
now
}
task
.
FailReason
=
taskResult
.
Url
if
!
(
len
(
taskResult
.
Url
)
>
5
&&
taskResult
.
Url
[
:
5
]
==
"data:"
)
{
task
.
FailReason
=
taskResult
.
Url
}
case
model
.
TaskStatusFailure
:
task
.
Status
=
model
.
TaskStatusFailure
task
.
Progress
=
"100%"
...
...
@@ -146,3 +148,37 @@ func updateVideoSingleTask(ctx context.Context, adaptor channel.TaskAdaptor, cha
return
nil
}
func
redactVideoResponseBody
(
body
[]
byte
)
[]
byte
{
var
m
map
[
string
]
any
if
err
:=
json
.
Unmarshal
(
body
,
&
m
);
err
!=
nil
{
return
body
}
resp
,
_
:=
m
[
"response"
]
.
(
map
[
string
]
any
)
if
resp
!=
nil
{
delete
(
resp
,
"bytesBase64Encoded"
)
if
v
,
ok
:=
resp
[
"video"
]
.
(
string
);
ok
{
resp
[
"video"
]
=
truncateBase64
(
v
)
}
if
vs
,
ok
:=
resp
[
"videos"
]
.
([]
any
);
ok
{
for
i
:=
range
vs
{
if
vm
,
ok
:=
vs
[
i
]
.
(
map
[
string
]
any
);
ok
{
delete
(
vm
,
"bytesBase64Encoded"
)
}
}
}
}
b
,
err
:=
json
.
Marshal
(
m
)
if
err
!=
nil
{
return
body
}
return
b
}
func
truncateBase64
(
s
string
)
string
{
const
maxKeep
=
256
if
len
(
s
)
<=
maxKeep
{
return
s
}
return
s
[
:
maxKeep
]
+
"..."
}
main.go
View file @
cf8b021b
...
...
@@ -208,4 +208,4 @@ func InitResources() error {
return
err
}
return
nil
}
}
\ No newline at end of file
middleware/distributor.go
View file @
cf8b021b
...
...
@@ -166,9 +166,9 @@ func getModelRequest(c *gin.Context) (*ModelRequest, bool, error) {
c
.
Set
(
"platform"
,
string
(
constant
.
TaskPlatformSuno
))
c
.
Set
(
"relay_mode"
,
relayMode
)
}
else
if
strings
.
Contains
(
c
.
Request
.
URL
.
Path
,
"/v1/video/generations"
)
{
err
=
common
.
UnmarshalBodyReusable
(
c
,
&
modelRequest
)
relayMode
:=
relayconstant
.
RelayModeUnknown
if
c
.
Request
.
Method
==
http
.
MethodPost
{
err
=
common
.
UnmarshalBodyReusable
(
c
,
&
modelRequest
)
relayMode
=
relayconstant
.
RelayModeVideoSubmit
}
else
if
c
.
Request
.
Method
==
http
.
MethodGet
{
relayMode
=
relayconstant
.
RelayModeVideoFetchByID
...
...
relay/channel/task/vertex/adaptor.go
0 → 100644
View file @
cf8b021b
This diff is collapsed.
Click to expand it.
relay/channel/vertex/adaptor.go
View file @
cf8b021b
...
...
@@ -174,6 +174,7 @@ func (a *Adaptor) SetupRequestHeader(c *gin.Context, req *http.Header, info *rel
return
err
}
req
.
Set
(
"Authorization"
,
"Bearer "
+
accessToken
)
req
.
Set
(
"x-goog-user-project"
,
a
.
AccountCredentials
.
ProjectID
)
return
nil
}
...
...
relay/channel/vertex/relay-vertex.go
View file @
cf8b021b
...
...
@@ -12,7 +12,10 @@ func GetModelRegion(other string, localModelName string) string {
if
m
[
localModelName
]
!=
nil
{
return
m
[
localModelName
]
.
(
string
)
}
else
{
return
m
[
"default"
]
.
(
string
)
if
v
,
ok
:=
m
[
"default"
];
ok
{
return
v
.
(
string
)
}
return
"global"
}
}
return
other
...
...
relay/channel/vertex/service_account.go
View file @
cf8b021b
...
...
@@ -6,14 +6,15 @@ import (
"encoding/json"
"encoding/pem"
"errors"
"github.com/bytedance/gopkg/cache/asynccache"
"github.com/golang-jwt/jwt"
"net/http"
"net/url"
relaycommon
"one-api/relay/common"
"one-api/service"
"strings"
"github.com/bytedance/gopkg/cache/asynccache"
"github.com/golang-jwt/jwt"
"fmt"
"time"
)
...
...
@@ -137,3 +138,45 @@ func exchangeJwtForAccessToken(signedJWT string, info *relaycommon.RelayInfo) (s
return
""
,
fmt
.
Errorf
(
"failed to get access token: %v"
,
result
)
}
func
AcquireAccessToken
(
creds
Credentials
,
proxy
string
)
(
string
,
error
)
{
signedJWT
,
err
:=
createSignedJWT
(
creds
.
ClientEmail
,
creds
.
PrivateKey
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"failed to create signed JWT: %w"
,
err
)
}
return
exchangeJwtForAccessTokenWithProxy
(
signedJWT
,
proxy
)
}
func
exchangeJwtForAccessTokenWithProxy
(
signedJWT
string
,
proxy
string
)
(
string
,
error
)
{
authURL
:=
"https://www.googleapis.com/oauth2/v4/token"
data
:=
url
.
Values
{}
data
.
Set
(
"grant_type"
,
"urn:ietf:params:oauth:grant-type:jwt-bearer"
)
data
.
Set
(
"assertion"
,
signedJWT
)
var
client
*
http
.
Client
var
err
error
if
proxy
!=
""
{
client
,
err
=
service
.
NewProxyHttpClient
(
proxy
)
if
err
!=
nil
{
return
""
,
fmt
.
Errorf
(
"new proxy http client failed: %w"
,
err
)
}
}
else
{
client
=
service
.
GetHttpClient
()
}
resp
,
err
:=
client
.
PostForm
(
authURL
,
data
)
if
err
!=
nil
{
return
""
,
err
}
defer
resp
.
Body
.
Close
()
var
result
map
[
string
]
interface
{}
if
err
:=
json
.
NewDecoder
(
resp
.
Body
)
.
Decode
(
&
result
);
err
!=
nil
{
return
""
,
err
}
if
accessToken
,
ok
:=
result
[
"access_token"
]
.
(
string
);
ok
{
return
accessToken
,
nil
}
return
""
,
fmt
.
Errorf
(
"failed to get access token: %v"
,
result
)
}
relay/relay_adaptor.go
View file @
cf8b021b
package
relay
import
(
"github.com/gin-gonic/gin"
"one-api/constant"
"one-api/relay/channel"
"one-api/relay/channel/ali"
...
...
@@ -28,6 +27,7 @@ import (
taskjimeng
"one-api/relay/channel/task/jimeng"
"one-api/relay/channel/task/kling"
"one-api/relay/channel/task/suno"
taskvertex
"one-api/relay/channel/task/vertex"
taskVidu
"one-api/relay/channel/task/vidu"
"one-api/relay/channel/tencent"
"one-api/relay/channel/vertex"
...
...
@@ -37,6 +37,8 @@ import (
"one-api/relay/channel/zhipu"
"one-api/relay/channel/zhipu_4v"
"strconv"
"github.com/gin-gonic/gin"
)
func
GetAdaptor
(
apiType
int
)
channel
.
Adaptor
{
...
...
@@ -126,6 +128,8 @@ func GetTaskAdaptor(platform constant.TaskPlatform) channel.TaskAdaptor {
return
&
kling
.
TaskAdaptor
{}
case
constant
.
ChannelTypeJimeng
:
return
&
taskjimeng
.
TaskAdaptor
{}
case
constant
.
ChannelTypeVertexAi
:
return
&
taskvertex
.
TaskAdaptor
{}
case
constant
.
ChannelTypeVidu
:
return
&
taskVidu
.
TaskAdaptor
{}
}
...
...
relay/relay_task.go
View file @
cf8b021b
...
...
@@ -15,6 +15,8 @@ import (
relayconstant
"one-api/relay/constant"
"one-api/service"
"one-api/setting/ratio_setting"
"strconv"
"strings"
"github.com/gin-gonic/gin"
)
...
...
@@ -32,6 +34,7 @@ func RelayTaskSubmit(c *gin.Context, relayMode int) (taskErr *dto.TaskError) {
if
err
!=
nil
{
return
service
.
TaskErrorWrapper
(
err
,
"gen_relay_info_failed"
,
http
.
StatusInternalServerError
)
}
relayInfo
.
InitChannelMeta
(
c
)
adaptor
:=
GetTaskAdaptor
(
platform
)
if
adaptor
==
nil
{
...
...
@@ -197,6 +200,9 @@ func RelayTaskFetch(c *gin.Context, relayMode int) (taskResp *dto.TaskError) {
if
taskErr
!=
nil
{
return
taskErr
}
if
len
(
respBody
)
==
0
{
respBody
=
[]
byte
(
"{
\"
code
\"
:
\"
success
\"
,
\"
data
\"
:null}"
)
}
c
.
Writer
.
Header
()
.
Set
(
"Content-Type"
,
"application/json"
)
_
,
err
:=
io
.
Copy
(
c
.
Writer
,
bytes
.
NewBuffer
(
respBody
))
...
...
@@ -276,10 +282,92 @@ func videoFetchByIDRespBodyBuilder(c *gin.Context) (respBody []byte, taskResp *d
return
}
respBody
,
err
=
json
.
Marshal
(
dto
.
TaskResponse
[
any
]{
Code
:
"success"
,
Data
:
TaskModel2Dto
(
originTask
),
})
func
()
{
channelModel
,
err2
:=
model
.
GetChannelById
(
originTask
.
ChannelId
,
true
)
if
err2
!=
nil
{
return
}
if
channelModel
.
Type
!=
constant
.
ChannelTypeVertexAi
{
return
}
baseURL
:=
constant
.
ChannelBaseURLs
[
channelModel
.
Type
]
if
channelModel
.
GetBaseURL
()
!=
""
{
baseURL
=
channelModel
.
GetBaseURL
()
}
adaptor
:=
GetTaskAdaptor
(
constant
.
TaskPlatform
(
strconv
.
Itoa
(
channelModel
.
Type
)))
if
adaptor
==
nil
{
return
}
resp
,
err2
:=
adaptor
.
FetchTask
(
baseURL
,
channelModel
.
Key
,
map
[
string
]
any
{
"task_id"
:
originTask
.
TaskID
,
"action"
:
originTask
.
Action
,
})
if
err2
!=
nil
||
resp
==
nil
{
return
}
defer
resp
.
Body
.
Close
()
body
,
err2
:=
io
.
ReadAll
(
resp
.
Body
)
if
err2
!=
nil
{
return
}
ti
,
err2
:=
adaptor
.
ParseTaskResult
(
body
)
if
err2
==
nil
&&
ti
!=
nil
{
if
ti
.
Status
!=
""
{
originTask
.
Status
=
model
.
TaskStatus
(
ti
.
Status
)
}
if
ti
.
Progress
!=
""
{
originTask
.
Progress
=
ti
.
Progress
}
if
ti
.
Url
!=
""
{
originTask
.
FailReason
=
ti
.
Url
}
_
=
originTask
.
Update
()
var
raw
map
[
string
]
any
_
=
json
.
Unmarshal
(
body
,
&
raw
)
format
:=
"mp4"
if
respObj
,
ok
:=
raw
[
"response"
]
.
(
map
[
string
]
any
);
ok
{
if
vids
,
ok
:=
respObj
[
"videos"
]
.
([]
any
);
ok
&&
len
(
vids
)
>
0
{
if
v0
,
ok
:=
vids
[
0
]
.
(
map
[
string
]
any
);
ok
{
if
mt
,
ok
:=
v0
[
"mimeType"
]
.
(
string
);
ok
&&
mt
!=
""
{
if
strings
.
Contains
(
mt
,
"mp4"
)
{
format
=
"mp4"
}
else
{
format
=
mt
}
}
}
}
}
status
:=
"processing"
switch
originTask
.
Status
{
case
model
.
TaskStatusSuccess
:
status
=
"succeeded"
case
model
.
TaskStatusFailure
:
status
=
"failed"
case
model
.
TaskStatusQueued
,
model
.
TaskStatusSubmitted
:
status
=
"queued"
}
out
:=
map
[
string
]
any
{
"error"
:
nil
,
"format"
:
format
,
"metadata"
:
nil
,
"status"
:
status
,
"task_id"
:
originTask
.
TaskID
,
"url"
:
originTask
.
FailReason
,
}
respBody
,
_
=
json
.
Marshal
(
dto
.
TaskResponse
[
any
]{
Code
:
"success"
,
Data
:
out
,
})
}
}()
if
len
(
respBody
)
==
0
{
respBody
,
err
=
json
.
Marshal
(
dto
.
TaskResponse
[
any
]{
Code
:
"success"
,
Data
:
TaskModel2Dto
(
originTask
),
})
}
return
}
...
...
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