mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-10 20:11:49 +00:00
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:
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"
|
||||
}
|
||||
}
|
||||
}
|
||||
+8
-8
@@ -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>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user