Merge pull request #224 from storytold/bflat-fy-landing-update

Bflat fy landing update
This commit is contained in:
Brandon Thomas authored and GitHub committed 2023-04-26 21:49:23 -07:00
commit b36fbbb3b9
5 files changed
+317 -51

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 10 KiB

@@ -1076,6 +1076,55 @@ styles with important tags:
pointer-events: none;
}
.upload-component {
overflow-x: hidden;
overflow-y: auto;
overscroll-behavior: contain;
.panel {
box-shadow: none !important;
}
.upload-zone {
height: 100%;
border: dashed 2px rgba($white, 0.12) !important;
border-radius: 0.5rem;
transition: 0.1s all;
&:hover {
background-color: lighten($panel, 6%);
cursor: pointer;
}
}
.upload-zone-drag {
background-color: $white !important;
}
.filename {
display: block;
max-width: 230px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.supported-files {
font-size: 12px;
}
.upload-icon {
font-size: 42px;
}
}
.nav-vc {
flex-wrap: nowrap;
height: auto;
overflow-y: hidden;
overflow-x: auto;
}
.video-container {
border: 2px solid;
border-color: #ffffff20;
@@ -1323,7 +1372,7 @@ textarea {
}
.lead {
font-size: 20px;
font-size: 18px;
}
.alert {
@@ -13,6 +13,7 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { faDiscord, faTwitter } from "@fortawesome/free-brands-svg-icons";
import { WebUrl } from "../../../../common/WebUrl";
import { faMicrophone, faRightLeft } from "@fortawesome/pro-solid-svg-icons";
// import { Analytics } from "../../../../../common/Analytics";
interface Props {
@@ -97,7 +98,7 @@ function LandingPage(props: Props) {
return (
<motion.div initial="hidden" animate="visible" variants={container}>
<div className="container pb-md-5 pt-lg-5 mb-4 px-md-5 px-lg-5 px-xl-3">
<div className="container pb-5 pb-lg-0 pt-lg-2 px-md-5 px-lg-5 px-xl-3">
<div className="row flex-md-row-reverse">
<div className="col-12 col-lg-5 p-md-0 d-flex justify-content-center">
<img
@@ -108,10 +109,10 @@ function LandingPage(props: Props) {
/>
</div>
<div className="col-12 col-lg-7 d-flex flex-column justify-content-center flex-reverse px-md-5 px-lg-3">
<h1 className="fw-bold display-4 text-center text-lg-start px-md-5 px-lg-0">
<h1 className="fw-bold display-5 text-center text-lg-start px-md-5 px-lg-0">
Text to Speech, Voice Conversion & AI Tools
</h1>
<p className="lead opacity-75 pb-4 text-center text-lg-start px-md-5 px-lg-0">
<p className="lead opacity-75 pb-4 text-center text-lg-start px-md-5 px-lg-0 pe-lg-5">
Generate audio or videos of your favorite characters saying
anything you want with FakeYou's deep fake tech.
</p>
@@ -125,6 +126,175 @@ function LandingPage(props: Props) {
</div>
</div>
<div className="container-panel pb-5 mb-5">
<div className="panel p-3 py-4 p-md-4">
<div className="d-flex gap-4">
<form
className="w-100 d-flex flex-column"
// onSubmit={handleFormSubmit}
>
<div className="row gx-5 gy-5">
<div className="col-12 d-flex flex-column gap-4">
<div>
<label className="sub-title">
Choose Target Voice (xxx to choose from)
</label>
<div className="input-icon-search pb-4">
<span className="form-control-feedback">
<FontAwesomeIcon icon={faMicrophone} />
</span>
{/* <VcModelListSearch
voiceConversionModels={props.voiceConversionModels}
setVoiceConversionModels={props.setVoiceConversionModels}
maybeSelectedVoiceConversionModel={
props.maybeSelectedVoiceConversionModel
}
setMaybeSelectedVoiceConversionModel={interceptModelChange}
/> */}
</div>
</div>
<ul className="nav nav-tabs nav-vc" id="myTab" role="tablist">
<li className="nav-item w-100" role="presentation">
<button
className="nav-link active w-100"
id="prerecorded-tab"
data-bs-toggle="tab"
data-bs-target="#prerecorded"
type="button"
role="tab"
aria-controls="prerecorded"
aria-selected="true"
>
Pre-recorded
</button>
</li>
<li className="nav-item w-100" role="presentation">
<button
className="nav-link w-100"
id="recordaudio-tab"
data-bs-toggle="tab"
data-bs-target="#recordaudio"
type="button"
role="tab"
aria-controls="recordaudio"
aria-selected="false"
>
Microphone
</button>
</li>
</ul>
<div className="tab-content" id="myTabContent">
<div
className="tab-pane fade show active"
id="prerecorded"
role="tabpanel"
aria-labelledby="prerecorded-tab"
>
<div className="d-flex flex-column gap-4 h-100">
<div>
<label className="sub-title">
Upload Input Audio
</label>
<div className="d-flex flex-column gap-3 upload-component">
{/* <UploadComponent
setMediaUploadToken={setMediaUploadToken}
formIsCleared={formIsCleared}
setFormIsCleared={setFormIsCleared}
setCanConvert={setCanConvert}
changeConvertIdempotencyToken={
changeConvertIdempotencyToken
}
/> */}
</div>
</div>
{/*<div>
<label className="sub-title">
Or pick from your audio collection (5 files)
</label>
<div className="d-flex flex-column gap-3">
<div className="input-icon-search">
<span className="form-control-feedback">
<FontAwesomeIcon icon={faFiles} />
</span>
<Select
value="test"
classNames={SearchFieldClass}
// On mobile, we don't want the onscreen keyboard to take up half the UI.
autoFocus={false}
isSearchable={false}
// NB: The following settings improve upon performance.
// See: https://github.com/JedWatson/react-select/issues/3128
filterOption={createFilter({
ignoreAccents: false,
})}
/>
</div>
</div>
</div>*/}
<div>
<label className="sub-title">Convert Audio</label>
<div className="d-flex gap-3">
<button className="btn btn-primary w-100">
<FontAwesomeIcon
icon={faRightLeft}
className="me-2"
/>
Convert
</button>
</div>
</div>
</div>
</div>
<div
className="tab-pane fade"
id="recordaudio"
role="tabpanel"
aria-labelledby="recordaudio-tab"
>
<div className="d-flex flex-column gap-4 h-100">
<div>
<label className="sub-title">Record Audio</label>
<div className="d-flex flex-column gap-3 upload-component">
{/* <RecordComponent
setMediaUploadToken={setMediaUploadToken}
formIsCleared={formIsCleared}
setFormIsCleared={setFormIsCleared}
setCanConvert={setCanConvert}
changeConvertIdempotencyToken={
changeConvertIdempotencyToken
}
/> */}
</div>
</div>
<div>
<label className="sub-title">Convert Audio</label>
<div className="d-flex gap-3">
<button className="btn btn-primary w-100">
<FontAwesomeIcon
icon={faRightLeft}
className="me-2"
/>
Convert
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
</div>
</div>
<div className="container pt-3 pt-md-0 pb-5 px-md-5 px-xl-3">
<h2 className="fw-bold mb-4">AI Tools</h2>
<div className="row g-4 position-relative">
@@ -153,7 +323,7 @@ function LandingPage(props: Props) {
<div className="panel panel-select d-flex flex-column align-items-center">
<div className="d-flex px-4 pt-4 align-items-center w-100">
<div className="flex-grow-1">
<h3 className="fw-bold text-white mb-1">Voice Conversion</h3>
<h3 className="fw-bold text-white mb-1">Voice to Voice</h3>
<h6 className="fw-normal opacity-75 text-white">
Speak as someone else
</h6>
@@ -228,21 +398,24 @@ function LandingPage(props: Props) {
<div className="col-12 col-md-6 col-lg-5 d-flex flex-column justify-content-center gap-3">
<h2 className="fw-bold">Make your favorite characters talk</h2>
<p className="opacity-75">
Our AI-powered text to speech service lets you choose your
favorite character's voice and input any text to hear them say it.
Our AI-powered text-to-speech and voice transformer tools let you
convert your text or voice into your favorite character's voice.
Perfect for content creators and anyone looking to add personality
to their messages.
</p>
<div className="d-flex mt-3">
<div className="d-flex mt-3 gap-3">
<Link to="/tts" className="btn btn-primary">
Generate text-to-speech
Text-to-Speech
</Link>
<Link to="/tts" className="btn btn-primary">
Voice Transformer
</Link>
</div>
</div>
</div>
</div>
<div className="container section px-md-5 px-xl-3">
{/* <div className="container section px-md-5 px-xl-3">
<div className="row g-4 g-lg-5">
<div className="col-12 col-md-6 col-lg-7">
<div className="position-relative">
@@ -278,7 +451,7 @@ function LandingPage(props: Props) {
</div>
</div>
</div>
</div>
</div> */}
<div className="d-flex flex-column section align-items-center panel rounded-0 my-5">
<div className="d-flex flex-column align-items-center text-center cta-container">
@@ -14,11 +14,21 @@ import {
import UploadComponent from "./components/UploadComponent";
import RecordComponent from "./components/RecordComponent";
import { usePrefixedDocumentTitle } from "../../../../../common/UsePrefixedDocumentTitle";
import { ListVoiceConversionModels, VoiceConversionModelListItem } from "@storyteller/components/src/api/voice_conversion/ListVoiceConversionModels";
import {
ListVoiceConversionModels,
VoiceConversionModelListItem,
} from "@storyteller/components/src/api/voice_conversion/ListVoiceConversionModels";
import { VcModelListSearch } from "./components/VcModelListSearchComponent";
import { EnqueueVoiceConversion, EnqueueVoiceConversionIsSuccess, EnqueueVoiceConversionRequest } from "@storyteller/components/src/api/voice_conversion/EnqueueVoiceConversion";
import {
EnqueueVoiceConversion,
EnqueueVoiceConversionIsSuccess,
EnqueueVoiceConversionRequest,
} from "@storyteller/components/src/api/voice_conversion/EnqueueVoiceConversion";
import { Analytics } from "../../../../../common/Analytics";
import { FrontendInferenceJobType, InferenceJob } from "@storyteller/components/src/jobs/InferenceJob";
import {
FrontendInferenceJobType,
InferenceJob,
} from "@storyteller/components/src/jobs/InferenceJob";
import { SessionVoiceConversionResultsList } from "../../../_common/SessionVoiceConversionResultsList";
interface Props {
@@ -26,12 +36,19 @@ interface Props {
sessionSubscriptionsWrapper: SessionSubscriptionsWrapper;
voiceConversionModels: Array<VoiceConversionModelListItem>;
setVoiceConversionModels: (ttsVoices: Array<VoiceConversionModelListItem>) => void;
setVoiceConversionModels: (
ttsVoices: Array<VoiceConversionModelListItem>
) => void;
maybeSelectedVoiceConversionModel?: VoiceConversionModelListItem;
setMaybeSelectedVoiceConversionModel: (maybeSelectedVoiceConversionModel: VoiceConversionModelListItem) => void;
setMaybeSelectedVoiceConversionModel: (
maybeSelectedVoiceConversionModel: VoiceConversionModelListItem
) => void;
enqueueInferenceJob: (jobToken: string, frontendInferenceJobType: FrontendInferenceJobType) => void;
enqueueInferenceJob: (
jobToken: string,
frontendInferenceJobType: FrontendInferenceJobType
) => void;
inferenceJobs: Array<InferenceJob>;
inferenceJobsByCategory: Map<FrontendInferenceJobType, Array<InferenceJob>>;
}
@@ -41,9 +58,13 @@ function VcModelListPage(props: Props) {
const [canConvert, setCanConvert] = useState(false);
const [mediaUploadToken, setMediaUploadToken] = useState<string|undefined>(undefined);
const [mediaUploadToken, setMediaUploadToken] = useState<string | undefined>(
undefined
);
const [convertIdempotencyToken, setConvertIdempotencyToken] = useState(uuidv4());
const [convertIdempotencyToken, setConvertIdempotencyToken] = useState(
uuidv4()
);
// NB: Something of a UI hack here.
// The 3rd party microphone component doesn't let you clear it, so we emulate form clearing
@@ -90,32 +111,48 @@ function VcModelListPage(props: Props) {
const changeConvertIdempotencyToken = () => {
setConvertIdempotencyToken(uuidv4());
}
};
const interceptModelChange = (maybeSelectedVoiceConversionModel: VoiceConversionModelListItem) => {
if (maybeSelectedVoiceConversionModel !== props.maybeSelectedVoiceConversionModel) {
const interceptModelChange = (
maybeSelectedVoiceConversionModel: VoiceConversionModelListItem
) => {
if (
maybeSelectedVoiceConversionModel !==
props.maybeSelectedVoiceConversionModel
) {
changeConvertIdempotencyToken();
}
props.setMaybeSelectedVoiceConversionModel(maybeSelectedVoiceConversionModel);
}
props.setMaybeSelectedVoiceConversionModel(
maybeSelectedVoiceConversionModel
);
};
const handleVoiceConversion = async () => {
if (props.maybeSelectedVoiceConversionModel === undefined || mediaUploadToken === undefined) {
if (
props.maybeSelectedVoiceConversionModel === undefined ||
mediaUploadToken === undefined
) {
return;
}
let request : EnqueueVoiceConversionRequest = {
let request: EnqueueVoiceConversionRequest = {
uuid_idempotency_token: convertIdempotencyToken,
voice_conversion_model_token: props.maybeSelectedVoiceConversionModel.token,
voice_conversion_model_token:
props.maybeSelectedVoiceConversionModel.token,
source_media_upload_token: mediaUploadToken,
};
Analytics.voiceConversionGenerate(props.maybeSelectedVoiceConversionModel.token);
Analytics.voiceConversionGenerate(
props.maybeSelectedVoiceConversionModel.token
);
let result = await EnqueueVoiceConversion(request);
if (EnqueueVoiceConversionIsSuccess(result)) {
props.enqueueInferenceJob(result.inference_job_token, FrontendInferenceJobType.VoiceConversion);
props.enqueueInferenceJob(
result.inference_job_token,
FrontendInferenceJobType.VoiceConversion
);
}
};
@@ -129,9 +166,10 @@ function VcModelListPage(props: Props) {
? "btn btn-primary w-100 disabled"
: "btn btn-primary w-100";
const enableConvertButton = canConvert
&& mediaUploadToken !== undefined
&& props.maybeSelectedVoiceConversionModel !== undefined;
const enableConvertButton =
canConvert &&
mediaUploadToken !== undefined &&
props.maybeSelectedVoiceConversionModel !== undefined;
return (
<motion.div initial="hidden" animate="visible" variants={container}>
@@ -149,7 +187,8 @@ function VcModelListPage(props: Props) {
>
{/* Explore Rollout */}
<label className="sub-title">
Choose Target Voice ({voiceConversionModels.length} to choose from)
Choose Target Voice ({voiceConversionModels.length} to choose
from)
</label>
<div className="input-icon-search pb-4">
<span className="form-control-feedback">
@@ -159,10 +198,11 @@ function VcModelListPage(props: Props) {
<VcModelListSearch
voiceConversionModels={props.voiceConversionModels}
setVoiceConversionModels={props.setVoiceConversionModels}
maybeSelectedVoiceConversionModel={props.maybeSelectedVoiceConversionModel}
maybeSelectedVoiceConversionModel={
props.maybeSelectedVoiceConversionModel
}
setMaybeSelectedVoiceConversionModel={interceptModelChange}
/>
/>
</div>
<div className="row gx-5 gy-5">
@@ -210,12 +250,14 @@ function VcModelListPage(props: Props) {
Upload Input Audio
</label>
<div className="d-flex flex-column gap-3 upload-component">
<UploadComponent
<UploadComponent
setMediaUploadToken={setMediaUploadToken}
formIsCleared={formIsCleared}
setFormIsCleared={setFormIsCleared}
setCanConvert={setCanConvert}
changeConvertIdempotencyToken={changeConvertIdempotencyToken}
changeConvertIdempotencyToken={
changeConvertIdempotencyToken
}
/>
</div>
</div>
@@ -247,9 +289,7 @@ function VcModelListPage(props: Props) {
</div>*/}
<div>
<label className="sub-title">
Convert Audio
</label>
<label className="sub-title">Convert Audio</label>
<div className="d-flex gap-3">
<button
@@ -267,7 +307,6 @@ function VcModelListPage(props: Props) {
</button>
</div>
</div>
</div>
</div>
<div
@@ -280,20 +319,20 @@ function VcModelListPage(props: Props) {
<div>
<label className="sub-title">Record Audio</label>
<div className="d-flex flex-column gap-3 upload-component">
<RecordComponent
<RecordComponent
setMediaUploadToken={setMediaUploadToken}
formIsCleared={formIsCleared}
setFormIsCleared={setFormIsCleared}
setCanConvert={setCanConvert}
changeConvertIdempotencyToken={changeConvertIdempotencyToken}
changeConvertIdempotencyToken={
changeConvertIdempotencyToken
}
/>
</div>
</div>
<div>
<label className="sub-title">
Convert Audio
</label>
<label className="sub-title">Convert Audio</label>
<div className="d-flex gap-3">
<button
@@ -311,7 +350,6 @@ function VcModelListPage(props: Props) {
</button>
</div>
</div>
</div>
</div>
</div>
@@ -326,9 +364,15 @@ function VcModelListPage(props: Props) {
Session VC Results
</h4>
<div className="d-flex flex-column gap-3 session-tts-section">
<SessionVoiceConversionResultsList
inferenceJobs={props.inferenceJobsByCategory.get(FrontendInferenceJobType.VoiceConversion)!}
sessionSubscriptionsWrapper={props.sessionSubscriptionsWrapper}
<SessionVoiceConversionResultsList
inferenceJobs={
props.inferenceJobsByCategory.get(
FrontendInferenceJobType.VoiceConversion
)!
}
sessionSubscriptionsWrapper={
props.sessionSubscriptionsWrapper
}
/>
</div>
</div>