Merge pull request #94 from space-nuko/disable-notifications

Option to control how notifications are shown
This commit is contained in:
space-nuko
2023-05-29 10:31:40 -05:00
committed by GitHub
7 changed files with 77 additions and 7 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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)

View File

@@ -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,

View File

@@ -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,

View File

@@ -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")
} }

View File

@@ -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();