mirror of
https://github.com/thecyberlearn/quantum-ai.git
synced 2026-08-18 09:32:59 +00:00
## Overview Replace generic `AgentUtils.displayResults()` with specialized display functions for each agent to provide optimized content formatting and presentation. ## Changes Made ### Custom Display Functions Created - **Job Posting Generator**: Professional business formatting with structured headers - **Social Ads Generator**: Engaging ad copy styling with creative glassmorphism effects - **Weather Reporter**: Clean weather data presentation with metric highlighting - **Data Analyzer**: Already had custom function with rich analysis formatting ### Agent-Specific Features #### Job Posting Generator - Professional headers with border styling and proper hierarchy - Clean business formatting for requirements and responsibilities - Justified text alignment for formal presentation - Enhanced bold text for key information #### Social Ads Generator - Creative pink/purple theme matching creative agent styling - Eye-catching call-to-action highlighting with background effects - Sparkle emoji bullets for engaging list presentation - Glassmorphism wrapper effects for modern visual appeal #### Weather Reporter - Clean blue theme for weather data presentation - Temperature and metric highlighting with background colors - Organized weather sections with proper data structure - Subtle background styling for data containers ### Removed Generic Function - Removed `AgentUtils.displayResults()` from agent-utils.js - Added explanatory comment about custom display logic - Kept shared utilities: showToast, updateWalletBalance, etc. ## Benefits - **Specialized Content Handling**: Each agent optimizes its specific data structure - **Better User Experience**: Content formatted appropriately for each use case - **Enhanced Visual Appeal**: Custom styling matches each agent's theme and purpose - **Maintainability**: Agent-specific logic contained within each agent - **Performance**: No unnecessary generic field checking ## Technical Implementation - Custom content extraction with priority field ordering - Agent-specific markdown/text formatting functions - Proper error handling and wallet balance updates - Consistent success/error messaging patterns - Type-safe content handling with fallbacks ## Testing - All agent templates render successfully - Django project passes system checks - Custom display functions handle content extraction properly - Maintained compatibility with existing agent workflows 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
245 lines
8.1 KiB
JavaScript
245 lines
8.1 KiB
JavaScript
/**
|
|
* NetCop AI Agents - Shared Utilities
|
|
* Contains common functions used across all agent templates
|
|
*/
|
|
|
|
window.AgentUtils = {
|
|
/**
|
|
* Enhanced Markdown Parser
|
|
* Converts markdown syntax to styled HTML with proper formatting
|
|
*/
|
|
parseMarkdown(text) {
|
|
// Handle null, undefined, or non-string inputs
|
|
if (!text || typeof text !== 'string') {
|
|
return '';
|
|
}
|
|
|
|
let html = text;
|
|
|
|
// Convert headers with proper styling
|
|
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 1.1em; font-weight: 600; margin: 12px 0 8px 0; color: #374151;">$1</h3>');
|
|
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 1.2em; font-weight: 600; margin: 14px 0 8px 0; color: #374151;">$1</h2>');
|
|
html = html.replace(/^# (.*$)/gm, '<h1 style="font-size: 1.3em; font-weight: 600; margin: 16px 0 10px 0; color: #374151;">$1</h1>');
|
|
|
|
// Convert bold text
|
|
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="font-weight: 500; color: #1f2937;">$1</strong>');
|
|
|
|
// Convert bullet points to proper lists
|
|
const lines = html.split('\n');
|
|
let inList = false;
|
|
let processedLines = [];
|
|
|
|
for (let i = 0; i < lines.length; i++) {
|
|
const line = lines[i].trim();
|
|
|
|
if (line.startsWith('- ')) {
|
|
if (!inList) {
|
|
processedLines.push('<ul style="margin: 8px 0; padding-left: 20px;">');
|
|
inList = true;
|
|
}
|
|
processedLines.push(`<li style="margin: 3px 0; color: #4b5563;">${line.substring(2).trim()}</li>`);
|
|
} else {
|
|
if (inList) {
|
|
processedLines.push('</ul>');
|
|
inList = false;
|
|
}
|
|
processedLines.push(line);
|
|
}
|
|
}
|
|
|
|
if (inList) {
|
|
processedLines.push('</ul>');
|
|
}
|
|
|
|
html = processedLines.join('\n');
|
|
|
|
// Reduce excessive line breaks and convert to paragraphs
|
|
html = html.replace(/\n{3,}/g, '\n\n');
|
|
|
|
// Convert double line breaks to paragraph breaks
|
|
const paragraphs = html.split('\n\n');
|
|
html = paragraphs
|
|
.filter(p => p.trim() !== '')
|
|
.map(p => {
|
|
const trimmed = p.trim();
|
|
// Don't wrap headers or lists in paragraphs
|
|
if (trimmed.startsWith('<h') || trimmed.startsWith('<ul') || trimmed.startsWith('</ul>') || trimmed.includes('<li')) {
|
|
return trimmed;
|
|
}
|
|
return `<p style="margin: 8px 0; line-height: 1.4; color: #4b5563;">${trimmed}</p>`;
|
|
})
|
|
.join('');
|
|
|
|
// Convert remaining single line breaks to <br> tags
|
|
html = html.replace(/\n/g, '<br>');
|
|
|
|
return html.trim();
|
|
},
|
|
|
|
/**
|
|
* Update wallet balance display across all agents
|
|
*/
|
|
updateWalletBalance(newBalance) {
|
|
const balanceElement = document.querySelector('[data-wallet-balance]') ||
|
|
document.getElementById('walletBalance');
|
|
if (balanceElement) {
|
|
balanceElement.textContent = `${newBalance.toFixed(2)} AED`;
|
|
}
|
|
window.currentWalletBalance = newBalance;
|
|
},
|
|
|
|
/**
|
|
* Reset UI to initial state
|
|
*/
|
|
resetUI(config) {
|
|
const elements = {
|
|
processingStatus: document.getElementById(config.processingStatusId || 'processingStatus'),
|
|
processButton: document.getElementById(config.processButtonId || 'processButton'),
|
|
results: document.getElementById(config.resultsId)
|
|
};
|
|
|
|
if (elements.processingStatus) {
|
|
elements.processingStatus.style.display = 'none';
|
|
}
|
|
|
|
if (elements.processButton) {
|
|
elements.processButton.disabled = false;
|
|
elements.processButton.innerHTML = config.buttonText || 'Process';
|
|
elements.processButton.classList.remove('loading');
|
|
}
|
|
|
|
if (elements.results) {
|
|
elements.results.style.display = 'none';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Show processing status
|
|
*/
|
|
showProcessing(config) {
|
|
const elements = {
|
|
processingStatus: document.getElementById(config.processingStatusId || 'processingStatus'),
|
|
processButton: document.getElementById(config.processButtonId || 'processButton'),
|
|
results: document.getElementById(config.resultsId)
|
|
};
|
|
|
|
if (elements.processingStatus) {
|
|
elements.processingStatus.style.display = 'block';
|
|
}
|
|
|
|
if (elements.processButton) {
|
|
elements.processButton.disabled = true;
|
|
elements.processButton.classList.add('loading');
|
|
elements.processButton.innerHTML = config.processingText || '⏳ Processing...';
|
|
}
|
|
|
|
if (elements.results) {
|
|
elements.results.style.display = 'none';
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Show toast notification with duplicate prevention
|
|
*/
|
|
showToast(message, type = 'info') {
|
|
// Prevent duplicate toasts
|
|
const existingToast = document.querySelector('.agent-toast');
|
|
if (existingToast) {
|
|
existingToast.remove();
|
|
}
|
|
|
|
const toast = document.createElement('div');
|
|
toast.className = 'agent-toast';
|
|
toast.style.cssText = `
|
|
position: fixed;
|
|
top: 16px;
|
|
right: 16px;
|
|
padding: 8px 12px;
|
|
border-radius: 4px;
|
|
color: white;
|
|
font-size: 13px;
|
|
z-index: 1000;
|
|
max-width: 300px;
|
|
font-weight: 500;
|
|
${type === 'success' ? 'background: #10b981;' : 'background: #ef4444;'}
|
|
`;
|
|
toast.textContent = message;
|
|
document.body.appendChild(toast);
|
|
|
|
setTimeout(() => {
|
|
if (toast.parentNode) {
|
|
toast.remove();
|
|
}
|
|
}, 2000);
|
|
},
|
|
|
|
// NOTE: displayResults() function removed - each agent now has its own custom display logic
|
|
|
|
/**
|
|
* Generate text for copy/download functionality
|
|
*/
|
|
generateTextForExport(contentElementId) {
|
|
const content = document.getElementById(contentElementId);
|
|
if (content) {
|
|
return content.innerText || content.textContent || '';
|
|
}
|
|
return 'No content available';
|
|
},
|
|
|
|
/**
|
|
* Copy content to clipboard
|
|
*/
|
|
copyToClipboard(text, successMessage = 'Content copied to clipboard!') {
|
|
navigator.clipboard.writeText(text).then(() => {
|
|
this.showToast(`📋 ${successMessage}`, 'success');
|
|
}).catch(() => {
|
|
this.showToast('Failed to copy content', 'error');
|
|
});
|
|
},
|
|
|
|
/**
|
|
* Download content as text file
|
|
*/
|
|
downloadAsFile(text, filename, successMessage = 'File downloaded!') {
|
|
const blob = new Blob([text], { type: 'text/plain' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = filename || `content-${Date.now()}.txt`;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
this.showToast(`💾 ${successMessage}`, 'success');
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Progressive status steps for better UX
|
|
*/
|
|
window.StatusStepper = class {
|
|
constructor(steps, statusTextElementId, interval = 800) {
|
|
this.steps = steps;
|
|
this.statusTextElement = document.getElementById(statusTextElementId);
|
|
this.interval = interval;
|
|
this.currentStep = 0;
|
|
this.stepInterval = null;
|
|
}
|
|
|
|
start() {
|
|
this.currentStep = 0;
|
|
this.stepInterval = setInterval(() => {
|
|
if (this.currentStep < this.steps.length && this.statusTextElement) {
|
|
this.statusTextElement.textContent = this.steps[this.currentStep];
|
|
this.currentStep++;
|
|
} else {
|
|
this.stop();
|
|
}
|
|
}, this.interval);
|
|
}
|
|
|
|
stop() {
|
|
if (this.stepInterval) {
|
|
clearInterval(this.stepInterval);
|
|
this.stepInterval = null;
|
|
}
|
|
}
|
|
}; |