# -*- coding: utf-8 -*- """ Markdown 报告生成器 """ from datetime import datetime from pathlib import Path from typing import List, Optional from ..metrics.models import AggregatedMetrics class MarkdownReporter: """Markdown 报告生成器""" def generate( self, asr_results: List[AggregatedMetrics], output_path: Path, config_info: Optional[dict] = None, ) -> None: """ 生成 Markdown 报告 Args: asr_results: ASR 测试结果 output_path: 输出文件路径 config_info: 配置信息 """ lines = [] # 标题 lines.append("# Qwen3-ASR 并发性能测试报告") lines.append("") lines.append(f"**测试时间:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") if config_info: lines.append(f"**服务器:** {config_info.get('host', 'localhost')}:{config_info.get('port', 8000)}") lines.append(f"**并发级别:** {', '.join(map(str, config_info.get('concurrency_levels', [])))}") lines.append("") lines.append("---") lines.append("") # ASR 结果 if asr_results: lines.extend(self._generate_asr_section(asr_results)) # 结论 lines.extend(self._generate_conclusions(asr_results)) # 写入文件 output_path.parent.mkdir(parents=True, exist_ok=True) output_path.write_text("\n".join(lines), encoding="utf-8") def _generate_asr_section(self, results: List[AggregatedMetrics]) -> List[str]: """生成 ASR 结果部分""" lines = [] lines.append("## ASR 性能测试结果") lines.append("") # 延迟指标表格 lines.append("### 延迟指标 (毫秒)") lines.append("") lines.append("| 并发数 | 首次响应 (Avg) | 首次响应 (P95) | 总时间 (Avg) | 总时间 (P95) | 总时间 (Max) |") lines.append("|--------|---------------|---------------|-------------|-------------|-------------|") for r in results: lines.append( f"| {r.concurrency_level} | " f"{r.first_latency_avg:.1f} | " f"{r.first_latency_p95:.1f} | " f"{r.total_time_avg:.1f} | " f"{r.total_time_p95:.1f} | " f"{r.total_time_max:.1f} |" ) lines.append("") # RTF 和吞吐量表格 lines.append("### RTF 和吞吐量") lines.append("") lines.append("| 并发数 | RTF (Avg) | RTF (P95) | 吞吐量 (req/s) | 成功率 |") lines.append("|--------|----------|----------|---------------|--------|") for r in results: lines.append( f"| {r.concurrency_level} | " f"{r.rtf_avg:.3f} | " f"{r.rtf_p95:.3f} | " f"{r.throughput:.3f} | " f"{r.success_rate:.1f}% |" ) lines.append("") return lines def _generate_conclusions( self, asr_results: List[AggregatedMetrics], ) -> List[str]: """生成结论部分""" lines = [] lines.append("## 结论") lines.append("") if asr_results: max_level = max(asr_results, key=lambda x: x.concurrency_level) lines.append(f"- **ASR 最大并发 ({max_level.concurrency_level}) RTF:** {max_level.rtf_avg:.3f}") lines.append(f"- **ASR 最大并发吞吐量:** {max_level.throughput:.3f} req/s") # 找到 RTF 超过 1.0 的并发级别 stable_levels = [r for r in asr_results if r.rtf_avg <= 1.0] if stable_levels: max_stable = max(stable_levels, key=lambda x: x.concurrency_level) lines.append(f"- **ASR 稳定并发上限 (RTF < 1.0):** {max_stable.concurrency_level}") lines.append("") lines.append("---") lines.append("") lines.append("*RTF (Real-Time Factor): 处理时间与音频时长的比值,小于 1.0 表示处理速度快于实时*") lines.append("") return lines