feat: add Chatterbox model support for Cloud asset browser

- Register Chatterbox TTS node mappings in modelToNodeStore:
  - chatterbox/chatterbox → FL_ChatterboxTTS
  - chatterbox/chatterbox_turbo → FL_ChatterboxTurboTTS
  - chatterbox/chatterbox_multilingual → FL_ChatterboxMultilingualTTS
  - chatterbox/chatterbox_vc → FL_ChatterboxVC

- Add hierarchical fallback in findProvidersWithFallback() for model
  type lookups (e.g., 'parent/child' falls back to 'parent')

- Support empty widget key for auto-load nodes (skip widget assignment
  in createModelNodeFromAsset when provider.key is empty)

- Add comprehensive tests for new behavior

Co-authored-by: Amp <amp@ampcode.com>
Amp-Thread-ID: https://ampcode.com/threads/T-019c0849-5650-7060-b4bd-23ef0c8dfa39
This commit is contained in:
Subagent 5
2026-01-28 23:24:59 -08:00
parent dd3e4d3edc
commit 050868c7d2
4 changed files with 131 additions and 24 deletions

View File

@@ -9,7 +9,7 @@ export class ModelNodeProvider {
/** The node definition to use for this model. */
public nodeDef: ComfyNodeDefImpl
/** The node input key for where to inside the model name. */
/** The node input key for where to insert the model name. */
public key: string
constructor(nodeDef: ComfyNodeDefImpl, key: string) {
@@ -73,23 +73,45 @@ export const useModelToNodeStore = defineStore('modelToNode', () => {
return nodeTypeToCategory.value[nodeType]
}
/**
* Find providers for modelType with hierarchical fallback.
* Tries exact match first, then falls back to top-level segment (e.g., "parent/child" → "parent").
* Note: Only falls back one level; "a/b/c" tries "a/b/c" then "a", not "a/b".
*/
function findProvidersWithFallback(
modelType: string
): ModelNodeProvider[] | undefined {
const exactMatch = modelToNodeMap.value[modelType]
if (exactMatch && exactMatch.length > 0) return exactMatch
const topLevel = modelType.split('/')[0]
if (topLevel !== modelType) {
const fallback = modelToNodeMap.value[topLevel]
if (fallback && fallback.length > 0) return fallback
}
return undefined
}
/**
* Get the node provider for the given model type name.
* Supports hierarchical lookups: if "parent/child" has no match, falls back to "parent".
* @param modelType The name of the model type to get the node provider for.
* @returns The node provider for the given model type name.
*/
function getNodeProvider(modelType: string): ModelNodeProvider | undefined {
registerDefaults()
return modelToNodeMap.value[modelType]?.[0]
return findProvidersWithFallback(modelType)?.[0]
}
/**
* Get the list of all valid node providers for the given model type name.
* Supports hierarchical lookups: if "parent/child" has no match, falls back to "parent".
* @param modelType The name of the model type to get the node providers for.
* @returns The list of all valid node providers for the given model type name.
*/
function getAllNodeProviders(modelType: string): ModelNodeProvider[] {
registerDefaults()
return modelToNodeMap.value[modelType] ?? []
return findProvidersWithFallback(modelType) ?? []
}
/**
* Register a node provider for the given model type name.
@@ -153,6 +175,17 @@ export const useModelToNodeStore = defineStore('modelToNode', () => {
'ADE_AnimateDiffLoRALoader',
'name'
)
// Chatterbox TTS nodes: empty key means the node auto-loads models without
// a widget selector (createModelNodeFromAsset skips widget assignment)
quickRegister('chatterbox/chatterbox', 'FL_ChatterboxTTS', '')
quickRegister('chatterbox/chatterbox_turbo', 'FL_ChatterboxTurboTTS', '')
quickRegister(
'chatterbox/chatterbox_multilingual',
'FL_ChatterboxMultilingualTTS',
''
)
quickRegister('chatterbox/chatterbox_vc', 'FL_ChatterboxVC', '')
}
return {