Merge pull request #94 from space-nuko/disable-notifications
Option to control how notifications are shown
This commit is contained in:
@@ -990,7 +990,7 @@ export default class ComfyApp {
|
|||||||
tag = null;
|
tag = null;
|
||||||
|
|
||||||
if (targetWorkflow.attrs.showDefaultNotifications) {
|
if (targetWorkflow.attrs.showDefaultNotifications) {
|
||||||
notify("Prompt queued.", { type: "info" });
|
notify("Prompt queued.", { type: "info", showOn: "web" });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processingQueue = true;
|
this.processingQueue = true;
|
||||||
|
|||||||
@@ -3,17 +3,20 @@ import notify from "$lib/notify";
|
|||||||
import { convertComfyOutputToGradio, type SerializedPromptOutput } from "$lib/utils";
|
import { convertComfyOutputToGradio, type SerializedPromptOutput } from "$lib/utils";
|
||||||
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
||||||
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "../ComfyGraphNode";
|
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "../ComfyGraphNode";
|
||||||
|
import configState from "$lib/stores/configState";
|
||||||
|
|
||||||
export interface ComfyNotifyActionProperties extends ComfyGraphNodeProperties {
|
export interface ComfyNotifyActionProperties extends ComfyGraphNodeProperties {
|
||||||
message: string,
|
message: string,
|
||||||
type: string
|
type: string,
|
||||||
|
alwaysShow: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class ComfyNotifyAction extends ComfyGraphNode {
|
export default class ComfyNotifyAction extends ComfyGraphNode {
|
||||||
override properties: ComfyNotifyActionProperties = {
|
override properties: ComfyNotifyActionProperties = {
|
||||||
tags: [],
|
tags: [],
|
||||||
message: "Nya.",
|
message: "Nya.",
|
||||||
type: "info"
|
type: "info",
|
||||||
|
alwaysShow: false
|
||||||
}
|
}
|
||||||
|
|
||||||
static slotLayout: SlotLayout = {
|
static slotLayout: SlotLayout = {
|
||||||
@@ -24,6 +27,9 @@ export default class ComfyNotifyAction extends ComfyGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override onAction(action: any, param: any) {
|
override onAction(action: any, param: any) {
|
||||||
|
if (!configState.canShowNotificationText() && !this.properties.alwaysShow)
|
||||||
|
return;
|
||||||
|
|
||||||
const message = this.getInputData(0) || this.properties.message;
|
const message = this.getInputData(0) || this.properties.message;
|
||||||
if (!message)
|
if (!message)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
import { BuiltInSlotType, LiteGraph, type SlotLayout } from "@litegraph-ts/core";
|
||||||
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "../ComfyGraphNode";
|
import ComfyGraphNode, { type ComfyGraphNodeProperties } from "../ComfyGraphNode";
|
||||||
import { playSound } from "$lib/utils";
|
import { playSound } from "$lib/utils";
|
||||||
|
import configState from "$lib/stores/configState";
|
||||||
|
|
||||||
export interface ComfyPlaySoundActionProperties extends ComfyGraphNodeProperties {
|
export interface ComfyPlaySoundActionProperties extends ComfyGraphNodeProperties {
|
||||||
sound: string,
|
sound: string,
|
||||||
@@ -20,6 +21,9 @@ export default class ComfyPlaySoundAction extends ComfyGraphNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override onAction(action: any, param: any) {
|
override onAction(action: any, param: any) {
|
||||||
|
if (!configState.canPlayNotificationSound())
|
||||||
|
return;
|
||||||
|
|
||||||
const sound = this.getInputData(0) || this.properties.sound;
|
const sound = this.getInputData(0) || this.properties.sound;
|
||||||
if (sound) {
|
if (sound) {
|
||||||
playSound(sound)
|
playSound(sound)
|
||||||
|
|||||||
@@ -84,6 +84,41 @@ const defComfyUIPort: ConfigDefNumber<"comfyUIPort"> = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export enum NotificationState {
|
||||||
|
MessageAndSound,
|
||||||
|
MessageOnly,
|
||||||
|
SoundOnly,
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
const defNotifications: ConfigDefEnum<"notifications", NotificationState> = {
|
||||||
|
name: "notifications",
|
||||||
|
type: "enum",
|
||||||
|
defaultValue: NotificationState.MessageAndSound,
|
||||||
|
category: "ui",
|
||||||
|
description: "Controls how notifications are shown",
|
||||||
|
options: {
|
||||||
|
values: [
|
||||||
|
{
|
||||||
|
value: NotificationState.MessageAndSound,
|
||||||
|
label: "Message & sound"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: NotificationState.MessageOnly,
|
||||||
|
label: "Message only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: NotificationState.SoundOnly,
|
||||||
|
label: "Sound only"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
value: NotificationState.None,
|
||||||
|
label: "None"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const defAlwaysStripUserState: ConfigDefBoolean<"alwaysStripUserState"> = {
|
const defAlwaysStripUserState: ConfigDefBoolean<"alwaysStripUserState"> = {
|
||||||
name: "alwaysStripUserState",
|
name: "alwaysStripUserState",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
@@ -158,6 +193,7 @@ const defBuiltInTemplates: ConfigDefStringArray<"builtInTemplates"> = {
|
|||||||
export const CONFIG_DEFS = [
|
export const CONFIG_DEFS = [
|
||||||
defComfyUIHostname,
|
defComfyUIHostname,
|
||||||
defComfyUIPort,
|
defComfyUIPort,
|
||||||
|
defNotifications,
|
||||||
defAlwaysStripUserState,
|
defAlwaysStripUserState,
|
||||||
defPromptForWorkflowName,
|
defPromptForWorkflowName,
|
||||||
defConfirmWhenUnloadingUnsavedChanges,
|
defConfirmWhenUnloadingUnsavedChanges,
|
||||||
|
|||||||
@@ -2,10 +2,12 @@ import { debounce } from '$lib/utils';
|
|||||||
import { toHashMap } from '@litegraph-ts/core';
|
import { toHashMap } from '@litegraph-ts/core';
|
||||||
import { get, writable } from 'svelte/store';
|
import { get, writable } from 'svelte/store';
|
||||||
import type { Writable } from 'svelte/store';
|
import type { Writable } from 'svelte/store';
|
||||||
import { defaultConfig, type ConfigState, type ConfigDefAny, CONFIG_DEFS_BY_NAME, validateConfigOption } from './configDefs';
|
import { defaultConfig, type ConfigState, type ConfigDefAny, CONFIG_DEFS_BY_NAME, validateConfigOption, NotificationState } from './configDefs';
|
||||||
|
|
||||||
type ConfigStateOps = {
|
type ConfigStateOps = {
|
||||||
getBackendURL: () => string,
|
getBackendURL: () => string,
|
||||||
|
canShowNotificationText: () => boolean,
|
||||||
|
canPlayNotificationSound: () => boolean,
|
||||||
|
|
||||||
load: (data: any, runOnChanged?: boolean) => ConfigState
|
load: (data: any, runOnChanged?: boolean) => ConfigState
|
||||||
loadDefault: (runOnChanged?: boolean) => ConfigState
|
loadDefault: (runOnChanged?: boolean) => ConfigState
|
||||||
@@ -25,6 +27,17 @@ function getBackendURL(): string {
|
|||||||
return `${window.location.protocol}//${state.comfyUIHostname}:${state.comfyUIPort}`
|
return `${window.location.protocol}//${state.comfyUIHostname}:${state.comfyUIPort}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function canShowNotificationText(): boolean {
|
||||||
|
const state = get(store).notifications;
|
||||||
|
return state === NotificationState.MessageAndSound || state === NotificationState.MessageOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
function canPlayNotificationSound(): boolean {
|
||||||
|
const state = get(store).notifications;
|
||||||
|
return state === NotificationState.MessageAndSound || state === NotificationState.SoundOnly;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function setConfigOption(def: ConfigDefAny, v: any, runOnChanged: boolean): boolean {
|
function setConfigOption(def: ConfigDefAny, v: any, runOnChanged: boolean): boolean {
|
||||||
let valid = false;
|
let valid = false;
|
||||||
store.update(state => {
|
store.update(state => {
|
||||||
@@ -112,6 +125,9 @@ const configStateStore: WritableConfigStateStore =
|
|||||||
{
|
{
|
||||||
...store,
|
...store,
|
||||||
getBackendURL,
|
getBackendURL,
|
||||||
|
canShowNotificationText,
|
||||||
|
canPlayNotificationSound,
|
||||||
|
|
||||||
validateConfigOption,
|
validateConfigOption,
|
||||||
setConfigOption,
|
setConfigOption,
|
||||||
load,
|
load,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { playSound } from "$lib/utils";
|
|||||||
import { get, writable, type Writable } from "svelte/store";
|
import { get, writable, type Writable } from "svelte/store";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import workflowState, { type WorkflowError, type WorkflowExecutionError, type WorkflowInstID, type WorkflowValidationError } from "./workflowState";
|
import workflowState, { type WorkflowError, type WorkflowExecutionError, type WorkflowInstID, type WorkflowValidationError } from "./workflowState";
|
||||||
|
import configState from "./configState";
|
||||||
|
|
||||||
export type QueueEntryStatus = "success" | "validation_failed" | "error" | "interrupted" | "all_cached" | "unknown";
|
export type QueueEntryStatus = "success" | "validation_failed" | "error" | "interrupted" | "all_cached" | "unknown";
|
||||||
|
|
||||||
@@ -283,14 +284,18 @@ function executingUpdated(promptID: PromptID, runningNodeID: ComfyNodeID | null)
|
|||||||
if (entry != null) {
|
if (entry != null) {
|
||||||
const totalNodesInPrompt = Object.keys(entry.prompt).length
|
const totalNodesInPrompt = Object.keys(entry.prompt).length
|
||||||
if (entry.cachedNodes.size >= Object.keys(entry.prompt).length) {
|
if (entry.cachedNodes.size >= Object.keys(entry.prompt).length) {
|
||||||
notify("Prompt was cached, nothing to run.", { type: "warning" })
|
notify("Prompt was cached, nothing to run.", { type: "warning", showOn: "web" })
|
||||||
moveToCompleted(index, queue, "all_cached", "(Execution was cached)");
|
moveToCompleted(index, queue, "all_cached", "(Execution was cached)");
|
||||||
}
|
}
|
||||||
else if (entry.nodesRan.size >= totalNodesInPrompt) {
|
else if (entry.nodesRan.size >= totalNodesInPrompt) {
|
||||||
const workflow = workflowState.getWorkflow(entry.extraData.workflowID);
|
const workflow = workflowState.getWorkflow(entry.extraData.workflowID);
|
||||||
if (workflow?.attrs.showDefaultNotifications) {
|
if (workflow?.attrs.showDefaultNotifications) {
|
||||||
notify("Prompt finished!", { type: "success" });
|
if (configState.canShowNotificationText()) {
|
||||||
playSound("notification.mp3")
|
notify("Prompt finished!", { type: "success" });
|
||||||
|
}
|
||||||
|
if (configState.canPlayNotificationSound()) {
|
||||||
|
playSound("notification.mp3")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
moveToCompleted(index, queue, "success")
|
moveToCompleted(index, queue, "success")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -635,6 +635,9 @@ export function nextLetter(s: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function playSound(sound: string) {
|
export function playSound(sound: string) {
|
||||||
|
if (!configState.canPlayNotificationSound())
|
||||||
|
return;
|
||||||
|
|
||||||
const url = `${location.origin}/sound/${sound}`;
|
const url = `${location.origin}/sound/${sound}`;
|
||||||
const audio = new Audio(url);
|
const audio = new Audio(url);
|
||||||
audio.play();
|
audio.play();
|
||||||
|
|||||||
Reference in New Issue
Block a user