Showing
1 changed file
with
85 additions
and
4 deletions
| @@ -7,7 +7,7 @@ Report Engine 命令行版本 | @@ -7,7 +7,7 @@ Report Engine 命令行版本 | ||
| 7 | 1. 检查PDF依赖 | 7 | 1. 检查PDF依赖 |
| 8 | 2. 获取最新的log、md文件 | 8 | 2. 获取最新的log、md文件 |
| 9 | 3. 直接调用Report Engine生成报告(跳过文件增加审核) | 9 | 3. 直接调用Report Engine生成报告(跳过文件增加审核) |
| 10 | -4. 自动保存HTML和PDF(如果有依赖)到final_reports/ | 10 | +4. 自动保存HTML、PDF(如果有依赖)和Markdown到final_reports/(Markdown 会在 PDF 之后生成) |
| 11 | 11 | ||
| 12 | 使用方法: | 12 | 使用方法: |
| 13 | python report_engine_only.py [选项] | 13 | python report_engine_only.py [选项] |
| @@ -15,6 +15,7 @@ Report Engine 命令行版本 | @@ -15,6 +15,7 @@ Report Engine 命令行版本 | ||
| 15 | 选项: | 15 | 选项: |
| 16 | --query QUERY 指定报告主题(可选,默认从文件名提取) | 16 | --query QUERY 指定报告主题(可选,默认从文件名提取) |
| 17 | --skip-pdf 跳过PDF生成(即使有依赖) | 17 | --skip-pdf 跳过PDF生成(即使有依赖) |
| 18 | + --skip-markdown 跳过Markdown生成 | ||
| 18 | --verbose 显示详细日志 | 19 | --verbose 显示详细日志 |
| 19 | --help 显示帮助信息 | 20 | --help 显示帮助信息 |
| 20 | """ | 21 | """ |
| @@ -358,6 +359,52 @@ def save_pdf(document_ir_path: str, query: str) -> Optional[str]: | @@ -358,6 +359,52 @@ def save_pdf(document_ir_path: str, query: str) -> Optional[str]: | ||
| 358 | return None | 359 | return None |
| 359 | 360 | ||
| 360 | 361 | ||
| 362 | +def save_markdown(document_ir_path: str, query: str) -> Optional[str]: | ||
| 363 | + """ | ||
| 364 | + 从IR文件生成并保存Markdown | ||
| 365 | + | ||
| 366 | + Args: | ||
| 367 | + document_ir_path: Document IR文件路径 | ||
| 368 | + query: 报告主题 | ||
| 369 | + | ||
| 370 | + Returns: | ||
| 371 | + Optional[str]: Markdown文件路径,如果失败则返回None | ||
| 372 | + """ | ||
| 373 | + logger.info("\n正在生成 Markdown 文件...") | ||
| 374 | + | ||
| 375 | + try: | ||
| 376 | + with open(document_ir_path, 'r', encoding='utf-8') as f: | ||
| 377 | + document_ir = json.load(f) | ||
| 378 | + | ||
| 379 | + from ReportEngine.renderers import MarkdownRenderer | ||
| 380 | + renderer = MarkdownRenderer() | ||
| 381 | + markdown_content = renderer.render(document_ir) | ||
| 382 | + | ||
| 383 | + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") | ||
| 384 | + query_safe = "".join( | ||
| 385 | + c for c in query if c.isalnum() or c in (" ", "-", "_") | ||
| 386 | + ).rstrip() | ||
| 387 | + query_safe = query_safe.replace(" ", "_")[:30] or "report" | ||
| 388 | + | ||
| 389 | + md_dir = Path("final_reports") / "md" | ||
| 390 | + md_dir.mkdir(parents=True, exist_ok=True) | ||
| 391 | + | ||
| 392 | + md_filename = f"final_report_{query_safe}_{timestamp}.md" | ||
| 393 | + md_path = md_dir / md_filename | ||
| 394 | + | ||
| 395 | + md_path.write_text(markdown_content, encoding='utf-8') | ||
| 396 | + | ||
| 397 | + file_size_kb = md_path.stat().st_size / 1024 | ||
| 398 | + logger.success(f"✓ Markdown 已保存: {md_path}") | ||
| 399 | + logger.info(f" 文件大小: {file_size_kb:.1f} KB") | ||
| 400 | + | ||
| 401 | + return str(md_path) | ||
| 402 | + | ||
| 403 | + except Exception as e: | ||
| 404 | + logger.exception(f"❌ Markdown 生成失败: {e}") | ||
| 405 | + return None | ||
| 406 | + | ||
| 407 | + | ||
| 361 | def parse_arguments(): | 408 | def parse_arguments(): |
| 362 | """解析命令行参数""" | 409 | """解析命令行参数""" |
| 363 | parser = argparse.ArgumentParser( | 410 | parser = argparse.ArgumentParser( |
| @@ -371,7 +418,7 @@ def parse_arguments(): | @@ -371,7 +418,7 @@ def parse_arguments(): | ||
| 371 | 418 | ||
| 372 | 注意: | 419 | 注意: |
| 373 | 程序会自动获取三个引擎目录中的最新报告文件, | 420 | 程序会自动获取三个引擎目录中的最新报告文件, |
| 374 | - 不进行文件增加审核,直接生成综合报告。 | 421 | + 不进行文件增加审核,直接生成综合报告,并默认在PDF之后生成Markdown。 |
| 375 | """ | 422 | """ |
| 376 | ) | 423 | ) |
| 377 | 424 | ||
| @@ -389,6 +436,12 @@ def parse_arguments(): | @@ -389,6 +436,12 @@ def parse_arguments(): | ||
| 389 | ) | 436 | ) |
| 390 | 437 | ||
| 391 | parser.add_argument( | 438 | parser.add_argument( |
| 439 | + '--skip-markdown', | ||
| 440 | + action='store_true', | ||
| 441 | + help='跳过Markdown生成' | ||
| 442 | + ) | ||
| 443 | + | ||
| 444 | + parser.add_argument( | ||
| 392 | '--verbose', | 445 | '--verbose', |
| 393 | action='store_true', | 446 | action='store_true', |
| 394 | help='显示详细日志信息' | 447 | help='显示详细日志信息' |
| @@ -413,12 +466,16 @@ def main(): | @@ -413,12 +466,16 @@ def main(): | ||
| 413 | 466 | ||
| 414 | # 步骤 1: 检查依赖 | 467 | # 步骤 1: 检查依赖 |
| 415 | pdf_available, _ = check_dependencies() | 468 | pdf_available, _ = check_dependencies() |
| 469 | + markdown_enabled = not args.skip_markdown | ||
| 416 | 470 | ||
| 417 | # 如果用户指定跳过PDF,则禁用PDF生成 | 471 | # 如果用户指定跳过PDF,则禁用PDF生成 |
| 418 | if args.skip_pdf: | 472 | if args.skip_pdf: |
| 419 | logger.info("用户指定 --skip-pdf,将跳过 PDF 生成") | 473 | logger.info("用户指定 --skip-pdf,将跳过 PDF 生成") |
| 420 | pdf_available = False | 474 | pdf_available = False |
| 421 | 475 | ||
| 476 | + if not markdown_enabled: | ||
| 477 | + logger.info("用户指定 --skip-markdown,将跳过 Markdown 生成") | ||
| 478 | + | ||
| 422 | # 步骤 2: 获取最新文件 | 479 | # 步骤 2: 获取最新文件 |
| 423 | latest_files = get_latest_engine_reports() | 480 | latest_files = get_latest_engine_reports() |
| 424 | 481 | ||
| @@ -448,12 +505,15 @@ def main(): | @@ -448,12 +505,15 @@ def main(): | ||
| 448 | 505 | ||
| 449 | # HTML 已经在 generate_report 中自动保存 | 506 | # HTML 已经在 generate_report 中自动保存 |
| 450 | html_path = result.get('report_filepath', '') | 507 | html_path = result.get('report_filepath', '') |
| 508 | + ir_path = result.get('ir_filepath', '') | ||
| 509 | + pdf_path = None | ||
| 510 | + markdown_path = None | ||
| 511 | + | ||
| 451 | if html_path: | 512 | if html_path: |
| 452 | logger.success(f"✓ HTML 已保存: {result.get('report_relative_path', html_path)}") | 513 | logger.success(f"✓ HTML 已保存: {result.get('report_relative_path', html_path)}") |
| 453 | 514 | ||
| 454 | # 如果有PDF依赖,生成并保存PDF | 515 | # 如果有PDF依赖,生成并保存PDF |
| 455 | if pdf_available: | 516 | if pdf_available: |
| 456 | - ir_path = result.get('ir_filepath', '') | ||
| 457 | if ir_path and os.path.exists(ir_path): | 517 | if ir_path and os.path.exists(ir_path): |
| 458 | pdf_path = save_pdf(ir_path, query) | 518 | pdf_path = save_pdf(ir_path, query) |
| 459 | else: | 519 | else: |
| @@ -461,6 +521,15 @@ def main(): | @@ -461,6 +521,15 @@ def main(): | ||
| 461 | else: | 521 | else: |
| 462 | logger.info("⚠ 跳过 PDF 生成(缺少系统依赖或用户指定跳过)") | 522 | logger.info("⚠ 跳过 PDF 生成(缺少系统依赖或用户指定跳过)") |
| 463 | 523 | ||
| 524 | + # 生成并保存Markdown(在PDF之后) | ||
| 525 | + if markdown_enabled: | ||
| 526 | + if ir_path and os.path.exists(ir_path): | ||
| 527 | + markdown_path = save_markdown(ir_path, query) | ||
| 528 | + else: | ||
| 529 | + logger.warning("⚠ 未找到 IR 文件,无法生成 Markdown") | ||
| 530 | + else: | ||
| 531 | + logger.info("⚠ 跳过 Markdown 生成(用户指定)") | ||
| 532 | + | ||
| 464 | # 总结 | 533 | # 总结 |
| 465 | logger.info("\n" + "=" * 70) | 534 | logger.info("\n" + "=" * 70) |
| 466 | logger.success("✓ 报告生成完成!") | 535 | logger.success("✓ 报告生成完成!") |
| @@ -468,7 +537,19 @@ def main(): | @@ -468,7 +537,19 @@ def main(): | ||
| 468 | logger.info(f"报告 ID: {result.get('report_id', 'N/A')}") | 537 | logger.info(f"报告 ID: {result.get('report_id', 'N/A')}") |
| 469 | logger.info(f"HTML 文件: {result.get('report_relative_path', 'N/A')}") | 538 | logger.info(f"HTML 文件: {result.get('report_relative_path', 'N/A')}") |
| 470 | if pdf_available: | 539 | if pdf_available: |
| 471 | - logger.info(f"PDF 文件: final_reports/pdf/ 目录下") | 540 | + if pdf_path: |
| 541 | + logger.info(f"PDF 文件: {os.path.relpath(pdf_path, os.getcwd())}") | ||
| 542 | + else: | ||
| 543 | + logger.info("PDF 文件: 生成失败,请检查日志") | ||
| 544 | + else: | ||
| 545 | + logger.info("PDF 文件: 已跳过") | ||
| 546 | + if markdown_enabled: | ||
| 547 | + if markdown_path: | ||
| 548 | + logger.info(f"Markdown 文件: {os.path.relpath(markdown_path, os.getcwd())}") | ||
| 549 | + else: | ||
| 550 | + logger.info("Markdown 文件: 生成失败,请检查日志") | ||
| 551 | + else: | ||
| 552 | + logger.info("Markdown 文件: 已跳过") | ||
| 472 | logger.info("=" * 70) | 553 | logger.info("=" * 70) |
| 473 | logger.info("\n程序结束") | 554 | logger.info("\n程序结束") |
| 474 | 555 |
-
Please register or login to post a comment