UNPKG

@himorishige/noren-devtools

Version:

Development and testing tools for Noren PII detection library

164 lines (163 loc) • 6.24 kB
/** * Common report generation utilities for noren-devtools * Unified formatting and output generation to eliminate duplication */ import { formatDuration, formatNumber, formatPercentage } from './stats-common.js'; // ===== Formatters ===== export function formatPerformanceSection(name, metrics, confidence) { const lines = [ `⚔ Avg Duration: ${formatDuration(metrics.duration)}`, `šŸš€ Throughput: ${formatNumber(metrics.throughput)}K chars/sec`, `šŸ’¾ Memory Efficiency: ${formatNumber(metrics.memoryUsage, 3)} MB/KB`, ]; if (metrics.errorRate !== undefined) { lines.push(`āŒ Error Rate: ${formatPercentage(metrics.errorRate)}`); } if (confidence) { lines.push(`šŸ“ˆ Confidence: [${formatDuration(confidence.lower)}, ${formatDuration(confidence.upper)}]`); } return { title: name, content: lines.map((line) => ` ${line}`).join('\n'), metadata: { type: 'performance', metrics }, }; } export function formatAccuracySection(name, metrics) { const lines = [ `šŸŽÆ F1 Score: ${formatNumber(metrics.f1Score, 3)}`, `āœ… Precision: ${formatNumber(metrics.precision, 3)}, Recall: ${formatNumber(metrics.recall, 3)}`, ]; if (metrics.truePositives || metrics.falsePositives || metrics.falseNegatives) { lines.push(`šŸ“Š TP: ${metrics.truePositives}, FP: ${metrics.falsePositives}, FN: ${metrics.falseNegatives}`); } return { title: name, content: lines.map((line) => ` ${line}`).join('\n'), metadata: { type: 'accuracy', metrics }, }; } export function formatSummaryStatsSection(name, stats) { const lines = [ `šŸ“Š Count: ${stats.count}`, `šŸ“ˆ Mean: ${formatNumber(stats.mean)} (±${formatNumber(stats.standardDeviation)})`, `šŸ“‰ Range: ${formatNumber(stats.min)} - ${formatNumber(stats.max)}`, `šŸ“Š Percentiles: P25=${formatNumber(stats.p25)}, P75=${formatNumber(stats.p75)}, P95=${formatNumber(stats.p95)}`, ]; return { title: name, content: lines.map((line) => ` ${line}`).join('\n'), metadata: { type: 'summary', stats }, }; } // ===== Report Builders ===== export class ReportBuilder { sections = []; title(text) { this.sections.push({ title: 'header', content: this.formatHeader(text), }); return this; } section(section) { this.sections.push(section); return this; } performance(name, metrics, confidence) { return this.section(formatPerformanceSection(name, metrics, confidence)); } accuracy(name, metrics) { return this.section(formatAccuracySection(name, metrics)); } summaryStats(name, stats) { return this.section(formatSummaryStatsSection(name, stats)); } comparison(winner, improvement, significance) { const lines = [ `šŸ† Winner: ${winner}`, `šŸ“ˆ Improvement: ${formatPercentage(improvement / 100)}`, `šŸ“Š Significance: ${formatPercentage(significance / 100)}`, ]; this.sections.push({ title: 'comparison', content: lines.map((line) => ` ${line}`).join('\n'), metadata: { winner, improvement, significance }, }); return this; } summary(testName, sampleCount, duration, completed) { const lines = [ `Test Name: ${testName}`, `Total Samples: ${sampleCount}`, `Duration: ${formatDuration(duration)}`, `Completed: ${completed}`, ]; this.sections.push({ title: 'summary', content: lines.map((line) => ` ${line}`).join('\n'), metadata: { testName, sampleCount, duration, completed }, }); return this; } text(content) { this.sections.push({ title: 'text', content, }); return this; } build() { return this.sections.map((section) => section.content).join('\n'); } formatHeader(text) { const separator = '='.repeat(60); return `\n${separator}\nšŸŽÆ ${text}\n${separator}`; } } // ===== Predefined Templates ===== export function createBenchmarkReport(name, results) { const builder = new ReportBuilder().title(`Benchmark Results: ${name}`); results.forEach((result) => { builder.performance(result.name, result.metrics, result.confidence); }); return builder.build(); } export function createABTestReport(testName, variantA, variantB, winner, improvement, significance, sampleCount, duration) { const builder = new ReportBuilder() .title(`A/B Test Results: ${testName}`) .text('\nšŸ“Š Variant Performance:\n'); builder.performance(variantA.name, variantA.performance); if (variantA.accuracy) { builder.accuracy(variantA.name, variantA.accuracy); } builder.text(''); // Add spacing builder.performance(variantB.name, variantB.performance); if (variantB.accuracy) { builder.accuracy(variantB.name, variantB.accuracy); } builder .text('') .comparison(winner, improvement, significance) .text('\nšŸ“‹ Test Summary:') .summary(testName, sampleCount, duration, new Date().toISOString()); return builder.build(); } export function createEvaluationReport(name, accuracy, performanceStats) { const builder = new ReportBuilder() .title(`Evaluation Results: ${name}`) .accuracy('Detection Accuracy', accuracy); if (performanceStats) { builder.summaryStats('Performance Statistics', performanceStats); } return builder.build(); } // ===== Console Output Utilities ===== export function printReport(report, options = {}) { const timestamp = options.timestamp ? `[${new Date().toISOString()}] ` : ''; const prefix = options.prefix ? `${options.prefix} ` : ''; console.log(`${timestamp}${prefix}${report}`); } export function printProgress(current, total, operation = 'Processing') { const percentage = ((current / total) * 100).toFixed(1); console.log(` Progress: ${percentage}% (${current}/${total}) - ${operation}`); }