mirror of
https://github.com/storytold/artcraft.git
synced 2026-10-21 09:22:41 -04:00
Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a955d5ae27 | ||
|
|
37c01bc0a1 | ||
|
|
8fd75a1cac | ||
|
|
c97e0f6b43 | ||
|
|
becb84ff68 |
@@ -36,9 +36,14 @@ interface Props {
|
||||
const appTabs: TabItem[] = [
|
||||
{ id: "2D", label: "2D" },
|
||||
{ id: "3D", label: "3D" },
|
||||
// { id: "VIDEO", label: "Video" },
|
||||
{ id: "VIDEO", label: "Video" },
|
||||
];
|
||||
|
||||
import { signal } from "@preact/signals-react";
|
||||
|
||||
export const topNavMediaId = signal<string>("");
|
||||
export const topNavMediaUrl = signal<string>("");
|
||||
|
||||
export const TopBar = ({
|
||||
pageName,
|
||||
appTabIdSignal,
|
||||
@@ -55,6 +60,9 @@ export const TopBar = ({
|
||||
const [activeLibraryTab, setActiveLibraryTab] = useState("my-media");
|
||||
const [isSettingsModalOpen, setIsSettingsModalOpen] = useState(false);
|
||||
|
||||
const [url, setUrl] = useState<string>("");
|
||||
const [mediaId, setMediaId] = useState<string>("");
|
||||
|
||||
const engine3D = useContext(EngineContext);
|
||||
const handleTabChange = (tabId: string) => {
|
||||
if (appTabIdSignal.peek() == "3D") {
|
||||
@@ -75,35 +83,28 @@ export const TopBar = ({
|
||||
url: string,
|
||||
media_id: string | undefined,
|
||||
) => {
|
||||
console.log("add to scene", url);
|
||||
console.log("Items to add to scene", currentAppTabId);
|
||||
console.log("url", url);
|
||||
console.log("media_id", media_id);
|
||||
|
||||
setUrl(url);
|
||||
setMediaId(media_id ?? "");
|
||||
|
||||
if (currentAppTabId === "2D") {
|
||||
console.log("Adding to 2D scene");
|
||||
|
||||
// from the uploaded image url.
|
||||
} else if (currentAppTabId === "3D") {
|
||||
console.log("Adding to 3D scene");
|
||||
|
||||
// from the uploaded image url.
|
||||
// engine3D?.activeScene.loadObjectFromUrl(
|
||||
// "https://cdn-2.fakeyou.com/media/r/h/0/5/3/rh053gbx8yvjwk1mdvag4gkr5c0h9wbh/image_rh053gbx8yvjwk1mdvag4gkr5c0h9wbh.png",
|
||||
// );
|
||||
|
||||
// from the gallery modal.
|
||||
// engine3D?.activeScene.loadObjectFromUrl(
|
||||
// "https://cdn-2.fakeyou.com/media/1/t/b/0/e/1tb0e53691mdgqmtd4fmzy58wp96vwxz/image_1tb0e53691mdgqmtd4fmzy58wp96vwxz.png",
|
||||
// );
|
||||
|
||||
// // working media id m_ehq8051fx4hddhja54a7zmz897cgrk
|
||||
// engine3D?.activeScene.loadObject(
|
||||
// "m_ehq8051fx4hddhja54a7zmz897cgrk",
|
||||
// "image",
|
||||
// true,
|
||||
// );
|
||||
|
||||
// media id from the image selected from gallery.
|
||||
engine3D?.activeScene.loadObject(media_id, "image", true);
|
||||
if (media_id) {
|
||||
engine3D?.activeScene.loadObject(media_id, "image", true);
|
||||
} else {
|
||||
console.warn("No media id provided");
|
||||
}
|
||||
} else if (currentAppTabId === "VIDEO") {
|
||||
console.log("Adding to Video scene");
|
||||
topNavMediaId.value = media_id ?? "";
|
||||
topNavMediaUrl.value = url;
|
||||
} else {
|
||||
console.warn(`Unknown tab type: ${currentAppTabId}`);
|
||||
}
|
||||
|
||||
@@ -50,6 +50,8 @@ import { LoginModal } from "@storyteller/ui-login-modal";
|
||||
import { DomLevels } from "./signals/hotkeys";
|
||||
import { AUTH_STATUS } from "../../enums/authentication";
|
||||
import { authentication } from "../../signals/authentication/authentication";
|
||||
import { topNavMediaId } from "~/components/signaled/TopBar/TopBar";
|
||||
import { topNavMediaUrl } from "~/components/signaled/TopBar/TopBar";
|
||||
|
||||
export const PageEditor = () => {
|
||||
useSignals();
|
||||
@@ -345,7 +347,11 @@ export const PageEditor = () => {
|
||||
</KonvaCanvasContainer>
|
||||
|
||||
<div style={{ display: displayVideo }}>
|
||||
<ImageToVideo className="h-full w-full" />
|
||||
<ImageToVideo
|
||||
className="h-full w-full"
|
||||
imageMediaId={topNavMediaId.value}
|
||||
imageUrl={topNavMediaUrl.value}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<LoginModal
|
||||
|
||||
@@ -5,25 +5,24 @@ import BackgroundGallery from "./BackgroundGallery";
|
||||
import { PopoverMenu, type PopoverItem } from "@storyteller/ui-popover";
|
||||
import { faFilm, faClock } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
|
||||
const ImageToVideo = () => {
|
||||
interface ImageToVideoProps {
|
||||
imageMediaId?: string;
|
||||
imageUrl?: string;
|
||||
}
|
||||
|
||||
const ImageToVideo = ({ imageMediaId, imageUrl }: ImageToVideoProps) => {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const [selectedModel, setSelectedModel] = useState<string>("Kling 2.0");
|
||||
const [useSystemPrompt, setUseSystemPrompt] = useState(false);
|
||||
|
||||
const [useSystemPrompt, setUseSystemPrompt] = useState(false);
|
||||
const [isImageBeingProcessed, setIsImageBeingProcessed] = useState(false);
|
||||
|
||||
const [selectedImage, setSelectedImage] = useState<File | null>(null);
|
||||
const [imagePreviewUrl, setImagePreviewUrl] = useState<string>("");
|
||||
const [isDialogOpen, setIsDialogOpen] = useState(false);
|
||||
|
||||
const handleClose = () => setIsDialogOpen(false);
|
||||
const handleAddImage = (image: File) => {
|
||||
setSelectedImage(image);
|
||||
setIsImageBeingProcessed(true);
|
||||
setImagePreviewUrl(URL.createObjectURL(image));
|
||||
setTimeout(() => setIsImageBeingProcessed(false), 3000);
|
||||
};
|
||||
|
||||
const jobContext: JobContextType = {
|
||||
jobTokens: [],
|
||||
addJobToken: () => {},
|
||||
@@ -72,8 +71,10 @@ const ImageToVideo = () => {
|
||||
console.log("Using job context");
|
||||
return jobContext;
|
||||
}}
|
||||
model={selectedModel}
|
||||
imageMediaId={imageMediaId}
|
||||
url={imageUrl ?? imagePreviewUrl ?? undefined}
|
||||
onEnqueuePressed={async () => {
|
||||
// TODO: Implement enqueue logic
|
||||
console.log("Enqueue pressed");
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { signal } from "@preact/signals-react";
|
||||
|
||||
// change starting tab
|
||||
export const appTabId = signal("3D");
|
||||
export const appTabId = signal("VIDEO");
|
||||
|
||||
export const setAppTabId = (newId: string) => {
|
||||
if (newId != "2D" && newId != "3D" && newId != "VIDEO") {
|
||||
|
||||
@@ -26,7 +26,6 @@ interface LightboxModalProps {
|
||||
url: string,
|
||||
media_id: string | undefined
|
||||
) => Promise<void>;
|
||||
activeTab?: string;
|
||||
}
|
||||
|
||||
export function LightboxModal({
|
||||
@@ -43,7 +42,6 @@ export function LightboxModal({
|
||||
mediaId, // media id of the image
|
||||
onDownloadClicked,
|
||||
onAddToSceneClicked,
|
||||
activeTab,
|
||||
}: LightboxModalProps) {
|
||||
return createPortal(
|
||||
<Transition appear show={isOpen}>
|
||||
@@ -94,11 +92,6 @@ export function LightboxModal({
|
||||
<div className="flex h-full w-full items-center justify-center bg-gray-800">
|
||||
<span className="text-white/60">Image not available</span>
|
||||
</div>
|
||||
) : activeTab === "videos" ? (
|
||||
<video controls className="h-full w-full object-contain">
|
||||
<source src={imageUrl} type="video/mp4" />
|
||||
Your browser does not support the video tag.
|
||||
</video>
|
||||
) : (
|
||||
<img
|
||||
src={imageUrl}
|
||||
@@ -113,7 +106,7 @@ export function LightboxModal({
|
||||
<div className="flex h-full flex-col py-5 pe-5">
|
||||
<div className="flex-1 space-y-4">
|
||||
<div className="text-xl font-medium">
|
||||
{title || (activeTab === "videos" ? "Video" : "Image")}
|
||||
{title || "Image Generation"}
|
||||
</div>
|
||||
{createdAt && (
|
||||
<div className="text-sm text-white/60">
|
||||
@@ -127,52 +120,34 @@ export function LightboxModal({
|
||||
{/* buttons with spacing */}
|
||||
{(onAddToSceneClicked && downloadUrl) || downloadUrl ? (
|
||||
<div className="mt-15 mb-15 flex justify-end gap-2">
|
||||
{activeTab !== "videos" && (
|
||||
<>
|
||||
<Button
|
||||
onClick={async (e) => {
|
||||
let _result = await FalKlingImageToVideo({
|
||||
image_media_token: mediaId,
|
||||
//base64_image: downloadUrl,
|
||||
});
|
||||
//e.stopPropagation();
|
||||
//await onAddToSceneClicked(downloadUrl, mediaId);
|
||||
//onClose(); // close the lightbox
|
||||
//onCloseGallery(); // close the gallery
|
||||
}}
|
||||
>
|
||||
Video
|
||||
</Button>
|
||||
<Button
|
||||
onClick={async (e) => {
|
||||
let _result = await FalHunyuanImageTo3d({
|
||||
image_media_token: mediaId,
|
||||
//base64_image: downloadUrl,
|
||||
});
|
||||
//e.stopPropagation();
|
||||
//await onAddToSceneClicked(downloadUrl, mediaId);
|
||||
//onClose(); // close the lightbox
|
||||
//onCloseGallery(); // close the gallery
|
||||
}}
|
||||
>
|
||||
3D
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
onClick={async (e) => {
|
||||
let _result = await FalHunyuanImageTo3d({
|
||||
image_media_token: mediaId,
|
||||
//base64_image: downloadUrl,
|
||||
});
|
||||
//e.stopPropagation();
|
||||
//await onAddToSceneClicked(downloadUrl, mediaId);
|
||||
//onClose(); // close the lightbox
|
||||
//onCloseGallery(); // close the gallery
|
||||
}}
|
||||
>
|
||||
3D
|
||||
</Button>
|
||||
|
||||
{onAddToSceneClicked && downloadUrl && (
|
||||
<Button
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
await onAddToSceneClicked(downloadUrl, mediaId);
|
||||
onClose(); // close the lightbox
|
||||
onCloseGallery(); // close the gallery
|
||||
}}
|
||||
>
|
||||
Add to Current Scene
|
||||
</Button>
|
||||
)}
|
||||
</>
|
||||
{onAddToSceneClicked && downloadUrl && (
|
||||
<Button
|
||||
onClick={async (e) => {
|
||||
e.stopPropagation();
|
||||
await onAddToSceneClicked(downloadUrl, mediaId);
|
||||
onClose(); // close the lightbox
|
||||
onCloseGallery(); // close the gallery
|
||||
}}
|
||||
>
|
||||
Add to Current Scene
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{downloadUrl &&
|
||||
(onDownloadClicked ? (
|
||||
<Button
|
||||
|
||||
@@ -1,17 +1,13 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useSignals } from "@preact/signals-react/runtime";
|
||||
import { toast } from "@storyteller/ui-toaster";
|
||||
import {
|
||||
JobContextType,
|
||||
MaybeCanvasRenderBitmapType,
|
||||
UploaderState,
|
||||
UploaderStates,
|
||||
} from "@storyteller/common";
|
||||
import { JobContextType } from "@storyteller/common";
|
||||
import { downloadFileFromUrl } from "@storyteller/api";
|
||||
import { PopoverMenu, PopoverItem } from "@storyteller/ui-popover";
|
||||
import { Tooltip } from "@storyteller/ui-tooltip";
|
||||
import { Button, ToggleButton } from "@storyteller/ui-button";
|
||||
import { Modal } from "@storyteller/ui-modal";
|
||||
import { FalKlingImageToVideo } from "@storyteller/tauri-api";
|
||||
import {
|
||||
faMessageXmark,
|
||||
faMessageCheck,
|
||||
@@ -30,12 +26,9 @@ import {
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { IsDesktopApp } from "@storyteller/tauri-utils";
|
||||
import { GalleryItem, GalleryModal } from "@storyteller/ui-gallery-modal";
|
||||
import { PromptsApi } from "@storyteller/api";
|
||||
import {
|
||||
CommandSuccessStatus,
|
||||
GetAppPreferences,
|
||||
SoraImageRemix,
|
||||
SoraImageRemixErrorType,
|
||||
} from "@storyteller/tauri-api";
|
||||
import { SoundRegistry } from "@storyteller/soundboard";
|
||||
|
||||
@@ -47,30 +40,35 @@ interface ReferenceImage {
|
||||
}
|
||||
|
||||
interface PromptBoxVideoProps {
|
||||
uploadImage: ({
|
||||
title,
|
||||
assetFile,
|
||||
progressCallback,
|
||||
}: {
|
||||
title: string;
|
||||
assetFile: File;
|
||||
progressCallback: (newState: UploaderState) => void;
|
||||
}) => Promise<void>;
|
||||
getCanvasRenderBitmap: () => MaybeCanvasRenderBitmapType;
|
||||
EncodeImageBitmapToBase64: (imageBitmap: ImageBitmap) => Promise<string>;
|
||||
useJobContext: () => JobContextType;
|
||||
onEnqueuePressed?: () => void | Promise<void>;
|
||||
model: string;
|
||||
imageMediaId?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
export const PromptBoxVideo = ({
|
||||
uploadImage,
|
||||
getCanvasRenderBitmap,
|
||||
EncodeImageBitmapToBase64,
|
||||
useJobContext,
|
||||
onEnqueuePressed,
|
||||
model,
|
||||
imageMediaId,
|
||||
url,
|
||||
}: PromptBoxVideoProps) => {
|
||||
useSignals();
|
||||
|
||||
// for the image media id and url, we need to set the reference image gallery panel.
|
||||
useEffect(() => {
|
||||
if (imageMediaId && url) {
|
||||
const referenceImage: ReferenceImage = {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
url: url,
|
||||
file: new File([], "library-image"),
|
||||
mediaToken: imageMediaId,
|
||||
};
|
||||
setReferenceImages([referenceImage]);
|
||||
}
|
||||
}, [imageMediaId, url]);
|
||||
|
||||
console.log("Is this a desktop app?", IsDesktopApp());
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
const [content, setContent] = useState("");
|
||||
@@ -112,6 +110,18 @@ export const PromptBoxVideo = ({
|
||||
}
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (imageMediaId && url) {
|
||||
const referenceImage: ReferenceImage = {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
url: url,
|
||||
file: new File([], "library-image"),
|
||||
mediaToken: imageMediaId,
|
||||
};
|
||||
setReferenceImages([referenceImage]);
|
||||
}
|
||||
}, [imageMediaId, url]);
|
||||
|
||||
const handleResolutionSelect = (selectedItem: PopoverItem) => {
|
||||
setResolutionList((prev) =>
|
||||
prev.map((item) => ({
|
||||
@@ -121,53 +131,6 @@ export const PromptBoxVideo = ({
|
||||
);
|
||||
};
|
||||
|
||||
const handleFileUpload = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const files = event.target.files;
|
||||
if (files) {
|
||||
Array.from(files).forEach((file) => {
|
||||
const uploadId = Math.random().toString(36).substring(7);
|
||||
setUploadingImages((prev) => [...prev, { id: uploadId, file }]);
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.onloadend = () => {
|
||||
uploadImage({
|
||||
title: `reference-image-${Math.random()
|
||||
.toString(36)
|
||||
.substring(2, 15)}`,
|
||||
assetFile: file,
|
||||
progressCallback: (newState) => {
|
||||
console.debug("Upload progress:", newState.data);
|
||||
if (newState.status === UploaderStates.success && newState.data) {
|
||||
const referenceImage: ReferenceImage = {
|
||||
id: Math.random().toString(36).substring(7),
|
||||
url: reader.result as string,
|
||||
file,
|
||||
mediaToken: newState.data || "",
|
||||
};
|
||||
setReferenceImages((prev) => [...prev, referenceImage]);
|
||||
setUploadingImages((prev) =>
|
||||
prev.filter((img) => img.id !== uploadId)
|
||||
);
|
||||
toast.success("Reference image added.");
|
||||
} else if (
|
||||
newState.status === UploaderStates.assetError ||
|
||||
newState.status === UploaderStates.imageCreateError
|
||||
) {
|
||||
setUploadingImages((prev) =>
|
||||
prev.filter((img) => img.id !== uploadId)
|
||||
);
|
||||
|
||||
toast.error("Upload failed. Please try again.");
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleRemoveReference = (id: string) => {
|
||||
setReferenceImages((prev) => prev.filter((img) => img.id !== id));
|
||||
if (fileInputRef.current) {
|
||||
@@ -175,10 +138,6 @@ export const PromptBoxVideo = ({
|
||||
}
|
||||
};
|
||||
|
||||
const handleUploadClick = () => {
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleGallerySelect = () => {
|
||||
setIsGalleryModalOpen(true);
|
||||
};
|
||||
@@ -236,49 +195,14 @@ export const PromptBoxVideo = ({
|
||||
setPrompt(e.target.value);
|
||||
};
|
||||
|
||||
const handleTauriEnqueue = async () => {
|
||||
const api = new PromptsApi();
|
||||
let image = getCanvasRenderBitmap();
|
||||
if (image === undefined) {
|
||||
console.log("image is undefined");
|
||||
return;
|
||||
}
|
||||
const base64Bitmap = await EncodeImageBitmapToBase64(image);
|
||||
|
||||
const byteString = atob(base64Bitmap);
|
||||
const mimeString = "image/png";
|
||||
|
||||
const ab = new ArrayBuffer(byteString.length);
|
||||
const ia = new Uint8Array(ab);
|
||||
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
ia[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const uuid = crypto.randomUUID(); // Generate a new UUID
|
||||
const file = new File([ab], `${uuid}.png`, { type: mimeString });
|
||||
|
||||
const snapshotMediaToken = await api.uploadSceneSnapshot({
|
||||
screenshot: file,
|
||||
});
|
||||
|
||||
if (snapshotMediaToken.data === undefined) {
|
||||
toast.error("Error: Unable to upload scene snapshot Please try again.");
|
||||
return;
|
||||
}
|
||||
console.log("useSystemPrompt", useSystemPrompt);
|
||||
console.log("Snapshot media token:", snapshotMediaToken.data);
|
||||
|
||||
const generateResponse = await SoraImageRemix({
|
||||
snapshot_media_token: snapshotMediaToken.data,
|
||||
disable_system_prompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
maybe_additional_images: referenceImages.map((image) => image.mediaToken),
|
||||
maybe_number_of_samples: 1,
|
||||
const handleEnqueue = async () => {
|
||||
setIsEnqueueing(true);
|
||||
const generateResponse = await FalKlingImageToVideo({
|
||||
image_media_token: referenceImages[0].mediaToken,
|
||||
});
|
||||
|
||||
console.log("generateResponse", generateResponse);
|
||||
|
||||
onEnqueuePressed?.();
|
||||
if (generateResponse.status === CommandSuccessStatus.Success) {
|
||||
const prefs = await GetAppPreferences();
|
||||
const soundName = prefs.preferences?.enqueue_success_sound;
|
||||
@@ -294,129 +218,34 @@ export const PromptBoxVideo = ({
|
||||
const registry = SoundRegistry.getInstance();
|
||||
registry.playSound(soundName);
|
||||
}
|
||||
|
||||
let errorMessage = "Failed to enqueue image";
|
||||
|
||||
if ("error_type" in generateResponse) {
|
||||
switch (generateResponse.error_type) {
|
||||
case SoraImageRemixErrorType.SoraLoginRequired:
|
||||
errorMessage =
|
||||
"You need to log into Sora to continue. See the settings menu.";
|
||||
break;
|
||||
case SoraImageRemixErrorType.ServerError:
|
||||
errorMessage = "Server error. Failed to enqueue image.";
|
||||
break;
|
||||
case SoraImageRemixErrorType.TooManyConcurrentTasks:
|
||||
errorMessage =
|
||||
"You have too many Sora image generation tasks running. Please wait a moment.";
|
||||
break;
|
||||
case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
|
||||
errorMessage =
|
||||
"Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
|
||||
break;
|
||||
case SoraImageRemixErrorType.SoraIsHavingProblems:
|
||||
errorMessage = "Sora is having problems. Please try again later.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
toast.error(errorMessage);
|
||||
}
|
||||
};
|
||||
|
||||
const handleWebEnqueue = async () => {
|
||||
const api = new PromptsApi();
|
||||
// to take the snapshot of the canvas
|
||||
// Call onEnqueuePressed if it exists
|
||||
|
||||
let image = getCanvasRenderBitmap();
|
||||
if (image === undefined) {
|
||||
toast.error(
|
||||
"Error: Unable to generate image. Please check the input and try again."
|
||||
);
|
||||
return;
|
||||
}
|
||||
const base64Bitmap = await EncodeImageBitmapToBase64(image);
|
||||
|
||||
const byteString = atob(base64Bitmap);
|
||||
const mimeString = "image/png";
|
||||
|
||||
const ab = new ArrayBuffer(byteString.length);
|
||||
const ia = new Uint8Array(ab);
|
||||
|
||||
for (let i = 0; i < byteString.length; i++) {
|
||||
ia[i] = byteString.charCodeAt(i);
|
||||
}
|
||||
|
||||
const uuid = crypto.randomUUID(); // Generate a new UUID
|
||||
const file = new File([ab], `${uuid}.png`, { type: mimeString });
|
||||
|
||||
const snapshotMediaToken = await api.uploadSceneSnapshot({
|
||||
screenshot: file,
|
||||
});
|
||||
|
||||
if (snapshotMediaToken.data === undefined) {
|
||||
toast.error("Error: Unable to upload scene snapshot Please try again.");
|
||||
return;
|
||||
}
|
||||
console.log("useSystemPrompt", useSystemPrompt);
|
||||
console.log("Snapshot media token:", snapshotMediaToken.data);
|
||||
|
||||
const response = await api.enqueueImageGeneration({
|
||||
disableSystemPrompt: !useSystemPrompt,
|
||||
prompt: prompt,
|
||||
snapshotMediaToken: snapshotMediaToken.data,
|
||||
additionalImages: referenceImages.map((image) => image.mediaToken),
|
||||
});
|
||||
|
||||
if (response.success === true) {
|
||||
toast.success("Please wait while we process your image.");
|
||||
if (response.data) {
|
||||
addJobToken(response.data);
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
toast.error("Failed to enqueue image generation. Please try again.");
|
||||
}
|
||||
};
|
||||
const handleEnqueue = async () => {
|
||||
console.log("Pressing Enqueue");
|
||||
if (onEnqueuePressed) {
|
||||
try {
|
||||
await onEnqueuePressed();
|
||||
} catch (error) {
|
||||
console.error("Error in onEnqueuePressed callback:", error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isEnqueueing) return;
|
||||
setIsEnqueueing(true);
|
||||
if (!prompt.trim()) return;
|
||||
try {
|
||||
console.log(
|
||||
"(4) Enqueuing with prompt:",
|
||||
prompt,
|
||||
"and reference images:",
|
||||
referenceImages
|
||||
);
|
||||
|
||||
const isDesktop = IsDesktopApp();
|
||||
console.log("Is this a desktop app?", isDesktop);
|
||||
|
||||
if (isDesktop) {
|
||||
await handleTauriEnqueue();
|
||||
} else {
|
||||
await handleWebEnqueue();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error during image generation:", error);
|
||||
toast.error(
|
||||
"An error occurred while generating the image. Please try again."
|
||||
);
|
||||
} finally {
|
||||
await new Promise((resolve) => setTimeout(resolve, 100));
|
||||
setIsEnqueueing(false);
|
||||
}
|
||||
// let errorMessage = "Failed to enqueue image";
|
||||
// if ("error_type" in generateResponse) {
|
||||
// switch (generateResponse.error_type) {
|
||||
// case SoraImageRemixErrorType.SoraLoginRequired:
|
||||
// errorMessage =
|
||||
// "You need to log into Sora to continue. See the settings menu.";
|
||||
// break;
|
||||
// case SoraImageRemixErrorType.ServerError:
|
||||
// errorMessage = "Server error. Failed to enqueue image.";
|
||||
// break;
|
||||
// case SoraImageRemixErrorType.TooManyConcurrentTasks:
|
||||
// errorMessage =
|
||||
// "You have too many Sora image generation tasks running. Please wait a moment.";
|
||||
// break;
|
||||
// case SoraImageRemixErrorType.SoraUsernameNotYetCreated:
|
||||
// errorMessage =
|
||||
// "Your Sora username is not yet created. Please visit the Sora.com website to create it first.";
|
||||
// break;
|
||||
// case SoraImageRemixErrorType.SoraIsHavingProblems:
|
||||
// errorMessage = "Sora is having problems. Please try again later.";
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// toast.error(errorMessage);
|
||||
// }
|
||||
setIsEnqueueing(false);
|
||||
};
|
||||
|
||||
const getCurrentResolutionIcon = () => {
|
||||
@@ -429,7 +258,6 @@ export const PromptBoxVideo = ({
|
||||
const handleKeyDown = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
|
||||
if (e.key === "Enter" && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
|
||||
handleEnqueue();
|
||||
}
|
||||
};
|
||||
@@ -492,14 +320,6 @@ export const PromptBoxVideo = ({
|
||||
</div>
|
||||
)}
|
||||
<div className="glass w-[730px] rounded-xl p-4">
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
className="hidden"
|
||||
accept="image/*"
|
||||
onChange={handleFileUpload}
|
||||
multiple
|
||||
/>
|
||||
<div className="flex justify-center gap-2">
|
||||
<PopoverMenu
|
||||
mode="button"
|
||||
|
||||
Reference in New Issue
Block a user