技能提交
This commit is contained in:
1 parent
2215ec3c49
commit
034a379ecd
14 files changed
+287
-118
No files matched your search
@@ -12,6 +12,8 @@
|
||||
6. 让用户选择一个或多个关键传播节点生成策略并入库;受众和节点不能在同一步交叉。
|
||||
7. 同步前端步骤状态,保证原 `item-aiceh` 页面步骤条可继续识别。
|
||||
|
||||
策略入库归属由步骤强制决定:Step5 固定写“目标受众账号”和 `designId + strategyId` 关系,Step6 固定写“关键传播节点账号”和 `pathwayId + strategyId` 关系,不用模型返回的 `accountType` 判断归属。
|
||||
|
||||
## 技能位置
|
||||
|
||||
```text
|
||||
@@ -146,6 +148,8 @@ python scripts/xdfx_flow.py --mode step6 --input xdfx-input.json --state xdfx-fl
|
||||
|
||||
策略信息形式/模态会按前端 `modelType` 字典保存为 value 逗号串,例如模型输出“图片,视频”时,脚本先查 `sys/sys-dict-data` 再写入 `task-action-message.modelType`,不会直接保存中文文字。
|
||||
|
||||
策略关系表写入时,Step5 只写受众 `designId`,Step6 只写传播节点 `pathwayId`;即使模型把 `账号类型/accountType` 生成反了,脚本也会按当前步骤强制纠正,避免受众策略和传播节点策略串写。
|
||||
|
||||
## 输出文件
|
||||
|
||||
执行后查看:
|
||||
|
||||
@@ -73,6 +73,8 @@ python scripts/xdfx_flow.py --mode step6 --input xdfx-input.json --state xdfx-fl
|
||||
|
||||
Step5 只能选择受众生成策略;Step6 只能选择关键传播节点生成策略。不要在同一步里同时传 `--select-strategy-audiences` 和 `--select-strategy-pathways`,受众和关键传播节点不能交叉生成策略。
|
||||
|
||||
策略归属必须由当前步骤强制决定,不能相信模型返回的 `账号类型/accountType`:Step5 固定按“目标受众账号”保存,只写 `designId + strategyId` 关系;Step6 固定按“关键传播节点账号”保存,只写 `pathwayId + strategyId` 关系,严禁把受众策略写到关键传播节点或反向串写。
|
||||
|
||||
脚本每次调用接口前还会输出 `操作反馈 {...}`,包含当前操作、HTTP 方法和 URL。智能体必须用简短中文告诉用户“正在做什么、调用哪个接口”。
|
||||
|
||||
每次保存接口成功拿到返回 ID 后会输出 `入库反馈 {...}`,包含 `入库对象类型`、`入库对象名称`、`返回ID` 和 `接口路径`。智能体必须把它转述成“已入库 xxx 受众 / xxx 脆弱点 / xxx 策略”等明确日志。
|
||||
@@ -106,7 +108,7 @@ python scripts/xdfx_flow.py --mode full --input xdfx-input.json --dry-run
|
||||
- 每个被选中的受众/传播节点默认生成最多 3 个策略,可用 `--max-strategies` 调整。
|
||||
- 每个保存接口必须拿到返回 `id` 才进入下游。
|
||||
- 保存后会同步前端 `task/task-action.step` 步骤状态;如只想入库不更新步骤条,追加 `--no-step-status`。
|
||||
- 策略保存会同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`,兼容策略表格/编排页面读取。
|
||||
- 策略保存会同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`,兼容策略表格/编排页面读取;Step5 只写受众 `designId` 关系,Step6 只写传播节点 `pathwayId` 关系,归属不使用模型返回的 `accountType` 判断。
|
||||
- 策略 `信息形式/模态` 入库前会读取 `sys/sys-dict-data` 的 `modelType` 字典,把模型返回的“图片,视频/文本,图片”等文字转成前端需要的 value 逗号串;字典读取失败时使用内置兜底映射。
|
||||
- Step1 的受众目标抽取结果里,`用户编号列表` / `编号id` / `id` 必须对应上一轮 `zhanghao` 账号数组的索引值;脚本会按这个索引依次找到账号并保存受众账号关系。
|
||||
- 模型流式 `{"answer":"..."}` 会自动拼接。
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -58,6 +58,8 @@ python scripts/xdfx_flow.py --mode step6 --input xdfx-input.json --state xdfx-fl
|
||||
|
||||
Step5 只能选择受众生成策略;Step6 只能选择关键传播节点生成策略。总控不能在同一步混传 `--select-strategy-audiences` 和 `--select-strategy-pathways`。
|
||||
|
||||
策略归属必须由当前步骤强制决定,不能相信模型返回的 `账号类型/accountType`:Step5 固定按“目标受众账号”保存,只写 `designId + strategyId` 关系;Step6 固定按“关键传播节点账号”保存,只写 `pathwayId + strategyId` 关系,严禁把受众策略写到关键传播节点或反向串写。
|
||||
|
||||
每次保存接口成功拿到返回 ID 后会输出 `入库反馈 {...}`。总控必须告诉用户已入库的对象类型、名称和返回 ID,例如“已入库关键传播节点:xxx,pathwayAccountId=123”。
|
||||
|
||||
如果接口或模型处理报错,会立即输出 `错误反馈 {...}`。总控必须立刻把失败阶段、URL、状态码、请求摘要和响应摘要告诉用户。
|
||||
@@ -95,7 +97,7 @@ python scripts/xdfx_run_full_steps.py --input xdfx-input.json --state xdfx-flow-
|
||||
- Step4/Step6 的传播节点下游分析默认从已入库传播节点中选择前 2 个继续;可用 `--downstream-audiences` / `--downstream-pathways` 调成 1 或 2。
|
||||
- Step3-Step6 对上述选中的每个受众/传播节点默认生成最多 3 个脆弱点或策略。
|
||||
- 各步骤会同步前端 `task/task-action.step`;需要禁用时每条命令追加 `--no-step-status`。
|
||||
- 策略步骤会同步写入 channel、narrate、message、策略与受众/传播节点关系表,保证原前端策略表格/编排页可继续读取。
|
||||
- 策略步骤会同步写入 channel、narrate、message、策略与受众/传播节点关系表,保证原前端策略表格/编排页可继续读取;Step5 只写受众 `designId` 关系,Step6 只写传播节点 `pathwayId` 关系,归属不使用模型返回的 `accountType` 判断。
|
||||
- 策略步骤保存 `信息形式/模态` 时,必须使用脚本读取 `sys/sys-dict-data` 的 `modelType` 字典并把文字转成 value 逗号串,不能把“图片,视频”等文字直接写入 `task-action-message.modelType`。
|
||||
- 每个步骤完成都会输出 `步骤反馈`,总控必须逐步转述给用户。
|
||||
- 每次操作和接口调用都会输出 `操作反馈`,总控必须逐条转述当前操作。
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -141,6 +141,7 @@ python scripts/xdfx_run_full_steps.py --input xdfx-input.json --state xdfx-flow-
|
||||
- Step4/Step6 的传播节点下游分析默认从已入库传播节点中选择前 2 个继续;可用 `--downstream-audiences` / `--downstream-pathways` 调成 1 或 2。
|
||||
- Step3-Step6 对上述选中的每个受众/传播节点默认生成最多 3 个脆弱点或策略。
|
||||
- Step5/Step6 的策略模态必须按前端 `modelType` 字典保存为 value 逗号串;脚本会自动把“图片,视频/文本,图片”等文字转成 `task-action-message.modelType` 需要的值。
|
||||
- Step5/Step6 的策略归属由步骤强制决定:Step5 固定写“目标受众账号”和 `designId + strategyId` 关系,Step6 固定写“关键传播节点账号”和 `pathwayId + strategyId` 关系,不用模型返回的 `accountType` 判断归属。
|
||||
|
||||
总控反馈用户时建议使用这种格式:
|
||||
|
||||
@@ -233,7 +234,7 @@ pathwayVulns
|
||||
- 输出 `用户协助`,等待用户选择一个或多个受众;带 `--select-strategy-audiences` 重跑后才生成并保存这些受众的策略。
|
||||
- 本步骤只能选择受众,不能选择或混入关键传播节点。
|
||||
- 保存策略主表。
|
||||
- 同步写入策略 channel、narrate、message 和策略-受众关系。
|
||||
- 同步写入策略 channel、narrate、message 和策略-受众关系;只写 `designId + strategyId`,即使模型返回关键传播节点账号类型也要按受众策略保存。
|
||||
- 同步前端 `step-analysis-strategy`、`step-analysis-strategy-gantt` 状态。
|
||||
|
||||
输出写入:
|
||||
@@ -252,7 +253,7 @@ audienceStrategies
|
||||
- 输出 `用户协助`,等待用户选择一个或多个关键传播节点;带 `--select-strategy-pathways` 重跑后才生成并保存这些传播节点的策略。
|
||||
- 本步骤只能选择关键传播节点,不能选择或混入受众。
|
||||
- 保存策略主表。
|
||||
- 同步写入策略 channel、narrate、message 和策略-传播节点关系。
|
||||
- 同步写入策略 channel、narrate、message 和策略-传播节点关系;只写 `pathwayId + strategyId`,即使模型返回受众账号类型也要按传播节点策略保存。
|
||||
- 同步前端 `step-analysis-strategy`、`step-analysis-strategy-gantt` 状态。
|
||||
|
||||
输出写入:
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -24,7 +24,7 @@ python scripts/xdfx_flow.py --mode step5 --input xdfx-input.json --state xdfx-fl
|
||||
- 流式模型接口首次空响应、模型无响应或超时类返回会自动再调用一次。
|
||||
- 自动解析 `发布人设N / 账号类型N / 信息标题N` 等字段。
|
||||
- 调用策略保存接口。
|
||||
- 同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`。
|
||||
- 同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`;本步骤强制按“目标受众账号”保存,只写 `designId + strategyId` 受众关系,不能使用模型返回的 `账号类型/accountType` 判断归属。
|
||||
- 保存 `task-action-message.modelType` 前会读取前端 `modelType` 字典并把“图片,视频/文本,图片”等模态文字转成 value 逗号串,避免策略表格回显为空。
|
||||
- 同步前端步骤状态 `step-analysis-strategy` 与 `step-analysis-strategy-gantt`。
|
||||
- 保存成功后写入 `audienceStrategies`。
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
@@ -24,7 +24,7 @@ python scripts/xdfx_flow.py --mode step6 --input xdfx-input.json --state xdfx-fl
|
||||
- 流式模型接口首次空响应、模型无响应或超时类返回会自动再调用一次。
|
||||
- 自动解析 `发布人设N / 账号类型N / 信息标题N` 等字段。
|
||||
- 调用策略保存接口。
|
||||
- 同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`。
|
||||
- 同步写入 `task-action-channel`、`base-narrate`、`task-action-message`、`task-action-design-strategy-relation`;本步骤强制按“关键传播节点账号”保存,只写 `pathwayId + strategyId` 传播节点关系,不能使用模型返回的 `账号类型/accountType` 判断归属。
|
||||
- 保存 `task-action-message.modelType` 前会读取前端 `modelType` 字典并把“图片,视频/文本,图片”等模态文字转成 value 逗号串,避免策略表格回显为空。
|
||||
- 同步前端步骤状态 `step-analysis-strategy` 与 `step-analysis-strategy-gantt`。
|
||||
- 保存成功后写入 `pathwayStrategies`。
|
||||
|
||||
@@ -2093,6 +2093,15 @@ def strategy_language(value: Any) -> int:
|
||||
return as_int(value) or 3
|
||||
|
||||
|
||||
STRATEGY_ACCOUNT_TYPE_AUDIENCE = "目标受众账号"
|
||||
STRATEGY_ACCOUNT_TYPE_PATHWAY = "关键传播节点账号"
|
||||
|
||||
|
||||
def strategy_account_type(*, audience: bool) -> str:
|
||||
"""Return the fixed account type for the current strategy step."""
|
||||
return STRATEGY_ACCOUNT_TYPE_AUDIENCE if audience else STRATEGY_ACCOUNT_TYPE_PATHWAY
|
||||
|
||||
|
||||
def save_strategy_details(
|
||||
ctx: FlowContext,
|
||||
state: dict[str, Any],
|
||||
@@ -2112,15 +2121,7 @@ def save_strategy_details(
|
||||
platform = strategy_platform(
|
||||
first_present(strategy.get("platform"), state.get("platform"), platform_label(item.get("account") or {}))
|
||||
)
|
||||
account_type = str(
|
||||
first_present(
|
||||
strategy.get("accountType"),
|
||||
item.get("accountType"),
|
||||
item.get("type"),
|
||||
"目标受众账号" if audience else "关键传播节点账号",
|
||||
)
|
||||
or ""
|
||||
).strip()
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
persona = strategy.get("persona") or "专业议题分析者"
|
||||
persona_size = chat_number(strategy.get("personaSize"), 3)
|
||||
responding_count = chat_number(first_present(strategy.get("respondingCount"), strategy.get("数量")), 10)
|
||||
@@ -2164,8 +2165,18 @@ def save_strategy_details(
|
||||
stage + "/save-message",
|
||||
)
|
||||
|
||||
design_ids = [item.get("designId")] if audience else item.get("designIds") or []
|
||||
pathway_ids = [] if audience else [item.get("pathwayAccountId")]
|
||||
# Strategy ownership must never be inferred from model text or mixed
|
||||
# relations: Step5 writes only audience designId, Step6 writes only pathwayId.
|
||||
if audience:
|
||||
design_ids = [item.get("designId")]
|
||||
pathway_ids: list[Any] = []
|
||||
if not any(design_ids):
|
||||
record_error(state, stage, "受众策略缺少 designId,无法写入受众策略关系", request=item)
|
||||
else:
|
||||
design_ids = []
|
||||
pathway_ids = [first_present(item.get("pathwayAccountId"), item.get("pathwayId"))]
|
||||
if not any(pathway_ids):
|
||||
record_error(state, stage, "关键传播节点策略缺少 pathwayId,无法写入传播节点策略关系", request=item)
|
||||
for design_id in [x for x in design_ids if x]:
|
||||
save_with_id(ctx, state, "save_strategy_relation", {"designId": design_id, "strategyId": strategy_id}, stage + "/save-strategy-relation")
|
||||
for pathway_id in [x for x in pathway_ids if x]:
|
||||
@@ -2901,7 +2912,16 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
strategies = extract_strategies(data, ctx.max_strategies)
|
||||
for strategy in strategies:
|
||||
target = (target_names[0] if target_names else "") or (item.get("accountName") if not audience else "")
|
||||
account_type = strategy.get("accountType") or ("目标受众账号" if audience else "关键传播节点账号")
|
||||
account_type = strategy_account_type(audience=audience)
|
||||
returned_account_type = str(first_present(strategy.get("accountType"), item.get("accountType"), item.get("type"), "") or "").strip()
|
||||
if returned_account_type and returned_account_type != account_type:
|
||||
record_event(
|
||||
state,
|
||||
stage,
|
||||
f"模型返回账号类型“{returned_account_type}”与当前步骤不一致,已强制按“{account_type}”入库",
|
||||
{"strategy": strategy, "item": item},
|
||||
)
|
||||
strategy_for_save = {**strategy, "accountType": account_type}
|
||||
topic = f"利用\"{strategy.get('persona') or '专业议题分析者'}\"人设,传播\"{strategy.get('title')}\"主题"
|
||||
if not strategy.get("title"):
|
||||
record_error(state, stage, "策略缺少信息标题,跳过", request=strategy, response=data)
|
||||
@@ -2922,9 +2942,9 @@ def run_strategy_step(ctx: FlowContext, state: dict[str, Any], *, audience: bool
|
||||
if strategy_id is not None:
|
||||
# Frontend strategy pages read these child tables, so a strategy
|
||||
# is not complete until this helper succeeds as far as possible.
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy, topic, stage, audience=audience)
|
||||
save_strategy_details(ctx, state, strategy_id, item, strategy_for_save, topic, stage, audience=audience)
|
||||
existing_topics.add(topic)
|
||||
state[output_key].append({**strategy, "id": strategy_id, "targetAudience": target, "accountType": account_type, "topic": topic, "saveResponse": resp})
|
||||
state[output_key].append({**strategy_for_save, "id": strategy_id, "targetAudience": target, "topic": topic, "saveResponse": resp})
|
||||
if state[output_key]:
|
||||
mark_step_status(ctx, state, ["step-analysis-strategy", "step-analysis-strategy-gantt"], stage + "/step-status")
|
||||
record_event(state, stage, "完成")
|
||||
|
||||
Reference in new issue
Block a user