mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-13 13:22:57 +00:00
Work on VITS, VC, generic inference
This commit is contained in:
1 parent
66e009480f
commit
2e5a3d7964
15 files changed
+441
-43
No files matched your search
@@ -422,12 +422,24 @@ class ApiConfig {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/voice_clone_requests/check`;
|
||||
}
|
||||
|
||||
enqueueRetrievalJob(): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/retrieval/enqueue`;
|
||||
// =============== Generic Model Downloads ===============
|
||||
|
||||
enqueueRemoteDownloadJob(): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/v1/remote_downloads/enqueue`;
|
||||
}
|
||||
|
||||
getRetrievalJobStatus(jobToken: string): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/retrieval/job_status/${jobToken}`;
|
||||
getRemoteDownloadJobStatus(jobToken: string): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/v1/remote_downloads/job_status/${jobToken}`;
|
||||
}
|
||||
|
||||
// =============== Generic Model Inference ===============
|
||||
|
||||
getModelInferenceJobStatus(jobToken: string): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/v1/model_inference/job_status/${jobToken}`;
|
||||
}
|
||||
|
||||
getPendingModelInferenceJobCount(): string {
|
||||
return `${this.getScheme()}://${this.getNewApiHost()}/v1/model_inference/queue_length`;
|
||||
}
|
||||
|
||||
// =============== User Ratings ===============
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
import { ApiConfig } from "../ApiConfig";
|
||||
|
||||
export interface GetModelInferenceJobStatusSuccessResponse {
|
||||
success: boolean,
|
||||
state: ModelInferenceJobStatus,
|
||||
}
|
||||
|
||||
export interface ModelInferenceJobStatus {
|
||||
// Job primary key
|
||||
job_token: string,
|
||||
|
||||
request: RequestDetails,
|
||||
status: StatusDetails,
|
||||
maybe_result?: ResultDetails,
|
||||
|
||||
created_at: Date,
|
||||
updated_at: Date,
|
||||
}
|
||||
|
||||
export interface RequestDetails {
|
||||
inference_category: string,
|
||||
|
||||
maybe_model_type?: string,
|
||||
maybe_model_token?: string,
|
||||
maybe_model_title?: string,
|
||||
|
||||
maybe_raw_inference_text?: string,
|
||||
}
|
||||
|
||||
export interface StatusDetails {
|
||||
status: string,
|
||||
maybe_extra_status_description?: string,
|
||||
attempt_count: number,
|
||||
}
|
||||
|
||||
export interface ResultDetails {
|
||||
entity_type: string,
|
||||
entity_token: string,
|
||||
|
||||
maybe_public_bucket_media_path?: string,
|
||||
}
|
||||
|
||||
export interface GetModelInferenceJobStatusErrorResponse {
|
||||
success: boolean,
|
||||
}
|
||||
|
||||
export type GetModelInferenceJobStatusResponse = GetModelInferenceJobStatusSuccessResponse | GetModelInferenceJobStatusErrorResponse;
|
||||
|
||||
export function GetModelInferenceJobStatusIsOk(response: GetModelInferenceJobStatusResponse): response is GetModelInferenceJobStatusSuccessResponse {
|
||||
return response?.success === true;
|
||||
}
|
||||
|
||||
export function GetModelInferenceJobStatusIsError(response: GetModelInferenceJobStatusResponse): response is GetModelInferenceJobStatusErrorResponse {
|
||||
return response?.success === false;
|
||||
}
|
||||
|
||||
export async function GetModelInferenceJobStatus(jobToken: string) : Promise<GetModelInferenceJobStatusResponse>
|
||||
{
|
||||
const endpoint = new ApiConfig().getModelInferenceJobStatus(jobToken);
|
||||
|
||||
return fetch(endpoint, {
|
||||
method: 'GET',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
})
|
||||
.then(res => res.json())
|
||||
.then(res => {
|
||||
if (res && 'success' in res) {
|
||||
return res;
|
||||
} else {
|
||||
return { success : false };
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
return { success : false };
|
||||
});
|
||||
}
|
||||
+8
-8
@@ -1,34 +1,34 @@
|
||||
import { ApiConfig } from "../ApiConfig";
|
||||
|
||||
export interface EnqueueRetrievalRequest {
|
||||
export interface EnqueueRemoteDownloadRequest {
|
||||
idempotency_token: string,
|
||||
title: string,
|
||||
download_url: string,
|
||||
generic_download_type: string,
|
||||
}
|
||||
|
||||
export interface EnqueueRetrievalSuccessResponse {
|
||||
export interface EnqueueRemoteDownloadSuccessResponse {
|
||||
success: boolean,
|
||||
job_token: string,
|
||||
}
|
||||
|
||||
export interface EnqueueRetrievalErrorResponse {
|
||||
export interface EnqueueRemoteDownloadErrorResponse {
|
||||
success: boolean,
|
||||
}
|
||||
|
||||
type EnqueueRetrievalResponse = EnqueueRetrievalSuccessResponse | EnqueueRetrievalErrorResponse;
|
||||
type EnqueueRemoteDownloadResponse = EnqueueRemoteDownloadSuccessResponse | EnqueueRemoteDownloadErrorResponse;
|
||||
|
||||
export function EnqueueRetrievalIsOk(response: EnqueueRetrievalResponse): response is EnqueueRetrievalSuccessResponse {
|
||||
export function EnqueueRemoteDownloadIsOk(response: EnqueueRemoteDownloadResponse): response is EnqueueRemoteDownloadSuccessResponse {
|
||||
return response?.success === true;
|
||||
}
|
||||
|
||||
export function EnqueueRetrievalIsError(response: EnqueueRetrievalResponse): response is EnqueueRetrievalErrorResponse {
|
||||
export function EnqueueRemoteDownloadIsError(response: EnqueueRemoteDownloadResponse): response is EnqueueRemoteDownloadErrorResponse {
|
||||
return response?.success === false;
|
||||
}
|
||||
|
||||
export async function EnqueueRetrieval(request: EnqueueRetrievalRequest) : Promise<EnqueueRetrievalResponse>
|
||||
export async function EnqueueRemoteDownload(request: EnqueueRemoteDownloadRequest) : Promise<EnqueueRemoteDownloadResponse>
|
||||
{
|
||||
const endpoint = new ApiConfig().enqueueRetrievalJob();
|
||||
const endpoint = new ApiConfig().enqueueRemoteDownloadJob();
|
||||
|
||||
return fetch(endpoint, {
|
||||
method: 'POST',
|
||||
+9
-9
@@ -1,11 +1,11 @@
|
||||
import { ApiConfig } from "../ApiConfig";
|
||||
|
||||
export interface GetRetrievalJobStatusSuccessResponse {
|
||||
export interface GetRemoteDownloadJobStatusSuccessResponse {
|
||||
success: boolean,
|
||||
state: RetrievalJobStatus,
|
||||
state: RemoteDownloadJobStatus,
|
||||
}
|
||||
|
||||
export interface RetrievalJobStatus {
|
||||
export interface RemoteDownloadJobStatus {
|
||||
// Job primary key
|
||||
job_token: string,
|
||||
|
||||
@@ -24,23 +24,23 @@ export interface RetrievalJobStatus {
|
||||
updated_at: Date,
|
||||
}
|
||||
|
||||
export interface GetRetrievalJobStatusErrorResponse {
|
||||
export interface GetRemoteDownloadJobStatusErrorResponse {
|
||||
success: boolean,
|
||||
}
|
||||
|
||||
type GetRetrievalJobStatusResponse = GetRetrievalJobStatusSuccessResponse | GetRetrievalJobStatusErrorResponse;
|
||||
type GetRemoteDownloadJobStatusResponse = GetRemoteDownloadJobStatusSuccessResponse | GetRemoteDownloadJobStatusErrorResponse;
|
||||
|
||||
export function GetRetrievalJobStatusIsOk(response: GetRetrievalJobStatusResponse): response is GetRetrievalJobStatusSuccessResponse {
|
||||
export function GetRemoteDownloadJobStatusIsOk(response: GetRemoteDownloadJobStatusResponse): response is GetRemoteDownloadJobStatusSuccessResponse {
|
||||
return response?.success === true;
|
||||
}
|
||||
|
||||
export function GetRetrievalJobStatusIsError(response: GetRetrievalJobStatusResponse): response is GetRetrievalJobStatusErrorResponse {
|
||||
export function GetRemoteDownloadJobStatusIsError(response: GetRemoteDownloadJobStatusResponse): response is GetRemoteDownloadJobStatusErrorResponse {
|
||||
return response?.success === false;
|
||||
}
|
||||
|
||||
export async function GetRetrievalJobStatus(jobToken: string) : Promise<GetRetrievalJobStatusResponse>
|
||||
export async function GetRemoteDownloadJobStatus(jobToken: string) : Promise<GetRemoteDownloadJobStatusResponse>
|
||||
{
|
||||
const endpoint = new ApiConfig().getRetrievalJobStatus(jobToken);
|
||||
const endpoint = new ApiConfig().getRemoteDownloadJobStatus(jobToken);
|
||||
|
||||
return fetch(endpoint, {
|
||||
method: 'GET',
|
||||
@@ -10,7 +10,10 @@ export interface GenerateTtsAudioRequest {
|
||||
}
|
||||
|
||||
export interface GenerateTtsAudioSuccess {
|
||||
success: boolean,
|
||||
inference_job_token: string,
|
||||
// Which queue to poll
|
||||
inference_job_token_type?: string,
|
||||
}
|
||||
|
||||
export interface GenerateTtsAudioError {
|
||||
@@ -63,6 +66,7 @@ export async function GenerateTtsAudio(request: GenerateTtsAudioRequest) : Promi
|
||||
} else {
|
||||
return <GenerateTtsAudioSuccess> {
|
||||
inference_job_token: fullResponse.body.inference_job_token,
|
||||
inference_job_token_type: fullResponse.body.inference_job_token_type,
|
||||
};
|
||||
}
|
||||
})
|
||||
@@ -95,6 +99,7 @@ function maybeMapError(statuslike: StatusLike) : GenerateTtsAudioErrorType | und
|
||||
interface EndpointSuccessResponse {
|
||||
success: boolean,
|
||||
inference_job_token: string,
|
||||
inference_job_token_type?: string,
|
||||
}
|
||||
|
||||
interface EndpointErrorResponse {
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { ModelInferenceJobStatus } from "../api/model_inference/GetModelInferenceJobStatus";
|
||||
import { JobState, jobStateFromString } from "./JobStates";
|
||||
|
||||
// NB: Many of these fields are optional despite the response payload containing them
|
||||
// This is because we create temporary placeholder objects with just the token.
|
||||
export class InferenceJob {
|
||||
// PK
|
||||
jobToken: string;
|
||||
|
||||
// Status
|
||||
jobState: JobState;
|
||||
maybeExtraStatusDescription: string | null;
|
||||
attemptCount: number;
|
||||
|
||||
// Request
|
||||
maybeModelType?: string;
|
||||
maybeModelToken?: string;
|
||||
maybeModelTitle?: string;
|
||||
maybeRawInferenceText?: string;
|
||||
|
||||
// Result
|
||||
maybeResultType: string | undefined | null;
|
||||
maybeResultToken: string | undefined | null;
|
||||
maybeResultPublicBucketMediaPath: string | undefined | null;
|
||||
|
||||
constructor(
|
||||
// PK
|
||||
jobToken: string,
|
||||
// Status
|
||||
status: string = 'unknown',
|
||||
maybeExtraStatusDescription: string | null = null,
|
||||
attemptCount: number = 0,
|
||||
// Request
|
||||
maybeModelType: string | undefined = undefined,
|
||||
maybeModelToken: string | undefined = undefined,
|
||||
maybeModelTitle: string | undefined = undefined,
|
||||
maybeRawInferenceText: string | undefined = undefined,
|
||||
// Result
|
||||
maybeResultEntityType: string | undefined | null = null,
|
||||
maybeResultEntityToken: string | undefined | null = null,
|
||||
maybeResultPublicBucketMediaPath: string | undefined | null = null,
|
||||
) {
|
||||
this.jobToken = jobToken;
|
||||
this.jobState = jobStateFromString(status);
|
||||
this.maybeExtraStatusDescription = maybeExtraStatusDescription;
|
||||
this.attemptCount = attemptCount;
|
||||
|
||||
if (!!maybeModelType) {
|
||||
this.maybeModelTitle = maybeModelType;
|
||||
}
|
||||
if (!!maybeModelToken) {
|
||||
this.maybeModelToken = maybeModelToken;
|
||||
}
|
||||
if (!!maybeModelTitle) {
|
||||
this.maybeModelTitle = maybeModelTitle;
|
||||
}
|
||||
|
||||
this.maybeRawInferenceText = maybeRawInferenceText;
|
||||
|
||||
if (!!maybeResultEntityType) {
|
||||
this.maybeResultType = maybeResultEntityType;
|
||||
}
|
||||
if (!!maybeResultEntityToken) {
|
||||
this.maybeResultToken = maybeResultEntityToken;
|
||||
}
|
||||
|
||||
this.maybeResultPublicBucketMediaPath = maybeResultPublicBucketMediaPath;
|
||||
}
|
||||
|
||||
static fromResponse(response: ModelInferenceJobStatus) : InferenceJob {
|
||||
return new InferenceJob(
|
||||
response.job_token,
|
||||
response.status.status,
|
||||
response.status.maybe_extra_status_description || null,
|
||||
response.status.attempt_count || 0,
|
||||
response.request.maybe_model_type,
|
||||
response.request.maybe_model_token,
|
||||
response.request.maybe_model_title,
|
||||
response.request.maybe_raw_inference_text,
|
||||
response.maybe_result?.entity_type,
|
||||
response.maybe_result?.entity_token,
|
||||
response.maybe_result?.maybe_public_bucket_media_path,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RetrievalJobStatus } from "../api/retrieval/GetRetrievalJobStatus";
|
||||
import { RemoteDownloadJobStatus } from "../api/remote_downloads/GetRemoteDownloadJobStatus";
|
||||
import { JobState, jobStateFromString } from "./JobStates";
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export class VocoderUploadJob {
|
||||
}
|
||||
}
|
||||
|
||||
static fromResponse(response: RetrievalJobStatus) : VocoderUploadJob {
|
||||
static fromResponse(response: RemoteDownloadJobStatus) : VocoderUploadJob {
|
||||
return new VocoderUploadJob(
|
||||
response.job_token,
|
||||
response.status,
|
||||
|
||||
@@ -35,15 +35,17 @@ import i18n from "i18next";
|
||||
import { initReactI18next } from "react-i18next";
|
||||
import { VocoderUploadJob } from "@storyteller/components/src/jobs/VocoderUploadJobs";
|
||||
import {
|
||||
GetRetrievalJobStatus,
|
||||
GetRetrievalJobStatusIsOk,
|
||||
} from "@storyteller/components/src/api/retrieval/GetRetrievalJobStatus";
|
||||
GetRemoteDownloadJobStatus,
|
||||
GetRemoteDownloadJobStatusIsOk,
|
||||
} from "@storyteller/components/src/api/remote_downloads/GetRemoteDownloadJobStatus";
|
||||
import { GetComputedTtsCategoryAssignmentsSuccessResponse } from "@storyteller/components/src/api/category/GetComputedTtsCategoryAssignments";
|
||||
import {
|
||||
AvailableLanguageKey,
|
||||
AVAILABLE_LANGUAGE_MAP,
|
||||
ENGLISH_LANGUAGE,
|
||||
} from "./_i18n/AvailableLanguageMap";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { GetModelInferenceJobStatus, GetModelInferenceJobStatusIsOk } from "@storyteller/components/src/api/model_inference/GetModelInferenceJobStatus";
|
||||
|
||||
i18n
|
||||
.use(initReactI18next) // passes i18n down to react-i18next
|
||||
@@ -126,6 +128,7 @@ interface State {
|
||||
isShowingBootstrapLanguageNotice: boolean;
|
||||
|
||||
// Jobs enqueued during this browser session.
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
w2lInferenceJobs: Array<W2lInferenceJob>;
|
||||
ttsModelUploadJobs: Array<TtsModelUploadJob>;
|
||||
@@ -185,6 +188,7 @@ class App extends React.Component<Props, State> {
|
||||
isShowingPleaseFollowNotice: showPleaseFollowNotice,
|
||||
isShowingBootstrapLanguageNotice: false,
|
||||
|
||||
inferenceJobs: [],
|
||||
ttsInferenceJobs: [],
|
||||
w2lInferenceJobs: [],
|
||||
ttsModelUploadJobs: [],
|
||||
@@ -313,6 +317,40 @@ class App extends React.Component<Props, State> {
|
||||
this.setState({ isShowingBootstrapLanguageNotice: false });
|
||||
};
|
||||
|
||||
checkInferenceJob = async (jobToken: string) => {
|
||||
const lookupResult = await GetModelInferenceJobStatus(jobToken);
|
||||
|
||||
if (GetModelInferenceJobStatusIsOk(lookupResult)) {
|
||||
let updatedJobs: Array<InferenceJob> = [];
|
||||
|
||||
this.state.inferenceJobs.forEach((existingJob) => {
|
||||
if (
|
||||
existingJob.jobToken !== lookupResult.state!.job_token ||
|
||||
!jobStateCanChange(existingJob.jobState)
|
||||
) {
|
||||
updatedJobs.push(existingJob);
|
||||
return;
|
||||
}
|
||||
|
||||
let updatedJob = InferenceJob.fromResponse(lookupResult.state!);
|
||||
updatedJobs.push(updatedJob);
|
||||
});
|
||||
|
||||
this.setState({
|
||||
inferenceJobs: updatedJobs,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
enqueueInferenceJob = (jobToken: string) => {
|
||||
const newJob = new InferenceJob(jobToken);
|
||||
let inferenceJobs = this.state.inferenceJobs.concat([newJob]);
|
||||
|
||||
this.setState({
|
||||
inferenceJobs: inferenceJobs,
|
||||
});
|
||||
};
|
||||
|
||||
enqueueTtsJob = (jobToken: string) => {
|
||||
const newJob = new TtsInferenceJob(jobToken);
|
||||
let inferenceJobs = this.state.ttsInferenceJobs.concat([newJob]);
|
||||
@@ -531,9 +569,9 @@ class App extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
checkVocoderUploadJob = async (jobToken: string) => {
|
||||
const lookupResult = await GetRetrievalJobStatus(jobToken);
|
||||
const lookupResult = await GetRemoteDownloadJobStatus(jobToken);
|
||||
|
||||
if (GetRetrievalJobStatusIsOk(lookupResult)) {
|
||||
if (GetRemoteDownloadJobStatusIsOk(lookupResult)) {
|
||||
let updatedJobs: Array<VocoderUploadJob> = [];
|
||||
|
||||
this.state.vocoderUploadJobs.forEach((existingJob) => {
|
||||
@@ -556,6 +594,11 @@ class App extends React.Component<Props, State> {
|
||||
};
|
||||
|
||||
pollJobs = () => {
|
||||
this.state.inferenceJobs.forEach((job) => {
|
||||
if (jobStateCanChange(job.jobState)) {
|
||||
this.checkInferenceJob(job.jobToken);
|
||||
}
|
||||
});
|
||||
this.state.ttsInferenceJobs.forEach((job) => {
|
||||
if (jobStateCanChange(job.jobState)) {
|
||||
this.checkTtsJob(job.jobToken);
|
||||
@@ -645,6 +688,8 @@ class App extends React.Component<Props, State> {
|
||||
clearBootstrapLanguageNotice={
|
||||
this.clearBootstrapLanguageNotice
|
||||
}
|
||||
enqueueInferenceJob={this.enqueueInferenceJob}
|
||||
inferenceJobs={this.state.inferenceJobs}
|
||||
enqueueTtsJob={this.enqueueTtsJob}
|
||||
ttsInferenceJobs={this.state.ttsInferenceJobs}
|
||||
enqueueW2lJob={this.enqueueW2lJob}
|
||||
|
||||
@@ -67,6 +67,7 @@ import { NewsPage } from "./pages/news/NewsPage";
|
||||
import { LandingPage } from "./pages/landing/LandingPage";
|
||||
import { ChannelsPage } from "./pages/channels/Channels";
|
||||
import { TrumpTtsPage } from "./pages/character/trump/TrumpTtsPage";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
//import { LandingPage } from "./pages/landing/LandingPage";
|
||||
//import { VcModelListPage } from "./pages/vc/vc_model_list/VcModelListPage";
|
||||
|
||||
@@ -94,6 +95,9 @@ interface Props {
|
||||
isShowingBootstrapLanguageNotice: boolean;
|
||||
clearBootstrapLanguageNotice: () => void;
|
||||
|
||||
enqueueInferenceJob: (jobToken: string) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
|
||||
enqueueTtsJob: (jobToken: string) => void;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
|
||||
@@ -294,6 +298,7 @@ class PageContainer extends React.Component<Props, State> {
|
||||
this.props.sessionSubscriptionsWrapper
|
||||
}
|
||||
enqueueTtsJob={this.props.enqueueTtsJob}
|
||||
inferenceJobs={this.props.inferenceJobs}
|
||||
ttsInferenceJobs={this.props.ttsInferenceJobs}
|
||||
textBuffer={this.props.textBuffer}
|
||||
setTextBuffer={this.props.setTextBuffer}
|
||||
@@ -487,6 +492,7 @@ class PageContainer extends React.Component<Props, State> {
|
||||
this.props.sessionSubscriptionsWrapper
|
||||
}
|
||||
enqueueTtsJob={this.props.enqueueTtsJob}
|
||||
inferenceJobs={this.props.inferenceJobs}
|
||||
ttsInferenceJobs={this.props.ttsInferenceJobs}
|
||||
ttsModelUploadJobs={this.props.ttsModelUploadJobs}
|
||||
w2lInferenceJobs={this.props.w2lInferenceJobs}
|
||||
@@ -545,6 +551,8 @@ class PageContainer extends React.Component<Props, State> {
|
||||
clearBootstrapLanguageNotice={
|
||||
this.props.clearBootstrapLanguageNotice
|
||||
}
|
||||
enqueueInferenceJob={this.props.enqueueInferenceJob}
|
||||
inferenceJobs={this.props.inferenceJobs}
|
||||
enqueueTtsJob={this.props.enqueueTtsJob}
|
||||
ttsInferenceJobs={this.props.ttsInferenceJobs}
|
||||
ttsModelUploadJobs={this.props.ttsModelUploadJobs}
|
||||
|
||||
@@ -22,8 +22,10 @@ import {
|
||||
GetPendingTtsJobCountIsOk,
|
||||
GetPendingTtsJobCountSuccessResponse,
|
||||
} from "@storyteller/components/src/api/tts/GetPendingTtsJobCount";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
interface Props {
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
}
|
||||
@@ -62,6 +64,123 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
|
||||
let results: Array<JSX.Element> = [];
|
||||
|
||||
// TODO(bt,2023-04-08): Clean this utter garbage duplication up.
|
||||
|
||||
// ============================= GENERIC INFERENCE =============================
|
||||
|
||||
props.inferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
let cssStyle = "alert alert-secondary mb-0";
|
||||
let stateDescription = "Pending...";
|
||||
|
||||
switch (job.jobState) {
|
||||
case JobState.PENDING:
|
||||
case JobState.UNKNOWN:
|
||||
stateDescription =
|
||||
job.maybeExtraStatusDescription == null
|
||||
? t("common.SessionTtsInferenceResults.progress.pending")
|
||||
: job.maybeExtraStatusDescription;
|
||||
break;
|
||||
case JobState.STARTED:
|
||||
cssStyle = "alert alert-success mb-0";
|
||||
stateDescription =
|
||||
job.maybeExtraStatusDescription == null
|
||||
? t("common.SessionTtsInferenceResults.progress.started")
|
||||
: job.maybeExtraStatusDescription;
|
||||
break;
|
||||
case JobState.ATTEMPT_FAILED:
|
||||
cssStyle = "alert alert-danger mb-0";
|
||||
stateDescription = `Failed ${job.attemptCount} attempt(s). Will retry...`;
|
||||
break;
|
||||
case JobState.COMPLETE_FAILURE:
|
||||
case JobState.DEAD:
|
||||
cssStyle = "alert alert-danger mb-0";
|
||||
// TODO(bt,2023-01-23): Translate when I can test it
|
||||
stateDescription = t(
|
||||
"common.SessionTtsInferenceResults.progress.dead"
|
||||
);
|
||||
break;
|
||||
case JobState.COMPLETE_SUCCESS:
|
||||
cssStyle = "message is-success mb-0";
|
||||
// Not sure why we're here instead of other branch!
|
||||
stateDescription = t(
|
||||
"common.SessionTtsInferenceResults.progress.success"
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
<div>
|
||||
<div>
|
||||
<motion.div className={cssStyle} variants={sessionItem}>
|
||||
{stateDescription}
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else {
|
||||
let audioLink = new BucketConfig().getGcsUrl(
|
||||
job.maybeResultPublicBucketMediaPath
|
||||
);
|
||||
let ttsPermalink = `/tts/result/${job.maybeResultToken}`;
|
||||
|
||||
let wavesurfers = <SessionTtsAudioPlayer filename={audioLink} />;
|
||||
|
||||
results.push(
|
||||
<div key={job.jobToken}>
|
||||
{/*<div className="message-header">
|
||||
<p>{job.title}</p>
|
||||
<button className="delete" aria-label="delete"></button>
|
||||
</div>*/}
|
||||
<div>
|
||||
<motion.div
|
||||
className="panel panel-tts-results p-4 gap-3 d-flex flex-column"
|
||||
variants={sessionItem}
|
||||
>
|
||||
<div>
|
||||
<h5 className="mb-2">{job.maybeModelTitle}</h5>
|
||||
<p>{job.maybeRawInferenceText}</p>
|
||||
</div>
|
||||
|
||||
{/* <audio
|
||||
className="w-100"
|
||||
controls
|
||||
src={audioLink}
|
||||
onClick={() => {
|
||||
Analytics.ttsClickResultInlinePlay();
|
||||
}}
|
||||
>
|
||||
Your browser does not support the
|
||||
<code>audio</code> element.
|
||||
</audio> */}
|
||||
|
||||
{wavesurfers}
|
||||
|
||||
<div className="mt-2">
|
||||
<Link
|
||||
to={ttsPermalink}
|
||||
onClick={() => {
|
||||
Analytics.ttsClickResultLink();
|
||||
}}
|
||||
className="fw-semibold"
|
||||
>
|
||||
<FontAwesomeIcon icon={faLink} className="me-2" />
|
||||
{t("common.SessionTtsInferenceResults.result.shareDownload")}
|
||||
</Link>
|
||||
</div>
|
||||
</motion.div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// TODO(bt,2023-04-08): Clean this utter garbage duplication up.
|
||||
|
||||
// ============================= LEGACY TTS =============================
|
||||
|
||||
props.ttsInferenceJobs.forEach((job) => {
|
||||
if (!job.maybeResultToken) {
|
||||
let cssStyle = "alert alert-secondary mb-0";
|
||||
@@ -171,6 +290,8 @@ function SessionTtsInferenceResultList(props: Props) {
|
||||
}
|
||||
});
|
||||
|
||||
// ============================= END LEGACY TTS =============================
|
||||
|
||||
let noResultsSection = (
|
||||
<div className="panel panel-inner text-center p-5 rounded-5 h-100">
|
||||
<div className="d-flex flex-column opacity-75 h-100 justify-content-center">
|
||||
|
||||
@@ -46,6 +46,7 @@ import { DynamicallyCategorizeModels } from "../../../../../model/categories/Syn
|
||||
|
||||
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
|
||||
import { SearchOmnibar } from "./search/SearchOmnibar";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
const PAGE_MODEL_TOKENS = new Set<string>([
|
||||
"TM:pmd1wm3kf6az", // Development: "Fake Donald Trump #1"
|
||||
@@ -66,6 +67,7 @@ interface Props {
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
|
||||
enqueueTtsJob: (jobToken: string) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
ttsModelUploadJobs: Array<TtsModelUploadJob>;
|
||||
w2lInferenceJobs: Array<W2lInferenceJob>;
|
||||
@@ -472,6 +474,7 @@ function TrumpTtsPage(props: Props) {
|
||||
</h4>
|
||||
<div className="d-flex flex-column gap-3 session-tts-section">
|
||||
<SessionTtsInferenceResultList
|
||||
inferenceJobs={props.inferenceJobs}
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={
|
||||
props.sessionSubscriptionsWrapper
|
||||
|
||||
@@ -7,6 +7,7 @@ import { SessionTtsModelUploadResultList } from "../../../_common/SessionTtsMode
|
||||
import { SessionW2lInferenceResultList } from "../../../_common/SessionW2lInferenceResultsList";
|
||||
import { SessionW2lTemplateUploadResultList } from "../../../_common/SessionW2lTemplateUploadResultsList";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { TtsInferenceJob } from "@storyteller/components/src/jobs/TtsInferenceJobs";
|
||||
import { TtsModelUploadJob } from "@storyteller/components/src/jobs/TtsModelUploadJobs";
|
||||
import { W2lInferenceJob } from "@storyteller/components/src/jobs/W2lInferenceJobs";
|
||||
@@ -91,8 +92,12 @@ interface Props {
|
||||
isShowingBootstrapLanguageNotice: boolean;
|
||||
clearBootstrapLanguageNotice: () => void;
|
||||
|
||||
enqueueInferenceJob: (jobToken: string) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
|
||||
enqueueTtsJob: (jobToken: string) => void;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
|
||||
ttsModelUploadJobs: Array<TtsModelUploadJob>;
|
||||
w2lInferenceJobs: Array<W2lInferenceJob>;
|
||||
w2lTemplateUploadJobs: Array<W2lTemplateUploadJob>;
|
||||
@@ -292,7 +297,13 @@ function TtsModelListPage(props: Props) {
|
||||
|
||||
if (GenerateTtsAudioIsOk(response)) {
|
||||
setMaybeTtsError(undefined);
|
||||
props.enqueueTtsJob(response.inference_job_token);
|
||||
|
||||
if (response.inference_job_token_type === "generic") {
|
||||
props.enqueueInferenceJob(response.inference_job_token);
|
||||
} else {
|
||||
props.enqueueTtsJob(response.inference_job_token);
|
||||
}
|
||||
|
||||
} else if (GenerateTtsAudioIsError(response)) {
|
||||
setMaybeTtsError(response.error);
|
||||
}
|
||||
@@ -598,6 +609,7 @@ function TtsModelListPage(props: Props) {
|
||||
</h4>
|
||||
<div className="d-flex flex-column gap-3 session-tts-section">
|
||||
<SessionTtsInferenceResultList
|
||||
inferenceJobs={props.inferenceJobs}
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={
|
||||
props.sessionSubscriptionsWrapper
|
||||
|
||||
@@ -66,11 +66,13 @@ import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocum
|
||||
import { RatingButtons } from "../../../_common/ratings/RatingButtons";
|
||||
import { RatingStats } from "../../../_common/ratings/RatingStats";
|
||||
import { CommentComponent } from "../../../_common/comments/CommentComponent";
|
||||
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
|
||||
|
||||
interface Props {
|
||||
sessionWrapper: SessionWrapper;
|
||||
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
|
||||
enqueueTtsJob: (jobToken: string) => void;
|
||||
inferenceJobs: Array<InferenceJob>;
|
||||
ttsInferenceJobs: Array<TtsInferenceJob>;
|
||||
textBuffer: string;
|
||||
setTextBuffer: (textBuffer: string) => void;
|
||||
@@ -857,6 +859,7 @@ function TtsModelViewPage(props: Props) {
|
||||
Session TTS Results
|
||||
</h4>
|
||||
<SessionTtsInferenceResultList
|
||||
inferenceJobs={props.inferenceJobs}
|
||||
ttsInferenceJobs={props.ttsInferenceJobs}
|
||||
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
|
||||
/>
|
||||
|
||||
@@ -28,6 +28,9 @@ function UploadTtsModelPage(props: Props) {
|
||||
|
||||
const [downloadUrl, setDownloadUrl] = useState("");
|
||||
const [title, setTitle] = useState("");
|
||||
const [modelType, setModelType] = useState("tacotron2"); // valid options: tacotron2, vits
|
||||
|
||||
// Form errors
|
||||
const [downloadUrlInvalidReason] = useState("");
|
||||
const [titleInvalidReason] = useState("");
|
||||
|
||||
@@ -65,6 +68,10 @@ function UploadTtsModelPage(props: Props) {
|
||||
return false;
|
||||
};
|
||||
|
||||
const handleModelTypeChange = (ev: React.FormEvent<HTMLSelectElement>) => {
|
||||
setModelType((ev.target as HTMLSelectElement).value);
|
||||
};
|
||||
|
||||
const handleFormSubmit = (ev: React.FormEvent<HTMLFormElement>) => {
|
||||
ev.preventDefault();
|
||||
|
||||
@@ -77,6 +84,7 @@ function UploadTtsModelPage(props: Props) {
|
||||
idempotency_token: idempotencyToken,
|
||||
title: title,
|
||||
download_url: downloadUrl,
|
||||
tts_model_type: modelType,
|
||||
};
|
||||
|
||||
fetch(endpointUrl, {
|
||||
@@ -176,6 +184,30 @@ function UploadTtsModelPage(props: Props) {
|
||||
<div className="container-panel py-5">
|
||||
<div className="panel p-3 py-4 p-lg-4">
|
||||
<div className="d-flex flex-column gap-4">
|
||||
|
||||
{/* Model Type */}
|
||||
<div>
|
||||
<label className="sub-title">
|
||||
TTS Model Type
|
||||
</label>
|
||||
<div className="control select">
|
||||
<select
|
||||
className="form-select"
|
||||
name="tts_model_type"
|
||||
onChange={handleModelTypeChange}
|
||||
value={modelType}
|
||||
>
|
||||
<option value="tacotron2">
|
||||
Tacotron 2
|
||||
</option>
|
||||
<option value="vits">
|
||||
VITS
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Title */}
|
||||
<div>
|
||||
<label className="sub-title">
|
||||
Title, eg. "Goku (Sean Schemmel)"
|
||||
@@ -192,9 +224,7 @@ function UploadTtsModelPage(props: Props) {
|
||||
<p className="help">{titleInvalidReason}</p>
|
||||
</div>
|
||||
|
||||
{/*
|
||||
https://drive.google.com/file/d/{TOKEN}/view?usp=sharing
|
||||
*/}
|
||||
{/* Download URL */}
|
||||
<div>
|
||||
<label className="sub-title">
|
||||
Download URL, eg. Google Drive link
|
||||
@@ -210,13 +240,8 @@ function UploadTtsModelPage(props: Props) {
|
||||
</div>
|
||||
<p className="help">{downloadUrlInvalidReason}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/*<div className="field is-grouped">
|
||||
<div className="control">
|
||||
<button className="button is-link is-large is-fullwidth">Upload</button>
|
||||
</div>
|
||||
</div>*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ import React, { useState } from "react";
|
||||
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
|
||||
import { DiscordLink } from "@storyteller/components/src/elements/DiscordLink";
|
||||
import {
|
||||
EnqueueRetrieval,
|
||||
EnqueueRetrievalIsOk,
|
||||
} from "@storyteller/components/src/api/retrieval/EnqueueRetrieval";
|
||||
EnqueueRemoteDownload,
|
||||
EnqueueRemoteDownloadIsOk,
|
||||
} from "@storyteller/components/src/api/remote_downloads/EnqueueRemoteDownload";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { BackLink } from "../../_common/BackLink";
|
||||
@@ -75,9 +75,9 @@ function UploadVocoderPage(props: Props) {
|
||||
generic_download_type: "hifigan",
|
||||
};
|
||||
|
||||
const response = await EnqueueRetrieval(request);
|
||||
const response = await EnqueueRemoteDownload(request);
|
||||
|
||||
if (EnqueueRetrievalIsOk(response)) {
|
||||
if (EnqueueRemoteDownloadIsOk(response)) {
|
||||
props.enqueueVocoderUploadJob(response.job_token);
|
||||
history.push("/");
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user