Showing
1 changed file
with
64 additions
and
3 deletions
| @@ -709,10 +709,36 @@ class HTMLRenderer: | @@ -709,10 +709,36 @@ class HTMLRenderer: | ||
| 709 | } | 709 | } |
| 710 | handler = handlers.get(block_type) | 710 | handler = handlers.get(block_type) |
| 711 | if handler: | 711 | if handler: |
| 712 | - return handler(block) | 712 | + html_fragment = handler(block) |
| 713 | + return self._wrap_error_block(html_fragment, block) | ||
| 713 | if isinstance(block.get("blocks"), list): | 714 | if isinstance(block.get("blocks"), list): |
| 714 | - return self._render_blocks(block["blocks"]) | ||
| 715 | - return f'<pre class="unknown-block">{self._escape_html(json.dumps(block, ensure_ascii=False, indent=2))}</pre>' | 715 | + html_fragment = self._render_blocks(block["blocks"]) |
| 716 | + return self._wrap_error_block(html_fragment, block) | ||
| 717 | + fallback = f'<pre class="unknown-block">{self._escape_html(json.dumps(block, ensure_ascii=False, indent=2))}</pre>' | ||
| 718 | + return self._wrap_error_block(fallback, block) | ||
| 719 | + | ||
| 720 | + def _wrap_error_block(self, html_fragment: str, block: Dict[str, Any]) -> str: | ||
| 721 | + """若block标记了error元数据,则包裹提示容器并注入tooltip。""" | ||
| 722 | + if not html_fragment: | ||
| 723 | + return html_fragment | ||
| 724 | + meta = block.get("meta") or {} | ||
| 725 | + log_ref = meta.get("errorLogRef") | ||
| 726 | + if not isinstance(log_ref, dict): | ||
| 727 | + return html_fragment | ||
| 728 | + raw_preview = (meta.get("rawJsonPreview") or "")[:1200] | ||
| 729 | + error_message = meta.get("errorMessage") or "LLM返回块解析错误" | ||
| 730 | + importance = meta.get("importance") or "standard" | ||
| 731 | + ref_label = "" | ||
| 732 | + if log_ref.get("relativeFile") and log_ref.get("entryId"): | ||
| 733 | + ref_label = f"{log_ref['relativeFile']}#{log_ref['entryId']}" | ||
| 734 | + tooltip = f"{error_message} | {ref_label}".strip() | ||
| 735 | + attr_raw = self._escape_attr(raw_preview or tooltip) | ||
| 736 | + attr_title = self._escape_attr(tooltip) | ||
| 737 | + class_suffix = self._escape_attr(importance) | ||
| 738 | + return ( | ||
| 739 | + f'<div class="llm-error-block importance-{class_suffix}" ' | ||
| 740 | + f'data-raw="{attr_raw}" title="{attr_title}">{html_fragment}</div>' | ||
| 741 | + ) | ||
| 716 | 742 | ||
| 717 | def _render_heading(self, block: Dict[str, Any]) -> str: | 743 | def _render_heading(self, block: Dict[str, Any]) -> str: |
| 718 | """渲染heading block,确保锚点存在""" | 744 | """渲染heading block,确保锚点存在""" |
| @@ -1498,6 +1524,41 @@ body {{ | @@ -1498,6 +1524,41 @@ body {{ | ||
| 1498 | font-weight: 500; | 1524 | font-weight: 500; |
| 1499 | margin-top: 0; | 1525 | margin-top: 0; |
| 1500 | }} | 1526 | }} |
| 1527 | +.llm-error-block {{ | ||
| 1528 | + border: 1px dashed var(--secondary-color); | ||
| 1529 | + border-radius: 12px; | ||
| 1530 | + padding: 12px; | ||
| 1531 | + margin: 12px 0; | ||
| 1532 | + background: rgba(229,62,62,0.06); | ||
| 1533 | + position: relative; | ||
| 1534 | +}} | ||
| 1535 | +.llm-error-block.importance-critical {{ | ||
| 1536 | + border-color: var(--secondary-color-dark); | ||
| 1537 | + background: rgba(229,62,62,0.12); | ||
| 1538 | +}} | ||
| 1539 | +.llm-error-block::after {{ | ||
| 1540 | + content: attr(data-raw); | ||
| 1541 | + white-space: pre-wrap; | ||
| 1542 | + position: absolute; | ||
| 1543 | + left: 0; | ||
| 1544 | + right: 0; | ||
| 1545 | + bottom: 100%; | ||
| 1546 | + max-height: 240px; | ||
| 1547 | + overflow: auto; | ||
| 1548 | + background: rgba(0,0,0,0.85); | ||
| 1549 | + color: #fff; | ||
| 1550 | + font-size: 0.85rem; | ||
| 1551 | + padding: 12px; | ||
| 1552 | + border-radius: 10px; | ||
| 1553 | + margin-bottom: 8px; | ||
| 1554 | + opacity: 0; | ||
| 1555 | + pointer-events: none; | ||
| 1556 | + transition: opacity 0.2s ease; | ||
| 1557 | + z-index: 20; | ||
| 1558 | +}} | ||
| 1559 | +.llm-error-block:hover::after {{ | ||
| 1560 | + opacity: 1; | ||
| 1561 | +}} | ||
| 1501 | .report-header h1 {{ | 1562 | .report-header h1 {{ |
| 1502 | margin: 0; | 1563 | margin: 0; |
| 1503 | font-size: 1.6rem; | 1564 | font-size: 1.6rem; |
-
Please register or login to post a comment