1. Added multi-language support to the UI
2. Optimized the voice name 3. Other UI optimizations
This commit is contained in:
1 parent
a7ba661053
commit
bc8e005f59
6 files changed
+1293
-137
No files matched your search
+38
-38
@@ -34,43 +34,43 @@ class MaterialInfo:
|
||||
duration: int = 0
|
||||
|
||||
|
||||
VoiceNames = [
|
||||
# zh-CN
|
||||
"female-zh-CN-XiaoxiaoNeural",
|
||||
"female-zh-CN-XiaoyiNeural",
|
||||
"female-zh-CN-liaoning-XiaobeiNeural",
|
||||
"female-zh-CN-shaanxi-XiaoniNeural",
|
||||
|
||||
"male-zh-CN-YunjianNeural",
|
||||
"male-zh-CN-YunxiNeural",
|
||||
"male-zh-CN-YunxiaNeural",
|
||||
"male-zh-CN-YunyangNeural",
|
||||
|
||||
# "female-zh-HK-HiuGaaiNeural",
|
||||
# "female-zh-HK-HiuMaanNeural",
|
||||
# "male-zh-HK-WanLungNeural",
|
||||
#
|
||||
# "female-zh-TW-HsiaoChenNeural",
|
||||
# "female-zh-TW-HsiaoYuNeural",
|
||||
# "male-zh-TW-YunJheNeural",
|
||||
|
||||
# en-US
|
||||
|
||||
"female-en-US-AnaNeural",
|
||||
"female-en-US-AriaNeural",
|
||||
"female-en-US-AvaNeural",
|
||||
"female-en-US-EmmaNeural",
|
||||
"female-en-US-JennyNeural",
|
||||
"female-en-US-MichelleNeural",
|
||||
|
||||
"male-en-US-AndrewNeural",
|
||||
"male-en-US-BrianNeural",
|
||||
"male-en-US-ChristopherNeural",
|
||||
"male-en-US-EricNeural",
|
||||
"male-en-US-GuyNeural",
|
||||
"male-en-US-RogerNeural",
|
||||
"male-en-US-SteffanNeural",
|
||||
]
|
||||
# VoiceNames = [
|
||||
# # zh-CN
|
||||
# "female-zh-CN-XiaoxiaoNeural",
|
||||
# "female-zh-CN-XiaoyiNeural",
|
||||
# "female-zh-CN-liaoning-XiaobeiNeural",
|
||||
# "female-zh-CN-shaanxi-XiaoniNeural",
|
||||
#
|
||||
# "male-zh-CN-YunjianNeural",
|
||||
# "male-zh-CN-YunxiNeural",
|
||||
# "male-zh-CN-YunxiaNeural",
|
||||
# "male-zh-CN-YunyangNeural",
|
||||
#
|
||||
# # "female-zh-HK-HiuGaaiNeural",
|
||||
# # "female-zh-HK-HiuMaanNeural",
|
||||
# # "male-zh-HK-WanLungNeural",
|
||||
# #
|
||||
# # "female-zh-TW-HsiaoChenNeural",
|
||||
# # "female-zh-TW-HsiaoYuNeural",
|
||||
# # "male-zh-TW-YunJheNeural",
|
||||
#
|
||||
# # en-US
|
||||
#
|
||||
# "female-en-US-AnaNeural",
|
||||
# "female-en-US-AriaNeural",
|
||||
# "female-en-US-AvaNeural",
|
||||
# "female-en-US-EmmaNeural",
|
||||
# "female-en-US-JennyNeural",
|
||||
# "female-en-US-MichelleNeural",
|
||||
#
|
||||
# "male-en-US-AndrewNeural",
|
||||
# "male-en-US-BrianNeural",
|
||||
# "male-en-US-ChristopherNeural",
|
||||
# "male-en-US-EricNeural",
|
||||
# "male-en-US-GuyNeural",
|
||||
# "male-en-US-RogerNeural",
|
||||
# "male-en-US-SteffanNeural",
|
||||
# ]
|
||||
|
||||
|
||||
class VideoParams:
|
||||
@@ -97,7 +97,7 @@ class VideoParams:
|
||||
|
||||
video_language: Optional[str] = "" # auto detect
|
||||
|
||||
voice_name: Optional[str] = VoiceNames[0]
|
||||
voice_name: Optional[str] = ""
|
||||
bgm_type: Optional[str] = "random"
|
||||
bgm_file: Optional[str] = ""
|
||||
bgm_volume: Optional[float] = 0.2
|
||||
|
||||
+2
-15
@@ -6,24 +6,11 @@ from os import path
|
||||
from loguru import logger
|
||||
|
||||
from app.config import config
|
||||
from app.models.schema import VideoParams, VoiceNames, VideoConcatMode
|
||||
from app.models.schema import VideoParams, VideoConcatMode
|
||||
from app.services import llm, material, voice, video, subtitle
|
||||
from app.utils import utils
|
||||
|
||||
|
||||
def _parse_voice(name: str):
|
||||
# "female-zh-CN-XiaoxiaoNeural",
|
||||
# remove first part split by "-"
|
||||
if name not in VoiceNames:
|
||||
name = VoiceNames[0]
|
||||
|
||||
parts = name.split("-")
|
||||
_lang = f"{parts[1]}-{parts[2]}"
|
||||
_voice = f"{_lang}-{parts[3]}"
|
||||
|
||||
return _voice, _lang
|
||||
|
||||
|
||||
def start(task_id, params: VideoParams):
|
||||
"""
|
||||
{
|
||||
@@ -40,7 +27,7 @@ def start(task_id, params: VideoParams):
|
||||
"""
|
||||
logger.info(f"start task: {task_id}")
|
||||
video_subject = params.video_subject
|
||||
voice_name, language = _parse_voice(params.voice_name)
|
||||
voice_name = voice.parse_voice_name(params.voice_name)
|
||||
paragraph_number = params.paragraph_number
|
||||
n_threads = params.n_threads
|
||||
max_clip_duration = params.video_clip_duration
|
||||
|
||||
+983
-1
@@ -1,5 +1,4 @@
|
||||
import asyncio
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from xml.sax.saxutils import unescape
|
||||
from edge_tts.submaker import mktimestamp
|
||||
from loguru import logger
|
||||
@@ -8,6 +7,985 @@ import edge_tts
|
||||
from app.utils import utils
|
||||
|
||||
|
||||
def get_all_voices(filter_locals=None) -> list[str]:
|
||||
if filter_locals is None:
|
||||
filter_locals = ["zh-CN", "en-US", "zh-HK", "zh-TW"]
|
||||
voices_str = """
|
||||
Name: af-ZA-AdriNeural
|
||||
Gender: Female
|
||||
|
||||
Name: af-ZA-WillemNeural
|
||||
Gender: Male
|
||||
|
||||
Name: am-ET-AmehaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: am-ET-MekdesNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-AE-FatimaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-AE-HamdanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-BH-AliNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-BH-LailaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-DZ-AminaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-DZ-IsmaelNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-EG-SalmaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-EG-ShakirNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-IQ-BasselNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-IQ-RanaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-JO-SanaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-JO-TaimNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-KW-FahedNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-KW-NouraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-LB-LaylaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-LB-RamiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-LY-ImanNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-LY-OmarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-MA-JamalNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-MA-MounaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-OM-AbdullahNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-OM-AyshaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-QA-AmalNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-QA-MoazNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-SA-HamedNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-SA-ZariyahNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-SY-AmanyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-SY-LaithNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-TN-HediNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ar-TN-ReemNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-YE-MaryamNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ar-YE-SalehNeural
|
||||
Gender: Male
|
||||
|
||||
Name: az-AZ-BabekNeural
|
||||
Gender: Male
|
||||
|
||||
Name: az-AZ-BanuNeural
|
||||
Gender: Female
|
||||
|
||||
Name: bg-BG-BorislavNeural
|
||||
Gender: Male
|
||||
|
||||
Name: bg-BG-KalinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: bn-BD-NabanitaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: bn-BD-PradeepNeural
|
||||
Gender: Male
|
||||
|
||||
Name: bn-IN-BashkarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: bn-IN-TanishaaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: bs-BA-GoranNeural
|
||||
Gender: Male
|
||||
|
||||
Name: bs-BA-VesnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ca-ES-EnricNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ca-ES-JoanaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: cs-CZ-AntoninNeural
|
||||
Gender: Male
|
||||
|
||||
Name: cs-CZ-VlastaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: cy-GB-AledNeural
|
||||
Gender: Male
|
||||
|
||||
Name: cy-GB-NiaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: da-DK-ChristelNeural
|
||||
Gender: Female
|
||||
|
||||
Name: da-DK-JeppeNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-AT-IngridNeural
|
||||
Gender: Female
|
||||
|
||||
Name: de-AT-JonasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-CH-JanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-CH-LeniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: de-DE-AmalaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: de-DE-ConradNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-DE-FlorianMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-DE-KatjaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: de-DE-KillianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: de-DE-SeraphinaMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: el-GR-AthinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: el-GR-NestorasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-AU-NatashaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-AU-WilliamNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-CA-ClaraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-CA-LiamNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-GB-LibbyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-GB-MaisieNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-GB-RyanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-GB-SoniaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-GB-ThomasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-HK-SamNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-HK-YanNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-IE-ConnorNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-IE-EmilyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-IN-NeerjaExpressiveNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-IN-NeerjaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-IN-PrabhatNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-KE-AsiliaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-KE-ChilembaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-NG-AbeoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-NG-EzinneNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-NZ-MitchellNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-NZ-MollyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-PH-JamesNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-PH-RosaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-SG-LunaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-SG-WayneNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-TZ-ElimuNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-TZ-ImaniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AndrewNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-AriaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-AvaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-BrianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-ChristopherNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-EmmaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-EricNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-GuyNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-JennyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-MichelleNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-US-RogerNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-US-SteffanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: en-ZA-LeahNeural
|
||||
Gender: Female
|
||||
|
||||
Name: en-ZA-LukeNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-AR-ElenaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-AR-TomasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-BO-MarceloNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-BO-SofiaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-CL-CatalinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-CL-LorenzoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-CO-GonzaloNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-CO-SalomeNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-CR-JuanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-CR-MariaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-CU-BelkysNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-CU-ManuelNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-DO-EmilioNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-DO-RamonaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-EC-AndreaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-EC-LuisNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-ES-AlvaroNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-ES-ElviraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-ES-XimenaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-GQ-JavierNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-GQ-TeresaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-GT-AndresNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-GT-MartaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-HN-CarlosNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-HN-KarlaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-MX-DaliaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-MX-JorgeNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-NI-FedericoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-NI-YolandaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-PA-MargaritaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-PA-RobertoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-PE-AlexNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-PE-CamilaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-PR-KarinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-PR-VictorNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-PY-MarioNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-PY-TaniaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-SV-LorenaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-SV-RodrigoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-US-AlonsoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-US-PalomaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-UY-MateoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: es-UY-ValentinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-VE-PaolaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: es-VE-SebastianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: et-EE-AnuNeural
|
||||
Gender: Female
|
||||
|
||||
Name: et-EE-KertNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fa-IR-DilaraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fa-IR-FaridNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fi-FI-HarriNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fi-FI-NooraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fil-PH-AngeloNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fil-PH-BlessicaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-BE-CharlineNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-BE-GerardNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-CA-AntoineNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-CA-JeanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-CA-SylvieNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-CA-ThierryNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-CH-ArianeNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-CH-FabriceNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-FR-DeniseNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-FR-EloiseNeural
|
||||
Gender: Female
|
||||
|
||||
Name: fr-FR-HenriNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-FR-RemyMultilingualNeural
|
||||
Gender: Male
|
||||
|
||||
Name: fr-FR-VivienneMultilingualNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ga-IE-ColmNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ga-IE-OrlaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: gl-ES-RoiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: gl-ES-SabelaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: gu-IN-DhwaniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: gu-IN-NiranjanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: he-IL-AvriNeural
|
||||
Gender: Male
|
||||
|
||||
Name: he-IL-HilaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: hi-IN-MadhurNeural
|
||||
Gender: Male
|
||||
|
||||
Name: hi-IN-SwaraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: hr-HR-GabrijelaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: hr-HR-SreckoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: hu-HU-NoemiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: hu-HU-TamasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: id-ID-ArdiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: id-ID-GadisNeural
|
||||
Gender: Female
|
||||
|
||||
Name: is-IS-GudrunNeural
|
||||
Gender: Female
|
||||
|
||||
Name: is-IS-GunnarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: it-IT-DiegoNeural
|
||||
Gender: Male
|
||||
|
||||
Name: it-IT-ElsaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: it-IT-GiuseppeNeural
|
||||
Gender: Male
|
||||
|
||||
Name: it-IT-IsabellaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ja-JP-KeitaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ja-JP-NanamiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: jv-ID-DimasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: jv-ID-SitiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ka-GE-EkaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ka-GE-GiorgiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: kk-KZ-AigulNeural
|
||||
Gender: Female
|
||||
|
||||
Name: kk-KZ-DauletNeural
|
||||
Gender: Male
|
||||
|
||||
Name: km-KH-PisethNeural
|
||||
Gender: Male
|
||||
|
||||
Name: km-KH-SreymomNeural
|
||||
Gender: Female
|
||||
|
||||
Name: kn-IN-GaganNeural
|
||||
Gender: Male
|
||||
|
||||
Name: kn-IN-SapnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ko-KR-HyunsuNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ko-KR-InJoonNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ko-KR-SunHiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: lo-LA-ChanthavongNeural
|
||||
Gender: Male
|
||||
|
||||
Name: lo-LA-KeomanyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: lt-LT-LeonasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: lt-LT-OnaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: lv-LV-EveritaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: lv-LV-NilsNeural
|
||||
Gender: Male
|
||||
|
||||
Name: mk-MK-AleksandarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: mk-MK-MarijaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ml-IN-MidhunNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ml-IN-SobhanaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: mn-MN-BataaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: mn-MN-YesuiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: mr-IN-AarohiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: mr-IN-ManoharNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ms-MY-OsmanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ms-MY-YasminNeural
|
||||
Gender: Female
|
||||
|
||||
Name: mt-MT-GraceNeural
|
||||
Gender: Female
|
||||
|
||||
Name: mt-MT-JosephNeural
|
||||
Gender: Male
|
||||
|
||||
Name: my-MM-NilarNeural
|
||||
Gender: Female
|
||||
|
||||
Name: my-MM-ThihaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: nb-NO-FinnNeural
|
||||
Gender: Male
|
||||
|
||||
Name: nb-NO-PernilleNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ne-NP-HemkalaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ne-NP-SagarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: nl-BE-ArnaudNeural
|
||||
Gender: Male
|
||||
|
||||
Name: nl-BE-DenaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: nl-NL-ColetteNeural
|
||||
Gender: Female
|
||||
|
||||
Name: nl-NL-FennaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: nl-NL-MaartenNeural
|
||||
Gender: Male
|
||||
|
||||
Name: pl-PL-MarekNeural
|
||||
Gender: Male
|
||||
|
||||
Name: pl-PL-ZofiaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ps-AF-GulNawazNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ps-AF-LatifaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-BR-AntonioNeural
|
||||
Gender: Male
|
||||
|
||||
Name: pt-BR-FranciscaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-BR-ThalitaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: pt-PT-DuarteNeural
|
||||
Gender: Male
|
||||
|
||||
Name: pt-PT-RaquelNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ro-RO-AlinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ro-RO-EmilNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ru-RU-DmitryNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ru-RU-SvetlanaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: si-LK-SameeraNeural
|
||||
Gender: Male
|
||||
|
||||
Name: si-LK-ThiliniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sk-SK-LukasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sk-SK-ViktoriaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sl-SI-PetraNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sl-SI-RokNeural
|
||||
Gender: Male
|
||||
|
||||
Name: so-SO-MuuseNeural
|
||||
Gender: Male
|
||||
|
||||
Name: so-SO-UbaxNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sq-AL-AnilaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sq-AL-IlirNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sr-RS-NicholasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sr-RS-SophieNeural
|
||||
Gender: Female
|
||||
|
||||
Name: su-ID-JajangNeural
|
||||
Gender: Male
|
||||
|
||||
Name: su-ID-TutiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sv-SE-MattiasNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sv-SE-SofieNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sw-KE-RafikiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sw-KE-ZuriNeural
|
||||
Gender: Female
|
||||
|
||||
Name: sw-TZ-DaudiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: sw-TZ-RehemaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ta-IN-PallaviNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ta-IN-ValluvarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ta-LK-KumarNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ta-LK-SaranyaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ta-MY-KaniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ta-MY-SuryaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ta-SG-AnbuNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ta-SG-VenbaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: te-IN-MohanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: te-IN-ShrutiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: th-TH-NiwatNeural
|
||||
Gender: Male
|
||||
|
||||
Name: th-TH-PremwadeeNeural
|
||||
Gender: Female
|
||||
|
||||
Name: tr-TR-AhmetNeural
|
||||
Gender: Male
|
||||
|
||||
Name: tr-TR-EmelNeural
|
||||
Gender: Female
|
||||
|
||||
Name: uk-UA-OstapNeural
|
||||
Gender: Male
|
||||
|
||||
Name: uk-UA-PolinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ur-IN-GulNeural
|
||||
Gender: Female
|
||||
|
||||
Name: ur-IN-SalmanNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ur-PK-AsadNeural
|
||||
Gender: Male
|
||||
|
||||
Name: ur-PK-UzmaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: uz-UZ-MadinaNeural
|
||||
Gender: Female
|
||||
|
||||
Name: uz-UZ-SardorNeural
|
||||
Gender: Male
|
||||
|
||||
Name: vi-VN-HoaiMyNeural
|
||||
Gender: Female
|
||||
|
||||
Name: vi-VN-NamMinhNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-CN-XiaoxiaoNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-CN-XiaoyiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-CN-YunjianNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-CN-YunxiNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-CN-YunxiaNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-CN-YunyangNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-CN-liaoning-XiaobeiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-CN-shaanxi-XiaoniNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-HK-HiuGaaiNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-HK-HiuMaanNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-HK-WanLungNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zh-TW-HsiaoChenNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-TW-HsiaoYuNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zh-TW-YunJheNeural
|
||||
Gender: Male
|
||||
|
||||
Name: zu-ZA-ThandoNeural
|
||||
Gender: Female
|
||||
|
||||
Name: zu-ZA-ThembaNeural
|
||||
Gender: Male
|
||||
""".strip()
|
||||
voices = []
|
||||
name = ''
|
||||
for line in voices_str.split("\n"):
|
||||
line = line.strip()
|
||||
if not line:
|
||||
continue
|
||||
if line.startswith("Name: "):
|
||||
name = line[6:].strip()
|
||||
if line.startswith("Gender: "):
|
||||
gender = line[8:].strip()
|
||||
if name and gender:
|
||||
# voices.append({
|
||||
# "name": name,
|
||||
# "gender": gender,
|
||||
# })
|
||||
if filter_locals:
|
||||
for filter_local in filter_locals:
|
||||
if name.lower().startswith(filter_local.lower()):
|
||||
voices.append(f"{name}-{gender}")
|
||||
else:
|
||||
voices.append(f"{name}-{gender}")
|
||||
name = ''
|
||||
voices.sort()
|
||||
return voices
|
||||
|
||||
|
||||
def parse_voice_name(name: str):
|
||||
# zh-CN-XiaoyiNeural-Female
|
||||
# zh-CN-YunxiNeural-Male
|
||||
name = name.replace("-Female", "").replace("-Male", "").strip()
|
||||
return name
|
||||
|
||||
|
||||
def tts(text: str, voice_name: str, voice_file: str) -> [SubMaker, None]:
|
||||
logger.info(f"start, voice name: {voice_name}")
|
||||
try:
|
||||
@@ -101,6 +1079,10 @@ def get_audio_duration(sub_maker: submaker.SubMaker):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
voices = get_all_voices()
|
||||
print(voices)
|
||||
print(len(voices))
|
||||
|
||||
|
||||
async def _do():
|
||||
temp_dir = utils.storage_dir("temp")
|
||||
|
||||
+168
-83
@@ -1,15 +1,28 @@
|
||||
import json
|
||||
import locale
|
||||
import streamlit as st
|
||||
|
||||
st.set_page_config(page_title="MoneyPrinterTurbo", page_icon="🤖", layout="wide",
|
||||
initial_sidebar_state="auto")
|
||||
import sys
|
||||
import os
|
||||
from uuid import uuid4
|
||||
import platform
|
||||
import streamlit.components.v1 as components
|
||||
import toml
|
||||
from loguru import logger
|
||||
from app.models.schema import VideoParams, VideoAspect, VoiceNames, VideoConcatMode
|
||||
from app.services import task as tm, llm
|
||||
|
||||
st.set_page_config(page_title="MoneyPrinterTurbo",
|
||||
page_icon="🤖",
|
||||
layout="wide",
|
||||
initial_sidebar_state="auto",
|
||||
menu_items={
|
||||
'Report a bug': "https://github.com/harry0703/MoneyPrinterTurbo/issues",
|
||||
'About': "# MoneyPrinterTurbo\nSimply provide a topic or keyword for a video, and it will "
|
||||
"automatically generate the video copy, video materials, video subtitles, "
|
||||
"and video background music before synthesizing a high-definition short "
|
||||
"video.\n\nhttps://github.com/harry0703/MoneyPrinterTurbo"
|
||||
})
|
||||
|
||||
from app.models.schema import VideoParams, VideoAspect, VideoConcatMode
|
||||
from app.services import task as tm, llm, voice
|
||||
from app.utils import utils
|
||||
|
||||
hide_streamlit_style = """
|
||||
@@ -21,6 +34,35 @@ st.title("MoneyPrinterTurbo")
|
||||
root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
font_dir = os.path.join(root_dir, "resource", "fonts")
|
||||
song_dir = os.path.join(root_dir, "resource", "songs")
|
||||
i18n_dir = os.path.join(root_dir, "webui", "i18n")
|
||||
config_file = os.path.join(root_dir, "webui", ".streamlit", "webui.toml")
|
||||
|
||||
|
||||
def load_config() -> dict:
|
||||
try:
|
||||
return toml.load(config_file)
|
||||
except Exception as e:
|
||||
return {}
|
||||
|
||||
|
||||
cfg = load_config()
|
||||
|
||||
|
||||
def save_config():
|
||||
with open(config_file, "w", encoding="utf-8") as f:
|
||||
f.write(toml.dumps(cfg))
|
||||
|
||||
|
||||
def get_system_locale():
|
||||
try:
|
||||
loc = locale.getdefaultlocale()
|
||||
# zh_CN, zh_TW return zh
|
||||
# en_US, en_GB return en
|
||||
language_code = loc[0].split("_")[0]
|
||||
return language_code
|
||||
except Exception as e:
|
||||
return "en"
|
||||
|
||||
|
||||
if 'video_subject' not in st.session_state:
|
||||
st.session_state['video_subject'] = ''
|
||||
@@ -28,6 +70,8 @@ if 'video_script' not in st.session_state:
|
||||
st.session_state['video_script'] = ''
|
||||
if 'video_terms' not in st.session_state:
|
||||
st.session_state['video_terms'] = ''
|
||||
if 'ui_language' not in st.session_state:
|
||||
st.session_state['ui_language'] = cfg.get("ui_language", get_system_locale())
|
||||
|
||||
|
||||
def get_all_fonts():
|
||||
@@ -109,113 +153,154 @@ def init_log():
|
||||
|
||||
init_log()
|
||||
|
||||
|
||||
def load_locales():
|
||||
locales = {}
|
||||
for root, dirs, files in os.walk(i18n_dir):
|
||||
for file in files:
|
||||
if file.endswith(".json"):
|
||||
lang = file.split(".")[0]
|
||||
with open(os.path.join(root, file), "r", encoding="utf-8") as f:
|
||||
locales[lang] = json.loads(f.read())
|
||||
return locales
|
||||
|
||||
|
||||
locales = load_locales()
|
||||
|
||||
|
||||
def tr(key):
|
||||
loc = locales.get(st.session_state['ui_language'], {})
|
||||
return loc.get("Translation", {}).get(key, key)
|
||||
|
||||
|
||||
display_languages = []
|
||||
selected_index = 0
|
||||
for i, code in enumerate(locales.keys()):
|
||||
display_languages.append(f"{code} - {locales[code].get('Language')}")
|
||||
if code == st.session_state['ui_language']:
|
||||
selected_index = i
|
||||
|
||||
selected_language = st.selectbox("Language", options=display_languages, label_visibility='collapsed',
|
||||
index=selected_index)
|
||||
if selected_language:
|
||||
code = selected_language.split(" - ")[0].strip()
|
||||
st.session_state['ui_language'] = code
|
||||
cfg['ui_language'] = code
|
||||
save_config()
|
||||
|
||||
panel = st.columns(3)
|
||||
left_panel = panel[0]
|
||||
middle_panel = panel[1]
|
||||
right_panel = panel[2]
|
||||
|
||||
cfg = VideoParams()
|
||||
params = VideoParams()
|
||||
|
||||
with left_panel:
|
||||
with st.container(border=True):
|
||||
st.write("**文案设置**")
|
||||
cfg.video_subject = st.text_input("视频主题(给定一个关键词,:red[AI自动生成]视频文案)",
|
||||
value=st.session_state['video_subject']).strip()
|
||||
st.write(tr("Video Script Settings"))
|
||||
params.video_subject = st.text_input(tr("Video Subject"),
|
||||
value=st.session_state['video_subject']).strip()
|
||||
|
||||
video_languages = [
|
||||
("自动判断(Auto detect)", ""),
|
||||
(tr("Auto Detect"), ""),
|
||||
]
|
||||
for lang in ["zh-CN", "zh-TW", "en-US"]:
|
||||
video_languages.append((lang, lang))
|
||||
for code in ["zh-CN", "zh-TW", "en-US"]:
|
||||
video_languages.append((code, code))
|
||||
|
||||
selected_index = st.selectbox("生成视频脚本的语言(:blue[一般情况AI会自动根据你输入的主题语言输出])",
|
||||
selected_index = st.selectbox(tr("Script Language"),
|
||||
index=0,
|
||||
options=range(len(video_languages)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: video_languages[x][0] # 显示给用户的是标签
|
||||
)
|
||||
cfg.video_language = video_languages[selected_index][1]
|
||||
params.video_language = video_languages[selected_index][1]
|
||||
|
||||
if cfg.video_language:
|
||||
st.write(f"设置AI输出文案语言为: **:red[{cfg.video_language}]**")
|
||||
|
||||
if st.button("点击使用AI根据**主题**生成 【视频文案】 和 【视频关键词】", key="auto_generate_script"):
|
||||
with st.spinner("AI正在生成视频文案和关键词..."):
|
||||
script = llm.generate_script(video_subject=cfg.video_subject, language=cfg.video_language)
|
||||
terms = llm.generate_terms(cfg.video_subject, script)
|
||||
st.toast('AI生成成功')
|
||||
if st.button(tr("Generate Video Script and Keywords"), key="auto_generate_script"):
|
||||
with st.spinner(tr("Generating Video Script and Keywords")):
|
||||
script = llm.generate_script(video_subject=params.video_subject, language=params.video_language)
|
||||
terms = llm.generate_terms(params.video_subject, script)
|
||||
st.session_state['video_script'] = script
|
||||
st.session_state['video_terms'] = ", ".join(terms)
|
||||
|
||||
cfg.video_script = st.text_area(
|
||||
"视频文案(:blue[①可不填,使用AI生成 ②合理使用标点断句,有助于生成字幕])",
|
||||
params.video_script = st.text_area(
|
||||
tr("Video Script"),
|
||||
value=st.session_state['video_script'],
|
||||
height=180
|
||||
)
|
||||
if st.button("点击使用AI根据**文案**生成【视频关键词】", key="auto_generate_terms"):
|
||||
if not cfg.video_script:
|
||||
st.error("请先填写视频文案")
|
||||
if st.button(tr("Generate Video Keywords"), key="auto_generate_terms"):
|
||||
if not params.video_script:
|
||||
st.error(tr("Please Enter the Video Subject"))
|
||||
st.stop()
|
||||
|
||||
with st.spinner("AI正在生成视频关键词..."):
|
||||
terms = llm.generate_terms(cfg.video_subject, cfg.video_script)
|
||||
st.toast('AI生成成功')
|
||||
with st.spinner(tr("Generating Video Keywords")):
|
||||
terms = llm.generate_terms(params.video_subject, params.video_script)
|
||||
st.session_state['video_terms'] = ", ".join(terms)
|
||||
|
||||
cfg.video_terms = st.text_area(
|
||||
"视频关键词(:blue[①可不填,使用AI生成 ②用**英文逗号**分隔,只支持英文])",
|
||||
params.video_terms = st.text_area(
|
||||
tr("Video Keywords"),
|
||||
value=st.session_state['video_terms'],
|
||||
height=50)
|
||||
|
||||
with middle_panel:
|
||||
with st.container(border=True):
|
||||
st.write("**视频设置**")
|
||||
st.write(tr("Video Settings"))
|
||||
video_concat_modes = [
|
||||
("顺序拼接", "sequential"),
|
||||
("随机拼接(推荐)", "random"),
|
||||
(tr("Sequential"), "sequential"),
|
||||
(tr("Random"), "random"),
|
||||
]
|
||||
selected_index = st.selectbox("视频拼接模式",
|
||||
selected_index = st.selectbox(tr("Video Concat Mode"),
|
||||
index=1,
|
||||
options=range(len(video_concat_modes)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: video_concat_modes[x][0] # 显示给用户的是标签
|
||||
)
|
||||
cfg.video_concat_mode = VideoConcatMode(video_concat_modes[selected_index][1])
|
||||
params.video_concat_mode = VideoConcatMode(video_concat_modes[selected_index][1])
|
||||
|
||||
video_aspect_ratios = [
|
||||
("竖屏 9:16(抖音视频)", VideoAspect.portrait.value),
|
||||
("横屏 16:9(西瓜视频)", VideoAspect.landscape.value),
|
||||
# ("方形 1:1", VideoAspect.square.value)
|
||||
(tr("Portrait"), VideoAspect.portrait.value),
|
||||
(tr("Landscape"), VideoAspect.landscape.value),
|
||||
]
|
||||
selected_index = st.selectbox("视频比例",
|
||||
selected_index = st.selectbox(tr("Video Ratio"),
|
||||
options=range(len(video_aspect_ratios)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: video_aspect_ratios[x][0] # 显示给用户的是标签
|
||||
)
|
||||
cfg.video_aspect = VideoAspect(video_aspect_ratios[selected_index][1])
|
||||
params.video_aspect = VideoAspect(video_aspect_ratios[selected_index][1])
|
||||
|
||||
cfg.video_clip_duration = st.selectbox("视频片段最大时长(秒)", options=[2, 3, 4, 5, 6], index=1)
|
||||
cfg.video_count = st.selectbox("同时生成视频数量", options=[1, 2, 3, 4, 5], index=0)
|
||||
params.video_clip_duration = st.selectbox(tr("Clip Duration"), options=[2, 3, 4, 5, 6], index=1)
|
||||
params.video_count = st.selectbox(tr("Number of Videos Generated Simultaneously"), options=[1, 2, 3, 4, 5],
|
||||
index=0)
|
||||
with st.container(border=True):
|
||||
st.write("**音频设置**")
|
||||
# 创建一个映射字典,将原始值映射到友好名称
|
||||
st.write(tr("Audio Settings"))
|
||||
voices = voice.get_all_voices(filter_locals=["zh-CN", "zh-HK", "zh-TW", "en-US"])
|
||||
friendly_names = {
|
||||
voice: voice.
|
||||
replace("female", "女性").
|
||||
replace("male", "男性").
|
||||
replace("zh-CN", "中文").
|
||||
replace("zh-HK", "香港").
|
||||
replace("zh-TW", "台湾").
|
||||
replace("en-US", "英文").
|
||||
replace("Female", tr("Female")).
|
||||
replace("Male", tr("Male")).
|
||||
replace("Neural", "") for
|
||||
voice in VoiceNames}
|
||||
selected_friendly_name = st.selectbox("朗读声音", options=list(friendly_names.values()))
|
||||
voice in voices}
|
||||
saved_voice_name = cfg.get("voice_name", "")
|
||||
saved_voice_name_index = 0
|
||||
if saved_voice_name in friendly_names:
|
||||
saved_voice_name_index = list(friendly_names.keys()).index(saved_voice_name)
|
||||
else:
|
||||
for i, voice in enumerate(voices):
|
||||
if voice.lower().startswith(st.session_state['ui_language'].lower()):
|
||||
saved_voice_name_index = i
|
||||
break
|
||||
|
||||
selected_friendly_name = st.selectbox(tr("Speech Synthesis"),
|
||||
options=list(friendly_names.values()),
|
||||
index=saved_voice_name_index)
|
||||
|
||||
voice_name = list(friendly_names.keys())[list(friendly_names.values()).index(selected_friendly_name)]
|
||||
cfg.voice_name = voice_name
|
||||
params.voice_name = voice_name
|
||||
cfg['voice_name'] = voice_name
|
||||
save_config()
|
||||
|
||||
bgm_options = [
|
||||
("无背景音乐 No BGM", ""),
|
||||
("随机背景音乐 Random BGM", "random"),
|
||||
("自定义背景音乐 Custom BGM", "custom"),
|
||||
(tr("No Background Music"), ""),
|
||||
(tr("Random Background Music"), "random"),
|
||||
(tr("Custom Background Music"), "custom"),
|
||||
]
|
||||
selected_index = st.selectbox("背景音乐",
|
||||
selected_index = st.selectbox(tr("Background Music"),
|
||||
index=1,
|
||||
options=range(len(bgm_options)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: bgm_options[x][0] # 显示给用户的是标签
|
||||
@@ -225,49 +310,49 @@ with middle_panel:
|
||||
|
||||
# 根据选择显示或隐藏组件
|
||||
if bgm_type == "custom":
|
||||
custom_bgm_file = st.text_input("请输入自定义背景音乐的文件路径:")
|
||||
custom_bgm_file = st.text_input(tr("Custom Background Music File"))
|
||||
if custom_bgm_file and os.path.exists(custom_bgm_file):
|
||||
cfg.bgm_file = custom_bgm_file
|
||||
params.bgm_file = custom_bgm_file
|
||||
# st.write(f":red[已选择自定义背景音乐]:**{custom_bgm_file}**")
|
||||
cfg.bgm_volume = st.selectbox("背景音乐音量(0.2表示20%,背景声音不宜过高)",
|
||||
options=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], index=2)
|
||||
params.bgm_volume = st.selectbox(tr("Background Music Volume"),
|
||||
options=[0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0], index=2)
|
||||
|
||||
with right_panel:
|
||||
with st.container(border=True):
|
||||
st.write("**字幕设置**")
|
||||
cfg.subtitle_enabled = st.checkbox("生成字幕(若取消勾选,下面的设置都将不生效)", value=True)
|
||||
st.write(tr("Subtitle Settings"))
|
||||
params.subtitle_enabled = st.checkbox(tr("Enable Subtitles"), value=True)
|
||||
font_names = get_all_fonts()
|
||||
cfg.font_name = st.selectbox("字体", font_names)
|
||||
params.font_name = st.selectbox(tr("Font"), font_names)
|
||||
|
||||
subtitle_positions = [
|
||||
("顶部(top)", "top"),
|
||||
("居中(center)", "center"),
|
||||
("底部(bottom,推荐)", "bottom"),
|
||||
(tr("Top"), "top"),
|
||||
(tr("Middle"), "center"),
|
||||
(tr("Bottom"), "bottom"),
|
||||
]
|
||||
selected_index = st.selectbox("字幕位置",
|
||||
selected_index = st.selectbox(tr("Position"),
|
||||
index=2,
|
||||
options=range(len(subtitle_positions)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: subtitle_positions[x][0] # 显示给用户的是标签
|
||||
)
|
||||
cfg.subtitle_position = subtitle_positions[selected_index][1]
|
||||
params.subtitle_position = subtitle_positions[selected_index][1]
|
||||
|
||||
font_cols = st.columns([0.3, 0.7])
|
||||
with font_cols[0]:
|
||||
cfg.text_fore_color = st.color_picker("字幕颜色", "#FFFFFF")
|
||||
params.text_fore_color = st.color_picker(tr("Font Color"), "#FFFFFF")
|
||||
with font_cols[1]:
|
||||
cfg.font_size = st.slider("字幕大小", 30, 100, 60)
|
||||
params.font_size = st.slider(tr("Font Size"), 30, 100, 60)
|
||||
|
||||
stroke_cols = st.columns([0.3, 0.7])
|
||||
with stroke_cols[0]:
|
||||
cfg.stroke_color = st.color_picker("描边颜色", "#000000")
|
||||
params.stroke_color = st.color_picker(tr("Stroke Color"), "#000000")
|
||||
with stroke_cols[1]:
|
||||
cfg.stroke_width = st.slider("描边粗细", 0.0, 10.0, 1.5)
|
||||
params.stroke_width = st.slider(tr("Stroke Width"), 0.0, 10.0, 1.5)
|
||||
|
||||
start_button = st.button("开始生成视频", use_container_width=True, type="primary")
|
||||
start_button = st.button(tr("Generate Video"), use_container_width=True, type="primary")
|
||||
if start_button:
|
||||
task_id = str(uuid4())
|
||||
if not cfg.video_subject and not cfg.video_script:
|
||||
st.error("视频主题 或 视频文案,不能同时为空")
|
||||
if not params.video_subject and not params.video_script:
|
||||
st.error(tr("Video Script and Subject Cannot Both Be Empty"))
|
||||
scroll_to_bottom()
|
||||
st.stop()
|
||||
|
||||
@@ -283,11 +368,11 @@ if start_button:
|
||||
|
||||
logger.add(log_received)
|
||||
|
||||
st.toast("正在生成视频,请稍候...")
|
||||
logger.info("开始生成视频")
|
||||
logger.info(utils.to_json(cfg))
|
||||
st.toast(tr("Generating Video"))
|
||||
logger.info(tr("Start Generating Video"))
|
||||
logger.info(utils.to_json(params))
|
||||
scroll_to_bottom()
|
||||
|
||||
tm.start(task_id=task_id, params=cfg)
|
||||
tm.start(task_id=task_id, params=params)
|
||||
open_task_folder(task_id)
|
||||
logger.info(f"完成")
|
||||
logger.info(tr("Video Generation Completed"))
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"Language": "English",
|
||||
"Translation": {
|
||||
"Video Script Settings": "**Video Script Settings**",
|
||||
"Video Subject": "Video Subject (Provide a keyword, :red[AI will automatically generate] video script)",
|
||||
"Script Language": "Language for Generating Video Script (AI will automatically output based on the language of your subject)",
|
||||
"Generate Video Script and Keywords": "Click to use AI to generate 【Video Script】 and 【Video Keywords】 based on **subject**",
|
||||
"Auto Detect": "Auto Detect",
|
||||
"Video Script": "Video Script (:blue[① Optional, AI generated ② Proper punctuation helps with subtitle generation])",
|
||||
"Generate Video Keywords": "Click to use AI to generate 【Video Keywords】 based on **script**",
|
||||
"Please Enter the Video Subject": "Please Enter the Video Script First",
|
||||
"Generating Video Script and Keywords": "AI is generating video script and keywords...",
|
||||
"Generating Video Keywords": "AI is generating video keywords...",
|
||||
"Video Keywords": "Video Keywords (:blue[① Optional, AI generated ② Use **English commas** for separation, English only])",
|
||||
"Video Settings": "**Video Settings**",
|
||||
"Video Concat Mode": "Video Concatenation Mode",
|
||||
"Random": "Random Concatenation (Recommended)",
|
||||
"Sequential": "Sequential Concatenation",
|
||||
"Video Ratio": "Video Aspect Ratio",
|
||||
"Portrait": "Portrait 9:16",
|
||||
"Landscape": "Landscape 16:9",
|
||||
"Clip Duration": "Maximum Duration of Video Clips (seconds)",
|
||||
"Number of Videos Generated Simultaneously": "Number of Videos Generated Simultaneously",
|
||||
"Audio Settings": "**Audio Settings**",
|
||||
"Speech Synthesis": "Speech Synthesis Voice",
|
||||
"Male": "Male",
|
||||
"Female": "Female",
|
||||
"Background Music": "Background Music",
|
||||
"No Background Music": "No Background Music",
|
||||
"Random Background Music": "Random Background Music",
|
||||
"Custom Background Music": "Custom Background Music",
|
||||
"Custom Background Music File": "Please enter the file path for custom background music:",
|
||||
"Background Music Volume": "Background Music Volume (0.2 represents 20%, background music should not be too loud)",
|
||||
"Subtitle Settings": "**Subtitle Settings**",
|
||||
"Enable Subtitles": "Enable Subtitles (If unchecked, the settings below will not take effect)",
|
||||
"Font": "Subtitle Font",
|
||||
"Position": "Subtitle Position",
|
||||
"Top": "Top",
|
||||
"Center": "Middle",
|
||||
"Bottom": "Bottom (Recommended)",
|
||||
"Font Size": "Subtitle Font Size",
|
||||
"Font Color": "Subtitle Font Color",
|
||||
"Stroke Color": "Subtitle Outline Color",
|
||||
"Stroke Width": "Subtitle Outline Width",
|
||||
"Generate Video": "Generate Video",
|
||||
"Video Script and Subject Cannot Both Be Empty": "Video Subject and Video Script cannot both be empty",
|
||||
"Generating Video": "Generating video, please wait...",
|
||||
"Start Generating Video": "Start Generating Video",
|
||||
"Video Generation Completed": "Video Generation Completed"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"Language": "简体中文",
|
||||
"Translation": {
|
||||
"Video Script Settings": "**文案设置**",
|
||||
"Video Subject": "视频主题(给定一个关键词,:red[AI自动生成]视频文案)",
|
||||
"Script Language": "生成视频脚本的语言(一般情况AI会自动根据你输入的主题语言输出)",
|
||||
"Generate Video Script and Keywords": "点击使用AI根据**主题**生成 【视频文案】 和 【视频关键词】",
|
||||
"Auto Detect": "自动检测",
|
||||
"Video Script": "视频文案(:blue[①可不填,使用AI生成 ②合理使用标点断句,有助于生成字幕])",
|
||||
"Generate Video Keywords": "点击使用AI根据**文案**生成【视频关键词】",
|
||||
"Please Enter the Video Subject": "请先填写视频文案",
|
||||
"Generating Video Script and Keywords": "AI正在生成视频文案和关键词...",
|
||||
"Generating Video Keywords": "AI正在生成视频关键词...",
|
||||
"Video Keywords": "视频关键词(:blue[①可不填,使用AI生成 ②用**英文逗号**分隔,只支持英文])",
|
||||
"Video Settings": "**视频设置**",
|
||||
"Video Concat Mode": "视频拼接模式",
|
||||
"Random": "随机拼接(推荐)",
|
||||
"Sequential": "顺序拼接",
|
||||
"Video Ratio": "视频比例",
|
||||
"Portrait": "竖屏 9:16(抖音视频)",
|
||||
"Landscape": "横屏 16:9(西瓜视频)",
|
||||
"Clip Duration": "视频片段最大时长(秒)",
|
||||
"Number of Videos Generated Simultaneously": "同时生成视频数量",
|
||||
"Audio Settings": "**音频设置**",
|
||||
"Speech Synthesis": "朗读声音",
|
||||
"Male": "男性",
|
||||
"Female": "女性",
|
||||
"Background Music": "背景音乐",
|
||||
"No Background Music": "无背景音乐",
|
||||
"Random Background Music": "随机背景音乐",
|
||||
"Custom Background Music": "自定义背景音乐",
|
||||
"Custom Background Music File": "请输入自定义背景音乐的文件路径",
|
||||
"Background Music Volume": "背景音乐音量(0.2表示20%,背景声音不宜过高)",
|
||||
"Subtitle Settings": "**字幕设置**",
|
||||
"Enable Subtitles": "启用字幕(若取消勾选,下面的设置都将不生效)",
|
||||
"Font": "字幕字体",
|
||||
"Position": "字幕位置",
|
||||
"Top": "顶部",
|
||||
"Center": "中间",
|
||||
"Bottom": "底部(推荐)",
|
||||
"Font Size": "字幕大小",
|
||||
"Font Color": "字幕颜色",
|
||||
"Stroke Color": "描边颜色",
|
||||
"Stroke Width": "描边粗细",
|
||||
"Generate Video": "生成视频",
|
||||
"Video Script and Subject Cannot Both Be Empty": "视频主题 和 视频文案,不能同时为空",
|
||||
"Generating Video": "正在生成视频,请稍候...",
|
||||
"Start Generating Video": "开始生成视频",
|
||||
"Video Generation Completed": "视频生成完成"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user