Skip to content

feat: Restore complete demo system (Fortress PR #209)#208

Merged
uelkerd merged 15 commits into
mainfrom
feat/restore-demo-system-pr169
Sep 28, 2025
Merged

feat: Restore complete demo system (Fortress PR #209)#208
uelkerd merged 15 commits into
mainfrom
feat/restore-demo-system-pr169

Conversation

@uelkerd
Copy link
Copy Markdown
Owner

@uelkerd uelkerd commented Sep 28, 2025

🚨 EMERGENCY RESTORATION: Complete Demo System Recovery

💥 CRITICAL ISSUE DISCOVERED

PR #200 completely corrupted our sophisticated demo system, replacing the fully-functional interface from PR #169 with broken Font Awesome implementation that destroyed all advanced features.

🔍 ROOT CAUSE ANALYSIS

COMPLETE SYSTEM RESTORATION

This PR restores the complete, fully-functional demo system from PR #169:

🚀 Restored Features

  • Complete "🚀 AI Processing Pipeline" interface
  • Material Icons design system (NOT Font Awesome)
  • Sophisticated side-by-side results layout
  • Real-time progress console with live feedback
  • Interactive emotion detection & text summarization
  • Glassmorphism styling with proper animations
  • Working API configuration and endpoints

📁 Files Restored (4/5 - Fortress Compliant)

  • website/comprehensive-demo.html - Complete working interface
  • website/css/comprehensive-demo.css - Full glassmorphism styling
  • website/js/comprehensive-demo.js - Complete JavaScript system
  • website/js/config.js - Working API configuration

🏰 FORTRESS COMPLIANCE

4/5 files (meets ≤5 file requirement)
Focused scope: Complete system restoration only
Clean separation: No audio integration (that stays in PR #205)

🎯 STRATEGIC CONTEXT

This is NOT about individual file fixes - this restores an entirely different, sophisticated design that was working perfectly in PR #169 before PR #200 corruption.

Separation of Concerns:

🧪 Test Plan

  • Verify Material Icons load correctly (NOT Font Awesome)
  • Test emotion detection pipeline with real-time console
  • Validate side-by-side results layout functionality
  • Confirm API configuration works with production endpoints
  • Test glassmorphism styling and animations
  • Verify complete user workflow from input to results

🚨 URGENT MERGE REQUIRED

This restoration is critical - the demo system is currently non-functional due to PR #200 corruption. This PR restores the sophisticated, working system that was lost.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Redesigned demo flow with progress steps, loading messages, reset, and clearer emotion details with chart rendering and fallbacks.
    • Configurable feature flags and environment-aware settings surfaced for debug/dev modes.
  • Style

    • Visual overhaul: glassy cards, improved contrast, refined inputs, granular responsive tweaks, and broader reduced-motion/accessibility support.
  • Bug Fixes

    • More resilient API interactions with retries, clearer error feedback, and mock fallbacks to reduce failures.
  • Refactor

    • Streamlined client configuration and simplified, more modular public demo API.

uelkerd and others added 13 commits September 27, 2025 10:54
Ultra-granular split for Sourcery compatibility (30k chars < 150k limit):
- favicon.ico: Professional website favicon
- css/comprehensive-demo.css: Advanced demo styling with CSS variables

Part 3/4 of website files from feat/clean-demo-website.
Completes the website assets for visual branding and styling.

Original work attribution: PR #169 feat/clean-demo-website

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
- Consolidate duplicate CSS rules (.demo-container, .feature-card, #textInput)
- Fix aggressive universal selector in prefers-reduced-motion with specific classes
- Make .step-label selector more specific to avoid conflicts
- Merge duplicate @media (max-width: 768px) blocks for better maintainability
- Add variables.css with design system variables
- Add base.css with typography and global styles
- Add main.css as entry point for component imports
- Add buttons.css for button styles and interactions
- Add forms.css for form controls and input styling
- Add navigation.css for navbar and menu components
- Add cards.css for feature cards and content containers
- Add containers.css for layout containers and hero sections
- Add progress.css for progress indicators and pipeline components
- Add charts.css for data visualization and chart components
- Add animations.css for transitions and animation effects
- Add messages.css for error and success message styling
- Add responsive.css for media queries and responsive design
- Add comprehensive README.md explaining the modular CSS architecture
- Merge feat/website-assets branch with comprehensive improvements
- Resolve merge conflicts between main and website-assets branches
- Keep improved modular CSS architecture and code review fixes
- Include proper binary favicon.ico and component-based CSS structure
- Address all code review issues: mobile performance, duplicate rules, selectors
This restores the sophisticated, fully-functional demo system from PR #169
commit f22683d that was corrupted when PR #200 replaced the working Material
Icons interface with broken Font Awesome implementation.

RESTORED FEATURES:
✅ Complete "🚀 AI Processing Pipeline" interface
✅ Material Icons design system (NOT Font Awesome)
✅ Sophisticated side-by-side results layout
✅ Real-time progress console with live feedback
✅ Interactive emotion detection & text summarization
✅ Glassmorphism styling with proper animations
✅ Working API configuration and endpoints

FORTRESS COMPLIANCE: 4/5 files (meets ≤5 file requirement)
- website/comprehensive-demo.html (complete working interface)
- website/css/comprehensive-demo.css (full glassmorphism styling)
- website/js/comprehensive-demo.js (complete JavaScript system)
- website/js/config.js (working API configuration)

🚨 CRITICAL: This restoration is essential - PR #200 completely destroyed
the working demo system, replacing sophisticated functionality with broken code.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings September 28, 2025 20:40
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @uelkerd, your pull request is larger than the review limit of 150000 diff characters

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 28, 2025

Warning

Rate limit exceeded

@uelkerd has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 18 minutes and 14 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 562405c and 1990349.

📒 Files selected for processing (2)
  • website/css/comprehensive-demo.css (21 hunks)
  • website/js/comprehensive-demo.js (22 hunks)

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Overhauls demo styling, refactors demo JS into a new ComprehensiveDemo class with granular exported functions and simplified fetch/retry logic, and replaces the old config with a streamlined SAMO_CONFIG structure including feature flags, external endpoints, and debug redaction.

Changes

Cohort / File(s) Summary
Styling overhaul
website/css/comprehensive-demo.css
Replaces icon-specific rules with new input and card styling; adds glass/blur/elevation visuals and hover/active states; restructures responsive rules into explicit @media blocks; broadens reduced-motion rules; adds !important overrides and refines progress/step/badge colors.
Demo logic refactor & public API
website/js/comprehensive-demo.js
Introduces ComprehensiveDemo class and lifecycle methods; replaces window.SamoDemo with multiple exported globals (generateSampleText, processText, testWithRealAPI, callSummarizationAPI, updateElement, showResultsSections, addToProgressConsole, clearProgressConsole, createEmotionChart, resetToInputScreen); simplifies fetch flows for journal/summarize/emotion, centralizes timeout/retry with exponential backoff, adds mock fallbacks, and improves chart lifecycle and UI helpers.
Config restructuring
website/js/config.js
Replaces legacy multi-environment config with window.SAMO_CONFIG containing API (BASE_URL, ENDPOINTS, TIMEOUT, RETRY_ATTEMPTS), OPENAI, EXTERNAL, FEATURES, ENVIRONMENT, and DEBUG; adds server merge hook and debug redaction; removes old URL helper methods and legacy blocks.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant UI as ComprehensiveDemo (UI)
  participant CFG as SAMO_CONFIG
  participant SUM as Summarize API
  participant EMO as Emotion API
  participant JNL as Voice Journal API

  User->>UI: Submit text or start voice
  UI->>CFG: Read endpoints, timeout, retries
  alt voice transcription
    UI->>JNL: fetch(VOICE_JOURNAL)
    JNL-->>UI: transcript / error
    UI->>UI: update progress step
  end
  UI->>SUM: fetch(SUMMARIZE?text=...)
  SUM-->>UI: summary / error
  UI->>EMO: fetch(EMOTION?text=...)
  EMO-->>UI: emotions / error
  par success path
    UI->>UI: render results, create/destroy chart safely
  and failure path
    UI->>UI: retry with backoff or use mock fallback
  end
  UI-->>User: display results & logs
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60–90 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

A rabbit taps keys in the glassy night,
Styles shimmer, inputs snug and bright.
Configs hop in, flags waving free,
Retries bounce kindly, charts sip tea.
Hoppity—demo dances with glee! 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly identifies the main change—restoring the complete demo system—and directly reflects the PR’s core objective, making it fully related to the changeset, although the parenthetical reference to “Fortress PR #209” adds minor noise without detracting from clarity.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@deepsource-io
Copy link
Copy Markdown
Contributor

deepsource-io Bot commented Sep 28, 2025

Here's the code health analysis summary for commits d9f0e56..1990349. View details on DeepSource ↗.

Analysis Summary

AnalyzerStatusSummaryLink
DeepSource Test coverage LogoTest coverage⚠️ Artifact not reportedTimed out: Artifact was never reportedView Check ↗
DeepSource Python LogoPython✅ SuccessView Check ↗
DeepSource Terraform LogoTerraform✅ SuccessView Check ↗
DeepSource Secrets LogoSecrets✅ SuccessView Check ↗
DeepSource Shell LogoShell✅ SuccessView Check ↗
DeepSource Docker LogoDocker✅ SuccessView Check ↗

💡 If you’re a repository administrator, you can configure the quality gates from the settings.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @uelkerd, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request performs an urgent and comprehensive restoration of the demo system, rolling back the changes introduced by PR #200 which had severely corrupted its functionality and user interface. The primary goal is to reinstate the robust and feature-rich demo experience that was present in PR #169, ensuring that all core AI processing pipelines, interactive elements, and visual styling are fully operational. This involves significant updates across CSS, JavaScript, and configuration files to re-establish the intended design and API interaction patterns.

Highlights

  • Emergency Restoration: This pull request is an emergency restoration to revert the demo system to its fully-functional state from PR feat: Add comprehensive demo website with DeBERTa v3 Large integration #169, addressing critical corruption introduced by PR feat: enhance website HTML files and configuration (Fortress PR #190-A) #200.
  • Feature Restoration: Key features restored include the complete 'AI Processing Pipeline' interface, Material Icons design system (replacing Font Awesome), sophisticated side-by-side results layout, real-time progress console, interactive emotion detection and text summarization, glassmorphism styling, and working API configuration.
  • API Client Simplification: The SAMOAPIClient has been significantly simplified by removing client-side API key management, cold start logic, and LayoutManager tracking, with API calls now directly fetching endpoints using query parameters for summarization and emotion detection.
  • CSS Refinements: Numerous CSS changes re-establish the original styling, including glassmorphism effects, responsive design rules, and explicit !important declarations to ensure styles are applied correctly, while removing styles related to the problematic Font Awesome implementation.
  • Demo Logic Refactor: The JavaScript demo logic has been refactored into a new ComprehensiveDemo class, encapsulating UI interactions, processing flow, and resource management, although the DOMContentLoaded listener currently defers to simple-demo-functions.js for chart implementation.
  • Configuration Update: The config.js file has been completely refactored to streamline API endpoints, introduce OpenAI configuration, define external service URLs, and manage environment/feature flags, removing many legacy or unused configurations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@uelkerd uelkerd changed the title 🚨 EMERGENCY: Restore complete demo system (Fortress PR #209) feat: Restore complete demo system (Fortress PR #209) Sep 28, 2025
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR restores the complete demo system that was previously corrupted, implementing a sophisticated comprehensive demo interface with Material Icons design system, glassmorphism styling, and advanced AI processing pipeline functionality.

  • Complete restoration of sophisticated demo system from PR #169
  • Implementation of Material Icons design system replacing Font Awesome
  • Advanced glassmorphism styling with smooth animations and visual effects

Reviewed Changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 9 comments.

File Description
website/js/config.js Complete configuration system rewrite with optimized API endpoints and environment handling
website/js/comprehensive-demo.js Full restoration of comprehensive demo class with complete AI processing pipeline
website/css/comprehensive-demo.css Glassmorphism styling system with Material Design principles

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request is an emergency restoration of the demo system. The changes revert the CSS and JavaScript to a previous state. While this restores functionality, the approach introduces several significant issues. In the CSS, there is a widespread use of !important, which makes the code difficult to maintain. In the JavaScript, there are multiple critical Cross-Site Scripting (XSS) vulnerabilities due to the use of innerHTML with untrusted data. Additionally, a large block of dead code has been added, the global namespace is polluted, and a robust API client has been bypassed in favor of direct fetch calls, which is a regression in terms of error handling and reliability. I've provided specific comments and suggestions to address these critical and high-severity issues.

Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
.comprehensive-demo .info-icon {
/* Text input styling */
#textInput {
min-height: 240px !important;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This pull request introduces a large number of !important declarations throughout the stylesheet (e.g., here, and on lines 66, 70, 76, 86, 90, 94, 112, etc.). While this might be a quick fix for specificity issues, it is a significant anti-pattern in CSS. It breaks the natural cascade, making the stylesheet extremely difficult to debug, maintain, and extend in the future. It's a sign of underlying specificity conflicts that should be resolved by refactoring selectors or reordering stylesheets. For example, instead of min-height: 240px !important;, you could use a more specific selector like body.comprehensive-demo #textInput to increase its weight and avoid !important.

Comment on lines 104 to 119
try {
// Use VOICE_JOURNAL endpoint for audio analysis flows with proper timeout handling
return await this.makeRequest(this.endpoints.VOICE_JOURNAL, formData, 'POST', true);
// Use VOICE_JOURNAL endpoint for audio analysis flows (no auth header)
const config = {
method: 'POST',
body: formData
};
const response = await fetch(`${this.baseURL}${this.endpoints.VOICE_JOURNAL}`, config);

if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
const msg = errorData.message || errorData.error || `HTTP ${response.status}`;
throw new Error(msg);
}

return await response.json();
} catch (error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This function now uses fetch directly, bypassing the SAMOAPIClient's makeRequest method. This is a regression, as it loses the benefits of the client, such as automatic retries with exponential backoff and centralized timeout management. This makes the API call less robust. It's recommended to use the makeRequest method for all API interactions to ensure consistency and reliability.

        try {
            // Use makeRequest method for proper timeout and error handling
            return await this.makeRequest(this.endpoints.VOICE_JOURNAL, formData, 'POST', true);
        } catch (error) {
            console.error('Transcription error:', error);
            throw error;
        }

Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Comment thread website/css/comprehensive-demo.css Outdated
Comment thread website/js/comprehensive-demo.js Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
website/js/comprehensive-demo.js (1)

1528-1537: Sanitize the summary rendering to avoid XSS.

callSummarizationAPI passes raw API output (derived from user text) into this branch, and the template is injected with innerHTML. Any <script> or <img onerror> that slips through the summarizer or API error message will execute in the browser. Switch to DOM-safe APIs (create an element, set textContent, append) instead of interpolating into HTML. For example:

-            if (id === 'summaryText') {
-                element.innerHTML = `<div class="p-3 bg-dark border border-secondary rounded text-light">${value !== null && value !== undefined ? value : 'No summary available'}</div>`;
+            if (id === 'summaryText') {
+                const wrapper = document.createElement('div');
+                wrapper.className = 'p-3 bg-dark border border-secondary rounded text-light';
+                wrapper.textContent = value ?? 'No summary available';
+                element.replaceChildren(wrapper);

This keeps the styling while preventing script injection.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d9f0e56 and 6929a36.

📒 Files selected for processing (3)
  • website/css/comprehensive-demo.css (20 hunks)
  • website/js/comprehensive-demo.js (21 hunks)
  • website/js/config.js (1 hunks)

Comment thread website/js/config.js
@uelkerd uelkerd merged commit a8fac34 into main Sep 28, 2025
11 of 13 checks passed
@uelkerd uelkerd deleted the feat/restore-demo-system-pr169 branch September 28, 2025 20:52
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6929a36 and 562405c.

📒 Files selected for processing (2)
  • website/js/comprehensive-demo.js (22 hunks)
  • website/js/config.js (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Sourcery review

Comment on lines +562 to +724
if (!ctx) {
console.error('Emotion chart canvas not found');
return;
}

// Destroy existing chart properly
if (this.chart) {
try {
this.chart.destroy();
this.chart = null;
} catch (error) {
console.warn('Error destroying chart:', error);
this.chart = null;
}
}

// Use the basic chart directly since we have Chart.js
this.createBasicChart(ctx, emotionData);
}

createBasicChart(ctx, emotionData) {
// Fallback chart creation if performance optimizer fails
console.log('🔍 createBasicChart called with:', emotionData);
console.log('🔍 emotionData type:', typeof emotionData);
console.log('🔍 emotionData length:', emotionData?.length);

// Check if Chart.js is loaded
if (typeof Chart === 'undefined') {
console.error('❌ Chart.js not loaded!');
this.showChartError('Chart.js library not loaded. Please refresh the page.');
return;
}

if (!Array.isArray(emotionData) || emotionData.length === 0) {
console.error('❌ Invalid emotion data for chart:', emotionData);
return;
}

const labels = emotionData.map(e => e.emotion || e.label);
const data = emotionData.map(e => (e.confidence || e.score) * 100);
const colors = labels.map(label => this.getEmotionColor(label));

console.log('🔍 Chart labels:', labels);
console.log('🔍 Chart data:', data);
console.log('🔍 Chart colors:', colors);

try {
this.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Confidence (%)',
data: data,
backgroundColor: colors,
borderColor: colors.map((c) =>
c.startsWith('rgba(')
? c.replace(/rgba\((\d+\s*,\s*\d+\s*,\s*\d+),\s*[\d.]+\)/, 'rgba($1, 1)')
: c
),
borderWidth: 2,
borderRadius: 8,
borderSkipped: false,
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
color: 'rgba(139, 92, 246, 0.1)',
borderColor: 'rgba(139, 92, 246, 0.2)'
},
ticks: {
color: '#cbd5e1',
maxRotation: 45
}
},
y: {
beginAtZero: true,
max: 100,
grid: {
color: 'rgba(139, 92, 246, 0.1)',
borderColor: 'rgba(139, 92, 246, 0.2)'
},
ticks: {
color: '#cbd5e1',
callback: function(value) {
return value + '%';
}
}
}
},
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: 'rgba(15, 15, 35, 0.9)',
titleColor: '#e2e8f0',
bodyColor: '#e2e8f0',
borderColor: 'rgba(139, 92, 246, 0.5)',
borderWidth: 1
}
}
}
});

} catch (error) {
console.error('❌ Error creating chart:', error);
this.showChartError('Failed to create chart: ' + error.message);
}
}

