Compare commits
No commits in common. "5545c5343ab2177f92dc47053451646b01bc79cd" and "c946d3c8713bfd04a361ae42d3127090d4695b07" have entirely different histories.
5545c5343a
...
c946d3c871
@ -646,33 +646,6 @@ class KSTCoordiComparator:
|
|||||||
|
|
||||||
return visualize_rows
|
return visualize_rows
|
||||||
|
|
||||||
def generate_excel_export_data(self) -> Dict[str, List[Dict[str, Any]]]:
|
|
||||||
"""Generate data for Excel export with all sheets in visualize format"""
|
|
||||||
export_data = {}
|
|
||||||
|
|
||||||
# Get all sheet names
|
|
||||||
sheet_names = list(self.data.keys()) if self.data else []
|
|
||||||
|
|
||||||
for sheet_name in sheet_names:
|
|
||||||
# Generate visualize data for each sheet
|
|
||||||
sheet_visualize_data = self.generate_visualize_data(sheet_name)
|
|
||||||
|
|
||||||
# Convert to Excel-friendly format
|
|
||||||
excel_rows = []
|
|
||||||
for row in sheet_visualize_data:
|
|
||||||
excel_rows.append({
|
|
||||||
'Coordi Title': row.get('coordi_title', ''),
|
|
||||||
'Coordi Chapter': row.get('coordi_chapter', ''),
|
|
||||||
'KST Title': row.get('kst_title', ''),
|
|
||||||
'KST Chapter': row.get('kst_chapter', ''),
|
|
||||||
'Status': row.get('reason', ''),
|
|
||||||
'Type': row.get('row_type', '').replace('_', ' ').title()
|
|
||||||
})
|
|
||||||
|
|
||||||
export_data[sheet_name] = excel_rows
|
|
||||||
|
|
||||||
return export_data
|
|
||||||
|
|
||||||
|
|
||||||
def print_comparison_summary(self, sheet_filter: str | None = None):
|
def print_comparison_summary(self, sheet_filter: str | None = None):
|
||||||
"""Print a formatted summary of the comparison for a specific sheet"""
|
"""Print a formatted summary of the comparison for a specific sheet"""
|
||||||
|
|||||||
@ -284,10 +284,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="visualize" class="tab-content">
|
<div id="visualize" class="tab-content">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
<h3>Data </h3>
|
||||||
<h3>Excel-like Visualization</h3>
|
|
||||||
<button onclick="downloadExcel()" id="downloadBtn" style="background: #28a745; padding: 8px 16px;">📥 Download All Sheets</button>
|
|
||||||
</div>
|
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table id="visualize-table">
|
<table id="visualize-table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -673,60 +670,6 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadExcel() {
|
|
||||||
const downloadBtn = document.getElementById('downloadBtn');
|
|
||||||
const originalText = downloadBtn.textContent;
|
|
||||||
|
|
||||||
// Show loading state
|
|
||||||
downloadBtn.disabled = true;
|
|
||||||
downloadBtn.textContent = '⏳ Generating...';
|
|
||||||
downloadBtn.style.background = '#6c757d';
|
|
||||||
|
|
||||||
// Create a temporary link and trigger download
|
|
||||||
fetch('/download_excel', {
|
|
||||||
method: 'GET'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Download failed');
|
|
||||||
}
|
|
||||||
return response.blob();
|
|
||||||
})
|
|
||||||
.then(blob => {
|
|
||||||
// Create download link
|
|
||||||
const url = window.URL.createObjectURL(blob);
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.style.display = 'none';
|
|
||||||
a.href = url;
|
|
||||||
a.download = 'data_comparison_export.xlsx';
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
document.body.removeChild(a);
|
|
||||||
|
|
||||||
// Show success message
|
|
||||||
const statusDiv = document.getElementById('status');
|
|
||||||
statusDiv.innerHTML = '<div class="success">Excel file downloaded successfully!</div>';
|
|
||||||
setTimeout(() => {
|
|
||||||
statusDiv.innerHTML = '';
|
|
||||||
}, 3000);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Download error:', error);
|
|
||||||
const statusDiv = document.getElementById('status');
|
|
||||||
statusDiv.innerHTML = '<div class="error">Download failed. Please try again.</div>';
|
|
||||||
setTimeout(() => {
|
|
||||||
statusDiv.innerHTML = '';
|
|
||||||
}, 5000);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
// Reset button state
|
|
||||||
downloadBtn.disabled = false;
|
|
||||||
downloadBtn.textContent = originalText;
|
|
||||||
downloadBtn.style.background = '#28a745';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-analyze on page load with default file
|
// Auto-analyze on page load with default file
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
// Initialize sheet filter with loading state
|
// Initialize sheet filter with loading state
|
||||||
|
|||||||
155
web_gui.py
155
web_gui.py
@ -1,8 +1,7 @@
|
|||||||
from flask import Flask, render_template, request, jsonify, send_file
|
from flask import Flask, render_template, request, jsonify
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
import tempfile
|
import tempfile
|
||||||
import pandas as pd
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from werkzeug.utils import secure_filename
|
from werkzeug.utils import secure_filename
|
||||||
from data_comparator import KSTCoordiComparator
|
from data_comparator import KSTCoordiComparator
|
||||||
@ -132,99 +131,6 @@ def get_sheets():
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
return jsonify({'error': str(e)}), 500
|
return jsonify({'error': str(e)}), 500
|
||||||
|
|
||||||
@app.route('/download_excel')
|
|
||||||
def download_excel():
|
|
||||||
"""Generate and download Excel file with all sheets in visualize format"""
|
|
||||||
global comparator_instance
|
|
||||||
|
|
||||||
try:
|
|
||||||
if not comparator_instance:
|
|
||||||
return jsonify({'error': 'No data available. Please analyze data first.'}), 400
|
|
||||||
|
|
||||||
# Generate export data for all sheets
|
|
||||||
export_data = comparator_instance.generate_excel_export_data()
|
|
||||||
|
|
||||||
if not export_data:
|
|
||||||
return jsonify({'error': 'No data available for export'}), 400
|
|
||||||
|
|
||||||
# Create temporary Excel file
|
|
||||||
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.xlsx')
|
|
||||||
temp_path = temp_file.name
|
|
||||||
temp_file.close()
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Create Excel writer with multiple sheets
|
|
||||||
with pd.ExcelWriter(temp_path, engine='openpyxl') as writer:
|
|
||||||
for sheet_name, sheet_data in export_data.items():
|
|
||||||
if sheet_data: # Only create sheet if there's data
|
|
||||||
df = pd.DataFrame(sheet_data)
|
|
||||||
|
|
||||||
# Clean sheet name for Excel (remove invalid characters)
|
|
||||||
clean_sheet_name = str(sheet_name).replace('/', '_').replace('\\', '_')[:31]
|
|
||||||
|
|
||||||
df.to_excel(writer, sheet_name=clean_sheet_name, index=False)
|
|
||||||
|
|
||||||
# Get the workbook and worksheet to apply formatting
|
|
||||||
workbook = writer.book
|
|
||||||
worksheet = writer.sheets[clean_sheet_name]
|
|
||||||
|
|
||||||
# Apply color formatting based on Type column
|
|
||||||
from openpyxl.styles import PatternFill
|
|
||||||
|
|
||||||
# Define colors matching the web interface
|
|
||||||
colors = {
|
|
||||||
'Coordi Only': PatternFill(start_color='FF4444', end_color='FF4444', fill_type='solid'),
|
|
||||||
'Kst Only': PatternFill(start_color='4488FF', end_color='4488FF', fill_type='solid'),
|
|
||||||
'Mixed Duplicate': PatternFill(start_color='FF8800', end_color='FF8800', fill_type='solid'),
|
|
||||||
'Pure Duplicate': PatternFill(start_color='8844FF', end_color='8844FF', fill_type='solid'),
|
|
||||||
'Matched': PatternFill(start_color='FFFFFF', end_color='FFFFFF', fill_type='solid')
|
|
||||||
}
|
|
||||||
|
|
||||||
# Find the Type column (should be column F, index 5)
|
|
||||||
type_col_idx = None
|
|
||||||
for idx, col in enumerate(df.columns):
|
|
||||||
if col == 'Type':
|
|
||||||
type_col_idx = idx + 1 # Excel is 1-indexed
|
|
||||||
break
|
|
||||||
|
|
||||||
# Apply formatting to data rows (skip header)
|
|
||||||
if type_col_idx:
|
|
||||||
for row_idx, row_data in enumerate(sheet_data, start=2): # Start from row 2 (after header)
|
|
||||||
row_type = row_data.get('Type', '')
|
|
||||||
fill = colors.get(row_type)
|
|
||||||
if fill:
|
|
||||||
for col_idx in range(1, len(df.columns) + 1):
|
|
||||||
cell = worksheet.cell(row=row_idx, column=col_idx)
|
|
||||||
cell.fill = fill
|
|
||||||
|
|
||||||
# Auto-adjust column widths
|
|
||||||
for column in worksheet.columns:
|
|
||||||
max_length = 0
|
|
||||||
column_letter = column[0].column_letter
|
|
||||||
for cell in column:
|
|
||||||
try:
|
|
||||||
if len(str(cell.value)) > max_length:
|
|
||||||
max_length = len(str(cell.value))
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
adjusted_width = min(max_length + 2, 50) # Cap at 50 characters
|
|
||||||
worksheet.column_dimensions[column_letter].width = adjusted_width
|
|
||||||
|
|
||||||
# Send file for download
|
|
||||||
return send_file(
|
|
||||||
temp_path,
|
|
||||||
as_attachment=True,
|
|
||||||
download_name='data_comparison_export.xlsx',
|
|
||||||
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
|
|
||||||
)
|
|
||||||
|
|
||||||
finally:
|
|
||||||
# Clean up temporary file after a delay (Flask handles this)
|
|
||||||
pass
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
return jsonify({'error': f'Export failed: {str(e)}'}), 500
|
|
||||||
|
|
||||||
def create_templates_dir():
|
def create_templates_dir():
|
||||||
"""Create templates directory and HTML file"""
|
"""Create templates directory and HTML file"""
|
||||||
templates_dir = Path('templates')
|
templates_dir = Path('templates')
|
||||||
@ -516,10 +422,7 @@ def create_templates_dir():
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="visualize" class="tab-content">
|
<div id="visualize" class="tab-content">
|
||||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px;">
|
<h3>Data </h3>
|
||||||
<h3>Excel-like Visualization</h3>
|
|
||||||
<button onclick="downloadExcel()" id="downloadBtn" style="background: #28a745; padding: 8px 16px;">📥 Download All Sheets</button>
|
|
||||||
</div>
|
|
||||||
<div class="table-container">
|
<div class="table-container">
|
||||||
<table id="visualize-table">
|
<table id="visualize-table">
|
||||||
<thead>
|
<thead>
|
||||||
@ -905,60 +808,6 @@ def create_templates_dir():
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadExcel() {
|
|
||||||
const downloadBtn = document.getElementById('downloadBtn');
|
|
||||||
const originalText = downloadBtn.textContent;
|
|
||||||
|
|
||||||
// Show loading state
|
|
||||||
downloadBtn.disabled = true;
|
|
||||||
downloadBtn.textContent = '⏳ Generating...';
|
|
||||||
downloadBtn.style.background = '#6c757d';
|
|
||||||
|
|
||||||
// Create a temporary link and trigger download
|
|
||||||
fetch('/download_excel', {
|
|
||||||
method: 'GET'
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Download failed');
|
|
||||||
}
|
|
||||||
return response.blob();
|
|
||||||
})
|
|
||||||
.then(blob => {
|
|
||||||
// Create download link
|
|
||||||
const url = window.URL.createObjectURL(blob);
|
|
||||||
const a = document.createElement('a');
|
|
||||||
a.style.display = 'none';
|
|
||||||
a.href = url;
|
|
||||||
a.download = 'data_comparison_export.xlsx';
|
|
||||||
document.body.appendChild(a);
|
|
||||||
a.click();
|
|
||||||
window.URL.revokeObjectURL(url);
|
|
||||||
document.body.removeChild(a);
|
|
||||||
|
|
||||||
// Show success message
|
|
||||||
const statusDiv = document.getElementById('status');
|
|
||||||
statusDiv.innerHTML = '<div class="success">Excel file downloaded successfully!</div>';
|
|
||||||
setTimeout(() => {
|
|
||||||
statusDiv.innerHTML = '';
|
|
||||||
}, 3000);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Download error:', error);
|
|
||||||
const statusDiv = document.getElementById('status');
|
|
||||||
statusDiv.innerHTML = '<div class="error">Download failed. Please try again.</div>';
|
|
||||||
setTimeout(() => {
|
|
||||||
statusDiv.innerHTML = '';
|
|
||||||
}, 5000);
|
|
||||||
})
|
|
||||||
.finally(() => {
|
|
||||||
// Reset button state
|
|
||||||
downloadBtn.disabled = false;
|
|
||||||
downloadBtn.textContent = originalText;
|
|
||||||
downloadBtn.style.background = '#28a745';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Auto-analyze on page load with default file
|
// Auto-analyze on page load with default file
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
// Initialize sheet filter with loading state
|
// Initialize sheet filter with loading state
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user