';
}
}
/**
* Process a single paper
* @param {string} paperId - The ID of the paper to process
*/
async processSinglePaper(paperId) {
if (!this.scraperSelect) return;
// Disable all process buttons to prevent multiple clicks
document.querySelectorAll(".process-paper-btn").forEach((btn) => {
btn.disabled = true;
});
// Show processing status via flash message
showFlashMessage("Processing paper...", "info");
// Get selected scraper
const selectedScraper = this.scraperSelect.value;
try {
const data = await apiRequest(`/scraper/process_single/${paperId}`, {
method: "POST",
body: JSON.stringify({
scraper_module: selectedScraper,
}),
});
if (data.success) {
// Update status in the search results
const row = document
.querySelector(`.process-paper-btn[data-paper-id="${paperId}"]`)
?.closest("tr");
if (row) {
const statusCell = row.querySelector("td:nth-child(4)");
if (statusCell) {
statusCell.innerHTML = createStatusBadge("Pending");
}
}
// Show success notification
showFlashMessage(data.message, "success");
// Set up polling to check paper status and refresh activity
this.pollPaperStatus(paperId, 3000, 20);
} else {
showFlashMessage(data.message, "error");
}
} catch (error) {
console.error("Error processing paper:", error);
showFlashMessage("Error processing paper", "error");
} finally {
// Re-enable the process buttons after a short delay
setTimeout(() => {
document.querySelectorAll(".process-paper-btn").forEach((btn) => {
if (btn.getAttribute("data-paper-id") !== paperId) {
btn.disabled = false;
}
});
}, 1000);
}
}
/**
* Poll paper status until it changes from Pending
* @param {string} paperId - The paper ID to poll
* @param {number} interval - Polling interval in milliseconds
* @param {number} maxAttempts - Maximum number of polling attempts
*/
pollPaperStatus(paperId, interval = 3000, maxAttempts = 20) {
let attempts = 0;
// Immediately refresh activity log to show the initial pending status
if (this.onActivityRefresh) {
this.onActivityRefresh();
}
const checkStatus = async () => {
attempts++;
console.log(
`Checking status of paper ${paperId}, attempt ${attempts}/${maxAttempts}`
);
try {
const data = await apiRequest(`/api/papers/${paperId}`);
if (data && data.paper) {
const paper = data.paper;
console.log(`Paper status: ${paper.status}`);
// Update the UI with the current status
const row = document
.querySelector(`.process-paper-btn[data-paper-id="${paperId}"]`)
?.closest("tr");
if (row) {
const statusCell = row.querySelector("td:nth-child(4)");
if (statusCell) {
statusCell.innerHTML = createStatusBadge(paper.status);
}
// Update processing status message if status changed
if (paper.status !== "Pending") {
if (paper.status === "Done") {
showFlashMessage(`Paper processed successfully: ${paper.title}`, "success");
} else if (paper.status === "Failed") {
showFlashMessage(`Paper processing failed: ${
paper.error_msg || "Unknown error"
}`, "error");
}
}
}
// Always refresh activity log
if (this.onActivityRefresh) {
this.onActivityRefresh();
}
// If status is still pending and we haven't reached max attempts, check again
if (paper.status === "Pending" && attempts < maxAttempts) {
setTimeout(checkStatus, interval);
} else {
// If status changed or we reached max attempts, refresh chart data too
if (this.onChartRefresh) {
this.onChartRefresh();
}
// If we hit max attempts but status is still pending, show a message
if (paper.status === "Pending" && attempts >= maxAttempts) {
showFlashMessage(
"Paper is still being processed. Check the activity log for updates.",
"info"
);
}
}
}
} catch (error) {
console.error(`Error polling paper status: ${error}`);
// If there's an error, we can still try again if under max attempts
if (attempts < maxAttempts) {
setTimeout(checkStatus, interval);
}
}
};
// Start checking
setTimeout(checkStatus, interval);
}
/**
* Set callback for activity refresh
*/
setActivityRefreshCallback(callback) {
this.onActivityRefresh = callback;
}
/**
* Set callback for chart refresh
*/
setChartRefreshCallback(callback) {
this.onChartRefresh = callback;
}
}