Checkpoint Type B pipeline refinement for run-002 and run-003
This commit is contained in:
@@ -103,6 +103,7 @@ def _stage_1a(ctx: PipelineContext, stage1a: dict) -> PipelineContext:
|
||||
core_message=analysis_raw['core_message'],
|
||||
title=analysis_raw['title'],
|
||||
total_pages=analysis_raw.get('total_pages', 1),
|
||||
layout_template=analysis_raw.get('layout_template', 'A'),
|
||||
)
|
||||
ctx.page_structure = PageStructure(roles=stage1a['page_structure'])
|
||||
ctx.topics = [Topic(**raw) for raw in stage1a['topics']]
|
||||
@@ -812,6 +813,13 @@ def _flatten_group_items(groups: list[dict[str, list[str] | str]]) -> list[str]:
|
||||
|
||||
|
||||
def _detect_generic_layout_family(ctx: PipelineContext, raw: str) -> str:
|
||||
template = getattr(getattr(ctx, 'analysis', None), 'layout_template', '') or ''
|
||||
if template == 'B_GOAL':
|
||||
return 'goal-image-stakeholder'
|
||||
if template == 'B_RPP':
|
||||
return 'requirements-process-product'
|
||||
if template == 'B_STACK':
|
||||
return 'section-stack'
|
||||
relation_types = {getattr(t, 'relation_type', '') for t in ctx.topics}
|
||||
if '<DxEffect' in raw or 'stakeholder_effect' in relation_types:
|
||||
return 'goal-image-stakeholder'
|
||||
@@ -832,9 +840,8 @@ def _build_goal_image_stakeholder_layout(ctx: PipelineContext, raw: str) -> dict
|
||||
conclusion_text = _prefer_source_text(conclusion_topic, ctx.analysis.core_message if ctx.analysis else '')
|
||||
|
||||
goal_groups = _extract_grouped_bullets(_extract_heading_block(raw, goal_title), base_indent=0)[:3]
|
||||
goal_popup_lines = _flatten_group_items(goal_groups)
|
||||
process_block_raw = _extract_heading_block(raw, process_title)
|
||||
process_lines = _bullet_lines_from_block(process_block_raw, limit=8)
|
||||
process_lines = _bullet_lines_from_block(process_block_raw, limit=10)
|
||||
process_popup_lines = process_lines[:] or _flatten_group_items(_extract_grouped_bullets(process_block_raw, base_indent=0))
|
||||
|
||||
dx_cards = _load_dx_effect_cards()
|
||||
@@ -849,68 +856,73 @@ def _build_goal_image_stakeholder_layout(ctx: PipelineContext, raw: str) -> dict
|
||||
image_src = ''
|
||||
image_caption = _extract_caption_from_raw(raw) or goal_title
|
||||
|
||||
goal_sections_html = ''.join(
|
||||
'<div style="background:#ffffff; border:1px solid #d6e2ef; border-left:6px solid {color}; border-radius:12px; padding:10px 12px;">'
|
||||
'<div style="font-size:12px; font-weight:900; color:#0f172a; margin-bottom:6px;">{title}</div>'
|
||||
'<ul style="margin:0; padding-left:16px; font-size:8.8px; line-height:1.28; color:#334155;">{items}</ul>'
|
||||
goal_summary_strips = ''.join(
|
||||
'<div style="background:#ffffff; border:1px solid #d6e2ef; border-top:5px solid {color}; border-radius:10px; padding:6px 8px; min-height:60px;">'
|
||||
'<div style="font-size:9.6px; font-weight:900; color:#0f172a; margin-bottom:3px;">{title}</div>'
|
||||
'<div style="font-size:8px; line-height:1.18; color:#334155;">{item}</div>'
|
||||
'</div>'.format(
|
||||
color=color,
|
||||
title=group['title'],
|
||||
items=_line_list_html([_plain_text(str(item)) for item in group.get('items', [])[:1]], floor=170, ceiling=360, margin_bottom=4),
|
||||
item=_trim_visible_copy(_plain_text(str(group.get('items', [''])[0])), floor=90, ceiling=180),
|
||||
)
|
||||
for group, color in zip(goal_groups, ['#c2410c', '#8b6b2e', '#166534'])
|
||||
)
|
||||
goal_popup = _popup_overlay('popup-goal', goal_title, _popup_list_html(goal_popup_lines, floor=240, ceiling=900)) if goal_popup_lines else ''
|
||||
process_popup = _popup_overlay('popup-process', process_title, _popup_list_html(process_popup_lines, floor=240, ceiling=900)) if process_popup_lines else ''
|
||||
stakeholder_popup = _popup_overlay('popup-stakeholder', support_title, _popup_list_html(stakeholder_popup_lines, floor=240, ceiling=900)) if stakeholder_popup_lines else ''
|
||||
|
||||
goal_popup = _popup_overlay('popup-goal', goal_title, _popup_list_html(_flatten_group_items(goal_groups), floor=220, ceiling=900)) if goal_groups else ''
|
||||
process_popup = _popup_overlay('popup-process', process_title, _popup_list_html(process_popup_lines, floor=220, ceiling=900)) if process_popup_lines else ''
|
||||
stakeholder_popup = _popup_overlay('popup-stakeholder', support_title, _popup_list_html(stakeholder_popup_lines, floor=220, ceiling=900)) if stakeholder_popup_lines else ''
|
||||
|
||||
visual_html = _relation_visual(image_src, image_caption).replace('height:220px', 'height:104px').replace('padding:10px', 'padding:4px') if image_src else _section_card('Goal visual', [_trim_visible_copy(_prefer_source_text(goal_topic, ''), floor=120, ceiling=260)], tone='blue')
|
||||
|
||||
goal_card = (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:12px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:15px; font-weight:900; color:#0f172a; margin-bottom:8px;">{goal_title}</div>'
|
||||
'<div style="display:grid; grid-template-columns:1.06fr 0.94fr; gap:10px; align-items:stretch;">'
|
||||
f'<div style="display:flex; flex-direction:column; gap:8px;">{goal_sections_html}</div>'
|
||||
'<div style="display:flex; flex-direction:column; gap:4px;">'
|
||||
f'{_relation_visual(image_src, image_caption).replace("height:220px", "height:132px").replace("padding:10px", "padding:6px")}'
|
||||
f'<div style="font-size:8.5px; line-height:1.2; color:#64748b; text-align:center;">{image_caption}</div>'
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:8px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:12.5px; font-weight:900; color:#0f172a; margin-bottom:5px;">{goal_title}</div>'
|
||||
'<div style="display:grid; grid-template-columns:1.08fr 0.92fr; gap:8px; align-items:start;">'
|
||||
f'<div style="display:grid; grid-template-columns:repeat(3,minmax(0,1fr)); gap:6px; align-items:stretch;">{goal_summary_strips}</div>'
|
||||
'<div style="display:flex; flex-direction:column; gap:3px; align-items:center;">'
|
||||
f'{visual_html}'
|
||||
f'<div style="font-size:7.2px; line-height:1.12; color:#64748b; text-align:center;">{image_caption}</div>'
|
||||
'</div></div>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:6px;">{_popup_button("popup-goal", "Details")}</div>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:4px;">{_popup_button("popup-goal", "Goal details")}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
process_card = (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:10px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:12.5px; font-weight:900; color:#0f172a; margin-bottom:6px;">{process_title}</div>'
|
||||
f'<ul style="margin:0; padding-left:18px; font-size:9px; line-height:1.34; color:#334155;">{_line_list_html(process_lines[:4], floor=190, ceiling=480, margin_bottom=4)}</ul>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:6px;">{_popup_button("popup-process", "Details")}</div>'
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:9px; box-sizing:border-box; min-height:118px;">'
|
||||
f'<div style="font-size:11px; font-weight:900; color:#0f172a; margin-bottom:5px;">{process_title}</div>'
|
||||
f'<ul style="margin:0; padding-left:16px; font-size:8.8px; line-height:1.28; color:#334155;">{_line_list_html(process_lines[:4], floor=160, ceiling=340, margin_bottom=2)}</ul>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:4px;">{_popup_button("popup-process", "Process details")}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
if dx_cards:
|
||||
stakeholder_body = ''.join(
|
||||
'<div style="margin-bottom:8px;">'
|
||||
f'<div style="font-size:10.5px; font-weight:800; color:#1e3a8a; margin-bottom:3px;">{title}</div>'
|
||||
f'<ul style="margin:0; padding-left:14px; font-size:8.6px; line-height:1.3; color:#334155;">{_line_list_html(lines[:1], floor=170, ceiling=380, margin_bottom=3)}</ul>'
|
||||
stakeholder_preview = ''.join(
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-radius:10px; padding:7px 9px;">'
|
||||
f'<div style="font-size:10px; font-weight:800; color:#1e3a8a; margin-bottom:3px;">{title}</div>'
|
||||
f'<div style="font-size:8.4px; line-height:1.24; color:#334155;">{_trim_visible_copy(lines[0], floor=100, ceiling=180) if lines else ""}</div>'
|
||||
'</div>'
|
||||
for title, lines in dx_cards[:3]
|
||||
for title, lines in dx_cards[:4]
|
||||
)
|
||||
else:
|
||||
stakeholder_body = f'<div style="font-size:9.4px; line-height:1.45; color:#475569;">{_trim_visible_copy(_prefer_source_text(support_topic, "No stakeholder detail available."), floor=260, ceiling=560)}</div>'
|
||||
stakeholder_preview = ''.join(
|
||||
f'<div style="font-size:8.8px; line-height:1.3; color:#334155;">{_trim_visible_copy(_prefer_source_text(support_topic, ""), floor=120, ceiling=240)}</div>'
|
||||
)
|
||||
|
||||
stakeholder_card = (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:10px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:13px; font-weight:900; color:#0f172a; margin-bottom:8px;">{support_title}</div>'
|
||||
f'{stakeholder_body}'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:6px;">{_popup_button("popup-stakeholder", "??Details")}</div>'
|
||||
'<div style="background:#f8fafc; border:1px solid #cbd5e1; border-radius:14px; padding:9px; box-sizing:border-box; min-height:118px;">'
|
||||
f'<div style="font-size:11px; font-weight:900; color:#0f172a; margin-bottom:5px;">{support_title}</div>'
|
||||
f'<div style="display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:6px;">{stakeholder_preview}</div>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:4px;">{_popup_button("popup-stakeholder", "Stakeholder details")}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
lower_block = '<div style="display:grid; grid-template-columns:1fr 1fr; gap:10px; align-items:start;">' + process_card + stakeholder_card + '</div>'
|
||||
lower_block = '<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px; align-items:start;">' + process_card + stakeholder_card + '</div>'
|
||||
|
||||
body_inner = f'{goal_card}{lower_block}{goal_popup}{process_popup}{stakeholder_popup}'
|
||||
body_html = _type_b_body_shell(body_inner)
|
||||
sidebar_html = '<div style="width:100%; height:100%; opacity:0; pointer-events:none;"></div>'
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:5px 16px; text-align:center; color:#ffffff; width:100%; height:40px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:11.5px; font-weight:900; line-height:1.28;">{_trim_visible_copy(conclusion_text, floor=150, ceiling=420)}</div>' + '</div>'
|
||||
return {'body_html': body_html, 'sidebar_html': sidebar_html, 'footer_html': footer_html, 'reasoning': 'goal-image-stakeholder layout selected from document content traits'}
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:4px 14px; text-align:center; color:#ffffff; width:100%; height:34px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:10.2px; font-weight:900; line-height:1.18;">{_trim_visible_copy(conclusion_text, floor=140, ceiling=360)}</div>' + '</div>'
|
||||
return {'body_html': body_html, 'sidebar_html': sidebar_html, 'footer_html': footer_html, 'reasoning': 'goal/effect Type B layout selected from document content traits'}
|
||||
|
||||
|
||||
def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -> dict:
|
||||
@@ -935,9 +947,9 @@ def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -
|
||||
product_popup = _popup_overlay('popup-product', product_title, _popup_list_html(_flatten_group_items(product_groups), floor=240, ceiling=940))
|
||||
|
||||
req_cards = ''.join(
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-top:5px solid {color}; border-radius:12px; padding:10px 12px; min-height:104px;">'
|
||||
'<div style="font-size:11px; font-weight:900; color:#0f172a; margin-bottom:6px;">{title}</div>'
|
||||
'<ul style="margin:0; padding-left:16px; font-size:9.2px; line-height:1.38; color:#334155;">{items}</ul>'
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-top:5px solid {color}; border-radius:12px; padding:8px 10px; min-height:90px;">'
|
||||
'<div style="font-size:10px; font-weight:900; color:#0f172a; margin-bottom:5px;">{title}</div>'
|
||||
'<ul style="margin:0; padding-left:15px; font-size:8.7px; line-height:1.3; color:#334155;">{items}</ul>'
|
||||
'</div>'.format(
|
||||
color=color,
|
||||
title=group['title'],
|
||||
@@ -946,9 +958,9 @@ def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -
|
||||
for group, color in zip(req_groups, ['#2563eb', '#7c3aed', '#16a34a'])
|
||||
)
|
||||
requirements_block = (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:12px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:14px; font-weight:900; color:#0f172a; margin-bottom:8px;">{req_title}</div>'
|
||||
f'<div style="display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:8px;">{req_cards}</div>'
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:10px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:13px; font-weight:900; color:#0f172a; margin-bottom:6px;">{req_title}</div>'
|
||||
f'<div style="display:grid; grid-template-columns:repeat(3, minmax(0,1fr)); gap:6px;">{req_cards}</div>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:6px;">{_popup_button("popup-req", "Details")}</div>'
|
||||
'</div>'
|
||||
)
|
||||
@@ -958,15 +970,15 @@ def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -
|
||||
process_left_title = process_left_groups[0]['title'] if process_left_groups else process_title
|
||||
process_left_lines = process_table_lines or _flatten_group_items(process_left_groups)
|
||||
process_left_card = (
|
||||
'<div style="background:#f8fafc; border:1px solid #d7e2f0; border-radius:12px; padding:12px; min-height:142px;">'
|
||||
f'<div style="font-size:11px; font-weight:800; color:#1e3a8a; margin-bottom:6px;">{process_left_title}</div>'
|
||||
f'<ul style="margin:0; padding-left:16px; font-size:9.2px; line-height:1.38; color:#334155;">{_line_list_html(process_left_lines[:4], floor=200, ceiling=500, margin_bottom=3)}</ul>'
|
||||
'<div style="background:#f8fafc; border:1px solid #d7e2f0; border-radius:12px; padding:10px; min-height:126px;">'
|
||||
f'<div style="font-size:10px; font-weight:800; color:#1e3a8a; margin-bottom:5px;">{process_left_title}</div>'
|
||||
f'<ul style="margin:0; padding-left:15px; font-size:8.8px; line-height:1.3; color:#334155;">{_line_list_html(process_left_lines[:4], floor=200, ceiling=500, margin_bottom=2)}</ul>'
|
||||
'</div>'
|
||||
)
|
||||
process_right_cards = ''.join(
|
||||
'<div style="background:#f8fafc; border:1px solid #d7e2f0; border-radius:12px; padding:10px 12px; min-height:66px;">'
|
||||
'<div style="font-size:10.8px; font-weight:800; color:#1e3a8a; margin-bottom:5px;">{title}</div>'
|
||||
'<ul style="margin:0; padding-left:16px; font-size:9px; line-height:1.36; color:#334155;">{items}</ul>'
|
||||
'<div style="background:#f8fafc; border:1px solid #d7e2f0; border-radius:12px; padding:8px 10px; min-height:60px;">'
|
||||
'<div style="font-size:10px; font-weight:800; color:#1e3a8a; margin-bottom:4px;">{title}</div>'
|
||||
'<ul style="margin:0; padding-left:15px; font-size:8.6px; line-height:1.28; color:#334155;">{items}</ul>'
|
||||
'</div>'.format(
|
||||
title=group['title'],
|
||||
items=_line_list_html([_plain_text(str(item)) for item in group.get('items', [])], floor=190, ceiling=420, margin_bottom=3),
|
||||
@@ -976,9 +988,9 @@ def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -
|
||||
process_card = (
|
||||
'<div style="background:#ffffff; border:1px solid #cbd5e1; border-radius:14px; padding:12px; box-sizing:border-box;">'
|
||||
f'<div style="font-size:13px; font-weight:900; color:#0f172a; margin-bottom:8px;">{process_title}</div>'
|
||||
'<div style="display:grid; grid-template-columns:1.12fr 0.88fr; gap:8px; align-items:start;">'
|
||||
'<div style="display:grid; grid-template-columns:1fr 1fr; gap:6px; align-items:start;">'
|
||||
f'{process_left_card}'
|
||||
f'<div style="display:grid; grid-auto-rows:minmax(0,1fr); gap:8px;">{process_right_cards}</div>'
|
||||
f'<div style="display:grid; grid-template-columns:repeat(2,minmax(0,1fr)); gap:6px;">{process_right_cards}</div>'
|
||||
'</div>'
|
||||
f'<div style="display:flex; justify-content:flex-end; margin-top:6px;">{_popup_button("popup-process", "Details")}</div>'
|
||||
'</div>'
|
||||
@@ -999,12 +1011,12 @@ def _build_requirements_process_product_layout(ctx: PipelineContext, raw: str) -
|
||||
'</div>'
|
||||
)
|
||||
|
||||
lower_block = '<div style="display:grid; grid-template-columns:1.02fr 0.98fr; gap:10px; align-items:start;">' + process_card + product_card + '</div>'
|
||||
lower_block = '<div style="display:grid; grid-template-columns:1fr 1fr; gap:8px; align-items:start;">' + process_card + product_card + '</div>'
|
||||
|
||||
body_inner = f'{requirements_block}{lower_block}{req_popup}{process_popup}{product_popup}'
|
||||
body_html = _type_b_body_shell(body_inner)
|
||||
sidebar_html = '<div style="width:100%; height:100%; opacity:0; pointer-events:none;"></div>'
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:7px 16px; text-align:center; color:#ffffff; width:100%; height:48px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:11.5px; font-weight:900; line-height:1.28;">{_trim_visible_copy(conclusion_text, floor=150, ceiling=420)}</div>' + '</div>'
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:5px 14px; text-align:center; color:#ffffff; width:100%; height:40px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:10.6px; font-weight:900; line-height:1.2;">{_trim_visible_copy(conclusion_text, floor=150, ceiling=420)}</div>' + '</div>'
|
||||
return {'body_html': body_html, 'sidebar_html': sidebar_html, 'footer_html': footer_html, 'reasoning': 'requirements-process-product layout selected from document content traits'}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user