Skip to content

Commit 87ca4ce

Browse files
committed
feat(runtime/util): add concat_latents, load_latent_from_path, save_latent_and_get_path (#118,#29)
1 parent 84eb6f7 commit 87ca4ce

File tree

4 files changed

+115
-5
lines changed

4 files changed

+115
-5
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
# Hide nodes imports to avoid overwhelming the suggestion list
2-
from ._impl import *
2+
from ._impl import *
3+
from .latent import *

src/comfy_script/runtime/util/_impl.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from .. import node
2121
from .. import data
22+
from . import path
2223

2324
def get_int(value: 'Int') -> int:
2425
'''
@@ -179,10 +180,7 @@ def save_image_and_get_paths(image: 'Image', prefix: str | None = None, *, temp:
179180
result = save_image(image, prefix, temp=temp)
180181

181182
images: list[dict] = result._output['images']
182-
if type:
183-
return list([f'{d["filename"]} [{d["type"]}]' for d in images])
184-
else:
185-
return list([d['filename'] for d in images])
183+
return path._outputs_to_paths(images, type)
186184

187185
def load_image_from_paths(paths: list[str]) -> 'Image':
188186
'''
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
'''
2+
`Latent`-related utility functions.
3+
'''
4+
from typing import TYPE_CHECKING
5+
6+
if TYPE_CHECKING:
7+
from comfy_script.runtime.nodes import *
8+
import comfy_script.runtime.real.nodes as real
9+
10+
from .. import node
11+
from .. import data
12+
from . import path
13+
14+
def concat_latents(*latents: 'Latent') -> 'Latent':
15+
'''
16+
- Note that unlike `Image`, batched `Latent` will still be saved to the same file.
17+
18+
## Example
19+
```
20+
util.concat_latents(gen_latent(), gen_latent())
21+
util.concat_latents(*[gen_latent() for _ in range(2)])
22+
23+
latents = util.save_latent_and_get_paths(util.concat_latents(
24+
EmptyLatentImage(batch_size=2),
25+
EmptyLatentImage(batch_size=2)
26+
))
27+
print(len(latents))
28+
# 1
29+
```
30+
'''
31+
LatentBatch: 'type[LatentBatch]' = node.nodes['LatentBatch']
32+
33+
assert len(latents) > 0
34+
latent = latents[0]
35+
for i in latents[1:]:
36+
latent = LatentBatch(latent, i)
37+
return latent
38+
39+
def load_latent_from_path(path: str) -> 'Latent':
40+
'''
41+
## Example
42+
```
43+
with Workflow():
44+
latent = EmptyLatentImage(batch_size=4)
45+
latent_path = util.save_latent_and_get_path(latent)
46+
print(latent_path)
47+
48+
with Workflow():
49+
latent = util.load_latent_from_path(latent_path)
50+
# Do something with the latent, for example:
51+
SaveLatent(latent, 'latents/loaded')
52+
```
53+
'''
54+
LoadLatent: 'type[LoadLatent]' = node.nodes['LoadLatent']
55+
return LoadLatent(path)
56+
57+
def load_latent_from_paths(paths: list[str]) -> 'Latent':
58+
'''Load and concat latents from paths.
59+
'''
60+
return concat_latents(*[load_latent_from_path(path) for path in paths])
61+
62+
def save_latent(latent: 'Latent', prefix: str | None = None) -> data.Result:
63+
'''
64+
- Unfortunately, currently there is no official way to save latent to `temp` instead of `output`.
65+
'''
66+
SaveLatent: 'type[SaveLatent]' = node.nodes['SaveLatent']
67+
return SaveLatent(latent, prefix).wait()
68+
69+
def save_latent_and_get_path(latent: 'Latent', prefix: str | None = None, *, type: bool = True) -> str:
70+
'''
71+
- Note that unlike `Image`, batched `Latent` will still be saved to the same file.
72+
73+
## Example
74+
```
75+
with Workflow():
76+
latent = EmptyLatentImage(batch_size=4)
77+
latent_path = util.save_latent_and_get_path(latent)
78+
print(latent_path)
79+
80+
with Workflow():
81+
latent = util.load_latent_from_path(latent_path)
82+
# Do something with the latent, for example:
83+
SaveLatent(latent, 'latents/loaded')
84+
```
85+
'''
86+
result = save_latent(latent, prefix)
87+
88+
latents: list[dict] = result._output['latents']
89+
return path._outputs_to_paths(latents, type)[0]
90+
91+
__all__ = [
92+
'concat_latents',
93+
'load_latent_from_path',
94+
'load_latent_from_paths',
95+
'save_latent',
96+
'save_latent_and_get_path',
97+
]
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
def _outputs_to_paths(outputs: list[dict], type: bool = True) -> list[str]:
2+
'''
3+
- `outputs`:
4+
e.g.
5+
```
6+
[{'filename': 'ComfyUI_00001_.latent',
7+
'subfolder': 'latents',
8+
'type': 'output'}]
9+
```
10+
'''
11+
if type:
12+
return list([f'{d["subfolder"]}/{d["filename"]} [{d["type"]}]' for d in outputs])
13+
else:
14+
return list([f'{d["subfolder"]}/{d["filename"]}' for d in outputs])

0 commit comments

Comments
 (0)