Work on VITS, VC, generic inference

This commit is contained in:
Brandon Thomas committed 2023-04-09 19:08:57 -07:00
1 parent 66e009480f
commit 2e5a3d7964
15 files changed
+441 -43

No files matched your search

+16 -4
View File
@@ -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 };
});
}
@@ -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',
@@ -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,
+50 -5
View File
@@ -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("/");
}