tab2.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. #!/usr/bin/env python3
  2. """
  3. Tab2内容生成器 - 段落结构
  4. """
  5. import html as html_module
  6. import re
  7. from typing import Dict, Any, List
  8. def extract_image_numbers(text: str) -> List[int]:
  9. """
  10. 从文本中提取图片编号
  11. Args:
  12. text: 包含图片编号的文本(如"图1"、"图片1"、"图2"或列表)
  13. Returns:
  14. 图片编号列表(从1开始)
  15. """
  16. if not text:
  17. return []
  18. # 使用正则表达式提取所有"图X"或"图片X"格式的编号
  19. matches = re.findall(r'图片?(\d+)', str(text))
  20. return [int(num) for num in matches]
  21. def render_images(text: str, images: List[str]) -> str:
  22. """
  23. 根据文本中的图片编号渲染图片HTML
  24. Args:
  25. text: 包含图片编号的文本
  26. images: 原始图片URL列表
  27. Returns:
  28. 图片HTML字符串
  29. """
  30. image_numbers = extract_image_numbers(text)
  31. if not image_numbers or not images:
  32. return ""
  33. html = '<div class="related-images">\n'
  34. for num in image_numbers:
  35. # 图片编号从1开始,数组索引从0开始
  36. idx = num - 1
  37. if 0 <= idx < len(images):
  38. html += f'<div class="image-item">\n'
  39. html += f'<img src="{images[idx]}" alt="图{num}" loading="lazy">\n'
  40. html += f'<div class="image-label">图{num}</div>\n'
  41. html += f'</div>\n'
  42. html += '</div>\n'
  43. return html
  44. def render_paragraph_tree(paragraphs: List[Dict[str, Any]], level: int = 0, images: List[str] = None) -> str:
  45. """
  46. 递归渲染段落树(支持展开/收起)
  47. Args:
  48. paragraphs: 段落列表
  49. level: 层级深度
  50. images: 原始图片URL列表
  51. Returns:
  52. HTML字符串
  53. """
  54. if not paragraphs:
  55. return ""
  56. if images is None:
  57. images = []
  58. html = f'<ul class="paragraph-list level-{level}">\n'
  59. for para in paragraphs:
  60. para_id = para.get('id', '')
  61. desc = para.get('描述', '')
  62. content_range = para.get('内容范围', '')
  63. reason = para.get('推理依据', '')
  64. children = para.get('子项', [])
  65. has_children = bool(children)
  66. collapsible_class = 'collapsible' if has_children else ''
  67. html += f'<li class="paragraph-item {collapsible_class}" data-para-id="{html_module.escape(para_id)}">\n'
  68. # 检查是否有详细信息
  69. has_details = bool(content_range or reason)
  70. html += f'<div class="paragraph-header" onclick="toggleCollapse(this)">\n'
  71. # 添加展开/收起图标
  72. if has_children:
  73. html += f'<span class="toggle-icon">▼</span>\n'
  74. # 将段落索引和描述包裹在一个容器中
  75. html += f'<div class="paragraph-header-content">\n'
  76. html += f'<span class="paragraph-index">{html_module.escape(para_id)}</span>\n'
  77. if desc:
  78. html += f'<span class="paragraph-desc">{html_module.escape(desc)}</span>\n'
  79. html += f'</div>\n'
  80. # 添加详细信息按钮(在标题右侧)
  81. if has_details:
  82. html += f'<div class="details-toggle-btn" onclick="event.stopPropagation(); toggleDetails(this)"><span class="details-icon">▶</span> 查看详细内容</div>\n'
  83. html += f'</div>\n'
  84. # 将内容包裹在可折叠的容器中
  85. html += f'<div class="collapsible-content">\n'
  86. # 添加详细信息区域(可独立收起展开)
  87. if has_details:
  88. html += f'<div class="paragraph-details collapsed">\n'
  89. html += f'<div class="details-content">\n'
  90. # 添加内容范围(处理列表或字符串类型)
  91. if content_range:
  92. if isinstance(content_range, list):
  93. # 如果是列表,格式化为带标签的列表
  94. range_html = '<ul class="content-range-list">'
  95. for item in content_range:
  96. range_html += f'<li>{html_module.escape(str(item))}</li>'
  97. range_html += '</ul>'
  98. html += f'<div class="paragraph-content"><strong>内容范围:</strong>{range_html}</div>\n'
  99. # 显示相关图片
  100. if images:
  101. html += render_images(str(content_range), images)
  102. else:
  103. # 如果是字符串,保持原有格式
  104. html += f'<div class="paragraph-content"><strong>内容范围:</strong>{html_module.escape(str(content_range))}</div>\n'
  105. # 显示相关图片
  106. if images:
  107. html += render_images(str(content_range), images)
  108. # 添加推理依据
  109. if reason:
  110. html += f'<div class="paragraph-reason"><strong>推理依据:</strong>{html_module.escape(reason)}</div>\n'
  111. html += f'</div>\n'
  112. html += f'</div>\n'
  113. if children:
  114. html += render_paragraph_tree(children, level + 1, images)
  115. html += '</div>\n'
  116. html += '</li>\n'
  117. html += '</ul>\n'
  118. return html
  119. def generate_tab2_content(data: Dict[str, Any]) -> str:
  120. """生成Tab2内容:段落"""
  121. html = '<div class="tab-content" id="tab2" style="display:none;">\n'
  122. if '脚本理解' in data:
  123. script = data['脚本理解']
  124. script_images = script.get('图片列表', [])
  125. html += '<div class="section">\n'
  126. html += '<h3>脚本理解</h3>\n'
  127. html += f'<div class="script-category"><strong>内容品类:</strong> {script.get("内容品类", "无")}</div>\n'
  128. # 段落列表
  129. if '段落列表' in script and script['段落列表']:
  130. html += '<div class="section-header">\n'
  131. html += '<h4>段落结构</h4>\n'
  132. html += '</div>\n'
  133. html += render_paragraph_tree(script['段落列表'], images=script_images)
  134. html += '</div>\n'
  135. html += '</div>\n'
  136. return html