$post_id, 'post_type' => $post_type, 'engine_type' => $engine_type, 'deduplicated' => $deduplicated, 'attempts' => array() ); } $failures[$key]['attempts'][] = array( 'timestamp' => current_time('mysql', true), 'error' => $error_message ); if (count($failures[$key]['attempts']) > self::MAX_FAILURES_PER_PRODUCT) { $failures[$key]['attempts'] = array_slice( $failures[$key]['attempts'], -self::MAX_FAILURES_PER_PRODUCT ); } update_option(self::FAILURES_OPTION_KEY, $failures, false); error_log(sprintf( 'AIEO Embedding Failure: post_id=%d, type=%s, engine=%s, error=%s', $post_id, $post_type, $engine_type, $error_message )); } public function clear_failure($post_id, $post_type, $engine_type, $deduplicated = 0) { $failures = get_option(self::FAILURES_OPTION_KEY, array()); $key = "{$post_id}_{$post_type}_{$engine_type}_{$deduplicated}"; if (isset($failures[$key])) { unset($failures[$key]); update_option(self::FAILURES_OPTION_KEY, $failures, false); } } public function get_failures() { return get_option(self::FAILURES_OPTION_KEY, array()); } public function get_failure_count() { $failures = $this->get_failures(); return count($failures); } public function clear_all_failures() { delete_option(self::FAILURES_OPTION_KEY); } public function ajax_get_failed_embeddings() { check_ajax_referer('aieo_chat_admin', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Insufficient permissions', 'ai-eshop-optimizer'))); } $failures = $this->get_failures(); $enriched = array(); foreach ($failures as $key => $failure) { $post = get_post($failure['post_id']); $failure['post_title'] = $post ? $post->post_title : '(Deleted)'; $failure['last_attempt'] = end($failure['attempts']); $failure['attempt_count'] = count($failure['attempts']); $enriched[] = $failure; } wp_send_json_success(array( 'failures' => $enriched, 'total' => count($enriched) )); } public function ajax_retry_failed_embeddings() { check_ajax_referer('aieo_chat_admin', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Insufficient permissions', 'ai-eshop-optimizer'))); } if (!AIEO_Chat_Indexing::enabled()) { wp_send_json_error(array('message' => AIEO_Chat_Indexing::refusal(), 'indexing_off' => true)); } $failures = $this->get_failures(); if (empty($failures)) { wp_send_json_success(array('message' => __('No failed embeddings to retry', 'ai-eshop-optimizer'))); } $embedding_manager = AI_eShop_Chat_Embedding_Manager::get_instance(); $success_count = 0; $still_failed = 0; foreach ($failures as $key => $failure) { $result = $embedding_manager->generate_embedding( $failure['post_id'], $failure['post_type'], true ); if (is_wp_error($result)) { $this->log_failure( $failure['post_id'], $failure['post_type'], $failure['engine_type'], $result->get_error_message(), $failure['deduplicated'] ); $still_failed++; } else { $this->clear_failure( $failure['post_id'], $failure['post_type'], $failure['engine_type'], $failure['deduplicated'] ); $success_count++; } } wp_send_json_success(array( 'message' => sprintf( __('Retry complete: %1$d succeeded, %2$d still failed', 'ai-eshop-optimizer'), $success_count, $still_failed ), 'success_count' => $success_count, 'failed_count' => $still_failed )); } public function ajax_clear_failed_embeddings() { check_ajax_referer('aieo_chat_admin', 'nonce'); if (!current_user_can('manage_options')) { wp_send_json_error(array('message' => __('Insufficient permissions', 'ai-eshop-optimizer'))); } $this->clear_all_failures(); wp_send_json_success(array( 'message' => __('Failed embeddings log cleared', 'ai-eshop-optimizer') )); } }