so-vits-svc upload handlers

This commit is contained in:
Brandon Thomas committed 2023-04-10 01:42:55 -07:00
1 parent a188c5ffc6
commit 2da69e8ae7
6 files changed
+207 -13

No files matched your search

+2 -2
View File
@@ -395,11 +395,11 @@ class ApiConfig {
// =============== Generic Model Downloads ===============
enqueueRemoteDownloadJob(): string {
return `${this.getApiOrigin()}/v1/remote_downloads/enqueue`;
return `${this.getApiOrigin()}/v1/remote_download/enqueue`;
}
getRemoteDownloadJobStatus(jobToken: string): string {
return `${this.getApiOrigin()}/v1/remote_downloads/job_status/${jobToken}`;
return `${this.getApiOrigin()}/v1/remote_download/job_status/${jobToken}`;
}
// =============== Generic Model Inference ===============
@@ -0,0 +1,58 @@
import { RemoteDownloadJobStatus } from "../api/remote_downloads/GetRemoteDownloadJobStatus";
import { JobState, jobStateFromString } from "./JobStates";
export class VoiceConversionModelUploadJob {
jobToken: string;
maybeDownloadedEntityType: string | undefined | null;
maybeDownloadedEntityToken: string | undefined | null;
jobState: JobState;
maybeExtraStatusDescription: string | null;
attemptCount: number;
constructor(
jobToken: string,
status: string = 'unknown',
maybeExtraStatusDescription: string | null = null,
attemptCount: number = 0,
maybeDownloadedEntityType: string | undefined | null = undefined,
maybeDownloadedEntityToken: string | undefined | null = undefined
) {
this.jobState = jobStateFromString(status);
this.maybeExtraStatusDescription = maybeExtraStatusDescription;
this.attemptCount = attemptCount;
this.jobToken = jobToken;
if (!!maybeDownloadedEntityType) {
this.maybeDownloadedEntityType = maybeDownloadedEntityType;
}
if (!!maybeDownloadedEntityToken) {
this.maybeDownloadedEntityToken = maybeDownloadedEntityToken;
}
}
static fromResponse(response: RemoteDownloadJobStatus) : VoiceConversionModelUploadJob {
return new VoiceConversionModelUploadJob(
response.job_token,
response.status,
response.maybe_extra_status_description || null,
response.attempt_count || 0,
response.maybe_downloaded_entity_type,
response.maybe_downloaded_entity_token,
);
}
}
export interface VoiceConversionModelUploadJobStateResponsePayload {
success: boolean,
state?: VoiceConversionModelUploadJobState,
}
export interface VoiceConversionModelUploadJobState {
job_token: string,
status: string,
maybe_extra_status_description: string | null,
attempt_count: number | undefined,
maybe_downloaded_entity_type: string | undefined | null,
maybe_downloaded_entity_token: string | undefined | null,
created_at: string,
updated_at: string,
}
+44
View File
@@ -46,6 +46,7 @@ import {
} from "./_i18n/AvailableLanguageMap";
import { InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
import { GetModelInferenceJobStatus, GetModelInferenceJobStatusIsOk } from "@storyteller/components/src/api/model_inference/GetModelInferenceJobStatus";
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
i18n
.use(initReactI18next) // passes i18n down to react-i18next
@@ -134,6 +135,7 @@ interface State {
ttsModelUploadJobs: Array<TtsModelUploadJob>;
w2lTemplateUploadJobs: Array<W2lTemplateUploadJob>;
vocoderUploadJobs: Array<VocoderUploadJob>;
voiceConversionModelUploadJobs: Array<VoiceConversionModelUploadJob>;
// Current text entered
textBuffer: string;
@@ -194,6 +196,7 @@ class App extends React.Component<Props, State> {
ttsModelUploadJobs: [],
w2lTemplateUploadJobs: [],
vocoderUploadJobs: [],
voiceConversionModelUploadJobs: [],
textBuffer: "",
};
@@ -593,6 +596,40 @@ class App extends React.Component<Props, State> {
}
};
enqueueVoiceConversionModelUploadJob = (jobToken: string) => {
const newJob = new VoiceConversionModelUploadJob(jobToken);
let uploadJobs = this.state.voiceConversionModelUploadJobs.concat([newJob]);
this.setState({
voiceConversionModelUploadJobs: uploadJobs,
});
};
checkVoiceConversionModelUploadJob = async (jobToken: string) => {
const lookupResult = await GetRemoteDownloadJobStatus(jobToken);
if (GetRemoteDownloadJobStatusIsOk(lookupResult)) {
let updatedJobs: Array<VocoderUploadJob> = [];
this.state.voiceConversionModelUploadJobs.forEach((existingJob) => {
if (
existingJob.jobToken !== lookupResult.state!.job_token ||
!jobStateCanChange(existingJob.jobState)
) {
updatedJobs.push(existingJob);
return;
}
let updatedJob = VoiceConversionModelUploadJob.fromResponse(lookupResult.state!);
updatedJobs.push(updatedJob);
});
this.setState({
voiceConversionModelUploadJobs: updatedJobs,
});
}
};
pollJobs = () => {
this.state.inferenceJobs.forEach((job) => {
if (jobStateCanChange(job.jobState)) {
@@ -624,6 +661,11 @@ class App extends React.Component<Props, State> {
this.checkVocoderUploadJob(job.jobToken);
}
});
this.state.voiceConversionModelUploadJobs.forEach((job) => {
if (jobStateCanChange(job.jobState)) {
this.checkVoiceConversionModelUploadJob(job.jobToken);
}
});
};
setMigrationMode = (mode: MigrationMode) => {
@@ -702,6 +744,8 @@ class App extends React.Component<Props, State> {
w2lTemplateUploadJobs={this.state.w2lTemplateUploadJobs}
enqueueVocoderUploadJob={this.enqueueVocoderUploadJob}
vocoderUploadJobs={this.state.vocoderUploadJobs}
enqueueVoiceConversionModelUploadJob={this.enqueueVoiceConversionModelUploadJob}
voiceConversionModelUploadJobs={this.state.voiceConversionModelUploadJobs}
textBuffer={this.state.textBuffer}
setTextBuffer={this.setTextBuffer}
clearTextBuffer={this.clearTextBuffer}
@@ -20,6 +20,7 @@ import { TtsModelDeletePage } from "./pages/tts/tts_model_delete/TtsModelDeleteP
import { TtsModelEditPage } from "./pages/tts/tts_model_edit/TtsModelEditPage";
import { TtsModelUploadJob } from "@storyteller/components/src/jobs/TtsModelUploadJobs";
import { VocoderUploadJob } from "@storyteller/components/src/jobs/VocoderUploadJobs";
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
import { TtsModelViewPage } from "./pages/tts/tts_model_view/TtsModelViewPage";
import { TtsResultDeletePage } from "./pages/tts/tts_result_delete/TtsResultDeletePage";
import { TtsResultViewPage } from "./pages/tts/tts_result_view/TtsResultViewPage";
@@ -111,9 +112,14 @@ interface Props {
enqueueW2lTemplateUploadJob: (jobToken: string) => void;
w2lTemplateUploadJobs: Array<W2lTemplateUploadJob>;
// TODO: Begin to unify generic download jobs (vocoder, voice conversion, ...)
enqueueVocoderUploadJob: (jobToken: string) => void;
vocoderUploadJobs: Array<VocoderUploadJob>;
// TODO: Begin to unify generic download jobs (vocoder, voice conversion, ...)
enqueueVoiceConversionModelUploadJob: (jobToken: string) => void;
voiceConversionModelUploadJobs: Array<VoiceConversionModelUploadJob>;
textBuffer: string;
setTextBuffer: (textBuffer: string) => void;
clearTextBuffer: () => void;
@@ -378,8 +384,8 @@ class PageContainer extends React.Component<Props, State> {
<Route path="/upload/voice_conversion">
<UploadVoiceConversionModel
sessionWrapper={this.props.sessionWrapper}
voiceConversionModelUploadJobs={[]}
enqueueVoiceConversionModelUploadJob={this.props.enqueueTtsModelUploadJob}
voiceConversionModelUploadJobs={this.props.voiceConversionModelUploadJobs}
enqueueVoiceConversionModelUploadJob={this.props.enqueueVoiceConversionModelUploadJob}
/>
</Route>
@@ -0,0 +1,89 @@
import React from "react";
import { Link } from "react-router-dom";
import { JobState } from "@storyteller/components/src/jobs/JobStates";
import { motion } from "framer-motion";
import { container, sessionItem, item } from "../../../data/animation";
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
interface Props {
voiceConversionModelUploadJobs: Array<VoiceConversionModelUploadJob>;
}
function SessionVoiceConversionModelUploadResultList(props: Props) {
let results: Array<JSX.Element> = [];
props.voiceConversionModelUploadJobs.forEach((job) => {
if (!job.maybeDownloadedEntityToken) {
let stateDescription = "Pending...";
switch (job.jobState) {
case JobState.PENDING:
case JobState.UNKNOWN:
stateDescription =
job.maybeExtraStatusDescription == null
? "Pending..."
: job.maybeExtraStatusDescription;
break;
case JobState.STARTED:
stateDescription =
job.maybeExtraStatusDescription == null
? "Started..."
: job.maybeExtraStatusDescription;
break;
case JobState.ATTEMPT_FAILED:
stateDescription = `Failed ${job.attemptCount} attempt(s). Will retry...`;
break;
case JobState.COMPLETE_FAILURE:
case JobState.DEAD:
stateDescription =
"Failed Permanently. Please tell us in Discord so we can fix. :(";
break;
case JobState.COMPLETE_SUCCESS:
stateDescription = "Success!"; // Not sure why we're here instead of other branch!
break;
}
results.push(
<div key={job.jobToken}>
<div className="alert alert-primary">{stateDescription}</div>
</div>
);
} else {
let permalink = `/voice_conversion/${job.maybeDownloadedEntityToken}`;
results.push(
<div key={job.jobToken}>
<motion.div
className="panel py-4 p-3 p-lg-4 gap-4"
variants={sessionItem}
>
Complete!
<Link to={permalink} className="btn btn-primary ms-4">
See &amp; use voice conversion model
</Link>
</motion.div>
</div>
);
}
});
let title = <span />;
if (results.length !== 0) {
title = (
<motion.h2 className="text-center text-lg-start fw-bold" variants={item}>
Voice Conversion Model Upload Status
</motion.h2>
);
}
return (
<motion.div initial="hidden" animate="visible" variants={container}>
<div className="container-panel pt-4 pb-5">
<div className="pb-4">{title}</div>
<div className="d-flex flex-column gap-4">{results}</div>
</div>
</motion.div>
);
}
export { SessionVoiceConversionModelUploadResultList };
@@ -12,15 +12,15 @@ import { Link } from "react-router-dom";
import { WebUrl } from "../../../../common/WebUrl";
import { motion } from "framer-motion";
import { container, item, panel } from "../../../../data/animation";
import { VocoderUploadJob } from "@storyteller/components/src/jobs/VocoderUploadJobs";
import { SessionVocoderUploadResultList } from "../../_common/SessionVocoderUploadResultsList";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faMicrophoneStand } from "@fortawesome/pro-solid-svg-icons";
import { VoiceConversionModelUploadJob } from "@storyteller/components/src/jobs/VoiceConversionModelUploadJob";
import { SessionVoiceConversionModelUploadResultList } from "../../_common/SessionVoiceConversionModelUploadResultsList";
interface Props {
sessionWrapper: SessionWrapper;
enqueueVoiceConversionModelUploadJob: (jobToken: string) => void;
voiceConversionModelUploadJobs: Array<number>; // TODO
voiceConversionModelUploadJobs: Array<VoiceConversionModelUploadJob>;
}
function UploadVoiceConversionModel(props: Props) {
@@ -74,7 +74,7 @@ function UploadVoiceConversionModel(props: Props) {
idempotency_token: idempotencyToken,
title: title,
download_url: downloadUrl,
generic_download_type: "hifigan",
generic_download_type: "so_vits_svc",
};
const response = await EnqueueRemoteDownload(request);
@@ -170,12 +170,9 @@ function UploadVoiceConversionModel(props: Props) {
</motion.div>
</motion.form>
{/*
<SessionVocoderUploadResultList
vocoderUploadJobs={props.vocoderUploadJobs}
<SessionVoiceConversionModelUploadResultList
voiceConversionModelUploadJobs={props.voiceConversionModelUploadJobs}
/>
*/}
</motion.div>
);
}