riffusion-app/components/ModelInference.tsx

218 lines
5.9 KiB
TypeScript

import { useRouter } from "next/router";
import { useCallback, useEffect, useState } from "react";
import {
AppState,
InferenceInput,
InferenceResult,
PromptInput,
} from "../types";
// TODO(hayk): Get this into a configuration.
const SERVER_URL = "http://129.146.52.68:3013/run_inference/";
// Baseten worklet api url. Using cors-anywhere to get around CORS issues.
const BASETEN_URL =
"https://app.baseten.co/applications/2qREaXP/production/worklets/mP7KkLP/invoke";
// Temporary basten API key "irritating-haircut"
const BASETEN_API_KEY = "JocxKmyo.g0JreAA8dZy5F20PdMxGAV34a4VGGpom";
interface ModelInferenceProps {
alpha: number;
seed: number;
appState: AppState;
promptInputs: PromptInput[];
nowPlayingResult: InferenceResult;
newResultCallback: (input: InferenceInput, result: InferenceResult) => void;
useBaseten: boolean;
}
/**
* Calls the server to run model inference.
*
*
*/
export default function ModelInference({
alpha,
seed,
appState,
promptInputs,
nowPlayingResult,
newResultCallback,
useBaseten,
}: ModelInferenceProps) {
// Create parameters for the inference request
const [denoising, setDenoising] = useState(0.75);
const [guidance, setGuidance] = useState(7.0);
const [numInferenceSteps, setNumInferenceSteps] = useState(50);
const [seedImageId, setSeedImageId] = useState("og_beat");
const [maskImageId, setMaskImageId] = useState(null);
const [initializedUrlParams, setInitializedUrlParams] = useState(false);
const [numRequestsMade, setNumRequestsMade] = useState(0);
const [numResponsesReceived, setNumResponsesReceived] = useState(0);
// Set initial params from URL query strings
const router = useRouter();
useEffect(() => {
if (router.query.denoising) {
setDenoising(parseFloat(router.query.denoising as string));
}
if (router.query.guidance) {
setGuidance(parseFloat(router.query.guidance as string));
}
if (router.query.numInferenceSteps) {
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 === "none") {
setMaskImageId("");
} else {
setMaskImageId(router.query.maskImageId as string);
}
}
setInitializedUrlParams(true);
}, [router.query]);
// Memoized function to kick off an inference request
const runInference = useCallback(
async (
alpha: number,
seed: number,
appState: AppState,
promptInputs: PromptInput[]
) => {
const startPrompt = promptInputs[promptInputs.length - 3].prompt;
const endPrompt = promptInputs[promptInputs.length - 2].prompt;
const transitioning = appState == AppState.TRANSITION;
const inferenceInput = {
alpha: alpha,
num_inference_steps: numInferenceSteps,
seed_image_id: seedImageId,
mask_image_id: maskImageId,
start: {
prompt: startPrompt,
seed: seed,
denoising: denoising,
guidance: guidance,
},
end: {
prompt: transitioning ? endPrompt : startPrompt,
seed: transitioning ? seed : seed + 1,
denoising: denoising,
guidance: guidance,
},
};
console.log(`Inference #${numRequestsMade}: `, {
alpha: alpha,
prompt_a: inferenceInput.start.prompt,
seed_a: inferenceInput.start.seed,
prompt_b: inferenceInput.end.prompt,
seed_b: inferenceInput.end.seed,
appState: appState,
});
setNumRequestsMade((n) => n + 1);
let headers = {
"Content-Type": "application/json",
"Access-Control-Allow-Origin": "*",
};
// Customize for baseten
const serverUrl = useBaseten ? BASETEN_URL : SERVER_URL;
const payload = useBaseten
? { worklet_input: inferenceInput }
: inferenceInput;
if (useBaseten) {
headers["Authorization"] = `Api-Key ${BASETEN_API_KEY}`;
}
const response = await fetch(serverUrl, {
method: "POST",
headers: headers,
body: JSON.stringify(payload),
});
const data = await response.json();
console.log(`Got result #${numResponsesReceived}`);
if (useBaseten) {
if (data?.worklet_output?.model_output) {
newResultCallback(
inferenceInput,
JSON.parse(data.worklet_output.model_output)
);
} else {
console.error("Baseten call failed: ", data);
}
} else {
newResultCallback(inferenceInput, data);
}
setNumResponsesReceived((n) => n + 1);
},
[
denoising,
guidance,
maskImageId,
numInferenceSteps,
seedImageId,
newResultCallback,
numRequestsMade,
numResponsesReceived,
useBaseten,
]
);
// Kick off inference requests
useEffect(() => {
// Make sure things are initialized properly
if (
!initializedUrlParams ||
appState == AppState.UNINITIALIZED ||
promptInputs.length == 0
) {
return;
}
if (numRequestsMade == 0) {
// Kick off the first request
runInference(alpha, seed, appState, promptInputs);
} else if (numRequestsMade == numResponsesReceived) {
// Otherwise buffer ahead a few from where the audio player currently is
// TODO(hayk): Replace this with better buffer management
const nowPlayingCounter = nowPlayingResult ? nowPlayingResult.counter : 0;
const numAhead = numRequestsMade - nowPlayingCounter;
if (numAhead < 3) {
runInference(alpha, seed, appState, promptInputs);
}
}
}, [
initializedUrlParams,
alpha,
seed,
appState,
promptInputs,
nowPlayingResult,
numRequestsMade,
numResponsesReceived,
runInference,
]);
return null;
}