/**
* Show chart error message
*/
showChartError(message) {
const chartContainer = document.getElementById('emotionChart');
if (chartContainer) {
const parent = chartContainer.parentElement;
if (parent) {
// Clear existing content safely
parent.textContent = '';

// Create alert container
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-warning';
alertDiv.setAttribute('role', 'alert');

// Create heading
const heading = document.createElement('h6');
heading.className = 'alert-heading';

const warningIcon = document.createElement('span');
warningIcon.className = 'material-icons me-2';
warningIcon.textContent = 'warning';

heading.appendChild(warningIcon);
heading.appendChild(document.createTextNode('Chart Error'));

// Create message paragraph
const messagePara = document.createElement('p');
messagePara.className = 'mb-0';
messagePara.textContent = message; // Safe text content

// Create separator
const hr = document.createElement('hr');

// Create instruction paragraph
const instructionPara = document.createElement('p');
instructionPara.className = 'mb-0 small';
instructionPara.textContent = 'Please refresh the page and try again.';

// Assemble the alert
alertDiv.appendChild(heading);
alertDiv.appendChild(messagePara);
alertDiv.appendChild(hr);
alertDiv.appendChild(instructionPara);

parent.appendChild(alertDiv);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Keep the emotion chart canvas available after errors.

showChartError wipes the parent node (parent.textContent = ''), which drops the <canvas id="emotionChart">. On the very next render attempt document.getElementById('emotionChart') is null, so Chart.js can never come back. Instead, leave the canvas in place (hide it if needed), render the alert beside it, and clear the alert when the chart successfully redraws.

         const ctx = document.getElementById('emotionChart');
         if (!ctx) {
             console.error('Emotion chart canvas not found');
             return;
         }
+
+        const container = ctx.parentElement;
+        if (container) {
+            const existingAlert = container.querySelector('.emotion-chart-error');
+            if (existingAlert) {
+                container.removeChild(existingAlert);
+            }
+        }
+        ctx.removeAttribute('hidden');
+        ctx.style.display = '';
 
         // Destroy existing chart properly
         if (this.chart) {
             try {
                 this.chart.destroy();
@@
-        if (chartContainer) {
-            const parent = chartContainer.parentElement;
-            if (parent) {
-                // Clear existing content safely
-                parent.textContent = '';
-
-                // Create alert container
-                const alertDiv = document.createElement('div');
-                alertDiv.className = 'alert alert-warning';
-                alertDiv.setAttribute('role', 'alert');
-
-                // Create heading
-                const heading = document.createElement('h6');
-                heading.className = 'alert-heading';
-
-                const warningIcon = document.createElement('span');
-                warningIcon.className = 'material-icons me-2';
-                warningIcon.textContent = 'warning';
-
-                heading.appendChild(warningIcon);
-                heading.appendChild(document.createTextNode('Chart Error'));
-
-                // Create message paragraph
-                const messagePara = document.createElement('p');
-                messagePara.className = 'mb-0';
-                messagePara.textContent = message; // Safe text content
-
-                // Create separator
-                const hr = document.createElement('hr');
-
-                // Create instruction paragraph
-                const instructionPara = document.createElement('p');
-                instructionPara.className = 'mb-0 small';
-                instructionPara.textContent = 'Please refresh the page and try again.';
-
-                // Assemble the alert
-                alertDiv.appendChild(heading);
-                alertDiv.appendChild(messagePara);
-                alertDiv.appendChild(hr);
-                alertDiv.appendChild(instructionPara);
-
-                parent.appendChild(alertDiv);
-            }
-        }
+        if (chartContainer) {
+            const parent = chartContainer.parentElement;
+            if (parent) {
+                let alertDiv = parent.querySelector('.emotion-chart-error');
+                if (!alertDiv) {
+                    alertDiv = document.createElement('div');
+                    alertDiv.className = 'emotion-chart-error alert alert-warning';
+                    alertDiv.setAttribute('role', 'alert');
+                    parent.insertBefore(alertDiv, chartContainer);
+                }
+
+                while (alertDiv.firstChild) {
+                    alertDiv.removeChild(alertDiv.firstChild);
+                }
+
+                const heading = document.createElement('h6');
+                heading.className = 'alert-heading';
+
+                const warningIcon = document.createElement('span');
+                warningIcon.className = 'material-icons me-2';
+                warningIcon.textContent = 'warning';
+
+                heading.appendChild(warningIcon);
+                heading.appendChild(document.createTextNode('Chart Error'));
+
+                const messagePara = document.createElement('p');
+                messagePara.className = 'mb-0';
+                messagePara.textContent = message;
+
+                const hr = document.createElement('hr');
+
+                const instructionPara = document.createElement('p');
+                instructionPara.className = 'mb-0 small';
+                instructionPara.textContent = 'Please refresh the page and try again.';
+
+                alertDiv.appendChild(heading);
+                alertDiv.appendChild(messagePara);
+                alertDiv.appendChild(hr);
+                alertDiv.appendChild(instructionPara);
+
+                chartContainer.setAttribute('hidden', 'true');
+                chartContainer.style.display = 'none';
+            }
+        }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!ctx) {
console.error('Emotion chart canvas not found');
return;
}
// Destroy existing chart properly
if (this.chart) {
try {
this.chart.destroy();
this.chart = null;
} catch (error) {
console.warn('Error destroying chart:', error);
this.chart = null;
}
}
// Use the basic chart directly since we have Chart.js
this.createBasicChart(ctx, emotionData);
}
createBasicChart(ctx, emotionData) {
// Fallback chart creation if performance optimizer fails
console.log('🔍 createBasicChart called with:', emotionData);
console.log('🔍 emotionData type:', typeof emotionData);
console.log('🔍 emotionData length:', emotionData?.length);
// Check if Chart.js is loaded
if (typeof Chart === 'undefined') {
console.error('❌ Chart.js not loaded!');
this.showChartError('Chart.js library not loaded. Please refresh the page.');
return;
}
if (!Array.isArray(emotionData) || emotionData.length === 0) {
console.error('❌ Invalid emotion data for chart:', emotionData);
return;
}
const labels = emotionData.map(e => e.emotion || e.label);
const data = emotionData.map(e => (e.confidence || e.score) * 100);
const colors = labels.map(label => this.getEmotionColor(label));
console.log('🔍 Chart labels:', labels);
console.log('🔍 Chart data:', data);
console.log('🔍 Chart colors:', colors);
try {
this.chart = new Chart(ctx, {
type: 'bar',
data: {
labels: labels,
datasets: [{
label: 'Confidence (%)',
data: data,
backgroundColor: colors,
borderColor: colors.map((c) =>
c.startsWith('rgba(')
? c.replace(/rgba\((\d+\s*,\s*\d+\s*,\s*\d+),\s*[\d.]+\)/, 'rgba($1, 1)')
: c
),
borderWidth: 2,
borderRadius: 8,
borderSkipped: false,
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
x: {
grid: {
color: 'rgba(139, 92, 246, 0.1)',
borderColor: 'rgba(139, 92, 246, 0.2)'
},
ticks: {
color: '#cbd5e1',
maxRotation: 45
}
},
y: {
beginAtZero: true,
max: 100,
grid: {
color: 'rgba(139, 92, 246, 0.1)',
borderColor: 'rgba(139, 92, 246, 0.2)'
},
ticks: {
color: '#cbd5e1',
callback: function(value) {
return value + '%';
}
}
}
},
plugins: {
legend: {
display: false
},
tooltip: {
backgroundColor: 'rgba(15, 15, 35, 0.9)',
titleColor: '#e2e8f0',
bodyColor: '#e2e8f0',
borderColor: 'rgba(139, 92, 246, 0.5)',
borderWidth: 1
}
}
}
});
} catch (error) {
console.error('❌ Error creating chart:', error);
this.showChartError('Failed to create chart: ' + error.message);
}
}
/**
* Show chart error message
*/
showChartError(message) {
const chartContainer = document.getElementById('emotionChart');
if (chartContainer) {
const parent = chartContainer.parentElement;
if (parent) {
// Clear existing content safely
parent.textContent = '';
// Create alert container
const alertDiv = document.createElement('div');
alertDiv.className = 'alert alert-warning';
alertDiv.setAttribute('role', 'alert');
// Create heading
const heading = document.createElement('h6');
heading.className = 'alert-heading';
const warningIcon = document.createElement('span');
warningIcon.className = 'material-icons me-2';
warningIcon.textContent = 'warning';
heading.appendChild(warningIcon);
heading.appendChild(document.createTextNode('Chart Error'));
// Create message paragraph
const messagePara = document.createElement('p');
messagePara.className = 'mb-0';
messagePara.textContent = message; // Safe text content
// Create separator
const hr = document.createElement('hr');
// Create instruction paragraph
const instructionPara = document.createElement('p');
instructionPara.className = 'mb-0 small';
instructionPara.textContent = 'Please refresh the page and try again.';
// Assemble the alert
alertDiv.appendChild(heading);
alertDiv.appendChild(messagePara);
alertDiv.appendChild(hr);
alertDiv.appendChild(instructionPara);
parent.appendChild(alertDiv);
}
const ctx = document.getElementById('emotionChart');
if (!ctx) {
console.error('Emotion chart canvas not found');
return;
}
// Remove any existing error alert and ensure the canvas is visible
const container = ctx.parentElement;
if (container) {
const existingAlert = container.querySelector('.emotion-chart-error');
if (existingAlert) {
container.removeChild(existingAlert);
}
}
ctx.removeAttribute('hidden');
ctx.style.display = '';
// Destroy existing chart properly
if (this.chart) {
try {
this.chart.destroy();
this.chart = null;
} catch (error) {
console.warn('Error destroying chart:', error);
this.chart = null;
}
}
// Use the basic chart directly since we have Chart.js
this.createBasicChart(ctx, emotionData);
}
/**
* Show chart error message
*/
showChartError(message) {
const chartContainer = document.getElementById('emotionChart');
if (chartContainer) {
const parent = chartContainer.parentElement;
if (parent) {
// Create or reuse the error alert container
let alertDiv = parent.querySelector('.emotion-chart-error');
if (!alertDiv) {
alertDiv = document.createElement('div');
alertDiv.className = 'emotion-chart-error alert alert-warning';
alertDiv.setAttribute('role', 'alert');
parent.insertBefore(alertDiv, chartContainer);
}
// Clear previous alert contents
while (alertDiv.firstChild) {
alertDiv.removeChild(alertDiv.firstChild);
}
// Build alert content
const heading = document.createElement('h6');
heading.className = 'alert-heading';
const warningIcon = document.createElement('span');
warningIcon.className = 'material-icons me-2';
warningIcon.textContent = 'warning';
heading.appendChild(warningIcon);
heading.appendChild(document.createTextNode('Chart Error'));
const messagePara = document.createElement('p');
messagePara.className = 'mb-0';
messagePara.textContent = message;
const hr = document.createElement('hr');
const instructionPara = document.createElement('p');
instructionPara.className = 'mb-0 small';
instructionPara.textContent = 'Please refresh the page and try again.';
alertDiv.appendChild(heading);
alertDiv.appendChild(messagePara);
alertDiv.appendChild(hr);
alertDiv.appendChild(instructionPara);
// Hide the canvas but keep it in the DOM
chartContainer.setAttribute('hidden', 'true');
chartContainer.style.display = 'none';
}
}
}
🤖 Prompt for AI Agents
In website/js/comprehensive-demo.js around lines 562-724, showChartError
currently clears the parent by setting parent.textContent = '' which removes the
<canvas id="emotionChart"> and prevents future chart renders; instead, preserve
the canvas and only manage an alert element: find the canvas within parent and
keep it (optionally hide it via style.display = 'none' or a CSS class), remove
or replace any existing alert node (querySelector by a specific id/class for the
alert), create and append the alert element as a sibling after the canvas, and
ensure createBasicChart (or the chart creation path) removes/hides the alert and
restores the canvas visibility before instantiating Chart.js so the canvas
remains available for future renders.

Comment thread website/js/config.js
Comment on lines +76 to +101
const sanitizedConfig = { ...window.SAMO_CONFIG };
const sensitiveKeys = ['apiKey', 'secret', 'token', 'password', 'clientSecret'];

// Redact sensitive fields
sensitiveKeys.forEach(key => {
if (sanitizedConfig[key]) {
sanitizedConfig[key] = 'REDACTED';
}
});

// Also check nested objects
if (sanitizedConfig.API) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.API[key]) {
sanitizedConfig.API[key] = 'REDACTED';
}
});
}

return wsUrl + cleanEndpoint;
};
if (sanitizedConfig.OPENAI) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.OPENAI[key]) {
sanitizedConfig.OPENAI[key] = 'REDACTED';
}
});
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Stop mutating the live config when redacting for debug logs.

