Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 78 additions & 4 deletions static/js/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -1359,29 +1359,103 @@ $(function () {
$gallery.removeClass("d-none");
}

// Poll the illustration job token until it reaches a terminal state,
// then fetch the full payload and render the images.
function _pollIllustrationJob(illustToken, _errorRetries) {
var retries = _errorRetries || 0;
$.ajax({
url: "/progress/" + illustToken,
method: "GET",
success: function (data) {
Comment on lines +1366 to +1369
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The polling GET requests don’t set a timeout. If a /progress/ request hangs (e.g., stalled connection), neither the success nor error callback will fire, so polling stops and the spinner/export buttons never recover. Add a reasonable timeout for the lightweight poll (and handle timeout in the error path) so the UI can continue retrying or fail gracefully.

Copilot uses AI. Check for mistakes.
if (data.status === "done") {
// Job finished – fetch the full payload to get the illustrations array.
$.ajax({
url: "/progress/" + illustToken + "/full",
method: "GET",
success: function (full) {
renderIllustrations(full.illustrations || []);
},
error: function () {
renderIllustrations([]);
},
complete: function () {
$("#illustrations-spinner").addClass("d-none");
$("#illustrations-spinner-label").addClass("d-none").text("");
_enableExportButtons();
Comment on lines +1372 to +1384
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If fetching /progress//full fails, the code renders an empty gallery without any alert, which can mislead users into thinking “no illustrations were generated” rather than “results couldn’t be retrieved”. Consider showing an error message (and/or keeping the existing gallery) when the full payload request fails.

Copilot uses AI. Check for mistakes.
},
});
} else if (data.status === "error") {
showAlert(
data.error ||
"Illustration generation failed. The AI service may be rate-limited — wait a few minutes and try again."
);
$("#illustrations-spinner").addClass("d-none");
$("#illustrations-spinner-label").addClass("d-none").text("");
_enableExportButtons();
} else {
// Still running – update the spinner label and keep polling.
var stepText = data.step || "Generating\u2026";
var current = data.current || 0;
var total = data.total || 0;
var label = total > 0
? stepText + " (" + current + "/" + total + ")"
: stepText;
$("#illustrations-spinner-label").text(label);
setTimeout(function () {
_pollIllustrationJob(illustToken, 0);
}, 3000);
}
},
error: function () {
// Retry on transient network errors, up to 10 attempts.
if (retries < 10) {
setTimeout(function () {
_pollIllustrationJob(illustToken, retries + 1);
}, 5000);
} else {
showAlert(
"Lost connection to the server while waiting for illustrations. Please check your connection and try again."
);
$("#illustrations-spinner").addClass("d-none");
$("#illustrations-spinner-label").addClass("d-none").text("");
_enableExportButtons();
}
Comment on lines +1409 to +1422
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The poll error handler retries all HTTP failures up to 10 times but doesn’t inspect the response. For non-transient errors like 404 {"error":"Unknown token"} (e.g., server restart/eviction), it should stop retrying and surface the server-provided error to the user instead of reporting a generic connectivity issue after 10 attempts.

Copilot uses AI. Check for mistakes.
},
});
}

$("#btn-generate-illustrations").on("click", function () {
clearAlerts();
var $btn = $(this);
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

var $btn = $(this); is unused in this click handler. Removing it avoids dead code and keeps the handler easier to maintain.

Suggested change
var $btn = $(this);

Copilot uses AI. Check for mistakes.
$("#illustrations-spinner").removeClass("d-none");
$("#illustrations-spinner-label").removeClass("d-none").text("Starting\u2026");
_disableExportButtons();

$.ajax({
url: "/generate_illustrations",
method: "POST",
contentType: "application/json",
data: JSON.stringify({ token: _progressToken }),
timeout: 600000, // 10 min timeout for image generations
success: function (resp) {
Comment on lines 1434 to 1439
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The initial POST to /generate_illustrations no longer has any timeout. That route should return quickly with an illustration_token; without a timeout a stalled request can leave the UI stuck in “Starting…”. Consider adding a short timeout (and treating timeouts like other transient errors) since the long-running work is now done via polling.

Copilot uses AI. Check for mistakes.
renderIllustrations(resp.illustrations || []);
var illustToken = resp.illustration_token;
if (illustToken) {
// Backend accepted the job; poll until done.
_pollIllustrationJob(illustToken, 0);
} else {
// Unexpected: no token in response.
renderIllustrations(resp.illustrations || []);
$("#illustrations-spinner").addClass("d-none");
$("#illustrations-spinner-label").addClass("d-none").text("");
_enableExportButtons();
}
},
error: function (xhr) {
var msg =
(xhr.responseJSON && xhr.responseJSON.error) ||
"Illustration generation failed. The AI service may be rate-limited — wait a few minutes and try again.";
showAlert(msg);
},
complete: function () {
$("#illustrations-spinner").addClass("d-none");
$("#illustrations-spinner-label").addClass("d-none").text("");
_enableExportButtons();
},
});
Expand Down
1 change: 1 addition & 0 deletions templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ <h6 class="fw-semibold mb-3"><i class="bi bi-pencil-square me-2"></i>Revise Indi
<h6 class="text-muted mb-2">Illustrations</h6>
<button class="btn btn-outline-primary" id="btn-generate-illustrations">
<span class="spinner-border spinner-border-sm d-none me-2" id="illustrations-spinner"></span>
<span id="illustrations-spinner-label" class="d-none me-1"></span>
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This label is updated live during polling but lacks the aria-live pattern used elsewhere in this template (e.g., #progress-label). Adding aria-live="polite" (and optionally role="status") will make progress updates accessible to screen readers.

Suggested change
<span id="illustrations-spinner-label" class="d-none me-1"></span>
<span id="illustrations-spinner-label" class="d-none me-1" aria-live="polite" role="status"></span>

Copilot uses AI. Check for mistakes.
<i class="bi bi-palette me-1"></i>Generate Cover &amp; Chapter Illustrations
</button>
<small class="text-muted d-block mt-1">Generates 5–10 images from key scenes (requires IMAGE_API_KEY)</small>
Expand Down
Loading