Adding a node to open a generated pecha kucha presentation

This commit is contained in:
Laurent Erignoux
2025-10-26 21:46:38 +08:00
parent 6891d35cc1
commit ab9f2133ef
4 changed files with 178 additions and 21 deletions
+4
View File
@@ -1,13 +1,17 @@
from comfy_api.latest import ComfyExtension, io
from .download_pecha_kucha import DownloadPechaKucha
from .pecha_kucha import GeneratePowerpoint
from .split_prompt import SplitPrompt
WEB_DIRECTORY = "./web"
class PechaKucha(ComfyExtension):
# must be declared as async
async def get_node_list(self) -> list[type[io.ComfyNode]]:
return [
DownloadPechaKucha,
GeneratePowerpoint,
SplitPrompt,
]
+38
View File
@@ -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))
+66 -21
View File
@@ -1,6 +1,8 @@
{
"last_node_id": 29,
"last_link_id": 31,
"id": "594262c2-cffc-4068-8fa7-d4ea47a1869d",
"revision": 0,
"last_node_id": 30,
"last_link_id": 32,
"nodes": [
{
"id": 19,
@@ -72,10 +74,10 @@
{
"name": "CONDITIONING",
"type": "CONDITIONING",
"slot_index": 0,
"links": [
16
],
"slot_index": 0
]
}
],
"properties": {
@@ -125,10 +127,10 @@
{
"name": "LATENT",
"type": "LATENT",
"slot_index": 0,
"links": [
19
],
"slot_index": 0
]
}
],
"properties": {
@@ -174,10 +176,10 @@
{
"name": "IMAGE",
"type": "IMAGE",
"slot_index": 0,
"links": [
28
],
"slot_index": 0
]
}
],
"properties": {
@@ -202,14 +204,13 @@
"inputs": [],
"outputs": [
{
"name": "Split Prompts",
"name": "split prompt",
"type": "STRING",
"shape": 6,
"slot_index": 0,
"links": [
24,
31
],
"slot_index": 0
]
}
],
"properties": {
@@ -273,19 +274,19 @@
{
"name": "MODEL",
"type": "MODEL",
"slot_index": 0,
"links": [
13
],
"slot_index": 0
]
},
{
"name": "CLIP",
"type": "CLIP",
"slot_index": 1,
"links": [
14,
15
],
"slot_index": 1
]
},
{
"name": "VAE",
@@ -302,6 +303,39 @@
"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,
"type": "GeneratePowerpoint",
@@ -335,8 +369,10 @@
{
"name": "filename",
"type": "STRING",
"links": null,
"slot_index": 0
"slot_index": 0,
"links": [
32
]
}
],
"properties": {
@@ -438,6 +474,14 @@
27,
1,
"STRING"
],
[
32,
27,
0,
30,
0,
"STRING"
]
],
"groups": [],
@@ -446,10 +490,11 @@
"ds": {
"scale": 0.9090909090909091,
"offset": [
812.004781836218,
-127.85274297232016
-220.895218163782,
-490.8527429723203
]
}
},
"frontendVersion": "1.27.10"
},
"version": 0.4
}
+70
View File
@@ -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;
},
});