11// app/client/ViduProxy.ts
22
3- import { SunoEndpoint , ViduEndpoint } from "@/constant" ;
3+ import { ViduEndpoint } from "@/constant" ;
44import { api2ProviderBaseUrl } from "@/app/store" ;
55import { getRequestOptions } from "@/app/client/helper" ;
66
@@ -12,17 +12,185 @@ export interface ViduTaskGenerationRequest {
1212 enhance : boolean ;
1313 } [ ] ;
1414 } ;
15- type : string | "img2video" ;
15+ type : keyof typeof ViduTaskType ;
1616 settings : {
17- style : string ;
17+ style : keyof typeof ViduStyle ;
1818 aspect_ratio : string ;
19- duration : number ;
20- model : string | "vidu-1" ;
19+ duration : 4 | 8 ;
20+ model : "vidu-1" | "stable ";
2121 } ;
2222}
2323
2424export interface ViduTaskGenerationResponse {
25+ id : string ;
26+ input : {
27+ creation_id : string ;
28+ prompts : {
29+ type : string ;
30+ content : string ;
31+ negative : boolean ;
32+ enhance : boolean ;
33+ recaption : string ;
34+ } [ ] ;
35+ lang : "zh" | "en" ;
36+ } ;
37+ settings : ViduTaskGenerationRequest [ "settings" ] ;
38+ type : ViduTaskGenerationRequest [ "type" ] ;
39+ state : "queueing" | "processing" | "success" | string ;
40+ creations : {
41+ id : string ;
42+ task_id : string ;
43+ type : "video" | string ;
44+ grade : "draft" | string ;
45+ uri : string ;
46+ cover_uri : string ;
47+ resolution : {
48+ width : number ;
49+ height : number ;
50+ } ;
51+ vote : "unspecified" | string ;
52+ is_favor : boolean ;
53+ src_video_duration : number ;
54+ creator_id : string ;
55+ video : {
56+ duration : number ;
57+ fps : number ;
58+ resolution : {
59+ width : number ;
60+ height : number ;
61+ } ;
62+ } ;
63+ is_deleted : boolean ;
64+ err_code : string ;
65+ created_at : string ;
66+ } [ ] ;
67+ err_code : string ;
68+ created_at : string ;
69+ }
70+
71+ export interface ViduUpscaleTaskRequest {
72+ input : {
73+ creation_id : string ;
74+ } ;
75+ type : "upscale" ;
76+ settings : {
77+ model : "stable" ;
78+ duration : 4 | 8 ;
79+ } ;
80+ }
81+
82+ export enum ViduTaskType {
83+ upscale = 'upscale' ,
84+ text2video = 'text2video' , // 无图片时
85+ img2video = 'img2video' , // 图片用途:用作起始帧(Use as First Frame)
86+ character2video = 'character2video' , // 图片用途:参考人物角色(Use for Character Reference)
87+ }
2588
89+ export enum ViduModel {
90+ stable = 'stable' ,
91+ vidu1 = 'vidu-1' ,
92+ }
93+
94+ export enum ViduStyle {
95+ general = 'general' ,
96+ anime = 'anime' ,
97+ }
98+
99+ const vidu_task_generation_response_queueing_example : ViduTaskGenerationResponse = {
100+ "id" : "2375606842092581" ,
101+ "input" : {
102+ "creation_id" : "0" ,
103+ "prompts" : [
104+ {
105+ "type" : "text" ,
106+ "content" : "cloud" ,
107+ "negative" : false ,
108+ "enhance" : false ,
109+ "recaption" : ""
110+ } ,
111+ {
112+ "type" : "image" ,
113+ "content" : "https://vidu.cf.vidu.studio/infer/tasks/24/0805/04/2375606842092581/input/prompt-02.jpeg?Expires=1722918735&Signature=ihq-BYHZm8TKhCcT3bTiv0ryQNyiNkizZYT1crgCinMxPtMVTfkLcXWWHwTKzrPxSebHFshqd7dgou1mjf0MbG8anwTxZdohytf6xjlPbFL94tYnx5YdAfwuwQX0-pJ7rcSY3VFqqbMNFGyHsu2h4OINGV0GEYn~bKPoRbkwYyVwN6XcLEeabxByCKhpw75b8~4cOSr4NH~YhOSfk~~6JWwqdezafxj7g823P0tVXms3TolK0e1FWu7Y~jJ0MmBdsfwcRrvDC5yjuWKPFb10dH32QOjKHY3QP1zLQXkD4QES11ZA6sCv4aq9j0MLQmq97mJSIRczRmCzH8ZP~0AiRQ__&Key-Pair-Id=KNW0SL0E7LV4E" ,
114+ "negative" : false ,
115+ "enhance" : false ,
116+ "recaption" : ""
117+ }
118+ ] ,
119+ "lang" : "en"
120+ } ,
121+ "settings" : {
122+ "style" : "general" ,
123+ "duration" : 4 ,
124+ "aspect_ratio" : "16:9" ,
125+ "model" : "vidu-1"
126+ } ,
127+ "type" : "img2video" ,
128+ "state" : "queueing" ,
129+ "creations" : [ ] ,
130+ "err_code" : "" ,
131+ "created_at" : "2024-08-05T04:32:14.795273Z"
132+ }
133+ const vidu_task_generation_response_success_example : ViduTaskGenerationResponse = {
134+ "id" : "2375646005579044" ,
135+ "input" : {
136+ "creation_id" : "0" ,
137+ "prompts" : [
138+ {
139+ "type" : "text" ,
140+ "content" : "在经典的西部风格中,一个表情忧郁的男人凝视着镜头,微微颤抖的嘴唇吐出一口烟雾。他的香烟发出的温暖光芒照亮了他的脸,投下的阴影强调了他的忧郁情绪。他戴着宽边帽,穿着粗犷的衣服,配有弹带。他的靴子放在栏杆上,姿态放松,但眼神中透露出更深的悲伤。" ,
141+ "negative" : false ,
142+ "enhance" : false ,
143+ "recaption" : ""
144+ }
145+ ] ,
146+ "lang" : "zh"
147+ } ,
148+ "settings" : {
149+ "style" : "general" ,
150+ "duration" : 4 ,
151+ "aspect_ratio" : "16:9" ,
152+ "model" : "vidu-1"
153+ } ,
154+ "type" : "text2video" ,
155+ "state" : "success" ,
156+ "creations" : [
157+ {
158+ "id" : "2375646502238865" ,
159+ "task_id" : "2375646005579044" ,
160+ "type" : "video" ,
161+ "grade" : "draft" ,
162+ "uri" : "https://vidu.cf.vidu.studio/infer/tasks/24/0805/05/2375646005579044/creation-01/watermarked.mp4?Expires=1722838357&Signature=m4WAZQ~M3Xcwv2z3EBdHrRXWHakBXhxlaeCcI9DxjsDMf~DbcBS0h6S29A-EtymTyEUkYHJ6jFSIBt0kQitGvluT7oN5rA1H6zR~tVSUd6FM2jjRQg4FR0ff5P48I0pUtbnLNcyr2Kb-f873gNkm3WS78JTpsk0SZ1yObTFqoVBTaA2PX7FyttuEYES2Z8YrMPEVMRta0W9iV9GgB12N3cqzWrMAW9uNHftqH0T78Al4PCk9xv3TnjdZw9H3i3wyIE6kpBTfWeh2zBtNm2zzN6u5BGsX6ujPxX72X9JeRCIUpE~Rsj0dTPwJDARJhVPoTLbwvnchPdoOn3zHWQUfFA__&Key-Pair-Id=KNW0SL0E7LV4E&response-content-disposition=attachment;filename=vidu-1-general-4-2024-08-05T05%3A12%3A35Z.mp4" ,
163+ "cover_uri" : "https://vidu.cf.vidu.studio/infer/tasks/24/0805/05/2375646005579044/creation-01/cover.jpeg?Expires=1722838357&Signature=ppjg5IrEjp45-zU4w5H2cH~~ZP7AW4-n9kBpS0uOQnl2DiuWIAw6y517F9jk6smVu8Q8R~Mm0nscAvdCrNABc-p~lGmYmzBBSJknjrGZVjSlZuVifuzKDR2C93qI63A1ZOemXBDUs6Ogx0Z7qqanG4HthUj1yOrAXmdWQ-Fk1pjptbBfuPwKZUDrbfVpiJdQsux6tTrYRkK1esJU~1ooIGS-NXar20FD36qGbFycQ1dCs~eQhn1vCQJ63gDkhPhcd7HDrxaZDdsACNtpF-pQi-br7Ixo4GomM~LoSblA2tohPl2e1HH8G4L0zCvLEVj6mORbJU-R2Nj6YZ8UipErNw__&Key-Pair-Id=KNW0SL0E7LV4E" ,
164+ "resolution" : {
165+ "width" : 688 ,
166+ "height" : 384
167+ } ,
168+ "vote" : "unspecified" ,
169+ "is_favor" : false ,
170+ "src_video_duration" : 0 ,
171+ "creator_id" : "0" ,
172+ "video" : {
173+ "duration" : 3.85 ,
174+ "fps" : 16 ,
175+ "resolution" : {
176+ "width" : 688 ,
177+ "height" : 384
178+ }
179+ } ,
180+ "is_deleted" : false ,
181+ "err_code" : "" ,
182+ "created_at" : "2024-08-05T05:12:35.458210Z"
183+ }
184+ ] ,
185+ "err_code" : "" ,
186+ "created_at" : "2024-08-05T05:12:05.145617Z"
187+ }
188+ const vidu_task_upscale_request_example : ViduUpscaleTaskRequest = {
189+ "input" : {
190+ "creation_id" : "2375584778357517"
191+ } ,
192+ "type" : "upscale" ,
193+ "settings" : { "model" : "stable" , "duration" : 4 }
26194}
27195
28196export class ViduAPI {
@@ -36,6 +204,66 @@ export class ViduAPI {
36204 return [ api2ProviderBaseUrl . Vidu , endpoint ] . join ( "/" ) ;
37205 }
38206
207+ // 根据用户输入的提示,返回可选用的任务类型
208+ availableTaskTypes ( prompts : ViduTaskGenerationRequest [ "input" ] [ "prompts" ] , isUpscale = false ) {
209+ if ( isUpscale ) {
210+ return [ ViduTaskType . upscale ] ;
211+ }
212+ if ( Array . isArray ( prompts ) ) {
213+
214+ if ( prompts . length === 0 ) {
215+ return Object . values ( ViduTaskType ) ;
216+ }
217+
218+ if ( prompts . length === 1 ) {
219+ const prompt = prompts [ 0 ] ;
220+ if ( prompt . type === "text" ) {
221+ return [ ViduTaskType . text2video ] ;
222+ }
223+
224+ if ( prompt . type === "image" ) {
225+ return [ ViduTaskType . img2video , ViduTaskType . character2video ] ;
226+ }
227+ }
228+
229+ if ( prompts . length === 2 ) {
230+ return [ ViduTaskType . img2video , ViduTaskType . character2video ] ;
231+ }
232+ }
233+
234+ return [ ] ;
235+ }
236+
237+ // 根据用户输入的提示,返回可选用的风格
238+ availableStyles ( prompts : ViduTaskGenerationRequest [ "input" ] [ "prompts" ] ) {
239+ if ( Array . isArray ( prompts ) ) {
240+ if ( prompts . length === 0 ) {
241+ return Object . values ( ViduStyle ) ;
242+ }
243+
244+ if ( prompts . length === 1 ) {
245+ const prompt = prompts [ 0 ] ;
246+ if ( prompt . type === "text" ) {
247+ return [ ViduStyle . general , ViduStyle . anime ] ;
248+ }
249+
250+ if ( prompt . type === "image" ) {
251+ return [ ViduStyle . general , ] ;
252+ }
253+ }
254+
255+ if ( prompts . length === 2 ) {
256+ return [ ViduStyle . general ] ;
257+ }
258+ }
259+
260+ return [ ] ;
261+ }
262+
263+ availableModels ( isUpscale : boolean ) {
264+ return isUpscale ? [ ViduModel . stable ] : [ ViduModel . vidu1 ] ;
265+ }
266+
39267 async generateViduTask ( request : ViduTaskGenerationRequest , signal ?: AbortSignal , timeoutMs : number = 10000 ) {
40268 const controller = new AbortController ( ) ;
41269 const timeoutId = setTimeout ( ( ) => controller . abort ( ) , timeoutMs ) ;
@@ -58,7 +286,29 @@ export class ViduAPI {
58286 }
59287 }
60288
61- async getViduTask ( id : string , signal ?: AbortSignal , timeoutMs : number = 10000 ) {
289+ async submitUpscaleTask ( request : ViduUpscaleTaskRequest , signal ?: AbortSignal , timeoutMs : number = 10000 ) {
290+ const controller = new AbortController ( ) ;
291+ const timeoutId = setTimeout ( ( ) => controller . abort ( ) , timeoutMs ) ;
292+ const abortSignal = signal || controller . signal ;
293+
294+ signal && signal . addEventListener ( "abort" , ( ) => controller . abort ( ) ) ;
295+
296+ try {
297+ const res = await fetch ( this . path ( ViduEndpoint . GENERATION ) , {
298+ ...getRequestOptions ( this . apiKey , request ) ,
299+ signal : abortSignal
300+ } ) ;
301+
302+ clearTimeout ( timeoutId ) ;
303+
304+ return res ;
305+ } catch ( e ) {
306+ console . error ( "[ViduProxy] failed to make a vidu upscale-task request" , e ) ;
307+ throw e ;
308+ }
309+ }
310+
311+ async getViduTask ( id : ViduTaskGenerationResponse [ "id" ] , signal ?: AbortSignal , timeoutMs : number = 10000 ) {
62312 const controller = new AbortController ( ) ;
63313 const timeoutId = setTimeout ( ( ) => controller . abort ( ) , timeoutMs ) ;
64314 const abortSignal = signal || controller . signal ;
@@ -67,7 +317,7 @@ export class ViduAPI {
67317
68318 try {
69319 const res = await fetch ( this . path ( ViduEndpoint . TASK_GET ) . replace ( "{{id}}" , id ) , {
70- ...getRequestOptions ( this . apiKey , "GET" ) ,
320+ ...getRequestOptions ( this . apiKey , "GET" ) ,
71321 signal : abortSignal
72322 } ) ;
73323
0 commit comments