mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-07-19 02:06:38 +00:00
Compare commits
10 Commits
vue-widget
...
feat/check
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0548e68b6 | ||
|
|
588f59c6ae | ||
|
|
316755b5db | ||
|
|
e00886e538 | ||
|
|
72949d93e6 | ||
|
|
9a3547a24b | ||
|
|
a937ac59ad | ||
|
|
995979a4e1 | ||
|
|
c02ac95815 | ||
|
|
d01926b043 |
12
CLAUDE.md
12
CLAUDE.md
@@ -4,7 +4,7 @@
|
||||
- When trying to set tailwind classes for dark theme, use "dark-theme:" prefix rather than "dark:"
|
||||
- Never add lines to PR descriptions that say "Generated with Claude Code"
|
||||
- When making PR names and commit messages, if you are going to add a prefix like "docs:", "feat:", "bugfix:", use square brackets around the prefix term and do not use a colon (e.g., should be "[docs]" rather than "docs:").
|
||||
- When I reference GitHub Repos related to Comfy-Org, you should proactively fetch or read the associated information in the repo. To do so, you should exhaust all options: (1) Check if we have a local copy of the repo, (2) Use the GitHub API to fetch the information; you may want to do this IN ADDITION to the other options, especially for reading speicifc branches/PRs/comments/reviews/metadata, and (3) curl the GitHub website and parse the html or json responses
|
||||
- When I reference GitHub Repos related to Comfy-Org, you should proactively fetch or read the associated information in the repo. To do so, you should exhaust all options: (1) Check if we have a local copy of the repo, (2) Use the GitHub API to fetch the information; you may want to do this IN ADDITION to the other options, especially for reading specific branches/PRs/comments/reviews/metadata, and (3) curl the GitHub website and parse the html or json responses
|
||||
- For information about ComfyUI, ComfyUI_frontend, or ComfyUI-Manager, you can web search or download these wikis: https://deepwiki.com/Comfy-Org/ComfyUI-Manager, https://deepwiki.com/Comfy-Org/ComfyUI_frontend/1-overview, https://deepwiki.com/comfyanonymous/ComfyUI/2-core-architecture
|
||||
- If a question/project is related to Comfy-Org, Comfy, or ComfyUI ecosystem, you should proactively use the Comfy docs to answer the question. The docs may be referenced with URLs like https://docs.comfy.org
|
||||
- When operating inside a repo, check for README files at key locations in the repo detailing info about the contents of that folder. E.g., top-level key folders like tests-ui, browser_tests, composables, extensions/core, stores, services often have their own README.md files. When writing code, make sure to frequently reference these README files to understand the overall architecture and design of the project. Pay close attention to the snippets to learn particular patterns that seem to be there for a reason, as you should emulate those.
|
||||
@@ -12,7 +12,7 @@
|
||||
- If using a lesser known or complex CLI tool, run the --help to see the documentation before deciding what to run, even if just for double-checking or verifying things.
|
||||
- IMPORTANT: the most important goal when writing code is to create clean, best-practices, sustainable, and scalable public APIs and interfaces. Our app is used by thousands of users and we have thousands of mods/extensions that are constantly changing and updating; and we are also always updating. That's why it is IMPORTANT that we design systems and write code that follows practices of domain-driven design, object-oriented design, and design patterns (such that you can assure stability while allowing for all components around you to change and evolve). We ABSOLUTELY prioritize clean APIs and public interfaces that clearly define and restrict how/what the mods/extensions can access.
|
||||
- If any of these technologies are referenced, you can proactively read their docs at these locations: https://primevue.org/theming, https://primevue.org/forms/, https://www.electronjs.org/docs/latest/api/browser-window, https://vitest.dev/guide/browser/, https://atlassian.design/components/pragmatic-drag-and-drop/core-package/drop-targets/, https://playwright.dev/docs/api/class-test, https://playwright.dev/docs/api/class-electron, https://www.algolia.com/doc/api-reference/rest-api/, https://pyav.org/docs/develop/cookbook/basics.html
|
||||
- IMPORTANT: Never add Co-Authored by Claude or any refrence to Claude or Claude Code in commit messages, PR descriptions, titles, or any documentation whatsoever
|
||||
- IMPORTANT: Never add Co-Authored by Claude or any reference to Claude or Claude Code in commit messages, PR descriptions, titles, or any documentation whatsoever
|
||||
- The npm script to type check is called "typecheck" NOT "type check"
|
||||
- Use the Vue 3 Composition API instead of the Options API when writing Vue components. An exception is when overriding or extending a PrimeVue component for compatibility, you may use the Options API.
|
||||
- when we are solving an issue we know the link/number for, we should add "Fixes #n" (where n is the issue number) to the PR description.
|
||||
@@ -46,3 +46,11 @@
|
||||
* `TabMenu` → Use `Tabs` without panels
|
||||
* `Steps` → Use `Stepper` without panels
|
||||
* `InlineMessage` → Use `Message` component
|
||||
* Use `api.apiURL()` for all backend API calls and routes
|
||||
- Actual API endpoints like /prompt, /queue, /view, etc.
|
||||
- Image previews: `api.apiURL('/view?...')`
|
||||
- Any backend-generated content or dynamic routes
|
||||
* Use `api.fileURL()` for static files served from the public folder:
|
||||
- Templates: `api.fileURL('/templates/default.json')`
|
||||
- Extensions: `api.fileURL(extensionPath)` for loading JS modules
|
||||
- Any static assets that exist in the public directory
|
||||
|
||||
@@ -762,7 +762,7 @@ export class ComfyPage {
|
||||
y: 625
|
||||
}
|
||||
})
|
||||
this.page.mouse.move(10, 10)
|
||||
await this.page.mouse.move(10, 10)
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
@@ -774,7 +774,7 @@ export class ComfyPage {
|
||||
},
|
||||
button: 'right'
|
||||
})
|
||||
this.page.mouse.move(10, 10)
|
||||
await this.page.mouse.move(10, 10)
|
||||
await this.nextFrame()
|
||||
}
|
||||
|
||||
@@ -1046,6 +1046,8 @@ export class ComfyPage {
|
||||
}
|
||||
}
|
||||
|
||||
export const testComfySnapToGridGridSize = 50
|
||||
|
||||
export const comfyPageFixture = base.extend<{
|
||||
comfyPage: ComfyPage
|
||||
comfyMouse: ComfyMouse
|
||||
@@ -1072,7 +1074,8 @@ export const comfyPageFixture = base.extend<{
|
||||
'Comfy.EnableTooltips': false,
|
||||
'Comfy.userId': userId,
|
||||
// Set tutorial completed to true to avoid loading the tutorial workflow.
|
||||
'Comfy.TutorialCompleted': true
|
||||
'Comfy.TutorialCompleted': true,
|
||||
'Comfy.SnapToGrid.GridSize': testComfySnapToGridGridSize
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
|
||||
@@ -1,6 +1,12 @@
|
||||
import { expect } from '@playwright/test'
|
||||
import { Position } from '@vueuse/core'
|
||||
|
||||
import { type ComfyPage, comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
import {
|
||||
type ComfyPage,
|
||||
comfyPageFixture as test,
|
||||
testComfySnapToGridGridSize
|
||||
} from '../fixtures/ComfyPage'
|
||||
import { type NodeReference } from '../fixtures/utils/litegraphUtils'
|
||||
|
||||
test.describe('Item Interaction', () => {
|
||||
test('Can select/delete all items', async ({ comfyPage }) => {
|
||||
@@ -57,8 +63,10 @@ test.describe('Node Interaction', () => {
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('selected-node2.png')
|
||||
})
|
||||
|
||||
test('Can drag-select nodes with Meta (mac)', async ({ comfyPage }) => {
|
||||
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
|
||||
const dragSelectNodes = async (
|
||||
comfyPage: ComfyPage,
|
||||
clipNodes: NodeReference[]
|
||||
) => {
|
||||
const clipNode1Pos = await clipNodes[0].getPosition()
|
||||
const clipNode2Pos = await clipNodes[1].getPosition()
|
||||
const offset = 64
|
||||
@@ -74,10 +82,67 @@ test.describe('Node Interaction', () => {
|
||||
}
|
||||
)
|
||||
await comfyPage.page.keyboard.up('Meta')
|
||||
}
|
||||
|
||||
test('Can drag-select nodes with Meta (mac)', async ({ comfyPage }) => {
|
||||
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
|
||||
await dragSelectNodes(comfyPage, clipNodes)
|
||||
expect(await comfyPage.getSelectedGraphNodesCount()).toBe(
|
||||
clipNodes.length
|
||||
)
|
||||
})
|
||||
|
||||
test('Can move selected nodes using the Comfy.Canvas.MoveSelectedNodes.{Up|Down|Left|Right} commands', async ({
|
||||
comfyPage
|
||||
}) => {
|
||||
const clipNodes = await comfyPage.getNodeRefsByType('CLIPTextEncode')
|
||||
const getPositions = () =>
|
||||
Promise.all(clipNodes.map((node) => node.getPosition()))
|
||||
const testDirection = async ({
|
||||
direction,
|
||||
expectedPosition
|
||||
}: {
|
||||
direction: string
|
||||
expectedPosition: (originalPosition: Position) => Position
|
||||
}) => {
|
||||
const originalPositions = await getPositions()
|
||||
await dragSelectNodes(comfyPage, clipNodes)
|
||||
await comfyPage.executeCommand(
|
||||
`Comfy.Canvas.MoveSelectedNodes.${direction}`
|
||||
)
|
||||
await comfyPage.canvas.press(`Control+Arrow${direction}`)
|
||||
const newPositions = await getPositions()
|
||||
expect(newPositions).toEqual(originalPositions.map(expectedPosition))
|
||||
}
|
||||
await testDirection({
|
||||
direction: 'Down',
|
||||
expectedPosition: (originalPosition) => ({
|
||||
...originalPosition,
|
||||
y: originalPosition.y + testComfySnapToGridGridSize
|
||||
})
|
||||
})
|
||||
await testDirection({
|
||||
direction: 'Right',
|
||||
expectedPosition: (originalPosition) => ({
|
||||
...originalPosition,
|
||||
x: originalPosition.x + testComfySnapToGridGridSize
|
||||
})
|
||||
})
|
||||
await testDirection({
|
||||
direction: 'Up',
|
||||
expectedPosition: (originalPosition) => ({
|
||||
...originalPosition,
|
||||
y: originalPosition.y - testComfySnapToGridGridSize
|
||||
})
|
||||
})
|
||||
await testDirection({
|
||||
direction: 'Left',
|
||||
expectedPosition: (originalPosition) => ({
|
||||
...originalPosition,
|
||||
x: originalPosition.x - testComfySnapToGridGridSize
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
test('Can drag node', async ({ comfyPage }) => {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { createPinia, setActivePinia } from 'pinia'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { ref } from 'vue'
|
||||
|
||||
import TemplateWorkflowCard from '@/components/templates/TemplateWorkflowCard.vue'
|
||||
@@ -109,6 +110,10 @@ vi.mock('@/composables/useTemplateWorkflows', () => ({
|
||||
}))
|
||||
|
||||
describe('TemplateWorkflowCard', () => {
|
||||
beforeEach(() => {
|
||||
setActivePinia(createPinia())
|
||||
})
|
||||
|
||||
const createTemplate = (overrides = {}): TemplateInfo => ({
|
||||
name: 'test-template',
|
||||
mediaType: 'image',
|
||||
|
||||
@@ -2,14 +2,18 @@
|
||||
<Card
|
||||
ref="cardRef"
|
||||
:data-testid="`template-workflow-${template.name}`"
|
||||
class="w-64 template-card rounded-2xl overflow-hidden cursor-pointer shadow-elevation-2 dark-theme:bg-dark-elevation-1.5 h-full"
|
||||
class="w-64 template-card rounded-2xl overflow-hidden shadow-elevation-2 dark-theme:bg-dark-elevation-1.5 h-full"
|
||||
:class="{
|
||||
'cursor-pointer': isCompatible,
|
||||
'cursor-not-allowed opacity-60 grayscale': !isCompatible
|
||||
}"
|
||||
:pt="{
|
||||
body: { class: 'p-0 h-full flex flex-col' }
|
||||
}"
|
||||
@click="$emit('loadWorkflow', template.name)"
|
||||
@click="handleCardClick"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="flex items-center justify-center relative">
|
||||
<div class="relative overflow-hidden rounded-t-lg">
|
||||
<template v-if="template.mediaType === 'audio'">
|
||||
<AudioThumbnail :src="baseThumbnailSrc" />
|
||||
@@ -19,7 +23,7 @@
|
||||
:base-image-src="baseThumbnailSrc"
|
||||
:overlay-image-src="overlayThumbnailSrc"
|
||||
:alt="title"
|
||||
:is-hovered="isHovered"
|
||||
:is-hovered="isHovered && isCompatible"
|
||||
:is-video="
|
||||
template.mediaType === 'video' ||
|
||||
template.mediaSubtype === 'webp'
|
||||
@@ -31,7 +35,7 @@
|
||||
:base-image-src="baseThumbnailSrc"
|
||||
:overlay-image-src="overlayThumbnailSrc"
|
||||
:alt="title"
|
||||
:is-hovered="isHovered"
|
||||
:is-hovered="isHovered && isCompatible"
|
||||
:is-video="
|
||||
template.mediaType === 'video' ||
|
||||
template.mediaSubtype === 'webp'
|
||||
@@ -42,7 +46,7 @@
|
||||
<DefaultThumbnail
|
||||
:src="baseThumbnailSrc"
|
||||
:alt="title"
|
||||
:is-hovered="isHovered"
|
||||
:is-hovered="isHovered && isCompatible"
|
||||
:is-video="
|
||||
template.mediaType === 'video' ||
|
||||
template.mediaSubtype === 'webp'
|
||||
@@ -59,6 +63,21 @@
|
||||
class="absolute inset-0 z-1 w-3/12 h-full"
|
||||
/>
|
||||
</div>
|
||||
<!-- Version incompatibility indicator -->
|
||||
<div
|
||||
v-if="!isCompatible"
|
||||
class="absolute top-2 right-2 bg-yellow-500 text-white text-xs px-2 py-1 rounded-full flex items-center gap-1 shadow-lg z-10"
|
||||
:title="
|
||||
$t('templateWorkflows.requiresUpgrade', {
|
||||
version: template.versionRequired
|
||||
})
|
||||
"
|
||||
>
|
||||
<i class="pi pi-exclamation-triangle text-xs"></i>
|
||||
<span class="text-xs font-medium"
|
||||
>v{{ template.versionRequired }}+</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<template #content>
|
||||
@@ -70,6 +89,21 @@
|
||||
<p class="line-clamp-2 text-sm text-muted grow" :title="description">
|
||||
{{ description }}
|
||||
</p>
|
||||
<!-- Upgrade prompt for incompatible templates -->
|
||||
<div
|
||||
v-if="!isCompatible"
|
||||
class="mt-2 text-xs text-yellow-600 dark:text-yellow-400 font-medium"
|
||||
>
|
||||
{{ $t('templateWorkflows.upgradeToUse') }}
|
||||
<br />
|
||||
<span class="text-muted">
|
||||
{{
|
||||
$t('templateWorkflows.currentVersion', {
|
||||
version: currentVersion
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -87,7 +121,9 @@ import CompareSliderThumbnail from '@/components/templates/thumbnails/CompareSli
|
||||
import DefaultThumbnail from '@/components/templates/thumbnails/DefaultThumbnail.vue'
|
||||
import HoverDissolveThumbnail from '@/components/templates/thumbnails/HoverDissolveThumbnail.vue'
|
||||
import { useTemplateWorkflows } from '@/composables/useTemplateWorkflows'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import { TemplateInfo } from '@/types/workflowTemplateTypes'
|
||||
import { compareVersions } from '@/utils/formatUtil'
|
||||
|
||||
const UPSCALE_ZOOM_SCALE = 16 // for upscale templates, exaggerate the hover zoom
|
||||
const DEFAULT_ZOOM_SCALE = 5
|
||||
@@ -101,6 +137,7 @@ const { sourceModule, loading, template } = defineProps<{
|
||||
|
||||
const cardRef = ref<HTMLElement | null>(null)
|
||||
const isHovered = useElementHover(cardRef)
|
||||
const systemStatsStore = useSystemStatsStore()
|
||||
|
||||
const { getTemplateThumbnailUrl, getTemplateTitle, getTemplateDescription } =
|
||||
useTemplateWorkflows()
|
||||
@@ -133,7 +170,31 @@ const title = computed(() =>
|
||||
getTemplateTitle(template, effectiveSourceModule.value)
|
||||
)
|
||||
|
||||
defineEmits<{
|
||||
// Version compatibility check
|
||||
const currentVersion = computed(() => {
|
||||
return systemStatsStore.systemStats?.system?.comfyui_version || ''
|
||||
})
|
||||
|
||||
const isCompatible = computed(() => {
|
||||
if (!template.versionRequired) {
|
||||
return true // No version requirement, always compatible
|
||||
}
|
||||
|
||||
if (!currentVersion.value) {
|
||||
return false // No current version available, assume incompatible
|
||||
}
|
||||
|
||||
// Return true if current version is >= required version
|
||||
return compareVersions(currentVersion.value, template.versionRequired) >= 0
|
||||
})
|
||||
|
||||
const emit = defineEmits<{
|
||||
loadWorkflow: [name: string]
|
||||
}>()
|
||||
|
||||
const handleCardClick = () => {
|
||||
if (isCompatible.value) {
|
||||
emit('loadWorkflow', template.name)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -56,12 +56,13 @@ import { useAsyncState } from '@vueuse/core'
|
||||
import Button from 'primevue/button'
|
||||
import Divider from 'primevue/divider'
|
||||
import ProgressSpinner from 'primevue/progressspinner'
|
||||
import { watch } from 'vue'
|
||||
import { onMounted, watch } from 'vue'
|
||||
|
||||
import TemplateWorkflowView from '@/components/templates/TemplateWorkflowView.vue'
|
||||
import TemplateWorkflowsSideNav from '@/components/templates/TemplateWorkflowsSideNav.vue'
|
||||
import { useResponsiveCollapse } from '@/composables/element/useResponsiveCollapse'
|
||||
import { useTemplateWorkflows } from '@/composables/useTemplateWorkflows'
|
||||
import { useSystemStatsStore } from '@/stores/systemStatsStore'
|
||||
import type { WorkflowTemplates } from '@/types/workflowTemplateTypes'
|
||||
|
||||
const {
|
||||
@@ -82,6 +83,14 @@ const {
|
||||
} = useTemplateWorkflows()
|
||||
|
||||
const { isReady } = useAsyncState(loadTemplates, null)
|
||||
const systemStatsStore = useSystemStatsStore()
|
||||
|
||||
// Initialize system stats when component mounts
|
||||
onMounted(async () => {
|
||||
if (!systemStatsStore.systemStats) {
|
||||
await systemStatsStore.fetchSystemStats()
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
isReady,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
LGraphNode,
|
||||
LiteGraph
|
||||
} from '@comfyorg/litegraph'
|
||||
import { Point } from '@comfyorg/litegraph'
|
||||
|
||||
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
|
||||
import {
|
||||
@@ -27,6 +28,8 @@ import { useColorPaletteStore } from '@/stores/workspace/colorPaletteStore'
|
||||
import { useSearchBoxStore } from '@/stores/workspace/searchBoxStore'
|
||||
import { useWorkspaceStore } from '@/stores/workspaceStore'
|
||||
|
||||
const moveSelectedNodesVersionAdded = '1.22.2'
|
||||
|
||||
export function useCoreCommands(): ComfyCommand[] {
|
||||
const workflowService = useWorkflowService()
|
||||
const workflowStore = useWorkflowStore()
|
||||
@@ -58,6 +61,20 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
})
|
||||
}
|
||||
|
||||
const moveSelectedNodes = (
|
||||
positionUpdater: (pos: Point, gridSize: number) => Point
|
||||
) => {
|
||||
const selectedNodes = getSelectedNodes()
|
||||
if (selectedNodes.length === 0) return
|
||||
|
||||
const gridSize = useSettingStore().get('Comfy.SnapToGrid.GridSize')
|
||||
selectedNodes.forEach((node) => {
|
||||
node.pos = positionUpdater(node.pos, gridSize)
|
||||
})
|
||||
app.canvas.state.selectionChanged = true
|
||||
app.canvas.setDirty(true, true)
|
||||
}
|
||||
|
||||
const commands = [
|
||||
{
|
||||
id: 'Comfy.NewBlankWorkflow',
|
||||
@@ -673,6 +690,34 @@ export function useCoreCommands(): ComfyCommand[] {
|
||||
function: async () => {
|
||||
await firebaseAuthActions.logout()
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.MoveSelectedNodes.Up',
|
||||
icon: 'pi pi-arrow-up',
|
||||
label: 'Move Selected Nodes Up',
|
||||
versionAdded: moveSelectedNodesVersionAdded,
|
||||
function: () => moveSelectedNodes(([x, y], gridSize) => [x, y - gridSize])
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.MoveSelectedNodes.Down',
|
||||
icon: 'pi pi-arrow-down',
|
||||
label: 'Move Selected Nodes Down',
|
||||
versionAdded: moveSelectedNodesVersionAdded,
|
||||
function: () => moveSelectedNodes(([x, y], gridSize) => [x, y + gridSize])
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.MoveSelectedNodes.Left',
|
||||
icon: 'pi pi-arrow-left',
|
||||
label: 'Move Selected Nodes Left',
|
||||
versionAdded: moveSelectedNodesVersionAdded,
|
||||
function: () => moveSelectedNodes(([x, y], gridSize) => [x - gridSize, y])
|
||||
},
|
||||
{
|
||||
id: 'Comfy.Canvas.MoveSelectedNodes.Right',
|
||||
icon: 'pi pi-arrow-right',
|
||||
label: 'Move Selected Nodes Right',
|
||||
versionAdded: moveSelectedNodesVersionAdded,
|
||||
function: () => moveSelectedNodes(([x, y], gridSize) => [x + gridSize, y])
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -501,6 +501,9 @@
|
||||
},
|
||||
"templateWorkflows": {
|
||||
"title": "Get Started with a Template",
|
||||
"requiresUpgrade": "Requires ComfyUI v{version} or higher",
|
||||
"upgradeToUse": "Upgrade to use this template",
|
||||
"currentVersion": "Current version: v{version}",
|
||||
"category": {
|
||||
"ComfyUI Examples": "ComfyUI Examples",
|
||||
"Custom Nodes": "Custom Nodes",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "Video",
|
||||
"Video API": "API de Video"
|
||||
},
|
||||
"currentVersion": "Versión actual: v{version}",
|
||||
"requiresUpgrade": "Requiere ComfyUI v{version} o superior",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "Hunyuan3D 2.0 MV",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "Usa la API Google Veo2 para generar videos a partir de imágenes."
|
||||
}
|
||||
},
|
||||
"title": "Comienza con una Plantilla"
|
||||
"title": "Comienza con una Plantilla",
|
||||
"upgradeToUse": "Actualiza para usar esta plantilla"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "No se pudo determinar el tipo de archivo",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "Vidéo",
|
||||
"Video API": "API vidéo"
|
||||
},
|
||||
"currentVersion": "Version actuelle : v{version}",
|
||||
"requiresUpgrade": "Nécessite ComfyUI v{version} ou supérieur",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "Hunyuan3D Multivue",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "Utilisez l'API Google Veo2 pour générer des vidéos à partir d'images."
|
||||
}
|
||||
},
|
||||
"title": "Commencez avec un modèle"
|
||||
"title": "Commencez avec un modèle",
|
||||
"upgradeToUse": "Mettez à jour pour utiliser ce modèle"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "Impossible de déterminer le type de fichier",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "ビデオ",
|
||||
"Video API": "動画API"
|
||||
},
|
||||
"currentVersion": "現在のバージョン: v{version}",
|
||||
"requiresUpgrade": "ComfyUI v{version} 以上が必要です",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "Hunyuan3D マルチビュー",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "Google Veo2 APIで画像から動画を生成します。"
|
||||
}
|
||||
},
|
||||
"title": "テンプレートを利用して開始"
|
||||
"title": "テンプレートを利用して開始",
|
||||
"upgradeToUse": "このテンプレートを使用するにはアップグレードしてください"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "ファイルタイプを判断できませんでした",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "비디오",
|
||||
"Video API": "비디오 API"
|
||||
},
|
||||
"currentVersion": "현재 버전: v{version}",
|
||||
"requiresUpgrade": "ComfyUI v{version} 이상이 필요합니다",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "Hunyuan3D 다중뷰",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "Google Veo2 API로 이미지에서 비디오를 생성합니다."
|
||||
}
|
||||
},
|
||||
"title": "템플릿으로 시작하기"
|
||||
"title": "템플릿으로 시작하기",
|
||||
"upgradeToUse": "이 템플릿을 사용하려면 업그레이드하세요"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "파일 유형을 결정할 수 없습니다",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "Видео",
|
||||
"Video API": "Video API"
|
||||
},
|
||||
"currentVersion": "Текущая версия: v{version}",
|
||||
"requiresUpgrade": "Требуется ComfyUI версии {version} или выше",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "Hunyuan3D Многовидовой",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "Используйте Google Veo2 API для генерации видео из изображений."
|
||||
}
|
||||
},
|
||||
"title": "Начните с шаблона"
|
||||
"title": "Начните с шаблона",
|
||||
"upgradeToUse": "Обновите, чтобы использовать этот шаблон"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "Не удалось определить тип файла",
|
||||
|
||||
@@ -1152,6 +1152,8 @@
|
||||
"Video": "视频",
|
||||
"Video API": "视频 API"
|
||||
},
|
||||
"currentVersion": "当前版本:v{version}",
|
||||
"requiresUpgrade": "需要 ComfyUI v{version} 或更高版本",
|
||||
"template": {
|
||||
"3D": {
|
||||
"hunyuan-3d-multiview-elf": "混元3D多视图",
|
||||
@@ -1354,7 +1356,8 @@
|
||||
"api_veo2_i2v": "使用 Google Veo2 API 通过图像生成视频。"
|
||||
}
|
||||
},
|
||||
"title": "从模板开始"
|
||||
"title": "从模板开始",
|
||||
"upgradeToUse": "升级以使用此模板"
|
||||
},
|
||||
"toastMessages": {
|
||||
"couldNotDetermineFileType": "无法确定文件类型",
|
||||
|
||||
@@ -124,19 +124,7 @@ export const useAlgoliaSearchService = (
|
||||
maxCacheSize = DEFAULT_MAX_CACHE_SIZE,
|
||||
minCharsForSuggestions = DEFAULT_MIN_CHARS_FOR_SUGGESTIONS
|
||||
} = options
|
||||
const searchClient = algoliasearch(__ALGOLIA_APP_ID__, __ALGOLIA_API_KEY__, {
|
||||
hosts: [
|
||||
{
|
||||
url: 'search.comfy.org/api/search',
|
||||
accept: 'read',
|
||||
protocol: 'https'
|
||||
}
|
||||
],
|
||||
baseHeaders: {
|
||||
'X-Algolia-Application-Id': __ALGOLIA_APP_ID__,
|
||||
'X-Algolia-API-Key': __ALGOLIA_API_KEY__
|
||||
}
|
||||
})
|
||||
const searchClient = algoliasearch(__ALGOLIA_APP_ID__, __ALGOLIA_API_KEY__)
|
||||
const searchPacksCache = new QuickLRU<string, SearchPacksResult>({
|
||||
maxSize: maxCacheSize
|
||||
})
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,6 +12,10 @@ export interface TemplateInfo {
|
||||
localizedTitle?: string
|
||||
localizedDescription?: string
|
||||
sourceModule?: string
|
||||
/**
|
||||
* Minimum version of ComfyUI required to use this template
|
||||
*/
|
||||
versionRequired?: string
|
||||
}
|
||||
|
||||
export interface WorkflowTemplates {
|
||||
|
||||
Reference in New Issue
Block a user