mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-05 01:38:44 +00:00
Wire screenshot upload and generate to the engine.
This commit is contained in:
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>
|
||||
|
||||
Reference in new issue
Block a user