PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.9.3
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.9.3
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
1155 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 $this->core->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 $reply = $mwai_core->run_query( $query );
838 return $reply->result;
839 }
840
841 public function simpleImageQuery( $message, $params = [] ) {
842 global $mwai_core;
843 $query = new Meow_MWAI_Query_Image( $message );
844 $query->inject_params( $params );
845 $reply = $mwai_core->run_query( $query );
846 return $reply->result;
847 }
848
849 public function simpleImageEditQuery( $message, $mediaId, $params = [] ) {
850 global $mwai_core;
851 $query = new Meow_MWAI_Query_EditImage( $message );
852 $query->inject_params( $params );
853 $path = get_attached_file( $mediaId );
854 if ( empty( $path ) ) {
855 throw new Exception( 'The media cannot be found.' );
856 }
857 // TODO: Maybe 'vision' should be 'edit'.
858 $query->set_file( Meow_MWAI_Query_DroppedFile::from_path( $path, 'vision' ) );
859 $reply = $mwai_core->run_query( $query );
860 return $reply->result;
861 }
862
863 /**
864 * Generates an image relevant to the text.
865 */
866 public function imageQueryForMediaLibrary( $message, $params = [], $postId = null ) {
867 $query = new Meow_MWAI_Query_Image( $message );
868 $query->inject_params( $params );
869 $query->set_local_download( null );
870 $reply = $this->core->run_query( $query );
871 preg_match( '/\!\[Image\]\((.*?)\)/', $reply->result, $matches );
872 $url = $matches[1] ?? $reply->result;
873
874 // Check if the URL is already a WordPress attachment URL to avoid duplicates
875 $attachmentId = null;
876 $upload_dir = wp_upload_dir();
877 if ( strpos( $url, $upload_dir['baseurl'] ) === 0 ) {
878 // This is already a local WordPress upload, try to find the attachment ID
879 // First try by GUID
880 global $wpdb;
881 $attachmentId = $wpdb->get_var( $wpdb->prepare(
882 "SELECT ID FROM {$wpdb->posts} WHERE guid = %s AND post_type = 'attachment'",
883 $url
884 ) );
885
886 // If not found by GUID, try by attachment URL (more reliable)
887 if ( empty( $attachmentId ) ) {
888 $attachmentId = attachment_url_to_postid( $url );
889 }
890 }
891
892 // If not found or not a local URL, add it to the media library
893 if ( empty( $attachmentId ) ) {
894 $attachmentId = $this->core->add_image_from_url( $url, null, null, null, null, null, $postId );
895 if ( empty( $attachmentId ) ) {
896 throw new Exception( 'Could not add the image to the Media Library.' );
897 }
898 }
899
900 // TODO: We should create a nice title, caption, and alt.
901 $media = [
902 'id' => $attachmentId,
903 'url' => wp_get_attachment_url( $attachmentId ),
904 'title' => get_the_title( $attachmentId ),
905 'caption' => wp_get_attachment_caption( $attachmentId ),
906 'alt' => get_post_meta( $attachmentId, '_wp_attachment_image_alt', true )
907 ];
908 return $media;
909 }
910
911 /**
912 * Executes a query that will have to return a JSON result.
913 *
914 * @param string $message The prompt for the AI.
915 * @param array $params Additional parameters for the AI query.
916 *
917 * @return array The result of the AI query.
918 */
919 public function simpleJsonQuery( $message, $url = null, $path = null, $params = [] ) {
920 if ( !empty( $url ) || !empty( $path ) ) {
921 throw new Exception( 'The url and path are not supported yet by the simpleJsonQuery.' );
922 }
923 global $mwai_core;
924 $query = new Meow_MWAI_Query_Text( $message . "\nYour reply must be a formatted JSON." );
925 $query->inject_params( $params );
926 $query->set_response_format( 'json' );
927 $ai_json_default_env = $mwai_core->get_option( 'ai_json_default_env' );
928 $ai_json_default_model = $mwai_core->get_option( 'ai_json_default_model' );
929 if ( !empty( $ai_json_default_env ) ) {
930 $query->set_env_id( $ai_json_default_env );
931 }
932 if ( !empty( $ai_json_default_model ) ) {
933 $query->set_model( $ai_json_default_model );
934 }
935 else {
936 $query->set_model( MWAI_FALLBACK_MODEL_JSON );
937 }
938 $reply = $mwai_core->run_query( $query );
939 try {
940 $json = json_decode( $reply->result, true );
941 return $json;
942 }
943 catch ( Exception $e ) {
944 throw new Exception( 'The result is not a valid JSON.' );
945 }
946 }
947
948 /**
949 * Uploads a file to the system.
950 *
951 * @param array|null $file The file array from $_FILES.
952 * @param string|null $base64 Base64 encoded file data.
953 * @param string|null $filename The filename for base64 uploads.
954 * @param string $purpose The purpose of the file upload (e.g., 'files', 'vision', 'assistant').
955 * @param int $ttl Time to live in seconds. Default 3600 (1 hour).
956 * @param string|null $target Target location: 'uploads' or 'library'.
957 * @param array $metadata Additional metadata to store with the file.
958 *
959 * @return array Array with 'id' (refId) and 'url' of the uploaded file.
960 */
961 public function simpleFileUpload( $file = null, $base64 = null, $filename = null, $purpose = 'files', $ttl = 3600, $target = null, $metadata = [] ) {
962 global $mwai_core;
963
964 if ( !$this->core->files ) {
965 throw new Exception( 'Files module is not available.' );
966 }
967
968 // Determine target from settings if not provided
969 if ( empty( $target ) ) {
970 $target = $this->core->get_option( 'image_local_upload', 'uploads' );
971 }
972
973 try {
974 if ( !empty( $base64 ) ) {
975 // Handle base64 upload
976 if ( empty( $filename ) ) {
977 $filename = 'upload-' . time() . '.dat';
978 }
979
980 // For base64 uploads, we need to decode and create a temp file first
981 $binary = base64_decode( $base64 );
982 if ( !$binary ) {
983 throw new Exception( 'Invalid base64 data.' );
984 }
985
986 // Create a temporary file
987 $tmp_path = wp_tempnam( 'mwai-upload' );
988 file_put_contents( $tmp_path, $binary );
989
990 // Use the regular upload method
991 $refId = $this->core->files->upload_file(
992 $tmp_path,
993 $filename,
994 $purpose,
995 $metadata,
996 null, // envId
997 $target,
998 $ttl
999 );
1000
1001 // Clean up temp file if it was uploaded to library
1002 if ( $target === 'library' && file_exists( $tmp_path ) ) {
1003 @unlink( $tmp_path );
1004 }
1005
1006 $url = $this->core->files->get_url( $refId );
1007
1008 return [
1009 'id' => $refId,
1010 'url' => $url
1011 ];
1012 }
1013 else if ( !empty( $file ) && is_array( $file ) ) {
1014 // Handle regular file upload
1015 if ( !empty( $file['error'] ) ) {
1016 throw new Exception( 'File upload error: ' . $file['error'] );
1017 }
1018
1019 $refId = $this->core->files->upload_file(
1020 $file['tmp_name'],
1021 $file['name'],
1022 $purpose,
1023 $metadata,
1024 null, // envId
1025 $target,
1026 $ttl
1027 );
1028
1029 $url = $this->core->files->get_url( $refId );
1030
1031 return [
1032 'id' => $refId,
1033 'url' => $url
1034 ];
1035 }
1036 else {
1037 throw new Exception( 'Either a file or base64 data must be provided.' );
1038 }
1039 }
1040 catch ( Exception $e ) {
1041 throw new Exception( 'File upload failed: ' . $e->getMessage() );
1042 }
1043 }
1044
1045 /**
1046 * Executes an audio transcription query.
1047 *
1048 * @param string $url The URL of the audio file to transcribe.
1049 * @param string|null $path The path to the audio file. If provided, the audio data will be read from this file.
1050 * @param array $params Additional parameters for the transcription query.
1051 *
1052 * @return string The transcribed text.
1053 */
1054 public function simpleTranscribeAudio( $url = null, $path = null, $params = [] ) {
1055 global $mwai_core;
1056 $ai_audio_default_env = $this->core->get_option( 'ai_audio_default_env' );
1057 $ai_audio_default_model = $this->core->get_option( 'ai_audio_default_model' );
1058
1059 if ( empty( $ai_audio_default_model ) ) {
1060 $ai_audio_default_model = 'whisper-1'; // Default transcription model
1061 }
1062
1063 $query = new Meow_MWAI_Query_Transcribe();
1064
1065 if ( !empty( $ai_audio_default_env ) ) {
1066 $query->set_env_id( $ai_audio_default_env );
1067 }
1068 if ( !empty( $ai_audio_default_model ) ) {
1069 $query->set_model( $ai_audio_default_model );
1070 }
1071
1072 $query->inject_params( $params );
1073
1074 if ( !empty( $url ) ) {
1075 // Use 'files' as the purpose for audio files
1076 $query->set_file( Meow_MWAI_Query_DroppedFile::from_url( $url, 'files' ) );
1077 }
1078 else if ( !empty( $path ) ) {
1079 // Use 'files' as the purpose for audio files
1080 $query->set_file( Meow_MWAI_Query_DroppedFile::from_path( $path, 'files' ) );
1081 }
1082 else {
1083 throw new Exception( 'Either a URL or a path must be provided for the audio file.' );
1084 }
1085
1086 $reply = $mwai_core->run_query( $query );
1087 return $reply->result;
1088 }
1089 #endregion
1090
1091 #region Standard API
1092 /**
1093 * Checks if a text is safe or not.
1094 *
1095 * @param string $text The text to check.
1096 *
1097 * @return bool True if the text is safe, false otherwise.
1098 */
1099 public function moderationCheck( $text ) {
1100 global $mwai_core;
1101 $openai = Meow_MWAI_Engines_Factory::get_openai( $mwai_core );
1102 $res = $openai->moderate( $text );
1103 if ( !empty( $res ) && !empty( $res['results'] ) ) {
1104 return (bool) $res['results'][0]['flagged'];
1105 }
1106 }
1107 #endregion
1108
1109 #region Standard API (No REST API)
1110
1111 /**
1112 * Checks the status of the AI environments.
1113 *
1114 * @return array The types of environments that are available.
1115 */
1116 public function checkStatus() {
1117 $env_types = [];
1118 $ai_envs = $this->core->get_option( 'ai_envs' );
1119 if ( empty( $ai_envs ) ) {
1120 throw new Exception( 'There are no AI environments yet.' );
1121 }
1122 foreach ( $ai_envs as $env ) {
1123 if ( !empty( $env['apikey'] ) ) {
1124 if ( !in_array( $env['type'], $env_types ) ) {
1125 $env_types[] = $env['type'];
1126 }
1127 }
1128 }
1129 if ( empty( $env_types ) ) {
1130 throw new Exception( 'There are no AI environments with an API key yet.' );
1131 }
1132 return $env_types;
1133 }
1134
1135 /**
1136 * Get function name by ID
1137 */
1138 private function get_function_name_by_id( $funcId ) {
1139 // Get function from registry using the static method
1140 $function = MeowPro_MWAI_FunctionAware::get_function( 'code-engine', $funcId );
1141 if ( $function && isset( $function->name ) ) {
1142 return $function->name;
1143 }
1144
1145 // If not found, try snippet-vault type as well
1146 $function = MeowPro_MWAI_FunctionAware::get_function( 'snippet-vault', $funcId );
1147 if ( $function && isset( $function->name ) ) {
1148 return $function->name;
1149 }
1150
1151 return null;
1152 }
1153 #endregion
1154 }
1155