diff --git a/app/components/signaled/TopBar/MyMoviesButton.tsx b/app/components/signaled/TopBar/MyMoviesButton.tsx
index 643a67ed38..678767d77a 100644
--- a/app/components/signaled/TopBar/MyMoviesButton.tsx
+++ b/app/components/signaled/TopBar/MyMoviesButton.tsx
@@ -9,7 +9,9 @@ import { activeWorkflowJobs } from "~/signals";
export const MyMoviesButton = () => {
useSignals();
- const activeCount = activeWorkflowJobs.value.length;
+ const activeCount = activeWorkflowJobs.value
+ ? activeWorkflowJobs.value.length
+ : 0;
return (
diff --git a/app/constants.ts b/app/constants.ts
index 9389eab36b..11d9e00d54 100644
--- a/app/constants.ts
+++ b/app/constants.ts
@@ -6,3 +6,4 @@ export const ONE_MINUTE = 60000;
export const TWO_SECONDS = 2000;
export const FIVE_SECONDS = 5000;
export const SEVEN_SECONDS = 7000;
+export const TEN_SECONDS = 10000;
diff --git a/app/enums/JobStatus.ts b/app/enums/JobStatus.ts
index 353a93dd7e..7b1099de11 100644
--- a/app/enums/JobStatus.ts
+++ b/app/enums/JobStatus.ts
@@ -8,3 +8,9 @@ export enum JobStatus {
CANCELLED_BY_USER = "cancelled_by_user",
CANCCELLED_BY_SYSTEM = "cancelled_by_system",
}
+
+export enum JobType {
+ TextToSpeech = "text_to_speech",
+ VoiceConversion = "voice_conversion",
+ VideoStyleTransfer = "workflow",
+}
diff --git a/app/hooks/index.tsx b/app/hooks/index.tsx
index f962410657..b5cc5590a2 100644
--- a/app/hooks/index.tsx
+++ b/app/hooks/index.tsx
@@ -1 +1 @@
-export * from "./useInferenceJobManager";
+export * from "./useActiveJobs";
diff --git a/app/hooks/useActiveJobs/index.tsx b/app/hooks/useActiveJobs/index.tsx
new file mode 100644
index 0000000000..59e67688ff
--- /dev/null
+++ b/app/hooks/useActiveJobs/index.tsx
@@ -0,0 +1 @@
+export { useActiveJobs } from "./useActiveJobs";
diff --git a/app/hooks/useInferenceJobManager/types.ts b/app/hooks/useActiveJobs/types.ts
similarity index 59%
rename from app/hooks/useInferenceJobManager/types.ts
rename to app/hooks/useActiveJobs/types.ts
index 3001bbee7a..182d2c8e06 100644
--- a/app/hooks/useInferenceJobManager/types.ts
+++ b/app/hooks/useActiveJobs/types.ts
@@ -1,5 +1,9 @@
import { Job } from "~/models";
+export type WindowExtended = typeof window & {
+ stopPollingActiveJobs: () => void;
+};
+
export type GetJobsResponse = {
success: boolean;
error_message?: string;
diff --git a/app/hooks/useActiveJobs/useActiveJobs.ts b/app/hooks/useActiveJobs/useActiveJobs.ts
new file mode 100644
index 0000000000..b667c7179d
--- /dev/null
+++ b/app/hooks/useActiveJobs/useActiveJobs.ts
@@ -0,0 +1,130 @@
+import { useCallback, useEffect, useLayoutEffect, useState } from "react";
+import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
+
+import { JobType } from "~/enums";
+
+import {
+ activeJobs,
+ shouldPollActiveJobs,
+ startPollingActiveJobs,
+ stopPollingActiveJobs,
+} from "~/signals";
+
+import { PollRecentJobs } from "./utilities";
+import { TEN_SECONDS, TWO_SECONDS } from "~/constants";
+import { WindowExtended } from "./types";
+
+export const useActiveJobs = () => {
+ useSignals();
+
+ const [timerState, setTimerState] = useState<{
+ timer: NodeJS.Timeout | undefined;
+ interval: number;
+ }>({
+ timer: undefined,
+ interval: TWO_SECONDS,
+ });
+
+ const resetTimer = useCallback((newTimeInterval: number) => {
+ setTimerState((curr) => {
+ if (!curr.timer) {
+ // if no timer, just change interval
+ return {
+ timer: curr.timer,
+ interval: newTimeInterval,
+ };
+ }
+ // if timer already exist, first clear
+ // then set new one with new interval
+ clearInterval(curr.timer);
+ const newTimer = setInterval(() => {
+ PollRecentJobs();
+ }, newTimeInterval);
+ return {
+ timer: newTimer,
+ interval: newTimeInterval,
+ };
+ });
+ }, []);
+
+ const clearTimer = useCallback(() => {
+ if (timerState.timer) {
+ clearInterval(timerState.timer);
+ setTimerState((curr) => ({
+ ...curr,
+ timer: undefined,
+ }));
+ }
+ }, [timerState.timer]);
+
+ useEffect(() => {
+ return () => {
+ //make sure we run clear timer as well on dismount;
+ clearInterval(timerState.timer);
+ };
+ }, [timerState.timer]);
+
+ useLayoutEffect(() => {
+ //TODO: add dev account guard
+ (window as WindowExtended).stopPollingActiveJobs = stopPollingActiveJobs;
+ }, []);
+
+ useSignalEffect(() => {
+ // if active jobs is not initiated, do do a first pull;
+ if (!activeJobs.value) {
+ PollRecentJobs();
+ return;
+ }
+ // if there are no active jobs, stop making polls
+ if (activeJobs.value.length === 0) {
+ stopPollingActiveJobs();
+ return;
+ }
+
+ if (activeJobs.value.length > 0) {
+ // if there are active jobs, first, manage polling interval
+ const hasShortJobs =
+ activeJobs.value.find((job) => {
+ return (
+ job.request.inference_category === JobType.TextToSpeech ||
+ job.request.inference_category === JobType.VoiceConversion
+ );
+ }) !== undefined;
+ if (!hasShortJobs && timerState.interval < TEN_SECONDS) {
+ resetTimer(TEN_SECONDS);
+ }
+ if (hasShortJobs && timerState.interval > TWO_SECONDS) {
+ resetTimer(TWO_SECONDS);
+ }
+
+ // if there are active jobs, and is not polling, start polling
+ if (!shouldPollActiveJobs.value) {
+ startPollingActiveJobs();
+ }
+ }
+ });
+
+ useSignalEffect(() => {
+ //trigger the pull via a timer
+ if (shouldPollActiveJobs.value) {
+ setTimerState((curr) => {
+ if (curr.timer) {
+ //do nothing if timer is already running;
+ return curr;
+ }
+
+ //else make and set timer
+ const newTimer = setInterval(() => {
+ PollRecentJobs();
+ }, curr.interval);
+ return {
+ ...curr,
+ timer: newTimer,
+ };
+ });
+ return;
+ }
+ // should not poll, then clear timer
+ clearTimer();
+ });
+};
diff --git a/app/hooks/useActiveJobs/utilities.ts b/app/hooks/useActiveJobs/utilities.ts
new file mode 100644
index 0000000000..05f0561335
--- /dev/null
+++ b/app/hooks/useActiveJobs/utilities.ts
@@ -0,0 +1,27 @@
+import { getRecentJobs } from "~/api";
+import { ToastTypes } from "~/enums";
+import { authentication, addToast, setJobs } from "~/signals";
+
+export function PollRecentJobs() {
+ console.log("Poll recent jobs");
+ const endpoint = getRecentJobs;
+
+ fetch(endpoint, {
+ method: "GET",
+ headers: {
+ Accept: "application/json",
+ session: authentication.sessionToken.value || "",
+ },
+ credentials: "include",
+ })
+ .then((res) => res.json())
+ .then((res) => {
+ if (res.jobs && res.jobs.length > 0) {
+ setJobs(res.jobs);
+ // just no jobs, not an error, do nothing
+ }
+ })
+ .catch(() => {
+ addToast(ToastTypes.ERROR, "Unknown Error in Getting Recent Jobs");
+ });
+}
diff --git a/app/hooks/useBackgroundLoadingMedia/useBackgroundLoadingMedia.tsx b/app/hooks/useBackgroundLoadingMedia/useBackgroundLoadingMedia.tsx
index ae66676099..f122638e35 100644
--- a/app/hooks/useBackgroundLoadingMedia/useBackgroundLoadingMedia.tsx
+++ b/app/hooks/useBackgroundLoadingMedia/useBackgroundLoadingMedia.tsx
@@ -1,47 +1,18 @@
-import { useCallback } from "react";
import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
-import { GetUserMovies, instanceOfMediaListResponse } from "./utilities";
-import { addToast, authentication, completedJobs } from "~/signals";
+import { PollUserMovies, PollUserAudioItems } from "./utilities";
-import {
- myMovies,
- setMyMovies,
- shouldPollMyMovies,
-} from "~/pages/PageEnigma/signals";
-import { ToastTypes } from "~/enums";
+import { completedJobs, userMovies, userAudioItems } from "~/signals";
+
+import { JobType } from "~/enums";
export const useBackgroundLoadingMedia = () => {
useSignals();
- const PollMyMovies = useCallback(() => {
- // console.log("polling my movies");
- if (authentication.userInfo.value?.username) {
- GetUserMovies(authentication.userInfo.value.username).then((res) => {
- // console.log("GetUerMovies has response:", res);
- if (instanceOfMediaListResponse(res)) {
- setMyMovies(res.results);
- } else {
- addToast(ToastTypes.ERROR, res.error_reason);
- }
- });
- }
- }, []);
-
- useSignalEffect(() => {
- if (shouldPollMyMovies.value) {
- // shouldPollMyMovies is initiated as true to guaruntee first pull on load
- PollMyMovies();
- }
- });
-
useSignalEffect(() => {
//CASE 1: first load
- // if myMovies undefined, first load is not done
- if (!myMovies.value) {
- // turn on polling if it is not already on
- if (!shouldPollMyMovies.value) {
- shouldPollMyMovies.value = true;
- }
+ // if myMovies undefined, poll for the first time
+ if (!userMovies.value) {
+ PollUserMovies();
return;
}
@@ -53,7 +24,7 @@ export const useBackgroundLoadingMedia = () => {
const workflowJobsTokens = completedJobs.value
.filter((job) => {
if (
- job.request.inference_category === "workflow" &&
+ job.request.inference_category === JobType.VideoStyleTransfer &&
job.maybe_result.entity_token
) {
return true;
@@ -67,21 +38,61 @@ export const useBackgroundLoadingMedia = () => {
return;
}
- const myMoviesTokens = myMovies.value.map((movie) => movie.token);
+ const userMoviesTokens = userMovies.value.map((movie) => movie.token);
const isEveryTokenIncludedInPolled = workflowJobsTokens.every((token) =>
- myMoviesTokens.includes(token),
+ userMoviesTokens.includes(token),
);
if (!isEveryTokenIncludedInPolled) {
//there are videos newly completed, poll
- shouldPollMyMovies.value = true;
+ PollUserMovies();
return;
}
- // at this point, make sure we stop polling because:
- // - myMovies first load is done
- // - completed jobs that contain new videos are all polled
- if (shouldPollMyMovies.value) {
- shouldPollMyMovies.value = false;
+ //else, no new movies, no need to poll;
+ });
+
+ useSignalEffect(() => {
+ //CASE 1: first load
+ // if audioItems undefined, poll for the first time
+ if (!userAudioItems.value) {
+ PollUserAudioItems();
+ return;
}
+
+ //CASE 2: pull after jobs completion
+ if (!completedJobs.value || completedJobs.value.length === 0) {
+ return; // nothing to do if there's no complete jobs
+ }
+
+ const audioJobsTokens = completedJobs.value
+ .filter((job) => {
+ if (
+ (job.request.inference_category === JobType.TextToSpeech ||
+ job.request.inference_category === JobType.VoiceConversion) &&
+ job.maybe_result.entity_token
+ ) {
+ return true;
+ }
+ return false;
+ })
+ .map((job) => job.maybe_result.entity_token);
+
+ if (audioJobsTokens.length === 0) {
+ //nothing to do if no complete jobs involves audio
+ return;
+ }
+
+ const userAudioItemsTokens = userAudioItems.value.map(
+ (audio) => audio.media_id,
+ );
+ const isEveryTokenIncludedInPolled = audioJobsTokens.every((token) =>
+ userAudioItemsTokens.includes(token),
+ );
+ if (!isEveryTokenIncludedInPolled) {
+ //there are videos newly completed, poll
+ PollUserAudioItems();
+ return;
+ }
+ //else, no new movies, no need to poll;
});
};
diff --git a/app/hooks/useBackgroundLoadingMedia/utilities.ts b/app/hooks/useBackgroundLoadingMedia/utilities.ts
index 3eccc1d97a..048afea2dc 100644
--- a/app/hooks/useBackgroundLoadingMedia/utilities.ts
+++ b/app/hooks/useBackgroundLoadingMedia/utilities.ts
@@ -1,30 +1,56 @@
import { MediaFileType } from "~/pages/PageEnigma/enums";
+import { ToastTypes } from "~/enums";
+
import {
GetMediaByUser,
GetMediaListResponse,
} from "~/api/media_files/GetMediaByUser";
-export function instanceOfMediaListResponse(
- object: GetMediaListResponse | { success: boolean; error_reason: string },
-): object is GetMediaListResponse {
- return "results" in object;
-}
-export function GetUserMovies(username: string) {
+import {
+ addToast,
+ authentication,
+ setUserAudioItems,
+ setUserMovies,
+} from "~/signals";
+const { userInfo } = authentication;
+
+export function PollUserMovies() {
+ if (!userInfo.value) {
+ //do nothing return if login info does not exist
+ return;
+ }
return GetMediaByUser(
- username,
+ userInfo.value.username,
{},
{
filter_media_type: MediaFileType.Video,
},
)
.then((res: GetMediaListResponse) => {
- return res;
+ setUserMovies(res.results);
})
.catch(() => {
- return {
- success: false,
- error_reason: "Unknown Error in Loading My Movies",
- };
+ addToast(ToastTypes.ERROR, "Unknown Error in Loading My Movies");
+ });
+}
+
+export function PollUserAudioItems() {
+ if (!userInfo.value) {
+ //do nothing return if login info does not exist
+ return;
+ }
+ return GetMediaByUser(
+ userInfo.value.username,
+ {},
+ {
+ filter_media_type: MediaFileType.Audio,
+ },
+ )
+ .then((res: GetMediaListResponse) => {
+ setUserAudioItems(res.results);
+ })
+ .catch(() => {
+ addToast(ToastTypes.ERROR, "Unknown Error in Loading My Audio Items");
});
}
diff --git a/app/hooks/useInferenceJobManager/index.tsx b/app/hooks/useInferenceJobManager/index.tsx
deleted file mode 100644
index 1e25310d00..0000000000
--- a/app/hooks/useInferenceJobManager/index.tsx
+++ /dev/null
@@ -1,2 +0,0 @@
-export { useInferenceJobManager } from "./useInferenceJobManager";
-export { useActiveJobs } from "./useActiveJobs";
diff --git a/app/hooks/useInferenceJobManager/useActiveJobs.ts b/app/hooks/useInferenceJobManager/useActiveJobs.ts
deleted file mode 100644
index 8372f2490f..0000000000
--- a/app/hooks/useInferenceJobManager/useActiveJobs.ts
+++ /dev/null
@@ -1,68 +0,0 @@
-import { useEffect } from "react";
-import { useSignalEffect, useSignals } from "@preact/signals-react/runtime";
-
-import { GetJobsResponse } from "./types";
-import { ToastTypes } from "~/enums";
-import { SEVEN_SECONDS } from "~/constants";
-
-import {
- activeJobs,
- addToast,
- setJobs,
- shouldPollActiveJobs,
- startPollingActiveJobs,
- stopPollingActiveJobs,
-} from "~/signals";
-
-import { GetRecentJobs } from "./utilities";
-
-export const useActiveJobs = () => {
- useSignals();
-
- useEffect(() => {
- const PollRecentJobs = () => {
- GetRecentJobs().then((res: GetJobsResponse) => {
- if (!res.success) {
- addToast(
- ToastTypes.ERROR,
- res.error_message || "Unknown Error in Getting Recent Jobs",
- );
- }
- if (res.jobs && res.jobs.length > 0) {
- setJobs(res.jobs);
- }
- // just no jobs, not an error, do nothing
- });
- };
-
- // Initial Poll
- PollRecentJobs();
-
- //trigger the pull every two seconds
- const intervalTimer = setInterval(() => {
- if (shouldPollActiveJobs.value) {
- //but only do it if necessary
- PollRecentJobs();
- }
- }, SEVEN_SECONDS);
- return () => {
- clearInterval(intervalTimer);
- };
- }, []);
-
- useSignalEffect(() => {
- // if active jobs is not initiated, do nothing
- if (!activeJobs.value) {
- return;
- }
- // if there are no active jobs, stop making polls
- if (activeJobs.value.length === 0) {
- stopPollingActiveJobs();
- return;
- }
- // if there are active jobs, and is not polling, start polling
- if (activeJobs.value.length > 0 && !shouldPollActiveJobs.value) {
- startPollingActiveJobs();
- }
- });
-};
diff --git a/app/hooks/useInferenceJobManager/useInferenceJobManager.tsx b/app/hooks/useInferenceJobManager/useInferenceJobManager.tsx
deleted file mode 100644
index 05eaf06c22..0000000000
--- a/app/hooks/useInferenceJobManager/useInferenceJobManager.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import { useCallback, useEffect } from "react";
-import { useSignals } from "@preact/signals-react/runtime";
-
-import { ErrorResponse, GetJobStatusResponse } from "~/pages/PageEnigma/models";
-import { JobState } from "~/pages/PageEnigma/enums";
-import { ToastTypes } from "~/enums";
-
-import { addToast } from "~/signals";
-import {
- inferenceJobs,
- updateInferenceJob,
-} from "~/pages/PageEnigma/signals/inferenceJobs";
-
-import { GetInferenceJobStatus } from "./utilities";
-
-function shouldKeepPolling(currStatus: string) {
- return currStatus === JobState.PENDING || currStatus === JobState.STARTED;
-}
-
-export const useInferenceJobManager = () => {
- useSignals();
-
- const pollInferenceJobs = useCallback(() => {
- if (inferenceJobs.value.length > 0) {
- inferenceJobs.value.forEach((job) => {
- if (shouldKeepPolling(job.job_status)) {
- GetInferenceJobStatus(job.job_id).then(
- (res: GetJobStatusResponse | ErrorResponse) => {
- if (res?.success) {
- console.log("inference", res);
- const response = res as GetJobStatusResponse;
- updateInferenceJob({
- ...job,
- job_status: response.state.status.status,
- result: response.state.maybe_result,
- });
- return;
- }
- addToast(ToastTypes.ERROR, (res as ErrorResponse).error_reason);
- },
- );
- }
- });
- }
- }, []);
-
- useEffect(() => {
- const intervalTimer = setInterval(() => {
- pollInferenceJobs();
- }, 2000);
- return () => {
- clearInterval(intervalTimer);
- };
- }, [pollInferenceJobs]);
-};
diff --git a/app/hooks/useInferenceJobManager/utilities.ts b/app/hooks/useInferenceJobManager/utilities.ts
deleted file mode 100644
index 95729821cc..0000000000
--- a/app/hooks/useInferenceJobManager/utilities.ts
+++ /dev/null
@@ -1,76 +0,0 @@
-import { ErrorResponse, GetJobStatusResponse } from "~/pages/PageEnigma/models";
-
-import { getActiveJobs, getJobStatus, getRecentJobs } from "~/api";
-import { authentication } from "~/signals";
-
-export function GetInferenceJobStatus(
- jobToken: string,
-): Promise
{
- const endpoint = getJobStatus(jobToken);
-
- return fetch(endpoint, {
- method: "GET",
- headers: {
- Accept: "application/json",
- session: authentication.sessionToken.value || "",
- },
- credentials: "include",
- })
- .then((res) => res.json())
- .then((res) => {
- const response: GetJobStatusResponse | ErrorResponse = res;
- return response;
- })
- .catch(() => {
- return {
- success: false,
- error_reason: "Unknown error",
- };
- });
-}
-
-export function GetRecentJobs() {
- const endpoint = getRecentJobs;
-
- return fetch(endpoint, {
- method: "GET",
- headers: {
- Accept: "application/json",
- session: authentication.sessionToken.value || "",
- },
- credentials: "include",
- })
- .then((res) => res.json())
- .then((res) => {
- return res;
- })
- .catch(() => {
- return {
- success: false,
- error_reason: "Unknown Error in Getting Recent Jobs",
- };
- });
-}
-
-export function GetActiveJobs() {
- const endpoint = getActiveJobs;
-
- return fetch(endpoint, {
- method: "GET",
- headers: {
- Accept: "application/json",
- session: authentication.sessionToken.value || "",
- },
- credentials: "include",
- })
- .then((res) => res.json())
- .then((res) => {
- return res;
- })
- .catch(() => {
- return {
- success: false,
- error_reason: "Unknown error",
- };
- });
-}
diff --git a/app/pages/PageEnigma/PageEnigma.tsx b/app/pages/PageEnigma/PageEnigma.tsx
index 5e5f61e27a..0f7bda0869 100644
--- a/app/pages/PageEnigma/PageEnigma.tsx
+++ b/app/pages/PageEnigma/PageEnigma.tsx
@@ -2,14 +2,13 @@ import { PageEditor } from "~/pages/PageEnigma/PageEditor";
import { TrackProvider } from "~/pages/PageEnigma/contexts/TrackContext/TrackProvider";
import { DragComponent } from "~/pages/PageEnigma/comps/DragComponent/DragComponent";
import { EngineProvider } from "./contexts/EngineContext";
-import { useInferenceJobManager, useActiveJobs } from "~/hooks";
+import { useActiveJobs } from "~/hooks";
import { useQueueHandler } from "./hooks/useQueueHandler";
import { ErrorDialog, LoadingBar } from "~/components";
import { GenerateModals } from "~/pages/PageEnigma/comps/GenerateModals/GenerateModals";
import { useBackgroundLoadingMedia } from "~/hooks/useBackgroundLoadingMedia";
export const PageEnigma = ({ sceneToken }: { sceneToken?: string }) => {
- useInferenceJobManager();
useActiveJobs();
useBackgroundLoadingMedia();
diff --git a/app/pages/PageEnigma/comps/GenerateModals/MyMovies.tsx b/app/pages/PageEnigma/comps/GenerateModals/MyMovies.tsx
index d61ee9839d..971dcecfbc 100644
--- a/app/pages/PageEnigma/comps/GenerateModals/MyMovies.tsx
+++ b/app/pages/PageEnigma/comps/GenerateModals/MyMovies.tsx
@@ -1,15 +1,12 @@
-import {
- // generateMovieId,
- myMovies,
- viewMyMovies,
-} from "~/pages/PageEnigma/signals";
+import { viewMyMovies } from "~/pages/PageEnigma/signals";
import { CompletedCard } from "~/pages/PageEnigma/comps/GenerateModals/CompletedCard";
import { InProgressCard } from "~/pages/PageEnigma/comps/GenerateModals/InProgressCard";
import { useSignals } from "@preact/signals-react/runtime";
import { faFilm } from "@fortawesome/pro-solid-svg-icons";
import { TransitionDialogue } from "~/components";
-import { activeWorkflowJobs } from "~/signals";
+import { activeWorkflowJobs, userMovies } from "~/signals";
+
interface Props {
setMovieId: (page: string) => void;
}
@@ -41,7 +38,7 @@ export function MyMovies({ setMovieId }: Props) {
Completed
- {myMovies.value?.map((movie) => (
+ {userMovies.value?.map((movie) => (
{
useSignals();
@@ -54,71 +35,9 @@ export const AudioTab = () => {
Array
>([]);
- const handleListAudioByUser = useCallback(() => {
- function getTitle(item: MediaInfo) {
- // console.log(item);
- if (item.maybe_title) return item.maybe_title;
- if (
- item.origin &&
- item.origin.maybe_model &&
- item.origin.maybe_model.title
- )
- return item.origin.maybe_model.title;
- return "Media Audio";
- }
- function getCategory(item: MediaInfo) {
- if (
- item.origin &&
- item.origin.product_category &&
- item.origin.product_category !== "unknown"
- )
- return item.origin.product_category;
- if (item.origin_category) return item.origin_category;
- return "unknown";
- }
- function checkIsNew(previousItems: AudioMediaItem[], token: string) {
- const foundItem = previousItems.find((item) => {
- return token === item.media_id && item.isNew !== true;
- });
- return foundItem === undefined;
- }
- function getLength(item: MediaInfo) {
- return item.maybe_duration_millis
- ? (item.maybe_duration_millis / 1000) * 60
- : undefined;
- }
- isRetreivingAudioItems.value = true;
- ListAudioByUser().then((res: MediaInfo[]) => {
- isRetreivingAudioItems.value = false;
- const previousItems = [...audioItemsFromServer.value];
- audioItemsFromServer.value = res.map((item) => {
- const morphedItem: AudioMediaItem = {
- version: 1,
- type: AssetType.AUDIO,
- category: getCategory(item),
- media_id: item.token,
- object_uuid: item.token,
- name: getTitle(item),
- description: item.maybe_text_transcript || "",
- publicBucketPath: item.public_bucket_path,
- length: getLength(item),
- thumbnail: "/resources/placeholders/audio_placeholder.png",
- isMine: true,
- isNew:
- previousItems.length > 0
- ? checkIsNew(previousItems, item.token)
- : false,
- // isBookmarked?: boolean;
- };
- return morphedItem;
- });
- });
- }, []);
-
useEffect(() => {
if (!state.firstLoad) {
//fetch all the data on first load once, after securing auth info
- handleListAudioByUser();
ListTtsModels().then((res) => {
if (res) setTtsModels(res);
});
@@ -128,79 +47,7 @@ export const AudioTab = () => {
setState((curr) => ({ ...curr, firstLoad: true }));
// completed the first load
}
- }, [state, handleListAudioByUser]);
-
- useEffect(() => {
- //this listens to ttsState and push its new inference jobs
- setState((curr) => {
- const { ttsState: currTtsState } = curr;
- if (currTtsState.hasEnqueued < currTtsState.inferenceTokens.length) {
- addInferenceJob({
- version: 1,
- job_id:
- currTtsState.inferenceTokens[
- currTtsState.inferenceTokens.length - 1
- ],
- job_type: InferenceJobType.TextToSpeech,
- job_status: JobState.PENDING,
- });
- return {
- ...curr,
- ttsState: {
- ...currTtsState,
- hasEnqueued: currTtsState.hasEnqueued + 1,
- },
- };
- }
- return curr; //case of no new jobs, do nothing
- });
- }, [state.ttsState]);
-
- useEffect(() => {
- //this listens to v2vState and push its new inference jobs
- setState((curr) => {
- const { v2vState: currV2VState } = curr;
- if (currV2VState.hasEnqueued < currV2VState.inferenceTokens.length) {
- addInferenceJob({
- version: 1,
- job_id:
- currV2VState.inferenceTokens[
- currV2VState.inferenceTokens.length - 1
- ],
- job_type: InferenceJobType.VoiceConversion,
- job_status: JobState.PENDING,
- });
- return {
- ...curr,
- v2vState: {
- ...currV2VState,
- hasEnqueued: currV2VState.hasEnqueued + 1,
- },
- };
- }
- return curr; //case of no new jobs, do nothing
- });
- }, [state.v2vState]);
-
- useSignalEffect(() => {
- // when inference changes, check if there's a new audio to refresh for
- let hasNewCompletedJob = false;
- inferenceJobs.value.forEach((job) => {
- if (
- job.job_status === JobState.COMPLETE_SUCCESS &&
- (job.job_type === InferenceJobType.TextToSpeech ||
- job.job_type === InferenceJobType.VoiceConversion)
- ) {
- const foundItemOfJob = audioItemsFromServer.value.find((item) => {
- return item.media_id === job.result.entity_token;
- });
- hasNewCompletedJob = foundItemOfJob === undefined;
- }
- });
- if (hasNewCompletedJob) {
- handleListAudioByUser();
- }
- });
+ }, [state]);
const changePage = useCallback((newPage: AudioTabPages) => {
setState((curr) => ({
@@ -212,9 +59,9 @@ export const AudioTab = () => {
switch (state.page) {
case AudioTabPages.LIBRARY: {
return (
-
);
}
diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/inferenceElement.tsx b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/inferenceElement.tsx
index 87ee7bd979..b4aa3599d7 100644
--- a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/inferenceElement.tsx
+++ b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/inferenceElement.tsx
@@ -6,33 +6,33 @@ import {
} from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import { InferenceJob } from "~/pages/PageEnigma/models";
+import { JobStatus } from "~/enums";
+import { Job } from "~/models";
import { ButtonIcon, H5 } from "~/components";
-import { JobState } from "~/pages/PageEnigma/enums";
-export const InferenceElement = ({ job }: { job: InferenceJob }) => {
+export const InferenceElement = ({ job }: { job: Job }) => {
const className = twMerge(
"rounded-md w-full flex justify-between items-center p-2 gap-2",
- job.job_status === JobState.PENDING ? "bg-inference-pending" : "",
- job.job_status === JobState.STARTED ? "bg-inference-generating" : "",
- job.job_status === JobState.DEAD ? "bg-inference-error" : "",
+ job.status.status === JobStatus.PENDING ? "bg-inference-pending" : "",
+ job.status.status === JobStatus.STARTED ? "bg-inference-generating" : "",
+ job.status.status === JobStatus.DEAD ? "bg-inference-error" : "",
);
const statusText = "".concat(
- job.job_status === JobState.PENDING ? "Pending..." : "",
- job.job_status === JobState.STARTED ? "Generating..." : "",
- job.job_status === JobState.DEAD ? "Error" : "",
+ job.status.status === JobStatus.PENDING ? "Pending..." : "",
+ job.status.status === JobStatus.STARTED ? "Generating..." : "",
+ job.status.status === JobStatus.DEAD ? "Error" : "",
);
return (
- {job.job_status === JobState.DEAD && (
+ {job.status.status === JobStatus.DEAD && (
)}
- {job.job_status !== JobState.DEAD && (
+ {job.status.status !== JobStatus.DEAD && (
)}
{statusText}
- {job.job_status === JobState.DEAD && (
+ {job.status.status === JobStatus.DEAD && (
{
diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageLibrary.tsx b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageAudioLibrary.tsx
similarity index 81%
rename from app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageLibrary.tsx
rename to app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageAudioLibrary.tsx
index 433939cfba..dfa181f11e 100644
--- a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageLibrary.tsx
+++ b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageAudioLibrary.tsx
@@ -3,8 +3,6 @@ import { faCirclePlus } from "@fortawesome/pro-solid-svg-icons";
import { twMerge } from "tailwind-merge";
import { useSignals, useComputed } from "@preact/signals-react/runtime";
import { audioFilter, audioItems } from "~/pages/PageEnigma/signals";
-import { audioItemsFromServer } from "~/pages/PageEnigma/signals/mediaFromServer";
-import { inferenceJobs } from "~/pages/PageEnigma/signals/inferenceJobs";
import { Button, Pagination, UploadAudioButtonDialogue } from "~/components";
@@ -12,13 +10,11 @@ import { AudioItemElements } from "./audioItemElements";
import { TabTitle } from "~/pages/PageEnigma/comps/SidePanelTabs/comps/TabTitle";
import { InferenceElement } from "./inferenceElement";
import { AssetFilterOption } from "~/enums";
-import {
- AudioTabPages,
- InferenceJobType,
- JobState,
-} from "~/pages/PageEnigma/enums";
+import { AudioTabPages } from "~/pages/PageEnigma/enums";
-export const PageLibrary = ({
+import { activeAudioJobs, userAudioItems } from "~/signals";
+
+export const PageAudioLibrary = ({
changePage,
reloadLibrary,
}: {
@@ -26,9 +22,10 @@ export const PageLibrary = ({
reloadLibrary: () => void;
}) => {
useSignals();
+ const loadUserAudioItems = userAudioItems.value ? userAudioItems.value : [];
const allAudioItems = useComputed(() => [
...audioItems.value,
- ...audioItemsFromServer.value,
+ ...loadUserAudioItems,
]);
const displayedItems = allAudioItems.value.filter((item) => {
if (audioFilter.value === AssetFilterOption.ALL) {
@@ -39,17 +36,7 @@ export const PageLibrary = ({
}
return item.isBookmarked;
});
- const audioInferenceJobs = useComputed(() =>
- inferenceJobs.value.filter((job) => {
- if (
- job.job_status !== JobState.COMPLETE_SUCCESS &&
- (job.job_type === InferenceJobType.TextToSpeech ||
- job.job_type === InferenceJobType.VoiceConversion)
- ) {
- return job;
- }
- }),
- );
+
const pageSize = 20;
const totalPages = Math.ceil(allAudioItems.value.length / pageSize);
const [currentPage, setCurrentPage] = useState(0);
@@ -109,10 +96,10 @@ export const PageLibrary = ({
- {audioInferenceJobs.value.length > 0 && (
+ {activeAudioJobs.value && activeAudioJobs.value.length > 0 && (
- {audioInferenceJobs.value.map((job) => {
- return ;
+ {activeAudioJobs.value.map((job) => {
+ return ;
})}
)}
diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageTTS.tsx b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageTTS.tsx
index 5c041ac421..fbf586da13 100644
--- a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageTTS.tsx
+++ b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageTTS.tsx
@@ -11,6 +11,7 @@ import { GenerateTtsAudioResponse } from "~/pages/PageEnigma/models/tts";
import { GenerateTtsAudio } from "./utilities";
import { TtsState } from "../../../../models/voice";
import { AudioTabPages } from "~/pages/PageEnigma/enums";
+import { startPollingActiveJobs } from "~/signals";
export const PageTTS = ({
changePage,
@@ -33,21 +34,14 @@ export const PageTTS = ({
GenerateTtsAudio(request).then((res: GenerateTtsAudioResponse) => {
if (res && res.inference_job_token) {
- setTtsState({
- ...ttsState,
- inferenceTokens: [
- ...ttsState.inferenceTokens,
- res.inference_job_token,
- ],
- });
-
+ startPollingActiveJobs();
changePage(AudioTabPages.LIBRARY);
}
});
} else {
console.log("no voice model selected");
}
- }, [ttsState, changePage, setTtsState]);
+ }, [ttsState, changePage]);
const handleTextInput = (e: React.ChangeEvent
) => {
setTtsState({
diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageVoiceToVoice.tsx b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageVoiceToVoice.tsx
index 49e049b6ad..9e6937b57f 100644
--- a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageVoiceToVoice.tsx
+++ b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/pageVoiceToVoice.tsx
@@ -13,6 +13,7 @@ import { GenerateVoiceConversion } from "./utilities";
import { H4, H6, Button, Label, UploadAudioComponent } from "~/components";
import { AudioTabPages } from "~/pages/PageEnigma/enums";
+import { startPollingActiveJobs } from "~/signals";
export const PageVoicetoVoice = ({
changePage,
@@ -35,19 +36,14 @@ export const PageVoicetoVoice = ({
GenerateVoiceConversion(request).then(
(res: EnqueueVoiceConversionResponse) => {
if (res && res.inference_job_token) {
- setV2VState({
- ...v2vState,
- inferenceTokens: [
- ...v2vState.inferenceTokens,
- res.inference_job_token,
- ],
- });
+ startPollingActiveJobs();
changePage(AudioTabPages.LIBRARY);
}
},
);
}
- }, [v2vState, changePage, setV2VState]);
+ }, [v2vState, changePage]);
+
return (
diff --git a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/values.ts b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/values.ts
index 6bfb4b800e..fe941a64b9 100644
--- a/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/values.ts
+++ b/app/pages/PageEnigma/comps/SidePanelTabs/itemTabs/AudioTab/values.ts
@@ -3,14 +3,10 @@ import { TtsState, V2VState } from "../../../../models/voice";
export const initialTtsState: TtsState = {
voice: undefined,
text: "",
- hasEnqueued: 0,
- inferenceTokens: [],
};
export const initialV2VState: V2VState = {
voice: undefined,
file: undefined,
inputFileToken: undefined,
- hasEnqueued: 0,
- inferenceTokens: [],
};
diff --git a/app/pages/PageEnigma/enums/InferenceJobType.ts b/app/pages/PageEnigma/enums/InferenceJobType.ts
deleted file mode 100644
index 08415541ef..0000000000
--- a/app/pages/PageEnigma/enums/InferenceJobType.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-export enum InferenceJobType {
- FaceAnimation,
- TextToSpeech,
- VoiceConversion,
- VoiceDesignerCreateVoice,
- VoiceDesignerTts,
- ImageGeneration,
- VideoMotionCapture,
- ConvertFbxtoGltf,
- EngineComposition,
- VideoWorkflow,
- VideoStyleTransfer,
-}
diff --git a/app/pages/PageEnigma/enums/index.ts b/app/pages/PageEnigma/enums/index.ts
index 6b6c2f1b1e..6b6c3f738d 100644
--- a/app/pages/PageEnigma/enums/index.ts
+++ b/app/pages/PageEnigma/enums/index.ts
@@ -5,7 +5,6 @@ export * from "./ClipType";
export * from "./EditorState";
export * from "./FetchStatus";
export * from "./GenerateTtsAudioErrorType";
-export * from "./InferenceJobType";
export * from "./JobState";
export * from "./MediaFileClass";
export * from "./MediaFileType";
diff --git a/app/pages/PageEnigma/models/voice.ts b/app/pages/PageEnigma/models/voice.ts
index 247695fced..029244b643 100644
--- a/app/pages/PageEnigma/models/voice.ts
+++ b/app/pages/PageEnigma/models/voice.ts
@@ -12,14 +12,10 @@ export type AudioPanelState = {
export type TtsState = {
voice: TtsModelListItem | undefined;
text: string;
- hasEnqueued: number;
- inferenceTokens: string[];
};
export type V2VState = {
voice: VoiceConversionModelListItem | undefined;
file: File | undefined;
inputFileToken: string | undefined;
- hasEnqueued: number;
- inferenceTokens: string[];
};
diff --git a/app/pages/PageEnigma/signals/inferenceJobs.ts b/app/pages/PageEnigma/signals/inferenceJobs.ts
deleted file mode 100644
index a6e2ae9b07..0000000000
--- a/app/pages/PageEnigma/signals/inferenceJobs.ts
+++ /dev/null
@@ -1,42 +0,0 @@
-import { signal } from "@preact/signals-core";
-
-import { InferenceJob } from "../models";
-
-export const inferenceJobs = signal
([]);
-
-export function addInferenceJob(newJob: InferenceJob) {
- const existingInferenceJobs = inferenceJobs.value;
- const jobExist = existingInferenceJobs.find(
- (job) => job.job_id == newJob.job_id,
- );
- if (!jobExist) {
- inferenceJobs.value = [...existingInferenceJobs, newJob];
- }
- // else do nothing
-}
-
-export function updateInferenceJob(updatableJob: InferenceJob) {
- const existingInferenceJobs = inferenceJobs.value;
- existingInferenceJobs.forEach((job) => {
- if (job.job_id === updatableJob.job_id) {
- job.job_status = updatableJob.job_status;
- }
- if (updatableJob.result) {
- job.result = updatableJob.result;
- }
- });
- inferenceJobs.value = [...existingInferenceJobs];
-}
-
-export function deleteInferenceJob(deletableJob: InferenceJob) {
- // console.log("delete");
- const newList: InferenceJob[] = [];
- inferenceJobs.value.forEach((job) => {
- if (job.job_id !== deletableJob.job_id) {
- newList.push(job);
- }
- // or else do nothing
- });
- // console.log(newList);
- inferenceJobs.value = [...newList];
-}
diff --git a/app/pages/PageEnigma/signals/myMovies.ts b/app/pages/PageEnigma/signals/myMovies.ts
index 61e8a67091..eece573172 100644
--- a/app/pages/PageEnigma/signals/myMovies.ts
+++ b/app/pages/PageEnigma/signals/myMovies.ts
@@ -1,14 +1,4 @@
import { signal } from "@preact/signals-core";
-import { MediaInfo } from "~/pages/PageEnigma/models/movies";
-
export const viewMyMovies = signal(false);
export const generateMovieId = signal("");
-
-export const myMovies = signal(undefined);
-
-export const setMyMovies = (newSet: MediaInfo[]) => {
- myMovies.value = newSet;
-};
-
-export const shouldPollMyMovies = signal(true);
diff --git a/app/signals/activeJobs.ts b/app/signals/activeJobs.ts
index 8797752ee7..13609dc1d4 100644
--- a/app/signals/activeJobs.ts
+++ b/app/signals/activeJobs.ts
@@ -1,10 +1,11 @@
import { signal, computed } from "@preact/signals-core";
-import { JobStatus } from "~/enums";
+import { JobStatus, JobType } from "~/enums";
+import { PollRecentJobs } from "~/hooks/useActiveJobs/utilities";
import { Job } from "~/models";
import { isJobStatusTerminal } from "~/utilities";
-export const recentJobs = signal([]);
+export const recentJobs = signal(undefined);
export const setJobs = (newJobList: Job[]) => {
recentJobs.value = [...newJobList];
};
@@ -24,9 +25,22 @@ export const activeWorkflowJobs = computed(() => {
return undefined;
}
return activeJobs.value.filter((job) => {
- return job.request.inference_category === "workflow";
+ return job.request.inference_category === JobType.VideoStyleTransfer;
});
});
+
+export const activeAudioJobs = computed(() => {
+ if (!activeJobs.value) {
+ return undefined;
+ }
+ return activeJobs.value.filter((job) => {
+ return (
+ job.request.inference_category === JobType.TextToSpeech ||
+ job.request.inference_category === JobType.VoiceConversion
+ );
+ });
+});
+
export const completedJobs = computed(() => {
if (!recentJobs.value) {
return undefined;
@@ -36,13 +50,13 @@ export const completedJobs = computed(() => {
});
});
-export const shouldPollActiveJobs = signal(true);
+export const shouldPollActiveJobs = signal(false);
export const startPollingActiveJobs = () => {
- console.info("start polling Active Jobs");
+ PollRecentJobs(); //poll once regardless of polling intervals
shouldPollActiveJobs.value = true;
};
+
export const stopPollingActiveJobs = () => {
- console.info("stop polling Active Jobs");
shouldPollActiveJobs.value = false;
};
diff --git a/app/signals/backgroundLoadedMedia.ts b/app/signals/backgroundLoadedMedia.ts
new file mode 100644
index 0000000000..d24acf8a7b
--- /dev/null
+++ b/app/signals/backgroundLoadedMedia.ts
@@ -0,0 +1,92 @@
+import { signal } from "@preact/signals-core";
+import { AssetType } from "~/enums";
+import { MediaInfo } from "~/pages/PageEnigma/models/movies";
+import { AudioMediaItem } from "~/pages/PageEnigma/models";
+
+// Signal for background loading User's Movies
+export const userMovies = signal(undefined);
+
+export const setUserMovies = (newSet: MediaInfo[]) => {
+ userMovies.value = newSet;
+};
+
+//Signal for background loading User's Audio Items.
+export const userAudioItems = signal(undefined);
+export const setUserAudioItems = (newSet: MediaInfo[]) => {
+ const previousItems = userAudioItems.value ? [...userAudioItems.value] : [];
+ const morphedNewSet = newSet.map((item) => {
+ const morphedItem: AudioMediaItem = {
+ version: 1,
+ type: AssetType.AUDIO,
+ category: getCategory(item),
+ media_id: item.token,
+ object_uuid: item.token,
+ name: getTitle(item),
+ description: item.maybe_text_transcript || "",
+ publicBucketPath: item.public_bucket_path,
+ length: getLength(item),
+ thumbnail: "/resources/placeholders/audio_placeholder.png",
+ isMine: true,
+ isNew:
+ previousItems.length > 0
+ ? checkIsNew(previousItems, item.token)
+ : false,
+ // isBookmarked?: boolean;
+ };
+ return morphedItem;
+ });
+ userAudioItems.value = morphedNewSet;
+};
+
+export const cancelNewFromAudioItem = (mediaId: string) => {
+ if (!userAudioItems.value || userAudioItems.value.length === 0) {
+ return;
+ }
+ const newList = userAudioItems.value.map((item) => {
+ if (item.media_id === mediaId) item.isNew = false;
+ return item;
+ });
+ userAudioItems.value = [...newList];
+};
+
+export const updateAudioItemLength = (mediaId: string, duration: number) => {
+ if (!userAudioItems.value || userAudioItems.value.length === 0) {
+ return;
+ }
+ const newList = userAudioItems.value.map((item) => {
+ if (item.media_id === mediaId) item.length = duration;
+ return item;
+ });
+ userAudioItems.value = [...newList];
+};
+
+// Helper functions to massage Media Info to AudioMediaItem
+// that's usable as a signal.
+function getTitle(item: MediaInfo) {
+ // console.log(item);
+ if (item.maybe_title) return item.maybe_title;
+ if (item.origin && item.origin.maybe_model && item.origin.maybe_model.title)
+ return item.origin.maybe_model.title;
+ return "Media Audio";
+}
+function getCategory(item: MediaInfo) {
+ if (
+ item.origin &&
+ item.origin.product_category &&
+ item.origin.product_category !== "unknown"
+ )
+ return item.origin.product_category;
+ if (item.origin_category) return item.origin_category;
+ return "unknown";
+}
+function checkIsNew(previousItems: AudioMediaItem[], token: string) {
+ const foundItem = previousItems.find((item) => {
+ return token === item.media_id && item.isNew !== true;
+ });
+ return foundItem === undefined;
+}
+function getLength(item: MediaInfo) {
+ return item.maybe_duration_millis
+ ? (item.maybe_duration_millis / 1000) * 60
+ : undefined;
+}
diff --git a/app/signals/index.ts b/app/signals/index.ts
index 3765e96bfc..7d0ef283ed 100644
--- a/app/signals/index.ts
+++ b/app/signals/index.ts
@@ -1,5 +1,6 @@
export * from "./authentication";
export * from "./activeJobs";
+export * from "./backgroundLoadedMedia";
export * from "./global";
export * from "./loadingBar";
export * from "./scene"; // THIS IS SHOULE BE PAGE LEVEL