Add change trigger when PS history changes and triggers prompt so auto queue change mode can be used

This commit is contained in:
CMonk
2024-04-23 18:21:55 +08:00
parent 562e97b21e
commit 47cbb4c2aa
6 changed files with 219 additions and 26 deletions
+25 -13
View File
@@ -1,3 +1,5 @@
import os
import shutil
from server import PromptServer
from aiohttp import web, WSMsgType
import json
@@ -61,6 +63,7 @@ class PhotoshopInstance:
self.wsCallsManager = WSCallsManager(ws)
self.destroyed = False
self.layers = []
self.push_data = {}
self.get_img_state_id = None
self.last_get_img_id = None
self.send_img_state_id = None
@@ -87,7 +90,9 @@ class PhotoshopInstance:
if msg.type == WSMsgType.TEXT:
payload = json.loads(msg.data)
if 'push_data' in payload:
push_data = payload['push_data']
self.push_data.update(push_data)
if 'call_id' in payload:
call_id = payload['call_id']
if 'error' in payload:
@@ -107,6 +112,9 @@ class PhotoshopInstance:
finally:
print('Photoshop Disconnected')
PhotoshopInstance.instance = None
def get_push_state_id(self):
return self.push_data.get('history_state_id', None)
async def get_layers(self):
result = await self.wsCallsManager.call('get_layers', {})
@@ -123,8 +131,11 @@ class PhotoshopInstance:
self.last_get_img_id = id
return id
def is_get_image_changed(self):
current_id = _invoke_async(self.get_active_history_state_id())
async def is_get_image_changed(self):
push_state_id = self.get_push_state_id()
if push_state_id is not None:
return self.get_img_state_id != push_state_id
current_id = await self.get_active_history_state_id()
return self.get_img_state_id != current_id
async def send_images(self, image_ids, layer_name=""):
@@ -139,7 +150,7 @@ class PhotoshopInstance:
async def get_active_history_state_id(self):
result = await self.wsCallsManager.call('get_active_history_state_id', {})
id = result['history_state_id']
id = result.get('history_state_id', None)
return id
async def destroy(self):
@@ -258,7 +269,7 @@ class GetImageFromPhotoshopLayerNode:
if (PhotoshopInstance.instance is None):
return np.random.rand()
else:
return PhotoshopInstance.instance.is_get_image_changed()
return _invoke_async(PhotoshopInstance.instance.get_active_history_state_id())
@classmethod
def INPUT_TYPES(cls):
@@ -376,15 +387,16 @@ class SendImageToPhotoshopSetLayerNode:
threading.Thread(target=lambda: asyncio.run(PhotoshopInstance.instance.send_images(image_ids=ret, layer_name=layer_name))).start()
return (None,)
loop = None
def _invoke_async(call):
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
task = loop.create_task(call)
loop.run_until_complete(task)
result = task.result()
loop.close()
return result
return asyncio.run(call)
@PromptServer.instance.routes.get("/sd-ppp/checkchanges")
async def fetch_customnode_mappings(request):
is_changed = False
if (PhotoshopInstance.instance is not None):
is_changed = await PhotoshopInstance.instance.is_get_image_changed()
return web.json_response({'is_changed': is_changed}, content_type='application/json')
NODE_CLASS_MAPPINGS = {
'Get Image From Photoshop Layer': GetImageFromPhotoshopLayerNode,
+28
View File
@@ -0,0 +1,28 @@
import { app } from "../../scripts/app.js";
import { api } from "../../scripts/api.js"
console.log("[sd-ppp]", "Loading js extension");
app.registerExtension({
name: "Comfy.SD-PPP",
init() {
},
async setup() {
setInterval(checkChanges, 1000);
},
});
const SDPPPNodes = [
'Get Image From Photoshop Layer',
'Send Images To Photoshop',
'Send Images To Photoshop Set Layer',
]
async function checkChanges() {
const currentState = app.graph.serialize();
const mode0NodeTypes = currentState.nodes.filter(node => node.mode == 0).map(node => node.type);
const containsSDPPPNodes = mode0NodeTypes.some(nodeType => SDPPPNodes.includes(nodeType));
if (!containsSDPPPNodes) return;
const res = await api.fetchApi(`/sd-ppp/checkchanges`);
const json = await res.json()
if (!json.is_changed) return;
api.dispatchEvent(new CustomEvent("graphChanged"));
}
+91 -8
View File
@@ -88,8 +88,10 @@ __webpack_require__.r(__webpack_exports__);
/* harmony export */ });
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
/* harmony import */ var _system_ComfyConnection__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../system/ComfyConnection */ "./src/system/ComfyConnection.js");
/* harmony import */ var uxp__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! uxp */ "uxp");
/* harmony import */ var uxp__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(uxp__WEBPACK_IMPORTED_MODULE_2__);
/* harmony import */ var _system_HistoryChecker__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../system/HistoryChecker */ "./src/system/HistoryChecker.js");
/* harmony import */ var uxp__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! uxp */ "uxp");
/* harmony import */ var uxp__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(uxp__WEBPACK_IMPORTED_MODULE_3__);
@@ -106,8 +108,18 @@ class Main extends react__WEBPACK_IMPORTED_MODULE_0__.Component {
isConnected: instance?.isConnected,
comfyURL: instance ? instance.comfyURL : ''
});
if (instance?.isConnected) {
const hc = _system_HistoryChecker__WEBPACK_IMPORTED_MODULE_2__["default"].createInstance();
hc.setChangeCallback(historyId => {
instance.pushData({
history_state_id: historyId
});
});
} else {
_system_HistoryChecker__WEBPACK_IMPORTED_MODULE_2__["default"].instance?.destroy();
}
});
uxp__WEBPACK_IMPORTED_MODULE_2__.storage.secureStorage.getItem('comfyURL').then(value => {
uxp__WEBPACK_IMPORTED_MODULE_3__.storage.secureStorage.getItem('comfyURL').then(value => {
if (!value) return;
this.setState({
comfyURL: Buffer.from(value).toString()
@@ -284,6 +296,19 @@ class ComfyConnection {
this.comfyURL = comfyURL.replace(/\/*$/, '');
this.connect();
}
pushData(data) {
if (!this.socket || this.socket.readyState != WebSocket.OPEN) {
console.error('Connection not open');
return;
}
try {
this.socket.send(JSON.stringify({
push_data: data
}));
} catch (e) {
console.error(e);
}
}
async onMessage(event) {
console.log("Message from comfy ", event.data);
try {
@@ -415,13 +440,15 @@ class ComfyConnection {
});
} else if (payload.action == 'get_active_history_state_id') {
try {
const historyStates = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument.historyStates;
const historyState = historyStates[historyStates.length - 1];
let result = {};
const historyStates = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument?.historyStates;
if (historyStates && historyStates.length > 0) {
const historyState = historyStates[historyStates.length - 1];
result.history_state_id = historyState.id;
}
this.socket.send(JSON.stringify({
call_id: payload.call_id,
result: {
history_state_id: historyState.id
}
result: result
}));
} catch (e) {
this.socket.send(JSON.stringify({
@@ -473,6 +500,62 @@ class ComfyConnection {
/***/ }),
/***/ "./src/system/HistoryChecker.js":
/*!**************************************!*\
!*** ./src/system/HistoryChecker.js ***!
\**************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
/* harmony export */ });
/* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! photoshop */ "photoshop");
/* harmony import */ var photoshop__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(photoshop__WEBPACK_IMPORTED_MODULE_0__);
class HistoryChecker {
static instance = null;
static createInstance() {
if (HistoryChecker.instance) {
return HistoryChecker.instance;
}
return new HistoryChecker();
}
constructor() {
HistoryChecker.instance = this;
this.lastCheckId = -1;
this.changeCallback = null;
// this.timer = setInterval(() => {
// this.checkHistoryState();
// }, 1000)
photoshop__WEBPACK_IMPORTED_MODULE_0__.action.addNotificationListener("historyStateChanged", () => {
this.checkHistoryState();
});
}
destroy() {
clearInterval(this.timer);
this.timer = null;
this.changeCallback = null;
HistoryChecker.instance = null;
}
setChangeCallback(callback) {
this.changeCallback = callback;
}
checkHistoryState() {
const historyStates = photoshop__WEBPACK_IMPORTED_MODULE_0__.app.activeDocument?.historyStates;
if (!historyStates || historyStates.length == 0) return;
const historyState = historyStates[historyStates.length - 1];
const historyId = historyState.id;
if (this.lastCheckId == historyId) return;
this.lastCheckId = historyId;
if (this.changeCallback) this.changeCallback(historyId);
}
}
/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (HistoryChecker);
/***/ }),
/***/ "./src/system/jimp.min.js":
/*!********************************!*\
!*** ./src/system/jimp.min.js ***!
+9
View File
@@ -1,5 +1,6 @@
import React from "react";
import ComfyConnection from "../system/ComfyConnection";
import HistoryChecker from "../system/HistoryChecker";
import { storage } from "uxp";
export default class Main extends React.Component {
@@ -16,6 +17,14 @@ export default class Main extends React.Component {
isConnected: instance?.isConnected,
comfyURL: instance ? instance.comfyURL : ''
})
if (instance?.isConnected) {
const hc = HistoryChecker.createInstance();
hc.setChangeCallback((historyId) => {
instance.pushData({history_state_id: historyId})
});
} else {
HistoryChecker.instance?.destroy();
}
});
storage.secureStorage.getItem('comfyURL').then((value) => {
if (!value) return
+20 -5
View File
@@ -131,6 +131,18 @@ class ComfyConnection {
this.connect();
}
pushData(data) {
if (!this.socket || this.socket.readyState != WebSocket.OPEN) {
console.error('Connection not open');
return;
}
try{
this.socket.send(JSON.stringify({
push_data: data,
}));
} catch (e) { console.error(e) }
}
async onMessage(event) {
console.log("Message from comfy ", event.data);
try {
@@ -280,14 +292,16 @@ class ComfyConnection {
} else if (payload.action == 'get_active_history_state_id') {
try {
const historyStates = app.activeDocument.historyStates;
const historyState = historyStates[historyStates.length - 1];
let result = {};
const historyStates = app.activeDocument?.historyStates;
if (historyStates && historyStates.length > 0) {
const historyState = historyStates[historyStates.length - 1];
result.history_state_id = historyState.id;
}
this.socket.send(
JSON.stringify({
call_id: payload.call_id,
result: {
history_state_id: historyState.id,
}
result: result
})
)
} catch (e) {
@@ -326,6 +340,7 @@ class ComfyConnection {
this._isConnected = false;
ComfyConnection._callConnectStateChange();
});
socket.addEventListener('error', (event) => {
console.log("Connection error", event);
this.reconnectTimer = setTimeout(() => {
+46
View File
@@ -0,0 +1,46 @@
import {app, action} from "photoshop";
class HistoryChecker {
static instance = null;
static createInstance() {
if (HistoryChecker.instance) {
return HistoryChecker.instance;
}
return new HistoryChecker();
}
constructor() {
HistoryChecker.instance = this;
this.lastCheckId = -1;
this.changeCallback = null;
// this.timer = setInterval(() => {
// this.checkHistoryState();
// }, 1000)
action.addNotificationListener("historyStateChanged", () => {
this.checkHistoryState();
});
}
destroy() {
clearInterval(this.timer);
this.timer = null;
this.changeCallback = null;
HistoryChecker.instance = null;
}
setChangeCallback(callback) {
this.changeCallback = callback;
}
checkHistoryState() {
const historyStates = app.activeDocument?.historyStates;
if (!historyStates || historyStates.length == 0) return;
const historyState = historyStates[historyStates.length - 1];
const historyId = historyState.id;
if (this.lastCheckId == historyId) return;
this.lastCheckId = historyId;
if (this.changeCallback)
this.changeCallback(historyId);
}
}
export default HistoryChecker;