From f83c2497cce0a5e96cd5e183ae9e9d84fb3b7196 Mon Sep 17 00:00:00 2001
From: Claude
Date: Sun, 13 Jul 2025 22:56:27 +0530
Subject: [PATCH] Fix data analyzer TypeError and enhance markdown parsing
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
## 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
---
data_analyzer/processor.py | 2 +-
.../templates/data_analyzer/detail.html | 108 ++++++++++++++++--
static/js/agent-utils.js | 75 ++++++++++--
3 files changed, 167 insertions(+), 18 deletions(-)
diff --git a/data_analyzer/processor.py b/data_analyzer/processor.py
index f352a8a..655d24c 100644
--- a/data_analyzer/processor.py
+++ b/data_analyzer/processor.py
@@ -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
diff --git a/data_analyzer/templates/data_analyzer/detail.html b/data_analyzer/templates/data_analyzer/detail.html
index 1625558..6bab689 100644
--- a/data_analyzer/templates/data_analyzer/detail.html
+++ b/data_analyzer/templates/data_analyzer/detail.html
@@ -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 'No content available.
';
+ }
+
+ let html = markdown;
+
+ // Convert headers (### Header, ## Header, # Header)
+ html = html.replace(/^### (.*$)/gm, '$1
');
+ html = html.replace(/^## (.*$)/gm, '$1
');
+ html = html.replace(/^# (.*$)/gm, '$1
');
+
+ // Convert bold text (**text** or __text__)
+ html = html.replace(/\*\*(.*?)\*\*/g, '$1');
+ html = html.replace(/__(.*?)__/g, '$1');
+
+ // Convert italic text (*text* or _text_)
+ html = html.replace(/\*(.*?)\*/g, '$1');
+ html = html.replace(/_(.*?)_/g, '$1');
+
+ // Convert bullet points (- item or * item)
+ html = html.replace(/^[\s]*[-\*]\s+(.*)$/gm, '$1');
+
+ // Wrap consecutive list items in ul tags
+ html = html.replace(/(]*>.*?<\/li>\s*)+/gs, function(match) {
+ return ``;
});
+
+ // Convert numbered lists (1. item, 2. item)
+ html = html.replace(/^\s*\d+\.\s+(.*)$/gm, '$1');
+
+ // Wrap consecutive numbered list items in ol tags
+ html = html.replace(/(]*>.*?<\/li>\s*)+/gs, function(match) {
+ if (match.includes('ul style')) return match; // Skip if already wrapped in ul
+ return `${match}
`;
+ });
+
+ // 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('${trimmed}
`;
+ }).filter(p => p !== '').join('');
+
+ return html;
}
// Track polling and results to prevent duplicates
diff --git a/static/js/agent-utils.js b/static/js/agent-utils.js
index 1814dd3..f532c96 100644
--- a/static/js/agent-utils.js
+++ b/static/js/agent-utils.js
@@ -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, '
') // Convert line breaks to HTML
- .trim();
+ let html = text;
+
+ // Convert headers with proper styling
+ html = html.replace(/^### (.*$)/gm, '$1
');
+ html = html.replace(/^## (.*$)/gm, '$1
');
+ html = html.replace(/^# (.*$)/gm, '$1
');
+
+ // Convert bold text
+ html = html.replace(/\*\*(.*?)\*\*/g, '$1');
+
+ // 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('');
+ inList = true;
+ }
+ processedLines.push(`- ${line.substring(2).trim()}
`);
+ } else {
+ if (inList) {
+ processedLines.push('
');
+ inList = false;
+ }
+ processedLines.push(line);
+ }
+ }
+
+ if (inList) {
+ processedLines.push('');
+ }
+
+ 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('') || trimmed.includes('${trimmed}`;
+ })
+ .join('');
+
+ // Convert remaining single line breaks to
tags
+ html = html.replace(/\n/g, '
');
+
+ return html.trim();
},
/**