Skip to content

Commit 6ea7401

Browse files
committed
feat: photoMaker in imageInference, IIpAdapter (guideImages, etc.), IEmbedding weight, dict coercion for nested options
1 parent 9df0226 commit 6ea7401

2 files changed

Lines changed: 78 additions & 28 deletions

File tree

runware/base.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,9 @@ async def _imageInference(
734734
ip_adapter_data = {
735735
k: v for k, v in vars(ip_adapter).items() if v is not None
736736
}
737-
if "guideImage" in ip_adapter_data:
737+
if "guideImages" in ip_adapter_data:
738+
ip_adapter_data["guideImages"] = await process_image(ip_adapter_data["guideImages"])
739+
elif "guideImage" in ip_adapter_data:
738740
ip_adapter_data["guideImage"] = await process_image(ip_adapter_data["guideImage"])
739741
ip_adapters_data.append(ip_adapter_data)
740742

@@ -762,9 +764,17 @@ async def _imageInference(
762764
if requestImage.puLID.inputImages:
763765
pulid_data["inputImages"] = await process_image(requestImage.puLID.inputImages)
764766

767+
photo_maker_data = {}
768+
if requestImage.photoMaker:
769+
photo_maker_data = {"images": []}
770+
if requestImage.photoMaker.style is not None:
771+
photo_maker_data["style"] = requestImage.photoMaker.style
772+
if requestImage.photoMaker.images:
773+
photo_maker_data["images"] = await process_image(requestImage.photoMaker.images)
774+
765775
request_object = self._buildImageRequest(
766776
requestImage, prompt, control_net_data_dicts,
767-
instant_id_data, ip_adapters_data, ace_plus_plus_data, pulid_data
777+
instant_id_data, ip_adapters_data, ace_plus_plus_data, pulid_data, photo_maker_data
768778
)
769779

770780
delivery_method_enum = EDeliveryMethod(requestImage.deliveryMethod) if isinstance(requestImage.deliveryMethod,
@@ -2356,7 +2366,7 @@ def is_text_complete(r: "Dict[str, Any]") -> bool:
23562366
finally:
23572367
await self._unregister_pending_operation(task_uuid)
23582368

2359-
def _buildImageRequest(self, requestImage: IImageInference, prompt: Optional[str], control_net_data_dicts: List[Dict], instant_id_data: Optional[Dict], ip_adapters_data: Optional[List[Dict]], ace_plus_plus_data: Optional[Dict], pulid_data: Optional[Dict]) -> Dict[str, Any]:
2369+
def _buildImageRequest(self, requestImage: IImageInference, prompt: Optional[str], control_net_data_dicts: List[Dict], instant_id_data: Optional[Dict], ip_adapters_data: Optional[List[Dict]], ace_plus_plus_data: Optional[Dict], pulid_data: Optional[Dict], photo_maker_data: Optional[Dict]) -> Dict[str, Any]:
23602370
request_object = {
23612371
"taskType": ETaskType.IMAGE_INFERENCE.value,
23622372
"taskUUID": requestImage.taskUUID,
@@ -2368,7 +2378,7 @@ def _buildImageRequest(self, requestImage: IImageInference, prompt: Optional[str
23682378
request_object["positivePrompt"] = prompt
23692379

23702380
self._addOptionalImageFields(request_object, requestImage)
2371-
self._addImageSpecialFields(request_object, requestImage, control_net_data_dicts, instant_id_data, ip_adapters_data, ace_plus_plus_data, pulid_data)
2381+
self._addImageSpecialFields(request_object, requestImage, control_net_data_dicts, instant_id_data, ip_adapters_data, ace_plus_plus_data, pulid_data, photo_maker_data)
23722382
self._addOptionalField(request_object, requestImage.inputs)
23732383
self._addImageProviderSettings(request_object, requestImage)
23742384
self._addOptionalField(request_object, requestImage.ultralytics)
@@ -2396,7 +2406,7 @@ def _addOptionalImageFields(self, request_object: Dict[str, Any], requestImage:
23962406
else:
23972407
request_object[field] = value
23982408

2399-
def _addImageSpecialFields(self, request_object: Dict[str, Any], requestImage: IImageInference, control_net_data_dicts: List[Dict], instant_id_data: Optional[Dict], ip_adapters_data: Optional[List[Dict]], ace_plus_plus_data: Optional[Dict], pulid_data: Optional[Dict]) -> None:
2409+
def _addImageSpecialFields(self, request_object: Dict[str, Any], requestImage: IImageInference, control_net_data_dicts: List[Dict], instant_id_data: Optional[Dict], ip_adapters_data: Optional[List[Dict]], ace_plus_plus_data: Optional[Dict], pulid_data: Optional[Dict], photo_maker_data: Optional[Dict]) -> None:
24002410
# Add controlNet if present
24012411
if control_net_data_dicts:
24022412
request_object["controlNet"] = control_net_data_dicts
@@ -2456,6 +2466,10 @@ def _addImageSpecialFields(self, request_object: Dict[str, Any], requestImage: I
24562466
if pulid_data:
24572467
request_object["puLID"] = pulid_data
24582468

2469+
# Add photoMaker if present
2470+
if photo_maker_data:
2471+
request_object["photoMaker"] = photo_maker_data
2472+
24592473
# Add referenceImages if present
24602474
if requestImage.referenceImages:
24612475
request_object["referenceImages"] = requestImage.referenceImages

runware/types.py

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ class ILycoris:
184184
@dataclass
185185
class IEmbedding:
186186
model: str
187+
weight: Optional[float] = None
187188

188189

189190
@dataclass
@@ -353,22 +354,9 @@ def __post_init__(self):
353354
raise ValueError("inputImages can contain a maximum of 4 elements.")
354355

355356
# Validate `style` to ensure it matches one of the allowed case-sensitive options
356-
valid_styles = {
357-
"No style",
358-
"Cinematic",
359-
"Disney Character",
360-
"Digital Art",
361-
"Photographic",
362-
"Fantasy art",
363-
"Neonpunk",
364-
"Enhance",
365-
"Comic book",
366-
"Lowpoly",
367-
"Line art",
368-
}
369-
if self.style and self.style not in valid_styles:
357+
if self.style and self.style not in _PHOTO_MAKER_VALID_STYLES:
370358
raise ValueError(
371-
f"style must be one of the following: {', '.join(valid_styles)}."
359+
f"style must be one of the following: {', '.join(sorted(_PHOTO_MAKER_VALID_STYLES))}."
372360
)
373361

374362

@@ -417,8 +405,13 @@ class IInstantID:
417405
@dataclass
418406
class IIpAdapter:
419407
model: Union[int, str]
420-
guideImage: Union[File, str]
408+
guideImage: Optional[Union[File, str]] = None
409+
guideImages: Optional[List[Union[str, File]]] = None
421410
weight: Optional[float] = None
411+
combineMethod: Optional[str] = None
412+
weightType: Optional[str] = None
413+
embedScaling: Optional[str] = None
414+
weightComposition: Optional[float] = None
422415

423416

424417
@dataclass
@@ -450,6 +443,24 @@ class IPuLID:
450443
CFGStartStepPercentage: Optional[int] = None # Min: 0, Max: 100
451444

452445

446+
_PHOTO_MAKER_VALID_STYLES = {"No style", "Cinematic", "Disney Character", "Digital Art", "Photographic", "Fantasy art", "Neonpunk", "Enhance", "Comic book", "Lowpoly", "Line art"}
447+
448+
449+
@dataclass
450+
class IPhotoMakerSettings:
451+
452+
images: List[Union[str, File]] = field(default_factory=list)
453+
style: Optional[str] = None
454+
455+
def __post_init__(self):
456+
if len(self.images) > 4:
457+
raise ValueError("photoMaker.images can contain a maximum of 4 elements.")
458+
if self.style and self.style not in _PHOTO_MAKER_VALID_STYLES:
459+
raise ValueError(
460+
f"photoMaker.style must be one of: {', '.join(sorted(_PHOTO_MAKER_VALID_STYLES))}."
461+
)
462+
463+
453464
@dataclass
454465
class IAcceleratorOptions(SerializableMixin):
455466
fbcache: Optional[bool] = None
@@ -938,22 +949,23 @@ class IImageInference:
938949
lycoris: Optional[List[ILycoris]] = field(default_factory=list)
939950
includeCost: Optional[bool] = None
940951
onPartialImages: Optional[Callable[[List[IImage], Optional[IError]], None]] = None
941-
refiner: Optional[IRefiner] = None
952+
refiner: Optional[Union[IRefiner, Dict[str, Any]]] = None
942953
vae: Optional[str] = None
943954
maskMargin: Optional[int] = None
944955
outputQuality: Optional[int] = None
945-
embeddings: Optional[List[IEmbedding]] = field(default_factory=list)
946-
outpaint: Optional[IOutpaint] = None
947-
instantID: Optional[IInstantID] = None
956+
embeddings: Optional[List[Union[IEmbedding, Dict[str, Any]]]] = field(default_factory=list)
957+
outpaint: Optional[Union[IOutpaint, Dict[str, Any]]] = None
958+
instantID: Optional[Union[IInstantID, Dict[str, Any]]] = None
948959
ipAdapters: Optional[List[IIpAdapter]] = field(default_factory=list)
949960
referenceImages: Optional[List[Union[str, File]]] = field(default_factory=list)
950-
acePlusPlus: Optional[IAcePlusPlus] = None
951-
puLID: Optional[IPuLID] = None
961+
acePlusPlus: Optional[Union[IAcePlusPlus, Dict[str, Any]]] = None
962+
puLID: Optional[Union[IPuLID, Dict[str, Any]]] = None
963+
photoMaker: Optional[Union[IPhotoMakerSettings, Dict[str, Any]]] = None
952964
providerSettings: Optional[ImageProviderSettings] = None
953965
safety: Optional[Union[ISafety, Dict[str, Any]]] = None
954966
settings: Optional[Union[ISettings, Dict[str, Any]]] = None
955967
inputs: Optional[Union[IInputs, Dict[str, Any]]] = None
956-
ultralytics: Optional[IUltralytics] = None
968+
ultralytics: Optional[Union[IUltralytics, Dict[str, Any]]] = None
957969
useCache: Optional[bool] = None
958970
resolution: Optional[str] = None
959971
extraArgs: Optional[Dict[str, Any]] = field(default_factory=dict)
@@ -967,6 +979,30 @@ def __post_init__(self):
967979
self.settings = ISettings(**self.settings)
968980
if self.inputs is not None and isinstance(self.inputs, dict):
969981
self.inputs = IInputs(**self.inputs)
982+
if self.outpaint is not None and isinstance(self.outpaint, dict):
983+
self.outpaint = IOutpaint(**self.outpaint)
984+
if self.refiner is not None and isinstance(self.refiner, dict):
985+
self.refiner = IRefiner(**self.refiner)
986+
if self.embeddings:
987+
self.embeddings = [
988+
IEmbedding(**item) if isinstance(item, dict) else item
989+
for item in self.embeddings
990+
]
991+
if self.photoMaker is not None and isinstance(self.photoMaker, dict):
992+
self.photoMaker = IPhotoMakerSettings(**self.photoMaker)
993+
if self.instantID is not None and isinstance(self.instantID, dict):
994+
self.instantID = IInstantID(**self.instantID)
995+
if self.acePlusPlus is not None and isinstance(self.acePlusPlus, dict):
996+
self.acePlusPlus = IAcePlusPlus(**self.acePlusPlus)
997+
if self.puLID is not None and isinstance(self.puLID, dict):
998+
self.puLID = IPuLID(**self.puLID)
999+
if self.ultralytics is not None and isinstance(self.ultralytics, dict):
1000+
self.ultralytics = IUltralytics(**self.ultralytics)
1001+
if self.ipAdapters:
1002+
self.ipAdapters = [
1003+
IIpAdapter(**item) if isinstance(item, dict) else item
1004+
for item in self.ipAdapters
1005+
]
9701006

9711007

9721008
@dataclass

0 commit comments

Comments
 (0)