riffusion-app/pages/index.tsx

259 lines
7.4 KiB
TypeScript
Raw Normal View History

import { useRouter } from "next/router";
2022-11-24 22:24:37 -07:00
import { useEffect, useState } from "react";
2022-11-26 13:12:40 -07:00
import * as Tone from "tone";
2022-11-24 21:22:03 -07:00
2022-11-27 14:53:22 -07:00
import AudioPlayer from "../components/AudioPlayer";
2022-12-11 18:14:42 -07:00
import DebugView from "../components/DebugView";
2022-11-27 17:59:00 -07:00
import PageHead from "../components/PageHead";
2022-11-24 17:54:00 -07:00
import Info from "../components/Info";
2022-12-02 12:54:47 -07:00
import Share from "../components/Share";
import Settings from "../components/Settings";
import ModelInference from "../components/ModelInference";
2022-11-23 23:08:00 -07:00
import Pause from "../components/Pause";
import PromptPanel from "../components/PromptPanel";
import ThreeCanvas from "../components/ThreeCanvas";
import {
AppState,
InferenceInput,
InferenceResult,
PromptInput,
} from "../types";
2022-11-24 21:22:03 -07:00
2022-11-23 23:08:00 -07:00
const defaultPromptInputs = [
2022-12-04 20:35:32 -07:00
{ prompt: "A jazz pianist playing a concerto" },
{ prompt: "Techno DJ and a Country Singer" },
{ prompt: "Classical italian tenor operatic pop" },
2022-11-24 23:58:52 -07:00
{ prompt: "lo-fi beat for the holidays" },
2022-11-24 21:22:03 -07:00
{ prompt: "" },
{ prompt: "" },
2022-11-23 23:08:00 -07:00
];
2022-11-23 22:46:32 -07:00
2022-11-25 00:26:44 -07:00
function getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}
2022-11-23 23:08:00 -07:00
export default function Home() {
// High-level state of the prompts
const [appState, setAppState] = useState<AppState>(AppState.UNINITIALIZED);
// Whether playback is paused
const [paused, setPaused] = useState(true);
// Current interpolation parameters
2022-11-27 14:53:22 -07:00
const [alpha, setAlpha] = useState(0.0);
const [alphaVelocity, setAlphaVelocity] = useState(0.25);
const [seed, setSeed] = useState(getRandomInt(1000000));
2022-11-23 22:46:32 -07:00
// Prompts shown on screen and maintained by the prompt panel
const [promptInputs, setPromptInputs] = useState<PromptInput[]>([]);
// Model execution results
2022-12-11 18:14:42 -07:00
const [inferenceResults, setInferenceResults] = useState<InferenceResult[]>(
[]
);
2022-11-23 23:08:00 -07:00
// Currently playing result, from the audio player
2022-12-11 18:14:42 -07:00
const [nowPlayingResult, setNowPlayingResult] =
useState<InferenceResult>(null);
// Set the initial seed from the URL if available
const router = useRouter();
useEffect(() => {
// Make sure params are ready
if (!router.isReady) {
return;
}
if (router.query.alphaVelocity) {
setAlphaVelocity(parseFloat(router.query.alphaVelocity as string));
}
if (router.query.seed) {
setSeed(parseInt(router.query.seed as string));
}
// Set prompt inputs here so that they are empty and incorrect information isn't shown
// until URL params have a chance to be read.
let initPromptInputs = defaultPromptInputs;
if (router.query.prompt) {
initPromptInputs[3].prompt = router.query.prompt as string;
}
setPromptInputs(defaultPromptInputs);
}, [router.isReady, router.query]);
2022-11-24 23:58:33 -07:00
// Set the app state based on the prompt inputs array
useEffect(() => {
if (alpha <= 1) {
return;
}
const upNextPrompt = promptInputs[promptInputs.length - 1].prompt;
const endPrompt = promptInputs[promptInputs.length - 2].prompt;
let newAppState = appState;
if (appState == AppState.SAME_PROMPT) {
if (upNextPrompt) {
newAppState = AppState.TRANSITION;
// swap the last two prompts to bring the upNextPrompt into the next inference call
setPromptInputs((prevPromptInputs) => {
const newPromptInputs = [...prevPromptInputs];
newPromptInputs[newPromptInputs.length - 1] = {
prompt: endPrompt,
};
newPromptInputs[newPromptInputs.length - 2] = {
prompt: upNextPrompt,
};
return newPromptInputs;
});
2022-11-24 23:58:33 -07:00
}
setSeed(seed + 1);
} else if (appState == AppState.TRANSITION) {
2022-11-24 23:58:33 -07:00
setPromptInputs([...promptInputs, { prompt: "" }]);
if (upNextPrompt) {
newAppState = AppState.TRANSITION;
2022-11-24 23:58:33 -07:00
} else {
newAppState = AppState.SAME_PROMPT;
2022-11-24 23:58:33 -07:00
}
}
if (newAppState != appState) {
setAppState(newAppState);
}
2022-11-24 23:58:33 -07:00
setAlpha(alpha - 1);
2022-11-26 12:30:42 -07:00
}, [promptInputs, alpha, appState, seed]);
2022-11-24 23:58:33 -07:00
// On any app state change, reset alpha
useEffect(() => {
console.log("App State: ", appState);
if (appState == AppState.UNINITIALIZED) {
setAppState(AppState.SAME_PROMPT);
} else {
setAlpha(0.25);
}
2022-11-24 23:58:33 -07:00
}, [appState]);
// What to do when a new inference result is available
const newResultCallback = (
input: InferenceInput,
result: InferenceResult
2022-11-24 23:58:33 -07:00
) => {
2022-11-26 12:30:42 -07:00
setInferenceResults((prevResults: InferenceResult[]) => {
2022-11-24 22:24:37 -07:00
const maxResultCounter = Math.max(...prevResults.map((r) => r.counter));
const lastResult = prevResults.find((r) => r.counter == maxResultCounter);
const newCounter = lastResult ? lastResult.counter + 1 : 0;
result.counter = newCounter;
result.input = input;
2022-11-30 12:53:40 -07:00
result.played = false;
2022-11-24 22:24:37 -07:00
2022-11-24 23:58:33 -07:00
setAlpha(alpha + alphaVelocity);
2022-11-24 22:24:37 -07:00
return [...prevResults, result];
});
};
2022-11-24 22:24:37 -07:00
const nowPlayingCallback = (result: InferenceResult, playerTime: number) => {
console.log(
"Now playing result ",
result.counter,
", player time is ",
playerTime
);
setNowPlayingResult(result);
2022-11-30 12:53:40 -07:00
// find the first promptInput that matches the result.input.end.prompt and set it's transitionCounter to the result.counter if not already set
setPromptInputs((prevPromptInputs) => {
const newPromptInputs = [...prevPromptInputs];
const promptInputIndex = newPromptInputs.findIndex(
(p) => p.prompt == result.input.end.prompt
);
if (promptInputIndex >= 0) {
if (newPromptInputs[promptInputIndex].transitionCounter == null) {
newPromptInputs[promptInputIndex].transitionCounter = result.counter;
}
}
return newPromptInputs;
});
// set played state for the result to true
setInferenceResults((prevResults: InferenceResult[]) => {
return prevResults.map((r) => {
if (r.counter == result.counter) {
r.played = true;
}
2022-12-11 18:14:42 -07:00
return r;
});
});
2022-11-24 22:24:37 -07:00
};
return (
2022-11-20 14:39:15 -07:00
<>
2022-11-27 17:59:00 -07:00
<PageHead />
2022-11-24 12:41:41 -07:00
<div className="bg-[#0A2342] flex flex-row min-h-screen text-white">
2022-12-08 15:34:03 -07:00
<div className="brightness-50 md:filter-none w-full z-0 md:w-1/3 min-h-screen">
2022-11-25 22:17:29 -07:00
<ThreeCanvas
paused={paused}
getTime={() => Tone.Transport.seconds}
inferenceResults={inferenceResults}
/>
2022-11-20 14:39:15 -07:00
</div>
<ModelInference
alpha={alpha}
seed={seed}
appState={appState}
promptInputs={promptInputs}
nowPlayingResult={nowPlayingResult}
newResultCallback={newResultCallback}
useBaseten={false}
/>
<AudioPlayer
paused={paused}
inferenceResults={inferenceResults}
nowPlayingCallback={nowPlayingCallback}
/>
2022-11-27 14:53:22 -07:00
2022-11-23 23:08:00 -07:00
<PromptPanel
prompts={promptInputs}
2022-11-30 12:53:40 -07:00
inferenceResults={inferenceResults}
nowPlayingResult={nowPlayingResult}
appState={appState}
2022-11-24 19:32:39 -07:00
changePrompt={(prompt: string, index: number) => {
2022-11-24 16:23:20 -07:00
const newPromptInputs = [...promptInputs];
2022-11-24 19:32:39 -07:00
newPromptInputs[index].prompt = prompt;
2022-11-24 16:23:20 -07:00
setPromptInputs(newPromptInputs);
}}
2022-11-23 23:08:00 -07:00
/>
2022-11-20 14:56:58 -07:00
<Pause paused={paused} setPaused={setPaused} />
2022-11-20 15:02:14 -07:00
2022-12-02 14:18:00 -07:00
<Share
inferenceResults={inferenceResults}
nowPlayingResult={nowPlayingResult}
/>
2022-12-02 12:54:47 -07:00
<Info />
2022-12-11 18:14:42 -07:00
<DebugView
promptInputs={promptInputs}
inferenceResults={inferenceResults}
nowPlayingResult={nowPlayingResult}
/>
<Settings />
2022-11-20 14:39:15 -07:00
</div>
</>
);
}