mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-06 02:00:46 +00:00
Merge branch 'feature/mvp' of https://github.com/storytold/storyteller-frontend into feature/mvp
This commit is contained in:
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}
|
||||
|
||||
Reference in new issue
Block a user