mirror of
https://github.com/thecyberlearn/quantum-ai.git
synced 2026-08-18 09:32:59 +00:00
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>
This commit is contained in:
parent
f83c2497cc
commit
ea944072aa
@ -295,16 +295,127 @@
|
||||
}
|
||||
|
||||
|
||||
// Display job posting results with markdown formatting
|
||||
// Display job posting results with professional formatting
|
||||
function displayResults(result) {
|
||||
AgentUtils.displayResults({
|
||||
result: result,
|
||||
resultsId: 'jobResults',
|
||||
contentId: 'jobContent',
|
||||
defaultMessage: 'Job posting generated successfully!',
|
||||
successMessage: '✅ Job posting created and payment processed!',
|
||||
errorMessage: '❌ Failed to generate job posting - no charge applied'
|
||||
});
|
||||
const resultsContainer = document.getElementById('jobResults');
|
||||
const contentElement = document.getElementById('jobContent');
|
||||
|
||||
if (!resultsContainer || !contentElement) {
|
||||
console.error('Job results elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update wallet balance if provided
|
||||
if (result.wallet_balance !== undefined) {
|
||||
updateWalletBalance(result.wallet_balance);
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if (result.error) {
|
||||
AgentUtils.showToast(`❌ ${result.error}`, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle failed status
|
||||
if (result.status === 'failed') {
|
||||
AgentUtils.showToast('❌ Failed to generate job posting - no charge applied', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract job posting content with priority order
|
||||
let content = '';
|
||||
|
||||
if (result.job_posting_content && typeof result.job_posting_content === 'string') {
|
||||
content = result.job_posting_content;
|
||||
} else if (result.content && typeof result.content === 'string') {
|
||||
content = result.content;
|
||||
} else if (result.formatted_report && typeof result.formatted_report === 'string') {
|
||||
content = result.formatted_report;
|
||||
} else if (result.output_text && typeof result.output_text === 'string') {
|
||||
content = result.output_text;
|
||||
} else {
|
||||
content = 'Job posting generated successfully!';
|
||||
}
|
||||
|
||||
// Format job posting content with professional styling
|
||||
const formattedContent = formatJobPostingContent(content);
|
||||
|
||||
// Update content
|
||||
contentElement.innerHTML = formattedContent;
|
||||
|
||||
// Show results
|
||||
resultsContainer.style.display = 'block';
|
||||
resultsContainer.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
// Show success message
|
||||
const successMessage = result.success ? '✅ Job posting created and payment processed!' : '✅ Job posting generated!';
|
||||
AgentUtils.showToast(successMessage, 'success');
|
||||
}
|
||||
|
||||
// Professional job posting formatter
|
||||
function formatJobPostingContent(content) {
|
||||
if (!content || typeof content !== 'string') {
|
||||
return '<p>No job posting content available.</p>';
|
||||
}
|
||||
|
||||
let html = content;
|
||||
|
||||
// Enhanced header formatting for job titles and company names
|
||||
html = html.replace(/^# (.*$)/gm, '<h1 style="font-size: 24px; font-weight: 700; color: var(--text-primary); margin: 24px 0 16px 0; border-bottom: 3px solid var(--primary-color); padding-bottom: 12px;">$1</h1>');
|
||||
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 20px; font-weight: 600; color: var(--text-primary); margin: 20px 0 12px 0; border-bottom: 2px solid var(--border-medium); padding-bottom: 8px;">$1</h2>');
|
||||
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 18px; font-weight: 600; color: var(--text-primary); margin: 16px 0 10px 0; padding-bottom: 6px;">$1</h3>');
|
||||
|
||||
// Professional bold text formatting
|
||||
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="font-weight: 600; color: var(--text-primary);">$1</strong>');
|
||||
|
||||
// Professional bullet point formatting
|
||||
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('- ') || line.startsWith('• ')) {
|
||||
if (!inList) {
|
||||
processedLines.push('<ul style="margin: 12px 0; padding-left: 24px; list-style-type: disc;">');
|
||||
inList = true;
|
||||
}
|
||||
const listContent = line.substring(2).trim();
|
||||
processedLines.push(`<li style="margin: 6px 0; line-height: 1.5; color: var(--text-primary);">${listContent}</li>`);
|
||||
} else {
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
inList = false;
|
||||
}
|
||||
processedLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
}
|
||||
|
||||
html = processedLines.join('\n');
|
||||
|
||||
// Convert line breaks to professional paragraphs
|
||||
const paragraphs = html.split(/\n\s*\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: 12px 0; line-height: 1.6; color: var(--text-primary); text-align: justify;">${trimmed}</p>`;
|
||||
})
|
||||
.join('');
|
||||
|
||||
// Add professional spacing and structure
|
||||
html = `<div style="font-family: 'Inter', sans-serif; max-width: 100%; overflow-wrap: break-word;">${html}</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// Track if results have been displayed to prevent duplicates
|
||||
|
||||
@ -199,16 +199,127 @@
|
||||
AgentUtils.showToast('Form reset! Ready for another ad campaign.', 'success');
|
||||
}
|
||||
|
||||
// Display social ads results with markdown parsing
|
||||
// Display social ads results with engaging ad copy formatting
|
||||
function displayResults(result) {
|
||||
AgentUtils.displayResults({
|
||||
result: result,
|
||||
resultsId: 'adResults',
|
||||
contentId: 'adContent',
|
||||
defaultMessage: 'Social ads generated successfully!',
|
||||
successMessage: '✅ Social ads created and payment processed!',
|
||||
errorMessage: '❌ Failed to generate ads - no charge applied'
|
||||
});
|
||||
const resultsContainer = document.getElementById('adResults');
|
||||
const contentElement = document.getElementById('adContent');
|
||||
|
||||
if (!resultsContainer || !contentElement) {
|
||||
console.error('Ad results elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update wallet balance if provided
|
||||
if (result.wallet_balance !== undefined) {
|
||||
updateWalletBalance(result.wallet_balance);
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if (result.error) {
|
||||
AgentUtils.showToast(`❌ ${result.error}`, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle failed status
|
||||
if (result.status === 'failed') {
|
||||
AgentUtils.showToast('❌ Failed to generate ads - no charge applied', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract ad copy content with priority order
|
||||
let content = '';
|
||||
|
||||
if (result.ad_copy_content && typeof result.ad_copy_content === 'string') {
|
||||
content = result.ad_copy_content;
|
||||
} else if (result.content && typeof result.content === 'string') {
|
||||
content = result.content;
|
||||
} else if (result.formatted_report && typeof result.formatted_report === 'string') {
|
||||
content = result.formatted_report;
|
||||
} else if (result.output_text && typeof result.output_text === 'string') {
|
||||
content = result.output_text;
|
||||
} else {
|
||||
content = 'Social ads generated successfully!';
|
||||
}
|
||||
|
||||
// Format ad copy content with engaging styling
|
||||
const formattedContent = formatSocialAdContent(content);
|
||||
|
||||
// Update content
|
||||
contentElement.innerHTML = formattedContent;
|
||||
|
||||
// Show results
|
||||
resultsContainer.style.display = 'block';
|
||||
resultsContainer.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
// Show success message
|
||||
const successMessage = result.success ? '✅ Social ads created and payment processed!' : '✅ Social ads generated!';
|
||||
AgentUtils.showToast(successMessage, 'success');
|
||||
}
|
||||
|
||||
// Engaging social ad copy formatter
|
||||
function formatSocialAdContent(content) {
|
||||
if (!content || typeof content !== 'string') {
|
||||
return '<p>No ad content available.</p>';
|
||||
}
|
||||
|
||||
let html = content;
|
||||
|
||||
// Enhanced header formatting for ad titles and platform sections
|
||||
html = html.replace(/^# (.*$)/gm, '<h1 style="font-size: 22px; font-weight: 700; color: rgba(236, 72, 153, 1); margin: 20px 0 14px 0; border-bottom: 3px solid rgba(236, 72, 153, 0.3); padding-bottom: 10px; text-align: center;">$1</h1>');
|
||||
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 18px; font-weight: 600; color: rgba(190, 24, 93, 1); margin: 16px 0 10px 0; padding: 8px 12px; background: rgba(236, 72, 153, 0.1); border-radius: 8px; border-left: 4px solid rgba(236, 72, 153, 1);">$1</h2>');
|
||||
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 16px; font-weight: 600; color: rgba(162, 28, 175, 1); margin: 14px 0 8px 0; padding-bottom: 4px;">$1</h3>');
|
||||
|
||||
// Eye-catching bold text for call-to-actions and key phrases
|
||||
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="font-weight: 700; color: rgba(190, 24, 93, 1); background: rgba(236, 72, 153, 0.1); padding: 2px 6px; border-radius: 4px;">$1</strong>');
|
||||
|
||||
// Engaging bullet point formatting for ad features
|
||||
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('- ') || line.startsWith('• ')) {
|
||||
if (!inList) {
|
||||
processedLines.push('<ul style="margin: 12px 0; padding-left: 20px; list-style: none;">');
|
||||
inList = true;
|
||||
}
|
||||
const listContent = line.substring(2).trim();
|
||||
processedLines.push(`<li style="margin: 8px 0; line-height: 1.5; color: var(--text-primary); position: relative; padding-left: 24px;"><span style="position: absolute; left: 0; color: rgba(236, 72, 153, 1); font-weight: bold;">✨</span>${listContent}</li>`);
|
||||
} else {
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
inList = false;
|
||||
}
|
||||
processedLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
}
|
||||
|
||||
html = processedLines.join('\n');
|
||||
|
||||
// Convert line breaks to engaging paragraphs
|
||||
const paragraphs = html.split(/\n\s*\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: 12px 0; line-height: 1.6; color: var(--text-primary); font-size: 15px;">${trimmed}</p>`;
|
||||
})
|
||||
.join('');
|
||||
|
||||
// Add creative wrapper with glassmorphism effect
|
||||
html = `<div style="font-family: 'Inter', sans-serif; max-width: 100%; overflow-wrap: break-word; background: rgba(255, 255, 255, 0.95); border-radius: 12px; padding: 20px; backdrop-filter: blur(10px); border: 1px solid rgba(236, 72, 153, 0.2);">${html}</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// Track polling and results to prevent duplicates
|
||||
|
||||
@ -173,44 +173,7 @@ window.AgentUtils = {
|
||||
}, 2000);
|
||||
},
|
||||
|
||||
/**
|
||||
* Display results with markdown parsing
|
||||
* Standardized across all agents
|
||||
*/
|
||||
displayResults(config) {
|
||||
const resultsContainer = document.getElementById(config.resultsId);
|
||||
const contentContainer = document.getElementById(config.contentId);
|
||||
|
||||
if (config.result.success && config.result.status === 'completed') {
|
||||
// Get content from various possible fields
|
||||
const content = config.result.content ||
|
||||
config.result.job_posting_content ||
|
||||
config.result.ad_copy_content ||
|
||||
config.result.analysis_results ||
|
||||
config.result.insights_summary ||
|
||||
config.result.report_text ||
|
||||
config.result.weather_data ||
|
||||
config.result.formatted_report ||
|
||||
config.result.output_text ||
|
||||
config.defaultMessage ||
|
||||
'Content generated successfully!';
|
||||
|
||||
// Parse markdown and display as HTML
|
||||
const formattedContent = this.parseMarkdown(content);
|
||||
contentContainer.innerHTML = formattedContent;
|
||||
|
||||
resultsContainer.style.display = 'block';
|
||||
|
||||
// Update wallet balance if provided
|
||||
if (config.result.wallet_balance !== undefined) {
|
||||
this.updateWalletBalance(config.result.wallet_balance);
|
||||
}
|
||||
|
||||
this.showToast(config.successMessage || '✅ Content generated and payment processed!', 'success');
|
||||
} else {
|
||||
this.showToast(config.errorMessage || '❌ Failed to generate content - no charge applied', 'error');
|
||||
}
|
||||
},
|
||||
// NOTE: displayResults() function removed - each agent now has its own custom display logic
|
||||
|
||||
/**
|
||||
* Generate text for copy/download functionality
|
||||
|
||||
@ -259,16 +259,127 @@
|
||||
// Simple toast notification
|
||||
|
||||
|
||||
// Display weather results with markdown parsing
|
||||
// Display weather results with clean weather data formatting
|
||||
function displayResults(result) {
|
||||
AgentUtils.displayResults({
|
||||
result: result,
|
||||
resultsId: 'weatherResults',
|
||||
contentId: 'weatherContent',
|
||||
defaultMessage: 'Weather report generated successfully!',
|
||||
successMessage: '✅ Weather report completed and payment processed!',
|
||||
errorMessage: '❌ Failed to generate weather report - no charge applied'
|
||||
});
|
||||
const resultsContainer = document.getElementById('weatherResults');
|
||||
const contentElement = document.getElementById('weatherContent');
|
||||
|
||||
if (!resultsContainer || !contentElement) {
|
||||
console.error('Weather results elements not found');
|
||||
return;
|
||||
}
|
||||
|
||||
// Update wallet balance if provided
|
||||
if (result.wallet_balance !== undefined) {
|
||||
updateWalletBalance(result.wallet_balance);
|
||||
}
|
||||
|
||||
// Handle errors
|
||||
if (result.error) {
|
||||
AgentUtils.showToast(`❌ ${result.error}`, 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle failed status
|
||||
if (result.status === 'failed') {
|
||||
AgentUtils.showToast('❌ Failed to generate weather report - no charge applied', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract weather content with priority order
|
||||
let content = '';
|
||||
|
||||
if (result.weather_data && typeof result.weather_data === 'string') {
|
||||
content = result.weather_data;
|
||||
} else if (result.formatted_report && typeof result.formatted_report === 'string') {
|
||||
content = result.formatted_report;
|
||||
} else if (result.content && typeof result.content === 'string') {
|
||||
content = result.content;
|
||||
} else if (result.output_text && typeof result.output_text === 'string') {
|
||||
content = result.output_text;
|
||||
} else {
|
||||
content = 'Weather report generated successfully!';
|
||||
}
|
||||
|
||||
// Format weather content with clean data presentation
|
||||
const formattedContent = formatWeatherContent(content);
|
||||
|
||||
// Update content
|
||||
contentElement.innerHTML = formattedContent;
|
||||
|
||||
// Show results
|
||||
resultsContainer.style.display = 'block';
|
||||
resultsContainer.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
// Show success message
|
||||
const successMessage = result.success ? '✅ Weather report completed and payment processed!' : '✅ Weather report generated!';
|
||||
AgentUtils.showToast(successMessage, 'success');
|
||||
}
|
||||
|
||||
// Clean weather data formatter
|
||||
function formatWeatherContent(content) {
|
||||
if (!content || typeof content !== 'string') {
|
||||
return '<p>No weather data available.</p>';
|
||||
}
|
||||
|
||||
let html = content;
|
||||
|
||||
// Enhanced header formatting for weather sections
|
||||
html = html.replace(/^# (.*$)/gm, '<h1 style="font-size: 22px; font-weight: 700; color: var(--primary-blue); margin: 20px 0 14px 0; border-bottom: 3px solid var(--primary-blue); padding-bottom: 10px; text-align: center;">$1</h1>');
|
||||
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 18px; font-weight: 600; color: var(--primary-dark); margin: 16px 0 10px 0; padding: 8px 12px; background: rgba(59, 130, 246, 0.1); border-radius: 8px; border-left: 4px solid var(--primary-blue);">$1</h2>');
|
||||
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 16px; font-weight: 600; color: var(--text-primary); margin: 14px 0 8px 0; padding-bottom: 4px;">$1</h3>');
|
||||
|
||||
// Temperature and weather metric highlighting
|
||||
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="font-weight: 600; color: var(--primary-dark); background: rgba(59, 130, 246, 0.1); padding: 2px 6px; border-radius: 4px;">$1</strong>');
|
||||
|
||||
// Weather condition formatting with clean presentation
|
||||
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('- ') || line.startsWith('• ')) {
|
||||
if (!inList) {
|
||||
processedLines.push('<ul style="margin: 12px 0; padding-left: 20px; list-style: none;">');
|
||||
inList = true;
|
||||
}
|
||||
const listContent = line.substring(2).trim();
|
||||
processedLines.push(`<li style="margin: 6px 0; line-height: 1.5; color: var(--text-primary); position: relative; padding-left: 20px;"><span style="position: absolute; left: 0; color: var(--primary-blue); font-weight: bold;">•</span>${listContent}</li>`);
|
||||
} else {
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
inList = false;
|
||||
}
|
||||
processedLines.push(line);
|
||||
}
|
||||
}
|
||||
|
||||
if (inList) {
|
||||
processedLines.push('</ul>');
|
||||
}
|
||||
|
||||
html = processedLines.join('\n');
|
||||
|
||||
// Convert line breaks to clean paragraphs
|
||||
const paragraphs = html.split(/\n\s*\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: 12px 0; line-height: 1.6; color: var(--text-primary); font-size: 15px;">${trimmed}</p>`;
|
||||
})
|
||||
.join('');
|
||||
|
||||
// Add clean wrapper for weather data
|
||||
html = `<div style="font-family: 'Inter', sans-serif; max-width: 100%; overflow-wrap: break-word; background: var(--background-subtle); border-radius: 8px; padding: 16px; border: 1px solid var(--border-light);">${html}</div>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
// Poll for results
|
||||
|
||||
Loading…
Reference in New Issue
Block a user