mirror of
https://github.com/linyqh/NarratoAI.git
synced 2026-07-17 11:38:09 +00:00
fix(webui, tests): 修复硬编码路径与组件默认值问题并新增测试
替换音频设置模块的硬编码本地路径为资源目录工具函数,提升跨平台兼容性 修正字幕预览方向选择组件的默认值处理逻辑,移除冗余的默认参数 新增Streamlit组件会话状态合规性测试,确保带key的组件不会同时声明default参数 更新.gitignore以允许提交新增的测试文件
This commit is contained in:
parent
2fbd3d0c25
commit
990fb36e98
1
.gitignore
vendored
1
.gitignore
vendored
@ -53,6 +53,7 @@ tests/*
|
||||
!tests/test_script_service_documentary_unittest.py
|
||||
!tests/test_generate_narration_script_documentary_unittest.py
|
||||
!tests/test_generate_script_docu_unittest.py
|
||||
!tests/test_streamlit_widget_session_state.py
|
||||
|
||||
docs/reddit-community
|
||||
docs/wechat-0.8
|
||||
|
||||
84
tests/test_streamlit_widget_session_state.py
Normal file
84
tests/test_streamlit_widget_session_state.py
Normal file
@ -0,0 +1,84 @@
|
||||
"""Regression coverage for Streamlit widget state initialization."""
|
||||
|
||||
import ast
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parents[1]
|
||||
|
||||
|
||||
def _attribute_name(node: ast.expr) -> str | None:
|
||||
if isinstance(node, ast.Name):
|
||||
return node.id
|
||||
if isinstance(node, ast.Attribute):
|
||||
parent = _attribute_name(node.value)
|
||||
return f"{parent}.{node.attr}" if parent else node.attr
|
||||
return None
|
||||
|
||||
|
||||
def _session_state_key(target: ast.expr) -> str | None:
|
||||
if not isinstance(target, ast.Subscript):
|
||||
return None
|
||||
if _attribute_name(target.value) != "st.session_state":
|
||||
return None
|
||||
if isinstance(target.slice, ast.Constant) and isinstance(target.slice.value, str):
|
||||
return target.slice.value
|
||||
return None
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("source_path", "function_name", "widget_key"),
|
||||
[
|
||||
(
|
||||
"webui/components/audio_settings.py",
|
||||
"render_bgm_settings",
|
||||
"bgm_source_selection",
|
||||
),
|
||||
(
|
||||
"webui/components/subtitle_settings.py",
|
||||
"_render_subtitle_preview_image",
|
||||
"subtitle_preview_orientation",
|
||||
),
|
||||
],
|
||||
)
|
||||
def test_state_initialized_widgets_do_not_also_declare_defaults(
|
||||
source_path: str,
|
||||
function_name: str,
|
||||
widget_key: str,
|
||||
):
|
||||
"""Streamlit warns when a keyed widget has both a default and state value."""
|
||||
module = ast.parse((PROJECT_ROOT / source_path).read_text(encoding="utf-8"))
|
||||
function = next(
|
||||
node
|
||||
for node in module.body
|
||||
if isinstance(node, ast.FunctionDef) and node.name == function_name
|
||||
)
|
||||
|
||||
assigned_keys = {
|
||||
key
|
||||
for node in ast.walk(function)
|
||||
if isinstance(node, ast.Assign)
|
||||
for target in node.targets
|
||||
if (key := _session_state_key(target)) is not None
|
||||
}
|
||||
assert widget_key in assigned_keys
|
||||
|
||||
widget_calls = []
|
||||
for node in ast.walk(function):
|
||||
if not isinstance(node, ast.Call):
|
||||
continue
|
||||
widget_name = _attribute_name(node.func)
|
||||
keywords = {keyword.arg: keyword.value for keyword in node.keywords}
|
||||
key_node = keywords.get("key")
|
||||
if (
|
||||
widget_name is not None
|
||||
and widget_name.startswith("st.")
|
||||
and isinstance(key_node, ast.Constant)
|
||||
and key_node.value == widget_key
|
||||
):
|
||||
widget_calls.append(keywords)
|
||||
|
||||
assert widget_calls
|
||||
assert all("default" not in keywords for keywords in widget_calls)
|
||||
@ -9,7 +9,7 @@ from app.models.schema import AudioVolumeDefaults
|
||||
from app.utils import utils
|
||||
|
||||
|
||||
INDEXTTS_REFERENCE_AUDIO_SOURCE_DIR = "/Users/viccy/Downloads/tts-mp3-clone/mp3"
|
||||
INDEXTTS_REFERENCE_AUDIO_SOURCE_DIR = utils.resource_dir("tts_reference_audio")
|
||||
INDEXTTS_REFERENCE_AUDIO_COPY_SUBDIR = "indextts_refs"
|
||||
INDEXTTS_REFERENCE_AUDIO_MAP = [
|
||||
("yingshijieshuo-zh-male.mp3", "影视解说", "Film Narration"),
|
||||
@ -36,7 +36,7 @@ INDEXTTS_REFERENCE_AUDIO_MAP = [
|
||||
("sarah-en-female.mp3", "莎拉", "Sarah"),
|
||||
]
|
||||
INDEXTTS_REFERENCE_AUDIO_EXTENSIONS = (".mp3", ".wav", ".flac", ".m4a", ".aac", ".ogg")
|
||||
BGM_RESOURCE_DIR = "/Users/viccy/Downloads/tts-mp3-clone/bgms-safe"
|
||||
BGM_RESOURCE_DIR = utils.resource_dir("bgm")
|
||||
BGM_TRACKS_JSON = os.path.join(BGM_RESOURCE_DIR, "tracks.json")
|
||||
BGM_UPLOAD_SUBDIR = "uploaded_bgms"
|
||||
BGM_AUDIO_EXTENSIONS = (".mp3", ".wav", ".flac", ".m4a", ".aac", ".ogg")
|
||||
@ -1965,7 +1965,6 @@ def render_bgm_settings(tr):
|
||||
tr("Background Music Source"),
|
||||
options=list(bgm_source_labels.keys()),
|
||||
selection_mode="single",
|
||||
default=default_bgm_source,
|
||||
key="bgm_source_selection",
|
||||
format_func=lambda source: tr(bgm_source_labels[source]),
|
||||
help=tr("Background Music Source Help"),
|
||||
|
||||
@ -788,11 +788,10 @@ def _render_subtitle_preview_image(tr):
|
||||
orientation = st.pills(
|
||||
tr("Subtitle Preview Orientation"),
|
||||
options=SUBTITLE_PREVIEW_ORIENTATIONS,
|
||||
default=orientation_default,
|
||||
format_func=lambda value: tr(SUBTITLE_PREVIEW_ORIENTATION_LABELS[value]),
|
||||
key="subtitle_preview_orientation",
|
||||
width="stretch",
|
||||
) or "portrait"
|
||||
) or orientation_default
|
||||
_render_subtitle_position_controls(tr, orientation)
|
||||
|
||||
preview_text = tr("Subtitle Preview Sample Text")
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user