fix(report): FE 问卷键名双侧兼容 + worker 持久事件循环(live E2E 两处修复)
CI / lint / typecheck / import-linter / tests / secrets (push) Canceled after 0s

FE↔后端联调实测暴露并修复:
1. 问卷键名三处错位(FE height_cm/weight_kg/psych_style vs 文档
   height/weight/psyche_style)——vision._bmi 多键取值、diagnosis 维度
   装配与规则上下文双键或运算,两侧谁改键名都不再炸
2. celery worker asyncio.run 每投递起新 loop + 模块级引擎缓存 →
   asyncpg 连接跨 loop(同进程第 3 个报告任务必现 RuntimeError:
   attached to a different loop;集成测试单循环掩盖)。新增
   apps/worker/loop.py 持久 loop,report/ping 两任务接入

E2E 终态: psyche_style/height_weight 恢复、BMI 体型确定值、ok 26/32、
真实 LLM 文案通过校验 degraded=False。
This commit is contained in:
xsl
2026-08-15 01:05:10 +08:00
parent da41e9ab0d
commit cb8a1e3c0f
5 changed files with 56 additions and 13 deletions
+7 -3
View File
@@ -192,7 +192,8 @@ def build_rule_context(
features=tuple(_str_list(derived_features.get("body_features"))),
goals=tuple(_str_list(questionnaire.get("core_goals"))),
occasion=occasion,
style=_str(questionnaire.get("psyche_style")),
style=_str(questionnaire.get("psyche_style"))
or _str(questionnaire.get("psych_style")),
user_taboos=tuple(_str_list(questionnaire.get("taboos"))),
)
@@ -214,7 +215,9 @@ def evaluate_dimensions(
else:
results.append(_skip(_spec("gender"), "问卷未填写性别"))
height, weight = _num(q.get("height")), _num(q.get("weight"))
# FE 发 height_cm/weight_kg(带单位键名),文档口径 height/weight——都认
height = _num(q.get("height_cm")) if q.get("height_cm") is not None else _num(q.get("height"))
weight = _num(q.get("weight_kg")) if q.get("weight_kg") is not None else _num(q.get("weight"))
parts: dict[str, float] = {}
if height is not None:
parts["height"] = height
@@ -538,7 +541,8 @@ def evaluate_dimensions(
all_hits = _rule_keys(verdict)
rule_text_all = _rule_evidence(verdict)
psyche = _str(q.get("psyche_style"))
# FE 发 psych_style,文档口径 psyche_style——都认(联调缝双侧兼容)
psyche = _str(q.get("psyche_style")) or _str(q.get("psych_style"))
if psyche:
results.append(
_ok(
+15 -2
View File
@@ -118,9 +118,22 @@ def _num(value: Any) -> float | None:
return float(value)
def _q_num(questionnaire: Mapping[str, Any], *keys: str) -> float | None:
"""多键取值:FE 发 height_cm/weight_kg,文档口径 height/weight——都认。
FE(ReportCreatePage)用带单位的键名,本函数按传入顺序取第一个可解析
数值,联调两侧谁改键名都不炸。
"""
for key in keys:
value = _num(questionnaire.get(key))
if value is not None:
return value
return None
def _bmi(questionnaire: Mapping[str, Any]) -> float | None:
height = _num(questionnaire.get("height"))
weight = _num(questionnaire.get("weight"))
height = _q_num(questionnaire, "height_cm", "height")
weight = _q_num(questionnaire, "weight_kg", "weight")
if height is None or weight is None or height <= 0:
return None
return weight / (height / 100.0) ** 2