@@ -56,12 +56,30 @@ export function buildHomeMediaComposer(
5656 } = { } ,
5757) : HomeMediaComposerState {
5858 const imageModels = options . imageModels ?? IMAGE_MODELS ;
59+ const defaultInputs = defaultInputsForSurface ( surface , promptTemplates , imageModels ) ;
60+ const seededInputs = {
61+ ...defaultInputs ,
62+ ...seedInputs ,
63+ } ;
64+ const templateAwareInputs = surface === 'image'
65+ ? homeMediaInputsAfterTemplateChange (
66+ surface ,
67+ seedInputs ,
68+ {
69+ ...seededInputs ,
70+ template : validTemplateId (
71+ surface ,
72+ stringValue ( seededInputs . template ) ,
73+ promptTemplates ,
74+ ) ,
75+ } ,
76+ promptTemplates ,
77+ imageModels ,
78+ )
79+ : seededInputs ;
5980 const inputs = normalizeHomeMediaInputs (
6081 surface ,
61- {
62- ...defaultInputsForSurface ( surface , promptTemplates ) ,
63- ...seedInputs ,
64- } ,
82+ templateAwareInputs ,
6583 promptTemplates ,
6684 voiceOptions ,
6785 imageModels ,
@@ -88,14 +106,15 @@ export function normalizeHomeMediaInputs(
88106) : Record < string , unknown > {
89107 if ( surface === 'image' ) {
90108 const ratio = validOption ( stringValue ( raw . ratio ) || stringValue ( raw . aspect ) , MEDIA_ASPECTS , '16:9' ) ;
109+ const rawModel = stringValue ( raw . model ) ;
91110 return {
92111 mediaKind : 'image' ,
93112 subject : stringValue ( raw . subject ) || 'a premium product concept' ,
94113 style : stringValue ( raw . style ) || 'premium product-studio, elegant composition, refined lighting, restrained color' ,
95114 aspect : ratio ,
96115 template : validTemplateId ( surface , stringValue ( raw . template ) , promptTemplates ) ,
97116 designSystem : stringValue ( raw . designSystem ) || 'the active project design system' ,
98- model : validOption ( stringValue ( raw . model ) , imageModels . map ( ( m ) => m . id ) , DEFAULT_IMAGE_MODEL ) ,
117+ model : validImageModel ( rawModel , imageModels ) ? rawModel : DEFAULT_IMAGE_MODEL ,
99118 ratio,
100119 resolution : validOption ( stringValue ( raw . resolution ) , MEDIA_RESOLUTIONS , DEFAULT_MEDIA_RESOLUTION ) ,
101120 } ;
@@ -191,9 +210,14 @@ export function metadataForHomeMediaComposer(
191210 // run aligned with the model shown in the Home composer.
192211 if ( surface === 'image' ) {
193212 const imageModel = stringValue ( inputs . model ) ;
213+ const selectedAspect = stringValue ( inputs . aspect ) ;
214+ const imageAspect = template && validImageTemplateAspect ( selectedAspect )
215+ ? selectedAspect
216+ : null ;
194217 return {
195218 kind : 'image' ,
196219 ...( imageModel ? { imageModel } : { } ) ,
220+ ...( imageAspect ? { imageAspect } : { } ) ,
197221 ...( promptTemplate ? { promptTemplate } : { } ) ,
198222 } ;
199223 }
@@ -209,6 +233,38 @@ export function metadataForHomeMediaComposer(
209233 } ;
210234}
211235
236+ export function homeMediaInputsAfterTemplateChange (
237+ surface : HomeComposerMediaSurface ,
238+ previousInputs : Record < string , unknown > ,
239+ nextInputs : Record < string , unknown > ,
240+ promptTemplates : PromptTemplateSummary [ ] ,
241+ imageModels : MediaModel [ ] = IMAGE_MODELS ,
242+ ) : Record < string , unknown > {
243+ if (
244+ surface !== 'image'
245+ || stringValue ( previousInputs . template ) === stringValue ( nextInputs . template )
246+ ) {
247+ return nextInputs ;
248+ }
249+
250+ const template = promptTemplates . find (
251+ ( item ) => item . surface === 'image' && item . id === stringValue ( nextInputs . template ) ,
252+ ) ;
253+ if ( ! template ) return nextInputs ;
254+
255+ const model = validImageModel ( template . model , imageModels )
256+ ? template . model
257+ : null ;
258+ const aspect = validImageTemplateAspect ( template . aspect )
259+ ? template . aspect
260+ : null ;
261+ return {
262+ ...nextInputs ,
263+ ...( model ? { model } : { } ) ,
264+ ...( aspect ? { aspect, ratio : aspect } : { } ) ,
265+ } ;
266+ }
267+
212268export function templatesForHomeMediaSurface (
213269 surface : HomeComposerMediaSurface ,
214270 promptTemplates : PromptTemplateSummary [ ] ,
@@ -309,13 +365,22 @@ function queryTemplateForSurface(surface: HomeComposerMediaSurface, inputs: Reco
309365function defaultInputsForSurface (
310366 surface : HomeComposerMediaSurface ,
311367 promptTemplates : PromptTemplateSummary [ ] ,
368+ imageModels : MediaModel [ ] = IMAGE_MODELS ,
312369) : Record < string , unknown > {
313370 if ( surface === 'image' ) {
371+ const template = templatesForHomeMediaSurface ( surface , promptTemplates ) [ 0 ] ?? null ;
372+ const model = template && validImageModel ( template . model , imageModels )
373+ ? template . model
374+ : DEFAULT_IMAGE_MODEL ;
375+ const aspect = template && validImageTemplateAspect ( template . aspect )
376+ ? template . aspect
377+ : '16:9' ;
314378 return {
315- template : firstTemplateId ( surface , promptTemplates ) ,
379+ template : template ?. id ?? NO_TEMPLATE_PLACEHOLDER ,
316380 designSystem : 'the active project design system' ,
317- model : DEFAULT_IMAGE_MODEL ,
318- ratio : '16:9' ,
381+ model,
382+ aspect,
383+ ratio : aspect ,
319384 resolution : DEFAULT_MEDIA_RESOLUTION ,
320385 } ;
321386 }
@@ -337,6 +402,22 @@ function defaultInputsForSurface(
337402 return { text : 'the user\'s brief' , audioType : 'speech' , model : defaultHomeAudioModel ( 'speech' ) , duration : 10 } ;
338403}
339404
405+ function validImageModel (
406+ model : string | undefined ,
407+ imageModels : MediaModel [ ] ,
408+ ) : model is string {
409+ return Boolean (
410+ model
411+ && ( imageModels . some ( ( item ) => item . id === model ) || model . startsWith ( 'aihubmix-' ) ) ,
412+ ) ;
413+ }
414+
415+ function validImageTemplateAspect (
416+ aspect : string | undefined ,
417+ ) : aspect is ( typeof MEDIA_ASPECTS ) [ number ] {
418+ return Boolean ( aspect && ( MEDIA_ASPECTS as readonly string [ ] ) . includes ( aspect ) ) ;
419+ }
420+
340421function stringField ( name : string , label : string , placeholder ?: string ) : InputFieldSpec {
341422 return {
342423 name,
0 commit comments