diff --git a/vocodes/src/App.tsx b/vocodes/src/App.tsx index 06efe2535a..fa444790b3 100644 --- a/vocodes/src/App.tsx +++ b/vocodes/src/App.tsx @@ -15,6 +15,54 @@ enum MigrationMode { OLD_VOCODES, } +class TtsInferenceJob { + jobToken: string; + modelToken?: string; + status: string; + title?: string; + maybeResultToken?: string; + + constructor( + jobToken: string, + status: string = 'unknown', + modelToken: string | undefined = undefined, + title: string | undefined = undefined, + maybeResulToken: string | undefined = undefined, + ) { + this.status = status; + this.jobToken = jobToken; + this.maybeResultToken = maybeResulToken; + this.modelToken = modelToken; + this.title = title; + } + + static fromResponse(response: TtsInferenceJobState) : TtsInferenceJob { + return new TtsInferenceJob( + response.job_token, + response.status, + response.model_token, + response.title, + response.maybe_result_token + ); + } +} + +interface TtsInferenceJobStateResponsePayload { + success: boolean, + state?: TtsInferenceJobState, +} + +interface TtsInferenceJobState { + job_token: string, + status: string, + maybe_result_token?: string, + model_token: string, + tts_model_type: string, + title: string, + created_at: string, + updated_at: string, +} + interface Props { // Certan browsers (iPhone) have pitiful support for drawing APIs. Worse yet, // they seem to lose the "touch event sandboxing" that allows for audio to be @@ -30,6 +78,8 @@ interface State { // Rollout of vocodes 2.0 enableAlpha: boolean, sessionWrapper: SessionWrapper, + + ttsInferenceJobs: Array, } class App extends React.Component { @@ -45,12 +95,17 @@ class App extends React.Component { enableAlpha: enableAlpha, migrationMode: migrationMode, sessionWrapper: SessionWrapper.emptySession(), + + ttsInferenceJobs: [], } } componentDidMount() { this.querySession(); - setInterval(() => this.querySession, 10000); + + setInterval(() => { this.querySession() }, 10000); + // TODO: Use websockets, this is dumb + setInterval(() => { this.pollJobs() }, 1000); //this.state.videoJobPoller.start(); //this.state.videoQueuePoller.start(); } @@ -107,6 +162,80 @@ class App extends React.Component { .catch(e => { /* Ignore. */ }); } + enqueueTtsJob = (jobToken: string) => { + console.log('enqueueTtsJob()') + if (!this.state.enableAlpha) { + console.log('enqueueTtsJob() disabled!') + return; + } + const newJob = new TtsInferenceJob(jobToken); + let inferenceJobs = this.state.ttsInferenceJobs.concat([newJob]); + + console.log('setting state!!') + this.setState({ + ttsInferenceJobs: inferenceJobs + }) + + console.log('inference jobs:', inferenceJobs.length); + } + + checkTtsJob = (jobToken: string) => { + if (!this.state.enableAlpha) { + return; + } + + const api = new ApiConfig(); + const endpointUrl = api.getTtsInferenceJobState(jobToken); + + fetch(endpointUrl, { + method: 'GET', + credentials: 'include', + headers: { + 'Accept': 'application/json', + }, + }) + .then(res => res.json()) + .then(response => { + const jobResponse : TtsInferenceJobStateResponsePayload = response; + + if (jobResponse === undefined || jobResponse.state === undefined) { + return; + } + + let updatedJobs : Array = []; + this.state.ttsInferenceJobs.forEach(job => { + if (job.jobToken !== jobResponse.state!.job_token || + job.maybeResultToken !== undefined) { // NB: Already done querying, no need to update again. + updatedJobs.push(job); + return; + } + + let updatedJob = TtsInferenceJob.fromResponse(jobResponse.state!); + updatedJobs.push(updatedJob); + }); + + this.setState({ + ttsInferenceJobs: updatedJobs, + }) + }) + .catch(e => { /* Ignore. */ }); + } + + pollJobs () { + console.log('pollJobs()') + this.state.ttsInferenceJobs.forEach(job => { + console.log('poll job:', job.jobToken) + switch (job.status) { + case 'unknown': + case 'pending': + this.checkTtsJob(job.jobToken); + break; + default: + return; + } + }); + } + setMigrationMode = (mode: MigrationMode) => { this.setState({migrationMode: mode}); } @@ -143,6 +272,7 @@ class App extends React.Component { diff --git a/vocodes/src/migration/MigrationTopNav_VersionSwitch.tsx b/vocodes/src/migration/MigrationTopNav_VersionSwitch.tsx index 3da7460768..bf4eb758be 100644 --- a/vocodes/src/migration/MigrationTopNav_VersionSwitch.tsx +++ b/vocodes/src/migration/MigrationTopNav_VersionSwitch.tsx @@ -15,12 +15,12 @@ function MigrationTopNavVersionSwitch(props: Props) { Switch to new vocodes (custom voices, video uploads, and more!) + >Switch to New Vocodes (it's awesome!) Switch to old vocodes (80+ voices) + >Old vocodes (80+ voices) ); diff --git a/vocodes/src/v1/api/ApiConfig.ts b/vocodes/src/v1/api/ApiConfig.ts index 70d07275d2..c0517bd8aa 100644 --- a/vocodes/src/v1/api/ApiConfig.ts +++ b/vocodes/src/v1/api/ApiConfig.ts @@ -56,6 +56,10 @@ class ApiConfig { return `${this.getScheme()}://${this.getNewApiHost()}/user/${username}/tts_results`; } + getTtsInferenceJobState(jobToken: string) : string { + return `${this.getScheme()}://${this.getNewApiHost()}/tts/job/${jobToken}`; + } + uploadTts() : string { return `${this.getScheme()}://${this.getNewApiHost()}/tts/upload`; } diff --git a/vocodes/src/v2/NewVocodesContainer.tsx b/vocodes/src/v2/NewVocodesContainer.tsx index ba65c57e9d..806038ca50 100644 --- a/vocodes/src/v2/NewVocodesContainer.tsx +++ b/vocodes/src/v2/NewVocodesContainer.tsx @@ -25,6 +25,7 @@ import { TtsResultViewFc } from './tts_result_view/TtsResultViewFc'; interface Props { sessionWrapper: SessionWrapper, querySessionAction: () => void, + enqueueTtsJob: (jobToken: string) => void, } interface State { @@ -114,6 +115,7 @@ class NewVocodesContainer extends React.Component { {}} sessionWrapper={this.props.sessionWrapper} + enqueueTtsJob={this.props.enqueueTtsJob} /> @@ -168,6 +170,7 @@ class NewVocodesContainer extends React.Component { diff --git a/vocodes/src/v2/tts_model_list/TtsModelFormFc.tsx b/vocodes/src/v2/tts_model_list/TtsModelFormFc.tsx index c00e2999cc..3b43f9273a 100644 --- a/vocodes/src/v2/tts_model_list/TtsModelFormFc.tsx +++ b/vocodes/src/v2/tts_model_list/TtsModelFormFc.tsx @@ -21,8 +21,14 @@ interface TtsModel { updated_at: string, } +interface EnqueueJobResponsePayload { + success: boolean, + inference_job_token?: string, +} + interface Props { sessionWrapper: SessionWrapper, + enqueueTtsJob: (jobToken: string) => void, } function TtsModelFormFc(props: Props) { @@ -174,9 +180,15 @@ function TtsModelFormFc(props: Props) { }) .then(res => res.json()) .then(res => { - console.log('tts infer response', res) - if (res.success) { + console.log('handleFormSubmit response:', res); + let response : EnqueueJobResponsePayload = res; + if (!response.success || response.inference_job_token === undefined) { + return; } + + console.log('enqueuing...') + + props.enqueueTtsJob(response.inference_job_token); }) .catch(e => { }); diff --git a/vocodes/src/v2/tts_model_list/TtsModelListComponent.tsx b/vocodes/src/v2/tts_model_list/TtsModelListComponent.tsx index 7b698251c2..44c29599b1 100644 --- a/vocodes/src/v2/tts_model_list/TtsModelListComponent.tsx +++ b/vocodes/src/v2/tts_model_list/TtsModelListComponent.tsx @@ -13,6 +13,7 @@ interface Props { sessionWrapper: SessionWrapper, querySessionCallback : () => void, switchModeCallback?: (mode: Mode) => void, + enqueueTtsJob: (jobToken: string) => void, } interface State {