PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.9.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.9.4
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 / api.php
ai-engine / classes Last commit date
data 1 year ago engines 11 months ago exceptions 1 year ago modules 11 months ago query 11 months ago rest 11 months ago services 11 months ago admin.php 1 year ago api.php 11 months ago core.php 11 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 11 months ago
api.php
1183 lines
1 <?php
2
3 class Meow_MWAI_API {
4 public $core;
5 private $chatbot_module;
6 private $discussions_module;
7 private $bearer_token;
8 private $debug = false;
9
10 public function __construct( $chatbot_module, $discussions_module ) {
11 global $mwai_core;
12 $this->core = $mwai_core;
13 $this->chatbot_module = $chatbot_module;
14 $this->discussions_module = $discussions_module;
15 add_action( 'rest_api_init', [ $this, 'rest_api_init' ] );
16 $this->debug = $this->core->get_option( 'server_debug_mode' );
17 }
18
19 #region REST API
20 public function rest_api_init() {
21 $public_api = $this->core->get_option( 'public_api' );
22 if ( !$public_api ) {
23 return;
24 }
25 $this->bearer_token = $this->core->get_option( 'public_api_bearer_token' );
26 if ( !empty( $this->bearer_token ) ) {
27 add_filter( 'mwai_allow_public_api', [ $this, 'auth_via_bearer_token' ], 10, 3 );
28 }
29
30 register_rest_route( 'mwai/v1', '/simpleAuthCheck', [
31 'methods' => 'GET',
32 'callback' => [ $this, 'rest_simpleAuthCheck' ],
33 'permission_callback' => function ( $request ) {
34 return $this->core->can_access_public_api( 'simpleAuthCheck', $request );
35 },
36 ] );
37 register_rest_route( 'mwai/v1', '/simpleTextQuery', [
38 'methods' => 'POST',
39 'callback' => [ $this, 'rest_simpleTextQuery' ],
40 'permission_callback' => function ( $request ) {
41 return $this->core->can_access_public_api( 'simpleTextQuery', $request );
42 },
43 ] );
44 register_rest_route( 'mwai/v1', '/simpleFastTextQuery', [
45 'methods' => 'POST',
46 'callback' => [ $this, 'rest_simpleFastTextQuery' ],
47 'permission_callback' => function ( $request ) {
48 return $this->core->can_access_public_api( 'simpleFastTextQuery', $request );
49 },
50 ] );
51 register_rest_route( 'mwai/v1', '/simpleImageQuery', [
52 'methods' => 'POST',
53 'callback' => [ $this, 'rest_simpleImageQuery' ],
54 'permission_callback' => function ( $request ) {
55 return $this->core->can_access_public_api( 'simpleImageQuery', $request );
56 },
57 ] );
58 register_rest_route( 'mwai/v1', '/simpleImageEditQuery', [
59 'methods' => 'POST',
60 'callback' => [ $this, 'rest_simpleImageEditQuery' ],
61 'permission_callback' => function ( $request ) {
62 return $this->core->can_access_public_api( 'simpleImageEditQuery', $request );
63 },
64 ] );
65 register_rest_route( 'mwai/v1', '/simpleVisionQuery', [
66 'methods' => 'POST',
67 'callback' => [ $this, 'rest_simpleVisionQuery' ],
68 'permission_callback' => function ( $request ) {
69 return $this->core->can_access_public_api( 'simpleVisionQuery', $request );
70 },
71 ] );
72 register_rest_route( 'mwai/v1', '/simpleJsonQuery', [
73 'methods' => 'POST',
74 'callback' => [ $this, 'rest_simpleJsonQuery' ],
75 'permission_callback' => function ( $request ) {
76 return $this->core->can_access_public_api( 'simpleJsonQuery', $request );
77 },
78 ] );
79 register_rest_route( 'mwai/v1', '/moderationCheck', [
80 'methods' => 'POST',
81 'callback' => [ $this, 'rest_moderationCheck' ],
82 'permission_callback' => function ( $request ) {
83 return $this->core->can_access_public_api( 'moderationCheck', $request );
84 },
85 ] );
86 register_rest_route( 'mwai/v1', '/simpleTranscribeAudio', [
87 'methods' => 'POST',
88 'callback' => [ $this, 'rest_simpleTranscribeAudio' ],
89 'permission_callback' => function ( $request ) {
90 return $this->core->can_access_public_api( 'simpleTranscribeAudio', $request );
91 },
92 ] );
93 register_rest_route( 'mwai/v1', '/simpleFileUpload', [
94 'methods' => 'POST',
95 'callback' => [ $this, 'rest_simpleFileUpload' ],
96 'permission_callback' => function ( $request ) {
97 return $this->core->can_access_public_api( 'simpleFileUpload', $request );
98 },
99 ] );
100
101 if ( $this->chatbot_module ) {
102 register_rest_route( 'mwai/v1', '/simpleChatbotQuery', [
103 'methods' => 'POST',
104 'callback' => [ $this, 'rest_simpleChatbotQuery' ],
105 'permission_callback' => function ( $request ) {
106 return $this->core->can_access_public_api( 'simpleChatbotQuery', $request );
107 },
108 ] );
109
110 register_rest_route( 'mwai/v1', '/listChatbots', [
111 'methods' => 'GET',
112 'callback' => [ $this, 'rest_listChatbots' ],
113 'permission_callback' => function ( $request ) {
114 return $this->core->can_access_public_api( 'listChatbots', $request );
115 },
116 ] );
117 }
118 }
119
120 public function rest_simpleAuthCheck( $request ) {
121 try {
122 $params = $request->get_params();
123 $current_user = wp_get_current_user();
124 $current_email = $current_user->user_email;
125 return new WP_REST_Response( [ 'success' => true, 'data' => [
126 'type' => 'email',
127 'value' => $current_email
128 ] ], 200 );
129 }
130 catch ( Exception $e ) {
131 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
132 }
133 }
134
135 public function auth_via_bearer_token( $allow, $feature, $extra ) {
136 if ( !empty( $extra ) && !empty( $extra->get_header( 'Authorization' ) ) ) {
137 $token = $extra->get_header( 'Authorization' );
138 $token = str_replace( 'Bearer ', '', $token );
139 if ( $token === $this->bearer_token ) {
140 // We set the current user to the first admin.
141 $admin = $this->core->get_admin_user();
142 wp_set_current_user( $admin->ID, $admin->user_login );
143 return true;
144 }
145 }
146 return $allow;
147 }
148
149 public function rest_simpleChatbotQuery( $request ) {
150 try {
151 $params = $request->get_params();
152 $botId = isset( $params['botId'] ) ? $params['botId'] : '';
153 $message = isset( $params['message'] ) ? $params['message'] : '';
154 if ( empty( $message ) ) {
155 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
156 }
157 $chatId = isset( $params['chatId'] ) ? $params['chatId'] : null;
158 $fileId = isset( $params['fileId'] ) ? $params['fileId'] : null;
159 $queryParams = [];
160 if ( !empty( $chatId ) ) {
161 $queryParams['chatId'] = $chatId;
162 }
163 if ( !empty( $fileId ) ) {
164 $queryParams['fileId'] = $fileId;
165 }
166 if ( empty( $botId ) || empty( $message ) ) {
167 throw new Exception( 'The botId and message are required.' );
168 }
169
170 if ( $this->debug ) {
171 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
172 $debug = sprintf( 'REST [SimpleChatbotQuery]: %s, %s', $shortMessage, json_encode( $queryParams ) );
173 Meow_MWAI_Logging::log( $debug );
174 }
175
176 $reply = $this->simpleChatbotQuery( $botId, $message, $queryParams, false );
177 return new WP_REST_Response( [
178 'success' => true,
179 'data' => $reply['reply'],
180 'extra' => [
181 'actions' => $reply['actions'],
182 'chatId' => $reply['chatId']
183 ]
184 ], 200 );
185 }
186 catch ( Exception $e ) {
187 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
188 }
189 }
190
191 public function rest_listChatbots( $request ) {
192 try {
193 // Get all chatbots
194 $chatbots = get_option( 'mwai_chatbots', [] );
195 $environments = $this->core->get_option( 'ai_envs' );
196 $mcp_envs = $this->core->get_option( 'mcp_envs', [] );
197
198 // Get all models from all environments
199 $all_models = [];
200 foreach ( $environments as $env ) {
201 try {
202 $engine = Meow_MWAI_Engines_Factory::get( $this->core, $env['id'] );
203 $env_models = $engine->retrieve_models();
204 foreach ( $env_models as $model ) {
205 $all_models[$model['model']] = $model;
206 }
207 }
208 catch ( Exception $e ) {
209 // Skip environments that fail
210 }
211 }
212
213 // Debug: Log model info for gpt-4.1-mini
214 if ( $this->debug && isset( $all_models['gpt-4.1-mini'] ) ) {
215 error_log( '[AI Engine API] Model info for gpt-4.1-mini: ' . json_encode( $all_models['gpt-4.1-mini'] ) );
216 }
217
218 // Get registered functions
219 $functions = apply_filters( 'mwai_functions_list', [] );
220 $function_names = [];
221 foreach ( $functions as $function ) {
222 $function_names[] = $function->name ?? 'unknown';
223 }
224
225 $result = [];
226
227 foreach ( $chatbots as $chatbotId => $chatbot ) {
228 // Debug log the chatbot structure
229 if ( $this->debug && ( $chatbot['name'] ?? '' ) === 'Jordy' ) {
230 error_log( '[AI Engine API] Jordy chatbot structure: ' . json_encode( $chatbot ) );
231 }
232
233 // Basic info
234 $info = [
235 'id' => $chatbot['botId'] ?? $chatbotId, // Use botId if available, fallback to array index
236 'name' => $chatbot['name'] ?? 'Unnamed',
237 'type' => 'chat', // Default type
238 'model' => null,
239 'model_name' => null,
240 'environment' => null,
241 'environment_name' => null,
242 'functions' => [],
243 'tools' => [], // Add tools array
244 'mcp_servers' => []
245 ];
246
247 // Determine chatbot type
248 if ( !empty( $chatbot['type'] ) ) {
249 $info['type'] = $chatbot['type'];
250 }
251 else {
252 // Try to infer type from model or other properties
253 if ( !empty( $chatbot['model'] ) ) {
254 if ( strpos( $chatbot['model'], 'realtime' ) !== false ) {
255 $info['type'] = 'realtime';
256 }
257 else if ( strpos( $chatbot['model'], 'image' ) !== false || strpos( $chatbot['model'], 'dall-e' ) !== false ) {
258 $info['type'] = 'images';
259 }
260 else if ( !empty( $chatbot['assistantId'] ) ) {
261 $info['type'] = 'assistant';
262 }
263 }
264 }
265
266 // Get model info
267 if ( !empty( $chatbot['model'] ) ) {
268 $info['model'] = $chatbot['model'];
269 // Find model name
270 if ( isset( $all_models[$chatbot['model']] ) ) {
271 $info['model_name'] = $all_models[$chatbot['model']]['name'] ?? $chatbot['model'];
272 }
273 else {
274 $info['model_name'] = $chatbot['model'];
275 }
276 }
277
278 // Get environment info
279 if ( !empty( $chatbot['envId'] ) ) {
280 $info['environment'] = $chatbot['envId'];
281 // Find environment name
282 foreach ( $environments as $env ) {
283 if ( $env['id'] === $chatbot['envId'] ) {
284 $info['environment_name'] = $env['name'] ?? $chatbot['envId'];
285 break;
286 }
287 }
288 }
289
290 // Check if it uses functions - get specific function names if available
291 if ( !empty( $chatbot['functions'] ) ) {
292 if ( is_array( $chatbot['functions'] ) ) {
293 // Functions are stored as array of objects with id and type
294 $chatbot_functions = [];
295 foreach ( $chatbot['functions'] as $func ) {
296 if ( isset( $func['id'] ) ) {
297 // Try to find function name by ID
298 $func_name = $this->get_function_name_by_id( $func['id'] );
299 if ( $func_name ) {
300 $chatbot_functions[] = $func_name;
301 }
302 else {
303 // Fallback: include the ID if name not found
304 $chatbot_functions[] = 'function_' . $func['id'];
305 }
306 }
307 }
308 $info['functions'] = $chatbot_functions;
309 }
310 else if ( $chatbot['functions'] === true ) {
311 // If functions is just true, it uses all registered functions
312 $info['functions'] = $function_names;
313 }
314 }
315
316 // Check for tools (Web Search, Image Generation)
317 if ( !empty( $chatbot['tools'] ) && is_array( $chatbot['tools'] ) ) {
318 // Filter tools based on model capabilities
319 $supported_tools = [];
320 if ( !empty( $chatbot['model'] ) ) {
321 // Try exact match first
322 $model_key = $chatbot['model'];
323 $model_info = $all_models[$model_key] ?? null;
324
325 // If not found and it's an OpenRouter model, try without prefix
326 if ( !$model_info && strpos( $model_key, '/' ) !== false ) {
327 $model_key = substr( $model_key, strpos( $model_key, '/' ) + 1 );
328 $model_info = $all_models[$model_key] ?? null;
329 }
330
331 if ( $model_info ) {
332 $model_tools = $model_info['tools'] ?? [];
333
334 // Only include tools that are both configured AND supported by the model
335 foreach ( $chatbot['tools'] as $tool ) {
336 if ( in_array( $tool, $model_tools ) ) {
337 $supported_tools[] = $tool;
338 }
339 }
340 }
341 else {
342 // If model not found in our list, keep all configured tools
343 // This allows custom models to use tools
344 $supported_tools = $chatbot['tools'];
345 }
346 }
347 $info['tools'] = $supported_tools;
348 }
349
350 // Check for MCP servers
351 if ( !empty( $chatbot['mcp_servers'] ) && is_array( $chatbot['mcp_servers'] ) ) {
352 foreach ( $chatbot['mcp_servers'] as $mcpServer ) {
353 if ( !empty( $mcpServer['id'] ) ) {
354 // Find MCP server name
355 foreach ( $mcp_envs as $mcp ) {
356 if ( $mcp['id'] === $mcpServer['id'] ) {
357 $info['mcp_servers'][] = [
358 'id' => $mcp['id'],
359 'name' => $mcp['name'] ?? 'Unnamed MCP Server'
360 ];
361 break;
362 }
363 }
364 }
365 }
366 }
367
368 $result[] = $info;
369 }
370
371 return new WP_REST_Response( [
372 'success' => true,
373 'data' => $result
374 ], 200 );
375 }
376 catch ( Exception $e ) {
377 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
378 }
379 }
380
381 public function rest_simpleTextQuery( $request ) {
382 try {
383 $params = $request->get_params();
384 $message = isset( $params['message'] ) ? $params['message'] : '';
385 if ( empty( $message ) ) {
386 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
387 }
388 $options = isset( $params['options'] ) ? $params['options'] : [];
389 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
390 if ( !empty( $scope ) ) {
391 $options['scope'] = $scope;
392 }
393 if ( empty( $message ) ) {
394 throw new Exception( 'The message is required.' );
395 }
396
397 if ( $this->debug ) {
398 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
399 $debug = sprintf( 'REST [SimpleTextQuery]: %s, %s', $shortMessage, json_encode( $options ) );
400 Meow_MWAI_Logging::log( $debug );
401 }
402
403 $reply = $this->simpleTextQuery( $message, $options );
404 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
405 }
406 catch ( Exception $e ) {
407 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
408 }
409 }
410
411 public function rest_simpleFastTextQuery( $request ) {
412 try {
413 $params = $request->get_params();
414 $message = isset( $params['message'] ) ? $params['message'] : '';
415 if ( empty( $message ) ) {
416 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
417 }
418 $options = isset( $params['options'] ) ? $params['options'] : [];
419 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
420 if ( !empty( $scope ) ) {
421 $options['scope'] = $scope;
422 }
423 if ( empty( $message ) ) {
424 throw new Exception( 'The message is required.' );
425 }
426
427 if ( $this->debug ) {
428 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
429 $debug = sprintf( 'REST [SimpleFastTextQuery]: %s, %s', $shortMessage, json_encode( $options ) );
430 Meow_MWAI_Logging::log( $debug );
431 }
432
433 $reply = $this->simpleFastTextQuery( $message, $options );
434 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
435 }
436 catch ( Exception $e ) {
437 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
438 }
439 }
440
441 public function rest_simpleImageQuery( $request ) {
442 try {
443 $params = $request->get_params();
444 $message = isset( $params['message'] ) ? $params['message'] : '';
445 if ( empty( $message ) ) {
446 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
447 }
448 $options = isset( $params['options'] ) ? $params['options'] : [];
449 $resolution = isset( $params['resolution'] ) ? $params['resolution'] : '';
450 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
451 if ( !empty( $scope ) ) {
452 $options['scope'] = $scope;
453 }
454 if ( empty( $message ) ) {
455 throw new Exception( 'The message is required.' );
456 }
457 if ( !empty( $resolution ) ) {
458 $options['resolution'] = $resolution;
459 }
460
461 if ( $this->debug ) {
462 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
463 $debug = sprintf( 'REST [SimpleImageQuery]: %s, %s', $shortMessage, json_encode( $options ) );
464 Meow_MWAI_Logging::log( $debug );
465 }
466
467 $reply = $this->simpleImageQuery( $message, $options );
468 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
469 }
470 catch ( Exception $e ) {
471 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
472 }
473 }
474
475 public function rest_simpleImageEditQuery( $request ) {
476 try {
477 $params = $request->get_params();
478 $message = isset( $params['message'] ) ? $params['message'] : '';
479 if ( empty( $message ) ) {
480 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
481 }
482 $mediaId = isset( $params['mediaId'] ) ? intval( $params['mediaId'] ) : 0;
483 $options = isset( $params['options'] ) ? $params['options'] : [];
484 $resolution = isset( $params['resolution'] ) ? $params['resolution'] : '';
485 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
486 if ( !empty( $scope ) ) {
487 $options['scope'] = $scope;
488 }
489 if ( empty( $message ) ) {
490 throw new Exception( 'The message is required.' );
491 }
492 if ( empty( $mediaId ) ) {
493 throw new Exception( 'The mediaId is required.' );
494 }
495 if ( !empty( $resolution ) ) {
496 $options['resolution'] = $resolution;
497 }
498
499 if ( $this->debug ) {
500 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
501 $debug = sprintf( 'REST [SimpleImageEditQuery]: %s, %s', $shortMessage, json_encode( $options ) );
502 Meow_MWAI_Logging::log( $debug );
503 }
504
505 $reply = $this->simpleImageEditQuery( $message, $mediaId, $options );
506 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
507 }
508 catch ( Exception $e ) {
509 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
510 }
511 }
512
513 public function rest_simpleVisionQuery( $request ) {
514 try {
515 $params = $request->get_params();
516 $message = isset( $params['message'] ) ? $params['message'] : '';
517 if ( empty( $message ) ) {
518 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
519 }
520 $url = isset( $params['url'] ) ? $params['url'] : '';
521
522 // Check for common parameter mistakes and provide helpful guidance
523 if ( empty( $url ) && isset( $params['imageUrl'] ) ) {
524 throw new Exception( 'Parameter "url" is required. Did you mean to use "url" instead of "imageUrl"?' );
525 }
526 if ( empty( $url ) && isset( $params['image_url'] ) ) {
527 throw new Exception( 'Parameter "url" is required. Did you mean to use "url" instead of "image_url"?' );
528 }
529
530 $options = isset( $params['options'] ) ? $params['options'] : [];
531 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
532 if ( !empty( $scope ) ) {
533 $options['scope'] = $scope;
534 }
535 if ( empty( $message ) ) {
536 throw new Exception( 'The message is required.' );
537 }
538 if ( empty( $url ) ) {
539 throw new Exception( 'The "url" parameter is required for image analysis.' );
540 }
541
542 if ( $this->debug ) {
543 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
544 $debug = sprintf( 'REST [SimpleVisionQuery]: %s, %s', $shortMessage, json_encode( $options ) );
545 Meow_MWAI_Logging::log( $debug );
546 }
547
548 $reply = $this->simpleVisionQuery( $message, $url, null, $options );
549 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
550 }
551 catch ( Exception $e ) {
552 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
553 }
554 }
555
556 public function rest_simpleJsonQuery( $request ) {
557 try {
558 $params = $request->get_params();
559 $message = isset( $params['message'] ) ? $params['message'] : '';
560 if ( empty( $message ) ) {
561 $message = isset( $params['prompt'] ) ? $params['prompt'] : '';
562 }
563 $options = isset( $params['options'] ) ? $params['options'] : [];
564 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
565 if ( !empty( $scope ) ) {
566 $options['scope'] = $scope;
567 }
568 if ( empty( $message ) ) {
569 throw new Exception( 'The message is required.' );
570 }
571
572 if ( $this->debug ) {
573 $shortMessage = Meow_MWAI_Logging::shorten( $message, 64 );
574 $debug = sprintf( 'REST [SimpleJsonQuery]: %s, %s', $shortMessage, json_encode( $options ) );
575 Meow_MWAI_Logging::log( $debug );
576 }
577
578 $reply = $this->simpleJsonQuery( $message, null, null, $options );
579 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
580 }
581 catch ( Exception $e ) {
582 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
583 }
584 }
585
586 public function rest_moderationCheck( $request ) {
587 try {
588 $params = $request->get_params();
589 $text = isset( $params['text'] ) ? $params['text'] : '';
590
591 // Check for common parameter mistakes and provide helpful guidance
592 if ( empty( $text ) && isset( $params['message'] ) ) {
593 throw new Exception( 'Parameter "text" is required. Did you mean to use "text" instead of "message"?' );
594 }
595 if ( empty( $text ) && isset( $params['content'] ) ) {
596 throw new Exception( 'Parameter "text" is required. Did you mean to use "text" instead of "content"?' );
597 }
598
599 if ( empty( $text ) ) {
600 throw new Exception( 'The "text" parameter is required for content moderation.' );
601 }
602
603 if ( $this->debug ) {
604 $shortText = Meow_MWAI_Logging::shorten( $text, 64 );
605 $debug = sprintf( 'REST [ModerationCheck]: %s', $shortText );
606 Meow_MWAI_Logging::log( $debug );
607 }
608
609 $reply = $this->moderationCheck( $text );
610 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
611 }
612 catch ( Exception $e ) {
613 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
614 }
615 }
616
617 public function rest_simpleTranscribeAudio( $request ) {
618 try {
619 $params = $request->get_params();
620 $url = isset( $params['url'] ) ? $params['url'] : '';
621 $mediaId = isset( $params['mediaId'] ) ? intval( $params['mediaId'] ) : 0;
622
623 // Check for common parameter mistakes and provide helpful guidance
624 if ( empty( $url ) && empty( $mediaId ) ) {
625 if ( isset( $params['audioUrl'] ) ) {
626 throw new Exception( 'Parameter "url" is required. Did you mean to use "url" instead of "audioUrl"?' );
627 }
628 if ( isset( $params['audio_url'] ) ) {
629 throw new Exception( 'Parameter "url" is required. Did you mean to use "url" instead of "audio_url"?' );
630 }
631 if ( isset( $params['file'] ) ) {
632 throw new Exception( 'Use "url" for remote files or "mediaId" for uploaded files. Found "file" parameter instead.' );
633 }
634 }
635
636 $options = isset( $params['options'] ) ? $params['options'] : [];
637 $scope = isset( $params['scope'] ) ? $params['scope'] : 'public-api';
638
639 if ( !empty( $scope ) ) {
640 $options['scope'] = $scope;
641 }
642
643 // Get file path from mediaId if provided
644 $path = null;
645 if ( $mediaId > 0 ) {
646 $path = get_attached_file( $mediaId );
647 if ( empty( $path ) ) {
648 throw new Exception( 'The media file cannot be found.' );
649 }
650 }
651
652 if ( empty( $url ) && empty( $path ) ) {
653 throw new Exception( 'Either a "url" parameter or a "mediaId" parameter is required for audio transcription.' );
654 }
655
656 if ( $this->debug ) {
657 $debug = sprintf( 'REST [SimpleTranscribeAudio]: url=%s, mediaId=%d, %s',
658 $url ? 'provided' : 'none',
659 $mediaId,
660 json_encode( $options )
661 );
662 Meow_MWAI_Logging::log( $debug );
663 }
664
665 $reply = $this->simpleTranscribeAudio( $url, $path, $options );
666 return new WP_REST_Response( [ 'success' => true, 'data' => $reply ], 200 );
667 }
668 catch ( Exception $e ) {
669 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
670 }
671 }
672
673 public function rest_simpleFileUpload( $request ) {
674 try {
675 $params = $request->get_params();
676 $files = $request->get_file_params();
677
678 // Check if file is provided
679 if ( empty( $files['file'] ) ) {
680 // Check for base64 encoded file data
681 $base64 = isset( $params['base64'] ) ? $params['base64'] : '';
682 $filename = isset( $params['filename'] ) ? $params['filename'] : '';
683
684 if ( empty( $base64 ) ) {
685 throw new Exception( 'Either a file upload or base64 encoded data is required.' );
686 }
687
688 // Handle base64 upload
689 $options = isset( $params['options'] ) ? $params['options'] : [];
690 $purpose = isset( $params['purpose'] ) ? $params['purpose'] : 'files';
691 $ttl = isset( $params['ttl'] ) ? intval( $params['ttl'] ) : 3600;
692 $target = isset( $params['target'] ) ? $params['target'] : null;
693 $metadata = isset( $params['metadata'] ) ? $params['metadata'] : [];
694
695 if ( empty( $filename ) ) {
696 $filename = 'upload-' . time() . '.png'; // Default filename for base64
697 }
698
699 // Log the request if debug is enabled
700 if ( $this->debug ) {
701 $debug = sprintf( 'REST [SimpleFileUpload]: base64 upload, filename=%s, purpose=%s',
702 $filename,
703 $purpose
704 );
705 Meow_MWAI_Logging::log( $debug );
706 }
707
708 $result = $this->simpleFileUpload( null, $base64, $filename, $purpose, $ttl, $target, $metadata );
709 }
710 else {
711 // Handle regular file upload
712 $file = $files['file'];
713 $purpose = isset( $params['purpose'] ) ? $params['purpose'] : 'files';
714 $ttl = isset( $params['ttl'] ) ? intval( $params['ttl'] ) : 3600;
715 $target = isset( $params['target'] ) ? $params['target'] : null;
716 $metadata = isset( $params['metadata'] ) ? $params['metadata'] : [];
717
718 if ( $this->debug ) {
719 $debug = sprintf( 'REST [SimpleFileUpload]: file upload, name=%s, purpose=%s',
720 $file['name'],
721 $purpose
722 );
723 Meow_MWAI_Logging::log( $debug );
724 }
725
726 $result = $this->simpleFileUpload( $file, null, null, $purpose, $ttl, $target, $metadata );
727 }
728
729 return new WP_REST_Response( [ 'success' => true, 'data' => $result ], 200 );
730 }
731 catch ( Exception $e ) {
732 return new WP_REST_Response( [ 'success' => false, 'message' => $e->getMessage() ], 500 );
733 }
734 }
735 #endregion
736
737 #region Simple API
738 /**
739 * Executes a vision query.`
740 *
741 * @param string $message The prompt for the AI.
742 * @param string $url The URL of the image to analyze.
743 * @param string|null $path The path to the image file. If provided, the image data will be read from this file.
744 * @param array $params Additional parameters for the AI query.
745 *
746 * @return string The result of the AI query.
747 */
748 public function simpleVisionQuery( $message, $url, $path = null, $params = [] ) {
749 global $mwai_core;
750 $ai_vision_default_env = $this->core->get_option( 'ai_vision_default_env' );
751 $ai_vision_default_model = $this->core->get_option( 'ai_vision_default_model' );
752 if ( empty( $ai_vision_default_model ) ) {
753 $ai_vision_default_model = MWAI_FALLBACK_MODEL_VISION;
754 }
755 $query = new Meow_MWAI_Query_Text( $message );
756 if ( !empty( $ai_vision_default_env ) ) {
757 $query->set_env_id( $ai_vision_default_env );
758 }
759 if ( !empty( $ai_vision_default_model ) ) {
760 $query->set_model( $ai_vision_default_model );
761 }
762 $query->inject_params( $params );
763 if ( isset( $params['image_remote_upload'] ) ) {
764 $query->image_remote_upload = $params['image_remote_upload'];
765 }
766 if ( !empty( $url ) ) {
767 $query->set_file( Meow_MWAI_Query_DroppedFile::from_url( $url, 'vision' ) );
768 }
769 else if ( !empty( $path ) ) {
770 $query->set_file( Meow_MWAI_Query_DroppedFile::from_path( $path, 'vision' ) );
771 }
772 $reply = $mwai_core->run_query( $query );
773 return $reply->result;
774 }
775
776 /**
777 * Executes a chatbot query.
778 * It will use the discussion if chatId is provided in the parameters.
779 *
780 * @param string $botId The ID of the chatbot.
781 * @param string $message The prompt for the AI.
782 * @param array $params Additional parameters for the AI query.
783 *
784 * @return string The result of the AI query.
785 */
786 public function simpleChatbotQuery( $botId, $message, $params = [], $onlyReply = true ) {
787 if ( !isset( $params['messages'] ) && isset( $params['chatId'] ) ) {
788 if ( $this->core->get_option( 'chatbot_discussions' ) ) {
789 $discussion = $this->discussions_module->get_discussion( $botId, $params['chatId'] );
790 if ( !empty( $discussion ) ) {
791 $params['messages'] = $discussion['messages'];
792 }
793 }
794 else {
795 Meow_MWAI_Logging::log( 'The chatId was provided; but the discussions are not enabled.' );
796 }
797 }
798 $fileId = isset( $params['fileId'] ) ? $params['fileId'] : null;
799 $data = $this->chatbot_module->chat_submit( $botId, $message, $fileId, $params );
800 return $onlyReply ? $data['reply'] : $data;
801 }
802
803 /**
804 * Executes a text query.
805 *
806 * @param string $message The prompt for the AI.
807 * @param array $params Additional parameters for the AI query.
808 *
809 * @return string The result of the AI query.
810 */
811 public function simpleTextQuery( $message, $params = [] ) {
812 global $mwai_core;
813 $query = new Meow_MWAI_Query_Text( $message );
814 $query->inject_params( $params );
815 $reply = $mwai_core->run_query( $query );
816 return $reply->result;
817 }
818
819 public function simpleFastTextQuery( $message, $params = [] ) {
820 global $mwai_core;
821 $query = new Meow_MWAI_Query_Text( $message );
822
823 // Use the Default (Fast) model and environment
824 $fastDefaultModel = $mwai_core->get_option( 'ai_fast_default_model' );
825 if ( !empty( $fastDefaultModel ) ) {
826 $query->set_model( $fastDefaultModel );
827 }
828
829 $fastDefaultEnv = $mwai_core->get_option( 'ai_fast_default_env' );
830 if ( !empty( $fastDefaultEnv ) ) {
831 $query->set_env_id( $fastDefaultEnv );
832 }
833
834 // Inject any additional params (which may override the defaults)
835 $query->inject_params( $params );
836
837 try {
838 $reply = $mwai_core->run_query( $query );
839 return $reply->result;
840 }
841 catch ( Exception $e ) {
842 // If Fast Model fails, try with default model
843 Meow_MWAI_Logging::warn( "Fast Model failed: " . $e->getMessage() . " - Falling back to default model." );
844
845 // Create a new query with default model/env
846 $fallbackQuery = new Meow_MWAI_Query_Text( $message );
847
848 $defaultModel = $mwai_core->get_option( 'ai_default_model' );
849 if ( !empty( $defaultModel ) ) {
850 $fallbackQuery->set_model( $defaultModel );
851 }
852
853 $defaultEnv = $mwai_core->get_option( 'ai_default_env' );
854 if ( !empty( $defaultEnv ) ) {
855 $fallbackQuery->set_env_id( $defaultEnv );
856 }
857
858 // Inject params again (except model/env which we just set)
859 $fallbackParams = $params;
860 unset( $fallbackParams['model'] );
861 unset( $fallbackParams['envId'] );
862 $fallbackQuery->inject_params( $fallbackParams );
863
864 $reply = $mwai_core->run_query( $fallbackQuery );
865 return $reply->result;
866 }
867 }
868
869 public function simpleImageQuery( $message, $params = [] ) {
870 global $mwai_core;
871 $query = new Meow_MWAI_Query_Image( $message );
872 $query->inject_params( $params );
873 $reply = $mwai_core->run_query( $query );
874 return $reply->result;
875 }
876
877 public function simpleImageEditQuery( $message, $mediaId, $params = [] ) {
878 global $mwai_core;
879 $query = new Meow_MWAI_Query_EditImage( $message );
880 $query->inject_params( $params );
881 $path = get_attached_file( $mediaId );
882 if ( empty( $path ) ) {
883 throw new Exception( 'The media cannot be found.' );
884 }
885 // TODO: Maybe 'vision' should be 'edit'.
886 $query->set_file( Meow_MWAI_Query_DroppedFile::from_path( $path, 'vision' ) );
887 $reply = $mwai_core->run_query( $query );
888 return $reply->result;
889 }
890
891 /**
892 * Generates an image relevant to the text.
893 */
894 public function imageQueryForMediaLibrary( $message, $params = [], $postId = null ) {
895 $query = new Meow_MWAI_Query_Image( $message );
896 $query->inject_params( $params );
897 $query->set_local_download( null );
898 $reply = $this->core->run_query( $query );
899 preg_match( '/\!\[Image\]\((.*?)\)/', $reply->result, $matches );
900 $url = $matches[1] ?? $reply->result;
901
902 // Check if the URL is already a WordPress attachment URL to avoid duplicates
903 $attachmentId = null;
904 $upload_dir = wp_upload_dir();
905 if ( strpos( $url, $upload_dir['baseurl'] ) === 0 ) {
906 // This is already a local WordPress upload, try to find the attachment ID
907 // First try by GUID
908 global $wpdb;
909 $attachmentId = $wpdb->get_var( $wpdb->prepare(
910 "SELECT ID FROM {$wpdb->posts} WHERE guid = %s AND post_type = 'attachment'",
911 $url
912 ) );
913
914 // If not found by GUID, try by attachment URL (more reliable)
915 if ( empty( $attachmentId ) ) {
916 $attachmentId = attachment_url_to_postid( $url );
917 }
918 }
919
920 // If not found or not a local URL, add it to the media library
921 if ( empty( $attachmentId ) ) {
922 $attachmentId = $this->core->add_image_from_url( $url, null, null, null, null, null, $postId );
923 if ( empty( $attachmentId ) ) {
924 throw new Exception( 'Could not add the image to the Media Library.' );
925 }
926 }
927
928 // TODO: We should create a nice title, caption, and alt.
929 $media = [
930 'id' => $attachmentId,
931 'url' => wp_get_attachment_url( $attachmentId ),
932 'title' => get_the_title( $attachmentId ),
933 'caption' => wp_get_attachment_caption( $attachmentId ),
934 'alt' => get_post_meta( $attachmentId, '_wp_attachment_image_alt', true )
935 ];
936 return $media;
937 }
938
939 /**
940 * Executes a query that will have to return a JSON result.
941 *
942 * @param string $message The prompt for the AI.
943 * @param array $params Additional parameters for the AI query.
944 *
945 * @return array The result of the AI query.
946 */
947 public function simpleJsonQuery( $message, $url = null, $path = null, $params = [] ) {
948 if ( !empty( $url ) || !empty( $path ) ) {
949 throw new Exception( 'The url and path are not supported yet by the simpleJsonQuery.' );
950 }
951 global $mwai_core;
952 $query = new Meow_MWAI_Query_Text( $message . "\nYour reply must be a formatted JSON." );
953 $query->inject_params( $params );
954 $query->set_response_format( 'json' );
955 $ai_json_default_env = $mwai_core->get_option( 'ai_json_default_env' );
956 $ai_json_default_model = $mwai_core->get_option( 'ai_json_default_model' );
957 if ( !empty( $ai_json_default_env ) ) {
958 $query->set_env_id( $ai_json_default_env );
959 }
960 if ( !empty( $ai_json_default_model ) ) {
961 $query->set_model( $ai_json_default_model );
962 }
963 else {
964 $query->set_model( MWAI_FALLBACK_MODEL_JSON );
965 }
966 $reply = $mwai_core->run_query( $query );
967 try {
968 $json = json_decode( $reply->result, true );
969 return $json;
970 }
971 catch ( Exception $e ) {
972 throw new Exception( 'The result is not a valid JSON.' );
973 }
974 }
975
976 /**
977 * Uploads a file to the system.
978 *
979 * @param array|null $file The file array from $_FILES.
980 * @param string|null $base64 Base64 encoded file data.
981 * @param string|null $filename The filename for base64 uploads.
982 * @param string $purpose The purpose of the file upload (e.g., 'files', 'vision', 'assistant').
983 * @param int $ttl Time to live in seconds. Default 3600 (1 hour).
984 * @param string|null $target Target location: 'uploads' or 'library'.
985 * @param array $metadata Additional metadata to store with the file.
986 *
987 * @return array Array with 'id' (refId) and 'url' of the uploaded file.
988 */
989 public function simpleFileUpload( $file = null, $base64 = null, $filename = null, $purpose = 'files', $ttl = 3600, $target = null, $metadata = [] ) {
990 global $mwai_core;
991
992 if ( !$this->core->files ) {
993 throw new Exception( 'Files module is not available.' );
994 }
995
996 // Determine target from settings if not provided
997 if ( empty( $target ) ) {
998 $target = $this->core->get_option( 'image_local_upload', 'uploads' );
999 }
1000
1001 try {
1002 if ( !empty( $base64 ) ) {
1003 // Handle base64 upload
1004 if ( empty( $filename ) ) {
1005 $filename = 'upload-' . time() . '.dat';
1006 }
1007
1008 // For base64 uploads, we need to decode and create a temp file first
1009 $binary = base64_decode( $base64 );
1010 if ( !$binary ) {
1011 throw new Exception( 'Invalid base64 data.' );
1012 }
1013
1014 // Create a temporary file
1015 $tmp_path = wp_tempnam( 'mwai-upload' );
1016 file_put_contents( $tmp_path, $binary );
1017
1018 // Use the regular upload method
1019 $refId = $this->core->files->upload_file(
1020 $tmp_path,
1021 $filename,
1022 $purpose,
1023 $metadata,
1024 null, // envId
1025 $target,
1026 $ttl
1027 );
1028
1029 // Clean up temp file if it was uploaded to library
1030 if ( $target === 'library' && file_exists( $tmp_path ) ) {
1031 @unlink( $tmp_path );
1032 }
1033
1034 $url = $this->core->files->get_url( $refId );
1035
1036 return [
1037 'id' => $refId,
1038 'url' => $url
1039 ];
1040 }
1041 else if ( !empty( $file ) && is_array( $file ) ) {
1042 // Handle regular file upload
1043 if ( !empty( $file['error'] ) ) {
1044 throw new Exception( 'File upload error: ' . $file['error'] );
1045 }
1046
1047 $refId = $this->core->files->upload_file(
1048 $file['tmp_name'],
1049 $file['name'],
1050 $purpose,
1051 $metadata,
1052 null, // envId
1053 $target,
1054 $ttl
1055 );
1056
1057 $url = $this->core->files->get_url( $refId );
1058
1059 return [
1060 'id' => $refId,
1061 'url' => $url
1062 ];
1063 }
1064 else {
1065 throw new Exception( 'Either a file or base64 data must be provided.' );
1066 }
1067 }
1068 catch ( Exception $e ) {
1069 throw new Exception( 'File upload failed: ' . $e->getMessage() );
1070 }
1071 }
1072
1073 /**
1074 * Executes an audio transcription query.
1075 *
1076 * @param string $url The URL of the audio file to transcribe.
1077 * @param string|null $path The path to the audio file. If provided, the audio data will be read from this file.
1078 * @param array $params Additional parameters for the transcription query.
1079 *
1080 * @return string The transcribed text.
1081 */
1082 public function simpleTranscribeAudio( $url = null, $path = null, $params = [] ) {
1083 global $mwai_core;
1084 $ai_audio_default_env = $this->core->get_option( 'ai_audio_default_env' );
1085 $ai_audio_default_model = $this->core->get_option( 'ai_audio_default_model' );
1086
1087 if ( empty( $ai_audio_default_model ) ) {
1088 $ai_audio_default_model = 'whisper-1'; // Default transcription model
1089 }
1090
1091 $query = new Meow_MWAI_Query_Transcribe();
1092
1093 if ( !empty( $ai_audio_default_env ) ) {
1094 $query->set_env_id( $ai_audio_default_env );
1095 }
1096 if ( !empty( $ai_audio_default_model ) ) {
1097 $query->set_model( $ai_audio_default_model );
1098 }
1099
1100 $query->inject_params( $params );
1101
1102 if ( !empty( $url ) ) {
1103 // Use 'files' as the purpose for audio files
1104 $query->set_file( Meow_MWAI_Query_DroppedFile::from_url( $url, 'files' ) );
1105 }
1106 else if ( !empty( $path ) ) {
1107 // Use 'files' as the purpose for audio files
1108 $query->set_file( Meow_MWAI_Query_DroppedFile::from_path( $path, 'files' ) );
1109 }
1110 else {
1111 throw new Exception( 'Either a URL or a path must be provided for the audio file.' );
1112 }
1113
1114 $reply = $mwai_core->run_query( $query );
1115 return $reply->result;
1116 }
1117 #endregion
1118
1119 #region Standard API
1120 /**
1121 * Checks if a text is safe or not.
1122 *
1123 * @param string $text The text to check.
1124 *
1125 * @return bool True if the text is safe, false otherwise.
1126 */
1127 public function moderationCheck( $text ) {
1128 global $mwai_core;
1129 $openai = Meow_MWAI_Engines_Factory::get_openai( $mwai_core );
1130 $res = $openai->moderate( $text );
1131 if ( !empty( $res ) && !empty( $res['results'] ) ) {
1132 return (bool) $res['results'][0]['flagged'];
1133 }
1134 }
1135 #endregion
1136
1137 #region Standard API (No REST API)
1138
1139 /**
1140 * Checks the status of the AI environments.
1141 *
1142 * @return array The types of environments that are available.
1143 */
1144 public function checkStatus() {
1145 $env_types = [];
1146 $ai_envs = $this->core->get_option( 'ai_envs' );
1147 if ( empty( $ai_envs ) ) {
1148 throw new Exception( 'There are no AI environments yet.' );
1149 }
1150 foreach ( $ai_envs as $env ) {
1151 if ( !empty( $env['apikey'] ) ) {
1152 if ( !in_array( $env['type'], $env_types ) ) {
1153 $env_types[] = $env['type'];
1154 }
1155 }
1156 }
1157 if ( empty( $env_types ) ) {
1158 throw new Exception( 'There are no AI environments with an API key yet.' );
1159 }
1160 return $env_types;
1161 }
1162
1163 /**
1164 * Get function name by ID
1165 */
1166 private function get_function_name_by_id( $funcId ) {
1167 // Get function from registry using the static method
1168 $function = MeowPro_MWAI_FunctionAware::get_function( 'code-engine', $funcId );
1169 if ( $function && isset( $function->name ) ) {
1170 return $function->name;
1171 }
1172
1173 // If not found, try snippet-vault type as well
1174 $function = MeowPro_MWAI_FunctionAware::get_function( 'snippet-vault', $funcId );
1175 if ( $function && isset( $function->name ) ) {
1176 return $function->name;
1177 }
1178
1179 return null;
1180 }
1181 #endregion
1182 }
1183