PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 3.0.5
AI Engine – The Chatbot, AI Framework & MCP for WordPress v3.0.5
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 10 months ago exceptions 1 year ago modules 10 months ago query 10 months ago rest 10 months ago services 10 months ago admin.php 10 months ago api.php 10 months ago core.php 10 months ago discussion.php 1 year ago event.php 1 year ago init.php 1 year ago logging.php 1 year ago reply.php 11 months ago rest.php 10 months ago
rest.php
1613 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 // Log will be written when token is included in response
69 }
70 }
71
72 // If the nonce has changed or should be refreshed, include the new one
73 if ( $should_refresh || ( $request_nonce && $current_nonce !== $request_nonce ) ) {
74 $data['new_token'] = $current_nonce;
75
76 // Log if server debug mode is enabled
77 if ( $this->core->get_option( 'server_debug_mode' ) ) {
78 error_log( '[AI Engine] Token refresh: Nonce refreshed (12-24 hours old)' );
79 }
80 }
81
82 return new WP_REST_Response( $data, $status );
83 }
84
85 public function rest_init() {
86 try {
87 // Session Endpoint
88 register_rest_route( $this->namespace, '/start_session', [
89 'methods' => 'POST',
90 'permission_callback' => '__return_true', // Public endpoint for guest users
91 'callback' => [ $this, 'rest_start_session' ],
92 ] );
93
94 // Settings Endpoints
95 register_rest_route( $this->namespace, '/settings/update', [
96 'methods' => 'POST',
97 'permission_callback' => [ $this->core, 'can_access_settings' ],
98 'callback' => [ $this, 'rest_settings_update' ],
99 ] );
100 register_rest_route( $this->namespace, '/settings/options', [
101 'methods' => 'GET',
102 'permission_callback' => [ $this->core, 'can_access_settings' ],
103 'callback' => [ $this, 'rest_settings_list' ],
104 ] );
105 register_rest_route( $this->namespace, '/settings/reset', [
106 'methods' => 'POST',
107 'permission_callback' => [ $this->core, 'can_access_settings' ],
108 'callback' => [ $this, 'rest_settings_reset' ],
109 ] );
110 register_rest_route( $this->namespace, '/settings/chatbots', [
111 'methods' => ['GET', 'POST'],
112 'permission_callback' => [ $this->core, 'can_access_settings' ],
113 'callback' => [ $this, 'rest_settings_chatbots' ],
114 ] );
115 register_rest_route( $this->namespace, '/settings/themes', [
116 'methods' => ['GET', 'POST'],
117 'permission_callback' => [ $this->core, 'can_access_settings' ],
118 'callback' => [ $this, 'rest_settings_themes' ],
119 ] );
120
121 // System Endpoints
122 register_rest_route( $this->namespace, '/system/logs/list', [
123 'methods' => 'POST',
124 'permission_callback' => [ $this->core, 'can_access_settings' ],
125 'callback' => [ $this, 'rest_system_logs_list' ],
126 ] );
127 register_rest_route( $this->namespace, '/system/logs/delete', [
128 'methods' => 'POST',
129 'permission_callback' => [ $this->core, 'can_access_settings' ],
130 'callback' => [ $this, 'rest_system_logs_delete' ],
131 ] );
132 register_rest_route( $this->namespace, '/system/logs/meta', [
133 'methods' => 'POST',
134 'permission_callback' => [ $this->core, 'can_access_settings' ],
135 'callback' => [ $this, 'rest_system_logs_meta_get' ],
136 ] );
137 register_rest_route( $this->namespace, '/system/logs/activity', [
138 'methods' => 'POST',
139 'permission_callback' => [ $this->core, 'can_access_settings' ],
140 'callback' => [ $this, 'rest_system_logs_activity' ],
141 ] );
142 register_rest_route( $this->namespace, '/system/logs/activity_daily', [
143 'methods' => 'POST',
144 'permission_callback' => [ $this->core, 'can_access_settings' ],
145 'callback' => [ $this, 'rest_system_logs_activity_daily' ],
146 ] );
147 register_rest_route( $this->namespace, '/system/templates', [
148 'methods' => 'POST',
149 'permission_callback' => [ $this->core, 'can_access_features' ],
150 'callback' => [ $this, 'rest_system_templates_save' ],
151 ] );
152 register_rest_route( $this->namespace, '/system/templates', [
153 'methods' => 'GET',
154 'permission_callback' => [ $this->core, 'can_access_features' ],
155 'callback' => [ $this, 'rest_system_templates_get' ],
156 ] );
157
158 // AI Endpoints
159 register_rest_route( $this->namespace, '/ai/models', [
160 'methods' => 'POST',
161 'permission_callback' => [ $this->core, 'can_access_features' ],
162 'callback' => [ $this, 'rest_ai_models' ],
163 ] );
164 register_rest_route( $this->namespace, '/ai/test_connection', [
165 'methods' => 'POST',
166 'permission_callback' => [ $this->core, 'can_access_settings' ],
167 'callback' => [ $this, 'rest_ai_test_connection' ],
168 ] );
169 register_rest_route( $this->namespace, '/ai/completions', [
170 'methods' => 'POST',
171 'permission_callback' => [ $this->core, 'can_access_features' ],
172 'callback' => [ $this, 'rest_ai_completions' ],
173 ] );
174 register_rest_route( $this->namespace, '/ai/images', [
175 'methods' => 'POST',
176 'permission_callback' => [ $this->core, 'can_access_features' ],
177 'callback' => [ $this, 'rest_ai_images' ],
178 ] );
179 register_rest_route( $this->namespace, '/ai/image_edit', [
180 'methods' => 'POST',
181 'permission_callback' => [ $this->core, 'can_access_features' ],
182 'callback' => [ $this, 'rest_ai_image_edit' ],
183 ] );
184 register_rest_route( $this->namespace, '/ai/copilot', [
185 'methods' => 'POST',
186 'permission_callback' => [ $this->core, 'can_access_features' ],
187 'callback' => [ $this, 'rest_ai_copilot' ],
188 ] );
189
190 register_rest_route( $this->namespace, '/ai/magic_wand', [
191 'methods' => 'POST',
192 'callback' => [ $this, 'rest_ai_magic_wand' ],
193 'permission_callback' => [ $this->core, 'can_access_features' ],
194 ] );
195 register_rest_route( $this->namespace, '/ai/moderate', [
196 'methods' => 'POST',
197 'permission_callback' => [ $this->core, 'can_access_settings' ],
198 'callback' => [ $this, 'rest_ai_moderate' ],
199 ] );
200 register_rest_route( $this->namespace, '/ai/transcribe_audio', [
201 'methods' => 'POST',
202 'permission_callback' => [ $this->core, 'can_access_settings' ],
203 'callback' => [ $this, 'rest_ai_transcribe_audio' ],
204 ] );
205 register_rest_route( $this->namespace, '/ai/transcribe_image', [
206 'methods' => 'POST',
207 'permission_callback' => [ $this->core, 'can_access_settings' ],
208 'callback' => [ $this, 'rest_ai_transcribe_image' ],
209 ] );
210 register_rest_route( $this->namespace, '/ai/json', [
211 'methods' => 'POST',
212 'permission_callback' => [ $this->core, 'can_access_settings' ],
213 'callback' => [ $this, 'rest_ai_json' ],
214 ] );
215
216 // MCP Endpoints
217 register_rest_route( $this->namespace, '/mcp/functions', [
218 'methods' => 'GET',
219 'permission_callback' => [ $this->core, 'can_access_settings' ],
220 'callback' => [ $this, 'rest_mcp_functions' ],
221 ] );
222
223 // Helpers Endpoints
224 register_rest_route( $this->namespace, '/helpers/update_post_title', [
225 'methods' => 'POST',
226 'permission_callback' => [ $this->core, 'can_access_features' ],
227 'callback' => [ $this, 'rest_helpers_update_title' ],
228 ] );
229 register_rest_route( $this->namespace, '/helpers/update_post_excerpt', [
230 'methods' => 'POST',
231 'permission_callback' => [ $this->core, 'can_access_features' ],
232 'callback' => [ $this, 'rest_helpers_update_excerpt' ],
233 ] );
234 register_rest_route( $this->namespace, '/helpers/create_post', [
235 'methods' => 'POST',
236 'permission_callback' => [ $this->core, 'can_access_features' ],
237 'callback' => [ $this, 'rest_helpers_create_post' ],
238 ] );
239 register_rest_route( $this->namespace, '/helpers/create_image', [
240 'methods' => 'POST',
241 'permission_callback' => [ $this->core, 'can_access_features' ],
242 'callback' => [ $this, 'rest_helpers_create_images' ],
243 ] );
244 register_rest_route( $this->namespace, '/helpers/generate_image_meta', [
245 'methods' => 'POST',
246 'permission_callback' => [ $this->core, 'can_access_features' ],
247 'callback' => [ $this, 'rest_helpers_generate_image_meta' ],
248 ] );
249 register_rest_route( $this->namespace, '/helpers/count_posts', [
250 'methods' => 'GET',
251 'permission_callback' => [ $this->core, 'can_access_features' ],
252 'callback' => [ $this, 'rest_helpers_count_posts' ],
253 ] );
254 register_rest_route( $this->namespace, '/helpers/posts_ids', [
255 'methods' => 'GET',
256 'permission_callback' => [ $this->core, 'can_access_features' ],
257 'callback' => [ $this, 'rest_helpers_posts_ids' ],
258 ] );
259 register_rest_route( $this->namespace, '/helpers/post_types', [
260 'methods' => 'GET',
261 'permission_callback' => [ $this->core, 'can_access_features' ],
262 'callback' => [ $this, 'rest_helpers_post_types' ],
263 ] );
264 register_rest_route( $this->namespace, '/helpers/post_content', [
265 'methods' => 'GET',
266 'permission_callback' => [ $this->core, 'can_access_features' ],
267 'callback' => [ $this, 'rest_helpers_post_content' ],
268 ] );
269 register_rest_route( $this->namespace, '/helpers/run_tasks', [
270 'methods' => 'POST',
271 'permission_callback' => [ $this->core, 'can_access_features' ],
272 'callback' => [ $this, 'rest_helpers_run_tasks' ],
273 ] );
274 register_rest_route( $this->namespace, '/helpers/optimize_database', [
275 'methods' => 'POST',
276 'permission_callback' => [ $this->core, 'can_access_settings' ],
277 'callback' => [ $this, 'rest_helpers_optimize_database' ],
278 ] );
279
280 // OpenAI Endpoints
281 register_rest_route( $this->namespace, '/openai/files/list', [
282 'methods' => 'GET',
283 'permission_callback' => [ $this->core, 'can_access_settings' ],
284 'callback' => [ $this, 'rest_openai_files_get' ],
285 ] );
286 register_rest_route( $this->namespace, '/openai/files/upload', [
287 'methods' => 'POST',
288 'permission_callback' => [ $this->core, 'can_access_settings' ],
289 'callback' => [ $this, 'rest_openai_files_upload' ],
290 ] );
291 register_rest_route( $this->namespace, '/openai/files/delete', [
292 'methods' => 'POST',
293 'permission_callback' => [ $this->core, 'can_access_settings' ],
294 'callback' => [ $this, 'rest_openai_files_delete' ],
295 ] );
296 register_rest_route( $this->namespace, '/openai/files/download', [
297 'methods' => 'POST',
298 'permission_callback' => [ $this->core, 'can_access_settings' ],
299 'callback' => [ $this, 'rest_openai_files_download' ],
300 ] );
301 register_rest_route( $this->namespace, '/openai/files/finetune', [
302 'methods' => 'POST',
303 'permission_callback' => [ $this->core, 'can_access_settings' ],
304 'callback' => [ $this, 'rest_openai_files_finetune' ],
305 ] );
306 register_rest_route( $this->namespace, '/openai/finetunes/list_deleted', [
307 'methods' => 'GET',
308 'permission_callback' => [ $this->core, 'can_access_settings' ],
309 'callback' => [ $this, 'rest_openai_deleted_finetunes_get' ],
310 ] );
311
312 // register_rest_route( $this->namespace, '/openai/models', array(
313 // 'methods' => 'GET',
314 // 'permission_callback' => [ $this->core, 'can_access_settings' ],
315 // 'callback' => [ $this, 'rest_openai_models_get' ],
316 // ) );
317
318 register_rest_route( $this->namespace, '/openai/finetunes/list', [
319 'methods' => 'GET',
320 'permission_callback' => [ $this->core, 'can_access_settings' ],
321 'callback' => [ $this, 'rest_openai_finetunes_get' ],
322 ] );
323 register_rest_route( $this->namespace, '/openai/finetunes/delete', [
324 'methods' => 'POST',
325 'permission_callback' => [ $this->core, 'can_access_settings' ],
326 'callback' => [ $this, 'rest_openai_finetunes_delete' ],
327 ] );
328 register_rest_route( $this->namespace, '/openai/finetunes/cancel', [
329 'methods' => 'POST',
330 'permission_callback' => [ $this->core, 'can_access_settings' ],
331 'callback' => [ $this, 'rest_openai_finetunes_cancel' ],
332 ] );
333
334 // Logging Endpoints
335 register_rest_route( $this->namespace, '/get_logs', [
336 'methods' => 'GET',
337 'permission_callback' => [ $this->core, 'can_access_features' ],
338 'callback' => [ $this, 'rest_get_logs' ]
339 ] );
340 register_rest_route( $this->namespace, '/clear_logs', [
341 'methods' => 'GET',
342 'permission_callback' => [ $this->core, 'can_access_features' ],
343 'callback' => [ $this, 'rest_clear_logs' ]
344 ] );
345
346 // Forms Endpoints
347 register_rest_route( $this->namespace, '/forms/list', [
348 'methods' => 'GET',
349 'permission_callback' => [ $this->core, 'can_access_settings' ],
350 'callback' => [ $this, 'rest_forms_list' ]
351 ] );
352 register_rest_route( $this->namespace, '/forms/get', [
353 'methods' => 'GET',
354 'permission_callback' => [ $this->core, 'can_access_settings' ],
355 'callback' => [ $this, 'rest_forms_get' ]
356 ] );
357 register_rest_route( $this->namespace, '/forms/create', [
358 'methods' => 'POST',
359 'permission_callback' => [ $this->core, 'can_access_settings' ],
360 'callback' => [ $this, 'rest_forms_create' ]
361 ] );
362 register_rest_route( $this->namespace, '/forms/update', [
363 'methods' => 'POST',
364 'permission_callback' => [ $this->core, 'can_access_settings' ],
365 'callback' => [ $this, 'rest_forms_update' ]
366 ] );
367 register_rest_route( $this->namespace, '/forms/delete', [
368 'methods' => 'POST',
369 'permission_callback' => [ $this->core, 'can_access_settings' ],
370 'callback' => [ $this, 'rest_forms_delete' ]
371 ] );
372 }
373 catch ( Exception $e ) {
374 Meow_MWAI_Logging::error( 'REST API initialization failed: ' . $e->getMessage() );
375 }
376 }
377
378 public function rest_start_session() {
379 try {
380 $sessionId = $this->core->get_session_id();
381 $restNonce = $this->core->get_nonce( true );
382
383 $response = [
384 'success' => true,
385 'sessionId' => $sessionId,
386 'restNonce' => $restNonce
387 ];
388
389 // If in test mode and we have a new token, it will be added by create_rest_response
390 // But we also want to ensure the restNonce matches the test token if available
391 if ( get_option( 'mwai_token_test_mode' ) ) {
392 $token_data = get_option( 'mwai_test_token_data' );
393 if ( $token_data && isset( $token_data['token'] ) ) {
394 $response['restNonce'] = $token_data['token'];
395 }
396 }
397
398 return $this->create_rest_response( $response, 200 );
399 }
400 catch ( Exception $e ) {
401 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
402 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
403 }
404 }
405
406 public function rest_settings_list() {
407 return $this->create_rest_response( [
408 'success' => true,
409 'options' => $this->core->get_all_options()
410 ], 200 );
411 }
412
413 public function rest_settings_update( $request ) {
414 try {
415 $params = $request->get_json_params();
416 $value = $params['options'];
417 $options = $this->core->update_options( $value );
418 $success = !!$options;
419 $message = __( $success ? 'OK' : 'Could not update options.', 'ai-engine' );
420 return $this->create_rest_response( [ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
421 }
422 catch ( Exception $e ) {
423 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
424 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
425 }
426 }
427
428 public function rest_settings_reset() {
429 try {
430 $options = $this->core->reset_options();
431 $success = !!$options;
432 $message = __( $success ? 'OK' : 'Could not reset options.', 'ai-engine' );
433 return $this->create_rest_response( [ 'success' => $success, 'message' => $message, 'options' => $options ], 200 );
434 }
435 catch ( Exception $e ) {
436 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
437 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
438 }
439 }
440
441 public function rest_ai_models( $request ) {
442 try {
443 $params = $request->get_json_params();
444 $envId = $params['envId'];
445 $engine = Meow_MWAI_Engines_Factory::get( $this->core, $envId );
446 $models = $engine->retrieve_models();
447 return $this->create_rest_response( [ 'success' => true, 'models' => $models ], 200 );
448 }
449 catch ( Exception $e ) {
450 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
451 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
452 }
453 }
454
455 public function rest_ai_test_connection( $request ) {
456 try {
457 $params = $request->get_json_params();
458 $envId = $params['env_id'];
459
460 // Get the environment details
461 $env = null;
462 $envs = $this->core->get_option( 'ai_envs' );
463 foreach ( $envs as $e ) {
464 if ( $e['id'] === $envId ) {
465 $env = $e;
466 break;
467 }
468 }
469
470 if ( !$env ) {
471 throw new Exception( __( 'Environment not found.', 'ai-engine' ) );
472 }
473
474 // Get the engine and test connection
475 $engine = Meow_MWAI_Engines_Factory::get( $this->core, $envId );
476 $result = $engine->connection_check();
477
478 // Format the response based on provider
479 $response = [
480 'success' => true,
481 'provider' => $env['type'],
482 'name' => $env['name'],
483 'data' => $result
484 ];
485
486 return $this->create_rest_response( $response, 200 );
487 }
488 catch ( Exception $e ) {
489 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
490 return $this->create_rest_response( [
491 'success' => false,
492 'error' => $message,
493 'provider' => isset( $env ) ? $env['type'] : 'unknown'
494 ], 200 ); // Return 200 even on error for consistent modal display
495 }
496 }
497
498 public function rest_ai_completions( $request ) {
499 try {
500 $params = $request->get_json_params();
501 $message = $this->retrieve_message( $params );
502 $query = new Meow_MWAI_Query_Text( $message );
503 $query->inject_params( $params );
504
505 // Handle streaming
506 $stream = $params['stream'] ?? false;
507 $streamCallback = null;
508 if ( $stream ) {
509 $streamCallback = function ( $reply ) use ( $query ) {
510 //$raw = _wp_specialchars( $reply, ENT_NOQUOTES, 'UTF-8', true );
511 $raw = $reply;
512 $this->core->stream_push( [ 'type' => 'live', 'data' => $raw ], $query );
513 if ( ob_get_level() > 0 ) {
514 ob_flush();
515 }
516 flush();
517 };
518 if ( headers_sent( $filename, $linenum ) ) {
519 throw new Exception( "Headers already sent in $filename on line $linenum. Cannot start streaming." );
520 }
521 header( 'Cache-Control: no-cache' );
522 header( 'Content-Type: text/event-stream' );
523 header( 'X-Accel-Buffering: no' ); // This is useful to disable buffering in nginx through headers.
524 ob_implicit_flush( true );
525 if ( ob_get_level() > 0 ) {
526 ob_end_flush();
527 }
528 }
529
530 // Process Reply
531 $reply = $this->core->run_query( $query, $streamCallback );
532 $restRes = [
533 'success' => true,
534 'data' => $reply->result,
535 'usage' => $reply->usage
536 ];
537 if ( $stream ) {
538 $this->core->stream_push( [ 'type' => 'end', 'data' => json_encode( $restRes ) ], $query );
539 die();
540 }
541 return $this->create_rest_response( $restRes, 200 );
542 }
543 catch ( Exception $e ) {
544 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
545 if ( $stream ) {
546 $this->core->stream_push( [ 'type' => 'error', 'data' => $message ], $query );
547 }
548 else {
549 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
550 }
551 }
552 }
553
554 public function rest_ai_images( $request ) {
555 try {
556 $params = $request->get_json_params();
557 $message = $this->retrieve_message( $params );
558 $query = new Meow_MWAI_Query_Image( $message );
559 $query->inject_params( $params );
560 $reply = $this->core->run_query( $query );
561 return $this->create_rest_response( [ 'success' => true, 'data' => $reply->results, 'usage' => $reply->usage ], 200 );
562 }
563 catch ( Exception $e ) {
564 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
565 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
566 }
567 }
568
569 public function rest_ai_image_edit( $request ) {
570 try {
571 // Check if this is a multipart request with files
572 $files = $request->get_file_params();
573 $params = null;
574
575 // Debug logging
576 if ( $this->core->get_option( 'queries_debug_mode' ) ) {
577 error_log( '[AI Engine Queries] Image Edit Request - Method: ' . $request->get_method() );
578 $content_type = $request->get_content_type();
579 if ( is_array( $content_type ) ) {
580 error_log( '[AI Engine Queries] Image Edit Request - Content-Type: ' . $content_type['value'] );
581 }
582 else {
583 error_log( '[AI Engine Queries] Image Edit Request - Content-Type: ' . $content_type );
584 }
585 error_log( '[AI Engine Queries] Image Edit Request - Has files: ' . ( !empty( $files ) ? 'yes (' . count( $files ) . ')' : 'no' ) );
586 }
587
588 if ( !empty( $files ) ) {
589 // Handle multipart form data - get all params including POST data
590 $params = $request->get_params();
591 if ( $this->core->get_option( 'queries_debug_mode' ) ) {
592 error_log( '[AI Engine Queries] Image Edit Request - Using form data params' );
593 }
594 }
595 else {
596 // Try to get body params first (for form data without files)
597 $body_params = $request->get_body_params();
598 if ( !empty( $body_params ) ) {
599 $params = $body_params;
600 if ( $this->core->get_option( 'queries_debug_mode' ) ) {
601 error_log( '[AI Engine Queries] Image Edit Request - Using body params' );
602 }
603 }
604 else {
605 // Handle JSON request
606 $params = $request->get_json_params();
607 if ( $this->core->get_option( 'queries_debug_mode' ) ) {
608 error_log( '[AI Engine Queries] Image Edit Request - Using JSON params' );
609 }
610 }
611 }
612
613 // Ensure params is always an array
614 if ( empty( $params ) ) {
615 $params = [];
616 }
617
618 // Debug logging
619 if ( $this->core->get_option( 'queries_debug_mode' ) ) {
620 error_log( '[AI Engine Queries] Image Edit Request - Has files: ' . ( !empty( $files ) ? 'yes' : 'no' ) );
621 error_log( '[AI Engine Queries] Image Edit Request - Params: ' . json_encode( $params ) );
622 }
623
624 $message = $this->retrieve_message( $params );
625 $mediaId = isset( $params['mediaId'] ) ? intval( $params['mediaId'] ) : 0;
626 $query = new Meow_MWAI_Query_EditImage( $message );
627
628 // The inject_params method will handle setting the file from mediaId
629 $query->inject_params( $params );
630
631 // Handle mask file if provided
632 if ( !empty( $files['mask'] ) ) {
633 $mask_file = $files['mask'];
634 if ( $mask_file['error'] === UPLOAD_ERR_OK ) {
635 $mask_data = file_get_contents( $mask_file['tmp_name'] );
636 $query->set_mask( Meow_MWAI_Query_DroppedFile::from_data( $mask_data, 'vision', $mask_file['type'] ) );
637 }
638 }
639
640 $reply = $this->core->run_query( $query );
641 return $this->create_rest_response( [ 'success' => true, 'data' => $reply->results, 'usage' => $reply->usage ], 200 );
642 }
643 catch ( Exception $e ) {
644 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
645 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
646 }
647 }
648
649 public function rest_ai_magic_wand( $request ) {
650 try {
651 $params = $request->get_json_params();
652 $action = isset( $params['action'] ) ? $params['action'] : null;
653 $data = isset( $params['data'] ) ? $params['data'] : null;
654 if ( empty( $data ) || empty( $action ) ) {
655 return $this->create_rest_response( [ 'success' => false, 'message' => 'An action and some data are required.' ], 500 );
656 }
657 $data = apply_filters( 'mwai_magic_wand_' . $action, '', $data );
658 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
659 }
660 catch ( Exception $e ) {
661 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
662 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
663 }
664 }
665
666 public function rest_ai_copilot( $request ) {
667 try {
668 $params = $request->get_json_params();
669 $action = sanitize_text_field( $params['action'] );
670 $message = $this->retrieve_message( $params, true );
671 $context = sanitize_text_field( $params['context'] );
672 $postId = !empty( $params['postId'] ) ? intval( $params['postId'] ) : null;
673 if ( empty( $action ) || empty( $message ) ) {
674 return $this->create_rest_response( [ 'success' => false, 'message' => 'Copilot needs an action and a prompt.' ], 500 );
675 }
676
677 global $mwai;
678 $result = null;
679 $params = [ 'scope' => 'copilot' ];
680
681 if ( $action === 'text' ) {
682 $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.";
683 if ( !empty( $model ) ) {
684 $params['model'] = $model;
685 }
686 $result = $mwai->simpleTextQuery( $prompt, $params );
687 }
688 else if ( $action === 'image' ) {
689 $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.";
690
691 // Create the image
692 $simplifiedPrompt = $mwai->simpleTextQuery( $prompt, $params );
693 $media = $mwai->imageQueryForMediaLibrary( $simplifiedPrompt, $params, $postId );
694 $result = [ 'media' => $media ];
695 }
696 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
697 }
698 catch ( Exception $e ) {
699 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
700 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
701 }
702 }
703
704 public function rest_helpers_update_title( $request ) {
705 try {
706 $params = $request->get_json_params();
707 $title = sanitize_text_field( $params['title'] );
708 $postId = intval( $params['postId'] );
709 $post = get_post( $postId );
710 if ( !$post ) {
711 throw new Exception( __( 'There is no post with this ID.', 'ai-engine' ) );
712 }
713 $post->post_title = $title;
714 //$post->post_name = sanitize_title( $title );
715 wp_update_post( $post );
716 return $this->create_rest_response( [ 'success' => true, 'message' => 'Title updated.' ], 200 );
717 }
718 catch ( Exception $e ) {
719 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
720 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
721 }
722 }
723
724 public function rest_helpers_update_excerpt( $request ) {
725 try {
726 $params = $request->get_json_params();
727 $excerpt = sanitize_text_field( $params['excerpt'] );
728 $postId = intval( $params['postId'] );
729 $post = get_post( $postId );
730 if ( !$post ) {
731 throw new Exception( __( 'There is no post with this ID.', 'ai-engine' ) );
732 }
733 $post->post_excerpt = $excerpt;
734 wp_update_post( $post );
735 return $this->create_rest_response( [ 'success' => true, 'message' => 'Excerpt updated.' ], 200 );
736 }
737 catch ( Exception $e ) {
738 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
739 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
740 }
741 }
742
743 public function rest_helpers_create_post( $request ) {
744 try {
745 $params = $request->get_json_params();
746 $title = sanitize_text_field( $params['title'] );
747 $content = sanitize_textarea_field( $params['content'] );
748 $excerpt = sanitize_text_field( $params['excerpt'] );
749 $postType = sanitize_text_field( $params['postType'] );
750 $post = new stdClass();
751 $post->post_title = $title;
752 $post->post_excerpt = $excerpt;
753 $post->post_content = $content;
754 $post->post_status = 'draft';
755 $post->post_type = isset( $postType ) ? $postType : 'post';
756 // TODO: Let's try to avoid using Markdown to create the Post
757 // Instead, we should create Gutenberg Blocks, or simple HTML.
758 // Then, we can get rid of the library for Markdown.
759 $post->post_content = $this->core->markdown_to_html( $post->post_content );
760 $postId = wp_insert_post( $post );
761 return $this->create_rest_response( [ 'success' => true, 'postId' => $postId ], 200 );
762 }
763 catch ( Exception $e ) {
764 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
765 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
766 }
767 }
768
769 public function rest_helpers_create_images( $request ) {
770 try {
771 $params = $request->get_json_params();
772 $title = sanitize_text_field( $params['title'] );
773 $caption = sanitize_text_field( $params['caption'] );
774 $alt = sanitize_text_field( $params['alt'] );
775 $description = sanitize_text_field( $params['description'] );
776 $url = $params['url'];
777 $filename = sanitize_text_field( $params['filename'] );
778 $attachmentId = $this->core->add_image_from_url( $url, $filename, $title, $description, $caption, $alt );
779 return $this->create_rest_response( [ 'success' => true, 'attachmentId' => $attachmentId ], 200 );
780 }
781 catch ( Exception $e ) {
782 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
783 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
784 }
785 }
786
787 public function rest_helpers_generate_image_meta( $request ) {
788 try {
789 global $mwai;
790 $params = $request->get_json_params();
791 $url = isset( $params['url'] ) ? esc_url_raw( $params['url'] ) : null;
792 if ( empty( $url ) ) {
793 throw new Exception( __( 'The url is required.', 'ai-engine' ) );
794 }
795 $prompt = 'Describe this image and suggest a short title, description and SEO-friendly (ASCII and lowercase) filename. '
796 . 'Return a JSON with the keys title, description, alt, caption, filename.';
797 $result = $mwai->simpleVisionQuery( $prompt, $url, null, [ 'image_remote_upload' => 'url', 'scope' => 'admin-tools' ] );
798 $result = preg_replace( '/^```json\s*/', '', $result );
799 $result = preg_replace( '/\s*```$/', '', $result );
800 if ( is_string( $result ) ) {
801 $data = json_decode( $result, true );
802 }
803 else {
804 $data = $result;
805 }
806 if ( !is_array( $data ) ) {
807 $data = [];
808 }
809 $data = array_merge( [ 'title' => '', 'description' => '', 'caption' => '', 'alt' => '', 'filename' => '' ], $data );
810 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
811 }
812 catch ( Exception $e ) {
813 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
814 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
815 }
816 }
817
818 public function rest_openai_files_get() {
819 try {
820 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
821 $purposeFilter = isset( $_GET['purpose'] ) ? $_GET['purpose'] : null;
822 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
823 $files = $openai->list_files( $purposeFilter );
824 return $this->create_rest_response( [ 'success' => true, 'files' => $files ], 200 );
825 }
826 catch ( Exception $e ) {
827 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
828 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
829 }
830 }
831
832 public function rest_openai_deleted_finetunes_get() {
833 try {
834 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
835 $legacy = isset( $_GET['legacy'] ) ? $_GET['legacy'] === 'true' : false;
836 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
837 $finetunes = $openai->list_deleted_finetunes( $legacy );
838 return $this->create_rest_response( [ 'success' => true, 'finetunes' => $finetunes ], 200 );
839 }
840 catch ( Exception $e ) {
841 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
842 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
843 }
844 }
845
846 public function rest_openai_finetunes_get() {
847 try {
848 $envId = isset( $_GET['envId'] ) ? $_GET['envId'] : null;
849 $legacy = isset( $_GET['legacy'] ) ? $_GET['legacy'] === 'true' : false;
850 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
851 $finetunes = $openai->list_finetunes( $legacy );
852 return $this->create_rest_response( [ 'success' => true, 'finetunes' => $finetunes ], 200 );
853 }
854 catch ( Exception $e ) {
855 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
856 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
857 }
858 }
859
860 public function rest_openai_files_upload( $request ) {
861 try {
862 $params = $request->get_json_params();
863 $envId = $params['envId'];
864 ;
865 $filename = sanitize_text_field( $params['filename'] );
866 $data = $params['data'];
867 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
868 $file = $openai->upload_file( $filename, $data );
869 return $this->create_rest_response( [ 'success' => true, 'file' => $file ], 200 );
870 }
871 catch ( Exception $e ) {
872 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
873 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
874 }
875 }
876
877 public function rest_openai_files_delete( $request ) {
878 try {
879 $params = $request->get_json_params();
880 $envId = $params['envId'];
881 ;
882 $fileId = $params['fileId'];
883 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
884 $openai->delete_file( $fileId );
885 return $this->create_rest_response( [ 'success' => true ], 200 );
886 }
887 catch ( Exception $e ) {
888 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
889 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
890 }
891 }
892
893 public function rest_openai_finetunes_cancel( $request ) {
894 try {
895 $params = $request->get_json_params();
896 $envId = $params['envId'];
897 ;
898 $finetuneId = $params['finetuneId'];
899 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
900 $openai->cancel_finetune( $finetuneId );
901 return $this->create_rest_response( [ 'success' => true ], 200 );
902 }
903 catch ( Exception $e ) {
904 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
905 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
906 }
907 }
908
909 public function rest_openai_finetunes_delete( $request ) {
910 try {
911 $params = $request->get_json_params();
912 $envId = $params['envId'];
913 ;
914 $modelId = $params['modelId'];
915 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
916 $openai->delete_finetune( $modelId );
917 return $this->create_rest_response( [ 'success' => true ], 200 );
918 }
919 catch ( Exception $e ) {
920 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
921 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
922 }
923 }
924
925 public function rest_openai_files_download( $request ) {
926 try {
927 $params = $request->get_json_params();
928 $envId = $params['envId'];
929 ;
930 $fileId = $params['fileId'];
931 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
932 $filename = $openai->download_file( $fileId );
933 $data = file_get_contents( $filename );
934 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
935 }
936 catch ( Exception $e ) {
937 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
938 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
939 }
940 }
941
942 public function rest_openai_files_finetune( $request ) {
943 try {
944 $params = $request->get_json_params();
945 $envId = $params['envId'];
946 ;
947 $fileId = $params['fileId'];
948 $model = $params['model'];
949 $suffix = $params['suffix'];
950 $hyperparams = [
951 'nEpochs' => isset( $params['nEpochs'] ) ? $params['nEpochs'] : null,
952 'batchSize' => isset( $params['batchSize'] ) ? $params['batchSize'] : null,
953 ];
954 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
955 $finetune = $openai->run_finetune( $fileId, $model, $suffix, $hyperparams );
956 return $this->create_rest_response( [ 'success' => true, 'finetune' => $finetune ], 200 );
957 }
958 catch ( Exception $e ) {
959 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
960 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
961 }
962 }
963
964 public function rest_helpers_count_posts( $request ) {
965 try {
966 $params = $request->get_query_params();
967 $postType = $params['postType'];
968 $postStatus = !empty( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
969 $count = wp_count_posts( $postType );
970 $count = array_sum( array_intersect_key( (array) $count, array_flip( $postStatus ) ) );
971 return $this->create_rest_response( [ 'success' => true, 'count' => $count ], 200 );
972 }
973 catch ( Exception $e ) {
974 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
975 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
976 }
977 }
978
979 public function rest_helpers_posts_ids( $request ) {
980 try {
981 $params = $request->get_query_params();
982 $postType = $params['postType'];
983 $postStatus = !empty( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
984 $posts = get_posts( [
985 'posts_per_page' => -1,
986 'post_type' => $postType,
987 'post_status' => $postStatus,
988 'fields' => 'ids'
989 ] );
990 return $this->create_rest_response( [ 'success' => true, 'postIds' => $posts ], 200 );
991 }
992 catch ( Exception $e ) {
993 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
994 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
995 }
996 }
997
998 public function rest_helpers_post_content( $request ) {
999 try {
1000 $params = $request->get_query_params();
1001 $offset = (int) $params['offset'];
1002 $postType = $params['postType'];
1003 $postStatus = isset( $params['postStatus'] ) ? explode( ',', $params['postStatus'] ) : [ 'publish' ];
1004 $postId = (int) $params['postId'];
1005
1006 $post = null;
1007 if ( !empty( $postId ) ) {
1008 $post = get_post( $postId );
1009 if ( $post->post_status !== 'publish' && $post->post_status !== 'future'
1010 && $post->post_status !== 'draft' && $post->post_status !== 'private' ) {
1011 $post = null;
1012 }
1013 }
1014 else {
1015 $posts = get_posts( [
1016 'posts_per_page' => 1,
1017 'post_type' => $postType,
1018 'offset' => $offset,
1019 'post_status' => $postStatus,
1020 ] );
1021 $post = count( $posts ) === 0 ? null : $posts[0];
1022 }
1023 if ( !$post ) {
1024 return $this->create_rest_response( [ 'success' => false, 'message' => 'Post not found' ], 404 );
1025 }
1026 $cleanPost = $this->core->get_post( $post );
1027 return $this->create_rest_response( [ 'success' => true, 'content' => $cleanPost['content'],
1028 'checksum' => $cleanPost['checksum'], 'language' => $cleanPost['language'], 'excerpt' => $cleanPost['excerpt'],
1029 'postId' => $cleanPost['postId'], 'title' => $cleanPost['title'], 'url' => $cleanPost['url'] ], 200 );
1030 }
1031 catch ( Exception $e ) {
1032 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1033 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1034 }
1035 }
1036
1037 public function rest_helpers_run_tasks( $request ) {
1038 try {
1039 do_action( 'mwai_tasks_run' );
1040 return $this->create_rest_response( [ 'success' => true ], 200 );
1041 }
1042 catch ( Exception $e ) {
1043 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1044 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1045 }
1046 }
1047
1048 public function rest_helpers_optimize_database( $request ) {
1049 try {
1050 global $wpdb;
1051 $results = [];
1052
1053 // Add indexes to optimize query performance
1054 $indexes = [
1055 // mwai_logs indexes
1056 [ 'table' => 'mwai_logs', 'name' => 'idx_mwai_logs_time', 'columns' => 'time' ],
1057 [ 'table' => 'mwai_logs', 'name' => 'idx_mwai_logs_userId', 'columns' => 'userId' ],
1058 [ 'table' => 'mwai_logs', 'name' => 'idx_mwai_logs_envId', 'columns' => 'envId' ],
1059 [ 'table' => 'mwai_logs', 'name' => 'idx_mwai_logs_refId', 'columns' => 'refId' ],
1060 [ 'table' => 'mwai_logs', 'name' => 'idx_mwai_logs_time_model', 'columns' => 'time, model' ],
1061
1062 // mwai_logmeta indexes
1063 [ 'table' => 'mwai_logmeta', 'name' => 'idx_mwai_logmeta_log_id', 'columns' => 'log_id' ],
1064
1065 // mwai_vectors indexes
1066 [ 'table' => 'mwai_vectors', 'name' => 'idx_mwai_vectors_envId_status_dbId', 'columns' => 'envId, status, dbId' ],
1067 [ 'table' => 'mwai_vectors', 'name' => 'idx_mwai_vectors_refId', 'columns' => 'refId' ],
1068 [ 'table' => 'mwai_vectors', 'name' => 'idx_mwai_vectors_status', 'columns' => 'status' ],
1069 [ 'table' => 'mwai_vectors', 'name' => 'idx_mwai_vectors_updated', 'columns' => 'updated' ],
1070
1071 // mwai_files indexes
1072 [ 'table' => 'mwai_files', 'name' => 'idx_mwai_files_expires', 'columns' => 'expires' ],
1073 [ 'table' => 'mwai_files', 'name' => 'idx_mwai_files_userId', 'columns' => 'userId' ],
1074 [ 'table' => 'mwai_files', 'name' => 'idx_mwai_files_purpose', 'columns' => 'purpose' ],
1075
1076 // mwai_filemeta indexes
1077 [ 'table' => 'mwai_filemeta', 'name' => 'idx_mwai_filemeta_file_id', 'columns' => 'file_id' ],
1078
1079 // mwai_chats indexes
1080 [ 'table' => 'mwai_chats', 'name' => 'idx_mwai_chats_chatId_botId', 'columns' => 'chatId, botId' ],
1081 [ 'table' => 'mwai_chats', 'name' => 'idx_mwai_chats_chatId_userId', 'columns' => 'chatId, userId' ],
1082 [ 'table' => 'mwai_chats', 'name' => 'idx_mwai_chats_updated', 'columns' => 'updated' ],
1083 ];
1084
1085 // Add indexes
1086 foreach ( $indexes as $index ) {
1087 $table = $wpdb->prefix . $index['table'];
1088 $index_name = $index['name'];
1089 $columns = $index['columns'];
1090
1091 // Check if index already exists
1092 $existing = $wpdb->get_var( $wpdb->prepare(
1093 "SELECT COUNT(*) FROM INFORMATION_SCHEMA.STATISTICS
1094 WHERE table_schema = %s AND table_name = %s AND index_name = %s",
1095 DB_NAME, $table, $index_name
1096 ) );
1097
1098 if ( !$existing ) {
1099 $wpdb->query( "ALTER TABLE `$table` ADD INDEX `$index_name` ($columns)" );
1100 $results[] = "Added index $index_name on $table";
1101 }
1102 }
1103
1104 // Clean up old logs (older than 3 months)
1105 $three_months_ago = date( 'Y-m-d H:i:s', strtotime( '-3 months' ) );
1106
1107 // Delete old logs
1108 $deleted_logs = $wpdb->query( $wpdb->prepare(
1109 "DELETE FROM {$wpdb->prefix}mwai_logs WHERE time < %s",
1110 $three_months_ago
1111 ) );
1112 $results[] = "Deleted $deleted_logs old log entries";
1113
1114 // Delete orphaned logmeta
1115 $deleted_logmeta = $wpdb->query(
1116 "DELETE lm FROM {$wpdb->prefix}mwai_logmeta lm
1117 LEFT JOIN {$wpdb->prefix}mwai_logs l ON lm.log_id = l.id
1118 WHERE l.id IS NULL"
1119 );
1120 $results[] = "Deleted $deleted_logmeta orphaned logmeta entries";
1121
1122 // Delete old chats (older than 3 months)
1123 $deleted_chats = $wpdb->query( $wpdb->prepare(
1124 "DELETE FROM {$wpdb->prefix}mwai_chats WHERE updated < %s",
1125 $three_months_ago
1126 ) );
1127 $results[] = "Deleted $deleted_chats old chat discussions";
1128
1129 // Optimize tables
1130 $tables = [ 'mwai_logs', 'mwai_logmeta', 'mwai_vectors', 'mwai_files', 'mwai_filemeta', 'mwai_chats' ];
1131 foreach ( $tables as $table ) {
1132 $wpdb->query( "OPTIMIZE TABLE {$wpdb->prefix}$table" );
1133 }
1134 $results[] = "Optimized all AI Engine tables";
1135
1136 $message = implode( "\n", $results );
1137 return $this->create_rest_response( [ 'success' => true, 'message' => $message ], 200 );
1138 }
1139 catch ( Exception $e ) {
1140 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1141 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1142 }
1143 }
1144
1145 public function rest_system_templates_get( $request ) {
1146 try {
1147 $params = $request->get_query_params();
1148 $category = $params['category'];
1149 $templates = [];
1150 $templates_option = get_option( 'mwai_templates', [] );
1151 if ( !is_array( $templates_option ) ) {
1152 update_option( 'mwai_templates', [] );
1153 }
1154 $categories = array_column( $templates_option, 'category' );
1155 $index = array_search( $category, $categories );
1156 $templates = [];
1157 if ( $index !== false ) {
1158 $templates = $templates_option[$index]['templates'];
1159 }
1160 return $this->create_rest_response( [ 'success' => true, 'templates' => $templates ], 200 );
1161 }
1162 catch ( Exception $e ) {
1163 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1164 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1165 }
1166 }
1167
1168 public function rest_system_templates_save( $request ) {
1169 try {
1170 $params = $request->get_json_params();
1171 $category = $params['category'];
1172 $templates = $params['templates'];
1173 $templates_option = get_option( 'mwai_templates', [] );
1174 $categories = array_column( $templates_option, 'category' );
1175 $index = array_search( $category, $categories );
1176 if ( $index !== false && $index >= 0 ) {
1177 $templates_option[$index]['templates'] = $templates;
1178 }
1179 else {
1180 $group = [ 'category' => $category, 'templates' => $templates ];
1181 $templates_option[] = $group;
1182 }
1183
1184 update_option( 'mwai_templates', $templates_option );
1185 return $this->create_rest_response( [ 'success' => true ], 200 );
1186 }
1187 catch ( Exception $e ) {
1188 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1189 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1190 }
1191 }
1192
1193 public function rest_system_logs_list( $request ) {
1194 try {
1195 $params = $request->get_json_params();
1196 $offset = $params['offset'];
1197 $limit = $params['limit'];
1198 $filters = $params['filters'];
1199 $sort = isset( $params['sort'] ) ? $params['sort'] : null;
1200 $logs = apply_filters( 'mwai_stats_logs_list', [], $offset, $limit, $filters, $sort );
1201 return $this->create_rest_response( [ 'success' => true, 'total' => $logs['total'], 'logs' => $logs['rows'] ], 200 );
1202 }
1203 catch ( Exception $e ) {
1204 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1205 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1206 }
1207 }
1208
1209 public function rest_system_logs_delete( $request ) {
1210 try {
1211 $params = $request->get_json_params();
1212 $logIds = $params['logIds'];
1213 $success = apply_filters( 'mwai_stats_logs_delete', true, $logIds );
1214 return $this->create_rest_response( [ 'success' => $success ], 200 );
1215 }
1216 catch ( Exception $e ) {
1217 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1218 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1219 }
1220 }
1221
1222 public function rest_system_logs_meta_get( $request ) {
1223 try {
1224 $params = $request->get_json_params();
1225 $logId = $params['logId'];
1226 $metaKeys = $params['metaKeys'];
1227 $data = apply_filters( 'mwai_stats_logs_meta', [], $logId, $metaKeys );
1228 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1229 }
1230 catch ( Exception $e ) {
1231 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1232 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1233 }
1234 }
1235
1236 public function rest_system_logs_activity( $request ) {
1237 try {
1238 $params = $request->get_json_params();
1239 $hours = isset( $params['hours'] ) ? intval( $params['hours'] ) : 24;
1240 $data = apply_filters( 'mwai_stats_logs_activity', [], $hours );
1241 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1242 }
1243 catch ( Exception $e ) {
1244 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1245 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1246 }
1247 }
1248
1249 public function rest_system_logs_activity_daily( $request ) {
1250 try {
1251 $params = $request->get_json_params();
1252 $days = isset( $params['days'] ) ? intval( $params['days'] ) : 31;
1253 $byModel = isset( $params['byModel'] ) ? (bool) $params['byModel'] : false;
1254
1255 if ( $byModel ) {
1256 $data = apply_filters( 'mwai_stats_logs_activity_daily_by_model', [], $days );
1257 } else {
1258 $data = apply_filters( 'mwai_stats_logs_activity_daily', [], $days );
1259 }
1260
1261 return $this->create_rest_response( [ 'success' => true, 'data' => $data ], 200 );
1262 }
1263 catch ( Exception $e ) {
1264 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1265 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1266 }
1267 }
1268
1269 public function rest_ai_moderate( $request ) {
1270 try {
1271 $params = $request->get_json_params();
1272 $envId = $params['envId'];
1273 $text = $params['text'];
1274 if ( !$text ) {
1275 return $this->create_rest_response( [ 'success' => false, 'message' => 'Text not found.' ], 404 );
1276 }
1277 $openai = Meow_MWAI_Engines_Factory::get_openai( $this->core, $envId );
1278 $results = $openai->moderate( $text );
1279 return $this->create_rest_response( [ 'success' => true, 'results' => $results ], 200 );
1280 }
1281 catch ( Exception $e ) {
1282 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1283 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1284 }
1285 }
1286
1287 public function rest_ai_transcribe_audio( $request ) {
1288 try {
1289 global $mwai;
1290 $params = $request->get_json_params();
1291 $url = !empty( $params['url'] ) ? $params['url'] : null;
1292 $mediaId = isset( $params['mediaId'] ) ? intval( $params['mediaId'] ) : 0;
1293 $path = !empty( $params['path'] ) ? $params['path'] : null;
1294
1295 // If mediaId is provided, get the file path
1296 if ( !$path && $mediaId > 0 ) {
1297 $path = get_attached_file( $mediaId );
1298 if ( empty( $path ) ) {
1299 throw new Exception( __( 'The media file cannot be found.', 'ai-engine' ) );
1300 }
1301 }
1302
1303 // Set the scope for admin tools
1304 if ( !isset( $params['scope'] ) ) {
1305 $params['scope'] = 'admin-tools';
1306 }
1307
1308 $result = $mwai->simpleTranscribeAudio( $url, $path, $params );
1309 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
1310 }
1311 catch ( Exception $e ) {
1312 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1313 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1314 }
1315 }
1316
1317 public function rest_ai_transcribe_image( $request ) {
1318 try {
1319 global $mwai;
1320 $params = $request->get_json_params();
1321 $message = $this->retrieve_message( $params );
1322 $url = !empty( $params['url'] ) ? $params['url'] : null;
1323 // This could lead to a security issue, so let's avoid using path directly.
1324 //$path = !empty( $params['path'] ) ? $params['path'] : null;
1325 $result = $mwai->simpleVisionQuery( $message, $url );
1326 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
1327 }
1328 catch ( Exception $e ) {
1329 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1330 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1331 }
1332 }
1333
1334 public function rest_ai_json( $request ) {
1335 try {
1336 global $mwai;
1337 $params = $request->get_json_params();
1338 $message = $this->retrieve_message( $params );
1339 $result = $mwai->simpleJsonQuery( $message );
1340 return $this->create_rest_response( [ 'success' => true, 'data' => $result ], 200 );
1341 }
1342 catch ( Exception $e ) {
1343 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1344 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1345 }
1346 }
1347
1348 public function rest_mcp_functions( $request ) {
1349 try {
1350 // Get all registered MCP tools
1351 $tools = apply_filters( 'mwai_mcp_tools', [] );
1352
1353 // Format the response
1354 $response = [
1355 'success' => true,
1356 'count' => count( $tools ),
1357 'functions' => $tools
1358 ];
1359
1360 return $this->create_rest_response( $response, 200 );
1361 }
1362 catch ( Exception $e ) {
1363 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1364 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1365 }
1366 }
1367
1368 public function rest_helpers_post_types() {
1369 try {
1370 $postTypes = $this->core->get_post_types();
1371 return $this->create_rest_response( [ 'success' => true, 'postTypes' => $postTypes ], 200 );
1372 }
1373 catch ( Exception $e ) {
1374 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1375 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1376 }
1377 }
1378
1379 public function rest_settings_themes( $request ) {
1380 try {
1381 $method = $request->get_method();
1382 if ( $method === 'GET' ) {
1383 $themes = $this->core->get_themes();
1384 return $this->create_rest_response( [ 'success' => true, 'themes' => $themes ], 200 );
1385 }
1386 else if ( $method === 'POST' ) {
1387 $params = $request->get_json_params();
1388 $themes = $params['themes'];
1389 $themes = $this->core->update_themes( $themes );
1390 return $this->create_rest_response( [ 'success' => true, 'themes' => $themes ], 200 );
1391 }
1392 }
1393 catch ( Exception $e ) {
1394 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1395 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1396 }
1397 }
1398
1399 public function rest_settings_chatbots( $request ) {
1400 try {
1401 $method = $request->get_method();
1402 if ( $method === 'GET' ) {
1403 $chatbots = $this->core->get_chatbots();
1404 return $this->create_rest_response( [ 'success' => true, 'chatbots' => $chatbots ], 200 );
1405 }
1406 else if ( $method === 'POST' ) {
1407 $params = $request->get_json_params();
1408 $chatbots = $params['chatbots'];
1409 $chatbots = $this->core->update_chatbots( $chatbots );
1410 return $this->create_rest_response( [ 'success' => true, 'chatbots' => $chatbots ], 200 );
1411 }
1412 return $this->create_rest_response( [ 'success' => false, 'message' => 'Method not allowed' ], 405 );
1413 }
1414 catch ( Exception $e ) {
1415 $message = apply_filters( 'mwai_ai_exception', $e->getMessage() );
1416 return $this->create_rest_response( [ 'success' => false, 'message' => $message ], 500 );
1417 }
1418 }
1419
1420 #region Logs
1421
1422 public function rest_get_logs() {
1423 $logs = Meow_MWAI_Logging::get();
1424 return $this->create_rest_response( [ 'success' => true, 'data' => $logs ], 200 );
1425 }
1426
1427 public function rest_clear_logs() {
1428 Meow_MWAI_Logging::clear();
1429 return $this->create_rest_response( [ 'success' => true ], 200 );
1430 }
1431
1432 #endregion
1433
1434 #region Forms
1435
1436 public function rest_forms_list( $request ) {
1437 try {
1438 $args = [
1439 'post_type' => 'mwai_form',
1440 'posts_per_page' => 100,
1441 'post_status' => 'any',
1442 'orderby' => 'date',
1443 'order' => 'DESC'
1444 ];
1445
1446 $posts = get_posts( $args );
1447 $forms = array_map( function( $post ) {
1448 return [
1449 'id' => $post->ID,
1450 'title' => $post->post_title,
1451 'status' => $post->post_status
1452 ];
1453 }, $posts );
1454
1455 return $this->create_rest_response( [ 'success' => true, 'forms' => $forms ], 200 );
1456 }
1457 catch ( Exception $e ) {
1458 return $this->create_rest_response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
1459 }
1460 }
1461
1462 public function rest_forms_get( $request ) {
1463 try {
1464 $id = intval( $request->get_param( 'id' ) );
1465 if ( !$id ) {
1466 return $this->create_rest_response( [ 'success' => false, 'message' => 'Invalid form ID' ], 400 );
1467 }
1468
1469 $post = get_post( $id );
1470 if ( !$post || $post->post_type !== 'mwai_form' ) {
1471 return $this->create_rest_response( [ 'success' => false, 'message' => 'Form not found' ], 404 );
1472 }
1473
1474 $form = [
1475 'id' => $post->ID,
1476 'title' => [
1477 'raw' => $post->post_title,
1478 'rendered' => $post->post_title
1479 ],
1480 'content' => [
1481 'raw' => $post->post_content,
1482 'rendered' => $post->post_content
1483 ],
1484 'status' => $post->post_status
1485 ];
1486
1487 return $this->create_rest_response( [ 'success' => true, 'form' => $form ], 200 );
1488 }
1489 catch ( Exception $e ) {
1490 return $this->create_rest_response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
1491 }
1492 }
1493
1494 public function rest_forms_create( $request ) {
1495 try {
1496 $params = $request->get_json_params();
1497 $title = isset( $params['title'] ) ? $params['title'] : 'Untitled Form';
1498
1499 $post_data = [
1500 'post_title' => $title,
1501 'post_content' => '',
1502 'post_status' => 'draft',
1503 'post_type' => 'mwai_form'
1504 ];
1505
1506 $post_id = wp_insert_post( $post_data );
1507
1508 if ( is_wp_error( $post_id ) ) {
1509 return $this->create_rest_response( [ 'success' => false, 'message' => $post_id->get_error_message() ], 500 );
1510 }
1511
1512 $post = get_post( $post_id );
1513 $form = [
1514 'id' => $post->ID,
1515 'title' => [
1516 'raw' => $post->post_title,
1517 'rendered' => $post->post_title
1518 ],
1519 'status' => $post->post_status
1520 ];
1521
1522 return $this->create_rest_response( [ 'success' => true, 'form' => $form ], 200 );
1523 }
1524 catch ( Exception $e ) {
1525 return $this->create_rest_response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
1526 }
1527 }
1528
1529 public function rest_forms_update( $request ) {
1530 try {
1531 $params = $request->get_json_params();
1532 $id = isset( $params['id'] ) ? intval( $params['id'] ) : 0;
1533
1534 if ( !$id ) {
1535 return $this->create_rest_response( [ 'success' => false, 'message' => 'Invalid form ID' ], 400 );
1536 }
1537
1538 $post = get_post( $id );
1539 if ( !$post || $post->post_type !== 'mwai_form' ) {
1540 return $this->create_rest_response( [ 'success' => false, 'message' => 'Form not found' ], 404 );
1541 }
1542
1543 $post_data = [ 'ID' => $id ];
1544
1545 if ( isset( $params['title'] ) ) {
1546 $post_data['post_title'] = $params['title'];
1547 }
1548
1549 if ( isset( $params['content'] ) ) {
1550 $post_data['post_content'] = $params['content'];
1551 }
1552
1553 if ( isset( $params['status'] ) ) {
1554 $post_data['post_status'] = $params['status'];
1555 }
1556
1557 $result = wp_update_post( $post_data );
1558
1559 if ( is_wp_error( $result ) ) {
1560 return $this->create_rest_response( [ 'success' => false, 'message' => $result->get_error_message() ], 500 );
1561 }
1562
1563 $post = get_post( $id );
1564 $form = [
1565 'id' => $post->ID,
1566 'title' => [
1567 'raw' => $post->post_title,
1568 'rendered' => $post->post_title
1569 ],
1570 'content' => [
1571 'raw' => $post->post_content,
1572 'rendered' => $post->post_content
1573 ],
1574 'status' => $post->post_status
1575 ];
1576
1577 return $this->create_rest_response( [ 'success' => true, 'form' => $form ], 200 );
1578 }
1579 catch ( Exception $e ) {
1580 return $this->create_rest_response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
1581 }
1582 }
1583
1584 public function rest_forms_delete( $request ) {
1585 try {
1586 $params = $request->get_json_params();
1587 $id = isset( $params['id'] ) ? intval( $params['id'] ) : 0;
1588
1589 if ( !$id ) {
1590 return $this->create_rest_response( [ 'success' => false, 'message' => 'Invalid form ID' ], 400 );
1591 }
1592
1593 $post = get_post( $id );
1594 if ( !$post || $post->post_type !== 'mwai_form' ) {
1595 return $this->create_rest_response( [ 'success' => false, 'message' => 'Form not found' ], 404 );
1596 }
1597
1598 $result = wp_delete_post( $id, true );
1599
1600 if ( !$result ) {
1601 return $this->create_rest_response( [ 'success' => false, 'message' => 'Failed to delete form' ], 500 );
1602 }
1603
1604 return $this->create_rest_response( [ 'success' => true ], 200 );
1605 }
1606 catch ( Exception $e ) {
1607 return $this->create_rest_response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
1608 }
1609 }
1610
1611 #endregion
1612 }
1613