Wire screenshot upload and generate to the engine.

This commit is contained in:
Michael Chung committed 2025-04-02 21:36:42 -04:00
1 parent 010e3be5dc
commit 534afbbbf9
3 files changed
+190 -3

No files matched your search

@@ -36,4 +36,141 @@ export class EngineApi extends ApiManager {
};
});
}
public async uploadSceneSnapshot({
screenshot,
sceneMediaToken,
}: {
screenshot: string; // base64 encoded PNG
sceneMediaToken?: string;
}): Promise<ApiResponse<string>> {
const endpoint = `${this.ApiTargets.BaseApi}/v1/image_studio/scene_snapshot`;
const formData = new FormData();
formData.append("screenshot", screenshot);
if (sceneMediaToken) {
formData.append("scene_media_token", sceneMediaToken);
}
return this.post<
FormData,
{ success?: boolean; snapshot_media_token?: string; BadInput?: string }
>({
endpoint,
body: formData,
headers: {
"Content-Type": "multipart/form-data",
},
})
.then((response) => {
return {
success: response.success ?? false,
data: response.snapshot_media_token,
errorMessage: response.BadInput,
};
})
.catch((err) => {
return {
success: false,
errorMessage: err.message,
};
});
}
public async enqueueImageGeneration({
prompt,
sceneMediaToken,
additionalImages,
}: {
prompt: string;
sceneMediaToken: string;
additionalImages?: string[];
}): Promise<ApiResponse<string>> {
const endpoint = `${this.ApiTargets.BaseApi}/v1/image_studio/prompt`;
const body = {
prompt,
scene_media_token: sceneMediaToken,
additional_images: additionalImages,
};
return this.post<
{
prompt: string;
scene_media_token: string;
additional_images?: string[];
},
{ success?: boolean; job_token?: string; BadInput?: string }
>({
endpoint,
body,
})
.then((response) => {
return {
success: response.success ?? false,
data: response.job_token,
errorMessage: response.BadInput,
};
})
.catch((err) => {
return {
success: false,
errorMessage: err.message,
};
});
}
public async pollJobSession(jobToken: string): Promise<ApiResponse<any>> {
const endpoint = `${this.ApiTargets.BaseApi}/v1/jobs/session/${jobToken}`;
return this.get<{
success?: boolean;
status?: string;
result?: any;
BadInput?: string;
}>({
endpoint,
})
.then((response) => {
return {
success: response.success ?? false,
data: response.result,
errorMessage: response.BadInput,
};
})
.catch((err) => {
return {
success: false,
errorMessage: err.message,
};
});
}
public async pollStudioSessionJobs(
jobToken: string,
): Promise<ApiResponse<any>> {
const endpoint = `${this.ApiTargets.BaseApi}/v1/image_studio/session_jobs/${jobToken}`;
return this.get<{
success?: boolean;
status?: string;
result?: any;
BadInput?: string;
}>({
endpoint,
})
.then((response) => {
return {
success: response.success ?? false,
data: response.result,
errorMessage: response.BadInput,
};
})
.catch((err) => {
return {
success: false,
errorMessage: err.message,
};
});
}
}
@@ -641,6 +641,18 @@ class Editor {
document.body.appendChild(this.stats.dom);
}
public snapShotOfCurrentFrame(shouldDownload: boolean = true) {
const snapshot = this.renderer?.domElement.toDataURL("image/png");
if (snapshot) {
const link = document.createElement("a");
link.download = "scene-snapshot.png";
link.href = snapshot;
link.click();
}
return snapshot;
}
public async newScene(sceneTitleInput: string) {
this.activeScene.clear();
this.audio_engine = new AudioEngine();
@@ -948,14 +960,14 @@ class Editor {
this.render_camera_aspect_ratio === CameraAspectRatio.HORIZONTAL_16_9
? 1024
: this.render_camera_aspect_ratio ===
CameraAspectRatio.VERTICAL_9_16
CameraAspectRatio.VERTICAL_9_16
? 576
: 1000;
const height =
this.render_camera_aspect_ratio === CameraAspectRatio.HORIZONTAL_16_9
? 576
: this.render_camera_aspect_ratio ===
CameraAspectRatio.VERTICAL_9_16
CameraAspectRatio.VERTICAL_9_16
? 1024
: 1000;
@@ -1,4 +1,7 @@
import { useState, useRef, useEffect } from "react";
import { useSignals } from "@preact/signals-react/runtime";
import { EngineContext } from "~/pages/PageEnigma/contexts/EngineContext";
import { useContext } from "react";
import {
faPlus,
@@ -13,8 +16,11 @@ import {
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { PopoverItem, PopoverMenu } from "~/components/reusable/Popover";
import { Button } from "~/components";
import { EngineApi } from "~/Classes/ApiManager/EngineApi";
import { scene } from "~/signals/scene";
export const PromptBox = () => {
useSignals();
const editorEngine = useContext(EngineContext);
const [prompt, setPrompt] = useState("");
const [isEnqueueing, setisEnqueueing] = useState(false);
const [aspectRatioList, setAspectRatioList] = useState<PopoverItem[]>([
@@ -116,6 +122,18 @@ export const PromptBox = () => {
const handleEnqueue = async () => {
if (!prompt.trim()) return;
if (editorEngine) {
editorEngine.positive_prompt = prompt;
}
const engineApi = new EngineApi();
engineApi.enqueueImageGeneration({
prompt: prompt,
sceneMediaToken: scene.value.token || "",
additionalImages: [],
});
setisEnqueueing(true);
try {
// generate logic here
@@ -133,6 +151,24 @@ export const PromptBox = () => {
}
};
const handleSaveFrame = () => {
if (editorEngine) {
const snapshot = editorEngine.snapShotOfCurrentFrame(false);
const engineApi = new EngineApi();
engineApi.uploadSceneSnapshot({
screenshot: snapshot || "",
sceneMediaToken: scene.value.token || "",
});
}
};
const handleDownloadFrame = () => {
if (editorEngine) {
editorEngine.snapShotOfCurrentFrame(true);
}
};
return (
<div className="glass absolute bottom-4 left-1/2 w-[730px] -translate-x-1/2 rounded-xl p-4">
<input
@@ -203,6 +239,7 @@ export const PromptBox = () => {
className="flex items-center border-none bg-[#5F5F68]/60 px-3 text-sm text-white backdrop-blur-lg hover:bg-[#5F5F68]/90"
variant="secondary"
icon={faDownload}
onClick={handleSaveFrame}
>
Download frame
</Button>
@@ -210,6 +247,7 @@ export const PromptBox = () => {
className="flex items-center border-none bg-[#5F5F68]/60 px-3 text-sm text-white backdrop-blur-lg hover:bg-[#5F5F68]/90"
variant="secondary"
icon={faSave}
onClick={handleDownloadFrame}
>
Save frame
</Button>