mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-03-07 22:20:03 +00:00
Merge main (as of 10-06-2025) into rh-test (#5965)
## Summary Merges latest changes from `main` as of 10-06-2025. ┆Issue is synchronized with this [Notion page](https://www.notion.so/PR-5965-Merge-main-as-of-10-06-2025-into-rh-test-2856d73d3650812cb95fd8917278a770) by [Unito](https://www.unito.io) --------- Signed-off-by: Marcel Petrick <mail@marcelpetrick.it> Co-authored-by: filtered <176114999+webfiltered@users.noreply.github.com> Co-authored-by: Christian Byrne <cbyrne@comfy.org> Co-authored-by: github-actions <github-actions@github.com> Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Alexander Brown <drjkl@comfy.org> Co-authored-by: Benjamin Lu <benceruleanlu@proton.me> Co-authored-by: Terry Jia <terryjia88@gmail.com> Co-authored-by: snomiao <snomiao@gmail.com> Co-authored-by: Simula_r <18093452+simula-r@users.noreply.github.com> Co-authored-by: Jake Schroeder <jake.schroeder@isophex.com> Co-authored-by: Comfy Org PR Bot <snomiao+comfy-pr@gmail.com> Co-authored-by: AustinMroz <4284322+AustinMroz@users.noreply.github.com> Co-authored-by: GitHub Action <action@github.com> Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com> Co-authored-by: Marcel Petrick <mail@marcelpetrick.it> Co-authored-by: Alexander Brown <DrJKL0424@gmail.com> Co-authored-by: Benjamin Lu <benjaminlu1107@gmail.com> Co-authored-by: Alexander Piskun <13381981+bigcat88@users.noreply.github.com> Co-authored-by: Rizumu Ayaka <rizumu@ayaka.moe> Co-authored-by: JakeSchroeder <jake@axiom.co> Co-authored-by: AustinMroz <austin@comfy.org> Co-authored-by: DrJKL <DrJKL@users.noreply.github.com> Co-authored-by: ComfyUI Wiki <contact@comfyui-wiki.com>
This commit is contained in:
@@ -1,30 +0,0 @@
|
||||
import { SerializeAddon } from '@xterm/addon-serialize'
|
||||
import { Terminal } from '@xterm/xterm'
|
||||
import { markRaw, onMounted, onUnmounted } from 'vue'
|
||||
|
||||
export function useTerminalBuffer() {
|
||||
const serializeAddon = new SerializeAddon()
|
||||
const terminal = markRaw(new Terminal({ convertEol: true }))
|
||||
|
||||
const copyTo = (destinationTerminal: Terminal) => {
|
||||
destinationTerminal.write(serializeAddon.serialize())
|
||||
}
|
||||
|
||||
const write = (message: string) => terminal.write(message)
|
||||
|
||||
const serialize = () => serializeAddon.serialize()
|
||||
|
||||
onMounted(() => {
|
||||
terminal.loadAddon(serializeAddon)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
terminal.dispose()
|
||||
})
|
||||
|
||||
return {
|
||||
copyTo,
|
||||
serialize,
|
||||
write
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import type { Ref } from 'vue'
|
||||
import { useSelectedLiteGraphItems } from '@/composables/canvas/useSelectedLiteGraphItems'
|
||||
import { useVueFeatureFlags } from '@/composables/useVueFeatureFlags'
|
||||
import type { ReadOnlyRect } from '@/lib/litegraph/src/interfaces'
|
||||
import { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { LGraphGroup, LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import { useCanvasStore } from '@/renderer/core/canvas/canvasStore'
|
||||
import { layoutStore } from '@/renderer/core/layout/store/layoutStore'
|
||||
import { isLGraphGroup, isLGraphNode } from '@/utils/litegraphUtil'
|
||||
@@ -89,7 +89,7 @@ export function useSelectionToolboxPosition(
|
||||
}
|
||||
} else {
|
||||
// Fallback to LiteGraph bounds for regular nodes or non-string IDs
|
||||
if (item instanceof LGraphNode) {
|
||||
if (item instanceof LGraphNode || item instanceof LGraphGroup) {
|
||||
const bounds = item.getBounding()
|
||||
allBounds.push([bounds[0], bounds[1], bounds[2], bounds[3]] as const)
|
||||
}
|
||||
|
||||
@@ -241,7 +241,7 @@ export function useGraphNodeManager(graph: LGraph): GraphNodeManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up widget callbacks for a node - now with reduced nesting
|
||||
* Sets up widget callbacks for a node
|
||||
*/
|
||||
const setupNodeWidgetCallbacks = (node: LGraphNode) => {
|
||||
if (!node.widgets) return
|
||||
|
||||
@@ -98,7 +98,7 @@ const useNodePreview = <T extends MediaElement>(
|
||||
/**
|
||||
* Attaches a preview image to a node.
|
||||
*/
|
||||
export const useNodeImage = (node: LGraphNode) => {
|
||||
export const useNodeImage = (node: LGraphNode, callback?: () => void) => {
|
||||
node.previewMediaType = 'image'
|
||||
|
||||
const loadElement = (url: string): Promise<HTMLImageElement | null> =>
|
||||
@@ -112,6 +112,7 @@ export const useNodeImage = (node: LGraphNode) => {
|
||||
const onLoaded = (elements: HTMLImageElement[]) => {
|
||||
node.imageIndex = null
|
||||
node.imgs = elements
|
||||
callback?.()
|
||||
}
|
||||
|
||||
return useNodePreview(node, {
|
||||
@@ -126,7 +127,7 @@ export const useNodeImage = (node: LGraphNode) => {
|
||||
/**
|
||||
* Attaches a preview video to a node.
|
||||
*/
|
||||
export const useNodeVideo = (node: LGraphNode) => {
|
||||
export const useNodeVideo = (node: LGraphNode, callback?: () => void) => {
|
||||
node.previewMediaType = 'video'
|
||||
let minHeight = DEFAULT_VIDEO_SIZE
|
||||
let minWidth = DEFAULT_VIDEO_SIZE
|
||||
@@ -187,6 +188,7 @@ export const useNodeVideo = (node: LGraphNode) => {
|
||||
}
|
||||
|
||||
node.videoContainer.replaceChildren(videoElement)
|
||||
callback?.()
|
||||
}
|
||||
|
||||
return useNodePreview(node, {
|
||||
|
||||
@@ -300,9 +300,6 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
const modeValue = String(modeWidget.value)
|
||||
const durationValue = String(durationWidget.value)
|
||||
const modelValue = String(modelWidget.value)
|
||||
console.log('modelValue', modelValue)
|
||||
console.log('modeValue', modeValue)
|
||||
console.log('durationValue', durationValue)
|
||||
|
||||
// Same pricing matrix as KlingTextToVideoNode
|
||||
if (modelValue.includes('v1-6') || modelValue.includes('v1-5')) {
|
||||
@@ -356,12 +353,14 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
const modeValue = String(modeWidget.value)
|
||||
const durationValue = String(durationWidget.value)
|
||||
const modelValue = String(modelWidget.value)
|
||||
console.log('modelValue', modelValue)
|
||||
console.log('modeValue', modeValue)
|
||||
console.log('durationValue', durationValue)
|
||||
|
||||
// Same pricing matrix as KlingTextToVideoNode
|
||||
if (
|
||||
if (modelValue.includes('v2-5-turbo')) {
|
||||
if (durationValue.includes('10')) {
|
||||
return '$0.70/Run'
|
||||
}
|
||||
return '$0.35/Run' // 5s default
|
||||
} else if (
|
||||
modelValue.includes('v2-1-master') ||
|
||||
modelValue.includes('v2-master')
|
||||
) {
|
||||
@@ -511,7 +510,12 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
const modeValue = String(modeWidget.value)
|
||||
|
||||
// Pricing matrix from CSV data based on mode string content
|
||||
if (modeValue.includes('v2-1-master')) {
|
||||
if (modeValue.includes('v2-5-turbo')) {
|
||||
if (modeValue.includes('10')) {
|
||||
return '$0.70/Run'
|
||||
}
|
||||
return '$0.35/Run' // 5s default
|
||||
} else if (modeValue.includes('v2-1-master')) {
|
||||
if (modeValue.includes('10s')) {
|
||||
return '$2.80/Run' // price is the same as for v2-master model
|
||||
}
|
||||
@@ -564,9 +568,6 @@ const apiNodeCosts: Record<string, { displayPrice: string | PricingFunction }> =
|
||||
const model = String(modelWidget.value)
|
||||
const resolution = String(resolutionWidget.value).toLowerCase()
|
||||
const duration = String(durationWidget.value)
|
||||
console.log('model', model)
|
||||
console.log('resolution', resolution)
|
||||
console.log('duration', duration)
|
||||
|
||||
if (model.includes('ray-flash-2')) {
|
||||
if (duration.includes('5s')) {
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
DEFAULT_DARK_COLOR_PALETTE,
|
||||
DEFAULT_LIGHT_COLOR_PALETTE
|
||||
} from '@/constants/coreColorPalettes'
|
||||
import { promoteRecommendedWidgets } from '@/core/graph/subgraph/proxyWidgetUtils'
|
||||
import { t } from '@/i18n'
|
||||
import {
|
||||
LGraphEventMode,
|
||||
@@ -14,6 +15,8 @@ import {
|
||||
SubgraphNode
|
||||
} from '@/lib/litegraph/src/litegraph'
|
||||
import type { Point } from '@/lib/litegraph/src/litegraph'
|
||||
import { useAssetBrowserDialog } from '@/platform/assets/composables/useAssetBrowserDialog'
|
||||
import { createModelNodeFromAsset } from '@/platform/assets/utils/createModelNodeFromAsset'
|
||||
import { useSettingStore } from '@/platform/settings/settingStore'
|
||||
import { useToastStore } from '@/platform/updates/common/toastStore'
|
||||
import { useWorkflowService } from '@/platform/workflow/core/services/workflowService'
|
||||
@@ -909,6 +912,7 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
|
||||
const { node } = res
|
||||
canvas.select(node)
|
||||
promoteRecommendedWidgets(node)
|
||||
canvasStore.updateSelectedItems()
|
||||
}
|
||||
},
|
||||
@@ -1060,6 +1064,60 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
}
|
||||
await api.freeMemory({ freeExecutionCache: true })
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'Comfy.BrowseModelAssets',
|
||||
icon: 'pi pi-folder-open',
|
||||
label: 'Experimental: Browse Model Assets',
|
||||
versionAdded: '1.28.3',
|
||||
function: async () => {
|
||||
if (!useSettingStore().get('Comfy.Assets.UseAssetAPI')) {
|
||||
const confirmed = await dialogService.confirm({
|
||||
title: 'Enable Asset API',
|
||||
message:
|
||||
'The Asset API is currently disabled. Would you like to enable it?',
|
||||
type: 'default'
|
||||
})
|
||||
|
||||
if (!confirmed) return
|
||||
|
||||
const settingStore = useSettingStore()
|
||||
await settingStore.set('Comfy.Assets.UseAssetAPI', true)
|
||||
await workflowService.reloadCurrentWorkflow()
|
||||
}
|
||||
const assetBrowserDialog = useAssetBrowserDialog()
|
||||
await assetBrowserDialog.browse({
|
||||
assetType: 'models',
|
||||
title: t('sideToolbar.modelLibrary'),
|
||||
onAssetSelected: (asset) => {
|
||||
const result = createModelNodeFromAsset(asset)
|
||||
if (!result.success) {
|
||||
toastStore.add({
|
||||
severity: 'error',
|
||||
summary: t('g.error'),
|
||||
detail: t('assetBrowser.failedToCreateNode')
|
||||
})
|
||||
console.error('Node creation failed:', result.error)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'Comfy.ToggleAssetAPI',
|
||||
icon: 'pi pi-database',
|
||||
label: () =>
|
||||
`Experimental: ${
|
||||
useSettingStore().get('Comfy.Assets.UseAssetAPI')
|
||||
? 'Disable'
|
||||
: 'Enable'
|
||||
} AssetAPI`,
|
||||
function: async () => {
|
||||
const settingStore = useSettingStore()
|
||||
const current = settingStore.get('Comfy.Assets.UseAssetAPI') ?? false
|
||||
await settingStore.set('Comfy.Assets.UseAssetAPI', !current)
|
||||
await useWorkflowService().reloadCurrentWorkflow() // ensure changes take effect immediately
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user