blaze-performance-tester 3.2.33 → 3.2.34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +126 -6
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -5867,7 +5867,7 @@ var i18n = {
5867
5867
  title: "\u0DA7\u0DD9\u0DBD\u0DD2\u0DB8\u0DD9\u0DA7\u0DCA\u200D\u0DBB\u0DD2 \u0D85\u0DB1\u0DD4\u0D9A\u0DD8\u0DAD\u0DD2 \u0DBD\u0DDC\u0D9C\u0DCA",
5868
5868
  threads: "\u0DC3\u0DB8\u0D9C\u0DCF\u0DB8\u0DD3\u0DAD\u0DCA\u0DC0\u0DBA (Threads)",
5869
5869
  throughput: "\u0DB4\u0DCA\u200D\u0DBB\u0DC0\u0DCF\u0DC4 \u0D85\u0DB1\u0DD4\u0DB4\u0DCF\u0DAD\u0DBA",
5870
- avgLatency: "\u0DC3\u0DCF\u0DB8\u0DCF\u0DB1\u0DCA\u200D\u0E22 \u0DB4\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DAF\u0DBA",
5870
+ avgLatency: "\u0DC3\u0DCF\u0DB8\u0DCF\u0DB1\u0DCA\u200D\u0DBA \u0DB4\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DAF\u0DBA",
5871
5871
  p95: "P95 \u0DB4\u0DCA\u200D\u0DBB\u0DB8\u0DCF\u0DAF\u0DBA",
5872
5872
  errors: "\u0DAF\u0DDD\u0DC2 \u0D85\u0DB1\u0DD4\u0DB4\u0DCF\u0DAD\u0DBA",
5873
5873
  status: "\u0DAD\u0DAD\u0DCA\u0DC0\u0DBA",
@@ -5976,6 +5976,34 @@ ${JSON.stringify(metrics, null, 2)}
5976
5976
  return null;
5977
5977
  }
5978
5978
  }
