Compare commits
7
Commits
registry
...
migration_v3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab9f2133ef | ||
|
|
6891d35cc1 | ||
|
|
96c128673e | ||
|
|
5b07327ea0 | ||
|
|
453c1311e2 | ||
|
|
606b65af25 | ||
|
|
fe26ccbdae |
@@ -7,14 +7,18 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- "pyproject.toml"
|
- "pyproject.toml"
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
publish-node:
|
publish-node:
|
||||||
name: Publish Custom Node to registry
|
name: Publish Custom Node to registry
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.repository_owner == 'lerignoux' }}
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code
|
- name: Check out code
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- name: Publish Custom Node
|
- name: Publish Custom Node
|
||||||
uses: Comfy-Org/publish-node-action@main
|
uses: Comfy-Org/publish-node-action@v1
|
||||||
with:
|
with:
|
||||||
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} ## Add your own personal access token to your Github Repository secrets and reference it here.
|
personal_access_token: ${{ secrets.REGISTRY_ACCESS_TOKEN }} ## Add your own personal access token to your Github Repository secrets and reference it here.
|
||||||
|
|||||||
+21
-12
@@ -1,16 +1,25 @@
|
|||||||
|
from comfy_api.latest import ComfyExtension, io
|
||||||
|
|
||||||
|
from .download_pecha_kucha import DownloadPechaKucha
|
||||||
from .pecha_kucha import GeneratePowerpoint
|
from .pecha_kucha import GeneratePowerpoint
|
||||||
from .split_prompt import SplitPrompt
|
from .split_prompt import SplitPrompt
|
||||||
# A dictionary that contains all nodes you want to export with their names
|
|
||||||
# NOTE: names should be globally unique
|
|
||||||
NODE_CLASS_MAPPINGS = {
|
|
||||||
"GeneratePowerpoint": GeneratePowerpoint,
|
|
||||||
"SplitPrompt": SplitPrompt
|
|
||||||
}
|
|
||||||
|
|
||||||
# A dictionary that contains the friendly/humanly readable titles for the nodes
|
WEB_DIRECTORY = "./web"
|
||||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
|
||||||
"GeneratePowerpoint": "Generate PechaKucha Powerpoint",
|
|
||||||
"SplitPrompt": "Split Prompt (To Batch)"
|
|
||||||
}
|
|
||||||
|
|
||||||
__all__ = [NODE_CLASS_MAPPINGS, NODE_DISPLAY_NAME_MAPPINGS]
|
|
||||||
|
class PechaKucha(ComfyExtension):
|
||||||
|
# must be declared as async
|
||||||
|
async def get_node_list(self) -> list[type[io.ComfyNode]]:
|
||||||
|
return [
|
||||||
|
DownloadPechaKucha,
|
||||||
|
GeneratePowerpoint,
|
||||||
|
SplitPrompt,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
# can be declared async or not, both will work
|
||||||
|
async def comfy_entrypoint() -> PechaKucha:
|
||||||
|
return PechaKucha()
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["WEB_DIRECTORY"]
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
import logging
|
||||||
|
|
||||||
|
from comfy_api.latest import io, ui
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadPechaKucha(io.ComfyNode):
|
||||||
|
"""
|
||||||
|
A simple node to view/download a generated PechaKucha Powerpoint.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def define_schema(cls) -> io.Schema:
|
||||||
|
return io.Schema(
|
||||||
|
node_id="DownloadPechaKucha",
|
||||||
|
display_name="Download a generated PechaKucha Powerpoint",
|
||||||
|
description="Download a generated pecha kucha presentation",
|
||||||
|
category="pecha_kucha",
|
||||||
|
inputs=[
|
||||||
|
io.String.Input(
|
||||||
|
"filename",
|
||||||
|
default="",
|
||||||
|
multiline=False,
|
||||||
|
tooltip="The path of this Presentation.",
|
||||||
|
)
|
||||||
|
],
|
||||||
|
is_output_node=True,
|
||||||
|
outputs=[],
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def fingerprint_inputs(cls, filename):
|
||||||
|
return float("NaN")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def execute(cls, filename):
|
||||||
|
return io.NodeOutput(filename, ui=ui.PreviewText(filename, cls=cls))
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
{
|
{
|
||||||
"last_node_id": 29,
|
"id": "594262c2-cffc-4068-8fa7-d4ea47a1869d",
|
||||||
"last_link_id": 31,
|
"revision": 0,
|
||||||
|
"last_node_id": 30,
|
||||||
|
"last_link_id": 32,
|
||||||
"nodes": [
|
"nodes": [
|
||||||
{
|
{
|
||||||
"id": 19,
|
"id": 19,
|
||||||
@@ -72,10 +74,10 @@
|
|||||||
{
|
{
|
||||||
"name": "CONDITIONING",
|
"name": "CONDITIONING",
|
||||||
"type": "CONDITIONING",
|
"type": "CONDITIONING",
|
||||||
|
"slot_index": 0,
|
||||||
"links": [
|
"links": [
|
||||||
16
|
16
|
||||||
],
|
]
|
||||||
"slot_index": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -125,10 +127,10 @@
|
|||||||
{
|
{
|
||||||
"name": "LATENT",
|
"name": "LATENT",
|
||||||
"type": "LATENT",
|
"type": "LATENT",
|
||||||
|
"slot_index": 0,
|
||||||
"links": [
|
"links": [
|
||||||
19
|
19
|
||||||
],
|
]
|
||||||
"slot_index": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -174,10 +176,10 @@
|
|||||||
{
|
{
|
||||||
"name": "IMAGE",
|
"name": "IMAGE",
|
||||||
"type": "IMAGE",
|
"type": "IMAGE",
|
||||||
|
"slot_index": 0,
|
||||||
"links": [
|
"links": [
|
||||||
28
|
28
|
||||||
],
|
]
|
||||||
"slot_index": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -202,14 +204,13 @@
|
|||||||
"inputs": [],
|
"inputs": [],
|
||||||
"outputs": [
|
"outputs": [
|
||||||
{
|
{
|
||||||
"name": "Split Prompts",
|
"name": "split prompt",
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"shape": 6,
|
"slot_index": 0,
|
||||||
"links": [
|
"links": [
|
||||||
24,
|
24,
|
||||||
31
|
31
|
||||||
],
|
]
|
||||||
"slot_index": 0
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -273,19 +274,19 @@
|
|||||||
{
|
{
|
||||||
"name": "MODEL",
|
"name": "MODEL",
|
||||||
"type": "MODEL",
|
"type": "MODEL",
|
||||||
|
"slot_index": 0,
|
||||||
"links": [
|
"links": [
|
||||||
13
|
13
|
||||||
],
|
]
|
||||||
"slot_index": 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "CLIP",
|
"name": "CLIP",
|
||||||
"type": "CLIP",
|
"type": "CLIP",
|
||||||
|
"slot_index": 1,
|
||||||
"links": [
|
"links": [
|
||||||
14,
|
14,
|
||||||
15
|
15
|
||||||
],
|
]
|
||||||
"slot_index": 1
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "VAE",
|
"name": "VAE",
|
||||||
@@ -302,6 +303,39 @@
|
|||||||
"epicrealismXL_v5Ultimate.safetensors"
|
"epicrealismXL_v5Ultimate.safetensors"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": 30,
|
||||||
|
"type": "DownloadPechaKucha",
|
||||||
|
"pos": [
|
||||||
|
1904.9952392578125,
|
||||||
|
915.4524536132812
|
||||||
|
],
|
||||||
|
"size": [
|
||||||
|
397.9166564941406,
|
||||||
|
82
|
||||||
|
],
|
||||||
|
"flags": {},
|
||||||
|
"order": 8,
|
||||||
|
"mode": 0,
|
||||||
|
"inputs": [
|
||||||
|
{
|
||||||
|
"name": "filename",
|
||||||
|
"type": "STRING",
|
||||||
|
"widget": {
|
||||||
|
"name": "filename"
|
||||||
|
},
|
||||||
|
"link": 32
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"outputs": [],
|
||||||
|
"properties": {
|
||||||
|
"Node name for S&R": "DownloadPechaKucha"
|
||||||
|
},
|
||||||
|
"widgets_values": [
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": 27,
|
"id": 27,
|
||||||
"type": "GeneratePowerpoint",
|
"type": "GeneratePowerpoint",
|
||||||
@@ -335,8 +369,10 @@
|
|||||||
{
|
{
|
||||||
"name": "filename",
|
"name": "filename",
|
||||||
"type": "STRING",
|
"type": "STRING",
|
||||||
"links": null,
|
"slot_index": 0,
|
||||||
"slot_index": 0
|
"links": [
|
||||||
|
32
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -438,6 +474,14 @@
|
|||||||
27,
|
27,
|
||||||
1,
|
1,
|
||||||
"STRING"
|
"STRING"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
32,
|
||||||
|
27,
|
||||||
|
0,
|
||||||
|
30,
|
||||||
|
0,
|
||||||
|
"STRING"
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
"groups": [],
|
"groups": [],
|
||||||
@@ -446,10 +490,11 @@
|
|||||||
"ds": {
|
"ds": {
|
||||||
"scale": 0.9090909090909091,
|
"scale": 0.9090909090909091,
|
||||||
"offset": [
|
"offset": [
|
||||||
812.004781836218,
|
-220.895218163782,
|
||||||
-127.85274297232016
|
-490.8527429723203
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"frontendVersion": "1.27.10"
|
||||||
},
|
},
|
||||||
"version": 0.4
|
"version": 0.4
|
||||||
}
|
}
|
||||||
+65
-54
@@ -1,11 +1,10 @@
|
|||||||
import io
|
|
||||||
import json
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import numpy
|
import numpy
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from PIL.PngImagePlugin import PngInfo
|
from PIL.PngImagePlugin import PngInfo
|
||||||
|
|
||||||
|
from comfy_api.latest import io
|
||||||
import folder_paths
|
import folder_paths
|
||||||
|
|
||||||
from .presentation_generation.pptx import Pptx
|
from .presentation_generation.pptx import Pptx
|
||||||
@@ -13,61 +12,68 @@ from .presentation_generation.pptx import Pptx
|
|||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class GeneratePowerpoint:
|
class GeneratePowerpoint(io.ComfyNode):
|
||||||
"""
|
"""
|
||||||
A node to generate a PechaKucha presentation
|
A node to generate a PechaKucha presentation
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
|
||||||
self.output_dir = folder_paths.get_output_directory()
|
INPUT_IS_LIST = True
|
||||||
self.temp_dir = folder_paths.get_temp_directory()
|
output_dir = folder_paths.get_output_directory()
|
||||||
self.compress_level = 4
|
temp_dir = folder_paths.get_temp_directory()
|
||||||
pass
|
compress_level = 4
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(s):
|
def define_schema(cls) -> io.Schema:
|
||||||
return {
|
return io.Schema(
|
||||||
"required": {
|
node_id="GeneratePowerpoint",
|
||||||
"images": ("IMAGE",),
|
display_name="Generate PechaKucha Powerpoint",
|
||||||
"title": ("STRING", {
|
description="Generates a Pecha Kucha generation from a list of images and prompts",
|
||||||
"multiline": False,
|
category="pecha_kucha",
|
||||||
"default": "My pecha",
|
inputs=[
|
||||||
"tooltip": "The title of this Presentation"
|
io.Image.Input("images"),
|
||||||
}),
|
io.String.Input(
|
||||||
"titles": ("STRING", {
|
"title",
|
||||||
"multiline": False,
|
default="My pecha",
|
||||||
"default": "",
|
multiline=False,
|
||||||
"tooltip": "the titles for each slide."
|
tooltip="The title of this Presentation.",
|
||||||
}),
|
),
|
||||||
"slide_duration": ("INT", {
|
io.String.Input(
|
||||||
"default": 20,
|
"titles",
|
||||||
"min": 0,
|
default="",
|
||||||
"max": 300,
|
multiline=False,
|
||||||
"step": 1,
|
tooltip="the titles for each slide.",
|
||||||
"display": "number",
|
),
|
||||||
"tooltip": "Each slide duration in seconds."
|
io.Int.Input(
|
||||||
}),
|
"slide_duration",
|
||||||
"show_titles": ("BOOLEAN", {
|
default=20,
|
||||||
"default": False,
|
min=0,
|
||||||
"tooltip": "Show each prompt as slide title. Needs to provide the titles input."
|
max=300,
|
||||||
})
|
step=1,
|
||||||
},
|
display_mode=io.NumberDisplay.number,
|
||||||
}
|
tooltip="Each slide duration in seconds.",
|
||||||
|
),
|
||||||
|
io.Boolean.Input(
|
||||||
|
"show_titles",
|
||||||
|
default=False,
|
||||||
|
tooltip="Show each prompt as slide title. Needs to provide the titles input.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
is_output_node=True,
|
||||||
|
outputs=[io.String.Output(display_name="filename")],
|
||||||
|
)
|
||||||
|
|
||||||
CATEGORY = "pecha_kucha"
|
@classmethod
|
||||||
DESCRIPTION = "Generates a Pecha Kucha generation from a list of images and prompts"
|
def save_images(cls, images, filename_prefix="PechaKucha"):
|
||||||
FUNCTION = "generate_pptx"
|
full_output_folder, filename, counter, subfolder, filename_prefix = (
|
||||||
INPUT_IS_LIST = True
|
folder_paths.get_save_image_path(
|
||||||
OUTPUT_NODE = True
|
filename_prefix, cls.temp_dir, images[0].shape[1], images[0].shape[0]
|
||||||
RETURN_NAMES = ("filename",)
|
)
|
||||||
RETURN_TYPES = ("STRING",)
|
)
|
||||||
|
|
||||||
def save_images(self, images, filename_prefix="PechaKucha"):
|
|
||||||
full_output_folder, filename, counter, subfolder, filename_prefix = folder_paths.get_save_image_path(filename_prefix, self.temp_dir, images[0].shape[1], images[0].shape[0])
|
|
||||||
results = list()
|
results = list()
|
||||||
log.debug(f"received {len(images)} images")
|
log.debug(f"received {len(images)} images")
|
||||||
for (batch_number, image) in enumerate(images):
|
for batch_number, image in enumerate(images):
|
||||||
log.debug(f"start saving image {batch_number}, shape: {image.shape}")
|
log.debug(f"start saving image {batch_number}, shape: {image.shape}")
|
||||||
i = 255. * image.cpu().numpy().squeeze()
|
i = 255.0 * image.cpu().numpy().squeeze()
|
||||||
img = Image.fromarray(numpy.clip(i, 0, 255).astype(numpy.uint8))
|
img = Image.fromarray(numpy.clip(i, 0, 255).astype(numpy.uint8))
|
||||||
metadata = None
|
metadata = None
|
||||||
metadata = PngInfo()
|
metadata = PngInfo()
|
||||||
@@ -75,24 +81,29 @@ class GeneratePowerpoint:
|
|||||||
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
|
filename_with_batch_num = filename.replace("%batch_num%", str(batch_number))
|
||||||
file = f"{filename_with_batch_num}_{counter:05}_.png"
|
file = f"{filename_with_batch_num}_{counter:05}_.png"
|
||||||
path = os.path.join(full_output_folder, file)
|
path = os.path.join(full_output_folder, file)
|
||||||
img.save(path, pnginfo=metadata, compress_level=self.compress_level)
|
img.save(path, pnginfo=metadata, compress_level=cls.compress_level)
|
||||||
results.append(path)
|
results.append(path)
|
||||||
counter += 1
|
counter += 1
|
||||||
|
|
||||||
return results
|
return results
|
||||||
|
|
||||||
def generate_pptx(self, images, title, titles, slide_duration, show_titles):
|
@classmethod
|
||||||
|
def execute(cls, images, title, titles, slide_duration, show_titles):
|
||||||
log.info(f"start pecha_kucha generation")
|
log.info(f"start pecha_kucha generation")
|
||||||
images = self.save_images(images)
|
images = cls.save_images(images)
|
||||||
# The following inputs are also considered as list but only contain a single value
|
# The following inputs are also considered as list but only contain a single value
|
||||||
title = title[0]
|
title = title[0]
|
||||||
slide_duration = slide_duration[0]
|
slide_duration = slide_duration[0]
|
||||||
show_titles = show_titles[0]
|
show_titles = show_titles[0]
|
||||||
output_folder = "./output/pecha_kucha"
|
output_folder = "./output/pecha_kucha"
|
||||||
filename = Pptx(output_folder).generate(title, slide_duration, images, show_titles, titles)
|
filename = Pptx(output_folder).generate(
|
||||||
|
title, slide_duration, images, show_titles, titles
|
||||||
|
)
|
||||||
log.info(f"Generated presentation {filename}")
|
log.info(f"Generated presentation {filename}")
|
||||||
return (filename,)
|
return io.NodeOutput(
|
||||||
|
filename,
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def IS_CHANGED(s, images, title, titles, slide_duration, show_titles):
|
def fingerprint_inputs(cls, **kwargs):
|
||||||
return float("NaN")
|
return float("NaN")
|
||||||
|
|||||||
+2
-2
@@ -1,7 +1,7 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "ComfyUI-PechaKucha"
|
name = "ComfyUI-PechaKucha"
|
||||||
description = "Nodes to generate a pecha kucha presentation in ComfyUI"
|
description = "Nodes to generate a pecha-kucha presentation in ComfyUI"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
license = { file = "LICENSE" }
|
license = { file = "LICENSE" }
|
||||||
dependencies = ["python-pptx >= 1.0.2"]
|
dependencies = ["python-pptx >= 1.0.2"]
|
||||||
|
|
||||||
|
|||||||
+34
-27
@@ -1,47 +1,54 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from comfy_api.latest import io
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class SplitPrompt:
|
class SplitPrompt(io.ComfyNode):
|
||||||
"""
|
"""
|
||||||
A simple node to split a prompt into a batch of prompt.
|
A simple node to split a prompt into a batch of prompt.
|
||||||
Inspired from [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
Inspired from [ComfyUI-Inspire-Pack](https://github.com/ltdrdata/ComfyUI-Inspire-Pack)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def INPUT_TYPES(cls):
|
def define_schema(cls) -> io.Schema:
|
||||||
return {
|
return io.Schema(
|
||||||
"required": {
|
node_id="SplitPrompt",
|
||||||
"prompt": (
|
display_name="Split prompt",
|
||||||
"STRING",
|
description="Split a prompt in a list of prompts",
|
||||||
{"multiline": True, "default": "First Prompt \nSecond Prompt", "tooltip": "A multiline prompt that will be split to batch generate"}
|
category="pecha_kucha",
|
||||||
)
|
inputs=[
|
||||||
},
|
io.String.Input(
|
||||||
"optional": {
|
"prompt",
|
||||||
"split_on": (
|
default="First Prompt \nSecond Prompt",
|
||||||
"STRING",
|
multiline=True,
|
||||||
{"default": '\n', "tooltip": "Will split the input prompt on this character"}
|
tooltip="A multiline prompt that will be split to batch generate.",
|
||||||
),
|
),
|
||||||
"trim": (
|
io.String.Input(
|
||||||
"BOOLEAN",
|
"split_on",
|
||||||
{"default": True, "tooltip": "Will trim prompts and remove empty ones"}
|
default="\n",
|
||||||
|
multiline=False,
|
||||||
|
tooltip="Will split the input prompt on this character.",
|
||||||
),
|
),
|
||||||
}
|
io.Boolean.Input(
|
||||||
}
|
"trim",
|
||||||
|
default=True,
|
||||||
|
tooltip="Will trim prompts and remove empty ones.",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
is_output_node=False,
|
||||||
|
outputs=[io.String.Output(display_name="split prompt")],
|
||||||
|
)
|
||||||
|
|
||||||
CATEGORY = "pecha_kucha"
|
|
||||||
DESCRIPTION = "Split a prompt in a list of prompts"
|
|
||||||
FUNCTION = "split"
|
|
||||||
OUTPUT_IS_LIST = (True,)
|
OUTPUT_IS_LIST = (True,)
|
||||||
RETURN_NAMES = ("Split Prompts",)
|
|
||||||
RETURN_TYPES = ("STRING",)
|
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def IS_CHANGED(prompt, split_on='\n', trim=True):
|
def fingerprint_inputs(cls, prompt, split_on="\n", trim=True):
|
||||||
return f"trim:{trim}_split:{split_on}_prompt:{prompt}"
|
return f"trim:{trim}_split:{split_on}_prompt:{prompt}"
|
||||||
|
|
||||||
@staticmethod
|
@classmethod
|
||||||
def split(prompt, split_on='\n', trim=True):
|
def execute(cls, prompt, split_on="\n", trim=True):
|
||||||
prompts = prompt.split(split_on)
|
prompts = prompt.split(split_on)
|
||||||
if trim:
|
if trim:
|
||||||
prompts = [prompt.strip() for prompt in prompts]
|
prompts = [prompt.strip() for prompt in prompts]
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import { app } from "/scripts/app.js";
|
||||||
|
|
||||||
|
app.registerExtension({
|
||||||
|
name: "pecha_kucha.DownloadPechaKucha",
|
||||||
|
nodeCreated(node) {
|
||||||
|
if (node.comfyClass !== "DownloadPechaKucha") return;
|
||||||
|
console.log("Creating DownloadPechaKucha node.");
|
||||||
|
|
||||||
|
const onExecuted = node.onExecuted;
|
||||||
|
|
||||||
|
node.onExecuted = function (message) {
|
||||||
|
onExecuted?.apply(this, arguments);
|
||||||
|
|
||||||
|
let filePath = message.text[0];
|
||||||
|
console.log(`Powerpoint path received : ${filePath}`);
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
const msg = "Unable to get presentation File path.";
|
||||||
|
console.error(msg);
|
||||||
|
useToastStore().addAlert(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelWidget = node.widgets?.find(
|
||||||
|
(w) => w.name === "Open Presentation",
|
||||||
|
);
|
||||||
|
|
||||||
|
if (modelWidget) {
|
||||||
|
modelWidget.value = filePath.replaceAll("\\", "/");
|
||||||
|
modelWidget.disabled = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const download = () => {
|
||||||
|
let filePath = "";
|
||||||
|
|
||||||
|
const fileNameWidget = node.widgets?.find(
|
||||||
|
(w) => w.name === "Open Presentation",
|
||||||
|
);
|
||||||
|
if (!fileNameWidget) {
|
||||||
|
console.error("Could not find Open presentation widget.");
|
||||||
|
}
|
||||||
|
filePath = fileNameWidget.value;
|
||||||
|
if (!filePath) {
|
||||||
|
console.error(`Could not find presentation file: ${filePath}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("Downloading presentation:", filePath);
|
||||||
|
|
||||||
|
// Remove any leading ./output/ prefix if present
|
||||||
|
const cleanFilePath = filePath.replace(/^\.\/output\//, "");
|
||||||
|
const folderName = cleanFilePath.replace(/[^\\/]+$/, "");
|
||||||
|
const fileNameMatch = cleanFilePath.match(/[^\\/]+$/);
|
||||||
|
const fileName = fileNameMatch ? fileNameMatch[0] : "";
|
||||||
|
const viewUrl = `/api/view?subfolder=${encodeURIComponent(folderName)}&filename=${encodeURIComponent(fileName)}&type=output`;
|
||||||
|
|
||||||
|
// Open the presentation in a new tab
|
||||||
|
window.open(viewUrl, "_blank");
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create the button widget (initially disabled until we get the presentation file available)
|
||||||
|
const downloadButton = node.addWidget(
|
||||||
|
"button",
|
||||||
|
"Open Presentation",
|
||||||
|
"",
|
||||||
|
download,
|
||||||
|
);
|
||||||
|
downloadButton.disabled = true;
|
||||||
|
node.downloadButton = downloadButton;
|
||||||
|
},
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user