PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.8.8
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.8.8
3.6.2 3.6.1 3.6.0 3.5.9 3.5.8 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 / rest.php
ai-engine / classes Last commit date
data 1 year ago engines 1 year ago exceptions 1 year ago modules 1 year ago query 1 year ago rest 1 year ago services 1 year ago admin.php 1 year ago api.php 1 year ago core.php 1 year ago discussion.php 1 year ago event.php 1 year ago init.php 1 year ago logging.php 1 year ago reply.php 1 year ago rest.php 1 year ago
rest.php
1282 lines
1 <?php
2
3 class Meow_MWAI_Rest {
4 private $core = null;
5 private $namespace = 'mwai/v1';
6
7 public function __construct( $core ) {
8 $this->core = $core;
9 add_action( 'rest_api_init', [ $this, 'rest_init' ] );
10 }
11
12 /**
13 * Retrieve the message from the parameters and optionally sanitize it.
14 *
15 * @param array &$params The parameters array, passed by reference.
16 * @param bool $sanitize Whether to sanitize the message using sanitize_text_field.
17 * @return string The retrieved (and optionally sanitized) message.
18 */
19 public function retrieve_message( &$params, $sanitize = false ): string {
20 if ( isset( $params['message'] ) ) {
21 $message = $params['message'];
22 }
23 elseif ( isset( $params['prompt'] ) ) {
24 $message = $params['prompt'];
25 unset( $params['prompt'] );
26 $params['message'] = $message;
27 Meow_MWAI_Logging::deprecated( '"prompt" is deprecated, please use "message" instead.' );
28 }
29 else {
30 $message = '';
31 }
32
33 if ( $sanitize ) {
34 $message = sanitize_text_field( $message );
35 }
36
37 return $message;
38 }
39
40 /**
41 * Helper method to create REST responses with automatic token refresh
42 *
43 * @param array $data The response data
44 * @param int $status HTTP status code
45 * @return WP_REST_Response
46 */
47 protected function create_rest_response( $data, $status = 200 ) {
48 // Always check if we need to provide a new nonce
49 $current_nonce = $this->core->get_nonce( true );
50 $request_nonce = isset( $_SERVER['HTTP_X_WP_NONCE'] ) ? $_SERVER['HTTP_X_WP_NONCE'] : null;
51
52 // Check if nonce is approaching expiration (WordPress nonces last 12-24 hours)
53 // We'll refresh if the nonce is older than 10 hours to be safe
54 $should_refresh = false;
55
56 if ( $request_nonce ) {
57 // Try to determine the age of the nonce
58 // WordPress uses a tick system where each tick is 12 hours
59 // If we're in the second half of the nonce's life, refresh it
60 $time = time();
61 $nonce_tick = wp_nonce_tick();
62
63 // Verify if the nonce is still valid but getting old
64 $verify = wp_verify_nonce( $request_nonce, 'wp_rest' );
65 if ( $verify === 2 ) {
66 // Nonce is valid but was generated 12-24 hours ago
67 $should_refresh = true;
68 if ( $this->core->get_option( 'debug_mode' ) ) {
69 error_log( '[MWAI] Token refresh: Nonce is 12-24 hours old, providing fresh token' );
70 }
71 }
72 }
73
74 // If the nonce has changed or should be refreshed, include the new one
75 if ( $should_refresh || ( $request_nonce && $current_nonce !== $request_nonce ) ) {
76 $data['new_token'] = $current_nonce;
77
78 // Log if debug mode is enabled
79 if ( $this->core->get_option( 'debug_mode' ) ) {
80 error_log( '[MWAI] Token refresh: Sending new token in response' );
81 }
82 }
83
84 return new WP_REST_Response( $data, $status );
85 }
86
87 public function rest_init() {
88 try {
89 // Session Endpoint
90 register_rest_route( $this->namespace, '/start_session', [
91 'methods' => 'POST',
92 'permission_callback' => [ $this->core, 'can_start_session' ],
93 'callback' => [ $this, 'rest_start_session' ],
94 ] );
95
96 // Settings Endpoints
97 register_rest_route( $this->namespace, '/settings/update', [
98 'methods' => 'POST',
99 'permission_callback' => [ $this->core, 'can_access_settings' ],
100 'callback' => [ $this, 'rest_settings_update' ],
101 ] );
102 register_rest_route( $this->namespace, '/settings/options', [
103 'methods' => 'GET',
104 'permission_callback' => [ $this->core, 'can_access_settings' ],
105 'callback' => [ $this, 'rest_settings_list' ],
106 ] );
107 register_rest_route( $this->namespace, '/settings/reset', [
108 'methods' => 'POST',
109 'permission_callback' => [ $this->core, 'can_access_settings' ],
110 'callback' => [ $this, 'rest_settings_reset' ],
111 ] );
112 register_rest_route( $this->namespace, '/settings/chatbots', [
113 'methods' => ['GET', 'POST'],
114 'permission_callback' => [ $this->core, 'can_access_settings' ],
115 'callback' => [ $this, 'rest_settings_chatbots' ],
116 ] );
117 register_rest_route( $this->namespace, '/settings/themes', [
118 'methods' => ['GET', 'POST'],
119 'permission_callback' => [ $this->core, 'can_access_settings' ],
120 'callback' => [ $this, 'rest_settings_themes' ],
121 ] );
122
123 // System Endpoints
124 register_rest_route( $this->namespace, '/system/logs/list', [
125 'methods' => 'POST',
126 'permission_callback' => [ $this->core, 'can_access_settings' ],
127 'callback' => [ $this, 'rest_system_logs_list' ],
128 ] );
129 register_rest_route( $this->namespace, '/system/logs/delete', [
130 'methods' => 'POST',
131 'permission_callback' => [ $this->core, 'can_access_settings' ],
132 'callback' => [ $this, 'rest_system_logs_delete' ],
133 ] );
134 register_rest_route( $this->namespace, '/system/logs/meta', [
135 'methods' => 'POST',
136 'permission_callback' => [ $this->core, 'can_access_settings' ],
137 'callback' => [ $this, 'rest_system_logs_meta_get' ],
138 ] );
139 register_rest_route( $this->namespace, '/system/logs/activity', [
140 'methods' => 'POST',
141 'permission_callback' => [ $this->core, 'can_access_settings' ],
142 'callback' => [ $this, 'rest_system_logs_activity' ],
143 ] );
144 register_rest_route( $this->namespace, '/system/logs/activity_daily', [
145 'methods' => 'POST',
146 'permission_callback' => [ $this->core, 'can_access_settings' ],
147 'callback' => [ $this, 'rest_system_logs_activity_daily' ],
148 ] );
149 register_rest_route( $this->namespace, '/system/templates', [
150 'methods' => 'POST',
151 'permission_callback' => [ $this->core, 'can_access_features' ],
152 'callback' => [ $this, 'rest_system_templates_save' ],
153 ] );
154 register_rest_route( $this->namespace, '/system/templates', [
155 'methods' => 'GET',
156 'permission_callback' => [ $this->core, 'can_access_features' ],
157 'callback' => [ $this, 'rest_system_templates_get' ],
158 ] );
159
160 // AI Endpoints
161 register_rest_route( $this->namespace, '/ai/models', [
162 'methods' => 'POST',
163 'permission_callback' => [ $this->core, 'can_access_features' ],
164 'callback' => [ $this, 'rest_ai_models' ],
165 ] );
166 register_rest_route( $this->namespace, '/ai/test_connection', [
167 'methods' => 'POST',
168 'permission_callback' => [ $this->core, 'can_access_settings' ],
169 'callback' => [ $this, 'rest_ai_test_connection' ],
170 ] );
171 register_rest_route( $this->namespace, '/ai/completions', [
172 'methods' => 'POST',
173 'permission_callback' => [ $this->core, 'can_access_features' ],
174 'callback' => [ $this, 'rest_ai_completions' ],
175 ] );
176 register_rest_route( $this->namespace, '/ai/images', [
177 'methods' => 'POST',
178 'permission_callback' => [ $this->core, 'can_access_features' ],
179 'callback' => [ $this, 'rest_ai_images' ],
180 ] );
181 register_rest_route( $this->namespace, '/ai/image_edit', [
182 'methods' => 'POST',
183 'permission_callback' => [ $this->core, 'can_access_features' ],
184 'callback' => [ $this, 'rest_ai_image_edit' ],
185 ] );
186 register_rest_route( $this->namespace, '/ai/copilot', [
187 'methods' => 'POST',
188 'permission_callback' => [ $this->core, 'can_access_features' ],
189 'callback' => [ $this, 'rest_ai_copilot' ],
190 ] );
191
192 register_rest_route( $this->namespace, '/ai/magic_wand', [
193 'methods' => 'POST',
194 'callback' => [ $this, 'rest_ai_magic_wand' ],
195 'permission_callback' => [ $this->core, 'can_access_features' ],
196 ] );
197 register_rest_route( $this->namespace, '/ai/moderate', [
198 'methods' => 'POST',
199 'permission_callback' => [ $this->core, 'can_access_settings' ],
200 'callback' => [ $this, 'rest_ai_moderate' ],
201 ] );
202 register_rest_route( $this->namespace, '/ai/transcribe_audio', [
203 'methods' => 'POST',
204 'permission_callback' => [ $this->core, 'can_access_settings' ],
205 'callback' => [ $this, 'rest_ai_transcribe_audio' ],
206 ] );
207 register_rest_route( $this->namespace, '/ai/transcribe_image', [
208 'methods' => 'POST',
209 'permission_callback' => [ $this->core, 'can_access_settings' ],
210 'callback' => [ $this, 'rest_ai_transcribe_image' ],
211 ] );
212 register_rest_route( $this->namespace, '/ai/json', [
213 'methods' => 'POST',
214 'permission_callback' => [ $this->core, 'can_access_settings' ],
215 'callback' => [ $this, 'rest_ai_json' ],
216 ] );
217
218 // MCP Endpoints
219 register_rest_route( $this->namespace, '/mcp/functions', [
220 'methods' => 'GET',
221 'permission_callback' => [ $this->core, 'can_access_settings' ],
222 'callback' => [ $this, 'rest_mcp_functions' ],
223 ] );
224
225 // Helpers Endpoints
226 register_rest_route( $this->namespace, '/helpers/update_post_title', [
227 'methods' => 'POST',
228 'permission_callback' => [ $this->core, 'can_access_features' ],
229 'callback' => [ $this, 'rest_helpers_update_title' ],
230 ] );
231 register_rest_route( $this->namespace, '/helpers/update_post_excerpt', [
232 'methods' => 'POST',
233 'permission_callback' => [ $this->core, 'can_access_features' ],
234 'callback' => [ $this, 'rest_helpers_update_excerpt' ],
235 ] );
236 register_rest_route( $this->namespace, '/helpers/create_post', [
237 'methods' => 'POST',
238 'permission_callback' => [ $this->core, 'can_access_features' ],
239 'callback' => [ $this, 'rest_helpers_create_post' ],
240 ] );
241 register_rest_route( $this->namespace, '/helpers/create_image', [
242 'methods' => 'POST',
243 'permission_callback' => [ $this->core, 'can_access_features' ],
244 'callback' => [ $this, 'rest_helpers_create_images' ],
245 ] );
246 register_rest_route( $this->namespace, '/helpers/generate_image_meta', [
247 'methods' => 'POST',
248 'permission_callback' => [ $this->core, 'can_access_features' ],
249 'callback' => [ $this, 'rest_helpers_generate_image_meta' ],
250 ] );
251 register_rest_route( $this->namespace, '/helpers/count_posts', [
252 'methods' => 'GET',
253 'permission_callback' => [ $this->core, 'can_access_features' ],
254 'callback' => [ $this, 'rest_helpers_count_posts' ],
255 ] );
256 register_rest_route( $this->namespace, '/helpers/posts_ids', [
257 'methods' => 'GET',
258 'permission_callback' => [ $this->core, 'can_access_features' ],
259 'callback' => [ $this, 'rest_helpers_posts_ids' ],
260 ] );
261 register_rest_route( $this->namespace, '/helpers/post_types', [
262 'methods' => 'GET',
263 'permission_callback' => [ $this->core, 'can_access_features' ],
264 'callback' => [ $this, 'rest_helpers_post_types' ],
265 ] );
266 register_rest_route( $this->namespace, '/helpers/post_content', [
267 'methods' => 'GET',
268 'permission_callback' => [ $this->core, 'can_access_features' ],
269 'callback' => [ $this, 'rest_helpers_post_content' ],
270 ] );
271 register_rest_route( $this->namespace, '/helpers/run_tasks', [
272 'methods' => 'POST',
273 'permission_callback' => [ $this->core, 'can_access_features' ],
274 'callback' => [ $this, 'rest_helpers_run_tasks' ],
275 ] );
276
277 // OpenAI Endpoints
278 register_rest_route( $this->namespace, '/openai/files/list', [
279 'methods' => 'GET',
280 'permission_callback' => [ $this->core, 'can_access_settings' ],
281 'callback' => [ $this, 'rest_openai_files_get' ],
282 ] );
283 register_rest_route( $this->namespace, '/openai/files/upload', [
284 'methods' => 'POST',
285 'permission_callback' => [ $this->core, 'can_access_settings' ],
286 'callback' => [ $this, 'rest_openai_files_upload' ],
287 ] );
288 register_rest_route( $this->namespace, '/openai/files/delete', [
289 'methods' => 'POST',
290 'permission_callback' => [ $this->core, 'can_access_settings' ],
291 'callback' => [ $this, 'rest_openai_files_delete' ],
292 ] );
293 register_rest_route( $this->namespace, '/openai/files/download', [
294 'methods' => 'POST',
295 'permission_callback' => [ $this->core, 'can_access_settings' ],
296 'callback' => [ $this, 'rest_openai_files_download' ],
297 ] );
298 register_rest_route( $this->namespace, '/openai/files/finetune', [
299 'methods' => 'POST',
300 'permission_callback' => [ $this->core, 'can_access_settings' ],
301 'callback' => [ $this, 'rest_openai_files_finetune' ],
302 ] );
303 register_rest_route( $this->namespace, '/openai/finetunes/list_deleted', [
304 'methods' => 'GET',
305 'permission_callback' => [ $this->core, 'can_access_settings' ],
306 'callback' => [ $this, 'rest_openai_deleted_finetunes_get' ],
307 ] );
308
309 // register_rest_route( $this->namespace, '/openai/models', array(
310 // 'methods' => 'GET',
311 // 'permission_callback' => [ $this->core, 'can_access_settings' ],
312 // 'callback' => [ $this, 'rest_openai_models_get' ],
313 // ) );
314
315 register_rest_route( $this->namespace, '/openai/finetunes/list', [
316 'methods' => 'GET',
317 'permission_callback' => [ $this->core, 'can_access_settings' ],
318 'callback' => [ $this, 'rest_openai_finetunes_get' ],
319 ] );
320 register_rest_route( $this->namespace, '/openai/finetunes/delete', [
321 'methods' => 'POST',
322 'permission_callback' => [ $this->core, 'can_access_settings' ],
323 'callback' => [ $this, 'rest_openai_finetunes_delete' ],
324 ] );
325 register_rest_route( $this->namespace, '/openai/finetunes/cancel', [
326 'methods' => 'POST',
327 'permission_callback' => [ $this->core, 'can_access_settings' ],
328 'callback' => [ $this, 'rest_openai_finetunes_cancel' ],
329 ] );
330
331 // Logging Endpoints
332 register_rest_route( $this->namespace, '/get_logs', [
333 'methods' => 'GET',
334 'permission_callback' => [ $this->core, 'can_access_features' ],
335 'callback' => [ $this, 'rest_get_logs' ]
336 ] );
337 register_rest_route( $this->namespace, '/clear_logs', [
338 'methods' => 'GET',
339 'permission_callback' => [ $this->core, 'can_access_features' ],
340 'callback' => [ $this, 'rest_clear_logs' ]
341 ] );
342 }
343 catch ( Exception $e ) {
344 Meow_MWAI_Logging::error( 'REST API initialization failed: ' . $e->getMessage() );
345 }
346 }
347
348 public function rest_start_session() {
349 try {
350 $sessionId = $this->core->get_session_id();
351 $restNonce = $this->core->get_nonce( true );
352
353 $response = [
354 'success' => true,
355 'sessionId' => $sessionId,
356 'restNonce' => $restNonce
357 ];
358
359 // If in test mode and we have a new token, it will be added by create_rest_response
360 // But we also want to ensure the restNonce matches the test token if available
361 if ( get_option( 'mwai_token_test_mode' ) ) {
362 $token_data = get_option( 'mwai_test_token_data' );
363 if ( $token_data && isset( $token_data['token'] ) ) {
364 $response['restNonce'] = $token_data['token'];
365 }
366 }
367
368 return $this->create_rest_response( $response, 200 );
369 }
370 catch ( Exception $e ) {
371 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
372 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
373 }
374 }
375
376 public function rest_settings_list() {
377 return $this->create_rest_response( [
378 'success' => true,
379 'options' => $this->core->get_all_options()
380 ], 200 );
381 }
382
383 public function rest_settings_update( $request ) {
384 try {
385 $params = $request->get_json_params();
386 $value = $params['options'];
387 $options = $this->core->update_options( $value );
388 $success = !!$options;
389 $message = __( $success ? 'OK' : 'Could not update options.', 'ai-engine' );
390 return $this->create_rest_response( [ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
391 }
392 catch ( Exception $e ) {
393 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
394 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
395 }
396 }
397
398 public function rest_settings_reset() {
399 try {
400 $options = $this->core->reset_options();
401 $success = !!$options;
402 $message = __( $success ? 'OK' : 'Could not reset options.', 'ai-engine' );
403 return $this->create_rest_response( [ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
404 }
405 catch ( Exception $e ) {
406 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
407 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
408 }
409 }
410
411 public function rest_ai_models( $request ) {
412 try {
413 $params = $request->get_json_params();
414 $envId = $params['envId'];
415 $engine = Meow_MWAI_Engines_Factory::get( $this->core, $envId );
416 $models = $engine->retrieve_models();
417 return $this->create_rest_response( [ 'success' => true, 'models' => $models ], 200 );
418 }
419 catch ( Exception $e ) {
420 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
421 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
422 }
423 }
424
425 public function rest_ai_test_connection( $request ) {
426 try {
427 $params = $request->get_json_params();
428 $envId = $params['env_id'];
429
430 // Get the environment details
431 $env = null;
432 $envs = $this->core->get_option( 'ai_envs' );
433 foreach ( $envs as $e ) {
434 if ( $e['id'] === $envId ) {
435 $env = $e;
436 break;
437 }
438 }
439
440 if ( !$env ) {
441 throw new Exception( 'Environment not found.' );
442 }
443
444 // Get the engine and test connection
445 $engine = Meow_MWAI_Engines_Factory::get( $this->core, $envId );
446 $result = $engine->connection_check();
447
448 // Format the response based on provider
449 $response = [
450 'success' => true,
451 'provider' => $env['type'],
452 'name' => $env['name'],
453 'data' => $result
454 ];
455
456 return $this->create_rest_response( $response, 200 );
457 }
458 catch ( Exception $e ) {
459 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
460 return $this->create_rest_response( [
461 'success' => false,
462 'error' => $message,
463 'provider' => isset( $env ) ? $env['type'] : 'unknown'
464 ], 200 ); // Return 200 even on error for consistent modal display
465 }
466 }
467
468 public function rest_ai_completions( $request ) {
469 try {
470 $params = $request->get_json_params();
471 $message = $this->retrieve_message( $params );
472 $query = new Meow_MWAI_Query_Text( $message );
473 $query->inject_params( $params );
474
475 // Handle streaming
476 $stream = $params['stream'] ?? false;
477 $streamCallback = null;
478 if ( $stream ) {
479 $streamCallback = function ( $reply ) use ( $query ) {
480 //$raw = _wp_specialchars( $reply, ENT_NOQUOTES, 'UTF-8', true );
481 $raw = $reply;
482 $this->core->stream_push( [ 'type' => 'live', 'data' => $raw ], $query );
483 if ( ob_get_level() > 0 ) {
484 ob_flush();
485 }
486 flush();
487 };
488 if ( headers_sent( $filename, $linenum ) ) {
489 throw new Exception( "Headers already sent in $filename on line $linenum. Cannot start streaming." );
490 }
491 header( 'Cache-Control: no-cache' );
492 header( 'Content-Type: text/event-stream' );
493 header( 'X-Accel-Buffering: no' ); // This is useful to disable buffering in nginx through headers.
494 ob_implicit_flush( true );
495 if ( ob_get_level() > 0 ) {
496 ob_end_flush();
497 }
498 }
499
500 // Process Reply
501 $reply = $this->core->run_query( $query, $streamCallback );
502 $restRes = [
503 'success' => true,
504 'data' => $reply->result,
505 'usage' => $reply->usage
506 ];
507 if ( $stream ) {
508 $this->core->stream_push( [ 'type' => 'end', 'data' => json_encode( $restRes ) ], $query );
509 die();
510 }
511 return $this->create_rest_response( $restRes, 200 );
512 }
513 catch ( Exception $e ) {
514 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
515 if ( $stream ) {
516 $this->core->stream_push( [ 'type' => 'error', 'data' => $message ], $query );
517 }
518 else {
519 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
520 }
521 }
522 }
523
524 public function rest_ai_images( $request ) {
525 try {
526 $params = $request->get_json_params();
527 $message = $this->retrieve_message( $params );
528 $query = new Meow_MWAI_Query_Image( $message );
529 $query->inject_params( $params );
530 $reply = $this->core->run_query( $query );
531 return $this->create_rest_response( [ 'success' => true, 'data' => $reply->results, 'usage' => $reply->usage ], 200 );
532 }
533 catch ( Exception $e ) {
534 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
535 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
536 }
537 }
538
539 public function rest_ai_image_edit( $request ) {
540 try {
541 // Check if this is a multipart request with files
542 $files = $request->get_file_params();
543 $params = null;
544
545 // Log all request data
546 error_log( 'Image Edit Request - Method: ' . $request->get_method() );
547 $content_type = $request->get_content_type();
548 if ( is_array( $content_type ) ) {
549 error_log( 'Image Edit Request - Content-Type: ' . $content_type['value'] );
550 }
551 else {
552 error_log( 'Image Edit Request - Content-Type: ' . $content_type );
553 }
554 error_log( 'Image Edit Request - Has files: ' . ( !empty( $files ) ? 'yes (' . count( $files ) . ')' : 'no' ) );
555
556 if ( !empty( $files ) ) {
557 // Handle multipart form data - get all params including POST data
558 $params = $request->get_params();
559 error_log( 'Image Edit Request - Using form data params' );
560 }
561 else {
562 // Try to get body params first (for form data without files)
563 $body_params = $request->get_body_params();
564 if ( !empty( $body_params ) ) {
565 $params = $body_params;
566 error_log( 'Image Edit Request - Using body params' );
567 }
568 else {
569 // Handle JSON request
570 $params = $request->get_json_params();
571 error_log( 'Image Edit Request - Using JSON params' );
572 }
573 }
574
575 // Ensure params is always an array
576 if ( empty( $params ) ) {
577 $params = [];
578 }
579
580 // Debug logging
581 error_log( 'Image Edit Request - Has files: ' . ( !empty( $files ) ? 'yes' : 'no' ) );
582 error_log( 'Image Edit Request - Params: ' . json_encode( $params ) );
583
584 $message = $this->retrieve_message( $params );
585 $mediaId = isset( $params['mediaId'] ) ? intval( $params['mediaId'] ) : 0;
586 $query = new Meow_MWAI_Query_EditImage( $message );
587
588 // The inject_params method will handle setting the file from mediaId
589 $query->inject_params( $params );
590
591 // Handle mask file if provided
592 if ( !empty( $files['mask'] ) ) {
593 $mask_file = $files['mask'];
594 if ( $mask_file['error'] === UPLOAD_ERR_OK ) {
595 $mask_data = file_get_contents( $mask_file['tmp_name'] );
596 $query->set_mask( Meow_MWAI_Query_DroppedFile::from_data( $mask_data, 'vision', $mask_file['type'] ) );
597 }
598 }
599
600 $reply = $this->core->run_query( $query );
601 return $this->create_rest_response( [ 'success' => true, 'data' => $reply->results, 'usage' => $reply->usage ], 200 );
602 }
603 catch ( Exception $e ) {
604 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
605 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
606 }
607 }
608
609 public function rest_ai_magic_wand( $request ) {
610 try {
611 $params = $request->get_json_params();
612 $action = isset( $params['action'] ) ? $params['action'] : null;
613 $data = isset( $params['data'] ) ? $params['data'] : null;
614 if ( empty( $data ) || empty( $action ) ) {
615 return $this->create_rest_response( [ 'success' => false, 'message' => 'An action and some data are required.' ], 500 );
616 }
617 $data = apply_filters( 'mwai_magic_wand_' . $action, '', $data );
618 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
619 }
620 catch ( Exception $e ) {
621 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
622 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
623 }
624 }
625
626 public function rest_ai_copilot( $request ) {
627 try {
628 $params = $request->get_json_params();
629 $action = sanitize_text_field( $params['action'] );
630 $message = $this->retrieve_message( $params, true );
631 $context = sanitize_text_field( $params['context'] );
632 $postId = !empty( $params['postId'] ) ? intval( $params['postId'] ) : null;
633 if ( empty( $action ) || empty( $message ) ) {
634 return $this->create_rest_response( [ 'success' => false, 'message' => 'Copilot needs an action and a prompt.' ], 500 );
635 }
636
637 global $mwai;
638 $result = null;
639 $params = [ 'scope' => 'copilot' ];
640
641 if ( $action === 'text' ) {
642 $prompt = "Here is the current article: \n\n===\n\n" . $context . "\n\n===\n\nIn this article, instead of the [== CURRENT BLOCK ==] placeholder, the author needs additional content. This new content should use the same tone, style, context, it should naturally flow in the article. The author shared additional information for this request:\n\n===\n\n" . $message . "\n\n===\n\nPlease provide the additional content. Only output the additional content, not the entire article, no need for extra information, and no need for the placeholders. Only output the content that should be added.";
643 if ( !empty( $model ) ) {
644 $params['model'] = $model;
645 }
646 $result = $mwai->simpleTextQuery( $prompt, $params );
647 }
648 else if ( $action === 'image' ) {
649 $prompt = "Here is the current article: \n\n===\n\n" . $context . "\n\n===\n\nIn this article, instead of the [== CURRENT BLOCK ==] placeholder, the author needs an image. Please write a detailed description (prompt) for that image that would fit this context. The image should be relevant to the article. The author shared additional information for this request:\n\n===\n\n" . $message . "\n\n===\n\nPlease only output the description for the image, not the entire article, no need for extra information, and no need for the placeholders. Only output the description.";
650
651 // Create the image
652 $simplifiedPrompt = $mwai->simpleTextQuery( $prompt, $params );
653 $media = $mwai->imageQueryForMediaLibrary( $simplifiedPrompt, $params, $postId );
654 $result = [ 'media' => $media ];
655 }
656 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
657 }
658 catch ( Exception $e ) {
659 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
660 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
661 }
662 }
663
664 public function rest_helpers_update_title( $request ) {
665 try {
666 $params = $request->get_json_params();
667 $title = sanitize_text_field( $params['title'] );
668 $postId = intval( $params['postId'] );
669 $post = get_post( $postId );
670 if ( !$post ) {
671 throw new Exception( 'There is no post with this ID.' );
672 }
673 $post->post_title = $title;
674 //$post->post_name = sanitize_title( $title );
675 wp_update_post( $post );
676 return $this->create_rest_response( [ 'success' => true, 'message' => 'Title updated.' ], 200 );
677 }
678 catch ( Exception $e ) {
679 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
680 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
681 }
682 }
683
684 public function rest_helpers_update_excerpt( $request ) {
685 try {
686 $params = $request->get_json_params();
687 $excerpt = sanitize_text_field( $params['excerpt'] );
688 $postId = intval( $params['postId'] );
689 $post = get_post( $postId );
690 if ( !$post ) {
691 throw new Exception( 'There is no post with this ID.' );
692 }
693 $post->post_excerpt = $excerpt;
694 wp_update_post( $post );
695 return $this->create_rest_response( [ 'success' => true, 'message' => 'Excerpt updated.' ], 200 );
696 }
697 catch ( Exception $e ) {
698 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
699 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
700 }
701 }
702
703 public function rest_helpers_create_post( $request ) {
704 try {
705 $params = $request->get_json_params();
706 $title = sanitize_text_field( $params['title'] );
707 $content = sanitize_textarea_field( $params['content'] );
708 $excerpt = sanitize_text_field( $params['excerpt'] );
709 $postType = sanitize_text_field( $params['postType'] );
710 $post = new stdClass();
711 $post->post_title = $title;
712 $post->post_excerpt = $excerpt;
713 $post->post_content = $content;
714 $post->post_status = 'draft';
715 $post->post_type = isset( $postType ) ? $postType : 'post';
716 // TODO: Let's try to avoid using Markdown to create the Post
717 // Instead, we should create Gutenberg Blocks, or simple HTML.
718 // Then, we can get rid of the library for Markdown.
719 $post->post_content = $this->core->markdown_to_html( $post->post_content );
720 $postId = wp_insert_post( $post );
721 return $this->create_rest_response( [ 'success' => true, 'postId' => $postId ], 200 );
722 }
723 catch ( Exception $e ) {
724 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
725 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
726 }
727 }
728
729 public function rest_helpers_create_images( $request ) {
730 try {
731 $params = $request->get_json_params();
732 $title = sanitize_text_field( $params['title'] );
733 $caption = sanitize_text_field( $params['caption'] );
734 $alt = sanitize_text_field( $params['alt'] );
735 $description = sanitize_text_field( $params['description'] );
736 $url = $params['url'];
737 $filename = sanitize_text_field( $params['filename'] );
738 $attachmentId = $this->core->add_image_from_url( $url, $filename, $title, $description, $caption, $alt );
739 return $this->create_rest_response( [ 'success' => true, 'attachmentId' => $attachmentId ], 200 );
740 }
741 catch ( Exception $e ) {
742 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
743 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
744 }
745 }
746
747 public function rest_helpers_generate_image_meta( $request ) {
748 try {
749 global $mwai;
750 $params = $request->get_json_params();
751 $url = isset( $params['url'] ) ? esc_url_raw( $params['url'] ) : null;
752 if ( empty( $url ) ) {
753 throw new Exception( 'The url is required.' );
754 }
755 $prompt = 'Describe this image and suggest a short title, description and SEO-friendly (ASCII and lowercase) filename. '
756 . 'Return a JSON with the keys title, description, alt, caption, filename.';
757 $result = $mwai->simpleVisionQuery( $prompt, $url, null, [ 'image_remote_upload' => 'url', 'scope' => 'admin-tools' ] );
758 $result = preg_replace( '/^```json\s*/', '', $result );
759 $result = preg_replace( '/\s*```$/', '', $result );
760 if ( is_string( $result ) ) {
761 $data = json_decode( $result, true );
762 }
763 else {
764 $data = $result;
765 }
766 if ( !is_array( $data ) ) {
767 $data = [];
768 }
769 $data = array_merge( [ 'title' => '', 'description' => '', 'caption' => '', 'alt' => '', 'filename' => '' ], $data );
770 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
771 }
772 catch ( Exception $e ) {
773 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
774 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
775 }
776 }
777
778 public function rest_openai_files_get() {
779 try {
780 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
781 $purposeFilter = isset( $_GET['purpose'] ) ? $_GET['purpose'] : null;
782 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
783 $files = $openai->list_files( $purposeFilter );
784 return $this->create_rest_response( [ 'success' => true, 'files' => $files ], 200 );
785 }
786 catch ( Exception $e ) {
787 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
788 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
789 }
790 }
791
792 public function rest_openai_deleted_finetunes_get() {
793 try {
794 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
795 $legacy = isset( $_GET['legacy'] ) ? $_GET['legacy'] === 'true' : false;
796 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
797 $finetunes = $openai->list_deleted_finetunes( $legacy );
798 return $this->create_rest_response( [ 'success' => true, 'finetunes' => $finetunes ], 200 );
799 }
800 catch ( Exception $e ) {
801 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
802 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
803 }
804 }
805
806 public function rest_openai_finetunes_get() {
807 try {
808 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
809 $legacy = isset( $_GET['legacy'] ) ? $_GET['legacy'] === 'true' : false;
810 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
811 $finetunes = $openai->list_finetunes( $legacy );
812 return $this->create_rest_response( [ 'success' => true, 'finetunes' => $finetunes ], 200 );
813 }
814 catch ( Exception $e ) {
815 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
816 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
817 }
818 }
819
820 public function rest_openai_files_upload( $request ) {
821 try {
822 $params = $request->get_json_params();
823 $envId = $params['envId'];
824 ;
825 $filename = sanitize_text_field( $params['filename'] );
826 $data = $params['data'];
827 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
828 $file = $openai->upload_file( $filename, $data );
829 return $this->create_rest_response( [ 'success' => true, 'file' => $file ], 200 );
830 }
831 catch ( Exception $e ) {
832 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
833 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
834 }
835 }
836
837 public function rest_openai_files_delete( $request ) {
838 try {
839 $params = $request->get_json_params();
840 $envId = $params['envId'];
841 ;
842 $fileId = $params['fileId'];
843 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
844 $openai->delete_file( $fileId );
845 return $this->create_rest_response( [ 'success' => true ], 200 );
846 }
847 catch ( Exception $e ) {
848 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
849 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
850 }
851 }
852
853 public function rest_openai_finetunes_cancel( $request ) {
854 try {
855 $params = $request->get_json_params();
856 $envId = $params['envId'];
857 ;
858 $finetuneId = $params['finetuneId'];
859 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
860 $openai->cancel_finetune( $finetuneId );
861 return $this->create_rest_response( [ 'success' => true ], 200 );
862 }
863 catch ( Exception $e ) {
864 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
865 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
866 }
867 }
868
869 public function rest_openai_finetunes_delete( $request ) {
870 try {
871 $params = $request->get_json_params();
872 $envId = $params['envId'];
873 ;
874 $modelId = $params['modelId'];
875 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
876 $openai->delete_finetune( $modelId );
877 return $this->create_rest_response( [ 'success' => true ], 200 );
878 }
879 catch ( Exception $e ) {
880 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
881 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
882 }
883 }
884
885 public function rest_openai_files_download( $request ) {
886 try {
887 $params = $request->get_json_params();
888 $envId = $params['envId'];
889 ;
890 $fileId = $params['fileId'];
891 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
892 $filename = $openai->download_file( $fileId );
893 $data = file_get_contents( $filename );
894 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
895 }
896 catch ( Exception $e ) {
897 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
898 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
899 }
900 }
901
902 public function rest_openai_files_finetune( $request ) {
903 try {
904 $params = $request->get_json_params();
905 $envId = $params['envId'];
906 ;
907 $fileId = $params['fileId'];
908 $model = $params['model'];
909 $suffix = $params['suffix'];
910 $hyperparams = [
911 'nEpochs' => isset( $params['nEpochs'] ) ? $params['nEpochs'] : null,
912 'batchSize' => isset( $params['batchSize'] ) ? $params['batchSize'] : null,
913 ];
914 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
915 $finetune = $openai->run_finetune( $fileId, $model, $suffix, $hyperparams );
916 return $this->create_rest_response( [ 'success' => true, 'finetune' => $finetune ], 200 );
917 }
918 catch ( Exception $e ) {
919 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
920 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
921 }
922 }
923
924 public function rest_helpers_count_posts( $request ) {
925 try {
926 $params = $request->get_query_params();
927 $postType = $params['postType'];
928 $postStatus = !empty( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
929 $count = wp_count_posts( $postType );
930 $count = array_sum( array_intersect_key( (array) $count, array_flip( $postStatus ) ) );
931 return $this->create_rest_response( [ 'success' => true, 'count' => $count ], 200 );
932 }
933 catch ( Exception $e ) {
934 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
935 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
936 }
937 }
938
939 public function rest_helpers_posts_ids( $request ) {
940 try {
941 $params = $request->get_query_params();
942 $postType = $params['postType'];
943 $postStatus = !empty( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
944 $posts = get_posts( [
945 'posts_per_page' => -1,
946 'post_type' => $postType,
947 'post_status' => $postStatus,
948 'fields' => 'ids'
949 ] );
950 return $this->create_rest_response( [ 'success' => true, 'postIds' => $posts ], 200 );
951 }
952 catch ( Exception $e ) {
953 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
954 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
955 }
956 }
957
958 public function rest_helpers_post_content( $request ) {
959 try {
960 $params = $request->get_query_params();
961 $offset = (int) $params['offset'];
962 $postType = $params['postType'];
963 $postStatus = isset( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
964 $postId = (int) $params['postId'];
965
966 $post = null;
967 if ( !empty( $postId ) ) {
968 $post = get_post( $postId );
969 if ( $post->post_status !== 'publish' && $post->post_status !== 'future'
970 && $post->post_status !== 'draft' && $post->post_status !== 'private' ) {
971 $post = null;
972 }
973 }
974 else {
975 $posts = get_posts( [
976 'posts_per_page' => 1,
977 'post_type' => $postType,
978 'offset' => $offset,
979 'post_status' => $postStatus,
980 ] );
981 $post = count( $posts ) === 0 ? null : $posts[0];
982 }
983 if ( !$post ) {
984 return $this->create_rest_response( [ 'success' => false, 'message' => 'Post not found' ], 404 );
985 }
986 $cleanPost = $this->core->get_post( $post );
987 return $this->create_rest_response( [ 'success' => true, 'content' => $cleanPost['content'],
988 'checksum' => $cleanPost['checksum'], 'language' => $cleanPost['language'], 'excerpt' => $cleanPost['excerpt'],
989 'postId' => $cleanPost['postId'], 'title' => $cleanPost['title'], 'url' => $cleanPost['url'] ], 200 );
990 }
991 catch ( Exception $e ) {
992 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
993 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
994 }
995 }
996
997 public function rest_helpers_run_tasks( $request ) {
998 try {
999 do_action( 'mwai_tasks_run' );
1000 return $this->create_rest_response( [ 'success' => true ], 200 );
1001 }
1002 catch ( Exception $e ) {
1003 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1004 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1005 }
1006 }
1007
1008 public function rest_system_templates_get( $request ) {
1009 try {
1010 $params = $request->get_query_params();
1011 $category = $params['category'];
1012 $templates = [];
1013 $templates_option = get_option( 'mwai_templates', [] );
1014 if ( !is_array( $templates_option ) ) {
1015 update_option( 'mwai_templates', [] );
1016 }
1017 $categories = array_column( $templates_option, 'category' );
1018 $index = array_search( $category, $categories );
1019 $templates = [];
1020 if ( $index !== false ) {
1021 $templates = $templates_option[$index]['templates'];
1022 }
1023 return $this->create_rest_response( [ 'success' => true, 'templates' => $templates ], 200 );
1024 }
1025 catch ( Exception $e ) {
1026 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1027 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1028 }
1029 }
1030
1031 public function rest_system_templates_save( $request ) {
1032 try {
1033 $params = $request->get_json_params();
1034 $category = $params['category'];
1035 $templates = $params['templates'];
1036 $templates_option = get_option( 'mwai_templates', [] );
1037 $categories = array_column( $templates_option, 'category' );
1038 $index = array_search( $category, $categories );
1039 if ( $index !== false && $index >= 0 ) {
1040 $templates_option[$index]['templates'] = $templates;
1041 }
1042 else {
1043 $group = [ 'category' => $category, 'templates' => $templates ];
1044 $templates_option[] = $group;
1045 }
1046
1047 update_option( 'mwai_templates', $templates_option );
1048 return $this->create_rest_response( [ 'success' => true ], 200 );
1049 }
1050 catch ( Exception $e ) {
1051 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1052 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1053 }
1054 }
1055
1056 public function rest_system_logs_list( $request ) {
1057 try {
1058 $params = $request->get_json_params();
1059 $offset = $params['offset'];
1060 $limit = $params['limit'];
1061 $filters = $params['filters'];
1062 $sort = $params['sort'];
1063 $logs = apply_filters( 'mwai_stats_logs_list', [], $offset, $limit, $filters, $sort );
1064 return $this->create_rest_response( [ 'success' => true, 'total' => $logs['total'], 'logs' => $logs['rows'] ], 200 );
1065 }
1066 catch ( Exception $e ) {
1067 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1068 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1069 }
1070 }
1071
1072 public function rest_system_logs_delete( $request ) {
1073 try {
1074 $params = $request->get_json_params();
1075 $logIds = $params['logIds'];
1076 $success = apply_filters( 'mwai_stats_logs_delete', true, $logIds );
1077 return $this->create_rest_response( [ 'success' => $success ], 200 );
1078 }
1079 catch ( Exception $e ) {
1080 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1081 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1082 }
1083 }
1084
1085 public function rest_system_logs_meta_get( $request ) {
1086 try {
1087 $params = $request->get_json_params();
1088 $logId = $params['logId'];
1089 $metaKeys = $params['metaKeys'];
1090 $data = apply_filters( 'mwai_stats_logs_meta', [], $logId, $metaKeys );
1091 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1092 }
1093 catch ( Exception $e ) {
1094 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1095 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1096 }
1097 }
1098
1099 public function rest_system_logs_activity( $request ) {
1100 try {
1101 $params = $request->get_json_params();
1102 $hours = isset( $params['hours'] ) ? intval( $params['hours'] ) : 24;
1103 $data = apply_filters( 'mwai_stats_logs_activity', [], $hours );
1104 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1105 }
1106 catch ( Exception $e ) {
1107 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1108 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1109 }
1110 }
1111
1112 public function rest_system_logs_activity_daily( $request ) {
1113 try {
1114 $params = $request->get_json_params();
1115 $days = isset( $params['days'] ) ? intval( $params['days'] ) : 31;
1116 $byModel = isset( $params['byModel'] ) ? (bool) $params['byModel'] : false;
1117
1118 if ( $byModel ) {
1119 $data = apply_filters( 'mwai_stats_logs_activity_daily_by_model', [], $days );
1120 } else {
1121 $data = apply_filters( 'mwai_stats_logs_activity_daily', [], $days );
1122 }
1123
1124 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1125 }
1126 catch ( Exception $e ) {
1127 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1128 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1129 }
1130 }
1131
1132 public function rest_ai_moderate( $request ) {
1133 try {
1134 $params = $request->get_json_params();
1135 $envId = $params['envId'];
1136 $text = $params['text'];
1137 if ( !$text ) {
1138 return $this->create_rest_response( [ 'success' => false, 'message' => 'Text not found.' ], 404 );
1139 }
1140 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
1141 $results = $openai->moderate( $text );
1142 return $this->create_rest_response( [ 'success' => true, 'results' => $results ], 200 );
1143 }
1144 catch ( Exception $e ) {
1145 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1146 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1147 }
1148 }
1149
1150 public function rest_ai_transcribe_audio( $request ) {
1151 try {
1152 $params = $request->get_json_params();
1153 $query = new Meow_MWAI_Query_Transcribe();
1154 $query->inject_params( $params );
1155 $query->set_scope( 'admin-tools' );
1156 $reply = $this->core->run_query( $query );
1157 return $this->create_rest_response( [ 'success' => true, 'data' => $reply->result ], 200 );
1158 }
1159 catch ( Exception $e ) {
1160 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1161 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1162 }
1163 }
1164
1165 public function rest_ai_transcribe_image( $request ) {
1166 try {
1167 global $mwai;
1168 $params = $request->get_json_params();
1169 $message = $this->retrieve_message( $params );
1170 $url = !empty( $params['url'] ) ? $params['url'] : null;
1171 // This could lead to a security issue, so let's avoid using path directly.
1172 //$path = !empty( $params['path'] ) ? $params['path'] : null;
1173 $result = $mwai->simpleVisionQuery( $message, $url );
1174 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
1175 }
1176 catch ( Exception $e ) {
1177 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1178 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1179 }
1180 }
1181
1182 public function rest_ai_json( $request ) {
1183 try {
1184 global $mwai;
1185 $params = $request->get_json_params();
1186 $message = $this->retrieve_message( $params );
1187 $result = $mwai->simpleJsonQuery( $message );
1188 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
1189 }
1190 catch ( Exception $e ) {
1191 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1192 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1193 }
1194 }
1195
1196 public function rest_mcp_functions( $request ) {
1197 try {
1198 // Get all registered MCP tools
1199 $tools = apply_filters( 'mwai_mcp_tools', [] );
1200
1201 // Format the response
1202 $response = [
1203 'success' => true,
1204 'count' => count( $tools ),
1205 'functions' => $tools
1206 ];
1207
1208 return $this->create_rest_response( $response, 200 );
1209 }
1210 catch ( Exception $e ) {
1211 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1212 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1213 }
1214 }
1215
1216 public function rest_helpers_post_types() {
1217 try {
1218 $postTypes = $this->core->get_post_types();
1219 return $this->create_rest_response( [ 'success' => true, 'postTypes' => $postTypes ], 200 );
1220 }
1221 catch ( Exception $e ) {
1222 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1223 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1224 }
1225 }
1226
1227 public function rest_settings_themes( $request ) {
1228 try {
1229 $method = $request->get_method();
1230 if ( $method === 'GET' ) {
1231 $themes = $this->core->get_themes();
1232 return $this->create_rest_response( [ 'success' => true, 'themes' => $themes ], 200 );
1233 }
1234 else if ( $method === 'POST' ) {
1235 $params = $request->get_json_params();
1236 $themes = $params['themes'];
1237 $themes = $this->core->update_themes( $themes );
1238 return $this->create_rest_response( [ 'success' => true, 'themes' => $themes ], 200 );
1239 }
1240 }
1241 catch ( Exception $e ) {
1242 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1243 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1244 }
1245 }
1246
1247 public function rest_settings_chatbots( $request ) {
1248 try {
1249 $method = $request->get_method();
1250 if ( $method === 'GET' ) {
1251 $chatbots = $this->core->get_chatbots();
1252 return $this->create_rest_response( [ 'success' => true, 'chatbots' => $chatbots ], 200 );
1253 }
1254 else if ( $method === 'POST' ) {
1255 $params = $request->get_json_params();
1256 $chatbots = $params['chatbots'];
1257 $chatbots = $this->core->update_chatbots( $chatbots );
1258 return $this->create_rest_response( [ 'success' => true, 'chatbots' => $chatbots ], 200 );
1259 }
1260 return $this->create_rest_response( [ 'success' => false, 'message' => 'Method not allowed' ], 405 );
1261 }
1262 catch ( Exception $e ) {
1263 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1264 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1265 }
1266 }
1267
1268 #region Logs
1269
1270 public function rest_get_logs() {
1271 $logs = Meow_MWAI_Logging::get();
1272 return $this->create_rest_response( [ 'success' => true, 'data' => $logs ], 200 );
1273 }
1274
1275 public function rest_clear_logs() {
1276 Meow_MWAI_Logging::clear();
1277 return $this->create_rest_response( [ 'success' => true ], 200 );
1278 }
1279
1280 #endregion
1281 }
1282