Choose generation mode automatically from starting image
This commit is contained in:
+17
-33
@@ -16,7 +16,6 @@
|
||||
:image-engine="v2Engine"
|
||||
@select="selectStudioKind"
|
||||
@video-engine="selectVideoEngine"
|
||||
@video-start="selectVideoStart"
|
||||
@image-engine="setV2Engine"
|
||||
/>
|
||||
<div class="grid min-w-0 gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] lg:items-stretch">
|
||||
@@ -25,7 +24,7 @@
|
||||
<h2 class="font-display text-2xl font-bold">Input</h2>
|
||||
<p class="text-sm text-zinc-400">{{ studioMode === 'editv2'
|
||||
? (v2Mode === 'generate'
|
||||
? 'Generate: no reference image. Prompt only.'
|
||||
? 'Text-to-image: describe what you want. Add a starting image to switch to image-to-image.'
|
||||
: v2Mode === 'iterate'
|
||||
? (file
|
||||
? (editRefFile
|
||||
@@ -41,7 +40,7 @@
|
||||
? 'Drop the still to edit. An optional second still applies image 2 onto image 1. Files leave the desktop after save.'
|
||||
: (textToVideo
|
||||
? 'Text-to-video: write a prompt and generate. No start still required. Shot 2+ still continues from the last frame.'
|
||||
: 'Drop a still, describe the motion, then send the job. Switch the Video card to Text for text-to-video.') }}</p>
|
||||
: 'Describe the motion and generate. Add a starting image for image-to-video; remove it for text-to-video.') }}</p>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -85,10 +84,11 @@
|
||||
<span class="mt-1 block text-zinc-500">Text-to-video does not need one. Shot 2+ still extends from the last frame.</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'generate' && (file || inputStillId)"
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'generate'"
|
||||
class="rounded-2xl border border-white/10 bg-zinc-950/40 px-4 py-3 text-sm text-zinc-400"
|
||||
>
|
||||
Still A is loaded for Edit / Compose / Refine / Iterate. Generate ignores it and uses the prompt only.
|
||||
<button type="button" class="font-medium text-amber-100 hover:underline" @click="openPicker('main')">Optional · add a starting image</button>
|
||||
<span class="mt-1 block text-zinc-400">No image: text-to-image. Add an image to edit it instead.</span>
|
||||
</div>
|
||||
<div
|
||||
v-else-if="studioMode === 'editv2' && v2Mode === 'iterate'"
|
||||
@@ -131,12 +131,12 @@
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border px-3 py-1 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-40"
|
||||
:class="v2Mode === 'edit' ? 'border-amber-300/70 bg-amber-400/10 text-amber-100' : 'border-white/10 text-zinc-400 hover:text-white'"
|
||||
:disabled="v2ModeLocked && v2Mode !== 'edit'"
|
||||
:title="v2ModeLocked && v2Mode !== 'edit' ? 'Remove extra passes to change graphs' : ''"
|
||||
:class="(v2Mode === 'edit' || v2Mode === 'generate') ? 'border-amber-300/70 bg-amber-400/10 text-amber-100' : 'border-white/10 text-zinc-400 hover:text-white'"
|
||||
:disabled="v2ModeLocked && v2Mode !== 'edit' && v2Mode !== 'generate'"
|
||||
:title="v2ModeLocked && v2Mode !== 'edit' && v2Mode !== 'generate' ? 'Remove extra passes to change graphs' : 'Uses your image when one is provided; otherwise generates from text'"
|
||||
@click="setV2Mode('edit')"
|
||||
>
|
||||
Edit
|
||||
Image
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -158,16 +158,6 @@
|
||||
>
|
||||
Refine
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border px-3 py-1 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-40"
|
||||
:class="v2Mode === 'generate' ? 'border-amber-300/70 bg-amber-400/10 text-amber-100' : 'border-white/10 text-zinc-400 hover:text-white'"
|
||||
:disabled="v2ModeLocked && v2Mode !== 'generate'"
|
||||
:title="v2ModeLocked && v2Mode !== 'generate' ? 'Remove extra passes to change graphs' : ''"
|
||||
@click="setV2Mode('generate')"
|
||||
>
|
||||
Generate
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="rounded-full border px-3 py-1 text-xs font-medium disabled:cursor-not-allowed disabled:opacity-40"
|
||||
@@ -2253,6 +2243,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { imageModeForInput, videoStartForInput } from '~/utils/generationInput'
|
||||
import { normalizeImageIterations, type ImageIteration } from '~/utils/imageIterations'
|
||||
import { composePromptParts, formatPromptParts, resolvePromptWrappers, restorePromptParts } from '~/utils/promptParts'
|
||||
import { parseEditPasses, looksLikeShotScript } from '~/utils/parseRecommend'
|
||||
@@ -2373,7 +2364,6 @@ import {
|
||||
minimaxGraphOf,
|
||||
parseVideoWorkflow,
|
||||
videoEngineOf,
|
||||
videoStartOf,
|
||||
type MiniMaxGraphId,
|
||||
type VideoEngineId,
|
||||
type VideoStartId
|
||||
@@ -2720,7 +2710,11 @@ const editScaleToTotalPixels = ref(false)
|
||||
const editScaleMegapixels = ref(1)
|
||||
const editRefFile = ref<File | null>(null)
|
||||
const editRefPreview = ref('')
|
||||
const v2Mode = ref<ImageV2Mode>('edit')
|
||||
const selectedV2Mode = ref<ImageV2Mode>('edit')
|
||||
const v2Mode = computed<ImageV2Mode>({
|
||||
get: () => imageModeForInput(selectedV2Mode.value, Boolean(file.value), editPassQueue.value.length > 0),
|
||||
set: mode => { selectedV2Mode.value = mode }
|
||||
})
|
||||
const v2Engine = ref<ImageV2Engine>('flux')
|
||||
const v2Task = ref<ImageV2Task>('scene')
|
||||
const v2Negative = ref('')
|
||||
@@ -2869,7 +2863,7 @@ const lastSelectedKey = ref('')
|
||||
const pendingLibraryDelete = ref<PendingLibraryDelete | null>(null)
|
||||
const libraryDeleteBusy = ref(false)
|
||||
const videoEngine = ref<VideoEngineId>('minimax')
|
||||
const videoStart = ref<VideoStartId>('still')
|
||||
const videoStart = computed<VideoStartId>(() => videoStartForInput(Boolean(file.value)))
|
||||
const minimaxGraph = ref<MiniMaxGraphId>('v2')
|
||||
const videoWorkflow = computed(() => composeVideoWorkflow(videoEngine.value, videoStart.value, minimaxGraph.value))
|
||||
const textToVideo = computed(() => isTextToVideo(videoWorkflow.value))
|
||||
@@ -4028,17 +4022,13 @@ onMounted(async () => {
|
||||
withSound.value = localStorage.getItem('aigen-generate-sound') !== 'false'
|
||||
autoplayEnabled.value = localStorage.getItem('aigen-autoplay') === 'true'
|
||||
videoEngine.value = 'minimax'
|
||||
videoStart.value = 'still'
|
||||
minimaxGraph.value = 'v2'
|
||||
try {
|
||||
const saved = parseVideoWorkflow(localStorage.getItem('aigen-video-workflow') || '')
|
||||
videoEngine.value = videoEngineOf(saved)
|
||||
videoStart.value = videoStartOf(saved)
|
||||
minimaxGraph.value = minimaxGraphOf(saved) === 'v1' ? 'v2' : minimaxGraphOf(saved)
|
||||
const engine = localStorage.getItem('aigen-video-engine')
|
||||
const start = localStorage.getItem('aigen-video-start')
|
||||
if (engine === 'ltx' || engine === 'minimax') videoEngine.value = engine
|
||||
if (start === 'text' || start === 'still') videoStart.value = start
|
||||
if (!ltxEnabled.value && videoEngine.value === 'ltx') {
|
||||
videoEngine.value = 'minimax'
|
||||
applyEngineDefaults('minimax')
|
||||
@@ -7171,7 +7161,7 @@ async function editImage() {
|
||||
}
|
||||
|
||||
function setV2Mode(mode: ImageV2Mode) {
|
||||
if (v2Mode.value === mode) return
|
||||
if (v2Mode.value === imageModeForInput(mode, Boolean(file.value), editPassQueue.value.length > 0)) return
|
||||
if (editPassQueue.value.length && v2PassChaining.value) {
|
||||
toast('Remove extra passes to change graphs. Extra passes stay in the current mode.')
|
||||
return
|
||||
@@ -7491,15 +7481,9 @@ function selectVideoEngine(engine: VideoEngineId) {
|
||||
applyEngineDefaults(engine)
|
||||
}
|
||||
|
||||
function selectVideoStart(start: VideoStartId) {
|
||||
videoStart.value = start
|
||||
if (studioMode.value !== 'video') selectStudioKind('video')
|
||||
}
|
||||
|
||||
function applyVideoWorkflow(raw?: string) {
|
||||
const parsed = coerceVideoWorkflow(raw, ltxEnabled.value)
|
||||
videoEngine.value = videoEngineOf(parsed)
|
||||
videoStart.value = videoStartOf(parsed)
|
||||
minimaxGraph.value = minimaxGraphOf(parsed) === 'v1' ? 'v2' : minimaxGraphOf(parsed)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user