#!/usr/bin/env python3 """ 脚本结果可视化工具 V2 功能:为 output_demo_script_v2.json 中的每个视频生成独立的HTML可视化页面 交互形式:卡片+点击详情 """ import json import argparse import sys from pathlib import Path from datetime import datetime from typing import List, Dict, Any, Optional import html as html_module # 保证可以从项目根目录导入 PROJECT_ROOT = Path(__file__).parent.parent if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) # 导入tab模块 from static.visualize_v2.tab1 import generate_tab1_content from static.visualize_v2.tab2 import generate_tab2_content from static.visualize_v2.tab3 import generate_tab3_content from static.visualize_v2.tab4 import generate_tab4_content class ScriptResultVisualizerV2: """脚本结果可视化器 V2""" def __init__(self, json_file: str = None): """ 初始化可视化器 Args: json_file: JSON文件路径 """ if json_file is None: self.json_file = None else: self.json_file = Path(json_file) if not self.json_file.is_absolute(): self.json_file = Path.cwd() / json_file def load_json_data(self, file_path: Path) -> Optional[Dict[str, Any]]: """ 加载JSON文件 Args: file_path: JSON文件路径 Returns: JSON数据字典,加载失败返回None """ try: with open(file_path, 'r', encoding='utf-8') as f: return json.load(f) except Exception as e: print(f"加载文件失败 {file_path}: {e}") return None def generate_html(self, data: Dict[str, Any], video_data: Dict[str, Any], json_filename: str) -> str: """生成完整的HTML页面""" # 开始构建HTML html = '\n' html += '\n' html += '\n' html += ' \n' html += ' \n' html += f' 脚本结果可视化 V2 - {json_filename}\n' html += ' \n' html += '\n' html += '\n' html += '
\n' # 页眉 html += '
\n' html += '

脚本结果可视化 V2

\n' # 显示视频信息 video_title = video_data.get("title", "") video_id = video_data.get("video_id", "") if video_title: html += f'
{html_module.escape(video_title)}
\n' if video_id: html += f'
视频ID: {video_id}
\n' html += f'
{json_filename}
\n' html += f'
生成时间: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
\n' html += '
\n' # Tab导航 html += '
\n' html += ' \n' html += ' \n' html += ' \n' html += ' \n' html += '
\n' # 主内容 html += '
\n' # Tab1内容:结构化内容库 html += generate_tab1_content(data) # Tab2内容:L3单元解构 html += generate_tab2_content(data) # Tab3内容:整体结构理解 html += generate_tab3_content(data) # Tab4内容:金句提取 html += generate_tab4_content(data) html += '
\n' # 页脚 html += '\n' html += '
\n' # JavaScript html += '\n' html += '\n' html += '\n' return html def save_all_html(self, output_dir: str | Path | None = None) -> List[str]: """ 基于 output_demo_script_v2.json,为其中每个视频生成一个独立的 HTML 页面。 支持结构: { "results": [ { "video_data": {...}, "script_result": {...} }, ... ] } """ if self.json_file is None: print("❌ 错误: 未指定JSON文件") return [] # 加载JSON数据 data = self.load_json_data(self.json_file) if data is None: return [] results = data.get("results") or [] if not isinstance(results, list) or not results: print("⚠️ JSON 中未找到有效的 results 数组") return [] # 确定输出目录 if output_dir is None: # 默认输出到examples/html目录 output_dir = Path(__file__).parent / "html" else: output_dir = Path(output_dir) if not output_dir.is_absolute(): output_dir = Path.cwd() / output_dir # 创建输出目录 output_dir.mkdir(parents=True, exist_ok=True) # 确保样式和脚本文件可用:从 html/visualize 拷贝到 输出目录/visualize source_visualize_dir = Path(__file__).parent / "html" / "visualize" target_visualize_dir = output_dir / "visualize" if source_visualize_dir.exists() and source_visualize_dir.is_dir(): import shutil target_visualize_dir.mkdir(parents=True, exist_ok=True) for item in source_visualize_dir.iterdir(): dst = target_visualize_dir / item.name if item.is_file(): # 如果源文件和目标文件是同一个,跳过 if item.resolve() != dst.resolve(): shutil.copy2(item, dst) generated_paths: List[str] = [] print(f"📁 检测到 output_demo_script_v2 格式,包含 {len(results)} 条结果") for idx, item in enumerate(results, start=1): script_data = item.get("script_result") if not isinstance(script_data, dict): print(f"⚠️ 跳过第 {idx} 条结果:缺少 script_result 字段或结构不正确") continue video_data = item.get("video_data") or {} video_id = video_data.get("video_id") or video_data.get("channel_content_id") # 用于 HTML 内部展示的"文件名"标签 json_label = f"{self.json_file.name}#{idx}" # 生成输出文件名:{video_id}_v2.html if video_id: output_filename = f"{video_id}_v2.html" else: output_filename = f"{self.json_file.stem}_{idx}_v2.html" output_path = output_dir / output_filename html_content = self.generate_html(script_data, video_data, json_label) with open(output_path, "w", encoding="utf-8") as f: f.write(html_content) generated_paths.append(str(output_path)) print(f"✅ HTML文件已生成: {output_path}") if not generated_paths: print("⚠️ 未能从 JSON 中生成任何 HTML 文件") return generated_paths def main(): """主函数""" # 解析命令行参数 parser = argparse.ArgumentParser( description='脚本结果可视化工具 V2 - 基于 output_demo_script_v2.json 为每个视频生成独立的HTML页面', formatter_class=argparse.RawDescriptionHelpFormatter, epilog=""" 使用示例: # 在当前 examples 目录下使用默认的 output_demo_script_v2.json 并输出到 examples/html python visualize_script_results_v2.py # 指定 JSON 文件 python visualize_script_results_v2.py examples/output_demo_script_v2.json # 指定 JSON 文件和输出目录 python visualize_script_results_v2.py examples/output_demo_script_v2.json --output-dir examples/html """ ) parser.add_argument( 'json_file', type=str, nargs='?', help='JSON文件路径(默认为 examples/output_demo_script_v2.json)' ) parser.add_argument( '-o', '--output-dir', type=str, default=None, help='输出目录路径(默认: examples/html)' ) args = parser.parse_args() # 确定 JSON 文件路径 if args.json_file: json_path = Path(args.json_file) if not json_path.is_absolute(): json_path = Path.cwd() / json_path else: # 默认使用 examples/output_demo_script_v2.json json_path = Path(__file__).parent / "output_demo_script_v2.json" print("🚀 开始生成脚本结果可视化 V2...") print(f"📁 JSON文件: {json_path}") print(f"📄 输出目录: {args.output_dir or (Path(__file__).parent / 'html')}") print() visualizer = ScriptResultVisualizerV2(json_file=str(json_path)) generated_files = visualizer.save_all_html(output_dir=args.output_dir) if generated_files: print() print(f"🎉 完成! 共生成 {len(generated_files)} 个HTML文件") # 提示其中一个示例文件 print(f"📄 示例: 请在浏览器中打开: {generated_files[0]}") if __name__ == "__main__": main()