Add guided FLUX Klein component setup and tested image pipeline

This commit is contained in:
Mikei386
2026-09-28 23:16:01 +02:00
parent 43c8d6456c
commit 9fecb30a8f
8 changed files with 95 additions and 26 deletions
+22 -10
View File
@@ -39,6 +39,17 @@ QWEN_COMPONENTS={
'text_encoder':{'label':'Textencoder','files':['text_encoders/qwen3vl_8b_int8_convrot.safetensors','text_encoders/qwen3vl_8b_bf16.safetensors']},
'vae':{'label':'VAE','files':['vae/qwen_image_2.1_vae_bf16.safetensors']}
}
FLUX_REPO='RunningHubAI/rh-flux.2-klein-9b-fp16-unet-2067980602644717569'
FLUX_COMPONENT_REPO='Comfy-Org/flux2-klein-9B'
FLUX_COMPONENTS={
'text_encoder':{'label':'Textencoder für FLUX.2 Klein 9B','repo':FLUX_COMPONENT_REPO,'files':['split_files/text_encoders/qwen_3_8b_fp8mixed.safetensors']},
'vae':{'label':'VAE für FLUX.2','repo':FLUX_COMPONENT_REPO,'files':['split_files/vae/flux2-vae.safetensors']}
}
def image_recipe(model):
if model['repo']==QWEN_REPO and model['file'].endswith('.gguf'):return QWEN_COMPONENTS
if model['repo']==FLUX_REPO and model['file']=='Flux.2 Klein-9B_fp16_nsfw.safetensors':return FLUX_COMPONENTS
return None
class Profiles:
def __init__(self,path,catalog):
self.path=Path(path);self.catalog=catalog;self.lock=threading.RLock()
@@ -53,13 +64,13 @@ class Profiles:
try:
p['model']=self.catalog.entry(p['model_id'])
p['blockers']=['Für dieses Profil ist noch kein ausführbarer Worker angebunden.']
if p['kind']=='image' and 'qwen-image-2.1' in p['model']['repo'].lower():
if p['kind']=='image' and (image_recipe(p['model']) or 'qwen-image-2.1' in p['model']['repo'].lower()):
p['blockers']=['Eine eigene Bildlaufzeit muss eingerichtet werden; llama.cpp führt keine Bildmodelle aus.']
for role,info in reversed(list(QWEN_COMPONENTS.items())):
for role,info in reversed(list((image_recipe(p['model']) or QWEN_COMPONENTS).items())):
try:self._component(p['model'],role,p.get('components',{}).get(role))
except ValueError:p['blockers'].insert(0,info['label']+' fehlt oder ist noch nicht zugeordnet.')
except ValueError as exc:p['model']=None;p['blockers']=[str(exc)]
if p.get('model') and p['model']['repo']==QWEN_REPO and p['model']['file'].endswith('.gguf') and self.image_runtime_ready():
if p.get('model') and image_recipe(p['model']) and self.image_runtime_ready():
p['blockers']=[b for b in p['blockers'] if not b.startswith('Eine eigene Bildlaufzeit')]
if p['kind']=='chat' and self.chat_blockers and p.get('model'):p['blockers']=self.chat_blockers(p)
if p['kind']=='image' and (p['parameters']['width']>1024 or p['parameters']['height']>1024):p['blockers'].append('Die Bildlaufzeit unterstützt derzeit maximal 1024 × 1024 Pixel.')
@@ -106,24 +117,25 @@ class Profiles:
return {'deleted':old['id']}
def _component(self,model,role,ident):
if model['repo']!=QWEN_REPO or role not in QWEN_COMPONENTS:raise ValueError('Für dieses Modell ist kein geprüftes Komponentenrezept hinterlegt.')
recipe=image_recipe(model)
if not recipe or role not in recipe:raise ValueError('Für dieses Modell ist kein geprüftes Komponentenrezept hinterlegt.')
item=self.catalog.entry(ident)
if item['repo']!=QWEN_REPO or item['kind']!='image' or item['file'] not in QWEN_COMPONENTS[role]['files']:raise ValueError('Die Datei gehört nicht zu dieser Komponente des Modells.')
if item['repo']!=recipe[role].get('repo',model['repo']) or item['kind']!='image' or item['file'] not in recipe[role]['files']:raise ValueError('Die Datei gehört nicht zu dieser Komponente des Modells.')
return item
def components(self,model_id):
model=self.catalog.entry(model_id)
if model['repo']!=QWEN_REPO or model['kind']!='image':return dict(supported=False,requirements=[],message='Für dieses Modell ist noch kein Komponentenrezept hinterlegt. Keine automatische Zuordnung.')
source=self.catalog.files(QWEN_REPO);entries=self.catalog.status()['entries'];requirements=[]
for role,info in QWEN_COMPONENTS.items():
if not image_recipe(model) or model['kind']!='image':return dict(supported=False,requirements=[],message='Für dieses Modell ist noch kein Komponentenrezept hinterlegt. Keine automatische Zuordnung.')
recipe=image_recipe(model);source=self.catalog.files(next(iter(recipe.values())).get('repo',model['repo']));entries=self.catalog.status()['entries'];requirements=[]
for role,info in recipe.items():
available=[]
for item in entries:
try:
self._component(model,role,item['id']);available.append(item)
except ValueError:pass
candidates=[dict(f,repo=QWEN_REPO,revision=source['revision'],gated=source['gated']) for name in info['files'] for f in source['files'] if f['name']==name]
candidates=[dict(f,repo=source.get('repo',info.get('repo',model['repo'])),revision=source['revision'],gated=source['gated']) for name in info['files'] for f in source['files'] if f['name']==name]
requirements.append(dict(role=role,label=info['label'],available=available,candidates=candidates))
return dict(supported=True,requirements=requirements,source=source['url'],license=source['license'],runtime='ComfyUI + ComfyUI-GGUF',runtime_installed=self.image_runtime_ready(),
message='Zusatzdateien laut Modellkarte für ComfyUI. Kompatibilität und Speicherbedarf müssen mit der eingerichteten Laufzeit noch praktisch geprüft werden.')
message='Fehlende Dateien herunterladen, danach Bibliothek aktualisieren und zuordnen. Für FLUX.2 Klein empfehlen sich zum Einstieg 4 Schritte und Guidance 1. Die Bildgewichte werden bei Bedarf zwischen RAM und RTX 5080 verschoben.' if model['repo']==FLUX_REPO else 'Zusatzdateien laut Modellkarte für ComfyUI. Kompatibilität und Speicherbedarf müssen mit der eingerichteten Laufzeit noch praktisch geprüft werden.')
def assign(self,data):
if set(data)!={'id','revision','components'} or not isinstance(data['components'],dict) or set(data['components'])-set(QWEN_COMPONENTS):raise ValueError('Ungültige Komponentenzuordnung.')
with self.lock: