PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.8.7
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.8.7
3.5.7 3.5.6 3.5.5 3.5.4 3.5.3 3.5.2 3.5.1 3.5.0 3.4.9 3.4.8 3.4.7 0.2.1 1.6.91 0.2.2 1.6.92 0.2.3 1.6.93 0.2.4 1.6.94 0.2.5 1.6.95 0.2.6 1.6.96 0.2.7 1.6.97 0.2.8 1.6.98 0.2.9 1.6.99 0.3.0 1.7.0 0.3.1 1.7.1 0.3.2 1.7.2 0.3.3 1.7.3 0.3.4 1.7.4 0.3.5 1.7.5 0.3.6 1.7.6 0.4.0 1.7.7 0.4.1 1.7.8 0.4.2 1.7.9 0.4.3 1.8.0 0.4.4 1.8.1 0.4.5 1.8.2 0.4.6 1.8.3 0.4.7 1.8.4 0.4.8 1.8.5 0.4.9 1.8.6 0.5.0 1.8.7 0.5.1 1.8.8 0.5.2 1.8.9 0.5.3 1.9.0 0.5.4 1.9.1 0.5.5 1.9.2 0.5.6 1.9.3 0.5.7 1.9.4 0.5.8 1.9.5 0.5.9 1.9.6 0.6.0 1.9.7 0.6.1 1.9.8 0.6.2 1.9.81 0.6.3 1.9.82 0.6.4 1.9.83 0.6.5 1.9.84 0.6.6 1.9.85 0.6.7 1.9.86 0.6.8 1.9.87 0.6.9 1.9.88 0.7.0 1.9.89 0.7.1 1.9.90 0.7.2 1.9.91 0.7.3 1.9.92 0.7.4 1.9.93 0.7.5 1.9.94 0.7.6 1.9.95 0.7.7 1.9.96 0.7.8 1.9.97 0.7.9 1.9.98 0.8.0 1.9.99 0.8.1 2.0.0 0.8.2 2.0.1 0.8.3 2.0.2 0.8.4 2.0.3 0.8.5 2.0.4 0.8.6 2.0.5 0.8.7 2.0.6 0.8.8 2.0.7 0.8.9 2.0.8 0.9.0 2.0.9 0.9.2 2.1.0 0.9.3 2.1.1 0.9.4 2.1.2 0.9.5 2.1.3 0.9.6 2.1.4 0.9.7 2.1.5 0.9.8 2.1.6 0.9.81 2.1.7 0.9.82 2.1.8 0.9.83 2.1.9 0.9.84 2.2.0 0.9.85 2.2.1 0.9.86 2.2.2 0.9.87 2.2.3 0.9.88 2.2.4 0.9.89 2.2.5 0.9.9 2.2.51 0.9.91 2.2.52 0.9.92 2.2.53 0.9.93 2.2.54 0.9.94 2.2.56 0.9.95 2.2.57 0.9.96 2.2.6 0.9.97 2.2.60 0.9.98 2.2.61 0.9.99 2.2.62 1.0.0 2.2.63 1.0.01 2.2.70 1.0.1 2.2.80 1.0.2 2.2.81 1.0.3 2.2.90 1.0.4 2.2.91 1.0.5 2.2.92 1.0.6 2.2.93 1.0.7 2.2.94 1.0.8 2.2.95 1.0.9 2.3.0 1.1.0 2.3.1 1.1.1 2.3.2 1.1.2 2.3.3 1.1.3 2.3.4 1.1.4 2.3.5 1.1.5 2.3.6 1.1.6 2.3.7 1.1.7 2.3.8 1.1.8 2.3.9 1.1.9 2.4.0 1.2.0 2.4.1 1.2.1 2.4.2 1.2.2 2.4.3 1.2.21 2.4.4 1.2.3 2.4.5 1.2.30 2.4.6 1.3.0 2.4.7 1.3.1 2.4.8 1.3.2 2.4.9 1.3.3 2.5.0 1.3.31 2.5.1 1.3.32 2.5.2 1.3.33 2.5.3 1.3.34 2.5.4 1.3.35 2.5.5 1.3.36 2.5.6 1.3.37 2.5.7 1.3.38 2.5.8 1.3.39 2.5.9 1.3.40 2.6.0 1.3.41 2.6.1 1.3.42 2.6.2 1.3.43 2.6.3 1.3.44 2.6.5 1.3.45 2.6.6 1.3.46 2.6.7 1.3.47 2.6.8 1.3.48 2.6.9 1.3.49 2.7.0 1.3.50 2.7.1 1.3.51 2.7.2 1.3.52 2.7.3 1.3.53 2.7.4 1.3.54 2.7.5 1.3.56 2.7.6 1.3.57 2.7.7 1.3.58 2.7.8 1.3.59 2.7.9 1.3.60 2.8.0 1.3.61 2.8.1 1.3.62 2.8.2 1.3.63 2.8.3 1.3.64 2.8.4 1.3.65 2.8.5 1.3.66 2.8.6 1.3.67 2.8.7 1.3.68 2.8.8 1.3.69 2.8.9 1.3.70 2.9.0 1.3.71 2.9.1 1.3.72 2.9.2 1.3.73 2.9.3 1.3.74 2.9.4 1.3.75 2.9.5 1.3.76 2.9.6 1.3.77 2.9.7 1.3.78 2.9.8 1.3.79 2.9.9 1.3.80 3.0.0 1.3.81 3.0.1 1.3.82 3.0.2 1.3.83 3.0.3 1.3.84 3.0.4 1.3.85 3.0.5 1.3.86 3.0.6 1.3.87 3.0.7 1.3.88 3.0.8 1.3.89 3.0.9 1.3.90 3.1.0 1.3.91 3.1.1 1.3.92 3.1.2 1.3.93 3.1.3 1.3.94 3.1.4 1.3.95 3.1.5 1.3.96 3.1.6 1.3.97 3.1.7 1.3.98 3.1.8 1.3.99 3.1.9 1.4.0 3.2.0 1.4.1 3.2.1 1.4.2 3.2.2 1.4.3 3.2.3 1.4.4 3.2.4 1.4.5 3.2.5 1.4.6 3.2.6 1.4.7 3.2.7 1.4.8 3.2.8 1.4.9 3.2.9 1.5.0 3.3.0 1.5.1 3.3.1 1.5.2 3.3.2 1.5.3 3.3.3 1.5.4 3.3.4 1.5.5 3.3.5 1.5.6 3.3.6 1.5.7 3.3.7 1.5.8 3.3.8 1.5.9 3.3.9 1.6.0 3.4.0 1.6.1 3.4.1 1.6.2 3.4.2 1.6.3 3.4.3 1.6.5 3.4.4 1.6.51 3.4.5 1.6.52 3.4.6 1.6.53 1.6.54 1.6.55 1.6.56 1.6.57 1.6.58 1.6.59 1.6.60 1.6.61 1.6.62 1.6.63 1.6.64 1.6.65 1.6.66 1.6.67 1.6.68 trunk 1.6.69 0.0.1 1.6.70 0.0.2 1.6.71 0.0.3 1.6.72 0.0.4 1.6.73 0.0.5 1.6.74 0.0.6 1.6.75 0.0.7 1.6.76 0.0.8 1.6.77 0.0.9 1.6.78 0.1.0 1.6.79 0.1.1 1.6.81 0.1.2 1.6.82 0.1.3 1.6.83 0.1.4 1.6.84 0.1.5 1.6.85 0.1.6 1.6.86 0.1.7 1.6.87 0.1.8 1.6.88 0.1.9 1.6.89 0.2.0 1.6.90
ai-engine / classes / modules / wand.php
ai-engine / classes / modules Last commit date
advisor.php 1 year ago chatbot.php 1 year ago discussions.php 1 year ago files.php 1 year ago gdpr.php 1 year ago search.php 1 year ago security.php 1 year ago tasks.php 1 year ago wand.php 1 year ago
wand.php
379 lines
1 <?php
2
3 class Meow_MWAI_Modules_Wand {
4 private $core;
5
6 public static $features = [
7 'correctText' => [
8 'label' => 'Correct Text',
9 'sublabel' => 'Grammar & Spelling',
10 'arguments' => ['postId', 'text'],
11 'where' => 'blockContext',
12 'group' => 'first'
13 ],
14 'enhanceText' => [
15 'label' => 'Enhance Text',
16 'sublabel' => 'Readibility & Quality',
17 'arguments' => ['postId', 'text'],
18 'where' => 'blockContext',
19 'group' => 'first'
20 ],
21 'longerText' => [
22 'label' => 'Longer Text',
23 'sublabel' => 'Readibility',
24 'arguments' => ['postId', 'text'],
25 'where' => 'blockContext',
26 'group' => 'first'
27 ],
28 'shorterText' => [
29 'label' => 'Shorter Text',
30 'sublabel' => 'Readibility',
31 'arguments' => ['postId', 'text'],
32 'where' => 'blockContext',
33 'group' => 'first'
34 ],
35 'translateText' => [
36 'label' => 'Translate Text',
37 'sublabel' => 'To Post Language',
38 'arguments' => ['postId', 'text', 'language'],
39 'where' => 'blockContext',
40 'group' => 'first'
41 ],
42 'translateSection' => [
43 'label' => 'Translate Post',
44 'sublabel' => 'To Post Language',
45 'arguments' => ['postId', 'text', 'context'],
46 'where' => 'postContext', // We should probably handle this dynamically on the front-side
47 'group' => 'first' // This is random
48 ],
49 'suggestSynonyms' => [
50 'label' => 'Suggest Synonyms',
51 'sublabel' => 'For Selected Words',
52 'arguments' => ['postId', 'text', 'selectedText'],
53 'where' => 'blockContext',
54 'group' => 'second'
55 ],
56 'generateImage' => [
57 'label' => 'Generate Image',
58 'sublabel' => 'For This Text',
59 'arguments' => ['postId', 'text'],
60 'where' => 'blockContext',
61 'group' => 'third'
62 ],
63 'suggestExcerpts' => [
64 'label' => 'Suggest Excerpts',
65 'sublabel' => 'Generate SEO-Optimized Excerpts',
66 'arguments' => ['postId'],
67 'where' => 'postActions'
68 ],
69 'suggestTitles' => [
70 'label' => 'Suggest Titles',
71 'sublabel' => 'Generate SEO-Optimized Titles',
72 'arguments' => ['postId'],
73 'where' => 'postActions'
74 ]
75 ];
76
77 public function __construct( $core ) {
78 $this->core = $core;
79 $this->register_filters();
80 }
81
82 private function register_filters() {
83 foreach ( self::$features as $action => $feature ) {
84 add_filter( 'mwai_magic_wand_' . $action, [ $this, 'action_' . $action ], 10, 2 );
85 }
86 }
87
88 /**
89 * Common method to process text actions (e.g., correct, enhance, lengthen, shorten text).
90 *
91 * @param array $arguments The arguments provided for the action.
92 * @param string $messagePrefix The prefix for the message to be set in the query.
93 * @return array The result of the text processing.
94 */
95 private function processTextAction( $arguments, $messagePrefix ) {
96 $postId = $arguments['postId'];
97 $isJson = isset( $arguments['json'] ) && !empty( $arguments['json'] );
98 $blockType = isset( $arguments['blockType'] ) ? $arguments['blockType'] : null;
99
100 if ( $isJson ) {
101 // Handle structured JSON data for complex blocks
102 $jsonData = $arguments['json'];
103 $text = json_encode( $jsonData, JSON_PRETTY_PRINT );
104
105 // Add specific instructions for JSON handling
106 $jsonInstructions = "\n\nIMPORTANT: The input is JSON data. You must return ONLY valid JSON (no markdown, no code blocks, no explanations). Return the EXACT SAME JSON structure, only modifying the text content within it.";
107
108 if ( $blockType === 'core/list' ) {
109 $jsonInstructions .= " This is a list with 'type' and 'items' fields. Return: {\"type\": \"list\", \"items\": [...modified items...]}";
110 }
111 elseif ( $blockType === 'core/table' ) {
112 $jsonInstructions .= " This is a table with 'type' and 'rows' fields. Each row has a 'cells' array. Return: {\"type\": \"table\", \"rows\": [{\"cells\": [...modified cells...]}, ...]}";
113 }
114
115 $messagePrefix .= $jsonInstructions;
116 }
117 else {
118 // Handle regular text
119 $text = $arguments['text'];
120 }
121
122 $query = new Meow_MWAI_Query_Text( '', 1024 );
123 $query->set_scope( 'admin-tools' );
124 $language = $keepLanguage = '';
125 if ( !empty( $postId ) ) {
126 $language = $this->core->get_post_language( $postId );
127 $keepLanguage = " Ensure the reply is in the same language as the original text ({$language}).";
128 }
129 $query->set_message( $messagePrefix . $keepLanguage . "\n\n" . $text );
130 $reply = $this->core->run_query( $query );
131
132 $result = $reply->result;
133 $responseType = 'text';
134
135 // If we sent JSON, we must get JSON back
136 if ( $isJson ) {
137 // First, try to extract JSON from markdown code blocks if present
138 $jsonPattern = '/```(?:json)?\s*\n?(.+?)\n?```/s';
139 if ( preg_match( $jsonPattern, $result, $matches ) ) {
140 $result = trim( $matches[1] );
141 }
142
143 // Now parse the JSON
144 $parsedJson = json_decode( $result, true );
145 if ( json_last_error() === JSON_ERROR_NONE ) {
146 // Validate that the JSON has the expected structure
147 if ( $blockType === 'core/list' && isset( $parsedJson['type'] ) && $parsedJson['type'] === 'list' && isset( $parsedJson['items'] ) ) {
148 $result = $parsedJson;
149 $responseType = 'json';
150 }
151 elseif ( $blockType === 'core/table' && isset( $parsedJson['type'] ) && $parsedJson['type'] === 'table' && isset( $parsedJson['rows'] ) ) {
152 $result = $parsedJson;
153 $responseType = 'json';
154 }
155 else {
156 // JSON is valid but doesn't match expected structure
157 error_log( 'AI Engine: JSON response does not match expected structure for block type: ' . $blockType );
158 throw new Exception( 'Invalid JSON structure returned by AI' );
159 }
160 }
161 else {
162 // JSON parsing failed
163 error_log( 'AI Engine: Failed to parse AI response as JSON. Error: ' . json_last_error_msg() );
164 error_log( 'AI Engine: Raw response: ' . $result );
165 throw new Exception( 'AI did not return valid JSON' );
166 }
167 }
168
169 return [
170 'mode' => 'replace',
171 'type' => $responseType,
172 'result' => $result,
173 'results' => $reply->results
174 ];
175 }
176
177 /**
178 * Handles the correction of text by checking and correcting grammatical errors.
179 */
180 public function action_correctText( $value, $arguments ) {
181 $prompt = apply_filters( 'mwai_prompt_correctText', "Correct the typos and grammar mistakes in this text without altering its content. Ensure the reply is in the same language as the original text.\n\n", $arguments );
182 return $this->processTextAction( $arguments, $prompt );
183 }
184
185 /**
186 * Enhances the text's readability and quality.
187 */
188 public function action_enhanceText( $value, $arguments ) {
189 $prompt = apply_filters( 'mwai_prompt_enhanceText', "Enhance this text by improving readability and quality, using a more suitable vocabulary, and refining its structure.\n\n", $arguments );
190 return $this->processTextAction( $arguments, $prompt );
191 }
192
193 /**
194 * Lengthens the text to improve readability.
195 */
196 public function action_longerText( $value, $arguments ) {
197 $prompt = apply_filters( 'mwai_prompt_longerText', "Expand the subsequent text to a minimum of three times its original length, integrating relevant and accurate information to enrich its content. If the text is a story, amplify its charm by elaborating on essential aspects, enhancing readability, and creating a sense of engagement for the reader. Maintain consistency in tone and vocabulary throughout the expansion process.\n\n", $arguments );
198 return $this->processTextAction( $arguments, $prompt );
199 }
200
201 /**
202 * Shortens the text to improve readability.
203 */
204 public function action_shorterText( $value, $arguments ) {
205 $prompt = apply_filters( 'mwai_prompt_shorterText', "Condense the following text by reducing its length to half, while retaining the core elements of the original narrative. Focus on maintaining the essence of the story and its key details.\n\n", $arguments );
206 return $this->processTextAction( $arguments, $prompt );
207 }
208
209 /**
210 * Suggests synonyms for selected words in the text.
211 */
212 public function action_suggestSynonyms( $value, $arguments ) {
213 $postId = $arguments['postId'];
214 $selectedText = $arguments['selectedText'];
215 $query = new Meow_MWAI_Query_Text( '', 1024 );
216 $query->set_scope( 'admin-tools' );
217 $language = $keepLanguage = '';
218 if ( !empty( $postId ) ) {
219 $language = $this->core->get_post_language( $postId );
220 $keepLanguage = " Ensure the reply is in the same language as the original text ({$language}).";
221 }
222 $prompt = apply_filters( 'mwai_prompt_suggestSynonyms', "Provide 5 synonyms or 5 ways of rephrasing the given word or sentence while retaining the original meaning and preserving the initial and final punctuation and spacing if any. Offer only the resulting word or expression, without additional context. If a suitable synonym or alternative cannot be identified, ensure that a creative response is still provided. Separate every suggestion with a new line, and that's it." . $keepLanguage . "\n\n", $arguments );
223 $query->set_message( $prompt . $selectedText );
224 $query->set_temperature( 1 );
225 $reply = $this->core->run_query( $query );
226 $lines = explode( "\n", $reply->result );
227 $results = [];
228 foreach ( $lines as $line ) {
229 $trimmed = trim( $line );
230 if ( !empty( $trimmed ) ) {
231 $results[] = $trimmed;
232 }
233 }
234 return [
235 'mode' => 'suggest',
236 'type' => $reply->type,
237 'result' => $results[0] ?? '',
238 'results' => $results
239 ];
240 }
241
242 /**
243 * Generates an image relevant to the text.
244 */
245 public function action_generateImage( $value, $arguments ) {
246 global $mwai;
247 $postId = $arguments['postId'];
248 $text = $arguments['text'];
249 $prompt = apply_filters( 'mwai_prompt_generateImage', "Generate an image that is relevant to the following text:\n\n", $arguments );
250 $message = $prompt . $text;
251 $media = $mwai->imageQueryForMediaLibrary( $message, $params = [], $postId );
252 return [
253 'mode' => 'insertMedia',
254 'type' => 'image',
255 'media' => $media
256 ];
257 }
258
259 /**
260 * Translates the specified text of text to the target language.
261 *
262 * @param mixed $value Unused parameter
263 * @param array $arguments Contains postId, text, and context
264 * @return array Translation result
265 */
266 public function action_translateSection( $value, $arguments ) {
267 $postId = $arguments['postId'];
268 $text = $arguments['text'];
269
270 if ( empty( $text ) ) {
271 return [
272 'mode' => 'replace',
273 'type' => 'text',
274 'result' => '',
275 'results' => []
276 ];
277 }
278
279 $context = $arguments['context'];
280 $targetLanguage = $this->core->get_post_language( $postId );
281 $query = new Meow_MWAI_Query_Text( '', 1024 );
282 $query->set_scope( 'admin-tools' );
283 $prompt = "Translate the following section into {$targetLanguage}:\n\n" .
284 "[SECTION TO TRANSLATE]\n{$text}\n[END SECTION TO TRANSLATE]\n\n" .
285 "Translation guidelines:\n" .
286 "1. Maintain the original tone, mood, and nuance.\n" .
287 "2. Preserve the intended meaning as accurately as possible.\n" .
288 "3. Ensure the translation fits seamlessly within the broader context.\n" .
289 "4. Use appropriate idiomatic expressions in the target language when applicable.\n" .
290 "5. Maintain any formatting or special characters present in the original text.\n\n" .
291 "Broader context (for reference only, do not translate):\n\n" .
292 "[CONTEXT]\n{$context}\n[END CONTEXT]\n\n" .
293 "Provide only the translated section, between the markers [TRANSLATED SECTION] and [END TRANSLATED SECTION], without any additional content. Do not include the markers [TRANSLATED SECTION] and [END TRANSLATED SECTION] in your reply!\n\n";
294 $prompt = apply_filters( 'mwai_prompt_translateSection', $prompt, $arguments );
295 $query->set_message( $prompt );
296 $reply = $this->core->run_query( $query );
297
298 // Clean up the result, just in case...
299 $result = $reply->result;
300 $result = str_replace( '[TRANSLATED SECTION]', '', $result );
301 $result = str_replace( '[END TRANSLATED SECTION]', '', $result );
302 $result = trim( $result );
303 $results = [];
304 foreach ( $reply->results as $r ) {
305 $r = str_replace( '[TRANSLATED SECTION]', '', $r );
306 $r = str_replace( '[END TRANSLATED SECTION]', '', $r );
307 $r = trim( $r );
308 $results[] = $r;
309 }
310
311 return [
312 'mode' => 'replace',
313 'type' => $reply->type,
314 'result' => $result,
315 'results' => $results
316 ];
317 }
318
319 /**
320 * Translates the text to the specified language.
321 */
322 public function action_translateText( $value, $arguments ) {
323 $postId = $arguments['postId'];
324 $text = $arguments['text'];
325 $language = $this->core->get_post_language( $postId );
326 $query = new Meow_MWAI_Query_Text( '', 1024 );
327 $query->set_scope( 'admin-tools' );
328 $prompt = apply_filters( 'mwai_prompt_translateText', "Translate the text into {$language}, preserving the tone, mood, and nuance, while staying as true as possible to the original meaning. Provide only the translated text, without any additional content.\n\n", $arguments );
329 $query->set_message( $prompt . $text );
330 $reply = $this->core->run_query( $query );
331 return [
332 'mode' => 'replace',
333 'type' => $reply->type,
334 'result' => $reply->result,
335 'results' => $reply->results
336 ];
337 }
338
339 /**
340 * Suggests SEO-optimized excerpts for the text.
341 */
342 public function action_suggestExcerpts( $value, $arguments ) {
343 $postId = $arguments['postId'];
344 $text = $this->core->get_post_content( $postId );
345 $query = new Meow_MWAI_Query_Text( '', 1024 );
346 $query->set_scope( 'admin-tools' );
347 $prompt = apply_filters( 'mwai_prompt_suggestExcerpts', "Craft a clear, SEO-optimized introduction for the following text, using 120 to 170 characters. Ensure the introduction is concise and relevant, without including any URLs.\n\n", $arguments );
348 $query->set_message( $prompt . $text );
349 $query->set_max_results( 5 );
350 $reply = $this->core->run_query( $query );
351 return [
352 'mode' => 'suggest',
353 'type' => $reply->type,
354 'result' => $reply->result,
355 'results' => $reply->results
356 ];
357 }
358
359 /**
360 * Suggests SEO-optimized titles for the text.
361 */
362 public function action_suggestTitles( $value, $arguments ) {
363 $postId = $arguments['postId'];
364 $text = $this->core->get_post_content( $postId );
365 $query = new Meow_MWAI_Query_Text( '', 1024 );
366 $query->set_scope( 'admin-tools' );
367 $prompt = apply_filters( 'mwai_prompt_suggestTitles', "Generate a concise, SEO-optimized title for the following text, without using quotes or any other formatting. Focus on clarity and relevance to the content.\n\n", $arguments );
368 $query->set_message( $prompt . $text );
369 $query->set_max_results( 5 );
370 $reply = $this->core->run_query( $query );
371 return [
372 'mode' => 'suggest',
373 'type' => $reply->type,
374 'result' => $reply->result,
375 'results' => $reply->results
376 ];
377 }
378 }
379