From 04d59933e568bee175fb7aef1d8ec501d7f53791 Mon Sep 17 00:00:00 2001 From: Brandon Thomas Date: Fri, 21 May 2021 06:04:20 -0400 Subject: [PATCH] upload mode (wip) --- vocodes/package-lock.json | 32 ++- vocodes/package.json | 4 +- vocodes/src/App.tsx | 8 + vocodes/src/AppMode.ts | 2 +- vocodes/src/api/ApiConfig.ts | 8 + vocodes/src/modes/upload/UploadComponent.tsx | 248 +++++++++++++++++++ vocodes/src/navigation/TopNav.tsx | 2 +- 7 files changed, 298 insertions(+), 6 deletions(-) create mode 100644 vocodes/src/modes/upload/UploadComponent.tsx diff --git a/vocodes/package-lock.json b/vocodes/package-lock.json index b67db714e4..614853e60d 100644 --- a/vocodes/package-lock.json +++ b/vocodes/package-lock.json @@ -1855,6 +1855,11 @@ } } }, + "@types/uuid": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", + "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==" + }, "@types/yargs": { "version": "13.0.9", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.9.tgz", @@ -11522,6 +11527,13 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "request-promise-core": { @@ -12272,6 +12284,13 @@ "requires": { "faye-websocket": "^0.10.0", "uuid": "^3.0.1" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "sockjs-client": { @@ -13468,9 +13487,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-compile-cache": { "version": "2.1.1", @@ -14159,6 +14178,13 @@ "requires": { "ansi-colors": "^3.0.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + } } }, "webpack-manifest-plugin": { diff --git a/vocodes/package.json b/vocodes/package.json index fa0bc8d180..b60d3e41ee 100644 --- a/vocodes/package.json +++ b/vocodes/package.json @@ -14,6 +14,7 @@ "@types/node": "^12.12.47", "@types/react": "^16.9.36", "@types/react-dom": "^16.9.8", + "@types/uuid": "^8.3.0", "axios": "^0.21.0", "bulma": "^0.9.0", "howler": "^2.2.0", @@ -21,7 +22,8 @@ "react": "^16.13.1", "react-dom": "^16.13.1", "react-scripts": "3.4.1", - "typescript": "^3.7.5" + "typescript": "^3.7.5", + "uuid": "^8.3.2" }, "scripts": { "start": "BROWSER=none react-scripts start", diff --git a/vocodes/src/App.tsx b/vocodes/src/App.tsx index b426d469d0..2e0f96bf00 100644 --- a/vocodes/src/App.tsx +++ b/vocodes/src/App.tsx @@ -22,6 +22,7 @@ import { SignupComponent } from './modes/signup/SignupComponent'; import { ApiConfig } from './api/ApiConfig'; import { SessionStateResponse } from './api/SessionState'; import { LoginComponent } from './modes/login/LoginComponent'; +import { UploadComponent } from './modes/upload/UploadComponent'; interface Props { // Certan browsers (iPhone) have pitiful support for drawing APIs. Worse yet, @@ -432,6 +433,13 @@ class App extends React.Component { switchModeCallback={this.switchMode} /> break; + case Mode.UPLOAD_MODE: + component = + break; } return (
diff --git a/vocodes/src/AppMode.ts b/vocodes/src/AppMode.ts index 9d7784f0c8..9f2c43a9c7 100644 --- a/vocodes/src/AppMode.ts +++ b/vocodes/src/AppMode.ts @@ -13,7 +13,7 @@ enum Mode { COMMUNITY_TTS_MODE, COMMUNITY_VIDEO_MODE, - UPLOAD, + UPLOAD_MODE, MY_DATA_MODE, } diff --git a/vocodes/src/api/ApiConfig.ts b/vocodes/src/api/ApiConfig.ts index 7e0d367ce8..dada4e7ffb 100644 --- a/vocodes/src/api/ApiConfig.ts +++ b/vocodes/src/api/ApiConfig.ts @@ -37,6 +37,14 @@ class ApiConfig { return `${this.getScheme()}://${this.getNewApiHost()}/session`; } + uploadTts() : string { + return `${this.getScheme()}://${this.getNewApiHost()}/tts/upload`; + } + + uploadW2l() : string { + return `${this.getScheme()}://${this.getNewApiHost()}/w2l/upload`; + } + private getScheme() : string { return this.isLocalDev ? "http" : "https"; } diff --git a/vocodes/src/modes/upload/UploadComponent.tsx b/vocodes/src/modes/upload/UploadComponent.tsx new file mode 100644 index 0000000000..8e909468ca --- /dev/null +++ b/vocodes/src/modes/upload/UploadComponent.tsx @@ -0,0 +1,248 @@ +import React from 'react'; +import { ApiConfig } from '../../api/ApiConfig'; +import { Mode } from '../../AppMode'; +import { v4 } from 'uuid'; + +enum UploadType { + TTS_MODEL, + W2L_TEMPLATE, +} + +enum FieldTriState { + EMPTY_FALSE, + FALSE, + TRUE, +} + +interface Props { + loggedIn: boolean, + querySessionCallback : () => void, + switchModeCallback: (mode: Mode) => void, +} + +interface State { + uploadType: UploadType, + + title: string, + titleValid: FieldTriState, + titleInvalidReason: string, + + downloadUrl: string, + downloadUrlValid: FieldTriState, + downloadUrlInvalidReason: string, + + idempotencyToken: string, +} + +class UploadComponent extends React.Component { + + constructor(props: Props) { + super(props); + this.state = { + uploadType: UploadType.TTS_MODEL, + + title: "", + titleValid: FieldTriState.EMPTY_FALSE, + titleInvalidReason: "", + + downloadUrl: "", + downloadUrlValid: FieldTriState.EMPTY_FALSE, + downloadUrlInvalidReason: "", + + idempotencyToken: "", + }; + } + + handleTitleChange = (ev: React.FormEvent) => { + ev.preventDefault(); + + const title = (ev.target as HTMLInputElement).value; + + this.setState({ + title: title, + }); + + return false; + } + + handleDownloadUrlChange = (ev: React.FormEvent) => { + ev.preventDefault(); + + const downloadUrl = (ev.target as HTMLInputElement).value; + + this.setState({ + downloadUrl: downloadUrl, + }); + + return false; + } + + handleFormSubmit = (ev: React.FormEvent) : boolean => { + ev.preventDefault(); + + const api = new ApiConfig(); + let endpointUrl = ""; + + switch (this.state.uploadType) { + case UploadType.TTS_MODEL: + endpointUrl = api.uploadTts(); + break; + case UploadType.W2L_TEMPLATE: + endpointUrl = api.uploadW2l(); + break; + } + + let idempotency_token = this.state.idempotencyToken; + + idempotency_token = v4(); + + const request = { + idempotency_token: idempotency_token, + title: this.state.title, + download_url: this.state.downloadUrl, + } + + fetch(endpointUrl, { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + credentials: 'include', + body: JSON.stringify(request), + }) + .then(res => res.json()) + .then(res => { + console.log('upload response', res) + if (res.success) { + this.props.switchModeCallback(Mode.SPEAK_MODE); + return; + } + }) + .catch(e => { + //this.props.onSpeakErrorCallback(); + }); + + return false; + } + + setTts = () => { + this.setState({ + uploadType: UploadType.TTS_MODEL, + }) + } + + setW2l = () => { + this.setState({ + uploadType: UploadType.W2L_TEMPLATE, + }) + } + + public render() { + if (!this.props.loggedIn) { + return ( +
+

You must be logged in to upload!

+ Invalid view for logged out users. +
+ ); + } + + let extra =
; + + if (this.state.uploadType === UploadType.TTS_MODEL) { + extra = ( +
+ Over $500 in prizes! +

You can help vo.codes grow by uploading Tacotron2 models. + The person that uploads the most models will get $100, + the person that uploads the most popular model will get $100, + and a number of other lucky winners will be chosen at random to + recieve cash prizes.

+
+ ); + } + + let title = ""; + let ttsClasses = ""; + let w2lClasses = ""; + + switch (this.state.uploadType) { + case UploadType.TTS_MODEL: + title = "Upload Tacotron 2 Model"; + ttsClasses = "button is-primary is-large is-light"; + w2lClasses = "button is-primary is-large"; + break; + case UploadType.W2L_TEMPLATE: + title = "Upload W2L Video or Image Template"; + ttsClasses = "button is-primary is-large"; + w2lClasses = "button is-primary is-large is-light"; + break; + } + + return ( +
+

{title}

+ +
+
+ +
+
+ +
+
+ + {extra} + +
+
+ +
+ + + + + + + +
+

{this.state.titleInvalidReason}

+
+ +
+ +
+ + + + + + + +
+

{this.state.downloadUrlInvalidReason}

+
+ +
+ +
+
+ +
+
+
+
+ ) + } +} + +export { UploadComponent }; \ No newline at end of file diff --git a/vocodes/src/navigation/TopNav.tsx b/vocodes/src/navigation/TopNav.tsx index 32242a00ec..c59f84d5a3 100644 --- a/vocodes/src/navigation/TopNav.tsx +++ b/vocodes/src/navigation/TopNav.tsx @@ -65,7 +65,7 @@ function TopNav(props: Props) {
props.switchModeCallback(Mode.COMMUNITY_TTS_MODE)}>TTS props.switchModeCallback(Mode.COMMUNITY_VIDEO_MODE)}>Video - props.switchModeCallback(Mode.UPLOAD)}>Upload + props.switchModeCallback(Mode.UPLOAD_MODE)}>Upload props.switchModeCallback(Mode.MY_DATA_MODE)}>My Data
);