mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 16:32:58 +00:00
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:
parent
8189cca054
commit
f83c2497cc
@ -99,7 +99,7 @@ class DataAnalysisAgentProcessor(StandardWebhookProcessor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Use analysis text for multiple fields for compatibility
|
# 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
|
report_text = analysis_text
|
||||||
raw_response = response_data
|
raw_response = response_data
|
||||||
|
|
||||||
|
|||||||
@ -676,16 +676,108 @@
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Display analysis results with markdown parsing
|
// Display analysis results with custom Data Analyzer formatting
|
||||||
function displayResults(result) {
|
function displayResults(result) {
|
||||||
AgentUtils.displayResults({
|
const resultsContainer = document.getElementById('analysisResults');
|
||||||
result: result,
|
const contentElement = document.getElementById('analysisContent');
|
||||||
resultsId: 'analysisResults',
|
|
||||||
contentId: 'analysisContent',
|
if (!resultsContainer || !contentElement) {
|
||||||
defaultMessage: 'Data analysis completed successfully!',
|
console.error('Results elements not found');
|
||||||
successMessage: '✅ Data analysis completed and payment processed!',
|
return;
|
||||||
errorMessage: '❌ Failed to analyze data - no charge applied'
|
}
|
||||||
|
|
||||||
|
// 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
|
// Track polling and results to prevent duplicates
|
||||||
|
|||||||
@ -5,18 +5,75 @@
|
|||||||
|
|
||||||
window.AgentUtils = {
|
window.AgentUtils = {
|
||||||
/**
|
/**
|
||||||
* Simple Text Formatter
|
* Enhanced Markdown Parser
|
||||||
* Cleans AI-generated text and converts to readable HTML
|
* Converts markdown syntax to styled HTML with proper formatting
|
||||||
*/
|
*/
|
||||||
parseMarkdown(text) {
|
parseMarkdown(text) {
|
||||||
if (!text) return '';
|
// Handle null, undefined, or non-string inputs
|
||||||
|
if (!text || typeof text !== 'string') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
return text
|
let html = text;
|
||||||
.replace(/\*\*/g, '') // Remove markdown bold syntax
|
|
||||||
.replace(/\#{1,3}\s/g, '') // Remove header syntax
|
// Convert headers with proper styling
|
||||||
.replace(/\n{3,}/g, '\n\n') // Reduce excessive line breaks
|
html = html.replace(/^### (.*$)/gm, '<h3 style="font-size: 1.1em; font-weight: 600; margin: 12px 0 8px 0; color: #374151;">$1</h3>');
|
||||||
.replace(/\n/g, '<br>') // Convert line breaks to HTML
|
html = html.replace(/^## (.*$)/gm, '<h2 style="font-size: 1.2em; font-weight: 600; margin: 14px 0 8px 0; color: #374151;">$1</h2>');
|
||||||
.trim();
|
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();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user