diff --git a/apps/scenarios/services.py b/apps/scenarios/services.py index 546ac70..1fdbf83 100644 --- a/apps/scenarios/services.py +++ b/apps/scenarios/services.py @@ -36,15 +36,15 @@ def _get_nested(config: dict, path: tuple[str, ...]): def validate_scenario(config: dict) -> dict: - # 只校验真正影响运行闭环的必填字段; - # 页面展示类字段如 applicable_questions 允许缺失,并在归一化阶段补默认值。 + # 仅校验真正影响运行闭环的必填字段; + # 页面展示字段允许缺失,并在归一化阶段补默认值。 for field_path in REQUIRED_FIELDS: _get_nested(config, field_path) return normalize_scenario(config) def normalize_scenario(config: dict) -> dict: - """补齐页面和其他模块常用的派生字段,减少模板中的条件判断。""" + """补齐页面和其它模块常用的派生字段,避免模板层重复判断。""" normalized = dict(config) normalized["applicable_questions"] = list(config.get("applicable_questions") or []) normalized["rag"] = dict(config.get("rag", {})) @@ -62,16 +62,47 @@ def _scenario_files() -> list[Path]: return sorted([*config_dir.glob("*.yaml"), *config_dir.glob("*.yml")]) +def _read_yaml_file(path: Path) -> dict: + with path.open("r", encoding="utf-8") as file: + return yaml.safe_load(file) or {} + + +def _collect_scenario_load_result() -> tuple[list[dict], list[dict]]: + """ + 统一读取配置目录中的所有场景文件。 + + 返回值: + - scenarios: 校验通过的场景列表 + - issues: 非法 YAML / 缺字段等错误摘要,供首页展示 + """ + scenarios = [] + issues = [] + for path in _scenario_files(): + try: + config = _read_yaml_file(path) + scenarios.append(validate_scenario(config)) + except (yaml.YAMLError, ScenarioValidationError) as exc: + issues.append( + { + "file_name": path.name, + "message": str(exc), + } + ) + return scenarios, issues + + def list_scenarios() -> list[dict]: # 首页每次读取最新 YAML,便于复试现场快速改题。 - scenarios = [] - for path in _scenario_files(): - with path.open("r", encoding="utf-8") as file: - config = yaml.safe_load(file) or {} - scenarios.append(validate_scenario(config)) + scenarios, _issues = _collect_scenario_load_result() return scenarios +def list_scenario_issues() -> list[dict]: + """返回配置异常摘要,便于页面明确提示而不是直接 500。""" + _scenarios, issues = _collect_scenario_load_result() + return issues + + def get_scenario(scenario_id: str) -> dict: for scenario in list_scenarios(): if scenario["id"] == scenario_id: diff --git a/apps/scenarios/views.py b/apps/scenarios/views.py index c17bf5f..ed6c68e 100644 --- a/apps/scenarios/views.py +++ b/apps/scenarios/views.py @@ -1,8 +1,15 @@ from django.shortcuts import render -from .services import list_scenarios +from .services import list_scenario_issues, list_scenarios def index(request): # 首页只消费服务层给出的场景摘要,不自行拼装配置字段。 - return render(request, "scenarios/index.html", {"scenarios": list_scenarios()}) + return render( + request, + "scenarios/index.html", + { + "scenarios": list_scenarios(), + "scenario_issues": list_scenario_issues(), + }, + ) diff --git a/templates/scenarios/index.html b/templates/scenarios/index.html index a7bb3d5..8fbca6d 100644 --- a/templates/scenarios/index.html +++ b/templates/scenarios/index.html @@ -9,6 +9,21 @@
当前首页直接读取 YAML 场景配置。你可以从这里进入对话、上传资料,再用审计日志验证整条执行链路。
+ {% if scenario_issues %} +以下 YAML 场景文件存在问题,系统已自动跳过,不会影响其它合法场景展示。
+