Save settings

This commit is contained in:
Hayk Martiros 2022-12-12 21:43:34 -08:00
parent 45bdd00312
commit 6ccb803968
7 changed files with 405 additions and 359 deletions

View File

@ -9,7 +9,7 @@ interface DebugViewProps {
promptInputs: PromptInput[]; promptInputs: PromptInput[];
inferenceResults: InferenceResult[]; inferenceResults: InferenceResult[];
nowPlayingResult: InferenceResult; nowPlayingResult: InferenceResult;
open: boolean ; open: boolean;
setOpen: (open: boolean) => void; setOpen: (open: boolean) => void;
} }
@ -39,8 +39,9 @@ export default function DebugView({
onClose={() => setOpen(false)} onClose={() => setOpen(false)}
as="div" as="div"
className="fixed inset-0 z-30" className="fixed inset-0 z-30"
key="debug-dialog"
> >
<ModalContainer> <ModalContainer key="debug-modal">
<div className="px-4 text-center text-sm whitespace-nowrap h-[40rem] w-[70rem] overflow-x-scroll"> <div className="px-4 text-center text-sm whitespace-nowrap h-[40rem] w-[70rem] overflow-x-scroll">
<div className="my-8 inline-block transform rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all"> <div className="my-8 inline-block transform rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Panel> <Dialog.Panel>

View File

@ -16,6 +16,8 @@ interface ModelInferenceProps {
nowPlayingResult: InferenceResult; nowPlayingResult: InferenceResult;
newResultCallback: (input: InferenceInput, result: InferenceResult) => void; newResultCallback: (input: InferenceInput, result: InferenceResult) => void;
useBaseten: boolean; useBaseten: boolean;
denoising: number;
seedImageId: string;
} }
/** /**
@ -31,12 +33,12 @@ export default function ModelInference({
nowPlayingResult, nowPlayingResult,
newResultCallback, newResultCallback,
useBaseten, useBaseten,
denoising,
seedImageId,
}: ModelInferenceProps) { }: ModelInferenceProps) {
// Create parameters for the inference request // Create parameters for the inference request
const [denoising, setDenoising] = useState(0.75);
const [guidance, setGuidance] = useState(7.0); const [guidance, setGuidance] = useState(7.0);
const [numInferenceSteps, setNumInferenceSteps] = useState(50); const [numInferenceSteps, setNumInferenceSteps] = useState(50);
const [seedImageId, setSeedImageId] = useState("og_beat");
const [maskImageId, setMaskImageId] = useState(null); const [maskImageId, setMaskImageId] = useState(null);
const [initializedUrlParams, setInitializedUrlParams] = useState(false); const [initializedUrlParams, setInitializedUrlParams] = useState(false);
@ -50,10 +52,6 @@ export default function ModelInference({
// Set initial params from URL query strings // Set initial params from URL query strings
const router = useRouter(); const router = useRouter();
useEffect(() => { useEffect(() => {
if (router.query.denoising) {
setDenoising(parseFloat(router.query.denoising as string));
}
if (router.query.guidance) { if (router.query.guidance) {
setGuidance(parseFloat(router.query.guidance as string)); setGuidance(parseFloat(router.query.guidance as string));
} }
@ -62,10 +60,6 @@ export default function ModelInference({
setNumInferenceSteps(parseInt(router.query.numInferenceSteps as string)); setNumInferenceSteps(parseInt(router.query.numInferenceSteps as string));
} }
if (router.query.seedImageId) {
setSeedImageId(router.query.seedImageId as string);
}
if (router.query.maskImageId) { if (router.query.maskImageId) {
if (router.query.maskImageId === "none") { if (router.query.maskImageId === "none") {
setMaskImageId(""); setMaskImageId("");

View File

@ -59,7 +59,7 @@ export default function PromptPanel({
displayPrompts = [...promptsToAdd, ...displayPrompts]; displayPrompts = [...promptsToAdd, ...displayPrompts];
} }
// Add in the upNext and staged prompts // Add in the upNext and staged prompts
// select the last 2 prompts from prompts // select the last 2 prompts from prompts
const lastPrompts = prompts.slice(-2); const lastPrompts = prompts.slice(-2);
@ -167,7 +167,7 @@ export default function PromptPanel({
}} }}
> >
<input <input
className="flex w-full md:fixed md:w-1/2 h-12 pl-3 pr-3 text-xl text-sky-900 rounded-lg border-sky-700 border-4 hover:border-sky-600 focus:outline-none focus:border-sky-400" className="flex w-full md:fixed md:w-1/2 h-12 pl-3 pr-3 text-xl text-sky-900 dark:text-sky-100 rounded-lg border-sky-700 border-4 hover:border-sky-600 focus:outline-none focus:border-sky-400"
ref={inputPrompt} ref={inputPrompt}
type="text" type="text"
id="prompt" id="prompt"
@ -238,7 +238,7 @@ const promptEntryClassNames_5_0 = {
1: promptEntryClassNameDict[15], 1: promptEntryClassNameDict[15],
2: promptEntryClassNameDict[23], // This is the start and end prompt 2: promptEntryClassNameDict[23], // This is the start and end prompt
3: promptEntryClassNameDict[31], // This is the staged prompt 3: promptEntryClassNameDict[31], // This is the staged prompt
4: promptEntryClassNameDict[36], // This is the UP NEXT prompt 4: promptEntryClassNameDict[36], // This is the UP NEXT prompt
} }
const promptEntryClassNames_5_25 = { // This is not reached unless user has poor connection or delayed server response const promptEntryClassNames_5_25 = { // This is not reached unless user has poor connection or delayed server response
@ -317,4 +317,4 @@ const promptEntryClassNames_6_1 = {
3: promptEntryClassNameDict[24], 3: promptEntryClassNameDict[24],
4: promptEntryClassNameDict[32], 4: promptEntryClassNameDict[32],
5: promptEntryClassNameDict[36], 5: promptEntryClassNameDict[36],
} }

View File

@ -2,40 +2,50 @@ import { Dialog, Transition } from "@headlessui/react";
import { Fragment, useState } from "react"; import { Fragment, useState } from "react";
import { FiSettings } from "react-icons/fi"; import { FiSettings } from "react-icons/fi";
import { ImStatsBars } from "react-icons/im"; import { ImStatsBars } from "react-icons/im";
import styled, { css } from "styled-components"; import styled from "styled-components";
import { InferenceResult, PromptInput } from "../types"; import { InferenceResult, PromptInput } from "../types";
import DebugView from "./DebugView"; import DebugView from "./DebugView";
const ModalContainer = styled.div` const ModalContainer = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
`; `;
interface DebugViewProps { interface DebugViewProps {
promptInputs: PromptInput[]; promptInputs: PromptInput[];
inferenceResults: InferenceResult[]; inferenceResults: InferenceResult[];
nowPlayingResult: InferenceResult; nowPlayingResult: InferenceResult;
denoising: number;
setDenoising: (denoising: number) => void;
seedImage: string;
setSeedImage: (seedImage: string) => void;
} }
export default function Settings({ export default function Settings({
promptInputs, promptInputs,
inferenceResults, inferenceResults,
nowPlayingResult, nowPlayingResult,
denoising,
setDenoising,
seedImage,
setSeedImage,
}: DebugViewProps) { }: DebugViewProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
var classNameCondition = "" var classNameCondition = "";
if (open) { if (open) {
classNameCondition = "fixed z-20 top-44 right-4 md:top-48 md:right-8 bg-sky-400 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-white text-2xl hover:bg-sky-500 hover:drop-shadow-2xl" classNameCondition =
"fixed z-20 top-44 right-4 md:top-48 md:right-8 bg-sky-400 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-white text-2xl hover:bg-sky-500 hover:drop-shadow-2xl";
} else { } else {
classNameCondition = "fixed z-20 top-44 right-4 md:top-48 md:right-8 bg-slate-100 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-sky-900 text-2xl hover:text-white hover:bg-sky-600 hover:drop-shadow-2xl" classNameCondition =
"fixed z-20 top-44 right-4 md:top-48 md:right-8 bg-slate-100 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-sky-900 text-2xl hover:text-white hover:bg-sky-600 hover:drop-shadow-2xl";
} }
return ( return (
@ -82,47 +92,36 @@ export default function Settings({
leaveFrom="opacity-100 scale-100" leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95" leaveTo="opacity-0 scale-95"
> >
<ModalContainer> <ModalContainer key="settings-modal-container">
<div className="my-8 inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all"> <div className="my-8 inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all">
<Dialog.Title <Dialog.Title
as="h1" as="h1"
className="text-3xl font-medium leading-6 text-gray-900 pb-2" className="text-3xl font-medium leading-6 text-gray-900 pb-4"
> >
Settings Settings
</Dialog.Title> </Dialog.Title>
<div className="mt-1"> <div className="mt-1">
<p className="label-text-alt"> <p className=" text-gray-700 text-sm">
<label className="label"> Riffusion generates music from text prompts using a
Riffusion generates music from text prompts using a diffusion model. Try typing in your favorite artist or genre, and playing with the settings below to explore the latent space of sound. diffusion model. Try typing in your favorite artist or
</label> genre, and playing with the settings below to explore the
latent space of sound.
{/* <input type="range" min="0" max="100" value="40" className="range" /> */}
{SeedImageSelector()}
{DenoisingSelector()}
{DebugButton(
promptInputs,
inferenceResults,
nowPlayingResult
)}
</p> </p>
{/* <input type="range" min="0" max="100" value="40" className="range" /> */}
{SeedImageSelector(seedImage, setSeedImage)}
{DenoisingSelector(denoising, setDenoising)}
{DebugButton(
promptInputs,
inferenceResults,
nowPlayingResult
)}
</div> </div>
<div className="mt-6"> <div className="mt-6">
<button
className="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-sky-500 group-hover:from-sky-600 group-hover:to-sky-500 hover:text-white"
onClick={() => {
setOpen(false);
}}
>
<span className="relative px-5 py-2 transition-all ease-in duration-75 bg-white rounded-md group-hover:bg-opacity-0">
Cancel
</span>
</button>
<button <button
className="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-sky-500 group-hover:from-sky-600 group-hover:to-sky-500 hover:text-white" className="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-sky-500 group-hover:from-sky-600 group-hover:to-sky-500 hover:text-white"
onClick={() => { onClick={() => {
@ -138,11 +137,12 @@ export default function Settings({
<button <button
type="button" type="button"
className="text-white bg-gradient-to-br from-purple-600 to-sky-500 hover:bg-gradient-to-bl font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2" className="text-white bg-gradient-to-br from-purple-600 to-sky-500 hover:bg-gradient-to-bl font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2"
onClick={() => setOpen(false)} onClick={() => {
setOpen(false);
}}
> >
Apply changes 🎧 Done 🎧
</button> </button>
</div> </div>
</div> </div>
</ModalContainer> </ModalContainer>
@ -152,57 +152,103 @@ export default function Settings({
</Transition> </Transition>
</> </>
); );
};
export function SeedImageSelector() {
return (
<div className="form-control w-full">
<label className="label">
<span className="label-text">Seed Image</span>
{/* <span className="label-text-alt">Chose your vibe</span> */}
</label>
<select className="select select-bordered select-sm">
<option disabled selected>Chose your vibe</option>
<option selected >Og Beat</option>
<option>Soul</option>
<option>High Energy</option>
<option>Spacy</option>
</select>
<label className="label">
<span className="label-text-alt">Used as the base for img2img diffusion. This keeps your riff on beat and impacts melodic patterns.</span>
{/* <span className="label-text-alt">Alt label</span> */}
</label>
</div>
)
} }
export function DenoisingSelector() { export function SeedImageSelector(
return ( seedImage: string,
<div className="form-control w-full"> setSeedImage: (seedImage: string) => void
<label className="label">
<span className="label-text">Denoising</span>
{/* <span className="label-text-alt">Chose your vibe</span> */}
</label>
<select className="select select-bordered select-sm">
<option disabled selected>How wild to get</option>
<option selected >Keep it on beat (0.75)</option>
<option>Get a little crazy (0.8)</option>
<option>I'm feeling lucky (0.85)</option>
<option>What is tempo? (0.95)</option>
</select>
<label className="label">
<span className="label-text-alt">The higher the denoising, the more creative the output, and the more likely you are to get off beat.</span>
{/* <span className="label-text-alt">Alt label</span> */}
</label>
</div>
)
}
export function DebugButton(
promptInputs,
inferenceResults,
nowPlayingResult
) { ) {
let selectOptions = [
["OG Beat", "og_beat"],
["Soul", "chill_soul_1"],
// ["High Energy", 0.85],
// ["Spacy", 0.95],
];
let matchedOption = selectOptions.find((x) => x[1] === seedImage);
if (matchedOption === undefined) {
matchedOption = [`Custom (${seedImage})`, seedImage];
selectOptions.push(matchedOption);
}
return (
<div className="form-control w-full">
<label className="label">
<span className="label-text text-gray-700">Seed Image</span>
</label>
<select
className="select select-bordered select-sm"
onChange={(e) => {
const newValue = selectOptions.find(
(x) => x[0] === e.target.value
)[1];
console.log("Setting seed image: ", newValue);
setSeedImage(newValue);
}}
defaultValue={matchedOption[0]}
>
<option disabled>Chose your vibe</option>
{selectOptions.map((x, i) => (
<option key={i}>{x[0]}</option>
))}
</select>
<p className="label-text-alt text-gray-700 pt-2">
Used as the base for img2img diffusion. This keeps your riff on beat and
impacts melodic patterns.
</p>
</div>
);
}
export function DenoisingSelector(
denoising: number,
setDenoising: (d: number) => void
) {
let selectOptions = [
["Keep it on beat (0.75)", 0.75],
["Get a little crazy (0.8)", 0.8],
["I'm feeling lucky (0.85)", 0.85],
["What is tempo? (0.95)", 0.95],
];
let matchedOption = selectOptions.find((x) => x[1] === denoising);
if (matchedOption === undefined) {
matchedOption = [`Custom (${denoising})`, denoising];
selectOptions.push(matchedOption);
}
return (
<div className="form-control w-full">
<label className="label">
<span className="label-text text-gray-700">Denoising</span>
</label>
<select
className="select select-bordered select-sm"
onChange={(e) => {
const newValue = selectOptions.find(
(x) => x[0] === e.target.value
)[1] as number;
console.log("Setting denoising: ", newValue);
setDenoising(newValue);
}}
defaultValue={matchedOption[0]}
>
<option disabled>How wild to get</option>
{selectOptions.map((x, i) => (
<option key={i}>{x[0]}</option>
))}
</select>
<p className="label-text-alt text-gray-700 pt-2">
The higher the denoising, the more creative the output, and the more
likely you are to get off beat.
</p>
</div>
);
}
export function DebugButton(promptInputs, inferenceResults, nowPlayingResult) {
const [debugOpen, debugSetOpen] = useState(false); const [debugOpen, debugSetOpen] = useState(false);
let buttonClassName = ""; let buttonClassName = "";
@ -218,6 +264,7 @@ export function DebugButton(
<> <>
<button <button
title="Debug" title="Debug"
key="debug-button"
className={buttonClassName} className={buttonClassName}
onClick={() => { onClick={() => {
debugSetOpen(true); debugSetOpen(true);
@ -232,7 +279,8 @@ export function DebugButton(
nowPlayingResult={nowPlayingResult} nowPlayingResult={nowPlayingResult}
open={debugOpen} open={debugOpen}
setOpen={debugSetOpen} setOpen={debugSetOpen}
key="debug-view"
/> />
</> </>
); );
} }

View File

@ -1,277 +1,262 @@
import { Dialog, Transition } from "@headlessui/react"; import { Dialog, Transition } from "@headlessui/react";
import { Fragment, useState } from "react"; import { Fragment, useState } from "react";
import { FiShare } from "react-icons/fi"; import { FiShare } from "react-icons/fi";
import styled, { css } from "styled-components"; import styled from "styled-components";
import { InferenceResult } from "../types"; import { InferenceResult } from "../types";
interface ShareProps { interface ShareProps {
inferenceResults: InferenceResult[]; inferenceResults: InferenceResult[];
nowPlayingResult: InferenceResult; nowPlayingResult: InferenceResult;
} }
const ModalContainer = styled.div` const ModalContainer = styled.div`
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
width: 100vw; width: 100vw;
height: 100vh; height: 100vh;
background: rgba(0, 0, 0, 0.5); background: rgba(0, 0, 0, 0.5);
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
`; `;
export default function Share({ export default function Share({
inferenceResults, inferenceResults,
nowPlayingResult, nowPlayingResult,
}: ShareProps) { }: ShareProps) {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
var classNameCondition = "" var classNameCondition = "";
if (open) { if (open) {
classNameCondition = "fixed z-20 top-24 right-4 md:top-28 md:right-8 bg-sky-400 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-white text-2xl hover:bg-sky-500 hover:drop-shadow-2xl" classNameCondition =
"fixed z-20 top-24 right-4 md:top-28 md:right-8 bg-sky-400 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-white text-2xl hover:bg-sky-500 hover:drop-shadow-2xl";
} else {
classNameCondition =
"fixed z-20 top-24 right-4 md:top-28 md:right-8 bg-slate-100 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-sky-900 text-2xl hover:text-white hover:bg-sky-600 hover:drop-shadow-2xl";
}
// function to copy link to moment in song to the clipboard
function copyLinkToClipboard(secondsAgo: number) {
// use generateLink to generate the link
const link = generateLink(secondsAgo);
navigator.clipboard.writeText(link);
}
function getActiveResult() {
if (!nowPlayingResult) {
if (inferenceResults.length == 0) {
return null;
}
return inferenceResults[0];
} else { } else {
classNameCondition = "fixed z-20 top-24 right-4 md:top-28 md:right-8 bg-slate-100 w-14 h-14 rounded-full drop-shadow-lg flex justify-center items-center text-sky-900 text-2xl hover:text-white hover:bg-sky-600 hover:drop-shadow-2xl" return nowPlayingResult;
}
}
// function to generate a link to a the moment in the song based on the played clips, input variable is how many seconds ago
function generateLink(secondsAgo: number) {
var prompt;
var seed;
var denoising;
var maskImageId;
var seedImageId;
var guidance;
var numInferenceSteps;
var alphaVelocity;
if (!nowPlayingResult) {
return window.location.href;
} else {
var selectedInput: InferenceResult["input"];
if (secondsAgo == 0) {
selectedInput = nowPlayingResult.input;
} else {
var selectedCounter = nowPlayingResult.counter - secondsAgo / 5;
selectedInput = inferenceResults.find(
(result) => result.counter == selectedCounter
)?.input;
if (!selectedInput) {
// TODO: ideally don't show the button in this case...
return window.location.href;
}
}
// TODO: Consider only including in the link the things that are different from the default values
prompt = selectedInput.start.prompt;
seed = selectedInput.start.seed;
denoising = selectedInput.start.denoising;
maskImageId = selectedInput.mask_image_id;
seedImageId = nowPlayingResult.input.seed_image_id;
// TODO, selectively add these based on whether we give user option to change them
// guidance = nowPlayingResult.input.guidance
// numInferenceSteps = nowPlayingResult.input.num_inference_steps
// alphaVelocity = nowPlayingResult.input.alpha_velocity
} }
// function to copy link to moment in song to the clipboard var baseUrl = window.location.origin + "/?";
function copyLinkToClipboard(secondsAgo: number) {
// use generateLink to generate the link if (prompt != null) {
const link = generateLink(secondsAgo); var promptString = "&prompt=" + prompt;
} else {
// Note that copying image and text to the clipboard simultaneously is not supported on all browsers, causes some funkiness promptString = "";
// This also has to be executed on a site secured with https on mobile, so will not work on localhost }
navigator.clipboard if (seed != null) {
.writeText(link) 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 = "";
} }
function copyImageToClipboard(secondsAgo: number) { // Format strings to have + in place of spaces for ease of sharing, note this is only necessary for prompts currently
// get image of the current moment in the song promptString = promptString.replace(/ /g, "+");
var image: string
if (!nowPlayingResult) {
if (inferenceResults.length == 0) {
return
}
image = inferenceResults[0].image
}
else {
image = nowPlayingResult.image
}
// make pngImageBlob from the image
const imageBlob = dataURItoBlob(image)
// convert pngImageBlob to a PNG file
const pngImageFile = new File([imageBlob], "image.png", { type: "image/png" })
// use generateLink to generate the link, we'll add this to the clipboard as plain text as well // create url string with the variables above combined
const link = generateLink(secondsAgo); var shareUrl =
baseUrl +
promptString +
seedString +
denoisingString +
maskImageIdString +
seedImageIdString +
guidanceString +
numInferenceStepsString +
alphaVelocityString;
try { return shareUrl;
navigator.clipboard.write([ }
new ClipboardItem({
'image/png': pngImageFile,
'text/plain': new Blob([link], { type: 'text/plain' }),
}),
]);
} catch (error) {
console.error(error);
}
}
function displayShareImage() { return (
var image: string <>
if (!nowPlayingResult) { <button
if (inferenceResults.length == 0) { title="Info"
return className={classNameCondition}
} onClick={() => setOpen(true)}
image = inferenceResults[0].image >
} <FiShare />
else { </button>
image = nowPlayingResult.image
} <Transition appear show={open} as={Fragment}>
<Dialog
return ( as="div"
<img src={image} className="fixed inset-0 z-20 overflow-y-auto"
alt="share image" onClose={() => setOpen(false)}
className="w-64 h-64" >
/> <div className="min-h-screen px-4 text-center">
) <Transition.Child
} as={Fragment}
enter="ease-out duration-300"
// function to generate a link to a the moment in the song based on the played clips, input variable is how many seconds ago enterFrom="opacity-0"
function generateLink(secondsAgo: number) { enterTo="opacity-100"
leave="ease-in duration-200"
var prompt leaveFrom="opacity-100"
var seed leaveTo="opacity-0"
var denoising
var maskImageId
var seedImageId
var guidance
var numInferenceSteps
var alphaVelocity
if (!nowPlayingResult) {
return window.location.href;
}
else {
var selectedInput: InferenceResult["input"]
if (secondsAgo == 0) {
selectedInput = nowPlayingResult.input
}
else {
var selectedCounter = nowPlayingResult.counter - (secondsAgo / 5)
selectedInput = inferenceResults.find((result) => result.counter == selectedCounter)?.input
if (!selectedInput) {
// TODO: ideally don't show the button in this case...
return window.location.href;
}
}
// TODO: Consider only including in the link the things that are different from the default values
prompt = selectedInput.start.prompt
seed = selectedInput.start.seed
denoising = selectedInput.start.denoising
maskImageId = selectedInput.mask_image_id
seedImageId = nowPlayingResult.input.seed_image_id
// TODO, selectively add these based on whether we give user option to change them
// guidance = nowPlayingResult.input.guidance
// numInferenceSteps = nowPlayingResult.input.num_inference_steps
// alphaVelocity = nowPlayingResult.input.alpha_velocity
}
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;
}
return (
<>
<button
title="Info"
className={classNameCondition}
onClick={() => setOpen(true)}
> >
<FiShare /> <Dialog.Overlay className="fixed inset-0" />
</button> </Transition.Child>
<Transition appear show={open} as={Fragment}> <span
<Dialog className="inline-block h-screen align-middle"
as="div" aria-hidden="true"
className="fixed inset-0 z-20 overflow-y-auto" >
onClose={() => setOpen(false)} &#8203;
> </span>
<div className="min-h-screen px-4 text-center"> <Transition.Child
<Transition.Child as={Fragment}
as={Fragment} enter="ease-out duration-300"
enter="ease-out duration-300" enterFrom="opacity-0 scale-95"
enterFrom="opacity-0" enterTo="opacity-100 scale-100"
enterTo="opacity-100" leave="ease-in duration-200"
leave="ease-in duration-200" leaveFrom="opacity-100 scale-100"
leaveFrom="opacity-100" leaveTo="opacity-0 scale-95"
leaveTo="opacity-0" >
> <ModalContainer>
<Dialog.Overlay className="fixed inset-0" /> <div className="my-8 p-8 inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-white text-left align-middle shadow-xl transition-all">
</Transition.Child> <Dialog.Title
as="h1"
className="text-3xl font-medium leading-6 text-gray-900 pb-2"
>
Share your riff
</Dialog.Title>
<div className="mt-4">
<img
src={getActiveResult()?.image}
alt="share image"
className="w-3/4"
/>
</div>
<span <div className="mt-4">
className="inline-block h-screen align-middle" <audio
aria-hidden="true" controls
> src={getActiveResult()?.audio}
&#8203; className="w-3/4"
</span> >
<Transition.Child Your browser does not support audio.
as={Fragment} </audio>
enter="ease-out duration-300" </div>
enterFrom="opacity-0 scale-95" <div className="mt-6">
enterTo="opacity-100 scale-100" <button
leave="ease-in duration-200" className="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-sky-500 group-hover:from-sky-600 group-hover:to-sky-500 hover:text-white"
leaveFrom="opacity-100 scale-100" onClick={() => {
leaveTo="opacity-0 scale-95" setOpen(false);
> }}
<ModalContainer> >
<div className="my-8 inline-block w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all"> <span className="relative px-5 py-2 transition-all ease-in duration-75 bg-white rounded-md group-hover:bg-opacity-0">
<Dialog.Title Cancel
as="h1" </span>
className="text-3xl font-medium leading-6 text-gray-900 pb-2" </button>
>
Share your riff
</Dialog.Title>
<div className="mt-4">
{displayShareImage()}
</div>
<div className="mt-6"> <button
type="button"
<button className="w-64 text-white bg-gradient-to-br from-purple-600 to-sky-500 hover:bg-gradient-to-bl font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2"
className="relative inline-flex items-center justify-center p-0.5 mb-2 mr-2 overflow-hidden text-sm font-medium text-gray-900 rounded-lg group bg-sky-500 group-hover:from-sky-600 group-hover:to-sky-500 hover:text-white" onClick={() => {
onClick={() => { copyLinkToClipboard(0);
setOpen(false); setOpen(false);
}} }}
> >
<span className="relative px-5 py-2 transition-all ease-in duration-75 bg-white rounded-md group-hover:bg-opacity-0"> Copy link to current moment 🔗
Cancel </button>
</span> </div>
</button> </div>
</ModalContainer>
<button </Transition.Child>
type="button" </div>
className="w-64 text-white bg-gradient-to-br from-purple-600 to-sky-500 hover:bg-gradient-to-bl font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 mb-2" </Dialog>
onClick={() => { </Transition>
copyLinkToClipboard(0) </>
// copyImageToClipboard(0) );
setOpen(false)
}}
>
Copy link to current moment 🔗
</button>
</div>
</div>
</ModalContainer>
</Transition.Child>
</div>
</Dialog>
</Transition>
</>
);
};
function dataURItoBlob(image: string) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (image.split(',')[0].indexOf('base64') >= 0)
byteString = atob(image.split(',')[1]);
else
byteString = unescape(image.split(',')[1]);
// separate out the mime component
var mimeString = image.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], { type: mimeString });
} }

View File

@ -404,7 +404,7 @@ export default function Home() {
results in under five seconds, you can run the experience locally. results in under five seconds, you can run the experience locally.
</p> </p>
<br /> <br />
<b>Code</b> <h2 className="pt-10 pb-5 text-3xl font-bold">Code</h2>
<ul className="mt-3 ml-10 list-disc"> <ul className="mt-3 ml-10 list-disc">
<li> <li>
Web app:{" "} Web app:{" "}

View File

@ -43,6 +43,10 @@ export default function Home() {
const [alphaVelocity, setAlphaVelocity] = useState(0.25); const [alphaVelocity, setAlphaVelocity] = useState(0.25);
const [seed, setSeed] = useState(getRandomInt(1000000)); const [seed, setSeed] = useState(getRandomInt(1000000));
// Settings
const [denoising, setDenoising] = useState(0.75);
const [seedImageId, setSeedImageId] = useState("og_beat");
// Prompts shown on screen and maintained by the prompt panel // Prompts shown on screen and maintained by the prompt panel
const [promptInputs, setPromptInputs] = useState<PromptInput[]>([]); const [promptInputs, setPromptInputs] = useState<PromptInput[]>([]);
@ -78,6 +82,14 @@ export default function Home() {
initPromptInputs[3].prompt = router.query.prompt as string; initPromptInputs[3].prompt = router.query.prompt as string;
} }
setPromptInputs(defaultPromptInputs); setPromptInputs(defaultPromptInputs);
if (router.query.denoising) {
setDenoising(parseFloat(router.query.denoising as string));
}
if (router.query.seedImageId) {
setSeedImageId(router.query.seedImageId as string);
}
}, [router.isReady, router.query]); }, [router.isReady, router.query]);
// Set the app state based on the prompt inputs array // Set the app state based on the prompt inputs array
@ -214,6 +226,8 @@ export default function Home() {
nowPlayingResult={nowPlayingResult} nowPlayingResult={nowPlayingResult}
newResultCallback={newResultCallback} newResultCallback={newResultCallback}
useBaseten={process.env.NEXT_PUBLIC_RIFFUSION_USE_BASETEN == "true"} useBaseten={process.env.NEXT_PUBLIC_RIFFUSION_USE_BASETEN == "true"}
denoising={denoising}
seedImageId={seedImageId}
/> />
<AudioPlayer <AudioPlayer
@ -245,6 +259,10 @@ export default function Home() {
promptInputs={promptInputs} promptInputs={promptInputs}
inferenceResults={inferenceResults} inferenceResults={inferenceResults}
nowPlayingResult={nowPlayingResult} nowPlayingResult={nowPlayingResult}
denoising={denoising}
setDenoising={setDenoising}
seedImage={seedImageId}
setSeedImage={setSeedImageId}
/> />
</div> </div>
</> </>