From e6cdab9293d886c1bd6ed9f50e0159a45ca519e1 Mon Sep 17 00:00:00 2001 From: Seth Forsgren Date: Wed, 14 Dec 2022 12:44:10 -0800 Subject: [PATCH] Adding jump and replay functionality --- components/PromptEntry.tsx | 214 +++++++++++++++++++++++++++++++++---- components/PromptPanel.tsx | 11 +- pages/index.tsx | 16 +-- prompts.ts | 65 ++++++++--- 4 files changed, 261 insertions(+), 45 deletions(-) diff --git a/components/PromptEntry.tsx b/components/PromptEntry.tsx index d315bb1..5b8e790 100644 --- a/components/PromptEntry.tsx +++ b/components/PromptEntry.tsx @@ -1,5 +1,6 @@ -import { PlayingState } from "../types"; +import { InferenceInput, InferenceResult, PlayingState } from "../types"; import { IoMdClose } from "react-icons/io"; +import Pause from "./Pause"; interface PromptEntryProps { prompt: string; @@ -7,6 +8,9 @@ interface PromptEntryProps { className: string; playingState: PlayingState; resetCallback: () => void; + inferenceResults: InferenceResult[]; + nowPlayingResult: InferenceResult; + setPaused: (value: boolean) => void; } export default function PromptEntry({ @@ -15,68 +19,117 @@ export default function PromptEntry({ className, playingState, resetCallback, + inferenceResults, + nowPlayingResult, + setPaused }: PromptEntryProps) { + const getPromptCopy = (prompt: string) => { switch (playingState) { case PlayingState.UNINITIALIZED: case PlayingState.SAME_PROMPT: switch (index) { case 0: - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ); case 1: - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ); case 2: + // active prompt if (prompt == " " || prompt == "") { return {""}; } else { - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ) } case 3: if (prompt == " " || prompt == "") { - return "..."; + return

...

} else { - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ) } case 4: if (prompt == " " || prompt == "") { - return "UP NEXT: Anything you want"; + return

UP NEXT: Anything you want

; } else { - return "UP NEXT: " + prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

UP NEXT: {prompt}

+
+ ) } default: { console.log("UNHANDLED default"); - return prompt; + return

{prompt}

; } } case PlayingState.TRANSITION: switch (index) { case 0: - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ); case 1: - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ); case 2: - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ) case 3: if (prompt == " " || prompt == "") { - return "< enter prompt >"; + return

-enter prompt-

; } else { - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

{prompt}

+
+ ) } case 4: if (prompt == " " || prompt == "") { - return "..."; + return

...

; } else { - return prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

UP NEXT: {prompt}

+
+ ) } case 5: if (prompt == " " || prompt == "") { - return "UP NEXT: Anything you want"; + return

UP NEXT: Anything you want

; } else { - return "UP NEXT: " + prompt; + return ( +
{ jumpToPrompt(prompt, inferenceResults, setPaused, nowPlayingResult) }} > +

UP NEXT: {prompt}

+
+ ) } default: { console.log("UNHANDLED default"); - return prompt; + return

{prompt}

; } } } @@ -84,7 +137,8 @@ export default function PromptEntry({ return (
-

{getPromptCopy(prompt)}

+ {getPromptCopy(prompt)} + {/* TODO(hayk): Re-enable this when it's working. */} {/* {index == 2 ? ( ) : null} */} -
+ ); } + +export function jumpToPrompt(prompt: String, inferenceResults: InferenceResult[], setPaused: (value: boolean) => void, nowPlayingResult?: InferenceResult) { + + // Pause player since this function will open new tab that user will interact with + setPaused(true) + + let firstTimePromptAppears = -1; + for (let i = 0; i < inferenceResults.length; i++) { + if (inferenceResults[i].input.start.prompt === prompt) { + firstTimePromptAppears = i; + break; + } + } + if (firstTimePromptAppears == -1) { + let url = generateLinkToUpcomingPrompt(prompt, nowPlayingResult) + window.open(url, "_blank").focus(); + } + else { + let url = generateLinkToPreviousInput(inferenceResults[firstTimePromptAppears].input) + window.open(url, "_blank").focus(); + } +} + +export function generateLinkToUpcomingPrompt(prompt, nowPlayingResult?: InferenceResult) { + + var promptString = "&prompt=" + prompt; + promptString = promptString.replace(/ /g, "+"); + + if (nowPlayingResult != null) { + var denoisingString = "&denoising=" + nowPlayingResult.input.start.denoising; + var seedImageIdString = "&seedImageId=" + nowPlayingResult.input.seed_image_id; + } else { + denoisingString = ""; + seedImageIdString = ""; + } + + var baseUrl = window.location.origin + "/?"; + var url = baseUrl + promptString + denoisingString + seedImageIdString; + return url; +} + +// Todo: DRY this and share functions +export function generateLinkToPreviousInput(selectedInput: InferenceInput) { + var prompt; + var seed; + var denoising; + var maskImageId; + var seedImageId; + var guidance; + var numInferenceSteps; + var alphaVelocity; + + prompt = selectedInput.start.prompt; + seed = selectedInput.start.seed; + denoising = selectedInput.start.denoising; + maskImageId = selectedInput.mask_image_id; + seedImageId = selectedInput.seed_image_id; + + var baseUrl = window.location.origin + "/?"; + + if (prompt != null) { + var promptString = "&prompt=" + prompt; + } else { + promptString = ""; + } + if (seed != null) { + var seedString = "&seed=" + seed; + } else { + seedString = ""; + } + if (denoising != null) { + var denoisingString = "&denoising=" + denoising; + } else { + denoisingString = ""; + } + if (maskImageId != null) { + var maskImageIdString = "&maskImageId=" + maskImageId; + } else { + maskImageIdString = ""; + } + if (seedImageId != null) { + var seedImageIdString = "&seedImageId=" + seedImageId; + } else { + seedImageIdString = ""; + } + if (guidance != null) { + var guidanceString = "&guidance=" + guidance; + } else { + guidanceString = ""; + } + if (numInferenceSteps != null) { + var numInferenceStepsString = "&numInferenceSteps=" + numInferenceSteps; + } else { + numInferenceStepsString = ""; + } + if (alphaVelocity != null) { + var alphaVelocityString = "&alphaVelocity=" + alphaVelocity; + } else { + alphaVelocityString = ""; + } + + // Format strings to have + in place of spaces for ease of sharing, note this is only necessary for prompts currently + promptString = promptString.replace(/ /g, "+"); + + // create url string with the variables above combined + var shareUrl = + baseUrl + + promptString + + seedString + + denoisingString + + maskImageIdString + + seedImageIdString + + guidanceString + + numInferenceStepsString + + alphaVelocityString; + + return shareUrl; +} \ No newline at end of file diff --git a/components/PromptPanel.tsx b/components/PromptPanel.tsx index dc2a547..e6d275b 100644 --- a/components/PromptPanel.tsx +++ b/components/PromptPanel.tsx @@ -10,6 +10,7 @@ interface PromptPanelProps { appState: AppState; changePrompt: (prompt: string, index: number) => void; resetCallback: () => void; + setPaused: (paused: boolean) => void; } export default function PromptPanel({ @@ -19,6 +20,7 @@ export default function PromptPanel({ appState, changePrompt, resetCallback, + setPaused, }: PromptPanelProps) { const inputPrompt = useRef(null); @@ -150,12 +152,15 @@ export default function PromptPanel({
{getDisplayPrompts().map((prompt, index) => ( ))}
@@ -194,6 +199,10 @@ export default function PromptPanel({ ); } +export function refreshPage() { + window.location.reload(); +} + const promptEntryClassNameDict = { 0: "font-extralight text-xs text-gray-500 text-opacity-20", 1: "font-extralight text-xs text-gray-400 text-opacity-20", diff --git a/pages/index.tsx b/pages/index.tsx index e8de887..579ae28 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -13,7 +13,7 @@ import Pause from "../components/Pause"; import PromptPanel from "../components/PromptPanel"; import ThreeCanvas from "../components/ThreeCanvas"; -import { samplePrompts } from "../prompts"; +import { samplePrompts, initialSeeds, initialSeedImageMap } from "../prompts"; import { AppState, @@ -22,10 +22,6 @@ import { PromptInput, } from "../types"; -function getRandomInt(max: number) { - return Math.floor(Math.random() * max); -} - function getRandomFromArray(arr: any[], n: number) { var result = new Array(n), len = arr.length, @@ -51,11 +47,11 @@ export default function Home() { const [alpha, setAlpha] = useState(0.0); const [alphaRollover, setAlphaRollover] = useState(false); const [alphaVelocity, setAlphaVelocity] = useState(0.25); - const [seed, setSeed] = useState(getRandomInt(1000000)); // Settings const [denoising, setDenoising] = useState(0.75); - const [seedImageId, setSeedImageId] = useState("og_beat"); + const [seedImageId, setSeedImageId] = useState(initialSeeds[Math.floor(Math.random() * initialSeeds.length)]); + const [seed, setSeed] = useState(initialSeedImageMap[seedImageId][Math.floor(Math.random() * initialSeedImageMap[seedImageId].length)]); // Prompts shown on screen and maintained by the prompt panel const [promptInputs, setPromptInputs] = useState([]); @@ -330,10 +326,14 @@ export default function Home() { newPromptInputs[index].prompt = prompt; setPromptInputs(newPromptInputs); }} + setPaused={setPaused} resetCallback={resetCallback} /> - +