pranit144's picture
Upload 8 files
d48c8b2 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TranscriptAI | YouTube Analysis Tool</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Poppins:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
:root {
--primary: #4361ee;
--primary-dark: #3a56d4;
--secondary: #3f37c9;
--accent: #f72585;
--accent-light: #ff8fa3;
--success: #4cc9f0;
--warning: #f8961e;
--danger: #f94144;
--light: #f8f9fa;
--dark: #212529;
--gray-100: #f8f9fa;
--gray-200: #e9ecef;
--gray-300: #dee2e6;
--gray-400: #ced4da;
--gray-500: #adb5bd;
--gray-600: #6c757d;
--gray-700: #495057;
--gray-800: #343a40;
--gray-900: #212529;
}
body {
font-family: 'Inter', sans-serif;
background-color: #f7f9fc;
color: var(--gray-800);
line-height: 1.6;
}
h1, h2, h3, h4, h5, h6, .display-1, .display-2, .display-3, .display-4, .display-5, .display-6 {
font-family: 'Poppins', sans-serif;
font-weight: 600;
}
.navbar-brand {
font-family: 'Poppins', sans-serif;
font-weight: 700;
}
.card {
border-radius: 12px;
border: none;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08);
transition: transform 0.2s, box-shadow 0.2s;
}
.card:hover {
transform: translateY(-3px);
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}
.card-header {
background-color: #fff;
border-bottom: 1px solid var(--gray-200);
font-weight: 600;
padding: 1.25rem 1.5rem;
}
.card-body {
padding: 1.5rem;
}
.btn {
border-radius: 8px;
font-weight: 500;
padding: 0.6rem 1.2rem;
transition: all 0.2s;
}
.btn-primary {
background-color: var(--primary);
border-color: var(--primary);
}
.btn-primary:hover {
background-color: var(--primary-dark);
border-color: var(--primary-dark);
}
.btn-outline-primary {
color: var(--primary);
border-color: var(--primary);
}
.btn-outline-primary:hover {
background-color: var(--primary);
border-color: var(--primary);
}
.btn-success {
background-color: var(--success);
border-color: var(--success);
}
.form-control {
border-radius: 8px;
padding: 0.75rem 1rem;
border: 1px solid var(--gray-300);
font-size: 1rem;
}
.form-control:focus {
box-shadow: 0 0 0 0.25rem rgba(67, 97, 238, 0.15);
border-color: var(--primary);
}
.form-label {
font-weight: 500;
margin-bottom: 0.5rem;
color: var(--gray-700);
}
.form-text {
color: var(--gray-600);
}
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(15, 23, 42, 0.8);
backdrop-filter: blur(8px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 1050;
color: white;
display: none;
}
.progress-container {
width: 80%;
max-width: 600px;
margin-top: 20px;
}
.progress {
height: 10px;
border-radius: 10px;
background-color: rgba(255, 255, 255, 0.2);
overflow: hidden;
}
.progress-bar {
background-image: linear-gradient(to right, var(--primary), var(--accent));
height: 100%;
border-radius: 10px;
}
.log-container {
width: 80%;
max-width: 600px;
height: 200px;
overflow-y: auto;
background-color: rgba(15, 23, 42, 0.5);
border-radius: 12px;
padding: 15px;
margin-top: 20px;
font-family: 'Courier New', monospace;
color: #e2e8f0;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.log-container div {
padding: 3px 0;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.log-container div:last-child {
border-bottom: none;
}
.logo {
font-size: 2.5rem;
background: linear-gradient(135deg, #f72585 0%, #4361ee 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
margin-right: 15px;
}
.nav-tabs {
border-bottom: none;
margin-bottom: 20px;
gap: 10px;
}
.nav-tabs .nav-item {
margin-bottom: 0;
}
.nav-tabs .nav-link {
border: none;
border-radius: 8px;
padding: 0.75rem 1.5rem;
color: var(--gray-600);
font-weight: 500;
transition: all 0.2s;
display: flex;
align-items: center;
gap: 8px;
}
.nav-tabs .nav-link:hover {
color: var(--primary);
background-color: rgba(67, 97, 238, 0.05);
}
.nav-tabs .nav-link.active {
color: var(--primary);
background-color: rgba(67, 97, 238, 0.1);
border-bottom: none;
font-weight: 600;
}
.nav-tabs .nav-link.active i {
color: var(--primary);
}
.tab-content {
background-color: #fff;
border-radius: 12px;
box-shadow: 0 2px 15px rgba(0, 0, 0, 0.08);
padding: 0;
border: none;
}
.recent-items {
max-height: 500px;
overflow-y: auto;
}
#preview-container {
max-height: 700px;
overflow-y: auto;
padding: 25px;
border-radius: 12px;
background-color: #fff;
font-family: 'Inter', sans-serif;
line-height: 1.7;
}
#preview-container h1, #preview-container h2 {
font-weight: 700;
color: var(--gray-800);
margin-top: 1.5em;
margin-bottom: 0.75em;
}
#preview-container h1 {
font-size: 2rem;
border-bottom: 2px solid var(--gray-200);
padding-bottom: 0.5rem;
}
#preview-container h2 {
font-size: 1.5rem;
color: var(--primary);
}
#preview-container p {
margin-bottom: 1rem;
}
#preview-container ul, #preview-container ol {
padding-left: 1.5rem;
margin-bottom: 1rem;
}
#preview-container blockquote {
border-left: 4px solid var(--primary);
padding-left: 1rem;
margin-left: 0;
color: var(--gray-700);
font-style: italic;
}
.table th {
background-color: rgba(67, 97, 238, 0.05);
color: var(--gray-700);
font-weight: 600;
}
.table-hover tbody tr:hover {
background-color: rgba(67, 97, 238, 0.05);
}
.badge {
padding: 0.4em 0.8em;
font-weight: 500;
border-radius: 6px;
}
.badge-hindi {
background-color: rgba(247, 37, 133, 0.1);
color: var(--accent);
}
.badge-english {
background-color: rgba(67, 97, 238, 0.1);
color: var(--primary);
}
.btn-action {
padding: 0.4rem 0.75rem;
border-radius: 6px;
font-size: 0.875rem;
display: inline-flex;
align-items: center;
gap: 5px;
}
.btn-icon {
width: 36px;
height: 36px;
padding: 0;
display: inline-flex;
align-items: center;
justify-content: center;
border-radius: 50%;
}
.features-icon {
width: 40px;
height: 40px;
background-color: rgba(67, 97, 238, 0.1);
color: var(--primary);
border-radius: 12px;
display: inline-flex;
align-items: center;
justify-content: center;
margin-right: 15px;
font-size: 1.25rem;
}
.feature-item {
display: flex;
align-items: flex-start;
margin-bottom: 1rem;
}
.feature-content {
flex: 1;
}
.feature-content h5 {
margin-bottom: 0.25rem;
font-weight: 600;
}
.help-card {
height: 100%;
display: flex;
flex-direction: column;
}
.help-card .card-body {
flex: 1;
}
.banner {
background: linear-gradient(135deg, var(--primary) 0%, var(--secondary) 100%);
color: white;
padding: 2rem 0;
border-radius: 16px;
margin-bottom: 2rem;
}
.banner h2 {
font-weight: 700;
margin-bottom: 1rem;
}
.banner p {
opacity: 0.9;
font-weight: 300;
font-size: 1.1rem;
max-width: 600px;
}
@keyframes pulse {
0% {
transform: scale(1);
}
50% {
transform: scale(1.05);
}
100% {
transform: scale(1);
}
}
.pulse-icon {
animation: pulse 1.5s infinite;
}
/* For mobile screens */
@media (max-width: 767.98px) {
.banner {
text-align: center;
padding: 1.5rem;
}
.banner p {
margin-left: auto;
margin-right: auto;
}
.nav-tabs {
overflow-x: auto;
flex-wrap: nowrap;
padding-bottom: 5px;
}
.nav-tabs .nav-link {
white-space: nowrap;
padding: 0.5rem 1rem;
}
}
</style>
</head>
<body>
<!-- Navbar -->
<nav class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="container">
<a class="navbar-brand d-flex align-items-center" href="/">
<i class="fab fa-youtube logo"></i>
<span>TranscriptAI</span>
</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href="#"><i class="fas fa-home me-1"></i> Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#"><i class="fas fa-info-circle me-1"></i> About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#"><i class="fas fa-question-circle me-1"></i> Help</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- Loading Overlay -->
<div class="loading-overlay" id="loadingOverlay">
<div class="text-center mb-4">
<i class="fas fa-spinner fa-spin fa-3x mb-3 pulse-icon"></i>
<h3 id="statusTitle" class="mb-3">Processing Your Video...</h3>
<p class="text-light opacity-75">This may take a few minutes depending on video length</p>
</div>
<div class="progress-container">
<div class="progress">
<div id="progressBar" class="progress-bar"
role="progressbar" style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"></div>
</div>
<div class="d-flex justify-content-between mt-2">
<small class="text-light opacity-75">Processing...</small>
<small id="progressText" class="text-light opacity-75">0%</small>
</div>
</div>
<!-- Success Alert (Hidden by default) -->
<div class="alert alert-success alert-dismissible fade show mt-4 w-75 mx-auto" role="alert" id="successAlert" style="display: none;">
<div class="d-flex">
<i class="fas fa-check-circle me-2 mt-1"></i>
<div>
<strong>Success!</strong> <span id="successMessage">The video has been processed successfully.</span>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<!-- Error Alert (Hidden by default) -->
<div class="alert alert-danger alert-dismissible fade show mt-4 w-75 mx-auto" role="alert" id="errorAlert" style="display: none;">
<div class="d-flex">
<i class="fas fa-exclamation-circle me-2 mt-1"></i>
<div>
<strong>Error!</strong> <span id="errorMessage">An error occurred during processing.</span>
</div>
</div>
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
<div class="log-container" id="logContainer">
<!-- Log messages will be added here dynamically -->
</div>
</div>
<div class="container py-5">
<!-- Banner -->
<div class="banner shadow-lg mb-5">
<div class="container-fluid px-4">
<div class="row align-items-center">
<div class="col-md-8">
<h2 class="display-5">Intelligent YouTube Transcript Analysis</h2>
<p>Transform video content into insightful summaries with AI-powered analysis in English and Hindi. Extract key points, topics, and quotes in seconds.</p>
</div>
<div class="col-md-4 text-md-end text-center mt-3 mt-md-0">
<i class="fas fa-brain fa-5x opacity-50"></i>
</div>
</div>
</div>
</div>
<!-- Main Content -->
<div class="row">
<div class="col-12 mb-4">
<!-- Navigation Tabs -->
<ul class="nav nav-tabs" id="myTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="home-tab" data-bs-toggle="tab" data-bs-target="#home" type="button" role="tab" aria-controls="home" aria-selected="true">
<i class="fas fa-play-circle"></i> Process Video
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="results-tab" data-bs-toggle="tab" data-bs-target="#results" type="button" role="tab" aria-controls="results" aria-selected="false">
<i class="fas fa-list-ul"></i> Recent Results
</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="preview-tab" data-bs-toggle="tab" data-bs-target="#preview" type="button" role="tab" aria-controls="preview" aria-selected="false">
<i class="fas fa-file-alt"></i> Preview Content
</button>
</li>
</ul>
</div>
</div>
<div class="tab-content" id="myTabContent">
<!-- Home Tab (Process Form) -->
<div class="tab-pane fade show active" id="home" role="tabpanel" aria-labelledby="home-tab">
<div class="row">
<div class="col-lg-8">
<div class="card mb-4">
<div class="card-header d-flex align-items-center">
<i class="fas fa-link text-primary me-2"></i>
<span>Enter Video Details</span>
</div>
<div class="card-body">
<form id="processingForm">
<div class="mb-4">
<label for="youtubeUrl" class="form-label">YouTube Video URL</label>
<div class="input-group mb-2">
<span class="input-group-text"><i class="fab fa-youtube text-danger"></i></span>
<input type="url" class="form-control" id="youtubeUrl" name="youtube_url"
placeholder="https://www.youtube.com/watch?v=..." required>
</div>
<div class="form-text">Enter the full URL of any YouTube video you want to analyze</div>
</div>
<div class="mb-4">
<label for="apiKey" class="form-label"></label>
<div class="input-group mb-2">
<span class="input-group-text"><i class="fas fa-key"></i></span>
<input type="password" class="form-control" id="apiKey" name="api_key"
value="{{ api_key }}" required>
</div>
</div>
<div class="d-grid">
<button type="submit" class="btn btn-primary btn-lg">
<i class="fas fa-rocket me-2"></i> Process Video
</button>
</div>
</form>
</div>
</div>
</div>
<div class="col-lg-4">
<div class="card help-card">
<div class="card-header d-flex align-items-center">
<i class="fas fa-info-circle text-primary me-2"></i>
<span>How It Works</span>
</div>
<div class="card-body">
<div class="feature-item">
<div class="features-icon">
<i class="fas fa-download"></i>
</div>
<div class="feature-content">
<h5>1. Fetch Transcript</h5>
<p class="text-muted">System automatically downloads video subtitles</p>
</div>
</div>
<div class="feature-item">
<div class="features-icon">
<i class="fas fa-robot"></i>
</div>
<div class="feature-content">
<h5>2. AI Processing</h5>
<p class="text-muted"> AI analyzes and extracts key information</p>
</div>
</div>
<div class="feature-item">
<div class="features-icon">
<i class="fas fa-language"></i>
</div>
<div class="feature-content">
<h5>3. Bilingual Output</h5>
<p class="text-muted">Get results in both English and Hindi</p>
</div>
</div>
<div class="feature-item">
<div class="features-icon">
<i class="fas fa-file-export"></i>
</div>
<div class="feature-content">
<h5>4. Export & Share</h5>
<p class="text-muted">Download or preview your analysis results</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- What You Get Section -->
<div class="row mt-4">
<div class="col-12">
<div class="card">
<div class="card-header d-flex align-items-center">
<i class="fas fa-lightbulb text-primary me-2"></i>
<span>What You'll Get</span>
</div>
<div class="card-body">
<div class="row g-4">
<div class="col-md-3 col-sm-6">
<div class="text-center">
<div class="mb-3">
<i class="fas fa-list-ul text-primary fa-2x"></i>
</div>
<h5>Key Points</h5>
<p class="text-muted small">Concise summary of main ideas</p>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="text-center">
<div class="mb-3">
<i class="fas fa-sitemap text-primary fa-2x"></i>
</div>
<h5>Topics Covered</h5>
<p class="text-muted small">Major themes and subjects</p>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="text-center">
<div class="mb-3">
<i class="fas fa-quote-right text-primary fa-2x"></i>
</div>
<h5>Notable Quotes</h5>
<p class="text-muted small">Important statements highlighted</p>
</div>
</div>
<div class="col-md-3 col-sm-6">
<div class="text-center">
<div class="mb-3">
<i class="fas fa-align-left text-primary fa-2x"></i>
</div>
<h5>Full Transcript</h5>
<p class="text-muted small">Complete formatted content</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Results Tab -->
<div class="tab-pane fade" id="results" role="tabpanel" aria-labelledby="results-tab">
<div class="card">
<div class="card-header d-flex justify-content-between align-items-center">
<div class="d-flex align-items-center">
<i class="fas fa-history text-primary me-2"></i>
<span>Recent Analyses</span>
</div>
<button id="refreshResultsBtn" class="btn btn-sm btn-outline-primary">
<i class="fas fa-sync-alt me-1"></i> Refresh
</button>
</div>
<div class="card-body p-0">
<div class="table-responsive recent-items">
<table class="table table-hover mb-0">
<thead>
<tr>
<th class="px-3 py-3">Filename</th>
<th class="px-3 py-3">Language</th>
<th class="px-3 py-3">Created</th>
<th class="px-3 py-3 text-end">Actions</th>
</tr>
</thead>
<tbody id="resultsList">
<!-- Results will be loaded here dynamically -->
<tr>
<td colspan="4" class="text-center p-4">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2 text-muted">Loading results...</p>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- Preview Tab -->
<div class="tab-pane fade" id="preview" role="tabpanel" aria-labelledby="preview-tab">
<div class="card">
<div class="card-header d-flex align-items-center mb-0">
<i class="fas fa-file-alt text-primary me-2"></i>
<h5 id="previewTitle" class="m-0">No content selected</h5>
</div>
<div class="card-body">
<div id="preview-container" class="markdown-body">
<div class="text-center p-5 text-muted">
<i class="far fa-file-alt fa-4x mb-3 opacity-25"></i>
<p>Select a result file from the "Recent Results" tab to preview content here</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Footer -->
<footer class="bg-dark text-light py-4 mt-5">
<div class="container">
<div class="row">
<div class="col-md-6">
<h5 class="mb-3">TranscriptAI</h5>
</div>
<div class="col-md-6 text-md-end">
<ul class="list-inline mb-0">
<li class="list-inline-item"><a href="#" class="text-muted text-decoration-none">Terms</a></li>
<li class="list-inline-item"><a href="#" class="text-muted text-decoration-none">Privacy</a></li>
<li class="list-inline-item"><a href="#" class="text-muted text-decoration-none">Contact</a></li>
</ul>
<p class="mt-2 mb-0 text-muted small">© 2025 TranscriptAI. All rights reserved.</p>
</div>
</div>
</div>
</footer>
<!-- Bootstrap and jQuery JS
<!-- Bootstrap and jQuery JS -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
// Set up polling for status updates
let statusInterval;
let isProcessing = false;
// Initialize UI elements
$(document).ready(function() {
// Load results list on page load
loadResultsList();
// Form submission handler
$('#processingForm').on('submit', function(e) {
e.preventDefault();
startProcessing();
});
// Refresh results button
$('#refreshResultsBtn').on('click', function() {
loadResultsList();
});
});
// Start processing a YouTube URL
function startProcessing() {
const youtubeUrl = $('#youtubeUrl').val().trim();
const apiKey = $('#apiKey').val().trim();
if (!youtubeUrl) {
alert('Please enter a valid YouTube URL');
return;
}
// Show loading overlay
$('#loadingOverlay').fadeIn();
$('#logContainer').empty();
$('#progressBar').css('width', '0%');
$('#progressText').text('0%');
$('#statusTitle').text('Processing Your Video...');
$('#successAlert').hide();
$('#errorAlert').hide();
// Submit request to server
$.ajax({
url: '/process',
method: 'POST',
data: {
youtube_url: youtubeUrl,
api_key: apiKey
},
success: function(response) {
if (response.success) {
// Start polling for status updates
isProcessing = true;
statusInterval = setInterval(checkStatus, 1000);
} else {
// Show error
$('#errorMessage').text(response.error);
$('#errorAlert').fadeIn();
setTimeout(function() {
$('#loadingOverlay').fadeOut();
}, 3000);
}
},
error: function() {
$('#errorMessage').text('Server error. Please try again later.');
$('#errorAlert').fadeIn();
setTimeout(function() {
$('#loadingOverlay').fadeOut();
}, 3000);
}
});
}
// Check processing status
function checkStatus() {
$.ajax({
url: '/status',
method: 'GET',
success: function(status) {
// Update progress bar
$('#progressBar').css('width', status.progress + '%');
$('#progressText').text(status.progress + '%');
$('#statusTitle').text(status.current_step);
// Update log
updateLog(status.log);
// Check if processing is complete
if (!status.is_processing && isProcessing) {
isProcessing = false;
clearInterval(statusInterval);
// Show success message
$('#successMessage').text('Processing complete! View your results in the "Recent Results" tab.');
$('#successAlert').fadeIn();
// Refresh results list
loadResultsList();
// Switch to results tab after 3 seconds
setTimeout(function() {
$('#results-tab').tab('show');
$('#loadingOverlay').fadeOut();
}, 3000);
}
},
error: function() {
clearInterval(statusInterval);
$('#errorMessage').text('Error checking status. Please try again.');
$('#errorAlert').fadeIn();
setTimeout(function() {
$('#loadingOverlay').fadeOut();
}, 3000);
}
});
}
// Update log display
function updateLog(logEntries) {
const logContainer = $('#logContainer');
logContainer.empty();
logEntries.forEach(function(entry) {
logContainer.append(`<div><span class="text-info">[${entry.time}]</span> ${entry.message}</div>`);
});
// Auto-scroll to bottom
logContainer.scrollTop(logContainer[0].scrollHeight);
}
// Load results list
function loadResultsList() {
$.ajax({
url: '/list_results',
method: 'GET',
success: function(files) {
const resultsList = $('#resultsList');
resultsList.empty();
if (files.length === 0) {
resultsList.append(`
<tr>
<td colspan="4" class="text-center p-4">
<i class="far fa-file-alt fa-3x mb-3 text-muted opacity-25"></i>
<p class="text-muted">No results found. Process a video to get started.</p>
</td>
</tr>
`);
return;
}
files.forEach(function(file) {
const date = new Date(file.created * 1000);
const formattedDate = date.toLocaleString();
const isHindi = file.is_hindi;
resultsList.append(`
<tr>
<td class="px-3 py-3">
<div class="d-flex align-items-center">
<i class="far fa-file-alt text-${isHindi ? 'danger' : 'primary'} me-2"></i>
<span>${file.filename}</span>
</div>
</td>
<td class="px-3 py-3">
<span class="badge ${isHindi ? 'badge-hindi' : 'badge-english'}">
${isHindi ? 'Hindi' : 'English'}
</span>
</td>
<td class="px-3 py-3">${formattedDate}</td>
<td class="px-3 py-3 text-end">
<button class="btn btn-sm btn-outline-primary btn-action view-result"
data-filename="${file.filename}">
<i class="fas fa-eye"></i> View
</button>
<a href="/results/${file.filename}" class="btn btn-sm btn-outline-success btn-action" download>
<i class="fas fa-download"></i> Download
</a>
</td>
</tr>
`);
});
// Attach event handlers to view buttons
$('.view-result').on('click', function() {
const filename = $(this).data('filename');
viewResult(filename);
});
},
error: function() {
const resultsList = $('#resultsList');
resultsList.empty();
resultsList.append(`
<tr>
<td colspan="4" class="text-center p-4">
<i class="fas fa-exclamation-circle fa-3x mb-3 text-danger opacity-25"></i>
<p class="text-danger">Error loading results. Please try again.</p>
</td>
</tr>
`);
}
});
}
// View a result file
function viewResult(filename) {
// Switch to preview tab
$('#preview-tab').tab('show');
// Set preview title
$('#previewTitle').text(filename);
// Show loading state
$('#preview-container').html(`
<div class="text-center p-5">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-3 text-muted">Loading content...</p>
</div>
`);
// Fetch and display the content
$.ajax({
url: `/results/${filename}`,
method: 'GET',
success: function(content) {
// Convert markdown to HTML
const htmlContent = marked.parse(content);
$('#preview-container').html(htmlContent);
},
error: function() {
$('#preview-container').html(`
<div class="text-center p-5 text-danger">
<i class="fas fa-exclamation-circle fa-4x mb-3 opacity-25"></i>
<p>Error loading content. Please try again.</p>
</div>
`);
}
});
}
</script>
</body>
</html>