@@ -1,6 +1,5 @@
import sys
import os
import time
import sys
# Add the root directory of the project to the system path to allow importing modules from the project
root_dir = os . path . dirname ( os . path . dirname ( os . path . realpath ( __file__ ) ) )
@@ -10,31 +9,33 @@ if root_dir not in sys.path:
print ( sys . path )
print ( " " )
import streamlit as st
import os
from uuid import uuid4
import platform
import streamlit . components . v1 as components
from uuid import uuid4
import streamlit as st
from loguru import logger
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 \n Simply 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 \n https://github.com/harry0703/MoneyPrinterTurbo "
} )
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 \n Simply 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 \n https://github.com/harry0703/MoneyPrinterTurbo " ,
} ,
)
from app . models . schema import VideoParams , VideoAspect , VideoConcatMode , MaterialInfo
from app . services import task as tm , llm , voice
from app . utils import utils
from app . config import config
from app . models . const import FILE_TYPE_VIDEO S , FILE_TYPE_IMAGE S
from app . models . const import FILE_TYPE_IMAGE S , FILE_TYPE_VIDEO S
from app . models . schema import MaterialInfo , VideoAspect , VideoConcatMode , VideoParams
from app . services import llm , voice
from app . services import task as tm
from app . utils import utils
hide_streamlit_style = """
<style>#root > div:nth-child(1) > div > div > div > div > section > div { padding-top: 0rem;}</style>
@@ -42,7 +43,16 @@ hide_streamlit_style = """
st . markdown ( hide_streamlit_style , unsafe_allow_html = True )
st . title ( f " MoneyPrinterTurbo v { config . project_version } " )
support_locales = [ " zh-CN " , " zh-HK " , " zh-TW " , " de-DE " , " en-US " , " fr-FR " , " vi-VN " , " th-TH " ]
support_locales = [
" zh-CN " ,
" zh-HK " ,
" zh-TW " ,
" de-DE " ,
" en-US " ,
" fr-FR " ,
" vi-VN " ,
" th-TH " ,
]
font_dir = os . path . join ( root_dir , " resource " , " fonts " )
song_dir = os . path . join ( root_dir , " resource " , " songs " )
@@ -51,14 +61,14 @@ config_file = os.path.join(root_dir, "webui", ".streamlit", "webui.toml")
system_locale = utils . get_system_locale ( )
# print(f"******** system locale: {system_locale} ********")
if ' video_subject' not in st . session_state :
st . session_state [ ' video_subject' ] = ' '
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' ] = config . ui . get ( " language " , system_locale )
if " video_subject" not in st . session_state :
st . session_state [ " video_subject" ] = " "
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" ] = config . ui . get ( " language " , system_locale )
def get_all_fonts ( ) :
@@ -85,25 +95,25 @@ def open_task_folder(task_id):
sys = platform . system ( )
path = os . path . join ( root_dir , " storage " , " tasks " , task_id )
if os . path . exists ( path ) :
if sys == ' Windows' :
if sys == " Windows" :
os . system ( f " start { path } " )
if sys == ' Darwin' :
if sys == " Darwin" :
os . system ( f " open { path } " )
except Exception as e :
logger . error ( e )
def scroll_to_bottom ( ) :
js = f """
js = """
<script>
console.log( " scroll_to_bottom " );
function scroll(dummy_var_to_force_repeat_execution) { {
function scroll(dummy_var_to_force_repeat_execution) {
var sections = parent.document.querySelectorAll( ' section.main ' );
console.log(sections);
for(let index = 0; index<sections.length; index++) { {
for(let index = 0; index<sections.length; index++) {
sections[index].scrollTop = sections[index].scrollHeight;
} }
} }
}
}
scroll(1);
</script>
"""
@@ -123,12 +133,15 @@ def init_log():
record [ " file " ] . path = f " ./ { relative_path } "
# 返回修改后的格式字符串
# 您可以根据需要调整这里的格式
record [ ' message' ] = record [ ' message' ] . replace ( root_dir , " . " )
record [ " message" ] = record [ " message" ] . replace ( root_dir , " . " )
_format = ' <green> { time: % Y- % m- %d % H: % M: % S}</> | ' + \
' <level> {level} </> | ' + \
' " {file.path} : {line} " :<blue> {function } </> ' + \
' - <level> {message }</> ' + " \n "
_format = (
" <green> { time: % Y- % m- %d % H: % M: % S}</> | "
+ " <level> {level } </> | "
+ ' " {file.path} : {line} " :<blue> {function }</> '
+ " - <level> {message} </> "
+ " \n "
)
return _format
logger . add (
@@ -145,7 +158,7 @@ locales = utils.load_locales(i18n_dir)
def tr ( key ) :
loc = locales . get ( st . session_state [ ' ui_language' ] , { } )
loc = locales . get ( st . session_state [ " ui_language" ] , { } )
return loc . get ( " Translation " , { } ) . get ( key , key )
@@ -164,19 +177,22 @@ if not config.app.get("hide_config", False):
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' ] :
if code == st . session_state [ " ui_language" ] :
selected_index = i
selected_language = st . selectbox ( tr ( " Language " ) , options = display_languages ,
index = selected_index )
selected_language = st . selectbox (
tr ( " Language " ) , options = display_languages , index = selected_index
)
if selected_language :
code = selected_language . split ( " - " ) [ 0 ] . strip ( )
st . session_state [ ' ui_language' ] = code
config . ui [ ' language' ] = code
st . session_state [ " ui_language" ] = code
config . ui [ " language" ] = code
# 是否禁用日志显示
hide_log = st . checkbox ( tr ( " Hide Log " ) , value = config . app . get ( " hide_log " , False ) )
config . ui [ ' hide_log' ] = hide_log
hide_log = st . checkbox (
tr ( " Hide Log " ) , value = config . app . get ( " hide_log" , False )
)
config . ui [ " hide_log " ] = hide_log
with middle_config_panel :
# openai
@@ -187,8 +203,19 @@ if not config.app.get("hide_config", False):
# qwen (通义千问)
# gemini
# ollama
llm_providers = [ ' OpenAI ' , ' Moonshot ' , ' Azure ' , ' Qwen ' , ' DeepSeek ' , ' Gemini ' , ' Ollama ' , ' G4f ' , ' OneAPI ' ,
" Cloudflare " , " ERNIE " ]
llm_providers = [
" OpenAI " ,
" Moonshot " ,
" Azure " ,
" Qwen " ,
" DeepSeek " ,
" Gemini " ,
" Ollama " ,
" G4f " ,
" OneAPI " ,
" Cloudflare " ,
" ERNIE " ,
]
saved_llm_provider = config . app . get ( " llm_provider " , " OpenAI " ) . lower ( )
saved_llm_provider_index = 0
for i , provider in enumerate ( llm_providers ) :
@@ -196,19 +223,25 @@ if not config.app.get("hide_config", False):
saved_llm_provider_index = i
break
llm_provider = st . selectbox ( tr ( " LLM Provider " ) , options = llm_providers , index = saved_llm_provider_index )
llm_provider = st . selectbox (
tr ( " LLM Provider " ) ,
options = llm_providers ,
index = saved_llm_provider_index ,
)
llm_helper = st . container ( )
llm_provider = llm_provider . lower ( )
config . app [ " llm_provider " ] = llm_provider
llm_api_key = config . app . get ( f " { llm_provider } _api_key " , " " )
llm_secret_key = config . app . get ( f " { llm_provider } _secret_key " , " " ) # only for baidu ernie
llm_secret_key = config . app . get (
f " { llm_provider } _secret_key " , " "
) # only for baidu ernie
llm_base_url = config . app . get ( f " { llm_provider } _base_url " , " " )
llm_model_name = config . app . get ( f " { llm_provider } _model_name " , " " )
llm_account_id = config . app . get ( f " { llm_provider } _account_id " , " " )
tips = " "
if llm_provider == ' ollama' :
if llm_provider == " ollama" :
if not llm_model_name :
llm_model_name = " qwen:7b "
if not llm_base_url :
@@ -224,7 +257,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 使用 `ollama list` 查看,比如 `qwen:7b`
"""
if llm_provider == ' openai' :
if llm_provider == " openai" :
if not llm_model_name :
llm_model_name = " gpt-3.5-turbo "
with llm_helper :
@@ -236,7 +269,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 填写**有权限**的模型,[点击查看模型列表](https://platform.openai.com/settings/organization/limits)
"""
if llm_provider == ' moonshot' :
if llm_provider == " moonshot" :
if not llm_model_name :
llm_model_name = " moonshot-v1-8k "
with llm_helper :
@@ -246,9 +279,11 @@ if not config.app.get("hide_config", False):
- **Base Url**: 固定为 https://api.moonshot.cn/v1
- **Model Name**: 比如 moonshot-v1-8k, [点击查看模型列表](https://platform.moonshot.cn/docs/intro# %E 6 % A8 % A1 %E 5 %9E % 8B %E 5 %88% 97 %E 8 % A1 % A8)
"""
if llm_provider == ' oneapi' :
if llm_provider == " oneapi" :
if not llm_model_name :
llm_model_name = " claude-3-5-sonnet-20240620 " # 默认模型,可以根据需要调整
llm_model_name = (
" claude-3-5-sonnet-20240620 " # 默认模型,可以根据需要调整
)
with llm_helper :
tips = """
##### OneAPI 配置说明
@@ -256,8 +291,8 @@ if not config.app.get("hide_config", False):
- **Base Url**: 填写 OneAPI 的基础 URL
- **Model Name**: 填写您要使用的模型名称,例如 claude-3-5-sonnet-20240620
"""
if llm_provider == ' qwen' :
if llm_provider == " qwen" :
if not llm_model_name :
llm_model_name = " qwen-max "
with llm_helper :
@@ -268,7 +303,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 比如 qwen-max, [点击查看模型列表](https://help.aliyun.com/zh/dashscope/developer-reference/model-introduction#3ef6d0bcf91wy)
"""
if llm_provider == ' g4f' :
if llm_provider == " g4f" :
if not llm_model_name :
llm_model_name = " gpt-3.5-turbo "
with llm_helper :
@@ -279,7 +314,7 @@ if not config.app.get("hide_config", False):
- **Base Url**: 留空
- **Model Name**: 比如 gpt-3.5-turbo, [点击查看模型列表](https://github.com/xtekky/gpt4free/blob/main/g4f/models.py#L308)
"""
if llm_provider == ' azure' :
if llm_provider == " azure" :
with llm_helper :
tips = """
##### Azure 配置说明
@@ -289,7 +324,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 填写你实际的部署名
"""
if llm_provider == ' gemini' :
if llm_provider == " gemini" :
if not llm_model_name :
llm_model_name = " gemini-1.0-pro "
@@ -302,7 +337,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 比如 gemini-1.0-pro
"""
if llm_provider == ' deepseek' :
if llm_provider == " deepseek" :
if not llm_model_name :
llm_model_name = " deepseek-chat "
if not llm_base_url :
@@ -315,7 +350,7 @@ if not config.app.get("hide_config", False):
- **Model Name**: 固定为 deepseek-chat
"""
if llm_provider == ' ernie' :
if llm_provider == " ernie" :
with llm_helper :
tips = """
##### 百度文心一言 配置说明
@@ -324,16 +359,23 @@ if not config.app.get("hide_config", False):
- **Base Url**: 填写 **请求地址** [点击查看文档](https://cloud.baidu.com/doc/WENXINWORKSHOP/s/jlil56u11# %E 8 % AF % B7 %E 6 % B1 %82% E8 % AF % B4 %E 6 %98% 8E)
"""
if tips and config . ui [ ' language' ] == ' zh' :
if tips and config . ui [ " language" ] == " zh" :
st . warning (
" 中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商 \n - 国内可直接访问, 不需要VPN \n - 注册就送额度,基本够用 " )
" 中国用户建议使用 **DeepSeek** 或 **Moonshot** 作为大模型提供商 \n - 国内可直接访问, 不需要VPN \n - 注册就送额度,基本够用 "
)
st . info ( tips )
st_llm_api_key = st . text_input ( tr ( " API Key " ) , value = llm_api_key , type = " password " )
st_llm_api_key = st . text_input (
tr ( " API Key " ) , value = llm_api_key , type = " password "
)
st_llm_base_url = st . text_input ( tr ( " Base Url " ) , value = llm_base_url )
st_llm_model_name = " "
if llm_provider != ' ernie' :
st_llm_model_name = st . text_input ( tr ( " Model Name " ) , value = llm_model_name , key = f " { llm_provider } _model_name_input " )
if llm_provider != " ernie" :
st_llm_model_name = st . text_input (
tr ( " Model Name " ) ,
value = llm_model_name ,
key = f " { llm_provider } _model_name_input " ,
)
if st_llm_model_name :
config . app [ f " { llm_provider } _model_name " ] = st_llm_model_name
else :
@@ -345,16 +387,21 @@ if not config.app.get("hide_config", False):
config . app [ f " { llm_provider } _base_url " ] = st_llm_base_url
if st_llm_model_name :
config . app [ f " { llm_provider } _model_name " ] = st_llm_model_name
if llm_provider == ' ernie' :
st_llm_secret_key = st . text_input ( tr ( " Secret Key " ) , value = llm_secret_key , type = " password " )
if llm_provider == " ernie" :
st_llm_secret_key = st . text_input (
tr ( " Secret Key " ) , value = llm_secret_key , type = " password "
)
config . app [ f " { llm_provider } _secret_key " ] = st_llm_secret_key
if llm_provider == ' cloudflare' :
st_llm_account_id = st . text_input ( tr ( " Account ID " ) , value = llm_account_id )
if llm_provider == " cloudflare" :
st_llm_account_id = st . text_input (
tr ( " Account ID " ) , value = llm_account_id
)
if st_llm_account_id :
config . app [ f " { llm_provider } _account_id " ] = st_llm_account_id
with right_config_panel :
def get_keys_from_config ( cfg_key ) :
api_keys = config . app . get ( cfg_key , [ ] )
if isinstance ( api_keys , str ) :
@@ -362,19 +409,21 @@ if not config.app.get("hide_config", False):
api_key = " , " . join ( api_keys )
return api_key
def save_keys_to_config ( cfg_key , value ) :
value = value . replace ( " " , " " )
if value :
config . app [ cfg_key ] = value . split ( " , " )
pexels_api_key = get_keys_from_config ( " pexels_api_keys " )
pexels_api_key = st . text_input ( tr ( " Pexels API Key " ) , value = pexels_api_key , type = " password " )
pexels_api_key = st . text_input (
tr ( " Pexels API Key " ) , value = pexels_api_key , type = " password "
)
save_keys_to_config ( " pexels_api_keys " , pexels_api_key )
pixabay_api_key = get_keys_from_config ( " pixabay_api_keys " )
pixabay_api_key = st . text_input ( tr ( " Pixabay API Key " ) , value = pixabay_api_key , type = " password " )
pixabay_api_key = st . text_input (
tr ( " Pixabay API Key " ) , value = pixabay_api_key , type = " password "
)
save_keys_to_config ( " pixabay_api_keys " , pixabay_api_key )
panel = st . columns ( 3 )
@@ -388,8 +437,9 @@ uploaded_files = []
with left_panel :
with st . container ( border = True ) :
st . write ( tr ( " Video Script Settings " ) )
params . video_subject = st . text_input ( tr ( " Video Subject " ) ,
value = st . session_state [ ' video_subject' ] ) . strip ( )
params . video_subject = st . text_input (
tr ( " Video Subject " ) , value = st . session_state [ " video_subject" ]
) . strip ( )
video_languages = [
( tr ( " Auto Detect " ) , " " ) ,
@@ -397,24 +447,27 @@ with left_panel:
for code in support_locales :
video_languages . append ( ( code , code ) )
selected_index = st . selectbox ( tr ( " Script Language " ) ,
index = 0 ,
options = range ( len ( video_languages ) ) , # 使用索引作为内部选项值
format_func = lambda x : video_languages [ x ] [ 0 ] # 显示给用户的是标签
)
selected_index = st . selectbox (
tr ( " Script Language " ) ,
index = 0 ,
options = range ( len ( video_languages ) ) , # 使用索引作为内部选项值
format_func = lambda x : video_languages [ x ] [ 0 ] , # 显示给用户的是标签
)
params . video_language = video_languages [ selected_index ] [ 1 ]
if st . button ( tr ( " Generate Video Script and Keywords " ) , key = " auto_generate_script " ) :
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 )
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 )
st . session_state [ " video_script" ] = script
st . session_state [ " video_terms" ] = " , " . join ( terms )
params . video_script = st . text_area (
tr ( " Video Script " ) ,
value = st . session_state [ ' video_script ' ] ,
height = 280
tr ( " Video Script " ) , value = st . session_state [ " video_script " ] , height = 280
)
if st . button ( tr ( " Generate Video Keywords " ) , key = " auto_generate_terms " ) :
if not params . video_script :
@@ -423,12 +476,11 @@ with left_panel:
with st . spinner ( tr ( " Generating Video Keywords " ) ) :
terms = llm . generate_terms ( params . video_subject , params . video_script )
st . session_state [ ' video_terms' ] = " , " . join ( terms )
st . session_state [ " video_terms" ] = " , " . join ( terms )
params . video_terms = st . text_area (
tr ( " Video Keywords " ) ,
value = st . session_state [ ' video_terms ' ] ,
height = 50 )
tr ( " Video Keywords " ) , value = st . session_state [ " video_terms " ] , height = 50
)
with middle_panel :
with st . container ( border = True ) :
@@ -447,73 +499,93 @@ with middle_panel:
]
saved_video_source_name = config . app . get ( " video_source " , " pexels " )
saved_video_source_index = [ v [ 1 ] for v in video_sources ] . index ( saved_video_source_name )
saved_video_source_index = [ v [ 1 ] for v in video_sources ] . index (
saved_video_source_name
)
selected_index = st . selectbox ( tr ( " Video Source " ) ,
options = range ( len ( v ideo_s ources ) ) ,
format_func = lambda x : video_sources [ x ] [ 0 ] ,
index = saved_video_source_index
)
selected_index = st . selectbox (
tr ( " V ideo S ource" ) ,
options = range ( len ( video_sources ) ) ,
format_func = lambda x : video_sources [ x ] [ 0 ] ,
index = saved_video_source_index ,
)
params . video_source = video_sources [ selected_index ] [ 1 ]
config . app [ " video_source " ] = params . video_source
if params . video_source == ' local' :
if params . video_source == " local" :
_supported_types = FILE_TYPE_VIDEOS + FILE_TYPE_IMAGES
uploaded_files = st . file_uploader ( " Upload Local Files " ,
type = [ " mp4 " , " mov " , " avi " , " flv " , " mkv " , " jpg " , " jpeg " , " png " ] ,
accept_multiple_files = True )
uploaded_files = st . file_uploader (
" Upload Local Files " ,
type = [ " mp4 " , " mov " , " avi " , " flv " , " mkv " , " jpg " , " jpeg " , " png " ] ,
accept_multiple_files = True ,
)
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 ] # 显示给用户的是标签
)
params . video_concat_mode = VideoConcatMode ( video_concat_modes [ selected_index ] [ 1 ] )
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 ] , # 显示给用户的是标签
)
params . video_concat_mode = VideoConcatMode (
video_concat_modes [ selected_index ] [ 1 ]
)
video_aspect_ratios = [
( tr ( " Portrait " ) , VideoAspect . portrait . value ) ,
( tr ( " Landscape " ) , VideoAspect . landscape . value ) ,
]
selected_index = st . selectbox ( tr ( " Video Ratio " ) ,
options = range ( len ( video_aspect_ratios ) ) , # 使用索引作为内部选项值
format_func = lambda x : video_aspect_ratios [ x ] [ 0 ] # 显示给用户的是标签
)
selected_index = st . selectbox (
tr ( " Video Ratio " ) ,
options = range ( len ( video_aspect_ratios ) ) , # 使用索引作为内部选项值
format_func = lambda x : video_aspect_ratios [ x ] [ 0 ] , # 显示给用户的是标签
)
params . video_aspect = VideoAspect ( video_aspect_ratios [ selected_index ] [ 1 ] )
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 )
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 ( tr ( " Audio Settings " ) )
# tts_providers = ['edge', 'azure']
# tts_provider = st.selectbox(tr("TTS Provider"), tts_providers)
voices = voice . get_all_azure_voices (
filter_locals = support_locales )
voices = voice . get_all_azure_voices ( filter_locals = support_locales )
friendly_names = {
v : v .
replace ( " Fem ale" , tr ( " Fem ale" ) ) .
replace ( " M ale " , tr ( " Male " ) ) .
replace ( " Neural " , " " ) for
v in voices }
v : v . replace ( " Female " , tr ( " Female " ) )
. replace ( " M ale" , tr ( " M ale" ) )
. replace ( " Neur al" , " " )
for v in voices
}
saved_voice_name = config . ui . 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 , v in enumerate ( voices ) :
if v . lower ( ) . startswith ( st . session_state [ ' ui_language ' ] . lower ( ) ) and " V2 " not in v :
if (
v . lower ( ) . startswith ( st . session_state [ " ui_language " ] . lower ( ) )
and " V2 " not in v
) :
saved_voice_name_index = i
break
selected_friendly_name = st . selectbox ( tr ( " Speech Synthesis " ) ,
options = list ( friendly_names . values ( ) ) ,
index = saved_voice_name_index )
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 ) ]
voice_name = list ( friendly_names . keys ( ) ) [
list ( friendly_names . values ( ) ) . index ( selected_friendly_name )
]
params . voice_name = voice_name
config . ui [ ' voice_name' ] = voice_name
config . ui [ " voice_name" ] = voice_name
if st . button ( tr ( " Play Voice " ) ) :
play_content = params . video_subject
@@ -524,11 +596,21 @@ with middle_panel:
with st . spinner ( tr ( " Synthesizing Voice " ) ) :
temp_dir = utils . storage_dir ( " temp " , create = True )
audio_file = os . path . join ( temp_dir , f " tmp-voice- { str ( uuid4 ( ) ) } .mp3 " )
sub_maker = voice . tts ( text = play_content , voice_name = voice_name , voice_rate = params . voice_rate , voice_file = audio_file )
sub_maker = voice . tts (
text = play_content ,
voice_name = voice_name ,
voice_rate = params . voice_rate ,
voice_file = audio_file ,
)
# if the voice file generation failed, try again with a default content.
if not sub_maker :
play_content = " This is a example voice. if you hear this, the voice synthesis failed with the original content. "
sub_maker = voice . tts ( text = play_content , voice_name = voice_name , voice_rate = params . voice_rate , voice_file = audio_file )
sub_maker = voice . tts (
text = play_content ,
voice_name = voice_name ,
voice_rate = params . voice_rate ,
voice_file = audio_file ,
)
if sub_maker and os . path . exists ( audio_file ) :
st . audio ( audio_file , format = " audio/mp3 " )
@@ -536,29 +618,40 @@ with middle_panel:
os . remove ( audio_file )
if voice . is_azure_v2_voice ( voice_name ) :
saved_azure_speech_region = config . azure . get ( f " speech_region " , " " )
saved_azure_speech_key = config . azure . get ( f " speech_key " , " " )
azure_speech_region = st . text_input ( tr ( " Speech Region " ) , value = saved_azure_speech_region )
azure_speech_key = st . text_input ( tr ( " Speech Key " ) , value = saved_azure_speech_key , type = " password " )
saved_azure_speech_region = config . azure . get ( " speech_region " , " " )
saved_azure_speech_key = config . azure . get ( " speech_key " , " " )
azure_speech_region = st . text_input (
tr ( " Speech Region " ) , value = saved_azure_speech_region
)
azure_speech_key = st . text_input (
tr ( " Speech Key " ) , value = saved_azure_speech_key , type = " password "
)
config . azure [ " speech_region " ] = azure_speech_region
config . azure [ " speech_key " ] = azure_speech_key
params . voice_volume = st . selectbox ( tr ( " Speech Volume " ) ,
options = [ 0.6 , 0.8 , 1.0 , 1.2 , 1.5 , 2.0 , 3.0 , 4.0 , 5.0 ] , index = 2 )
params . voice_rate = st . selectbox ( tr ( " Speech Rate " ) ,
options = [ 0.8 , 0.9 , 1.0 , 1.1 , 1.2 , 1.3 , 1.5 , 1.8 , 2.0 ] , index = 2 )
params . voice_volume = st . selectbox (
tr ( " Speech Volume " ) ,
options = [ 0.6 , 0.8 , 1.0 , 1.2 , 1.5 , 2.0 , 3.0 , 4.0 , 5.0 ] ,
index = 2 ,
)
params . voice_rate = st . selectbox (
tr ( " Speech Rate " ) ,
options = [ 0.8 , 0.9 , 1.0 , 1.1 , 1.2 , 1.3 , 1.5 , 1.8 , 2.0 ] ,
index = 2 ,
)
bgm_options = [
( tr ( " No Background Music " ) , " " ) ,
( tr ( " Random Background Music " ) , " random " ) ,
( tr ( " Custom Background Music " ) , " custom " ) ,
]
selected_index = st . selectbox ( tr ( " Background Music " ) ,
index = 1 ,
options = range ( len ( bgm_options ) ) , # 使用索引作为内部选项值
format_func = lambda x : bgm_options [ x ] [ 0 ] # 显示给用户的是标签
)
selected_index = st . selectbox (
tr ( " Background Music " ) ,
index = 1 ,
options = range ( len ( bgm_options ) ) , # 使用索引作为内部选项值
format_func = lambda x : bgm_options [ x ] [ 0 ] , # 显示给用户的是标签
)
# 获取选择的背景音乐类型
params . bgm_type = bgm_options [ selected_index ] [ 1 ]
@@ -568,8 +661,11 @@ with middle_panel:
if custom_bgm_file and os . path . exists ( custom_bgm_file ) :
params . bgm_file = custom_bgm_file
# st.write(f":red[已选择自定义背景音乐]: **{custom_bgm_file}**")
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 )
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 ) :
@@ -580,31 +676,48 @@ with right_panel:
saved_font_name_index = 0
if saved_font_name in font_names :
saved_font_name_index = font_names . index ( saved_font_name )
params . font_name = st . selectbox ( tr ( " Font " ) , font_names , index = saved_font_name_index )
config . ui [ ' font_name ' ] = params . font_name
params . font_name = st . selectbox (
tr ( " Font " ) , font_names , index = saved_ font_name_index
)
config . ui [ " font_name " ] = params . font_name
subtitle_positions = [
( tr ( " Top " ) , " top " ) ,
( tr ( " Center " ) , " center " ) ,
( tr ( " Bottom " ) , " bottom " ) ,
( tr ( " Custom " ) , " custom " ) ,
]
selected_index = st . selectbox ( tr ( " Position " ) ,
index = 2 ,
options = range ( len ( subtitle_positions ) ) , # 使用索引作为内部选项值
format_func = lambda x : subtitle_positions [ x ] [ 0 ] # 显示给用户的是标签
)
selected_index = st . selectbox (
tr ( " Position " ) ,
index = 2 ,
options = range ( len ( subtitle_positions ) ) ,
format_func = lambda x : subtitle_positions [ x ] [ 0 ] ,
)
params . subtitle_position = subtitle_positions [ selected_index ] [ 1 ]
if params . subtitle_position == " custom " :
custom_position = st . text_input (
tr ( " Custom Position ( % f rom top) " ) , value = " 50 "
)
try :
params . custom_position = float ( custom_position )
if params . custom_position < 0 or params . custom_position > 100 :
st . error ( tr ( " Please enter a value between 0 and 100 " ) )
except ValueError :
st . error ( tr ( " Please enter a valid number " ) )
font_cols = st . columns ( [ 0.3 , 0.7 ] )
with font_cols [ 0 ] :
saved_text_fore_color = config . ui . get ( " text_fore_color " , " #FFFFFF " )
params . text_fore_color = st . color_picker ( tr ( " Font Color " ) , saved_text_fore_color )
config . ui [ ' text_fore_color ' ] = params . text_fore_color
params . text_fore_color = st . color_picker (
tr ( " Font Color " ) , saved_ text_fore_color
)
config . ui [ " text_fore_color " ] = params . text_fore_color
with font_cols [ 1 ] :
saved_font_size = config . ui . get ( " font_size " , 60 )
params . font_size = st . slider ( tr ( " Font Size " ) , 30 , 100 , saved_font_size )
config . ui [ ' font_size' ] = params . font_size
config . ui [ " font_size" ] = params . font_size
stroke_cols = st . columns ( [ 0.3 , 0.7 ] )
with stroke_cols [ 0 ] :
@@ -621,7 +734,7 @@ if start_button:
scroll_to_bottom ( )
st . stop ( )
if llm_provider != ' g4f' and not config . app . get ( f " { llm_provider } _api_key " , " " ) :
if llm_provider != " g4f" and not config . app . get ( f " { llm_provider } _api_key " , " " ) :
st . error ( tr ( " Please Enter the LLM API Key " ) )
scroll_to_bottom ( )
st . stop ( )
@@ -657,15 +770,13 @@ if start_button:
log_container = st . empty ( )
log_records = [ ]
def log_received ( msg ) :
if config . ui [ ' hide_log' ] :
if config . ui [ " hide_log" ] :
return
with log_container :
log_records . append ( msg )
st . code ( " \n " . join ( log_records ) )
logger . add ( log_received )
st . toast ( tr ( " Generating Video " ) )
@@ -687,7 +798,7 @@ if start_button:
player_cols = st . columns ( len ( video_files ) * 2 + 1 )
for i , url in enumerate ( video_files ) :
player_cols [ i * 2 + 1 ] . video ( url )
except Exception as e :
except Exception :
pass
open_task_folder ( task_id )