Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp

This commit is contained in:
Victor committed 2024-02-12 12:17:19 -08:00
commit 90e64a72fe
28 files changed
+440 -273

No files matched your search

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

@@ -1,4 +1,6 @@
{
"alertTtiCta": "এটা এখন চেষ্টা কর",
"alertTtiText": "আপনি কি আমাদের নতুন টেক্সট টু ইমেজ চেষ্টা করেছেন? আপনার টেক্সট প্রম্পটকে ইমেজে পরিণত করুন!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "আমরা আপনার সাথে চ্যাট করতে চাই! আপনার কোন প্রশ্ন থাকলে অনুগ্রহ করে আমাদের সাথে ডিসকর্ডে যোগ দিন।",
@@ -19,12 +21,14 @@
"heroTitle": "এআই মিউজিক, টেক্সট টু স্পিচ এবং ভয়েস টু ভয়েস",
"productFaceAnimatorText": "অডিও দিয়ে মুখগুলোকে অ্যানিমেট করুন",
"productFaceAnimatorTitle": "ফেস অ্যানিমেটর",
"productImageGenText": "পাঠ্য থেকে ছবি তৈরি করুন",
"productImageGenTitle": "টেক্সট টু ইমেজ",
"productNewTag": "নতুন",
"productTtsText": "পাঠ্য থেকে অডিও তৈরি করুন",
"productTtsTitle": "টেক্সট টু স্পিচ",
"productVcText": "অন্য কণ্ঠে কথা বলুন",
"productVcTitle": "ভয়েস টু ভয়েস",
"productVideoText": "ঠোঁট সিঙ্ক ভিডিও অডিও",
"productVideoTitle": "ভিডিও লিপ সিঙ্ক",
"productVdText": "আপনার নিজস্ব AI ভয়েস তৈরি করুন",
"productVdTitle": "ভয়েস ডিজাইনার",
"productsTitle": "এআই টুলস"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Probieren Sie es jetzt",
"alertTtiText": "Haben Sie schon unseren neuen Text to Image ausprobiert? Verwandeln Sie Ihre Textaufforderungen in Bilder!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Wir würden uns freuen, mit Ihnen zu chatten! Bitte treten Sie uns im Discord bei, wenn Sie Fragen haben.",
@@ -19,12 +21,14 @@
"heroTitle": "KI-Musik, Text-to-Speech und Voice-to-Voice",
"productFaceAnimatorText": "Animieren Sie Gesichter mit Audio",
"productFaceAnimatorTitle": "Gesichtsanimator",
"productImageGenText": "Erstellen Sie Bilder aus Text",
"productImageGenTitle": "Text zu Bild",
"productNewTag": "NEU",
"productTtsText": "Generieren Sie Audio aus Text",
"productTtsTitle": "Text zu Sprache",
"productVcText": "Sprechen Sie mit einer anderen Stimme",
"productVcTitle": "Stimme zu Stimme",
"productVideoText": "Lippensynchronisation von Video zu Audio",
"productVideoTitle": "Video-Lippen synchronisation",
"productVdText": "Erstellen Sie Ihre eigene KI-Stimme",
"productVdTitle": "Sprachdesigner",
"productsTitle": "KI-Tools"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Try it now",
"alertTtiText": "Have you tried our new Text to Image? Turn your text prompts into images!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "We'd love to chat with you! Please join us in Discord if you have any questions.",
@@ -19,12 +21,14 @@
"heroTitle": "AI Music, Text to Speech, and Voice to Voice",
"productFaceAnimatorText": "Animate faces with audio",
"productFaceAnimatorTitle": "Face Animator",
"productImageGenText": "Create images from text",
"productImageGenTitle": "Text to Image",
"productNewTag": "NEW",
"productTtsText": "Generate audio from text",
"productTtsTitle": "Text to Speech",
"productVcText": "Speak in another voice",
"productVcTitle": "Voice to Voice",
"productVideoText": "Lip sync video to audio",
"productVideoTitle": "Video Lip Sync",
"productVdText": "Create your own AI voice",
"productVdTitle": "Voice Designer",
"productsTitle": "AI Tools"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Pruebalo ahora",
"alertTtiText": "¿Has probado nuestro nuevo Texto a Imagen? ¡Convierte tus mensajes de texto en imágenes!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "¡Nos encantaría charlar contigo! Únase a nosotros en Discord si tiene alguna pregunta.",
@@ -19,12 +21,14 @@
"heroTitle": "Música con IA, texto a voz y voz a voz",
"productFaceAnimatorText": "Animar caras con audio.",
"productFaceAnimatorTitle": "Animador de rostros",
"productImageGenText": "Crear imágenes a partir de texto",
"productImageGenTitle": "Texto a imagen",
"productNewTag": "NUEVO",
"productTtsText": "Generar audio a partir de texto",
"productTtsTitle": "Texto a voz",
"productVcText": "Habla con otra voz",
"productVcTitle": "Voz a Voz",
"productVideoText": "Sincronización de labios de vídeo con audio",
"productVideoTitle": "Sincronización de labios de vídeo",
"productVdText": "Crea tu propia voz de IA",
"productVdTitle": "Diseñador de voz",
"productsTitle": "Herramientas de IA"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Essayez-le maintenant",
"alertTtiText": "Avez-vous essayé notre nouveau Text to Image ? Transformez vos invites textuelles en images !",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Nous serions ravis de discuter avec vous ! Veuillez nous rejoindre sur Discord si vous avez des questions.",
@@ -19,12 +21,14 @@
"heroTitle": "Musique AI, synthèse vocale et voix à voix",
"productFaceAnimatorText": "Animer des visages avec de l'audio",
"productFaceAnimatorTitle": "Animateur de visage",
"productImageGenText": "Créer des images à partir de texte",
"productImageGenTitle": "Texte en image",
"productNewTag": "NOUVEAU",
"productTtsText": "Générer de l'audio à partir du texte",
"productTtsTitle": "Texte pour parler",
"productVcText": "Parle d'une autre voix",
"productVcTitle": "Voix à voix",
"productVideoText": "Synchronisation labiale de la vidéo avec l'audio",
"productVideoTitle": "Synchronisation labiale vidéo",
"productVdText": "Créez votre propre voix IA",
"productVdTitle": "Concepteur de voix",
"productsTitle": "Outils d'IA"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "अब इसे आजमाओ",
"alertTtiText": "क्या आपने हमारा नया टेक्स्ट टू इमेज आज़माया है? अपने टेक्स्ट संकेतों को छवियों में बदलें!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "हमें आपसे चैट करना अच्छा लगेगा! यदि आपके कोई प्रश्न हैं तो कृपया डिस्कॉर्ड में हमसे जुड़ें।",
@@ -19,12 +21,14 @@
"heroTitle": "एआई म्यूजिक, टेक्स्ट टू स्पीच और वॉयस टू वॉयस",
"productFaceAnimatorText": "ऑडियो के साथ चेहरों को चेतन करें",
"productFaceAnimatorTitle": "फेस एनिमेटर",
"productImageGenText": "पाठ से छवियाँ बनाएँ",
"productImageGenTitle": "छवि पर पाठ",
"productNewTag": "नया",
"productTtsText": "टेक्स्ट से ऑडियो जेनरेट करें",
"productTtsTitle": "भाषण के पाठ",
"productVcText": "दूसरे स्वर में बोलो",
"productVcTitle": "आवाज से आवाज",
"productVideoText": "लिप सिंक वीडियो से ऑडियो",
"productVideoTitle": "वीडियो लिप सिंक",
"productVdText": "अपनी खुद की एआई आवाज बनाएं",
"productVdTitle": "आवाज डिजाइनर",
"productsTitle": "एआई उपकरण"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Coba sekarang",
"alertTtiText": "Sudahkah Anda mencoba Teks ke Gambar baru kami? Ubah perintah teks Anda menjadi gambar!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Kami ingin mengobrol dengan Anda! Silakan bergabung dengan kami di Discord jika Anda memiliki pertanyaan.",
@@ -19,12 +21,14 @@
"heroTitle": "Musik AI, Teks ke Ucapan, dan Suara ke Suara",
"productFaceAnimatorText": "Animasikan wajah dengan audio",
"productFaceAnimatorTitle": "Animator Wajah",
"productImageGenText": "Buat gambar dari teks",
"productImageGenTitle": "Teks ke Gambar",
"productNewTag": "BARU",
"productTtsText": "Hasilkan audio dari teks",
"productTtsTitle": "Teks pidato",
"productVcText": "Bicaralah dengan suara lain",
"productVcTitle": "Suara ke Suara",
"productVideoText": "Sinkronisasi bibir video ke audio",
"productVideoTitle": "Sinkronisasi Bibir Video",
"productVdText": "Buat suara AI Anda sendiri",
"productVdTitle": "Desainer Suara",
"productsTitle": "Alat AI"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Provalo ora",
"alertTtiText": "Hai provato il nostro nuovo testo in immagine? Trasforma i tuoi suggerimenti di testo in immagini!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Ci piacerebbe chiacchierare con te! Unisciti a noi su Discord se hai domande.",
@@ -19,12 +21,14 @@
"heroTitle": "Musica AI, sintesi vocale e voce a voce",
"productFaceAnimatorText": "Anima i volti con l'audio",
"productFaceAnimatorTitle": "Animatore di volti",
"productImageGenText": "Creare immagini dal testo",
"productImageGenTitle": "Testo in immagine",
"productNewTag": "NUOVO",
"productTtsText": "Genera audio dal testo",
"productTtsTitle": "Sintesi vocale da testo",
"productVcText": "Parla con un'altra voce",
"productVcTitle": "Da voce a voce",
"productVideoText": "Sincronizzazione labiale del video con l'audio",
"productVideoTitle": "Sincronizzazione labiale video",
"productVdText": "Crea la tua voce AI",
"productVdTitle": "Progettista vocale",
"productsTitle": "Strumenti di intelligenza artificiale"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "やってみよう",
"alertTtiText": "新しい Text to Image を試してみましたか?テキストプロンプトを画像に変換しましょう。",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "ぜひお話ししたいと思います!ご質問がございましたら、Discord にご参加ください。",
@@ -19,12 +21,14 @@
"heroTitle": "AI 音楽、テキスト読み上げ、音声変換",
"productFaceAnimatorText": "音声で顔をアニメーション化する",
"productFaceAnimatorTitle": "フェイスアニメーター",
"productImageGenText": "テキストから画像を作成する",
"productImageGenTitle": "テキストから画像へ",
"productNewTag": "新しい",
"productTtsText": "テキストから音声を生成する",
"productTtsTitle": "テキスト読み上げ",
"productVcText": "別の声で話してください",
"productVcTitle": "声から声へ",
"productVideoText": "ビデオをオーディオにリップシンク",
"productVideoTitle": "ビデオリップシンク",
"productVdText": "独自の AI 音声を作成する",
"productVdTitle": "ボイスデザイナー",
"productsTitle": "AIツール"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "지금 사용해 보세요",
"alertTtiText": "새로운 Text to Image를 사용해 보셨나요? 텍스트 프롬프트를 이미지로 바꿔보세요!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "우리는 당신과 이야기를 나누고 싶습니다! 질문이 있으시면 Discord에 참여해주세요.",
@@ -19,12 +21,14 @@
"heroTitle": "AI 음악, 텍스트 음성 변환, 음성 변환",
"productFaceAnimatorText": "오디오로 얼굴 애니메이션 만들기",
"productFaceAnimatorTitle": "얼굴 애니메이터",
"productImageGenText": "텍스트에서 이미지 만들기",
"productImageGenTitle": "텍스트를 이미지로",
"productNewTag": "새로운",
"productTtsText": "텍스트에서 오디오 생성",
"productTtsTitle": "텍스트 음성 변환",
"productVcText": "다른 목소리로 말해보세요",
"productVcTitle": "음성 대 음성",
"productVideoText": "비디오를 오디오로 립싱크",
"productVideoTitle": "비디오 립싱크",
"productVdText": "나만의 AI 목소리 만들기",
"productVdTitle": "보이스 디자이너",
"productsTitle": "AI 도구"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Tente agora",
"alertTtiText": "Você já experimentou nosso novo Texto para Imagem? Transforme suas instruções de texto em imagens!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Adoraríamos conversar com você! Junte-se a nós no Discord se tiver alguma dúvida.",
@@ -19,12 +21,14 @@
"heroTitle": "Música AI, texto em fala e voz em voz",
"productFaceAnimatorText": "Animar rostos com áudio",
"productFaceAnimatorTitle": "Animador facial",
"productImageGenText": "Crie imagens a partir de texto",
"productImageGenTitle": "Texto para imagem",
"productNewTag": "NOVO",
"productTtsText": "Gerar áudio a partir de texto",
"productTtsTitle": "Texto para fala",
"productVcText": "Fale com outra voz",
"productVcTitle": "Voz para Voz",
"productVideoText": "Sincronização labial de vídeo com áudio",
"productVideoTitle": "Sincronização labial de vídeo",
"productVdText": "Crie sua própria voz de IA",
"productVdTitle": "Designer de voz",
"productsTitle": "Ferramentas de IA"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Попробуй это сейчас",
"alertTtiText": "Вы пробовали наш новый текст в изображение? Превратите текстовые подсказки в изображения!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Мы хотели бы пообщаться с вами! Присоединяйтесь к нам в Discord, если у вас есть вопросы.",
@@ -19,12 +21,14 @@
"heroTitle": "AI-музыка, преобразование текста в речь и голос в голос",
"productFaceAnimatorText": "Анимация лиц с помощью звука",
"productFaceAnimatorTitle": "Лицевой Аниматор",
"productImageGenText": "Создание изображений из текста",
"productImageGenTitle": "Текст в изображение",
"productNewTag": "НОВЫЙ",
"productTtsText": "Генерировать аудио из текста",
"productTtsTitle": "Текст в речь",
"productVcText": "Говори другим голосом",
"productVcTitle": "Голос в голос",
"productVideoText": "Синхронизация видео и аудио по губам",
"productVideoTitle": "Видео синхронизация губ",
"productVdText": "Создайте свой собственный голос с искусственным интеллектом",
"productVdTitle": "Голосовой дизайнер",
"productsTitle": "Инструменты искусственного интеллекта"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "ลองตอนนี้",
"alertTtiText": "คุณได้ลองใช้ Text to Image ใหม่ของเราแล้วหรือยัง? เปลี่ยนข้อความของคุณให้เป็นรูปภาพ!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "เราอยากจะพูดคุยกับคุณ! กรุณาเข้าร่วม Discord กับเราหากคุณมีคำถามใด ๆ",
@@ -19,12 +21,14 @@
"heroTitle": "แปลงข้อความเป็นคำพูด แปลงเสียง และร้องเพลงด้วย AI",
"productFaceAnimatorText": "ทำให้ใบหน้าเคลื่อนไหวด้วยเสียง",
"productFaceAnimatorTitle": "แอนิเมชั่นใบหน้า",
"productImageGenText": "สร้างภาพจากข้อความ",
"productImageGenTitle": "ข้อความเป็นรูปภาพ",
"productNewTag": "ใหม่",
"productTtsText": "สร้างเสียงจากข้อความ",
"productTtsTitle": "ข้อความเป็นคำพูด",
"productVcText": "พูดเป็นเสียงอื่น",
"productVcTitle": "เสียงเป็นเสียง",
"productVideoText": "ลิปซิงค์วิดีโอกับเสียง",
"productVideoTitle": "วิดีโอลิปซิงค์",
"productVdText": "สร้างเสียง AI ของคุณเอง",
"productVdTitle": "นักออกแบบเสียง",
"productsTitle": "เครื่องมือ AI"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Şimdi dene",
"alertTtiText": "Yeni Metinden Görüntüye ürünümüzü denediniz mi? Metin istemlerinizi görsellere dönüştürün!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Sizinle sohbet etmeyi çok isteriz! Sorularınız varsa lütfen Discord'da bize katılın.",
@@ -19,12 +21,14 @@
"heroTitle": "AI Müzik, Metinden Konuşmaya ve Sesten Sese",
"productFaceAnimatorText": "Yüzleri sesle canlandırın",
"productFaceAnimatorTitle": "Yüz Animatörü",
"productImageGenText": "Metinden görseller oluşturun",
"productImageGenTitle": "Metinden Görüntüye",
"productNewTag": "YENİ",
"productTtsText": "Metinden ses oluştur",
"productTtsTitle": "Konuşma metni",
"productVcText": "Başka bir sesle konuş",
"productVcTitle": "Sesten Sese",
"productVideoText": "Videoyu sese dudak senkronizasyonu",
"productVideoTitle": "Video Dudak Senkronizasyonu",
"productVdText": "Kendi yapay zeka sesinizi yaratın",
"productVdTitle": "Ses Tasarımcısı",
"productsTitle": "Yapay Zeka Araçları"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "Thử ngay bây giờ",
"alertTtiText": "Bạn đã thử Chuyển văn bản thành hình ảnh mới của chúng tôi chưa? Biến lời nhắc văn bản của bạn thành hình ảnh!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "Chúng tôi muốn trò chuyện với bạn! Hãy tham gia cùng chúng tôi trong Discord nếu bạn có bất kỳ câu hỏi nào.",
@@ -19,12 +21,14 @@
"heroTitle": "Âm nhạc AI, Chuyển văn bản thành giọng nói và Giọng nói thành giọng nói",
"productFaceAnimatorText": "Làm sinh động khuôn mặt bằng âm thanh",
"productFaceAnimatorTitle": "khuôn mặt hoạt hình",
"productImageGenText": "Tạo hình ảnh từ văn bản",
"productImageGenTitle": "văn bản thành hình ảnh",
"productNewTag": "MỚI",
"productTtsText": "Tạo âm thanh từ văn bản",
"productTtsTitle": "Chuyển văn bản thành giọng nói",
"productVcText": "Nói bằng giọng khác",
"productVcTitle": "Giọng nói thành giọng nói",
"productVideoText": "Hát nhép video thành âm thanh",
"productVideoTitle": "Hát nhép video",
"productVdText": "Tạo giọng nói AI của riêng bạn",
"productVdTitle": "Nhà thiết kế giọng nói",
"productsTitle": "Công cụ AI"
}
@@ -1,4 +1,6 @@
{
"alertTtiCta": "现在就试试",
"alertTtiText": "您尝试过我们的新文本到图像吗?将您的文字提示变成图像!",
"communityButtonDiscord": "Discord",
"communityButtonTwitter": "Twitter",
"communityText": "我们很乐意与您聊天!如果您有任何疑问,请加入我们的 Discord。",
@@ -19,12 +21,14 @@
"heroTitle": "AI 音乐、文字转语音、语音转语音",
"productFaceAnimatorText": "用音频制作面孔动画",
"productFaceAnimatorTitle": "脸部动画师",
"productImageGenText": "从文本创建图像",
"productImageGenTitle": "文字转图像",
"productNewTag": "新的",
"productTtsText": "从文本生成音频",
"productTtsTitle": "文字转语音",
"productVcText": "用另一种声音说话",
"productVcTitle": "语音到语音",
"productVideoText": "视频与音频口型同步",
"productVideoTitle": "视频唇形同步",
"productVdText": "创建您自己的人工智能声音",
"productVdTitle": "声音设计师",
"productsTitle": "人工智能工具"
}
@@ -43,7 +43,7 @@ export default function AudioCard({
const linkUrl = getCardUrl(data, source, type);
const history = useHistory();
console.log("🟩",data);
console.log("🟩", data);
const handleSelectModalResultSelect = () => {
if (inSelectModal) {
@@ -180,7 +180,8 @@ export default function AudioCard({
</div>
<CardFooter
{...{
creator: data?.creator,
creator:
data?.creator || data.details.maybe_weight_data?.maybe_creator,
entityToken: data.weight_token,
entityType: "model_weight",
makeBookmarksProps: bookmarks?.makeProps,
@@ -181,7 +181,9 @@ export default function ImageCard({
</div>
<CardFooter
{...{
creator: data.creator,
creator:
data.creator ||
data.details.maybe_weight_data?.maybe_creator,
entityToken: data.weight_token,
entityType: "model_weight",
makeBookmarksProps: bookmarks?.makeProps,
@@ -1,3 +1,27 @@
.fy-temp-select { // NO !IMPORTANT
.fy-temp-select {
margin-bottom: 1rem;
}
&:only-child,
&:last-child {
margin-bottom: 0;
}
}
.d-flex:not(.flex-column) > .fy-temp-select {
margin-bottom: 0;
margin-right: 0.5rem;
&:only-child,
&:last-child {
margin-bottom: 0;
}
}
.gap-1 > .fy-temp-select,
.gap-2 > .fy-temp-select,
.gap-3 > .fy-temp-select,
.gap-4 > .fy-temp-select,
.gap-5 > .fy-temp-select {
margin-bottom: 0;
margin-right: 0 !important;
}
@@ -12,13 +12,26 @@ interface Props {
sessionWrapper?: any;
}
export default function SessionProvider({ children, querySession, querySubscriptions, sessionFetched, sessionWrapper }: Props) {
const sessionResponse = sessionWrapper?.sessionStateResponse || { logged_in: false };
export default function SessionProvider({
children,
querySession,
querySubscriptions,
sessionFetched,
sessionWrapper,
}: Props) {
const sessionResponse = sessionWrapper?.sessionStateResponse || {
logged_in: false,
};
const { logged_in: loggedIn, user } = sessionResponse;
const [view,viewSet] = useState(ModalView.Closed);
const [view, viewSet] = useState(ModalView.Closed);
const open = () => viewSet(ModalView.Signup);
const close = () => { viewSet(ModalView.Closed);};
const viewSwitch = () => view === ModalView.Signup ? viewSet(ModalView.Login) : viewSet(ModalView.Signup);
const close = () => {
viewSet(ModalView.Closed);
};
const viewSwitch = () =>
view === ModalView.Signup
? viewSet(ModalView.Login)
: viewSet(ModalView.Signup);
const check = () => {
if (user) {
return true;
@@ -27,31 +40,45 @@ export default function SessionProvider({ children, querySession, querySubscript
return false;
}
};
const userTokenMatch = (otherUserToken: string) => !otherUserToken || !user?.user_token ? false : user.user_token === otherUserToken;
const canEditTtsModel = (userToken: string) => user?.canEditOtherUsersTtsModels || userTokenMatch(userToken);
const userTokenMatch = (otherUserToken: string) =>
!otherUserToken || !user?.user_token
? false
: user.user_token === otherUserToken;
const canEditTtsModel = (userToken: string) =>
user?.canEditOtherUsersTtsModels || userTokenMatch(userToken);
const canBanUsers = () => user?.can_ban_users || false;
return <SessionContext.Provider {...{ value: {
canEditTtsModel,
check,
loggedIn,
modal: { close, open, view },
querySession,
querySubscriptions,
sessionFetched,
user,
userTokenMatch
} }}>
{ children }
{
<Modal {...{
content: AccountModal,
contentProps: { view, viewSwitch },
handleClose: close,
noHeader: true,
show: view > 0,
showButtons: false,
// title: "You need to login",
}}/>
}
</SessionContext.Provider>
};
return (
<SessionContext.Provider
{...{
value: {
canEditTtsModel,
canBanUsers,
check,
loggedIn,
modal: { close, open, view },
querySession,
querySubscriptions,
sessionFetched,
user,
userTokenMatch,
},
}}
>
{children}
{
<Modal
{...{
content: AccountModal,
contentProps: { view, viewSwitch },
handleClose: close,
noHeader: true,
show: view > 0,
showButtons: false,
// title: "You need to login",
}}
/>
}
</SessionContext.Provider>
);
}
@@ -3,29 +3,31 @@ import { createContext } from "react";
export enum ModalView {
Closed,
Signup,
Login
Login,
}
interface ModalProps {
close: () => void,
open: () => void,
view: ModalView
close: () => void;
open: () => void;
view: ModalView;
}
interface SessionContextType {
canEditTtsModel: (token:string) => boolean,
check: () => boolean,
loggedIn: boolean,
modal: ModalProps,
querySession?: any,
querySubscriptions?: any,
sessionFetched: boolean,
user?: any,
userTokenMatch: (token:string) => boolean
canEditTtsModel: (token: string) => boolean;
canBanUsers: () => boolean;
check: () => boolean;
loggedIn: boolean;
modal: ModalProps;
querySession?: any;
querySubscriptions?: any;
sessionFetched: boolean;
user?: any;
userTokenMatch: (token: string) => boolean;
}
export default createContext<SessionContextType>({
canEditTtsModel: () => false,
canBanUsers: () => false,
check: () => false,
loggedIn: false,
sessionFetched: false,
@@ -34,5 +36,5 @@ export default createContext<SessionContextType>({
open: () => {},
view: ModalView.Closed,
},
userTokenMatch: () => false
});
userTokenMatch: () => false,
});
@@ -21,7 +21,7 @@ export default function MediaTab() {
const bookmarks = useBookmarks();
const ratings = useRatings();
const toTopBtnRef = useRef<HTMLDivElement | null>(null);
const onScreen = useOnScreen(toTopBtnRef,"0px");
const onScreen = useOnScreen(toTopBtnRef, "0px");
const gridContainerRef = useRef<HTMLDivElement | null>(null);
const [mediaType, mediaTypeSet] = useState(
@@ -86,20 +86,30 @@ export default function MediaTab() {
}}
/>
</div>
{ media.urlCursor ?
<Button {...{
className: `to-top-button`,
buttonRef: toTopBtnRef,
{media.urlCursor ? (
<div>
<Button
{...{
className: `to-top-button`,
buttonRef: toTopBtnRef,
label: "Back to top",
onClick: () => media.reset(),
small: true,
}}
/>
</div>
) : null}
</div>
{media.urlCursor && !onScreen ? (
<Button
{...{
className: `to-top-button-off-screen`,
label: "Back to top",
onClick: () => media.reset(),
}}/> : null }
</div>
{ media.urlCursor && !onScreen ?
<Button {...{
className: `to-top-button-off-screen`,
label: "Back to top",
onClick: () => media.reset(),
}}/> : null }
small: true,
}}
/>
) : null}
<AudioPlayerProvider>
{media.isLoading && !media.list.length ? (
<div className="row gx-3 gy-3">
@@ -108,7 +118,6 @@ export default function MediaTab() {
))}
</div>
) : (
<InfiniteScroll
dataLength={media.list.length}
next={media.getMore}
@@ -21,12 +21,16 @@ export default function WeightsTab() {
const bookmarks = useBookmarks();
const ratings = useRatings();
const gridContainerRef = useRef<HTMLDivElement | null>(null);
const [weightType, weightTypeSet] = useState(urlQueries.get("maybe_scoped_weight_type") || "all");
const [weightCategory, weightCategorySet] = useState(urlQueries.get("maybe_scoped_weight_category") || "all");
const [weightType, weightTypeSet] = useState(
urlQueries.get("maybe_scoped_weight_type") || "all"
);
const [weightCategory, weightCategorySet] = useState(
urlQueries.get("maybe_scoped_weight_category") || "all"
);
const [showMasonryGrid, setShowMasonryGrid] = useState(true);
const [list, listSet] = useState<Weight[]>([]);
const toTopBtnRef = useRef<HTMLDivElement | null>(null);
const onScreen = useOnScreen(toTopBtnRef,"0px");
const onScreen = useOnScreen(toTopBtnRef, "0px");
const weights = useLazyLists({
addQueries: {
page_size: 24,
@@ -39,8 +43,8 @@ export default function WeightsTab() {
list,
listSet,
onInputChange: () => setShowMasonryGrid(false),
onSuccess: (res) => {
bookmarks.gather({ res, expand: true, key: "weight_token" }); // expand rather than replace for lazy loading
onSuccess: res => {
bookmarks.gather({ res, expand: true, key: "weight_token" }); // expand rather than replace for lazy loading
ratings.gather({ res, expand: true, key: "weight_token" });
setShowMasonryGrid(true);
},
@@ -54,7 +58,8 @@ export default function WeightsTab() {
// { value: "sd", label: "Image Generation" },
// ];
const weightTypeOpts = [ // these probably need beter labels
const weightTypeOpts = [
// these probably need beter labels
{ value: "all", label: "All weight types" },
{ value: "hifigan_tt2", label: "hifigan_tt2" },
{ value: "sd_1.5", label: "sd_1.5" },
@@ -111,20 +116,24 @@ export default function WeightsTab() {
value: weights.sort,
}}
/>
<TempSelect {...{
icon: faFilter,
options: weightCategoryOpts,
name: "weightCategory",
onChange: weights.onChange,
value: weightCategory,
}} />
<TempSelect {...{
icon: faFilter,
options: weightTypeOpts,
name: "weightType",
onChange: weights.onChange,
value: weightType,
}} />
<TempSelect
{...{
icon: faFilter,
options: weightCategoryOpts,
name: "weightCategory",
onChange: weights.onChange,
value: weightCategory,
}}
/>
<TempSelect
{...{
icon: faFilter,
options: weightTypeOpts,
name: "weightType",
onChange: weights.onChange,
value: weightType,
}}
/>
{/* {selectedFilter === "tts" && (
<TempSelect
options={modelTtsOptions}
@@ -147,20 +156,31 @@ export default function WeightsTab() {
/>
)} */}
</div>
{ weights.urlCursor ?
<Button {...{
className: `to-top-button`,
buttonRef: toTopBtnRef,
{weights.urlCursor ? (
<div>
<Button
{...{
className: `to-top-button`,
buttonRef: toTopBtnRef,
label: "Back to top",
onClick: () => weights.reset(),
small: true,
}}
/>
</div>
) : null}
</div>
{weights.urlCursor && !onScreen ? (
<Button
{...{
className: `to-top-button-off-screen`,
label: "Back to top",
onClick: () => weights.reset(),
}}/> : null }
</div>
{ weights.urlCursor && !onScreen ?
<Button {...{
className: `to-top-button-off-screen`,
label: "Back to top",
onClick: () => weights.reset(),
}}/> : null }
small: true,
}}
/>
) : null}
<AudioPlayerProvider>
{weights.isLoading && !weights.list.length ? (
<div className="row gx-3 gy-3">
@@ -1,5 +1,4 @@
import {
faArrowRight,
faFileArrowUp,
faFlask,
faSparkles,
@@ -10,6 +9,7 @@ import { Panel } from "components/common";
import { useLocalize } from "hooks";
import React from "react";
import { Link } from "react-router-dom";
import DashboardRow from "./components/DashboardRow";
interface DashboardProps {
sessionWrapper: SessionWrapper;
@@ -51,141 +51,59 @@ export default function Dashboard(props: DashboardProps) {
);
}
const dashboardProducts = [
{
to: "/tts",
title: t("productTtsTitle"),
text: t("productTtsText"),
imgSrc: "/images/landing/select-tts.webp",
imgAlt: "Text to Speech",
},
{
to: "/voice-conversion",
title: t("productVcTitle"),
text: t("productVcText"),
imgSrc: "/images/landing/select-vc.webp",
imgAlt: "Voice Conversion",
},
{
to: "/voice-designer",
title: t("productVdTitle"),
text: t("productVdText"),
imgSrc: "/images/landing/select-vd.webp",
imgAlt: "Voice Cloning",
badgeContent: {
type: "beta",
icon: faFlask,
label: "BETA",
},
},
{
to: "/face-animator",
title: t("productFaceAnimatorTitle"),
text: t("productFaceAnimatorText"),
imgSrc: "/images/landing/select-w2l.webp",
imgAlt: "Face Animator",
},
{
to: "/text-to-image",
title: t("productImageGenTitle"),
text: t("productImageGenText"),
imgSrc: "/images/landing/select-tti.webp",
imgAlt: "AI Image Generation",
badgeContent: {
type: "new",
icon: faSparkles,
label: "NEW",
},
},
];
return (
<Panel clear={true} className="mt-5">
<h1 className="fw-bold mb-4">{t("productsTitle")}</h1>
<div className="row g-4 position-relative">
<div className="col-12 col-md-4">
<Link
to="/tts"
className="panel panel-select d-flex flex-column align-items-center"
>
<div className="d-flex px-4 pt-4 align-items-start w-100">
<div className="flex-grow-1">
<h3 className="fw-bold text-white mb-1">
{t("productTtsTitle")}
</h3>
<h6 className="fw-normal opacity-75 text-white">
{t("productTtsText")}
</h6>
</div>
<Link to="/tts" className="btn btn-square mt-1">
<FontAwesomeIcon icon={faArrowRight} />
</Link>
</div>
<img
className="img-fluid"
src="/images/landing/select-tts.webp"
alt="Text to speech"
/>
</Link>
</div>
<div className="col-12 col-md-4">
<Link
to="/voice-conversion"
className="panel panel-select d-flex flex-column align-items-center"
>
<div className="d-flex px-4 pt-4 align-items-start w-100">
<div className="flex-grow-1">
<h3 className="fw-bold text-white mb-1">
{t("productVcTitle")}
</h3>
<h6 className="fw-normal opacity-75 text-white">
{t("productVcText")}
</h6>
</div>
<Link to="/voice-conversion" className="btn btn-square mt-1">
<FontAwesomeIcon icon={faArrowRight} />
</Link>
</div>
<img
className="img-fluid"
src="/images/landing/select-vc.webp"
alt="Voice Conversion"
/>
</Link>
</div>
<div className="col-12 col-md-4">
<Link
to="/voice-designer"
className="panel panel-select d-flex flex-column align-items-center"
>
<div className="d-flex px-4 pt-4 align-items-start w-100">
<div className="flex-grow-1">
<div className="mb-1">
<span className="badge-beta d-inline-flex align-items-center mb-2 me-2">
<FontAwesomeIcon icon={faFlask} className="me-1" />
BETA
</span>
<h4 className="fw-bold text-white d-inline-flex align-items-center mb-0">
<span>Voice Designer</span>
</h4>
</div>
<h6 className="fw-normal opacity-75 text-white">
Create your own AI voice
</h6>
</div>
<Link to="/voice-designer" className="btn btn-square mt-1">
<FontAwesomeIcon icon={faArrowRight} />
</Link>
</div>
<img
className="img-fluid"
src="/images/landing/select-vd.webp"
alt="Voice Designer"
/>
</Link>
</div>
<div className="col-12 col-md-4">
<Link
to="/face-animator"
className="panel panel-select d-flex flex-column align-items-center"
>
<div className="d-flex px-4 pt-4 align-items-start w-100">
<div className="flex-grow-1">
<div className="mb-1">
<span className="badge-new d-inline-flex align-items-center mb-2 me-2">
<FontAwesomeIcon icon={faSparkles} className="me-1" />
{t("productNewTag")}
</span>
<h4 className="fw-bold text-white d-inline-flex align-items-center mb-0">
<span>{t("productFaceAnimatorTitle")}</span>
</h4>
</div>
<h6 className="fw-normal opacity-75 text-white">
{t("productFaceAnimatorText")}
</h6>
</div>
<Link to="/face-animator" className="btn btn-square mt-1">
<FontAwesomeIcon icon={faArrowRight} />
</Link>
</div>
<img
className="img-fluid"
src="/images/landing/select-w2l.webp"
alt="Face Animator"
/>
</Link>
</div>
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-right-top"
/>
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-left-bottom"
/>
</div>
<DashboardRow items={dashboardProducts} />
{uploadModelSection}
</Panel>
@@ -0,0 +1,93 @@
import React from "react";
import { Link } from "react-router-dom";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { IconDefinition } from "@fortawesome/fontawesome-svg-core";
import { faArrowRight } from "@fortawesome/pro-solid-svg-icons";
interface BadgeContent {
type: string;
icon: IconDefinition;
label: string;
}
interface DashboardItemProps {
to: string;
title: string;
text?: string;
imgSrc: string;
imgAlt: string;
badgeContent?: BadgeContent;
}
export function DashboardItem({
to,
title,
text,
imgSrc,
imgAlt,
badgeContent,
}: DashboardItemProps) {
return (
<div className="col-12 col-md-4">
<Link
to={to}
className="panel panel-select d-flex flex-column align-items-center"
>
<div className="d-flex px-4 pt-4 align-items-start w-100">
<div className="flex-grow-1">
{badgeContent && (
<div className="mb-1">
<span
className={`badge-${badgeContent.type} d-inline-flex align-items-center mb-2 me-2`}
>
<FontAwesomeIcon icon={badgeContent.icon} className="me-1" />
{badgeContent.label}
</span>
<h4 className="fw-bold text-white d-inline-flex align-items-center mb-0">
<span>{title}</span>
</h4>
<h6 className="fw-normal opacity-75 text-white">{text}</h6>
</div>
)}
{!badgeContent && (
<>
<h3 className="fw-bold text-white mb-1">{title}</h3>
<h6 className="fw-normal opacity-75 text-white">{text}</h6>
</>
)}
</div>
<Link to={to} className="btn btn-square mt-1">
<FontAwesomeIcon icon={faArrowRight} />
</Link>
</div>
<img className="img-fluid" src={imgSrc} alt={imgAlt} />
</Link>
</div>
);
}
interface DashboardRowProps {
items: DashboardItemProps[];
}
export function DashboardRow({ items }: DashboardRowProps) {
return (
<div className="row g-4 position-relative">
{items.map((item, index) => (
<DashboardItem key={index} {...item} />
))}
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-right-top"
/>
<img
src="/images/landing/bg-dots.webp"
alt="background dots"
className="dots-left-bottom"
/>
</div>
);
}
export default DashboardRow;
@@ -1,9 +1,15 @@
import { faArrowRight, faStar, faUser } from "@fortawesome/pro-solid-svg-icons";
import {
faArrowRight,
faSparkles,
faStar,
faUser,
} from "@fortawesome/pro-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { SessionSubscriptionsWrapper } from "@storyteller/components/src/session/SessionSubscriptionsWrapper";
import { SessionWrapper } from "@storyteller/components/src/session/SessionWrapper";
import { WebUrl } from "common/WebUrl";
import { Panel } from "components/common";
import Alert from "components/common/Alert/Alert";
import { useLocalize } from "hooks";
import React, { useMemo } from "react";
import { Link } from "react-router-dom";
@@ -113,14 +119,14 @@ export default function FakeYouLandingHeader(props: FakeYouLandingHeaderProps) {
return (
<Panel clear={true} className="mt-5">
{/* <Alert
id="face-animation-alert"
icon={faSparkles}
message="Have you tried our new Face Animator? Turn photos of faces into animated lip-synced videos with just a picture and some audio!"
alertVariant="new"
link="/face-animator"
linkText="Try it now"
/> */}
<Alert
id="text-to-image-alert"
icon={faSparkles}
message={t("alertTtiText")}
alertVariant="new"
link="/text-to-image"
linkText={t("alertTtiCta")}
/>
<div className="row flex-md-row-reverse">
<div className="col-12 col-lg-5 p-md-0 d-flex justify-content-center">
@@ -66,7 +66,7 @@ export default function WeightPage({
enqueueTtsJob,
inferenceJobsByCategory,
}: WeightProps) {
const { canEditTtsModel, user } = useSession();
const { canEditTtsModel, canBanUsers, user } = useSession();
const { search } = useLocation();
const { weight_token } = useParams<{ weight_token: string }>();
const source = search ? new URLSearchParams(search).get("source") : "";
@@ -572,7 +572,8 @@ export default function WeightPage({
</div>
</Panel>
{canEditTtsModel(weight.creator?.user_token) && (
{(canEditTtsModel(weight.creator?.user_token) ||
canBanUsers()) && (
<div className="d-flex gap-2">
<Button
full={true}