From 86e2b1fc611b4d63960c2a6b98abd65ae22bcc0d Mon Sep 17 00:00:00 2001 From: Deep Roy Date: Thu, 14 Aug 2025 09:37:48 -0400 Subject: [PATCH] Add analytics for workflow loading (#4966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Needs to land after https://github.com/Comfy-Org/cloud/pull/398 ## Description - Adds a postCloudAnalytics method in `api.ts` - Adds a workflow_loaded event - The event contains - the source (not file type, more like workflow format) one of: - apiJson (I think this is the "prompt" format?) - graph (the richest type) - template: don't fully understand this but it works - The actual data for the workflow, depends on the source type - If available, missingModels and missingNodeTypes, so we can easily query those This talks to a new endpoint on the ingest server that is being added. ## Tests Tested manually with: - loading an image from civitAI with missing models - loading an image from comfy examples with no missing models - opening a json file in the prompt format (I asked claude to generate one - this is the format handled by the loadApiJson function) - opening a template file (claude generated one - this is the format handled by loadTemplateJson function) - Testing these for both dragAndDrop and (menu --> open --> open workflow) ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-4966-Add-analytics-for-workflow-loading-24e6d73d36508170acacefb3125b7017) by [Unito](https://www.unito.io) --- src/scripts/api.ts | 22 ++++++++++++++++++++++ src/scripts/app.ts | 15 +++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/scripts/api.ts b/src/scripts/api.ts index 8e2d4f81e1..39d79589fc 100644 --- a/src/scripts/api.ts +++ b/src/scripts/api.ts @@ -1275,6 +1275,28 @@ export class ComfyApi extends EventTarget { getServerFeatures(): Record { return { ...this.serverFeatureFlags } } + + /** + * Posts analytics event to cloud analytics service + * @param eventName The name of the analytics event + * @param eventData The event data (any JSON-serializable object) + * @returns Promise resolving to the response + */ + async postCloudAnalytics( + eventName: string, + eventData: any + ): Promise { + return this.fetchApi(this.internalURL('/cloud_analytics'), { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + event_name: eventName, + event_data: eventData + }) + }) + } } export const api = new ComfyApi() diff --git a/src/scripts/app.ts b/src/scripts/app.ts index e77f7842fd..24ef7d220f 100644 --- a/src/scripts/app.ts +++ b/src/scripts/app.ts @@ -997,6 +997,10 @@ export class ComfyApp { if (!templateData?.templates) { return } + api.postCloudAnalytics('load_workflow', { + source: 'template', + sourceData: { templateData } + }) const old = localStorage.getItem('litegrapheditor_clipboard') @@ -1277,6 +1281,12 @@ export class ComfyApp { const paths = await api.getFolderPaths() this.#showMissingModelsError(missingModels, paths) } + api.postCloudAnalytics('load_workflow', { + source: 'graph', + graph: this.graph.asSerialisable(), + missingNodeTypes, + missingModels + }) await useExtensionService().invokeExtensionsAsync( 'afterConfigureGraph', missingNodeTypes @@ -1585,6 +1595,11 @@ export class ComfyApp { const missingNodeTypes = Object.values(apiData).filter( (n) => !LiteGraph.registered_node_types[n.class_type] ) + api.postCloudAnalytics('load_workflow', { + source: 'api_json', + missingNodeTypes, + apiJson: apiData + }) if (missingNodeTypes.length) { this.#showMissingNodesError(missingNodeTypes.map((t) => t.class_type)) return