Fix data analyzer TypeError and enhance markdown parsing

## Issues Fixed
- Fixed TypeError: text.replace is not a function in parseMarkdown
- Enhanced type checking for null/undefined inputs in agent-utils.js
- Data analyzer now properly handles all response data types

## Enhancements
- Improved parseMarkdown function with better type safety
- Enhanced markdown parsing with proper HTML styling
- Added custom parseMarkdownToHTML for data analyzer with rich formatting
- Better handling of headers, lists, bold text, and paragraphs

## Data Analyzer Improvements
- Custom markdown parser with styled headers and lists
- Proper content extraction priority: report_text > insights_summary > raw_response.analysis
- Enhanced visual formatting with CSS variables for consistent theming
- Better error handling and fallback content

## Technical Changes
- Added typeof checks to prevent non-string inputs causing errors
- Enhanced bullet point and numbered list conversion
- Improved paragraph formatting and line break handling
- Consistent styling across all markdown elements

## Test Results
- Data analyzer successfully processes PDF files
- Returns proper JSON responses with formatted analysis
- Markdown parsing works correctly with complex content structure
- No more JavaScript type errors in console

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Claude 2025-07-13 22:56:27 +05:30
parent 8189cca054
commit f83c2497cc
3 changed files with 167 additions and 18 deletions

View File

@ -99,7 +99,7 @@ class DataAnalysisAgentProcessor(StandardWebhookProcessor):
}
# Use analysis text for multiple fields for compatibility
insights_summary = analysis_text[:500] + '...' if len(analysis_text) > 500 else analysis_text
insights_summary = analysis_text
report_text = analysis_text
raw_response = response_data

View File

@ -676,16 +676,108 @@
});
});
// Display analysis results with markdown parsing
// Display analysis results with custom Data Analyzer formatting
function displayResults(result) {
AgentUtils.displayResults({
result: result,
resultsId: 'analysisResults',
contentId: 'analysisContent',
defaultMessage: 'Data analysis completed successfully!',
successMessage: '✅ Data analysis completed and payment processed!',
errorMessage: '❌ Failed to analyze data - no charge applied'
const resultsContainer = document.getElementById('analysisResults');
const contentElement = document.getElementById('analysisContent');
if (!resultsContainer || !contentElement) {
console.error('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;
}
// Extract content with priority: report_text > insights_summary > raw_response.analysis
let content = '';
if (result.report_text && typeof result.report_text === 'string') {
content = result.report_text;
} else if (result.insights_summary && typeof result.insights_summary === 'string') {
content = result.insights_summary;
} else if (result.raw_response && result.raw_response.analysis && typeof result.raw_response.analysis === 'string') {
content = result.raw_response.analysis;
} else {
content = 'Data analysis completed successfully!';
}
// Parse markdown content to HTML
const formattedContent = parseMarkdownToHTML(content);
// Update content
contentElement.innerHTML = formattedContent;
// Show results
resultsContainer.style.display = 'block';
resultsContainer.scrollIntoView({ behavior: 'smooth' });
// Show success message
const successMessage = result.success ? '✅ Data analysis completed and payment processed!' : '✅ Data analysis completed!';
AgentUtils.showToast(successMessage, 'success');
}
// Enhanced markdown parser for Data Analyzer results
function parseMarkdownToHTML(markdown) {
if (!markdown || typeof markdown !== 'string') {
return '<p>No content available.</p>';
}
let html = markdown;
// Convert headers (### Header, ## Header, # Header)
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 18px; font-weight: 600; color: var(--text-primary); margin: 20px 0 12px 0; border-bottom: 2px solid var(--success-green); padding-bottom: 8px;">$1</h3>');
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 20px; font-weight: 600; color: var(--text-primary); margin: 24px 0 16px 0; border-bottom: 2px solid var(--success-green); padding-bottom: 8px;">$1</h2>');
html = html.replace(/^# (.*$)/gm, '<h1 style="font-size: 22px; font-weight: 600; color: var(--text-primary); margin: 28px 0 18px 0; border-bottom: 2px solid var(--success-green); padding-bottom: 10px;">$1</h1>');
// Convert bold text (**text** or __text__)
html = html.replace(/\*\*(.*?)\*\*/g, '<strong style="font-weight: 600; color: var(--text-primary);">$1</strong>');
html = html.replace(/__(.*?)__/g, '<strong style="font-weight: 600; color: var(--text-primary);">$1</strong>');
// Convert italic text (*text* or _text_)
html = html.replace(/\*(.*?)\*/g, '<em style="font-style: italic; color: var(--text-secondary);">$1</em>');
html = html.replace(/_(.*?)_/g, '<em style="font-style: italic; color: var(--text-secondary);">$1</em>');
// Convert bullet points (- item or * item)
html = html.replace(/^[\s]*[-\*]\s+(.*)$/gm, '<li style="margin: 8px 0; padding-left: 8px; color: var(--text-primary);">$1</li>');
// Wrap consecutive list items in ul tags
html = html.replace(/(<li[^>]*>.*?<\/li>\s*)+/gs, function(match) {
return `<ul style="margin: 16px 0; padding-left: 20px; list-style-type: disc; color: var(--success-green);">${match}</ul>`;
});
// Convert numbered lists (1. item, 2. item)
html = html.replace(/^\s*\d+\.\s+(.*)$/gm, '<li style="margin: 8px 0; padding-left: 8px; color: var(--text-primary);">$1</li>');
// Wrap consecutive numbered list items in ol tags
html = html.replace(/(<li[^>]*>.*?<\/li>\s*)+/gs, function(match) {
if (match.includes('ul style')) return match; // Skip if already wrapped in ul
return `<ol style="margin: 16px 0; padding-left: 20px; list-style-type: decimal; color: var(--success-green);">${match}</ol>`;
});
// Convert line breaks to paragraphs
const paragraphs = html.split(/\n\s*\n/);
html = paragraphs.map(p => {
const trimmed = p.trim();
if (trimmed === '') return '';
// Skip if already wrapped in HTML tags
if (trimmed.startsWith('<h') || trimmed.startsWith('<ul') || trimmed.startsWith('<ol') || trimmed.startsWith('<li')) {
return trimmed;
}
return `<p style="margin: 12px 0; line-height: 1.6; color: var(--text-primary);">${trimmed}</p>`;
}).filter(p => p !== '').join('');
return html;
}
// Track polling and results to prevent duplicates

View File

@ -5,18 +5,75 @@
window.AgentUtils = {
/**
* Simple Text Formatter
* Cleans AI-generated text and converts to readable HTML
* Enhanced Markdown Parser
* Converts markdown syntax to styled HTML with proper formatting
*/
parseMarkdown(text) {
if (!text) return '';
// Handle null, undefined, or non-string inputs
if (!text || typeof text !== 'string') {
return '';
}
return text
.replace(/\*\*/g, '') // Remove markdown bold syntax
.replace(/\#{1,3}\s/g, '') // Remove header syntax
.replace(/\n{3,}/g, '\n\n') // Reduce excessive line breaks
.replace(/\n/g, '<br>') // Convert line breaks to HTML
.trim();
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();
},
/**