mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 12:12:58 +00:00
TOAST IMPROVEMENTS: - Standardize success messages: "✅ [Action] completed successfully\!" - Standardize clipboard messages: "📋 Copied to clipboard\!" - Standardize error messages with ❌ emoji prefix - Remove download and reset toast notifications (feedback is file/visual) DYNAMIC PRICING: - Replace hardcoded prices with {{ agent.price }} template variables - Update JavaScript balance checks to use dynamic pricing - Fix button text and error messages to show correct pricing PRESERVED: - All existing displayResults function logic (no changes to result display) - All existing function names and calling patterns - All agent-specific utilities (DataAnalyzerUtils, SocialAdsUtils, etc.) - Result display functionality remains intact 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
929 lines
30 KiB
HTML
929 lines
30 KiB
HTML
{% extends 'base.html' %}
|
||
{% load static %}
|
||
|
||
{% block title %}Data Analyzer - Quantum Tasks AI{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<link rel="stylesheet" href="{% static 'css/agent-base.css' %}?v={{ timestamp }}">
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<script>
|
||
// Consolidated DOMContentLoaded initialization
|
||
document.addEventListener('DOMContentLoaded', function() {
|
||
// Set data for JavaScript access
|
||
document.body.setAttribute('data-user-authenticated', '{{ user.is_authenticated|yesno:"true,false" }}');
|
||
document.body.setAttribute('data-agent-price', '{{ agent.price }}');
|
||
|
||
// Initialize form submission
|
||
const form = document.getElementById('agentForm');
|
||
if (form) {
|
||
form.addEventListener('submit', handleFormSubmission);
|
||
}
|
||
|
||
// Initialize file upload
|
||
const fileInput = document.getElementById('dataFile');
|
||
if (fileInput) {
|
||
fileInput.addEventListener('change', handleFileChange);
|
||
}
|
||
|
||
// Initialize drag and drop
|
||
const uploadArea = document.querySelector('.file-upload-area');
|
||
if (uploadArea) {
|
||
setupDragAndDrop(uploadArea, fileInput);
|
||
}
|
||
|
||
// Set initial radio selection
|
||
const firstRadio = document.querySelector('.radio-card');
|
||
if (firstRadio && !document.querySelector('.radio-card.selected')) {
|
||
firstRadio.classList.add('selected');
|
||
const input = firstRadio.querySelector('input[type="radio"]');
|
||
if (input) input.checked = true;
|
||
}
|
||
});
|
||
|
||
// Data Analyzer Utils
|
||
const DataAnalyzerUtils = {
|
||
// Update wallet balance display
|
||
updateWalletBalance(newBalance) {
|
||
if (newBalance !== undefined) {
|
||
// Update header balance
|
||
const headerBalance = document.querySelector('a[data-wallet-balance]');
|
||
if (headerBalance) {
|
||
headerBalance.textContent = `💰 ${newBalance.toFixed(2)} AED`;
|
||
}
|
||
|
||
// Update page balance
|
||
const pageBalance = document.getElementById('walletBalance');
|
||
if (pageBalance) {
|
||
pageBalance.textContent = newBalance.toFixed(2);
|
||
}
|
||
|
||
// Update all data attributes
|
||
document.querySelectorAll('[data-wallet-balance]').forEach(element => {
|
||
element.textContent = `${newBalance.toFixed(2)} AED`;
|
||
});
|
||
|
||
// Store current balance globally
|
||
window.currentWalletBalance = newBalance;
|
||
}
|
||
},
|
||
|
||
// Show toast notification
|
||
showToast(message, type = 'info') {
|
||
// Remove existing toasts
|
||
document.querySelectorAll('.toast').forEach(toast => toast.remove());
|
||
|
||
// Create new toast
|
||
const toast = document.createElement('div');
|
||
toast.className = `toast ${type}`;
|
||
toast.textContent = message;
|
||
|
||
// Add to page
|
||
document.body.appendChild(toast);
|
||
|
||
// Show toast
|
||
setTimeout(() => toast.classList.add('show'), 100);
|
||
|
||
// Auto remove after 3 seconds
|
||
setTimeout(() => {
|
||
toast.classList.remove('show');
|
||
setTimeout(() => toast.remove(), 300);
|
||
}, 3000);
|
||
},
|
||
|
||
// Display processing status
|
||
showProcessing() {
|
||
const processingStatus = document.getElementById('processingStatus');
|
||
const resultsContainer = document.getElementById('resultsContainer');
|
||
|
||
if (processingStatus) processingStatus.style.display = 'block';
|
||
if (resultsContainer) resultsContainer.style.display = 'none';
|
||
|
||
this.showToast('🔄 Processing your data file...', 'success');
|
||
},
|
||
|
||
// Hide processing status
|
||
hideProcessing() {
|
||
const processingStatus = document.getElementById('processingStatus');
|
||
if (processingStatus) processingStatus.style.display = 'none';
|
||
},
|
||
|
||
// Display analysis results
|
||
displayResults(result) {
|
||
const resultsContainer = document.getElementById('resultsContainer');
|
||
const resultsContent = document.getElementById('resultsContent');
|
||
const processingStatus = document.getElementById('processingStatus');
|
||
|
||
if (result.success) {
|
||
// Hide processing status
|
||
this.hideProcessing();
|
||
|
||
// Show results with rich formatting
|
||
const analysisText = result.report_text || result.insights_summary || result.analysis_results || 'Analysis completed successfully.';
|
||
if (resultsContent) {
|
||
// Convert newlines to HTML and preserve formatting
|
||
const formattedText = analysisText
|
||
.replace(/\n\n/g, '</p><p>')
|
||
.replace(/\n/g, '<br>')
|
||
.replace(/### (.*?)(<br>|$)/g, '<h3>$1</h3>')
|
||
.replace(/## (.*?)(<br>|$)/g, '<h2>$1</h2>')
|
||
.replace(/# (.*?)(<br>|$)/g, '<h1>$1</h1>')
|
||
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
||
.replace(/\*(.*?)\*/g, '<em>$1</em>');
|
||
|
||
resultsContent.innerHTML = `<p>${formattedText}</p>`;
|
||
}
|
||
|
||
// Show results container
|
||
if (resultsContainer) {
|
||
resultsContainer.style.display = 'block';
|
||
}
|
||
|
||
// Update wallet balance if provided
|
||
if (result.wallet_balance !== undefined) {
|
||
this.updateWalletBalance(result.wallet_balance);
|
||
}
|
||
|
||
this.showToast('✅ Data analysis completed successfully!', 'success');
|
||
} else if (result.error) {
|
||
this.hideProcessing();
|
||
this.showToast(`❌ Error: ${result.error}`, 'error');
|
||
} else {
|
||
this.hideProcessing();
|
||
this.showToast('❌ Analysis failed. Please try again.', 'error');
|
||
}
|
||
}
|
||
};
|
||
|
||
// For backward compatibility
|
||
const AgentUtils = DataAnalyzerUtils;
|
||
|
||
// Modern Radio Selection
|
||
function selectRadio(value) {
|
||
// Remove selected class from all cards
|
||
document.querySelectorAll('.radio-card').forEach(card => {
|
||
card.classList.remove('selected');
|
||
});
|
||
|
||
// Add selected class to clicked card
|
||
const selectedCard = document.querySelector(`input[value="${value}"]`).closest('.radio-card');
|
||
if (selectedCard) {
|
||
selectedCard.classList.add('selected');
|
||
}
|
||
|
||
// Select the radio button
|
||
const radioInput = document.getElementById(value);
|
||
if (radioInput) {
|
||
radioInput.checked = true;
|
||
}
|
||
}
|
||
|
||
// File upload handling
|
||
function handleFileChange(event) {
|
||
const file = event.target.files[0];
|
||
const uploadArea = document.querySelector('.file-upload-area');
|
||
const uploadText = document.querySelector('.upload-text');
|
||
|
||
if (file) {
|
||
uploadArea.classList.add('file-selected');
|
||
uploadText.innerHTML = `
|
||
<div style="display: flex; align-items: center; gap: 8px;">
|
||
<span>📄</span>
|
||
<div>
|
||
<div style="font-weight: 500;">${file.name}</div>
|
||
<div style="font-size: 12px; color: var(--on-surface-variant);">${(file.size / 1024 / 1024).toFixed(2)} MB</div>
|
||
</div>
|
||
</div>
|
||
`;
|
||
DataAnalyzerUtils.showToast(`File selected: ${file.name}`, 'success');
|
||
} else {
|
||
uploadArea.classList.remove('file-selected');
|
||
uploadText.innerHTML = `
|
||
<div class="upload-icon">📁</div>
|
||
<div><strong>Click to upload</strong> or drag and drop</div>
|
||
<div>PDF files only</div>
|
||
`;
|
||
}
|
||
}
|
||
|
||
// Drag and drop setup
|
||
function setupDragAndDrop(uploadArea, fileInput) {
|
||
let dragCounter = 0;
|
||
|
||
function handleDragOver(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
uploadArea.classList.add('drag-over');
|
||
}
|
||
|
||
function handleDragLeave(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
dragCounter--;
|
||
if (dragCounter <= 0) {
|
||
uploadArea.classList.remove('drag-over');
|
||
dragCounter = 0;
|
||
}
|
||
}
|
||
|
||
function handleDragEnter(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
dragCounter++;
|
||
uploadArea.classList.add('drag-over');
|
||
}
|
||
|
||
function handleDrop(e) {
|
||
e.preventDefault();
|
||
e.stopPropagation();
|
||
dragCounter = 0;
|
||
uploadArea.classList.remove('drag-over');
|
||
|
||
const files = e.dataTransfer.files;
|
||
if (files.length > 0) {
|
||
fileInput.files = files;
|
||
handleFileChange({ target: fileInput });
|
||
}
|
||
}
|
||
|
||
uploadArea.addEventListener('dragenter', handleDragEnter);
|
||
uploadArea.addEventListener('dragover', handleDragOver);
|
||
uploadArea.addEventListener('dragleave', handleDragLeave);
|
||
uploadArea.addEventListener('drop', handleDrop);
|
||
}
|
||
|
||
// Form validation
|
||
function isFormValid() {
|
||
const fileInput = document.getElementById('dataFile');
|
||
const analysisType = document.querySelector('input[name="analysisType"]:checked');
|
||
|
||
if (!fileInput.files || fileInput.files.length === 0) {
|
||
DataAnalyzerUtils.showToast('Please select a data file', 'error');
|
||
return false;
|
||
}
|
||
|
||
if (!analysisType) {
|
||
DataAnalyzerUtils.showToast('Please select an analysis type', 'error');
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
// Copy analysis results
|
||
function copyResults() {
|
||
const content = document.getElementById('resultsContent');
|
||
if (content) {
|
||
const text = content.textContent || '';
|
||
navigator.clipboard.writeText(text).then(() => {
|
||
DataAnalyzerUtils.showToast('📋 Copied to clipboard!', 'success');
|
||
}).catch(() => {
|
||
DataAnalyzerUtils.showToast('❌ Failed to copy to clipboard', 'error');
|
||
});
|
||
}
|
||
}
|
||
|
||
// Download analysis results
|
||
function downloadResults() {
|
||
const content = document.getElementById('resultsContent');
|
||
if (content) {
|
||
const text = content.textContent || '';
|
||
const blob = new Blob([text], { type: 'text/plain' });
|
||
const url = URL.createObjectURL(blob);
|
||
const a = document.createElement('a');
|
||
a.href = url;
|
||
a.download = 'data-analysis-results.txt';
|
||
a.click();
|
||
URL.revokeObjectURL(url);
|
||
// No toast for download - file download is confirmation enough
|
||
}
|
||
}
|
||
|
||
// Reset form for new analysis
|
||
function resetForm() {
|
||
const form = document.getElementById('agentForm');
|
||
if (form) {
|
||
form.reset();
|
||
}
|
||
|
||
const resultsContainer = document.getElementById('resultsContainer');
|
||
const processingStatus = document.getElementById('processingStatus');
|
||
|
||
if (resultsContainer) resultsContainer.style.display = 'none';
|
||
if (processingStatus) processingStatus.style.display = 'none';
|
||
|
||
// Reset file upload area
|
||
const uploadArea = document.querySelector('.file-upload-area');
|
||
const uploadText = document.querySelector('.upload-text');
|
||
if (uploadArea) uploadArea.classList.remove('file-selected');
|
||
if (uploadText) {
|
||
uploadText.innerHTML = `
|
||
<div class="upload-icon">📁</div>
|
||
<div><strong>Click to upload</strong> or drag and drop</div>
|
||
<div>PDF files only</div>
|
||
`;
|
||
}
|
||
|
||
// Reset radio selection
|
||
document.querySelectorAll('.radio-card').forEach(card => {
|
||
card.classList.remove('selected');
|
||
});
|
||
const firstCard = document.querySelector('.radio-card');
|
||
if (firstCard) {
|
||
firstCard.classList.add('selected');
|
||
const input = firstCard.querySelector('input[type="radio"]');
|
||
if (input) input.checked = true;
|
||
}
|
||
|
||
// No toast for reset - visual feedback is enough
|
||
}
|
||
|
||
// Quick Agent Access Functions
|
||
function toggleQuickAgents() {
|
||
const panel = document.getElementById('quickAgentsPanel');
|
||
const overlay = document.getElementById('quickAgentsOverlay');
|
||
const toggle = document.querySelector('.quick-agent-toggle');
|
||
|
||
if (!panel || !overlay) return;
|
||
|
||
const isActive = panel.classList.contains('active');
|
||
|
||
if (isActive) {
|
||
// Close panel
|
||
panel.classList.remove('active');
|
||
overlay.classList.remove('active');
|
||
if (toggle) toggle.classList.remove('active');
|
||
// Update ARIA attributes
|
||
if (toggle) toggle.setAttribute('aria-expanded', 'false');
|
||
panel.setAttribute('aria-hidden', 'true');
|
||
overlay.setAttribute('aria-hidden', 'true');
|
||
} else {
|
||
// Open panel
|
||
panel.classList.add('active');
|
||
overlay.classList.add('active');
|
||
if (toggle) toggle.classList.add('active');
|
||
// Update ARIA attributes
|
||
if (toggle) toggle.setAttribute('aria-expanded', 'true');
|
||
panel.setAttribute('aria-hidden', 'false');
|
||
overlay.setAttribute('aria-hidden', 'false');
|
||
}
|
||
}
|
||
|
||
function closeQuickAgents() {
|
||
const panel = document.getElementById('quickAgentsPanel');
|
||
const overlay = document.getElementById('quickAgentsOverlay');
|
||
const toggle = document.querySelector('.quick-agent-toggle');
|
||
|
||
if (panel) panel.classList.remove('active');
|
||
if (overlay) overlay.classList.remove('active');
|
||
if (toggle) toggle.classList.remove('active');
|
||
|
||
// Update ARIA attributes
|
||
if (toggle) toggle.setAttribute('aria-expanded', 'false');
|
||
if (panel) panel.setAttribute('aria-hidden', 'true');
|
||
if (overlay) overlay.setAttribute('aria-hidden', 'true');
|
||
}
|
||
|
||
// Form submission handler
|
||
function handleFormSubmission(e) {
|
||
e.preventDefault();
|
||
|
||
if (!isFormValid()) {
|
||
return;
|
||
}
|
||
|
||
// Check authentication and balance
|
||
const isAuthenticated = document.body.getAttribute('data-user-authenticated') === 'true';
|
||
if (!isAuthenticated) {
|
||
DataAnalyzerUtils.showToast('Please login to continue', 'error');
|
||
window.location.href = "{% url 'authentication:login' %}";
|
||
return;
|
||
}
|
||
|
||
const walletBalance = parseFloat(document.getElementById('walletBalance')?.textContent) || 0;
|
||
if (walletBalance < {{ agent.price }}) {
|
||
DataAnalyzerUtils.showToast('Insufficient wallet balance', 'error');
|
||
setTimeout(() => {
|
||
window.location.href = "{% url 'wallet:wallet' %}";
|
||
}, 2000);
|
||
return;
|
||
}
|
||
|
||
// Show processing status
|
||
DataAnalyzerUtils.showProcessing();
|
||
|
||
// Submit form with AJAX
|
||
const formData = new FormData(e.target);
|
||
|
||
fetch(window.location.href, {
|
||
method: 'POST',
|
||
body: formData,
|
||
headers: {
|
||
'X-Requested-With': 'XMLHttpRequest'
|
||
}
|
||
})
|
||
.then(response => response.json())
|
||
.then(result => {
|
||
if (result.success && result.request_id) {
|
||
// Start polling for results
|
||
checkResults(result.request_id);
|
||
DataAnalyzerUtils.updateWalletBalance(result.wallet_balance);
|
||
} else {
|
||
DataAnalyzerUtils.hideProcessing();
|
||
DataAnalyzerUtils.showToast(`❌ ${result.error || 'Processing failed'}`, 'error');
|
||
}
|
||
})
|
||
.catch(error => {
|
||
console.error('Form submission error:', error);
|
||
DataAnalyzerUtils.hideProcessing();
|
||
DataAnalyzerUtils.showToast('❌ Connection error. Please try again.', 'error');
|
||
});
|
||
}
|
||
|
||
// Check results (polling for webhook completion)
|
||
function checkResults(requestId) {
|
||
let pollCount = 0;
|
||
const maxPolls = 30; // 5 minutes max
|
||
|
||
const pollInterval = setInterval(() => {
|
||
pollCount++;
|
||
|
||
fetch(`/agents/data-analyzer/status/${requestId}/`)
|
||
.then(response => response.json())
|
||
.then(result => {
|
||
if (result.status === 'completed') {
|
||
clearInterval(pollInterval);
|
||
DataAnalyzerUtils.displayResults(result);
|
||
} else if (result.status === 'failed') {
|
||
clearInterval(pollInterval);
|
||
DataAnalyzerUtils.hideProcessing();
|
||
DataAnalyzerUtils.showToast('❌ Analysis failed. Please try again.', 'error');
|
||
} else if (pollCount >= maxPolls) {
|
||
clearInterval(pollInterval);
|
||
DataAnalyzerUtils.hideProcessing();
|
||
DataAnalyzerUtils.showToast('⏰ Analysis is taking longer than expected. Please check back later.', 'error');
|
||
}
|
||
// Continue polling if still processing
|
||
})
|
||
.catch(error => {
|
||
console.error('Status check error:', error);
|
||
if (pollCount >= maxPolls) {
|
||
clearInterval(pollInterval);
|
||
DataAnalyzerUtils.hideProcessing();
|
||
DataAnalyzerUtils.showToast('❌ Connection error during processing.', 'error');
|
||
}
|
||
});
|
||
}, 10000); // Check every 10 seconds
|
||
}
|
||
|
||
// Close panel with Escape key
|
||
document.addEventListener('keydown', function(e) {
|
||
if (e.key === 'Escape') {
|
||
closeQuickAgents();
|
||
}
|
||
});
|
||
</script>
|
||
|
||
<div class="agent-container">
|
||
<!-- Agent Header -->
|
||
{% include "components/agent_header.html" with agent_title="Data Analyzer" agent_subtitle="AI-powered analysis of your data files with comprehensive insights" %}
|
||
|
||
<!-- Quick Agent Access Panel -->
|
||
{% include "components/quick_agents_panel.html" %}
|
||
|
||
<!-- Agent Grid -->
|
||
<div class="agent-grid">
|
||
<!-- Data Analysis Form Widget -->
|
||
<div class="agent-widget widget-large" style="flex: 1; margin-right: clamp(0px, var(--spacing-lg), 2vw);">
|
||
<div class="widget-header">
|
||
<h3 class="widget-title">
|
||
<span class="widget-icon">📊</span>
|
||
Data Analysis Configuration
|
||
</h3>
|
||
</div>
|
||
<div class="widget-content">
|
||
<form id="agentForm" method="POST" enctype="multipart/form-data">
|
||
{% csrf_token %}
|
||
|
||
<!-- File Upload -->
|
||
<div class="form-group">
|
||
<label class="form-label">📁 Upload Data File</label>
|
||
<div class="file-upload-area" onclick="document.getElementById('dataFile').click()"
|
||
role="button" tabindex="0" aria-label="Click to upload data file or drag and drop"
|
||
onkeydown="if(event.key==='Enter'||event.key===' '){document.getElementById('dataFile').click()}">
|
||
<div class="upload-text">
|
||
<div class="upload-icon">📁</div>
|
||
<div><strong>Click to upload</strong> or drag and drop</div>
|
||
<div>PDF files only</div>
|
||
</div>
|
||
</div>
|
||
<input type="file" id="dataFile" name="file" accept=".pdf" style="display: none;" required>
|
||
<div class="form-help">Supported format: PDF files only. Max size: 10MB</div>
|
||
</div>
|
||
|
||
<!-- Analysis Type Selection -->
|
||
<div class="form-group">
|
||
<label class="form-label">📈 Analysis Type</label>
|
||
<div class="radio-grid">
|
||
<div class="radio-card selected" onclick="selectRadio('summary')">
|
||
<input type="radio" id="summary" name="analysisType" value="summary" checked>
|
||
<div class="radio-button"></div>
|
||
<label for="summary" class="radio-label">📋 Summary</label>
|
||
</div>
|
||
<div class="radio-card" onclick="selectRadio('detailed')">
|
||
<input type="radio" id="detailed" name="analysisType" value="detailed">
|
||
<div class="radio-button"></div>
|
||
<label for="detailed" class="radio-label">📈 Detailed</label>
|
||
</div>
|
||
<div class="radio-card" onclick="selectRadio('statistical')">
|
||
<input type="radio" id="statistical" name="analysisType" value="statistical">
|
||
<div class="radio-button"></div>
|
||
<label for="statistical" class="radio-label">🔢 Statistical</label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Submit Button -->
|
||
<div style="margin-top: var(--spacing-lg);">
|
||
{% if user.is_authenticated %}
|
||
{% if user.wallet_balance >= agent.price %}
|
||
<button type="submit" class="btn btn-primary btn-full" id="analyzeBtn">
|
||
🚀 Analyze Data ({{ agent.price }} AED)
|
||
</button>
|
||
{% else %}
|
||
<div style="background: #fef2f2; color: #dc2626; padding: var(--spacing-md); border-radius: var(--radius-md); margin-bottom: var(--spacing-md); font-size: 14px; font-weight: 500; text-align: center;">
|
||
Insufficient balance! You need {{ agent.price }} AED.
|
||
</div>
|
||
<a href="{% url 'wallet:wallet' %}" class="btn btn-primary btn-full" style="text-decoration: none;">
|
||
💰 Top Up Wallet
|
||
</a>
|
||
{% endif %}
|
||
{% else %}
|
||
<a href="{% url 'authentication:login' %}" class="btn btn-primary btn-full">
|
||
🔐 Login to Continue
|
||
</a>
|
||
{% endif %}
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- How It Works Widget - Positioned on the right -->
|
||
<div class="agent-widget widget-small" style="min-width: min(280px, 100%); max-width: min(280px, 100%); margin-left: auto;">
|
||
<div class="widget-header">
|
||
<h3 class="widget-title">
|
||
<span class="widget-icon">ℹ️</span>
|
||
How It Works
|
||
</h3>
|
||
</div>
|
||
<div class="widget-content">
|
||
<ol class="info-list">
|
||
<li>Upload your PDF file</li>
|
||
<li>Choose analysis type and preferences</li>
|
||
<li>Our AI analyzes your data</li>
|
||
<li>Get comprehensive insights and reports</li>
|
||
</ol>
|
||
|
||
<!-- Other Agents Button -->
|
||
<button class="quick-agent-toggle btn btn-secondary btn-full" onclick="toggleQuickAgents()"
|
||
title="Quick access to other agents"
|
||
aria-label="Open quick access panel for other AI agents"
|
||
aria-expanded="false"
|
||
aria-controls="quickAgentsPanel"
|
||
style="margin-top: var(--spacing-md);">
|
||
<span class="toggle-icon" aria-hidden="true">🚀</span>
|
||
<span class="toggle-text">Explore Other Agents</span>
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Main Content Grid -->
|
||
<div class="agent-grid">
|
||
<!-- Processing Status -->
|
||
{% include "components/processing_status.html" with status_title="Analyzing Your Data..." status_text="Please wait while our AI processes your file..." %}
|
||
|
||
<!-- Results Widget -->
|
||
{% include "components/results_container.html" with results_title="Analysis Results" %}
|
||
</div>
|
||
</div>
|
||
|
||
<style>
|
||
/* Data Analyzer Specific Styles */
|
||
.file-upload-area {
|
||
border: 2px dashed var(--outline);
|
||
border-radius: var(--radius-md);
|
||
padding: var(--spacing-xl);
|
||
text-align: center;
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
background: var(--surface-variant);
|
||
margin-bottom: var(--spacing-sm);
|
||
}
|
||
|
||
.file-upload-area:hover {
|
||
border-color: var(--primary);
|
||
background: var(--surface);
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.file-upload-area.drag-over {
|
||
border-color: var(--primary);
|
||
background: rgba(0, 0, 0, 0.02);
|
||
transform: scale(1.02);
|
||
}
|
||
|
||
.file-upload-area.file-selected {
|
||
border-color: var(--success);
|
||
background: #f0fdf4;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.upload-icon {
|
||
font-size: 48px;
|
||
margin-bottom: var(--spacing-md);
|
||
opacity: 0.7;
|
||
}
|
||
|
||
.upload-text {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: var(--spacing-sm);
|
||
color: var(--on-surface-variant);
|
||
}
|
||
|
||
.upload-text > div:first-child {
|
||
font-weight: 500;
|
||
color: var(--on-surface);
|
||
}
|
||
|
||
.radio-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
|
||
gap: var(--spacing-md);
|
||
margin-top: var(--spacing-sm);
|
||
}
|
||
|
||
.radio-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--spacing-sm);
|
||
padding: var(--spacing-md);
|
||
border: 2px solid var(--outline-variant);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
transition: all 0.2s ease;
|
||
background: var(--surface);
|
||
position: relative;
|
||
}
|
||
|
||
.radio-card:hover {
|
||
border-color: var(--primary);
|
||
background: var(--surface-variant);
|
||
transform: translateY(-1px);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.radio-card.selected {
|
||
border-color: var(--primary);
|
||
background: rgba(0, 0, 0, 0.02);
|
||
}
|
||
|
||
.radio-card input[type="radio"] {
|
||
position: absolute;
|
||
opacity: 0;
|
||
pointer-events: none;
|
||
}
|
||
|
||
.radio-button {
|
||
width: 20px;
|
||
height: 20px;
|
||
border: 2px solid var(--outline);
|
||
border-radius: 50%;
|
||
position: relative;
|
||
transition: all 0.2s ease;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.radio-card.selected .radio-button {
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
.radio-card.selected .radio-button::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 50%;
|
||
left: 50%;
|
||
width: 8px;
|
||
height: 8px;
|
||
background: var(--primary);
|
||
border-radius: 50%;
|
||
transform: translate(-50%, -50%);
|
||
}
|
||
|
||
.radio-label {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
color: var(--on-surface);
|
||
cursor: pointer;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--spacing-xs);
|
||
}
|
||
|
||
/* Toast Notifications */
|
||
.toast {
|
||
position: fixed;
|
||
top: 20px;
|
||
right: 20px;
|
||
background: var(--surface);
|
||
border: 1px solid var(--outline);
|
||
border-radius: var(--radius-md);
|
||
padding: var(--spacing-md) var(--spacing-lg);
|
||
box-shadow: var(--shadow-lg);
|
||
z-index: 1000;
|
||
max-width: 400px;
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
transform: translateX(100%);
|
||
transition: transform 0.3s ease;
|
||
}
|
||
|
||
.toast.show {
|
||
transform: translateX(0);
|
||
}
|
||
|
||
.toast.success {
|
||
border-color: var(--success);
|
||
background: #f0fdf4;
|
||
color: #16a34a;
|
||
}
|
||
|
||
.toast.error {
|
||
border-color: var(--error);
|
||
background: #fef2f2;
|
||
color: #dc2626;
|
||
}
|
||
|
||
/* Enhanced Results Display - Restored from Original */
|
||
.results-content {
|
||
background: var(--surface-variant);
|
||
border-radius: var(--radius-md);
|
||
padding: var(--spacing-xl);
|
||
margin-bottom: var(--spacing-lg);
|
||
line-height: 1.7;
|
||
color: var(--on-surface);
|
||
font-size: 15px;
|
||
}
|
||
|
||
/* Enhanced Results Typography */
|
||
.results-content h1,
|
||
.results-content h2,
|
||
.results-content h3 {
|
||
color: var(--primary);
|
||
font-weight: 700;
|
||
margin: var(--spacing-xl) 0 var(--spacing-md) 0;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.results-content h1 {
|
||
font-size: 24px;
|
||
border-bottom: 3px solid var(--primary);
|
||
padding-bottom: var(--spacing-sm);
|
||
margin-bottom: var(--spacing-lg);
|
||
}
|
||
|
||
.results-content h2 {
|
||
font-size: 20px;
|
||
margin-top: var(--spacing-xl);
|
||
position: relative;
|
||
padding-left: var(--spacing-md);
|
||
}
|
||
|
||
.results-content h2::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 4px;
|
||
background: var(--primary);
|
||
border-radius: 2px;
|
||
}
|
||
|
||
.results-content h3 {
|
||
font-size: 18px;
|
||
color: var(--on-surface);
|
||
font-weight: 600;
|
||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||
padding: var(--spacing-md) var(--spacing-lg);
|
||
border-radius: var(--radius-sm);
|
||
border-left: 4px solid var(--primary);
|
||
margin: var(--spacing-lg) 0 var(--spacing-md) 0;
|
||
}
|
||
|
||
.results-content p {
|
||
margin: var(--spacing-md) 0;
|
||
text-align: justify;
|
||
}
|
||
|
||
.results-content ul,
|
||
.results-content ol {
|
||
margin: var(--spacing-md) 0;
|
||
padding-left: var(--spacing-xl);
|
||
}
|
||
|
||
.results-content li {
|
||
margin: var(--spacing-sm) 0;
|
||
position: relative;
|
||
}
|
||
|
||
.results-content ul li::marker {
|
||
color: var(--primary);
|
||
font-weight: bold;
|
||
}
|
||
|
||
.results-content ol li::marker {
|
||
color: var(--primary);
|
||
font-weight: bold;
|
||
}
|
||
|
||
/* Modern Info Boxes */
|
||
.results-content .key-points,
|
||
.results-content .insights,
|
||
.results-content .summary {
|
||
background: var(--surface);
|
||
border: 1px solid var(--outline-variant);
|
||
border-radius: var(--radius-md);
|
||
padding: var(--spacing-lg);
|
||
margin: var(--spacing-lg) 0;
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
|
||
.results-content .key-points {
|
||
border-left: 4px solid #3b82f6;
|
||
}
|
||
|
||
.results-content .insights {
|
||
border-left: 4px solid #10b981;
|
||
}
|
||
|
||
.results-content .summary {
|
||
border-left: 4px solid #f59e0b;
|
||
}
|
||
|
||
/* Strong text styling */
|
||
.results-content strong {
|
||
color: var(--primary);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* Code and technical terms */
|
||
.results-content code {
|
||
background: #f1f5f9;
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
font-family: 'SF Mono', Monaco, 'Cascadia Code', monospace;
|
||
font-size: 14px;
|
||
color: #1e293b;
|
||
}
|
||
|
||
@media (max-width: 768px) {
|
||
.radio-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.toast {
|
||
left: 20px;
|
||
right: 20px;
|
||
max-width: none;
|
||
transform: translateY(-100%);
|
||
}
|
||
|
||
.toast.show {
|
||
transform: translateY(0);
|
||
}
|
||
|
||
.results-content {
|
||
padding: var(--spacing-md);
|
||
font-size: 14px;
|
||
}
|
||
|
||
.results-content h1 {
|
||
font-size: 20px;
|
||
}
|
||
|
||
.results-content h2 {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.results-content h3 {
|
||
font-size: 16px;
|
||
padding: var(--spacing-sm) var(--spacing-md);
|
||
}
|
||
}
|
||
</style>
|
||
{% endblock %} |