@@ -24,9 +24,8 @@ import { BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT, BOOL_FLAG_WATERMARK } from "bailia
2424
2525export default defineCommand ( {
2626 description : {
27- "en-US" :
28- "Generate a video from text or image (happyhorse-1.1-t2v / happyhorse-1.1-i2v / wan2.6-t2v)" ,
29- "zh-CN" : "根据文本或图片生成视频(happyhorse-1.1-t2v / happyhorse-1.1-i2v / wan2.6-t2v)" ,
27+ "en-US" : "Generate a video from text or image (wan3.0-video / wan2.6-t2v / happyhorse-1.1-i2v)" ,
28+ "zh-CN" : "根据文本或图片生成视频(wan3.0-video / wan2.6-t2v / happyhorse-1.1-i2v)" ,
3029 } ,
3130 auth : "apiKey" ,
3231 usageArgs : "--prompt <text> [--image <url>] [flags]" ,
@@ -35,8 +34,8 @@ export default defineCommand({
3534 type : "string" ,
3635 valueHint : "<model>" ,
3736 description : {
38- "en-US" : "Model ID (default: happyhorse-1.1-t2v, or happyhorse-1.1-i2v with --image )" ,
39- "zh-CN" : "模型 ID(默认:happyhorse-1.1-t2v;使用 --image 时为 happyhorse-1.1-i2v )" ,
37+ "en-US" : "Model ID (default: wan3.0-video )" ,
38+ "zh-CN" : "模型 ID(默认:wan3.0-video )" ,
4039 } ,
4140 } ,
4241 prompt : {
@@ -119,6 +118,16 @@ export default defineCommand({
119118 "zh-CN" : "完成后将视频保存到文件" ,
120119 } ,
121120 } ,
121+ file : {
122+ type : "string" ,
123+ valueHint : "<url-or-path>" ,
124+ description : {
125+ "en-US" :
126+ "Reference file URL or local path for file-to-video (wan3.0-video only; mutually exclusive with --image/--last-frame)" ,
127+ "zh-CN" :
128+ "参考文件 URL 或本地路径,用于文件生视频(仅 wan3.0-video;与 --image/--last-frame 互斥)" ,
129+ } ,
130+ } ,
122131 ...ASYNC_FLAG ,
123132 ...CONCURRENT_FLAG ,
124133 pollInterval : {
@@ -159,12 +168,20 @@ export default defineCommand({
159168 const model =
160169 flags . model ||
161170 ( flags . image
162- ? settings . defaultImageToVideoModel || "happyhorse-1.1-i2v "
163- : settings . defaultVideoModel || "happyhorse-1.1-t2v " ) ;
171+ ? settings . defaultImageToVideoModel || "wan3.0-video "
172+ : settings . defaultVideoModel || "wan3.0-video " ) ;
164173 const format = detectOutputFormat ( settings . output ) ;
165174
166175 const imageUrl = flags . image ;
167176 const lastFrameUrl = flags . lastFrame as string | undefined ;
177+ const fileUrl = flags . file as string | undefined ;
178+
179+ if ( fileUrl && ( imageUrl || lastFrameUrl ) ) {
180+ throw new BailianError (
181+ "--file is mutually exclusive with --image/--last-frame." ,
182+ ExitCode . USAGE ,
183+ ) ;
184+ }
168185
169186 // Auto-upload local image file for i2v
170187 let resolvedImageUrl : string | undefined ;
@@ -178,6 +195,18 @@ export default defineCommand({
178195
179196 // kf2v mode: both --image and --last-frame provided.
180197 const isKf2v = Boolean ( resolvedImageUrl && resolvedLastFrameUrl ) ;
198+ // 万相 3.x(All-in-One)首尾帧走 media[];旧 kf2v 仍走 image2video 平铺字段。
199+ // 与 video/ref.ts 的 useReferenceAudio 保持同一判定:忽略大小写、覆盖 wan3.x 系列。
200+ const isWan30 = / ^ w a n 3 \. / i. test ( model ) ;
201+
202+ if ( fileUrl && ! isWan30 ) {
203+ throw new BailianError ( "--file is only supported by wan3.0-video." , ExitCode . USAGE ) ;
204+ }
205+
206+ let resolvedFileUrl : string | undefined ;
207+ if ( fileUrl ) {
208+ resolvedFileUrl = await ctx . client . uploadFile ( fileUrl , model ) ;
209+ }
181210
182211 const watermark = resolveWatermark ( flags . watermark ) ;
183212 const promptExtend = resolveBooleanFlag ( flags . promptExtend , undefined , "prompt-extend" ) ;
@@ -187,16 +216,26 @@ export default defineCommand({
187216 input : {
188217 prompt : prompt ,
189218 negative_prompt : flags . negativePrompt || undefined ,
190- // kf2v: first+last frame flat fields via image2video endpoint.
219+ // wan3.0 kf2v: media[first_frame, last_frame] via video-generation endpoint.
220+ // legacy kf2v: first_frame_url/last_frame_url via image2video endpoint.
191221 // wan2.1~2.6 i2v: flat img_url via video-generation endpoint.
192222 // wan2.7+ / happyhorse i2v: media[] via video-generation endpoint.
193- ...( isKf2v
194- ? { first_frame_url : resolvedImageUrl , last_frame_url : resolvedLastFrameUrl }
195- : resolvedImageUrl
196- ? / w a n [ x ] ? 2 \. [ 1 - 6 ] / i. test ( model )
197- ? { img_url : resolvedImageUrl }
198- : { media : [ { type : "first_frame" as const , url : resolvedImageUrl } ] }
199- : { } ) ,
223+ ...( resolvedFileUrl
224+ ? { media : [ { type : "file" as const , url : resolvedFileUrl } ] }
225+ : isKf2v
226+ ? isWan30
227+ ? {
228+ media : [
229+ { type : "first_frame" as const , url : resolvedImageUrl ! } ,
230+ { type : "last_frame" as const , url : resolvedLastFrameUrl ! } ,
231+ ] ,
232+ }
233+ : { first_frame_url : resolvedImageUrl , last_frame_url : resolvedLastFrameUrl }
234+ : resolvedImageUrl
235+ ? / w a n [ x ] ? 2 \. [ 1 - 6 ] / i. test ( model )
236+ ? { img_url : resolvedImageUrl }
237+ : { media : [ { type : "first_frame" as const , url : resolvedImageUrl } ] }
238+ : { } ) ,
200239 } ,
201240 parameters : {
202241 resolution : flags . resolution || undefined ,
@@ -210,13 +249,29 @@ export default defineCommand({
210249
211250 if ( settings . dryRun ) {
212251 let previewBody = body ;
213- if ( isKf2v ) {
252+ if ( resolvedFileUrl ) {
253+ previewBody = {
254+ ...body ,
255+ input : {
256+ ...body . input ,
257+ media : [ { type : "file" as const , url : redactDataUri ( resolvedFileUrl ) } ] ,
258+ } ,
259+ } ;
260+ } else if ( isKf2v ) {
261+ const redactedFirst = redactDataUri ( resolvedImageUrl ?? "" ) ;
262+ const redactedLast = redactDataUri ( resolvedLastFrameUrl ?? "" ) ;
214263 previewBody = {
215264 ...body ,
216265 input : {
217266 ...body . input ,
218- first_frame_url : redactDataUri ( resolvedImageUrl ?? "" ) ,
219- last_frame_url : redactDataUri ( resolvedLastFrameUrl ?? "" ) ,
267+ ...( isWan30
268+ ? {
269+ media : [
270+ { type : "first_frame" as const , url : redactedFirst } ,
271+ { type : "last_frame" as const , url : redactedLast } ,
272+ ] ,
273+ }
274+ : { first_frame_url : redactedFirst , last_frame_url : redactedLast } ) ,
220275 } ,
221276 } ;
222277 } else if ( resolvedImageUrl ) {
@@ -243,7 +298,7 @@ export default defineCommand({
243298 settings ,
244299 ( ) =>
245300 ctx . client . requestJson < DashScopeAsyncResponse > ( {
246- path : isKf2v ? image2videoPath ( ) : videoGeneratePath ( ) ,
301+ path : isKf2v && ! isWan30 ? image2videoPath ( ) : videoGeneratePath ( ) ,
247302 method : "POST" ,
248303 body,
249304 async : true ,
0 commit comments