quantum-ai-v3/static/js/agent-utils.js
Claude ea944072aa Implement custom display functions for all agents
## 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>
2025-07-13 23:08:05 +05:30

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;
}
}
};