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:
Claude 2025-07-13 23:08:05 +05:30
parent f83c2497cc
commit ea944072aa
4 changed files with 361 additions and 65 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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