@@ -8,15 +8,15 @@ import { formatOutput, detectOutputFormat } from '../../output/formatter';
88import type { Config } from '../../config/schema' ;
99import type { GlobalFlags } from '../../types/flags' ;
1010import type { ImageRequest , ImageResponse } from '../../types/api' ;
11- import { mkdirSync , existsSync , readFileSync } from 'fs' ;
11+ import { mkdirSync , existsSync , readFileSync , writeFileSync } from 'fs' ;
1212import { dirname , join , resolve , extname } from 'path' ;
13+ import { isInteractive } from '../../utils/env' ;
14+ import { promptText , failIfMissing } from '../../utils/prompt' ;
1315
1416const MIME_TYPES : Record < string , string > = {
1517 '.jpg' : 'image/jpeg' , '.jpeg' : 'image/jpeg' ,
1618 '.png' : 'image/png' , '.webp' : 'image/webp' ,
1719} ;
18- import { isInteractive } from '../../utils/env' ;
19- import { promptText , failIfMissing } from '../../utils/prompt' ;
2020
2121export default defineCommand ( {
2222 name : 'image generate' ,
@@ -34,6 +34,7 @@ export default defineCommand({
3434 { flag : '--aigc-watermark' , description : 'Embed AI-generated content watermark in the output image.' } ,
3535 { flag : '--subject-ref <params>' , description : 'Subject reference for character consistency. Format: type=character,image=path-or-url' } ,
3636 { flag : '--out <path>' , description : 'Save image to exact file path (single image only)' } ,
37+ { flag : '--response-format <format>' , description : 'Response format: url (download), base64 (embed). Default: url' } ,
3738 { flag : '--out-dir <dir>' , description : 'Download images to directory' } ,
3839 { flag : '--out-prefix <prefix>' , description : 'Filename prefix (default: image)' } ,
3940 ] ,
@@ -49,6 +50,8 @@ export default defineCommand({
4950 'mmx image generate --prompt "sunset" --prompt-optimizer --aigc-watermark' ,
5051 '# Save to exact path' ,
5152 'mmx image generate --prompt "A cat" --out /tmp/cat.jpg' ,
53+ '# Base64 response (bypasses CDN, useful when image URLs are unreachable)' ,
54+ 'mmx image generate --prompt "A cat" --response-format base64' ,
5255 ] ,
5356 async run ( config : Config , flags : GlobalFlags ) {
5457 let prompt = ( flags . prompt ?? ( flags . _positional as string [ ] | undefined ) ?. [ 0 ] ) as string | undefined ;
@@ -96,6 +99,8 @@ export default defineCommand({
9699 throw new CLIError ( '--out cannot be used with --n > 1. Use --out-dir instead.' , ExitCode . USAGE ) ;
97100 }
98101
102+ const responseFormat = ( flags . responseFormat as 'url' | 'base64' | undefined ) || 'url' ;
103+
99104 const body : ImageRequest = {
100105 model : 'image-01' ,
101106 prompt,
@@ -106,6 +111,7 @@ export default defineCommand({
106111 height : height ,
107112 prompt_optimizer : flags . promptOptimizer === true || undefined ,
108113 aigc_watermark : flags . aigcWatermark === true || undefined ,
114+ response_format : responseFormat ,
109115 } ;
110116
111117 if ( flags . subjectRef ) {
@@ -151,8 +157,6 @@ export default defineCommand({
151157 body,
152158 } ) ;
153159
154- const imageUrls = response . data . image_urls || [ ] ;
155-
156160 if ( ! config . quiet ) {
157161 process . stderr . write ( '[Model: image-01]\n' ) ;
158162 }
@@ -166,21 +170,41 @@ export default defineCommand({
166170 if ( existsSync ( destPath ) ) {
167171 process . stderr . write ( `Warning: overwriting existing file: ${ destPath } \n` ) ;
168172 }
169- await downloadFile ( imageUrls [ 0 ] ! , destPath , { quiet : config . quiet } ) ;
173+ if ( responseFormat === 'base64' ) {
174+ const image = ( response . data . image_base64 || [ ] ) [ 0 ] ;
175+ if ( image ) writeFileSync ( destPath , image , 'base64' ) ;
176+ } else {
177+ const imageUrl = ( response . data . image_urls || [ ] ) [ 0 ] ;
178+ if ( imageUrl ) await downloadFile ( imageUrl , destPath , { quiet : config . quiet } ) ;
179+ }
170180 saved . push ( destPath ) ;
171181 } else {
172182 const outDir = ( flags . outDir as string | undefined ) ?? '.' ;
173183 if ( ! existsSync ( outDir ) ) mkdirSync ( outDir , { recursive : true } ) ;
174184 const prefix = ( flags . outPrefix as string ) || 'image' ;
175185
176- for ( let i = 0 ; i < imageUrls . length ; i ++ ) {
177- const filename = `${ prefix } _${ String ( i + 1 ) . padStart ( 3 , '0' ) } .jpg` ;
178- const destPath = join ( outDir , filename ) ;
179- if ( existsSync ( destPath ) ) {
180- process . stderr . write ( `Warning: overwriting existing file: ${ destPath } \n` ) ;
186+ if ( responseFormat === 'base64' ) {
187+ const images = response . data . image_base64 || [ ] ;
188+ for ( let i = 0 ; i < images . length ; i ++ ) {
189+ const filename = `${ prefix } _${ String ( i + 1 ) . padStart ( 3 , '0' ) } .jpg` ;
190+ const destPath = join ( outDir , filename ) ;
191+ if ( existsSync ( destPath ) ) {
192+ process . stderr . write ( `Warning: overwriting existing file: ${ destPath } \n` ) ;
193+ }
194+ writeFileSync ( destPath , images [ i ] ! , 'base64' ) ;
195+ saved . push ( destPath ) ;
196+ }
197+ } else {
198+ const imageUrls = response . data . image_urls || [ ] ;
199+ for ( let i = 0 ; i < imageUrls . length ; i ++ ) {
200+ const filename = `${ prefix } _${ String ( i + 1 ) . padStart ( 3 , '0' ) } .jpg` ;
201+ const destPath = join ( outDir , filename ) ;
202+ if ( existsSync ( destPath ) ) {
203+ process . stderr . write ( `Warning: overwriting existing file: ${ destPath } \n` ) ;
204+ }
205+ await downloadFile ( imageUrls [ i ] ! , destPath , { quiet : config . quiet } ) ;
206+ saved . push ( destPath ) ;
181207 }
182- await downloadFile ( imageUrls [ i ] ! , destPath , { quiet : config . quiet } ) ;
183- saved . push ( destPath ) ;
184208 }
185209 }
186210
0 commit comments