Merge pull request #701 from storytold/feature/new-trump-tts

added new Trump tts page, removed wrapper div in PageContainer
This commit is contained in:
Victor O authored and GitHub committed 2024-09-12 11:34:45 -07:00
commit 889db40215
9 files changed
+906 -627

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

@@ -16,7 +16,10 @@
"output": "Output",
"search": "Search for a Voice",
"select": "Select a Voice",
"selected": "Selected Voice"
"selected": "Selected Voice",
"trumpAngry": "angry",
"trumpCasual": "casual",
"trumpSarcastic": "sarcastic"
},
"link": {
"exploreNewVoices": "Explore Newest Voices",
@@ -50,4 +53,4 @@
"featuredVoices": "Featured Voices",
"tts": "Text to Speech"
}
}
}
@@ -2,16 +2,16 @@
/* Toggle Styles */
#wrapper {
padding-left: 0;
-webkit-transition: all 0.2s ease;
-moz-transition: all 0.2s ease;
-o-transition: all 0.2s ease;
transition: all 0.2s ease;
}
$topbar-height: 66px;
#wrapper {
padding: $topbar-height 0 0;
// -webkit-transition: all 0.2s ease;
// -moz-transition: all 0.2s ease;
// -o-transition: all 0.2s ease;
// transition: all 0.2s ease;
}
#profile-sidebar-wrapper {
z-index: 999;
position: fixed;
File diff suppressed because it is too large. Load diff
@@ -97,3 +97,60 @@
display: flex;
height: min-content;
}
.fy-trump-select {
// background-color: red;
height: 10rem;
margin-bottom: 1rem;
display: flex;
// display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 1rem;
button {
flex-grow: 1;
background: $secondary;
appearance: none;
color: #fff;
outline: none;
border-radius: 0.5rem;
border: 2px solid $secondary;
overflow: hidden;
padding: 0;
display: flex;
// justify-content: center;
// align-items: center;
position: relative;
&.fy-selected-trump {
border-color: $primary;
}
img {
border-radius: 0.25rem;
width: 100%;
height: auto;
position: absolute;
top: 50%;
left: 50%;
opacity: 0.45;
transform: translate(-50%, -50%);
transition: 0.25s all;
}
&:hover img {
transform: translate(-50%, -50%) scale(1.05);
opacity: 0.66;
}
b {
position: absolute;
color: rgba(#fff, 0.66);
font-size: 1.125rem;
height: 1em;
line-height: 1em;
margin: 0.5rem auto auto 0.5rem;
}
}
}
@@ -0,0 +1,181 @@
import React, { useState } from "react";
import { Button, Container, Label, Panel, TextArea } from "components/common";
import { useInferenceJobs, useLocalize, useSession } from "hooks";
import {
faVolumeHigh,
faDeleteLeft,
faWaveformLines,
} from "@fortawesome/pro-solid-svg-icons";
import "../AudioGen.scss";
import { SessionTtsInferenceResultList } from "v2/view/_common/SessionTtsInferenceResultsList";
import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
import {
GenerateTtsAudio,
GenerateTtsAudioRequest,
GenerateTtsAudioResponse,
GenerateTtsAudioIsOk,
} from "@storyteller/components/src/api/tts/GenerateTtsAudio";
import { v4 as uuidv4 } from "uuid";
import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
import { isMobile } from "react-device-detect";
import { useTtsStore } from "hooks";
import { AITools } from "components/marketing";
import { getLocalStorageItem, setLocalStorageItem } from "utils/localStorage";
import PageHeaderWithImage from "components/layout/PageHeaderWithImage";
import TrumpSelect, { TrumpOption } from "./TrumpSelect";
export default function NewTTS() {
const { enqueueInferenceJob } = useInferenceJobs();
const { loggedIn, loggedInOrModal, sessionSubscriptions } = useSession();
const [trumpOption, trumpOptionSet] = useState<TrumpOption>({
trump: "angry",
token: "weight_x6r5w2tsxgcrrsgweva6dkrqj",
});
const { text, setText } = useTtsStore();
const textChange = ({ target }: { target: any }) => {
setText(target.value);
};
const [isGenerating, setIsGenerating] = useState(false);
usePrefixedDocumentTitle("FakeYou. Deep Fake Text to Speech.");
const { t } = useLocalize("NewTTS");
const cap = (string: string) =>
string.charAt(0).toUpperCase() + string.slice(1);
const handleSpeak = async (ev: React.FormEvent<HTMLFormElement>) => {
ev.preventDefault();
const generationCountKey = "generationCountTTS";
const promptShownKey = "promptShownTTS";
const ttl = 2 * 60 * 1000; // 2 minutes in milliseconds
let generationCount = parseInt(
getLocalStorageItem(generationCountKey) || "0"
);
const promptShown = getLocalStorageItem(promptShownKey);
// Show sign up prompt after 2 generations, and dont show again until local storage expires
if (!loggedIn && generationCount >= 2 && !promptShown) {
loggedInOrModal({
loginMessage: "Login to keep your generated audio history",
signupMessage: "Sign up to keep your generated audio history",
});
setLocalStorageItem(promptShownKey, "true", ttl);
}
if (!text) return;
setIsGenerating(true);
const request: GenerateTtsAudioRequest = {
uuid_idempotency_token: uuidv4(),
tts_model_token: trumpOption.token,
inference_text: text,
};
try {
const response: GenerateTtsAudioResponse =
await GenerateTtsAudio(request);
if (GenerateTtsAudioIsOk(response)) {
console.log("TTS queued successfully:", response.inference_job_token);
enqueueInferenceJob(
response.inference_job_token,
FrontendInferenceJobType.TextToSpeech
);
setIsGenerating(false);
} else {
console.error("Error queuing TTS:", response.error);
setIsGenerating(false);
}
} catch (error) {
// @ts-ignore
window.dataLayer.push({
event: "enqueue_failure",
page: "/tts",
user_id: "$user_id",
});
console.error("Unexpected error:", error);
setIsGenerating(false);
}
generationCount += 1;
setLocalStorageItem(generationCountKey, generationCount.toString(), ttl);
};
return (
<>
<Container type="panel" className="mt-3 mt-lg-5">
<PageHeaderWithImage
headerImage="/mascot/trump.webp"
titleIcon={faVolumeHigh}
title="Donald Trump TTS"
subText="FakeYou has the very best Donald Trump AI voice on the internet. Use deep
fake Donald Trump to say your favorite memes."
yOffset="60%"
/>
<Panel padding={true}>
<Label {...{ label: "Select a trump voice" }} />
<TrumpSelect {...{ cap, t, trumpOptionSet, value: trumpOption }} />
<form onSubmit={handleSpeak}>
<div className="d-flex flex-column gap-3">
<div className="row">
<div className="d-flex flex-column gap-3 col-12 col-lg-6">
<TextArea
autoFocus={true}
label={t("label.enterText")}
onChange={textChange}
value={text}
rows={isMobile ? 5 : 13}
placeholder={t("input.textPlaceholder", {
character: `${t(
"label.trump" + cap(trumpOption.trump)
)} Trump`,
})}
resize={false}
/>
<div className="d-flex justify-content-end gap-2">
<Button
icon={faDeleteLeft}
label={t("button.clear")}
disabled={!text}
variant="secondary"
onClick={() => setText("")}
/>
<Button
icon={faWaveformLines}
label={t("button.speak")}
type="submit"
disabled={!text}
isLoading={isGenerating}
/>
</div>
</div>
<div className="col-12 col-lg-6">
<div className="d-flex flex-column">
<Label label={t("label.output")} />
<div className="d-flex flex-column session-tts-section">
{sessionSubscriptions ? (
<SessionTtsInferenceResultList
sessionSubscriptionsWrapper={sessionSubscriptions}
/>
) : null}
</div>
</div>
</div>
</div>
</div>
</form>
</Panel>
</Container>
<Container type="panel" className="pt-5 mt-5">
<Panel clear={true}>
<h2 className="fw-bold mb-3">Try our other AI tools</h2>
<AITools />
</Panel>
{/* <MentionsSection /> */}
{/* <StorytellerStudioCTA /> */}
</Container>
</>
);
}
@@ -0,0 +1,64 @@
import React from "react";
import { TFunction } from "i18next";
export interface TrumpOption {
trump: string;
token: string;
}
interface TrumpSelectProps {
cap: (string: string) => string;
t: TFunction;
trumpOptionSet: (trumpOption: TrumpOption) => void;
value: TrumpOption;
}
export default function TrumpSelect({
cap,
t,
trumpOptionSet,
value,
}: TrumpSelectProps) {
const trumpOptions: TrumpOption[] = [
{
trump: "angry",
token: "weight_x6r5w2tsxgcrrsgweva6dkrqj",
},
{
trump: "casual",
token: "weight_vrx7j407cxk45jenkrd769h9b",
},
{
trump: "sarcastic",
token: "weight_jazc270pdr3qe0yer61a5cvh5",
},
];
return (
<div
{...{
className: "fy-trump-select",
}}
>
{trumpOptions.map((trumpOption: TrumpOption) => (
<button
{...{
className:
trumpOption.token === value.token ? "fy-selected-trump" : "",
onClick: () => trumpOptionSet(trumpOption),
}}
>
<img
{...{
alt: `Trump ${trumpOption.trump} voice`,
height: 640,
width: 640,
src: `/images/trump-select/trump-${trumpOption.trump}.webp`,
}}
/>
<b>{cap(t("label.trump" + cap(trumpOption.trump)))}</b>
</button>
))}
</div>
);
}