5979
+ async function generateWittyAudioBriefing(cards) {
5980
+ const apiKey = process.env.GEMINI_API_KEY;
5981
+ if (!apiKey) {
5982
+ return "Hey Product Manager! Here is your quick performance update. Actually, your Gemini API Key is missing, so I am improvising. Your health score is sitting at " + cards.healthScore + " out of 100. Check the logs, configure your credentials, and let's make it snappy next time!";
5983
+ }
5984
+ console.log("\u{1F9E0} Querying Gemini 2.5 Flash for a Witty PM Executive Briefing...");
5985
+ const prompt = `
5986
+ You are a fast-talking, highly witty, slightly sarcastic AI performance consultant reporting to a very busy Product Manager.
5987
+ Review these metrics:
5988
+ - Blaze Health Score: ${cards.healthScore}/100
5989
+ - Apdex: ${cards.apdex.toFixed(2)}
5990
+ - Throughput: ${cards.throughput.toFixed(1)} req/s
5991
+ - Error Rate: ${(cards.errorRate * 100).toFixed(2)}%
5992
+ - P95 Latency: ${cards.p95Latency.toFixed(1)}ms
5993
+
5994
+ Compose a witty, energetic daily audio update script that takes exactly 30 seconds to read aloud (around 65-75 words maximum). Focus on what the numbers mean for the business or the features. Return ONLY standard plain-text narrative string, free of markdown styling (*, #, bold tags) or technical headers, ready for immediate browser text-to-speech engine streaming. Make it punchy!
5995
+ `;
5996
+ try {
5997
+ const ai = new GoogleGenAI({});
5998
+ const response = await ai.models.generateContent({
5999
+ model: "gemini-2.5-flash",
6000
+ contents: prompt
6001
+ });
6002
+ return response.text?.replace(/["'**#]/g, "").trim() || "Performance matrix evaluated. Status operational.";
6003
+ } catch (error) {
6004
+ return `System alert PM. Your test achieved a health score of ${cards.healthScore} running at ${cards.throughput.toFixed(0)} requests per second. Check dashboard details for full diagnostic breakdowns.`;
6005
+ }
6006
+ }
5979
6007
  async function generateGeminiRCA(history, finalSummary, errorLogs) {
5980
6008
  const apiKey = process.env.GEMINI_API_KEY;
5981
6009
  if (!apiKey) {
@@ -6424,6 +6452,7 @@ async function runIntelligentAgenticStressTest(config) {
6424
6452
  };
6425
6453
  generateFinalAgentReport(history, healthScore);
6426
6454
  const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, aggregateErrorLogs);
6455
+ const wittyBriefingText = await generateWittyAudioBriefing(finalSummaryCards);
6427
6456
  if (config.optionValue === "elif") {
6428
6457
  const plainEnglishSummary = await generateElifExplanation(finalSummaryCards);
6429
6458
  if (plainEnglishSummary) {
@@ -6443,7 +6472,7 @@ async function runIntelligentAgenticStressTest(config) {
6443
6472
  breakdownRates[code] = totalRequestsAccumulator === 0 ? 0 : globalCodeCounts[code] / totalRequestsAccumulator * 100;
6444
6473
  });
6445
6474
  const baselineData = loadBaselineData(config.baselinePath);
6446
- exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, baselineData);
6475
+ exportHtmlDashboard(history, config, verdictReason, semanticReport, { total1xx, total2xx, total3xx, total4xx, total5xx, breakdownRates }, finalSummaryCards, lastRawRequests, geminiAnalysisHtml, wittyBriefingText, baselineData);
6447
6476
  }
6448
6477
  async function runStandardStressTest(config) {
6449
6478
  console.log(`\u{1F3CB}\uFE0F Running Standard Stress Test [Threads: ${config.threads} | Duration: ${config.durationSec}s | RampUp: ${config.rampUpSec}s | RampDown: ${config.rampDownSec}s]`);
@@ -6486,6 +6515,7 @@ async function runStandardStressTest(config) {
6486
6515
  const isPassed = metrics.apdexScore >= config.targetApdex && metrics.errorRate <= config.targetErrorRate;
6487
6516
  const verdictReason = isPassed ? "Static single-wave baseline checks concluded successfully without triggering health boundaries." : "Static verification loop completed with values exceeding defined quality thresholds.";
6488
6517
  const geminiAnalysisHtml = await generateGeminiRCA(history, finalSummaryCards, rawErrors.length > 0 ? rawErrors : getFallbackClusterLogs());
6518
+ const wittyBriefingText = await generateWittyAudioBriefing(finalSummaryCards);
6489
6519
  if (config.optionValue === "elif") {
6490
6520
  const plainEnglishSummary = await generateElifExplanation(finalSummaryCards);
6491
6521
  if (plainEnglishSummary) {
@@ -6511,7 +6541,7 @@ async function runStandardStressTest(config) {
6511
6541
  total4xx: metrics.c4xx,
6512
6542
  total5xx: metrics.c5xx,
6513
6543
  breakdownRates
6514
- }, finalSummaryCards, rawRequests, geminiAnalysisHtml, baselineData);
6544
+ }, finalSummaryCards, rawRequests, geminiAnalysisHtml, wittyBriefingText, baselineData);
6515
6545
  }
6516
6546
  function getFallbackClusterLogs() {
6517
6547
  const logs = [];
@@ -6576,7 +6606,7 @@ function processMetricsTelemetry(requests, durationSec) {
6576
6606
  const avgTlsMs = mathUtils.mean(requests.map((r) => r.tlsTimeMs || 0));
6577
6607
  const avgTtfbMs = avgDnsMs + avgTcpMs + avgTlsMs + avgLatencyMs * 0.3;
6578
6608
  let c1xx = 0, c2xx = 0, c3xx = 0, c4xx = 0, c5xx = 0;
6579
- const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 0, 502: 0, 503: 0, 504: 0 };
6609
+ const codeCounts = { 400: 0, 401: 0, 403: 0, 404: 0, 429: 0, 500: 502, 503: 0, 504: 0 };
6580
6610
  [400, 401, 403, 404, 429, 500, 502, 503, 504].forEach((c) => codeCounts[c] = 0);
6581
6611
  requests.forEach((r) => {
6582
6612
  if (r.statusCode >= 100 && r.statusCode < 200)
@@ -6644,7 +6674,7 @@ function generateFinalAgentReport(history, score) {
6644
6674
  console.log(`\u26A1 Peak Achieved Cluster Velocity : ${peakThroughput.toFixed(0)} req/sec`);
6645
6675
  console.log("=======================================================\n");
6646
6676
  }
6647
- function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", baselineData = null) {
6677
+ function exportHtmlDashboard(history, config, verdictReason, semanticReport, responseMatrix, cards, rawRequests = [], geminiAnalysisHtml = "", wittyBriefingText = "", baselineData = null) {
6648
6678
  const dict = i18n[config.locale] || i18n["en-US"];
6649
6679
  const dir = dict.rtl ? "rtl" : "ltr";
6650
6680
  const formatter = new Intl.DateTimeFormat(config.locale || "en-US", {
@@ -6851,7 +6881,7 @@ ${formattedTicketLogs}
6851
6881
  .metric-card { background: #131c2e; border: 1px solid #1e293b; border-radius: 6px; padding: 1.25rem; position: relative; }
6852
6882
  .card-title { font-size: 0.75rem; font-weight: 700; color: #64748b; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
6853
6883
  .card-value { font-size: 1.6rem; font-weight: 700; color: #ffffff; }
6854
- .card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-inline-start: 0.2rem; }
6884
+ .card-value .unit { font-size: 0.9rem; font-weight: 500; color: #94a3b8; margin-inline-start: 0.2rem; display: inline-block; }
6855
6885
  .card-value.green { color: #10b981; }
6856
6886
  .card-value.orange { color: #f97316; }
6857
6887
  .card-value.purple { color: #a855f7; }
@@ -6905,6 +6935,28 @@ ${formattedTicketLogs}
6905
6935
  <h1>\u{1F525} ${dict.title}</h1>
6906
6936
  <div class="meta">${dict.targetScript}: <code>${config.targetScript}</code> | ${dict.rampUp}: ${config.rampUpSec}s | ${dict.rampDown}: ${config.rampDownSec}s | ${dict.generatedAt}: ${formattedDate}</div>
6907
6937
  </div>
6938
+
6939
+ <!-- \u{1F399}\uFE0F Automated Executive Summary Audio Player Dashboard Widget Component -->
6940
+ <div class="card" style="margin-bottom: 2rem; background: #1e1b4b; border: 1px solid #6366f1; display: flex; align-items: center; gap: 1.5rem; padding: 1rem 1.5rem; border-radius: 8px;">
6941
+ <div style="background: #312e81; border-radius: 50%; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; cursor: pointer; border: 2px solid #818cf8; transition: transform 0.2s; flex-shrink: 0;" id="audioPlayBtn" onclick="toggleBriefingAudio()">
6942
+ <svg id="playIcon" width="18" height="18" viewBox="0 0 24 24" fill="#818cf8"><path d="M8 5v14l11-7z"/></svg>
6943
+ <svg id="pauseIcon" width="18" height="18" viewBox="0 0 24 24" fill="#818cf8" style="display:none;"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>
6944
+ </div>
6945
+ <div style="flex-grow: 1; min-width: 0;">
6946
+ <div style="font-size: 0.85rem; font-weight: bold; color: #818cf8; text-transform: uppercase; letter-spacing: 0.05em; display: flex; align-items: center; gap: 0.5rem;">
6947
+ <span>\u{1F399}\uFE0F Executive Summary Briefing</span>
6948
+ <span id="audioStatus" style="font-size: 0.75rem; color: #94a3b8; text-transform: none; font-weight: normal;">(Ready to play)</span>
6949
+ </div>
6950
+ <div style="font-size: 0.9rem; color: #cbd5e1; font-style: italic; margin-top: 0.25rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;" id="briefingTextPreview"></div>
6951
+ </div>
6952
+ <div style="display: flex; align-items: flex-end; gap: 3px; height: 20px; flex-shrink: 0;" id="visualizerBars">
6953
+ <div style="width: 3px; height: 8px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
6954
+ <div style="width: 3px; height: 14px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
6955
+ <div style="width: 3px; height: 6px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
6956
+ <div style="width: 3px; height: 18px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
6957
+ <div style="width: 3px; height: 10px; background: #6366f1; border-radius: 1px; transition: height 0.15s ease;"></div>
6958
+ </div>
6959
+ </div>
6908
6960
 
6909
6961
  <div class="cards-wrapper">
6910
6962
  <div class="metric-card">
@@ -7086,6 +7138,74 @@ ${formattedTicketLogs}
7086
7138
  </div>
7087
7139
 
7088
7140
  <script>
7141
+ // Inject the generated Briefing Text payload
7142
+ const textBriefingPayload = ${JSON.stringify(wittyBriefingText)};
7143
+ document.getElementById('briefingTextPreview').textContent = '"' + textBriefingPayload + '"';
7144
+
7145
+ let synthesisEngine = window.speechSynthesis;
7146
+ let textUtterance = null;
7147
+ let audioStateActive = false;
7148
+ let visualBarsTimer = null;
7149
+
7150
+ function toggleBriefingAudio() {
7151
+ if (!synthesisEngine) {
7152
+ alert("Speech synthesis metrics streaming unsupported on this browser platform.");
7153
+ return;
7154
+ }
7155
+
7156
+ if (audioStateActive) {
7157
+ synthesisEngine.cancel();
7158
+ terminateAudioVisuals();
7159
+ } else {
7160
+ synthesisEngine.cancel();
7161
+ textUtterance = new SpeechSynthesisUtterance(textBriefingPayload);
7162
+
7163
+ // Match specialized high quality voice parameters if dynamically present
7164
+ let targetVoices = synthesisEngine.getVoices();
7165
+ let activeVoice = targetVoices.find(v => v.lang.startsWith('en') && v.name.includes('Google')) || targetVoices.find(v => v.lang.startsWith('en'));
7166
+ if (activeVoice) textUtterance.voice = activeVoice;
7167
+
7168
+ textUtterance.rate = 1.08; // Snappy presentation delivery mapping
7169
+ textUtterance.pitch = 1.0;
7170
+
7171
+ textUtterance.onend = () => terminateAudioVisuals();
7172
+ textUtterance.onerror = () => terminateAudioVisuals();
7173
+
7174
+ synthesisEngine.speak(textUtterance);
7175
+ initializeAudioVisuals();
7176
+ }
7177
+ }
7178
+
7179
+ function initializeAudioVisuals() {
7180
+ audioStateActive = true;
7181
+ document.getElementById('playIcon').style.display = 'none';
7182
+ document.getElementById('pauseIcon').style.display = 'block';
7183
+ document.getElementById('audioStatus').textContent = '(Briefing playing...)';
7184
+ document.getElementById('audioPlayBtn').style.transform = 'scale(1.05)';
7185
+
7186
+ const bars = document.getElementById('visualizerBars').children;
7187
+ visualBarsTimer = setInterval(() => {
7188
+ for (let bar of bars) {
7189
+ bar.style.height = (Math.floor(Math.random() * 16) + 4) + 'px';
7190
+ }
7191
+ }, 120);
7192
+ }
7193
+
7194
+ function terminateAudioVisuals() {
7195
+ audioStateActive = false;
7196
+ document.getElementById('playIcon').style.display = 'block';
7197
+ document.getElementById('pauseIcon').style.display = 'none';
7198
+ document.getElementById('audioStatus').textContent = '(Paused / Finished)';
7199
+ document.getElementById('audioPlayBtn').style.transform = 'scale(1)';
7200
+ clearInterval(visualBarsTimer);
7201
+
7202
+ const defaultHeights = [8, 14, 6, 18, 10];
7203
+ const bars = document.getElementById('visualizerBars').children;
7204
+ for (let i = 0; i < bars.length; i++) {
7205
+ if(bars[i]) bars[i].style.height = defaultHeights[i] + 'px';
7206
+ }
7207
+ }
7208
+
7089
7209
  // Inject and expose the formatted Fix-It Ticket Markdown
7090
7210
  const rawTicketMarkdown = ${JSON.stringify(generatedTicketMarkdown)};
7091
7211
  document.getElementById('ticketBodyPreview').textContent = rawTicketMarkdown;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blaze-performance-tester",
3
- "version": "3.2.33",
3
+ "version": "3.2.34",
4
4
  "description": "A high-performance, multi-threaded load testing engine built with Rust and QuickJS.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",