diff --git a/vocodes/src/v2/profile/ProfileFc.tsx b/vocodes/src/v2/profile/ProfileFc.tsx
index 7d6877b85a..d0889efcd9 100644
--- a/vocodes/src/v2/profile/ProfileFc.tsx
+++ b/vocodes/src/v2/profile/ProfileFc.tsx
@@ -2,6 +2,8 @@ import React, { useEffect, useState } from 'react';
import { ApiConfig } from '../../v1/api/ApiConfig';
import { GravatarFc } from '../common/GravatarFc';
import { Link } from 'react-router-dom';
+import { ProfileTtsInferenceResultsListFc } from './Profile_TtsInferenceResultListFc';
+import { ProfileTtsModelListFc } from './Profile_TtsModelListFc';
import { ProfileW2lInferenceResultsListFc } from './Profile_W2lInferenceResultListFc';
import { ProfileW2lTemplateListFc } from './Profile_W2lTemplateListFc';
import { SessionWrapper } from '../../session/SessionWrapper';
@@ -97,8 +99,9 @@ function ProfileFc(props: Props) {
-
Uploaded Templates
-
+ TTS Results
+
+
@@ -106,6 +109,24 @@ function ProfileFc(props: Props) {
Lipsync Results
+
+
+
+ Uploaded TTS Models
+
+
+
+
+
+ Uploaded Templates
+
+
+
+
+ Badges
+ EARLY USER ! !
+
+
)
}
diff --git a/vocodes/src/v2/profile/Profile_TtsInferenceResultListFc.tsx b/vocodes/src/v2/profile/Profile_TtsInferenceResultListFc.tsx
new file mode 100644
index 0000000000..e6a9595bc5
--- /dev/null
+++ b/vocodes/src/v2/profile/Profile_TtsInferenceResultListFc.tsx
@@ -0,0 +1,103 @@
+import React, { useState, useEffect } from 'react';
+import { ApiConfig } from '../../v1/api/ApiConfig';
+import { Link } from "react-router-dom";
+
+interface TtsInferenceResultListResponsePayload {
+ success: boolean,
+ results: Array,
+}
+
+interface TtsInferenceResult {
+ w2l_result_token: string,
+ maybe_w2l_template_token?: string,
+ maybe_tts_inference_result_token?: string,
+
+ template_type: string,
+ template_title: string,
+
+ maybe_creator_user_token?: string,
+ maybe_creator_username?: string,
+ maybe_creator_display_name?: string,
+
+ file_size_bytes: number,
+ frame_width: number,
+ frame_height: number,
+ duration_millis: number,
+
+ created_at: string,
+ updated_at: string,
+}
+
+interface Props {
+ username: string,
+}
+
+function ProfileTtsInferenceResultsListFc(props: Props) {
+ const [w2lResults, setW2lResults] = useState>([]);
+
+ useEffect(() => {
+ const api = new ApiConfig();
+ const endpointUrl = api.listW2lInferenceResultsForUser(props.username);
+
+ fetch(endpointUrl, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ },
+ credentials: 'include',
+ })
+ .then(res => res.json())
+ .then(res => {
+ const templatesResponse : TtsInferenceResultListResponsePayload = res;
+ if (!templatesResponse.success) {
+ return;
+ }
+
+ setW2lResults(templatesResponse.results)
+ })
+ .catch(e => {
+ //this.props.onSpeakErrorCallback();
+ });
+ }, [props.username]); // NB: Empty array dependency sets to run ONLY on mount
+
+ let rows : Array = [];
+
+ w2lResults.forEach(result => {
+ let duration_seconds = result.duration_millis / 1000;
+ let templateTitle = result.template_title.length < 5 ? `Title: ${result.template_title}` : result.template_title;
+
+ let inferenceLink = `/w2l/result/${result.w2l_result_token}`;
+ let templateLink = `/w2l/${result.maybe_w2l_template_token}`;
+
+ rows.push(
+
+ | ▶️ Result |
+ {templateTitle} |
+ (custom audio) |
+ {duration_seconds} s |
+ {result.created_at} s |
+
+ );
+ });
+
+ return (
+
+
+
+
+ | Result Link |
+ Template |
+ Audio Source |
+ Duration |
+ Creation Date (UTC) |
+
+
+
+ {rows}
+
+
+
+ )
+}
+
+export { ProfileTtsInferenceResultsListFc };
diff --git a/vocodes/src/v2/profile/Profile_TtsModelListFc.tsx b/vocodes/src/v2/profile/Profile_TtsModelListFc.tsx
new file mode 100644
index 0000000000..7556d50f1a
--- /dev/null
+++ b/vocodes/src/v2/profile/Profile_TtsModelListFc.tsx
@@ -0,0 +1,136 @@
+import React, { useState, useEffect } from 'react';
+import { ApiConfig } from '../../v1/api/ApiConfig';
+import { Link } from "react-router-dom";
+import { getRandomInt } from '../../Utils';
+
+interface TtsModelListResponsePayload {
+ success: boolean,
+ templates: Array,
+}
+
+interface TtsModel {
+ template_token: string,
+ template_type: string,
+ creator_user_token: string,
+ username: string,
+ display_name: string,
+ updatable_slug: string,
+ title: string,
+ frame_width: number,
+ frame_height: number,
+ duration_millis: number,
+ maybe_image_object_name: string,
+ maybe_video_object_name: string,
+ created_at: string,
+ updated_at: string,
+}
+
+interface Props {
+ username: string,
+}
+
+function ProfileTtsModelListFc(props: Props) {
+ const [w2lTemplates, setTtsModels] = useState>([]);
+
+ useEffect(() => {
+ const api = new ApiConfig();
+ const endpointUrl = api.listW2lTemplatesForUser(props.username);
+
+ fetch(endpointUrl, {
+ method: 'GET',
+ headers: {
+ 'Accept': 'application/json',
+ },
+ credentials: 'include',
+ })
+ .then(res => res.json())
+ .then(res => {
+ const templatesResponse : TtsModelListResponsePayload = res;
+ if (!templatesResponse.success) {
+ return;
+ }
+
+ setTtsModels(templatesResponse.templates)
+ })
+ .catch(e => {
+ //this.props.onSpeakErrorCallback();
+ });
+ }, [props.username]); // NB: Empty array dependency sets to run ONLY on mount
+
+
+ let templateElements : Array = [];
+
+ w2lTemplates.forEach(t => {
+ let object = null;
+
+ if (t.maybe_image_object_name !== undefined && t.maybe_image_object_name !== null) {
+ object = t.maybe_image_object_name;
+ } else if (t.maybe_video_object_name !== undefined && t.maybe_video_object_name !== null) {
+ object = t.maybe_video_object_name;
+ } else {
+ console.warn(`No image for template ${t.template_token}`);
+ return;
+ }
+
+ let url = `https://storage.googleapis.com/dev-vocodes-public${object}`;
+
+ let link = `/w2l/${t.updatable_slug}`;
+
+ templateElements.push((
+
+
+ {/*One
*/}
+
+
+
+ ));
+ });
+
+ let allRowsOfTemplateElements : Array = [];
+ let rowOfTemplateElements : Array = [];
+
+ let nextRowSize = getRandomInt(3, 4);
+
+ // NB: To prevent React spamming about children having unique key props
+ let rowKey = "row0";
+ let rowIndex = 0;
+
+ templateElements.forEach(el => {
+ rowOfTemplateElements.push(el);
+
+ if (rowOfTemplateElements.length === nextRowSize) {
+ allRowsOfTemplateElements.push(
+
+ {rowOfTemplateElements.map(el => el)}
+
+ );
+ rowOfTemplateElements = [];
+ rowIndex += 1;
+ rowKey = `row${rowIndex}`;
+
+ // Don't have the same number on each row.
+ let lastRowSize = nextRowSize;
+ while (lastRowSize === nextRowSize) {
+ nextRowSize = getRandomInt(3, 6);
+ }
+ }
+ });
+
+ // Make sure last row is built.
+ if (rowOfTemplateElements.length !== 0) {
+ allRowsOfTemplateElements.push(
+
+ {rowOfTemplateElements.map(el => el)}
+
+ );
+ rowOfTemplateElements = [];
+ }
+
+ return (
+
+ {allRowsOfTemplateElements.map(el => el)}
+
+ )
+}
+
+export { ProfileTtsModelListFc };