Line 76 creates only a shallow copy, so the redaction loop rewrites window.SAMO_CONFIG itself (e.g., OPENAI.API_KEY becomes "REDACTED"). After the first debug log every subsequent API call is broken because the real secrets are gone. Please deep-clone before redacting so the production config stays intact.

-    const sanitizedConfig = { ...window.SAMO_CONFIG };
+    const sanitizedConfig = JSON.parse(JSON.stringify(window.SAMO_CONFIG));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const sanitizedConfig = { ...window.SAMO_CONFIG };
const sensitiveKeys = ['apiKey', 'secret', 'token', 'password', 'clientSecret'];
// Redact sensitive fields
sensitiveKeys.forEach(key => {
if (sanitizedConfig[key]) {
sanitizedConfig[key] = 'REDACTED';
}
});
// Also check nested objects
if (sanitizedConfig.API) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.API[key]) {
sanitizedConfig.API[key] = 'REDACTED';
}
});
}
return wsUrl + cleanEndpoint;
};
if (sanitizedConfig.OPENAI) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.OPENAI[key]) {
sanitizedConfig.OPENAI[key] = 'REDACTED';
}
});
}
// Deep-clone the config to avoid mutating window.SAMO_CONFIG
const sanitizedConfig = JSON.parse(JSON.stringify(window.SAMO_CONFIG));
const sensitiveKeys = ['apiKey', 'secret', 'token', 'password', 'clientSecret'];
// Redact sensitive fields
sensitiveKeys.forEach(key => {
if (sanitizedConfig[key]) {
sanitizedConfig[key] = 'REDACTED';
}
});
// Also check nested objects
if (sanitizedConfig.API) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.API[key]) {
sanitizedConfig.API[key] = 'REDACTED';
}
});
}
if (sanitizedConfig.OPENAI) {
sensitiveKeys.forEach(key => {
if (sanitizedConfig.OPENAI[key]) {
sanitizedConfig.OPENAI[key] = 'REDACTED';
}
});
}
🤖 Prompt for AI Agents
In website/js/config.js around lines 76 to 101 the code only creates a shallow
copy of window.SAMO_CONFIG then redacts sensitive fields, which ends up mutating
the live config (breaking subsequent API calls); replace the shallow copy with a
deep clone (e.g., use structuredClone(window.SAMO_CONFIG) if available, falling
back to JSON.parse(JSON.stringify(window.SAMO_CONFIG))) and perform redaction on
that clone so window.SAMO_CONFIG is never modified; keep the existing redaction
logic but operate on the cloned object and use that cloned sanitizedConfig for
logging/output.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants