Deploy ab56ec7 from main

This commit is contained in:
github-actions[bot]
2026-04-07 07:59:55 +00:00
parent 8831622d03
commit 526959257f
3 changed files with 122 additions and 9 deletions

View File

@@ -568,6 +568,13 @@ class Peptide_News_Admin {
echo '</button>'; echo '</button>';
echo '<span id="peptide-backfill-result" style="margin-left:10px;"></span>'; echo '<span id="peptide-backfill-result" style="margin-left:10px;"></span>';
// Generate AI Summaries button.
echo '<br style="margin-bottom:8px;">';
echo '<button type="button" id="peptide-generate-summaries" class="button button-primary" style="margin-top:8px;">';
echo esc_html__( 'Generate AI Summaries', 'peptide-news' );
echo '</button>';
echo '<span id="peptide-summary-result" style="margin-left:10px;"></span>';
?> ?>
<script> <script>
(function($) { (function($) {
@@ -591,6 +598,50 @@ class Peptide_News_Admin {
}); });
}); });
// Generate AI Summaries — loops in batches until all articles are done.
$('#peptide-generate-summaries').on('click', function() {
var $btn = $(this), $result = $('#peptide-summary-result');
var totalProcessed = 0;
$btn.prop('disabled', true);
$result.text('<?php echo esc_js( __( 'Starting...', 'peptide-news' ) ); ?>');
function runBatch() {
$btn.text('<?php echo esc_js( __( 'Generating...', 'peptide-news' ) ); ?>');
$.post(peptideNewsAdmin.ajax_url, {
action: 'peptide_news_generate_summaries',
nonce: peptideNewsAdmin.admin_nonce
}, function(response) {
if (response.success) {
totalProcessed += response.data.processed;
var remaining = response.data.remaining;
$result.text(totalProcessed + ' summarized, ' + remaining + ' remaining...');
if (remaining > 0 && response.data.processed > 0) {
// Continue with next batch.
runBatch();
} else {
// Done — either all processed or no progress (error).
$btn.prop('disabled', false).text('<?php echo esc_js( __( 'Generate AI Summaries', 'peptide-news' ) ); ?>');
if (remaining === 0) {
$result.text('Done! ' + totalProcessed + ' article(s) summarized.');
} else {
$result.text(totalProcessed + ' summarized. ' + remaining + ' could not be processed — check the debug log.');
}
}
} else {
$btn.prop('disabled', false).text('<?php echo esc_js( __( 'Generate AI Summaries', 'peptide-news' ) ); ?>');
$result.text('Error: ' + (response.data || 'Unknown error'));
}
}).fail(function() {
$btn.prop('disabled', false).text('<?php echo esc_js( __( 'Generate AI Summaries', 'peptide-news' ) ); ?>');
$result.text('Request failed. ' + totalProcessed + ' completed before failure.');
});
}
runBatch();
});
})(jQuery); })(jQuery);
</script> </script>
<?php <?php

View File

@@ -114,22 +114,26 @@ class Peptide_News_LLM {
* Process all unanalyzed articles (called after a fetch cycle). * Process all unanalyzed articles (called after a fetch cycle).
* *
* Includes a time-based guard to prevent cron timeouts and * Includes a time-based guard to prevent cron timeouts and
* respects the admin-configured max articles per cycle. * respects the admin-configured max articles per cycle unless
* $override_limit is true (used by the manual bulk-generate button).
* *
* @param int $batch_size Max articles to process per run. * @param int $batch_size Max articles to process per run.
* @param bool $override_limit When true, ignore the admin "max per cycle" cap.
* @return int Number of articles successfully processed. * @return int Number of articles successfully processed.
*/ */
public static function process_unanalyzed( $batch_size = 10 ) { public static function process_unanalyzed( $batch_size = 10, $override_limit = false ) {
if ( ! self::is_enabled() ) { if ( ! self::is_enabled() ) {
return 0; return 0;
} }
// Respect admin cost-control setting. if ( ! $override_limit ) {
// Respect admin cost-control setting for automated cron runs.
$max_per_cycle = absint( get_option( 'peptide_news_llm_max_articles', 10 ) ); $max_per_cycle = absint( get_option( 'peptide_news_llm_max_articles', 10 ) );
if ( $max_per_cycle < 1 ) { if ( $max_per_cycle < 1 ) {
$max_per_cycle = 10; $max_per_cycle = 10;
} }
$batch_size = min( $batch_size, $max_per_cycle ); $batch_size = min( $batch_size, $max_per_cycle );
}
global $wpdb; global $wpdb;
$table = $wpdb->prefix . 'peptide_news_articles'; $table = $wpdb->prefix . 'peptide_news_articles';
@@ -370,6 +374,63 @@ class Peptide_News_LLM {
} }
} }
/**
* AJAX handler: bulk-generate AI summaries for articles that are missing them.
*
* Processes up to 50 articles per request. Returns the count of articles
* processed and remaining so the admin UI can loop until done.
*
* @since 2.0.1
*/
public static function ajax_generate_summaries() {
check_ajax_referer( 'peptide_news_admin', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( 'Unauthorized', 403 );
}
if ( ! self::is_enabled() ) {
wp_send_json_error( 'AI Analysis is not enabled. Please enable it and set an OpenRouter API key in Peptide News → Settings.' );
}
global $wpdb;
$table = $wpdb->prefix . 'peptide_news_articles';
// Count how many still need processing.
$remaining = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM {$table}
WHERE is_active = 1
AND ( ai_summary = '' OR ai_summary IS NULL )"
);
if ( $remaining < 1 ) {
wp_send_json_success( array(
'processed' => 0,
'remaining' => 0,
'message' => 'All articles already have AI summaries.',
) );
}
// Process a generous batch — the 120-second timeout guard inside
// process_unanalyzed() will stop early if needed. Override the
// per-cycle limit since this is a manual admin action.
$batch_size = min( 50, $remaining );
$processed = self::process_unanalyzed( $batch_size, true );
// Recount remaining after this batch.
$still_remaining = (int) $wpdb->get_var(
"SELECT COUNT(*) FROM {$table}
WHERE is_active = 1
AND ( ai_summary = '' OR ai_summary IS NULL )"
);
wp_send_json_success( array(
'processed' => $processed,
'remaining' => $still_remaining,
'message' => sprintf( '%d article(s) summarized, %d remaining.', $processed, $still_remaining ),
) );
}
/** /**
* Clear all article transient caches. * Clear all article transient caches.
*/ */

View File

@@ -81,6 +81,7 @@ class Peptide_News {
$this->loader->add_action( 'peptide_news_cron_fetch', $fetcher, 'fetch_all_sources' ); $this->loader->add_action( 'peptide_news_cron_fetch', $fetcher, 'fetch_all_sources' );
$this->loader->add_filter( 'cron_schedules', $fetcher, 'add_custom_cron_schedules' ); $this->loader->add_filter( 'cron_schedules', $fetcher, 'add_custom_cron_schedules' );
$this->loader->add_action( 'wp_ajax_peptide_news_backfill_sources', $fetcher, 'ajax_backfill_sources' ); $this->loader->add_action( 'wp_ajax_peptide_news_backfill_sources', $fetcher, 'ajax_backfill_sources' );
$this->loader->add_action( 'wp_ajax_peptide_news_generate_summaries', 'Peptide_News_LLM', 'ajax_generate_summaries' );
} }
/** /**