mirror of
https://github.com/linyqh/NarratoAI.git
synced 2025-12-11 02:12:50 +00:00
优化 webui 代码逻辑
This commit is contained in:
parent
93188e1328
commit
6669b28361
@ -166,7 +166,7 @@ sudo yum install ImageMagick
|
||||
```
|
||||
3. 启动 webui
|
||||
```shell
|
||||
streamlit run ./webui/Main.py --browser.serverAddress=127.0.0.1 --server.enableCORS=True --browser.gatherUsageStats=False
|
||||
streamlit run ./webui/webui.py --browser.serverAddress=127.0.0.1 --server.enableCORS=True --browser.gatherUsageStats=False
|
||||
```
|
||||
4. 访问 http://127.0.0.1:8501
|
||||
|
||||
|
||||
@ -167,7 +167,7 @@ sudo yum install ImageMagick
|
||||
|
||||
3. initiate webui
|
||||
```shell
|
||||
streamlit run ./webui/Main.py --browser.serverAddress=127.0.0.1 --server.enableCORS=True --browser.gatherUsageStats=False
|
||||
streamlit run ./webui/webui.py --browser.serverAddress=127.0.0.1 --server.enableCORS=True --browser.gatherUsageStats=False
|
||||
```
|
||||
4. Access http://127.0.0.1:8501
|
||||
|
||||
|
||||
@ -339,7 +339,7 @@ class VideoClipParams(BaseModel):
|
||||
video_count: Optional[int] = 1 # 视频片段数量
|
||||
video_source: Optional[str] = "local"
|
||||
video_language: Optional[str] = "" # 自动检测
|
||||
video_concat_mode: Optional[VideoConcatMode] = VideoConcatMode.random.value
|
||||
# video_concat_mode: Optional[VideoConcatMode] = VideoConcatMode.random.value
|
||||
|
||||
# # 女性
|
||||
# "zh-CN-XiaoxiaoNeural",
|
||||
@ -366,5 +366,6 @@ class VideoClipParams(BaseModel):
|
||||
font_size: int = 60 # 文字大小
|
||||
stroke_color: Optional[str] = "#000000" # 文字描边颜色
|
||||
stroke_width: float = 1.5 # 文字描边宽度
|
||||
custom_position: float = 70.0 # 自定义位置
|
||||
n_threads: Optional[int] = 2 # 线程数
|
||||
paragraph_number: Optional[int] = 1 # 段落数量
|
||||
|
||||
@ -20,7 +20,9 @@ services:
|
||||
dockerfile: Dockerfile
|
||||
container_name: "api"
|
||||
ports:
|
||||
- "8502:8080"
|
||||
command: [ "python3", "main.py" ]
|
||||
- "8502:22"
|
||||
command: [ "sleep", "48h" ]
|
||||
volumes: *common-volumes
|
||||
environment:
|
||||
- "VPN_PROXY_URL=http://host.docker.internal:7890"
|
||||
restart: always
|
||||
|
||||
@ -40,4 +40,4 @@ pause
|
||||
|
||||
|
||||
rem set HF_ENDPOINT=https://hf-mirror.com
|
||||
streamlit run .\webui\Main.py --browser.gatherUsageStats=False --server.enableCORS=True
|
||||
streamlit run webui.py --browser.gatherUsageStats=False --server.enableCORS=True
|
||||
|
||||
@ -5,24 +5,26 @@ import json
|
||||
import time
|
||||
import datetime
|
||||
import traceback
|
||||
import streamlit as st
|
||||
from uuid import uuid4
|
||||
import platform
|
||||
import streamlit.components.v1 as components
|
||||
from loguru import logger
|
||||
|
||||
# 将项目的根目录添加到系统路径中,以允许从项目导入模块
|
||||
root_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
|
||||
from app.config import config
|
||||
from app.models.const import FILE_TYPE_VIDEOS
|
||||
from app.models.schema import VideoClipParams, VideoAspect, VideoConcatMode
|
||||
from app.services import task as tm, llm, voice, material
|
||||
from app.utils import utils
|
||||
|
||||
# # 将项目的根目录添加到系统路径中,以允许从项目导入模块
|
||||
root_dir = os.path.dirname(os.path.realpath(__file__))
|
||||
if root_dir not in sys.path:
|
||||
sys.path.append(root_dir)
|
||||
print("******** 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 loguru import logger
|
||||
from app.config import config
|
||||
|
||||
st.set_page_config(
|
||||
page_title="NarratoAI",
|
||||
page_icon="📽️",
|
||||
@ -35,11 +37,6 @@ st.set_page_config(
|
||||
},
|
||||
)
|
||||
|
||||
from app.models.const import FILE_TYPE_IMAGES, FILE_TYPE_VIDEOS
|
||||
from app.models.schema import VideoClipParams, VideoAspect, VideoConcatMode
|
||||
from app.services import task as tm, llm, voice, material
|
||||
from app.utils import utils
|
||||
|
||||
proxy_url_http = config.proxy.get("http", "") or os.getenv("VPN_PROXY_URL", "")
|
||||
proxy_url_https = config.proxy.get("https", "") or os.getenv("VPN_PROXY_URL", "")
|
||||
os.environ["HTTP_PROXY"] = proxy_url_http
|
||||
@ -278,18 +275,23 @@ with left_panel:
|
||||
"name": os.path.basename(file),
|
||||
"size": os.path.getsize(file),
|
||||
"file": file,
|
||||
"ctime": os.path.getctime(file) # 获取文件创建时间
|
||||
})
|
||||
|
||||
script_path = [(tr("Auto Generate"), ""), ]
|
||||
for code in [file['file'] for file in script_list]:
|
||||
script_path.append((code, code))
|
||||
# 按创建时间降序排序
|
||||
script_list.sort(key=lambda x: x["ctime"], reverse=True)
|
||||
|
||||
selected_json2 = st.selectbox(tr("Script Files"),
|
||||
index=0,
|
||||
options=range(len(script_path)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: script_path[x][0] # 显示给用户的是标签
|
||||
)
|
||||
params.video_clip_json = script_path[selected_json2][1]
|
||||
# 脚本文件 下拉框
|
||||
script_path = [(tr("Auto Generate"), ""), ]
|
||||
for file in script_list:
|
||||
display_name = file['file'].replace(root_dir, "")
|
||||
script_path.append((display_name, file['file']))
|
||||
selected_script_index = st.selectbox(tr("Script Files"),
|
||||
index=0,
|
||||
options=range(len(script_path)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: script_path[x][0] # 显示给用户的是标签
|
||||
)
|
||||
params.video_clip_json = script_path[selected_script_index][1]
|
||||
video_json_file = params.video_clip_json
|
||||
|
||||
# 视频文件处理
|
||||
@ -310,12 +312,12 @@ with left_panel:
|
||||
for code in [file['file'] for file in video_list]:
|
||||
video_path.append((code, code))
|
||||
|
||||
selected_index2 = st.selectbox(tr("Video File"),
|
||||
index=0,
|
||||
options=range(len(video_path)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: video_path[x][0] # 显示给用户的是标签
|
||||
)
|
||||
params.video_origin_path = video_path[selected_index2][1]
|
||||
selected_video_index = st.selectbox(tr("Video File"),
|
||||
index=0,
|
||||
options=range(len(video_path)), # 使用索引作为内部选项值
|
||||
format_func=lambda x: video_path[x][0] # 显示给用户的是标签
|
||||
)
|
||||
params.video_origin_path = video_path[selected_video_index][1]
|
||||
config.app["video_origin_path"] = params.video_origin_path
|
||||
|
||||
# 从本地上传 mp4 文件
|
||||
@ -341,8 +343,6 @@ with left_panel:
|
||||
st.success(tr("File Uploaded Successfully"))
|
||||
time.sleep(1)
|
||||
st.rerun()
|
||||
# params.video_origin_path = video_path[selected_index2][1]
|
||||
# config.app["video_origin_path"] = params.video_origin_path
|
||||
|
||||
# 剧情内容
|
||||
video_plot = st.text_area(
|
||||
@ -351,12 +351,13 @@ with left_panel:
|
||||
height=180
|
||||
)
|
||||
|
||||
# 生成视频脚本
|
||||
if st.button(tr("Video Script Generate"), key="auto_generate_script"):
|
||||
with st.spinner(tr("Video Script Generate")):
|
||||
if video_json_file == "" and params.video_origin_path != "":
|
||||
# 使用大模型生成视频脚本
|
||||
script = llm.gemini_video2json(
|
||||
video_origin_name=params.video_origin_path.split("\\")[-1],
|
||||
video_origin_name=os.path.basename(params.video_origin_path),
|
||||
video_origin_path=params.video_origin_path,
|
||||
video_plot=video_plot,
|
||||
language=params.video_language,
|
||||
@ -371,12 +372,14 @@ with left_panel:
|
||||
cleaned_string = script.strip("```json").strip("```")
|
||||
st.session_state['video_script_list'] = json.loads(cleaned_string)
|
||||
|
||||
# 视频脚本
|
||||
video_clip_json_details = st.text_area(
|
||||
tr("Video Script"),
|
||||
value=st.session_state['video_clip_json'],
|
||||
height=180
|
||||
)
|
||||
|
||||
# 保存脚本
|
||||
button_columns = st.columns(2)
|
||||
with button_columns[0]:
|
||||
if st.button(tr("Save Script"), key="auto_generate_terms", use_container_width=True):
|
||||
@ -397,20 +400,23 @@ with left_panel:
|
||||
try:
|
||||
data = utils.add_new_timestamps(json.loads(input_json))
|
||||
except Exception as err:
|
||||
raise ValueError(
|
||||
f"视频脚本格式错误,请检查脚本是否符合 JSON 格式;{err} \n\n{traceback.format_exc()}")
|
||||
st.error(f"视频脚本格式错误,请检查脚本是否符合 JSON 格式;{err} \n\n{traceback.format_exc()}")
|
||||
st.stop()
|
||||
|
||||
# 检查是否是一个列表
|
||||
if not isinstance(data, list):
|
||||
raise ValueError("JSON is not a list")
|
||||
st.error("JSON is not a list")
|
||||
st.stop()
|
||||
|
||||
# 检查列表中的每个元素是否包含所需的键
|
||||
required_keys = {"picture", "timestamp", "narration"}
|
||||
for item in data:
|
||||
if not isinstance(item, dict):
|
||||
raise ValueError("List 元素不是字典")
|
||||
st.error("List 元素不是字典")
|
||||
st.stop()
|
||||
if not required_keys.issubset(item.keys()):
|
||||
raise ValueError("Dict 元素不包含必需的键")
|
||||
st.error("Dict 元素不包含必需的键")
|
||||
st.stop()
|
||||
|
||||
# 存储为新的 JSON 文件
|
||||
with open(save_path, 'w', encoding='utf-8') as file:
|
||||
@ -441,13 +447,13 @@ with left_panel:
|
||||
for video_script in video_script_list:
|
||||
try:
|
||||
video_script['path'] = subclip_videos[video_script['timestamp']]
|
||||
except KeyError as e:
|
||||
st.error(f"裁剪视频失败")
|
||||
except KeyError as err:
|
||||
st.error(f"裁剪视频失败 {err}")
|
||||
# logger.debug(f"当前的脚本为:{st.session_state.video_script_list}")
|
||||
else:
|
||||
st.error(tr("请先生成视频脚本"))
|
||||
|
||||
|
||||
# 裁剪视频
|
||||
with button_columns[1]:
|
||||
if st.button(tr("Crop Video"), key="auto_crop_video", use_container_width=True):
|
||||
caijian()
|
||||
@ -456,10 +462,10 @@ with left_panel:
|
||||
with middle_panel:
|
||||
with st.container(border=True):
|
||||
st.write(tr("Video Settings"))
|
||||
video_concat_modes = [
|
||||
(tr("Sequential"), "sequential"),
|
||||
(tr("Random"), "random"),
|
||||
]
|
||||
# video_concat_modes = [
|
||||
# (tr("Sequential"), "sequential"),
|
||||
# (tr("Random"), "random"),
|
||||
# ]
|
||||
# video_sources = [
|
||||
# (tr("Pexels"), "pexels"),
|
||||
# (tr("Pixabay"), "pixabay"),
|
||||
@ -491,16 +497,17 @@ with middle_panel:
|
||||
# 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),
|
||||
@ -512,14 +519,14 @@ with middle_panel:
|
||||
)
|
||||
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, 7, 8, 9, 10], 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, 7, 8, 9, 10], 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"))
|
||||
|
||||
@ -638,7 +645,7 @@ with middle_panel:
|
||||
index=2,
|
||||
)
|
||||
|
||||
# 新右侧面板
|
||||
# 新侧面板
|
||||
with right_panel:
|
||||
with st.container(border=True):
|
||||
st.write(tr("Subtitle Settings"))
|
||||
@ -676,6 +683,7 @@ with right_panel:
|
||||
if params.custom_position < 0 or params.custom_position > 100:
|
||||
st.error(tr("Please enter a value between 0 and 100"))
|
||||
except ValueError:
|
||||
logger.error(f"输入的值无效: {traceback.format_exc()}")
|
||||
st.error(tr("Please enter a valid number"))
|
||||
|
||||
font_cols = st.columns([0.3, 0.7])
|
||||
2
webui.sh
2
webui.sh
@ -47,4 +47,4 @@ done
|
||||
# 等待所有后台任务完成
|
||||
wait
|
||||
echo "所有文件已成功下载到指定目录"
|
||||
streamlit run ./webui/Main.py --browser.serverAddress="0.0.0.0" --server.enableCORS=True --server.maxUploadSize=2048 --browser.gatherUsageStats=False
|
||||
streamlit run webui.py --browser.serverAddress="0.0.0.0" --server.enableCORS=True --server.maxUploadSize=2048 --browser.gatherUsageStats=False
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
"Please Enter the LLM API Key": "Please enter the **LLM API Key**",
|
||||
"Please Enter the Pexels API Key": "Please enter the **Pexels API Key**",
|
||||
"Please Enter the Pixabay API Key": "Please enter the **Pixabay API Key**",
|
||||
"Get Help": "One-stop AI video commentary + automated editing tool\uD83C\uDF89\uD83C\uDF89\uD83C\uDF89\n\nFor any questions or suggestions, you can join the **community channel** for help or discussion: https://discord.gg/WBKChhmZ",
|
||||
"Get Help": "One-stop AI video commentary + automated editing tool\uD83C\uDF89\uD83C\uDF89\uD83C\uDF89\n\nFor any questions or suggestions, you can join the **community channel** for help or discussion: https://github.com/linyqh/NarratoAI/wiki",
|
||||
"Video Source": "Video Source",
|
||||
"TikTok": "TikTok (Support is coming soon)",
|
||||
"Bilibili": "Bilibili (Support is coming soon)",
|
||||
|
||||
@ -73,7 +73,7 @@
|
||||
"Please Enter the LLM API Key": "请先填写大模型 **API Key**",
|
||||
"Please Enter the Pexels API Key": "请先填写 **Pexels API Key**",
|
||||
"Please Enter the Pixabay API Key": "请先填写 **Pixabay API Key**",
|
||||
"Get Help": "一站式 AI 影视解说+自动化剪辑工具\uD83C\uDF89\uD83C\uDF89\uD83C\uDF89\n\n有任何问题或建议,可以加入 **社区频道** 求助或讨论:https://discord.gg/WBKChhmZ",
|
||||
"Get Help": "一站式 AI 影视解说+自动化剪辑工具\uD83C\uDF89\uD83C\uDF89\uD83C\uDF89\n\n有任何问题或建议,可以加入 **社区频道** 求助或讨论:https://github.com/linyqh/NarratoAI/wiki",
|
||||
"Video Source": "视频来源",
|
||||
"TikTok": "抖音 (TikTok 支持中,敬请期待)",
|
||||
"Bilibili": "哔哩哔哩 (Bilibili 支持中,敬请期待)",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user