PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
betterdocs / includes / Core / ArticleSummary.php

ArticleSummary.php in BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot 4.2.0, at includes/Core/ArticleSummary.php

244 lines 7.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace WPDeveloper\BetterDocs\Core;
4
5 use WPDeveloper\BetterDocs\Utils\Base;
6 use WPDeveloper\BetterDocs\Core\Settings;
7 use WPDeveloper\BetterDocs\Utils\AIHelper;
8
9 class ArticleSummary extends Base {
10
11 public $settings;
12 public $ai_helper;
13
14 public function __construct( Settings $settings ) {
15 $this->settings = $settings;
16 $this->ai_helper = new AIHelper( $settings );
17
18 // Register AJAX handlers
19 add_action( 'wp_ajax_betterdocs_generate_article_summary', [ $this, 'generate_article_summary_callback' ] );
20 add_action( 'wp_ajax_nopriv_betterdocs_generate_article_summary', [ $this, 'generate_article_summary_callback' ] );
21
22 // Clear summary when post is updated
23 add_action( 'post_updated', [ $this, 'clear_article_summary_on_update' ], 10, 3 );
24 }
25
26 /**
27 * Check if article summary feature is enabled
28 *
29 * @return bool
30 */
31 public function is_enabled() {
32 return $this->settings->get( 'enable_article_summary', false );
33 }
34
35 /**
36 * Get OpenAI API key from settings
37 *
38 * @return string
39 */
40 public function get_api_key() {
41 return $this->ai_helper->get_api_key();
42 }
43
44 /**
45 * AJAX callback for generating article summary
46 */
47 public function generate_article_summary_callback() {
48 // Check if Article Summary feature is enabled
49 if ( ! $this->is_enabled() ) {
50 wp_send_json_error( 'AI Doc Summarizer feature is not enabled.' );
51 wp_die();
52 }
53
54 // Verify the nonce
55 if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'betterdocs_article_summary_nonce' ) ) { //phpcs:ignore
56 wp_send_json_error( 'Invalid nonce' );
57 wp_die();
58 }
59
60 $post_id = intval( $_POST['post_id'] ); //phpcs:ignore
61 $post_title = sanitize_text_field( $_POST['post_title'] ); //phpcs:ignore
62 $post_content = wp_kses_post( $_POST['post_content'] ); //phpcs:ignore
63
64 // Validate that this is a docs post type
65 if ( $post_id > 0 ) {
66 $post_type = get_post_type( $post_id );
67 if ( $post_type !== 'docs' ) {
68 wp_send_json_error( 'Doc Summarizer is only available for documentation posts.' );
69 wp_die();
70 }
71
72 // Check if post is password protected and user hasn't provided correct password
73 if ( post_password_required( $post_id ) ) {
74 wp_send_json_error( 'This document is password protected. Please enter the correct password to access the summary.' );
75 wp_die();
76 }
77 }
78
79 if ( empty( $post_content ) ) {
80 wp_send_json_error( 'No content provided for summary generation.' );
81 wp_die();
82 }
83
84 // Check if summary already exists in post meta
85 if ( $post_id > 0 ) {
86 $existing_summary = get_post_meta( $post_id, '_betterdocs_article_summary', true );
87 $content_hash = md5( $post_content );
88 $stored_hash = get_post_meta( $post_id, '_betterdocs_article_summary_hash', true );
89
90 // Return existing summary if content hasn't changed
91 if ( ! empty( $existing_summary ) && $content_hash === $stored_hash ) {
92 // Clean existing summary in case it has old formatting
93 $cleaned_existing = $this->clean_summary_content( $existing_summary );
94 wp_send_json_success( $cleaned_existing );
95 wp_die();
96 }
97 }
98
99 // Generate new summary using OpenAI
100 $summary = $this->generate_summary( $post_title, $post_content );
101
102 if ( is_wp_error( $summary ) ) {
103 wp_send_json_error( $summary->get_error_message() );
104 wp_die();
105 }
106
107 // Clean up the summary content
108 $cleaned_summary = $this->clean_summary_content( $summary );
109
110 // Store summary in post meta if post ID is provided
111 if ( $post_id > 0 && ! empty( $cleaned_summary ) ) {
112 update_post_meta( $post_id, '_betterdocs_article_summary', $cleaned_summary );
113 update_post_meta( $post_id, '_betterdocs_article_summary_hash', md5( $post_content ) );
114 }
115
116 wp_send_json_success( $cleaned_summary );
117 wp_die();
118 }
119
120 /**
121 * Generate article summary using OpenAI
122 *
123 * @param string $title Article title
124 * @param string $content Article content
125 * @return string|\WP_Error Generated summary or error
126 */
127 public function generate_summary( $title, $content ) {
128 // Check if Article Summary feature is enabled
129 if ( ! $this->is_enabled() ) {
130 return new \WP_Error( 'feature_disabled', 'AI Doc Summarizer feature is not enabled.' );
131 }
132
133 try {
134 if ( ! $this->ai_helper->has_api_key() ) {
135 return new \WP_Error( 'no_api_key', 'OpenAI API key is not configured. Please add your API key in BetterDocs settings.' );
136 }
137
138 // Prepare content for AI processing
139 $prepared_content = $this->ai_helper->prepare_content_for_ai( $content, 4000 );
140
141 // Create messages for summary generation
142 $messages = $this->ai_helper->create_summary_messages( $title, $prepared_content );
143
144 // Set options for summary generation
145 $options = [
146 'max_tokens' => 500,
147 'temperature' => 0.3,
148 'timeout' => 30
149 ];
150
151 $response = $this->ai_helper->make_openai_request( $messages, $options );
152
153 return $response;
154
155 } catch ( \Exception $error ) {
156 return new \WP_Error( 'exception', 'Error generating summary: ' . $error->getMessage() );
157 }
158 }
159
160
161
162 /**
163 * Clear article summary when post is updated
164 *
165 * @param int $post_id Post ID
166 * @param \WP_Post $post_after Post object after update
167 * @param \WP_Post $post_before Post object before update
168 */
169 public function clear_article_summary_on_update( $post_id, $post_after, $post_before ) {
170 // Only clear summary for docs post type
171 if ( get_post_type( $post_id ) !== 'docs' ) {
172 return;
173 }
174
175 // Only clear if content has actually changed
176 if ( $post_after->post_content !== $post_before->post_content ) {
177 delete_post_meta( $post_id, '_betterdocs_article_summary' );
178 delete_post_meta( $post_id, '_betterdocs_article_summary_hash' );
179 }
180 }
181
182 /**
183 * Get cached summary for a post
184 *
185 * @param int $post_id Post ID
186 * @return string|false Cached summary or false if not found
187 */
188 public function get_cached_summary( $post_id ) {
189 return get_post_meta( $post_id, '_betterdocs_article_summary', true );
190 }
191
192 /**
193 * Check if summary exists for a post
194 *
195 * @param int $post_id Post ID
196 * @return bool True if summary exists
197 */
198 public function has_cached_summary( $post_id ) {
199 $summary = $this->get_cached_summary( $post_id );
200 return ! empty( $summary );
201 }
202
203 /**
204 * Manually clear summary cache for a post
205 *
206 * @param int $post_id Post ID
207 * @return bool True on success
208 */
209 public function clear_summary_cache( $post_id ) {
210 $deleted_summary = delete_post_meta( $post_id, '_betterdocs_article_summary' );
211 $deleted_hash = delete_post_meta( $post_id, '_betterdocs_article_summary_hash' );
212
213 return $deleted_summary || $deleted_hash;
214 }
215
216 /**
217 * Clean summary content by removing markdown code blocks and unwanted formatting
218 *
219 * @param string $content Raw summary content from OpenAI
220 * @return string Cleaned summary content
221 */
222 public function clean_summary_content( $content ) {
223 if ( empty( $content ) ) {
224 return $content;
225 }
226
227 // Remove markdown code blocks (```html, ```, etc.)
228 $content = preg_replace( '/^```[a-zA-Z]*\s*/m', '', $content );
229 $content = preg_replace( '/\s*```\s*$/m', '', $content );
230
231 // Remove any remaining triple backticks
232 $content = str_replace( '```', '', $content );
233
234 // Clean up extra whitespace
235 $content = trim( $content );
236
237 // Remove any leading/trailing newlines
238 $content = preg_replace( '/^\s*\n+/', '', $content );
239 $content = preg_replace( '/\n+\s*$/', '', $content );
240
241 return $content;
242 }
243 }
244