Generalize retry rendering for run-002 and run-003
This commit is contained in:
@@ -335,6 +335,25 @@ def _plain_text(value: str) -> str:
|
||||
text = re.sub(r'\s+', ' ', text).strip()
|
||||
return text
|
||||
|
||||
|
||||
def _bulletish_lines(text: str, limit: int = 6) -> list[str]:
|
||||
normalized = re.sub(r"\s+", " ", text or "").strip()
|
||||
if not normalized:
|
||||
return []
|
||||
parts = re.split(r"(?:•|\*\*[^*]+\*\*:?|\s+-\s+|\.\s+)", normalized)
|
||||
cleaned = []
|
||||
for part in parts:
|
||||
item = re.sub(r"\s+", " ", part).strip(" -•")
|
||||
if not item:
|
||||
continue
|
||||
if len(item) < 6:
|
||||
continue
|
||||
cleaned.append(item)
|
||||
if cleaned:
|
||||
return cleaned[:limit]
|
||||
sentences = [s.strip() for s in re.split(r"(?<=[.!?])\s+", normalized) if s.strip()]
|
||||
return sentences[:limit]
|
||||
|
||||
def _markdown_section(text: str, start_marker: str, end_marker: str | None = None) -> str:
|
||||
start = text.find(start_marker)
|
||||
if start == -1:
|
||||
@@ -546,40 +565,183 @@ def _relation_visual(image_src: str, caption: str) -> str:
|
||||
)
|
||||
|
||||
|
||||
def _is_run001_style_document(ctx: PipelineContext, raw: str) -> bool:
|
||||
relation_types = {getattr(t, 'relation_type', '') for t in ctx.topics}
|
||||
if {'hierarchy', 'comparison', 'definition', 'problem'} & relation_types:
|
||||
return True
|
||||
return all(keyword in raw for keyword in ['건설산업', 'BIM', 'DX']) and bool(_parse_comparison_rows_from_raw(raw))
|
||||
|
||||
|
||||
def _section_card(title: str, lines: list[str], tone: str = 'blue') -> str:
|
||||
palette = {
|
||||
'orange': ('#fff7ed', '#fdba74', '#9a3412'),
|
||||
'blue': ('#eff6ff', '#93c5fd', '#1e3a8a'),
|
||||
'slate': ('#f8fafc', '#cbd5e1', '#334155'),
|
||||
'green': ('#ecfdf5', '#86efac', '#166534'),
|
||||
}
|
||||
bg, border, text = palette.get(tone, palette['blue'])
|
||||
items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:6px;">{_trim_visible_copy(item, floor=160, ceiling=460)}</li>'
|
||||
for item in lines if item
|
||||
)
|
||||
return (
|
||||
f'<div style="background:{bg}; border:1px solid {border}; border-radius:14px; padding:12px 14px;">'
|
||||
f'<div style="font-size:13px; font-weight:900; color:{text}; margin-bottom:8px;">{title}</div>'
|
||||
f'<ul style="font-size:10.4px; line-height:1.6; color:#334155; padding-left:0; margin:0; list-style:disc;">{items_html}</ul>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
|
||||
def _component_placeholder(title: str, summary: str) -> str:
|
||||
return (
|
||||
'<div style="background:#ffffff; border:1px dashed #94a3b8; border-radius:14px; padding:14px;">'
|
||||
f'<div style="font-size:13px; font-weight:900; color:#334155; margin-bottom:8px;">{title}</div>'
|
||||
f'<div style="font-size:10.4px; line-height:1.62; color:#475569;">{_trim_visible_copy(summary, floor=240, ceiling=560)}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
|
||||
def _build_stage2_retry_html(ctx: PipelineContext, retry_plan: dict) -> dict:
|
||||
raw = ctx.raw_content or ''
|
||||
is_run001_style = _is_run001_style_document(ctx, raw)
|
||||
|
||||
problem_topic = _topic(ctx, 1)
|
||||
definitions_topic = _topic(ctx, 2)
|
||||
relation_topic = _topic(ctx, 3)
|
||||
evidence_topic = _topic(ctx, 4)
|
||||
comparison_topic = _topic(ctx, 5)
|
||||
if is_run001_style:
|
||||
problem_topic = _topic(ctx, 1)
|
||||
definitions_topic = _topic(ctx, 2)
|
||||
relation_topic = _topic(ctx, 3)
|
||||
evidence_topic = _topic(ctx, 4)
|
||||
comparison_topic = _topic(ctx, 5)
|
||||
|
||||
problem_title = problem_topic.title if problem_topic and problem_topic.title else '??? ??'
|
||||
definitions_title = definitions_topic.title if definitions_topic and definitions_topic.title else '?? ??'
|
||||
relation_title = relation_topic.title if relation_topic and relation_topic.title else '??? ????'
|
||||
evidence_title = evidence_topic.title if evidence_topic and evidence_topic.title else '?? ?? ??'
|
||||
comparison_title = comparison_topic.title if comparison_topic and comparison_topic.title else 'DX? BIM? ??'
|
||||
problem_title = problem_topic.title if problem_topic and problem_topic.title else '용어의 혼용'
|
||||
definitions_title = definitions_topic.title if definitions_topic and definitions_topic.title else '용어 정의'
|
||||
relation_title = relation_topic.title if relation_topic and relation_topic.title else '용어간 상호관계'
|
||||
evidence_title = evidence_topic.title if evidence_topic and evidence_topic.title else '혼용 대표 사례'
|
||||
comparison_title = comparison_topic.title if comparison_topic and comparison_topic.title else 'DX와 BIM의 구분'
|
||||
|
||||
problem_bullets = _problem_bullets_from_raw(raw)[:2]
|
||||
all_evidence_bullets = _evidence_bullets_from_raw(raw)
|
||||
evidence_bullets = all_evidence_bullets[:2]
|
||||
definition_sections = _definition_sections_from_raw(raw)[:3]
|
||||
relation_bullets = _relation_bullets_from_raw(raw)[:5]
|
||||
comparison_rows = _parse_comparison_rows_from_raw(raw)
|
||||
problem_bullets = _problem_bullets_from_raw(raw)[:2]
|
||||
all_evidence_bullets = _evidence_bullets_from_raw(raw)
|
||||
evidence_bullets = all_evidence_bullets[:2]
|
||||
definition_sections = _definition_sections_from_raw(raw)[:3]
|
||||
relation_bullets = _relation_bullets_from_raw(raw)[:5]
|
||||
comparison_rows = _parse_comparison_rows_from_raw(raw)
|
||||
|
||||
preferred_axes = ['??', '????', '???', '???']
|
||||
picked_rows = [row for row in comparison_rows if row[0] in preferred_axes]
|
||||
if len(picked_rows) < 4:
|
||||
seen = {row[0] for row in picked_rows}
|
||||
for row in comparison_rows:
|
||||
if row[0] not in seen:
|
||||
picked_rows.append(row)
|
||||
seen.add(row[0])
|
||||
if len(picked_rows) >= 4:
|
||||
break
|
||||
picked_rows = picked_rows[:4]
|
||||
preferred_axes = ['범위', '프로세스', '성과품', '확장성']
|
||||
picked_rows = [row for row in comparison_rows if row[0] in preferred_axes]
|
||||
if len(picked_rows) < 4:
|
||||
seen = {row[0] for row in picked_rows}
|
||||
for row in comparison_rows:
|
||||
if row[0] not in seen:
|
||||
picked_rows.append(row)
|
||||
seen.add(row[0])
|
||||
if len(picked_rows) >= 4:
|
||||
break
|
||||
picked_rows = picked_rows[:4]
|
||||
|
||||
image_src = _extract_image_src_from_raw(raw)
|
||||
if image_src and ctx.base_path:
|
||||
candidate = Path(ctx.base_path) / image_src.lstrip('/\\').replace('/', '\\')
|
||||
if not candidate.exists():
|
||||
image_src = ''
|
||||
else:
|
||||
image_src = ''
|
||||
image_caption = _extract_caption_from_raw(raw)
|
||||
conclusion_text = _conclusion_from_raw(raw)
|
||||
|
||||
problem_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:5px;">{_trim_visible_copy(item, floor=130, ceiling=280)}</li>'
|
||||
for item in problem_bullets
|
||||
)
|
||||
evidence_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:5px;">{_trim_visible_copy(item, floor=140, ceiling=320)}</li>'
|
||||
for item in evidence_bullets
|
||||
)
|
||||
relation_items_html = ''.join(
|
||||
f'<li style="margin-left:18px; margin-bottom:6px;">{_trim_visible_copy(item, floor=120, ceiling=260)}</li>'
|
||||
for item in relation_bullets
|
||||
)
|
||||
|
||||
definition_cards_html = ''
|
||||
for idx, section in enumerate(definition_sections, start=1):
|
||||
definition_cards_html += (
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-radius:14px; padding:12px; display:flex; gap:10px; align-items:flex-start; min-height:108px;">'
|
||||
f'<div style="width:34px; height:34px; border-radius:999px; background:#2563eb; color:#fff; font-size:15px; font-weight:800; display:flex; align-items:center; justify-content:center; flex-shrink:0;">{idx}</div>'
|
||||
'<div style="flex:1;">'
|
||||
f'<div style="font-size:13px; font-weight:800; color:#0f172a; margin-bottom:6px; line-height:1.35;">{section["title"]}</div>'
|
||||
f'<div style="font-size:10px; line-height:1.58; color:#334155; word-break:keep-all;">{_trim_visible_copy(section["body"], floor=220, ceiling=520)}</div>'
|
||||
'</div></div>'
|
||||
)
|
||||
|
||||
comparison_rows_html = ''
|
||||
for axis, dx, bim in picked_rows:
|
||||
comparison_rows_html += (
|
||||
'<div style="display:grid; grid-template-columns:1fr 86px 1fr; border-top:1px solid #dbe5f2; align-items:stretch;">'
|
||||
f'<div style="padding:7px 10px; font-size:9.8px; line-height:1.42; color:#1e3a8a; font-weight:600; background:#ffffff;">{_trim_visible_copy(dx, floor=110, ceiling=220)}</div>'
|
||||
f'<div style="padding:7px 6px; font-size:9.6px; line-height:1.25; color:#1d4ed8; font-weight:800; text-align:center; background:#eff6ff; border-left:1px solid #dbe5f2; border-right:1px solid #dbe5f2; display:flex; align-items:center; justify-content:center;">{axis}</div>'
|
||||
f'<div style="padding:7px 10px; font-size:9.8px; line-height:1.42; color:#475569; text-align:right; background:#ffffff;">{_trim_visible_copy(bim, floor=110, ceiling=220)}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
evidence_popup_html = _popup_overlay('popup-evidence', evidence_title, _popup_list_html(all_evidence_bullets, floor=220, ceiling=520))
|
||||
comparison_popup_html = _popup_overlay('popup-comparison', comparison_title, _popup_comparison_table(comparison_rows))
|
||||
|
||||
intro_html = (
|
||||
'<div style="background:linear-gradient(135deg,#fff5f5 0%,#ffe8e8 100%); border:2px solid #f8a4a4; border-radius:12px; padding:12px 16px;">'
|
||||
'<div style="display:flex; gap:12px; align-items:flex-start;">'
|
||||
'<div style="font-size:24px; line-height:1; color:#f59e0b; margin-top:2px;">⚠</div>'
|
||||
'<div style="flex:1;">'
|
||||
f'<div style="font-size:12.5px; font-weight:900; color:#b42318; margin-bottom:6px;">{problem_title}</div>'
|
||||
f'<ul style="font-size:9.4px; line-height:1.5; color:#7a271a; padding-left:0; margin:0 0 6px 0; list-style:disc;">{problem_items_html}</ul>'
|
||||
f'<div style="font-size:9px; line-height:1.42; color:#9a3412; margin-top:4px;"><span style="font-weight:800;">{evidence_title}</span></div>'
|
||||
f'<ul style="font-size:8.9px; line-height:1.42; color:#9a3412; padding-left:0; margin:2px 0 0 0; list-style:disc;">{evidence_items_html}</ul>'
|
||||
f'{_popup_button("popup-evidence", "상세 사례")}'
|
||||
'<div style="margin-top:8px; background:#991b1b; color:#ffffff; border-radius:4px; padding:5px 10px; font-size:10px; font-weight:800; word-break:keep-all;">→ 각 용어의 정의, 역할, 상호관계에 대한 체계적 정리 필요</div>'
|
||||
'</div></div></div>'
|
||||
)
|
||||
|
||||
relation_html = (
|
||||
'<div style="background:#ffffff; border:1px solid #d6e2ef; border-radius:14px; padding:10px 12px;">'
|
||||
f'<div style="font-size:14px; font-weight:900; color:#1f3b63; margin-bottom:6px;">{relation_title}</div>'
|
||||
'<div style="display:grid; grid-template-columns:250px 1fr; gap:14px; align-items:start;">'
|
||||
'<div>'
|
||||
f'{_relation_visual(image_src, image_caption).replace("height:220px", "height:210px").replace("padding:10px", "padding:12px")}'
|
||||
f'<div style="margin-top:8px; background:#dcfce7; border:1px solid #86efac; color:#166534; font-size:9px; line-height:1.3; border-radius:999px; padding:4px 10px; text-align:center;">{image_caption}</div>'
|
||||
'</div>'
|
||||
'<div style="display:flex; flex-direction:column; gap:8px;">'
|
||||
f'<ul style="font-size:9px; line-height:1.46; color:#334155; padding-left:0; margin:0; list-style:disc;">{relation_items_html}</ul>'
|
||||
'<div style="margin-top:4px; border:1px solid #b9d3ff; border-radius:10px; overflow:hidden;">'
|
||||
'<div style="display:grid; grid-template-columns:1fr 86px 1fr; background:linear-gradient(135deg,#0d47a1,#1565c0); color:#fff; font-weight:800; font-size:12px; text-align:center;">'
|
||||
'<div style="padding:7px 10px;">DX</div>'
|
||||
'<div style="padding:7px 6px; background:rgba(0,0,0,0.14); font-size:11px;">구분</div>'
|
||||
'<div style="padding:7px 10px;">BIM</div>'
|
||||
'</div>'
|
||||
f'{comparison_rows_html}'
|
||||
'</div>'
|
||||
f'{_popup_button("popup-comparison", "상세 비교 보기")}'
|
||||
'</div></div></div>'
|
||||
)
|
||||
|
||||
body_html = '<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:8px;">' + intro_html + relation_html + evidence_popup_html + comparison_popup_html + '</div>'
|
||||
sidebar_html = '<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; display:flex; flex-direction:column; gap:10px;">' + f'<div style="font-size:12px; font-weight:800; color:#475569; padding:2px 6px;">{definitions_title}</div>' + definition_cards_html + '</div>'
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:58px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:13px; font-weight:900; line-height:1.35;">{conclusion_text}</div>' + '</div>'
|
||||
return {'body_html': body_html, 'sidebar_html': sidebar_html, 'footer_html': footer_html, 'reasoning': 'retry regrouping by content importance: grouped problem+evidence with popup details, relation block, visible comparison summary with full popup, numbered definition cards'}
|
||||
|
||||
main_topics = [t for t in ctx.topics if getattr(t, 'layer', '') != 'conclusion']
|
||||
intro_topic = main_topics[0] if len(main_topics) > 0 else None
|
||||
body_topic = main_topics[1] if len(main_topics) > 1 else None
|
||||
support_topic = main_topics[2] if len(main_topics) > 2 else None
|
||||
conclusion_topic = next((t for t in ctx.topics if getattr(t, 'layer', '') == 'conclusion'), ctx.topics[-1] if ctx.topics else None)
|
||||
|
||||
intro_title = intro_topic.title if intro_topic and intro_topic.title else ctx.analysis.title
|
||||
body_title = body_topic.title if body_topic and body_topic.title else '본문'
|
||||
support_title = support_topic.title if support_topic and support_topic.title else '보조 정보'
|
||||
conclusion_text = _prefer_source_text(conclusion_topic, ctx.analysis.core_message if ctx.analysis else '')
|
||||
|
||||
intro_lines = _bulletish_lines(_prefer_source_text(intro_topic, ''), 6)
|
||||
body_lines = _bulletish_lines(_prefer_source_text(body_topic, ''), 8)
|
||||
support_lines = _bulletish_lines(_prefer_source_text(support_topic, ''), 8)
|
||||
details = _details_blocks(raw)
|
||||
detail_source = details[0] if details else _prefer_source_text(support_topic, '')
|
||||
detail_popup = _popup_overlay('popup-detail', support_title, _popup_list_html(_bulletish_lines(detail_source, 14), floor=200, ceiling=560))
|
||||
|
||||
image_src = _extract_image_src_from_raw(raw)
|
||||
if image_src and ctx.base_path:
|
||||
@@ -588,124 +750,42 @@ def _build_stage2_retry_html(ctx: PipelineContext, retry_plan: dict) -> dict:
|
||||
image_src = ''
|
||||
else:
|
||||
image_src = ''
|
||||
image_caption = _extract_caption_from_raw(raw)
|
||||
conclusion_text = _conclusion_from_raw(raw)
|
||||
image_caption = _extract_caption_from_raw(raw) or body_title
|
||||
|
||||
problem_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:5px;">{_trim_visible_copy(item, floor=130, ceiling=280)}</li>'
|
||||
for item in problem_bullets
|
||||
)
|
||||
evidence_items_html = ''.join(
|
||||
f'<li style="margin-left:16px; margin-bottom:5px;">{_trim_visible_copy(item, floor=140, ceiling=320)}</li>'
|
||||
for item in evidence_bullets
|
||||
)
|
||||
relation_items_html = ''.join(
|
||||
f'<li style="margin-left:18px; margin-bottom:6px;">{_trim_visible_copy(item, floor=120, ceiling=260)}</li>'
|
||||
for item in relation_bullets
|
||||
)
|
||||
intro_card = _section_card(intro_title, intro_lines[:5], tone='orange')
|
||||
body_card = _section_card(body_title, body_lines[:6], tone='blue')
|
||||
|
||||
definition_cards_html = ''
|
||||
for idx, section in enumerate(definition_sections, start=1):
|
||||
definition_cards_html += (
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-radius:14px; padding:12px; display:flex; gap:10px; align-items:flex-start; min-height:108px;">'
|
||||
f'<div style="width:34px; height:34px; border-radius:999px; background:#2563eb; color:#fff; font-size:15px; font-weight:800; display:flex; align-items:center; justify-content:center; flex-shrink:0;">{idx}</div>'
|
||||
'<div style="flex:1;">'
|
||||
f'<div style="font-size:13px; font-weight:800; color:#0f172a; margin-bottom:6px; line-height:1.35;">{section["title"]}</div>'
|
||||
f'<div style="font-size:10px; line-height:1.58; color:#334155; word-break:keep-all;">{_trim_visible_copy(section["body"], floor=220, ceiling=520)}</div>'
|
||||
'</div>'
|
||||
if image_src:
|
||||
visual_block = (
|
||||
'<div style="background:#ffffff; border:1px solid #d7e2f0; border-radius:14px; padding:12px;">'
|
||||
f'{_relation_visual(image_src, image_caption).replace("height:220px", "height:215px")}'
|
||||
f'<div style="margin-top:8px; font-size:9px; color:#166534; text-align:center;">{image_caption}</div>'
|
||||
'</div>'
|
||||
)
|
||||
elif support_topic and '<DxEffect' in (support_topic.source_data or support_topic.summary or ''):
|
||||
visual_block = _component_placeholder(support_title, _prefer_source_text(support_topic, '주체별 기대효과를 보조 영역에서 요약함.'))
|
||||
else:
|
||||
visual_block = _section_card(support_title, support_lines[:5], tone='slate')
|
||||
|
||||
comparison_rows_html = ''
|
||||
for axis, dx, bim in picked_rows:
|
||||
comparison_rows_html += (
|
||||
'<div style="display:grid; grid-template-columns:1fr 86px 1fr; border-top:1px solid #dbe5f2; align-items:stretch;">'
|
||||
f'<div style="padding:7px 10px; font-size:9.8px; line-height:1.42; color:#1e3a8a; font-weight:600; background:#ffffff;">{_trim_visible_copy(dx, floor=110, ceiling=220)}</div>'
|
||||
f'<div style="padding:7px 6px; font-size:9.6px; line-height:1.25; color:#1d4ed8; font-weight:800; text-align:center; background:#eff6ff; border-left:1px solid #dbe5f2; border-right:1px solid #dbe5f2; display:flex; align-items:center; justify-content:center;">{axis}</div>'
|
||||
f'<div style="padding:7px 10px; font-size:9.8px; line-height:1.42; color:#475569; text-align:right; background:#ffffff;">{_trim_visible_copy(bim, floor=110, ceiling=220)}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
evidence_popup_html = _popup_overlay(
|
||||
'popup-evidence',
|
||||
evidence_title,
|
||||
_popup_list_html(all_evidence_bullets, floor=220, ceiling=520),
|
||||
)
|
||||
comparison_popup_html = _popup_overlay(
|
||||
'popup-comparison',
|
||||
comparison_title,
|
||||
_popup_comparison_table(comparison_rows),
|
||||
)
|
||||
|
||||
intro_html = (
|
||||
'<div style="background:linear-gradient(135deg,#fff5f5 0%,#ffe8e8 100%); border:2px solid #f8a4a4; border-radius:12px; padding:12px 16px;">'
|
||||
'<div style="display:flex; gap:12px; align-items:flex-start;">'
|
||||
'<div style="font-size:24px; line-height:1; color:#f59e0b; margin-top:2px;">⚠</div>'
|
||||
'<div style="flex:1;">'
|
||||
f'<div style="font-size:12.5px; font-weight:900; color:#b42318; margin-bottom:6px;">{problem_title}</div>'
|
||||
f'<ul style="font-size:9.4px; line-height:1.5; color:#7a271a; padding-left:0; margin:0 0 6px 0; list-style:disc;">{problem_items_html}</ul>'
|
||||
f'<div style="font-size:9px; line-height:1.42; color:#9a3412; margin-top:4px;"><span style="font-weight:800;">{evidence_title}</span></div>'
|
||||
f'<ul style="font-size:8.9px; line-height:1.42; color:#9a3412; padding-left:0; margin:2px 0 0 0; list-style:disc;">{evidence_items_html}</ul>'
|
||||
f'{_popup_button("popup-evidence", "?? ???")}'
|
||||
'<div style="margin-top:8px; background:#991b1b; color:#ffffff; border-radius:4px; padding:5px 10px; font-size:10px; font-weight:800; word-break:keep-all;">→ ? ??? ??, ??, ????? ?? ??? ?? ??</div>'
|
||||
'</div>'
|
||||
'</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
relation_html = (
|
||||
'<div style="background:#ffffff; border:1px solid #d6e2ef; border-radius:14px; padding:10px 12px;">'
|
||||
f'<div style="font-size:14px; font-weight:900; color:#1f3b63; margin-bottom:6px;">{relation_title}</div>'
|
||||
'<div style="display:grid; grid-template-columns:250px 1fr; gap:14px; align-items:start;">'
|
||||
'<div>'
|
||||
f'{_relation_visual(image_src, image_caption).replace("height:220px", "height:210px").replace("padding:10px", "padding:12px")}'
|
||||
f'<div style="margin-top:8px; background:#dcfce7; border:1px solid #86efac; color:#166534; font-size:9px; line-height:1.3; border-radius:999px; padding:4px 10px; text-align:center;">{image_caption}</div>'
|
||||
'</div>'
|
||||
'<div style="display:flex; flex-direction:column; gap:8px;">'
|
||||
f'<ul style="font-size:9px; line-height:1.46; color:#334155; padding-left:0; margin:0; list-style:disc;">{relation_items_html}</ul>'
|
||||
'<div style="margin-top:4px; border:1px solid #b9d3ff; border-radius:10px; overflow:hidden;">'
|
||||
'<div style="display:grid; grid-template-columns:1fr 86px 1fr; background:linear-gradient(135deg,#0d47a1,#1565c0); color:#fff; font-weight:800; font-size:12px; text-align:center;">'
|
||||
'<div style="padding:7px 10px;">DX</div>'
|
||||
'<div style="padding:7px 6px; background:rgba(0,0,0,0.14); font-size:11px;">??</div>'
|
||||
'<div style="padding:7px 10px;">BIM</div>'
|
||||
'</div>'
|
||||
f'{comparison_rows_html}'
|
||||
'</div>'
|
||||
f'{_popup_button("popup-comparison", "??? ?? ??")}'
|
||||
'</div>'
|
||||
'</div>'
|
||||
'</div>'
|
||||
)
|
||||
sidebar_inner = _section_card(support_title, support_lines[:5], tone='slate') if support_lines else _component_placeholder(support_title, _prefer_source_text(support_topic, '보조 정보가 없음.'))
|
||||
if support_lines:
|
||||
sidebar_inner += _popup_button('popup-detail', '상세 내용 보기')
|
||||
|
||||
body_html = (
|
||||
'<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:8px;">'
|
||||
f'{intro_html}'
|
||||
f'{relation_html}'
|
||||
f'{evidence_popup_html}'
|
||||
f'{comparison_popup_html}'
|
||||
'<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; color:#0f172a; display:flex; flex-direction:column; gap:10px;">'
|
||||
f'{intro_card}'
|
||||
'<div style="display:grid; grid-template-columns:1.05fr 0.95fr; gap:12px; align-items:start;">'
|
||||
f'{body_card}'
|
||||
f'{visual_block}'
|
||||
'</div>'
|
||||
f'{detail_popup}'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
sidebar_html = (
|
||||
'<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; display:flex; flex-direction:column; gap:10px;">'
|
||||
f'<div style="font-size:12px; font-weight:800; color:#475569; padding:2px 6px;">{definitions_title}</div>'
|
||||
f'{definition_cards_html}'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
footer_html = (
|
||||
'<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:58px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">'
|
||||
f'<div style="font-size:13px; font-weight:900; line-height:1.35;">{conclusion_text}</div>'
|
||||
'</div>'
|
||||
)
|
||||
|
||||
return {
|
||||
'body_html': body_html,
|
||||
'sidebar_html': sidebar_html,
|
||||
'footer_html': footer_html,
|
||||
'reasoning': 'retry regrouping by content importance: grouped problem+evidence with popup details, relation block, visible comparison summary with full popup, numbered definition cards',
|
||||
}
|
||||
sidebar_html = '<div style="width:100%; height:100%; box-sizing:border-box; font-family:Segoe UI,sans-serif; display:flex; flex-direction:column; gap:10px;">' + sidebar_inner + '</div>'
|
||||
|
||||
footer_html = '<div style="background:linear-gradient(135deg, #0b6ef3 0%, #17a6f5 100%); border-radius:10px; padding:10px 20px; text-align:center; color:#ffffff; width:100%; height:58px; display:flex; align-items:center; justify-content:center; box-sizing:border-box;">' + f'<div style="font-size:13px; font-weight:900; line-height:1.35;">{_trim_visible_copy(conclusion_text, floor=90, ceiling=240)}</div>' + '</div>'
|
||||
return {'body_html': body_html, 'sidebar_html': sidebar_html, 'footer_html': footer_html, 'reasoning': 'generic retry layout for non-run001 documents: preserve original section titles, visible intro/body/support blocks, and popup detail support'}
|
||||
|
||||
async def _stage_2(ctx: PipelineContext, retry_plan: dict | None = None) -> PipelineContext:
|
||||
analysis_dict = {
|
||||
@@ -842,3 +922,5 @@ async def main() -> None:
|
||||
if __name__ == '__main__':
|
||||
asyncio.run(main())
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user