-
-
- {upgradeNotice}
-
{results}
-
-
+
+ {upgradeNotice}
+
{results}
);
}
diff --git a/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.scss b/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.scss
index 675b4617f0..c4a4262cd5 100644
--- a/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.scss
+++ b/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.scss
@@ -1,37 +1,81 @@
@import "scss/colours.scss";
@import "scss/site-refresh.scss";
+.fy-featured-voices-section {
+ background-color: rgba($action, 0.25);
+ border-radius: 0.5rem;
+ padding: 20px;
+}
+
+.fy-featured-voices {
+ background-color: $secondary-light;
+ border-radius: 0.5rem;
+ padding: 0.6rem;
+ border: 2px solid $action;
+ cursor: pointer;
+ transition: all 0.2s;
+ user-select: none;
+ height: 100%;
+
+ &:hover {
+ border-color: $primary;
+ background-color: rgba($action, 0.7);
+ }
+
+ .fy-select-voice {
+ color: $white;
+ padding: 1px 8px;
+ background-color: lighten($action, 5%);
+ border-radius: 0.35rem;
+ font-size: 13px !important;
+ }
+}
+
.fy-weight-picker {
-
@include panel;
- border-radius: .5rem;
- background-color: rgba($secondary, .6);
+ border-radius: 0.5rem;
+ background-color: rgba($secondary, 0.6);
- &.fy-weight-picker-full {
- .fy-input input { border-radius: .5rem .5rem 0 0 }
- }
+ .fy-card-badge {
+ display: inline-flex;
+ margin-left: 0.5rem;
+ }
- .fy-weight-picker-preview {
- border-top: 1px solid rgba(#fff,.15);
- display: flex;
- }
+ .fy-input {
+ margin-bottom: 0;
+ }
+}
- .fy-card-badge {
- display: inline-flex;
- margin-left: .5rem;
- }
+.fy-weight-picker-preview {
+ border-radius: 0 0 0.5rem 0.5rem;
+ padding: 0.6rem;
+ background-color: rgba($action, 0.8);
+ border: 2px solid lighten($action, 12%);
+ display: flex;
+ align-items: center;
+ transition: all 0.2s;
+ cursor: pointer;
- .fy-input { margin-bottom: 0 }
+ &:hover {
+ background-color: rgba($action, 1);
+ border: 2px solid $primary;
+ }
+}
- .fy-weight-picker-reselect {
- background-color: $secondary-light;
- border-radius: .5rem;
- padding: .5rem;
- margin: 0 0 auto auto;
- }
+.fy-weight-picker-reselect {
+ background-color: $secondary;
+ border-radius: 0.5rem;
+ padding: 0.5rem;
+ margin: 0 0 auto auto;
+ transition: all 0.2s;
+ cursor: pointer;
+
+ &:hover {
+ background-color: $action;
+ }
}
.fy-card-badge {
- display: flex;
- height: min-content;
-}
\ No newline at end of file
+ display: flex;
+ height: min-content;
+}
diff --git a/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.tsx b/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.tsx
index 70bfd66bfb..a6561e3985 100644
--- a/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.tsx
+++ b/packages/fakeyou.com/src/v2/view/pages/dev_tts/DevTTS.tsx
@@ -1,39 +1,84 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
-import PageHeader from 'components/layout/PageHeader';
import { MediaBrowser } from "components/modals";
import { CardBadge } from "components/entities";
-import { Button, Container, Label, Panel, TempTextArea as TextArea, TempInput as Input, WeightCoverImage } from "components/common";
-import { useDebounce, useModal } from "hooks";
+import {
+ Button,
+ Container,
+ Input,
+ Label,
+ Panel,
+ TextArea,
+ WeightCoverImage,
+} from "components/common";
+import { useDebounce, useInferenceJobs, useModal } from "hooks";
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
import { Weight } from "@storyteller/components/src/api/weights/GetWeight";
-import { FontAwesomeIcon as Icon } from "@fortawesome/react-fontawesome";
-import { faRotateLeft, faSearch } from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import {
+ faArrowRight,
+ faBell,
+ faChevronRight,
+ faDeleteLeft,
+ faSearch,
+ faWaveformLines,
+ faXmark,
+} from "@fortawesome/pro-solid-svg-icons";
import "./DevTTS.scss";
+import { FeaturedVoice } from "./FeaturedVoice";
+import { SessionTtsInferenceResultList } from "v2/view/_common/SessionTtsInferenceResultsList";
+import StorytellerStudioCTA from "components/common/StorytellerStudioCTA";
+import { usePrefixedDocumentTitle } from "common/UsePrefixedDocumentTitle";
+import {
+ GenerateTtsAudio,
+ GenerateTtsAudioRequest,
+ GenerateTtsAudioResponse,
+ GenerateTtsAudioIsOk,
+} from "@storyteller/components/src/api/tts/GenerateTtsAudio";
+import { v4 as uuidv4 } from "uuid";
+import { WeightType } from "@storyteller/components/src/api/_common/enums";
+import useWeightTypeInfo from "hooks/useWeightTypeInfo";
+import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
interface Props {
- value?: any;
+ sessionSubscriptionsWrapper: any;
}
-export default function DevTTS({ value }: Props) {
+export default function DevTTS({ sessionSubscriptionsWrapper }: Props) {
+ const { enqueueInferenceJob } = useInferenceJobs();
const { modalState, open } = useModal();
- const [search,searchSet] = useState("");
- const [updated,updatedSet] = useState(false);
- const [selectedVoice,selectedVoiceSet] = useState
();
- const [text,textSet] = useState("");
+ const [search, searchSet] = useState("");
+ const [updated, updatedSet] = useState(false);
+ const [selectedVoice, selectedVoiceSet] = useState();
+ const [text, textSet] = useState("");
const bucketConfig = new BucketConfig();
- const preview = bucketConfig.getCdnUrl(selectedVoice?.cover_image?.maybe_cover_image_public_bucket_path || "");
-
+ const preview = selectedVoice?.cover_image
+ ?.maybe_cover_image_public_bucket_path
+ ? bucketConfig.getCdnUrl(
+ selectedVoice?.cover_image?.maybe_cover_image_public_bucket_path
+ )
+ : "/images/avatars/default-pfp.png";
const textChange = ({ target }: { target: any }) => {
textSet(target.value);
};
+ const [isGenerating, setIsGenerating] = useState(false);
+ usePrefixedDocumentTitle(
+ selectedVoice
+ ? selectedVoice.title + " Text to Speech"
+ : "FakeYou. Deep Fake Text to Speech."
+ );
- const searchChange = (setUpdate = true) => ({ target }: { target: any }) => {
- // console.log("🩵",target.value);
- if (setUpdate) updatedSet(true);
- // console.log("aaaa",);
- searchSet(target.value);
- };
+ const weightTypeInfo = useWeightTypeInfo(
+ selectedVoice?.weight_type || WeightType.NONE
+ );
+ const { label: weightType, color: weightTagColor } = weightTypeInfo;
+
+ const searchChange =
+ (setUpdate = true) =>
+ ({ target }: { target: any }) => {
+ if (setUpdate) updatedSet(true);
+ searchSet(target.value);
+ };
useDebounce({
blocked: !(updated && !modalState && search),
@@ -45,47 +90,257 @@ export default function DevTTS({ value }: Props) {
onSelect: (weight: any) => selectedVoiceSet(weight),
inputMode: 3,
onSearchChange: searchChange(false),
- search
- }
+ search,
+ },
});
- }
+ },
});
- return
-
-
-
-
-
- {
- selectedVoice &&
-
-
-
- { selectedVoice.title }
-
-
-
- by
-
- {
- " " + selectedVoice.creator?.display_name || ""
- }
-
-
+ const openModal = () => {
+ open({
+ component: MediaBrowser,
+ props: {
+ onSelect: (weight: any) => selectedVoiceSet(weight),
+ inputMode: 3,
+ onSearchChange: searchChange(false),
+ search,
+ accept: ["tts"],
+ title: "Select a Voice",
+ },
+ });
+ };
-
-
-
- }
-
- { selectedVoice && }
- {
- text &&
+ const featuredVoiceTokens = [
+ "weight_31ewdsvev9bttgb4eg7zy7mj5",
+ "weight_b8rncypy7gw6nb0wthnwe2kk4",
+ "weight_3k28fws0v6r1ke3p0w0vw48gm",
+ "weight_0f762jdzgsy1dhpb86qxy4ssm",
+ "weight_1ptwk6pa8krh3ykfr7rztf3pz",
+ "weight_b8rncypy7gw6nb0wthnwe2kk4",
+ "weight_3k28fws0v6r1ke3p0w0vw48gm",
+ "weight_0f762jdzgsy1dhpb86qxy4ssm",
+ ];
+
+ const handleSpeak = async () => {
+ if (!selectedVoice || !text) return;
+
+ setIsGenerating(true);
+
+ const request: GenerateTtsAudioRequest = {
+ uuid_idempotency_token: uuidv4(),
+ tts_model_token: selectedVoice.weight_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);
}
-
- ;
-};
\ No newline at end of file
+ } catch (error) {
+ console.error("Unexpected error:", error);
+ setIsGenerating(false);
+ }
+ };
+
+ return (
+ <>
+
+
+ Text to Speech
+
+ Make your favorite characters speak!
+
+
+
+
+
Featured Voices
+
+ {featuredVoiceTokens.map(token => (
+
+ ))}
+
+
+
+
+
+
+
+ {!selectedVoice && (
+
+ )}
+
+
+
+
+
+
+
+ {selectedVoice && (
+
+ )}
+
+
+
+
+
+
+ {search && (
+ searchSet("")}
+ />
+ )}
+
+
+
+
+
+
{selectedVoice?.title || "No Voice Selected"}
+
+ {selectedVoice?.weight_type && (
+
+ )}
+
+ {selectedVoice ? (
+
+
+ by
+ e.stopPropagation()}
+ >
+ {" " + selectedVoice?.creator?.display_name || ""}
+
+
+
+ {/* |
+ English */}
+
+
+ |
+
+ e.stopPropagation()}
+ >
+ View voice details
+
+
+
+
+ ) : (
+
+ Click to select a voice
+
+ )}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {/* */}
+ .
+
+ >
+ );
+}
diff --git a/packages/fakeyou.com/src/v2/view/pages/dev_tts/FeaturedVoice.tsx b/packages/fakeyou.com/src/v2/view/pages/dev_tts/FeaturedVoice.tsx
new file mode 100644
index 0000000000..85eb4667e7
--- /dev/null
+++ b/packages/fakeyou.com/src/v2/view/pages/dev_tts/FeaturedVoice.tsx
@@ -0,0 +1,81 @@
+import { WeightType } from "@storyteller/components/src/api/_common/enums";
+import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
+import LoadingSpinner from "components/common/LoadingSpinner";
+import WeightCoverImage from "components/common/WeightCoverImage";
+import { CardBadge } from "components/entities";
+import { useWeightFetch } from "hooks";
+import useWeightTypeInfo from "hooks/useWeightTypeInfo";
+import React, { useState } from "react";
+import { Link } from "react-router-dom";
+
+interface FeaturedVoiceProps {
+ token: string;
+ onClick?: (weight: any) => void;
+}
+
+export const FeaturedVoice = ({ token, onClick }: FeaturedVoiceProps) => {
+ const weight_token = token;
+ const fetchedWeight = useWeightFetch({
+ onSuccess: () => setIsLoading(false),
+ token: weight_token,
+ });
+
+ const { data: weight } = fetchedWeight;
+
+ const bucketConfig = new BucketConfig();
+
+ const weightTypeInfo = useWeightTypeInfo(
+ weight?.weight_type || WeightType.NONE
+ );
+ const { label: weightType, color: weightTagColor } = weightTypeInfo;
+
+ const coverImage = weight?.cover_image?.maybe_cover_image_public_bucket_path
+ ? bucketConfig.getCdnUrl(
+ weight?.cover_image?.maybe_cover_image_public_bucket_path
+ )
+ : "/images/avatars/default-pfp.png";
+
+ const [isLoading, setIsLoading] = useState(true);
+
+ return (
+
+
onClick && weight && onClick(weight)}
+ style={{ height: "74px" }}
+ >
+ {isLoading ? (
+
+
+
+ ) : (
+ <>
+
+
+
+ {weight?.title}
+
+
+
+ by{" "}
+
+ {weight?.creator.display_name}
+
+
+
+
+ Use
+
+ >
+ )}
+
+
+ );
+};