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 / Utils / AIHelper.php

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

266 lines 7.5 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\Utils;
4
5 use WPDeveloper\BetterDocs\Core\Settings;
6
7 class AIHelper {
8
9 /**
10 * Settings instance
11 *
12 * @var Settings
13 */
14 private $settings;
15
16 public function __construct( Settings $settings ) {
17 $this->settings = $settings;
18 }
19
20 /**
21 * Get OpenAI API key from settings
22 *
23 * @return string
24 */
25 public function get_api_key() {
26 return $this->settings->get( 'ai_autowrite_api_key', '' );
27 }
28
29 /**
30 * Check if OpenAI API key is configured
31 *
32 * @return bool
33 */
34 public function has_api_key() {
35 $api_key = $this->get_api_key();
36 return ! empty( $api_key );
37 }
38
39 /**
40 * Validate OpenAI API key
41 *
42 * @param string $api_key Optional API key to validate, uses stored key if not provided
43 * @return array Array with 'valid' boolean and 'message' string
44 */
45 public function validate_api_key( $api_key = '' ) {
46 if ( empty( $api_key ) ) {
47 $api_key = $this->get_api_key();
48 }
49
50 if ( empty( $api_key ) ) {
51 return [
52 'valid' => false,
53 'message' => 'Please Insert your <a href="/admin.php?page=betterdocs-settings">OpenAI API Key</a> to use AI features.'
54 ];
55 }
56
57 $ch = curl_init( 'https://api.openai.com/v1/models' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init
58 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
59 curl_setopt( //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
60 $ch,
61 CURLOPT_HTTPHEADER,
62 [
63 'Content-Type: application/json',
64 'Authorization: Bearer ' . $api_key,
65 ]
66 );
67
68 $response = curl_exec( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_exec
69 $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_getinfo
70 curl_close( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close
71
72 if ( $httpCode == 200 ) {
73 return [
74 'valid' => true,
75 'message' => 'Valid API Key'
76 ];
77 } else {
78 $responseData = json_decode( $response, true );
79 $messageData = $responseData['error'] ?? '';
80 return [
81 'valid' => false,
82 'message' => $messageData['message'] ?? 'Invalid API Key'
83 ];
84 }
85 }
86
87 /**
88 * Make a request to OpenAI API
89 *
90 * @param array $messages Array of messages for the chat completion
91 * @param array $options Optional parameters (model, max_tokens, temperature, etc.)
92 * @return string|\WP_Error API response content or error
93 */
94 public function make_openai_request( $messages, $options = [] ) {
95 $api_key = $this->get_api_key();
96 $max_tokens = $this->settings->get( 'article_summary_max_token', 1500 );
97 $model = $this->settings->get( 'article_summary_model', 'gpt-4o-mini' );
98
99 if ( empty( $api_key ) ) {
100 return new \WP_Error( 'no_api_key', 'OpenAI API key is not configured.' );
101 }
102
103 // Default options
104 $defaults = [
105 'model' => $model,
106 'max_tokens' => $max_tokens,
107 'temperature' => 0.7,
108 'timeout' => 50
109 ];
110
111 $options = wp_parse_args( $options, $defaults );
112
113 $api_endpoint = 'https://api.openai.com/v1/chat/completions';
114
115 $request_body = [
116 'model' => $options['model'],
117 'messages' => $messages,
118 'max_tokens' => $options['max_tokens'],
119 'temperature' => $options['temperature']
120 ];
121
122 $request_options = [
123 'headers' => [
124 'Content-Type' => 'application/json',
125 'Authorization' => 'Bearer ' . $api_key,
126 ],
127 'body' => json_encode( $request_body ), //phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
128 'timeout' => $options['timeout'],
129 ];
130
131 $response = wp_remote_post( $api_endpoint, $request_options );
132
133 if ( is_wp_error( $response ) ) {
134 return new \WP_Error( 'api_error', 'Failed to connect to OpenAI API: ' . $response->get_error_message() );
135 }
136
137 $body = wp_remote_retrieve_body( $response );
138 $data = json_decode( $body, true );
139
140 if ( ! empty( $data['error'] ) ) {
141 return new \WP_Error( 'openai_error', $data['error']['message'] );
142 }
143
144 if ( empty( $data['choices'][0]['message']['content'] ) ) {
145 return new \WP_Error( 'no_content', 'No content received from OpenAI.' );
146 }
147
148 return $data['choices'][0]['message']['content'];
149 }
150
151 /**
152 * Create a system message for OpenAI
153 *
154 * @param string $content System message content
155 * @return array Message array
156 */
157 public function create_system_message( $content ) {
158 return [
159 'role' => 'system',
160 'content' => $content
161 ];
162 }
163
164 /**
165 * Create a user message for OpenAI
166 *
167 * @param string $content User message content
168 * @return array Message array
169 */
170 public function create_user_message( $content ) {
171 return [
172 'role' => 'user',
173 'content' => $content
174 ];
175 }
176
177 /**
178 * Create messages array for article summarization
179 *
180 * @param string $title Article title
181 * @param string $content Article content
182 * @return array Messages array
183 */
184 public function create_summary_messages( $title, $content ) {
185 $system_message = $this->create_system_message(
186 'You are a helpful assistant that creates concise, informative summaries of documentation articles. Always format your response in clean HTML with paragraph tags. Do not use markdown formatting, code blocks, or backticks. Return only the HTML content without any wrapper formatting.'
187 );
188
189 $user_prompt = "Please provide a concise summary of the following article titled '{$title}'. The summary should be 2-3 paragraphs long, highlighting the main points and key takeaways. Format the response in HTML with proper paragraph tags. Do not wrap the response in markdown code blocks or use any markdown formatting.\n\nArticle content:\n{$content}";
190
191 $user_message = $this->create_user_message( $user_prompt );
192
193 return [ $system_message, $user_message ];
194 }
195
196 /**
197 * Create messages array for content generation
198 *
199 * @param string $prompt User prompt
200 * @param string $keywords Optional keywords
201 * @return array Messages array
202 */
203 public function create_content_messages( $prompt, $keywords = '' ) {
204 $system_message = $this->create_system_message(
205 'You are a helpful assistant who writes documentation for users.'
206 );
207
208 $user_message = $this->create_user_message( $prompt );
209
210 return [ $system_message, $user_message ];
211 }
212
213 /**
214 * Sanitize and prepare content for AI processing
215 *
216 * @param string $content Raw content
217 * @param int $max_length Maximum length to keep
218 * @return string Sanitized content
219 */
220 public function prepare_content_for_ai( $content, $max_length = 4000 ) {
221 // Strip HTML tags and decode entities
222 $content = wp_strip_all_tags( $content );
223 $content = html_entity_decode( $content, ENT_QUOTES, 'UTF-8' );
224
225 // Remove extra whitespace
226 $content = preg_replace( '/\s+/', ' ', $content );
227 $content = trim( $content );
228
229 // Limit length
230 if ( strlen( $content ) > $max_length ) {
231 $content = substr( $content, 0, $max_length );
232 // Try to cut at a word boundary
233 $last_space = strrpos( $content, ' ' );
234 if ( $last_space !== false && $last_space > $max_length * 0.8 ) {
235 $content = substr( $content, 0, $last_space );
236 }
237 $content .= '...';
238 }
239
240 return $content;
241 }
242
243 /**
244 * Check if AI features are enabled
245 *
246 * @return bool
247 */
248 public function is_ai_enabled() {
249 return $this->settings->get( 'enable_write_with_ai', true ) && $this->has_api_key();
250 }
251
252 /**
253 * Get AI usage statistics (placeholder for future implementation)
254 *
255 * @return array Usage statistics
256 */
257 public function get_usage_stats() {
258 // This could be implemented to track API usage, costs, etc.
259 return [
260 'requests_today' => 0,
261 'tokens_used' => 0,
262 'cost_estimate' => 0
263 ];
264 }
265 }
266