mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-07 02:21:23 +00:00
so-vits-svc upload handlers
This commit is contained in:
1 parent
a188c5ffc6
commit
2da69e8ae7
6 files changed
+207
-13
No files matched your search
@@ -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,
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
|
||||
+89
@@ -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 & 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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user