PluginProbe
Elementor Website Builder – more than just a page builder / 3.14.0-beta4
Elementor Website Builder – more than just a page builder v3.14.0-beta4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / modules / ai / module.php

module.php in Elementor Website Builder – more than just a page builder 3.14.0-beta4, at modules/ai/module.php

504 lines 13.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor\Modules\Ai;
3
4 use Elementor\Core\Base\Module as BaseModule;
5 use Elementor\Core\Common\Modules\Connect\Module as ConnectModule;
6 use Elementor\Modules\Ai\Connect\Ai;
7 use Elementor\Plugin;
8 use Elementor\User;
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly.
12 }
13 class Module extends BaseModule {
14
15 public function get_name() {
16 return 'ai';
17 }
18
19 public function __construct() {
20 parent::__construct();
21
22 add_action( 'elementor/connect/apps/register', function ( ConnectModule $connect_module ) {
23 $connect_module->register_app( 'ai', Ai::get_class_name() );
24 } );
25
26 add_action( 'elementor/ajax/register_actions', function( $ajax ) {
27 $ajax->register_ajax_action( 'ai_get_user_information', [ $this, 'ajax_ai_get_user_information' ] );
28 $ajax->register_ajax_action( 'ai_get_completion_text', [ $this, 'ajax_ai_get_completion_text' ] );
29 $ajax->register_ajax_action( 'ai_get_edit_text', [ $this, 'ajax_ai_get_edit_text' ] );
30 $ajax->register_ajax_action( 'ai_get_custom_code', [ $this, 'ajax_ai_get_custom_code' ] );
31 $ajax->register_ajax_action( 'ai_get_custom_css', [ $this, 'ajax_ai_get_custom_css' ] );
32 $ajax->register_ajax_action( 'ai_set_get_started', [ $this, 'ajax_ai_set_get_started' ] );
33 $ajax->register_ajax_action( 'ai_set_status_feedback', [ $this, 'ajax_ai_set_status_feedback' ] );
34 $ajax->register_ajax_action( 'ai_get_image_prompt_enhancer', [ $this, 'ajax_ai_get_image_prompt_enhancer' ] );
35 $ajax->register_ajax_action( 'ai_get_text_to_image', [ $this, 'ajax_ai_get_text_to_image' ] );
36 $ajax->register_ajax_action( 'ai_get_image_to_image', [ $this, 'ajax_ai_get_image_to_image' ] );
37 $ajax->register_ajax_action( 'ai_get_image_to_image_mask', [ $this, 'ajax_ai_get_image_to_image_mask' ] );
38 $ajax->register_ajax_action( 'ai_get_image_to_image_outpainting', [ $this, 'ajax_ai_get_image_to_image_outpainting' ] );
39 $ajax->register_ajax_action( 'ai_get_image_to_image_upscale', [ $this, 'ajax_ai_get_image_to_image_upscale' ] );
40 $ajax->register_ajax_action( 'ai_upload_image', [ $this, 'ajax_ai_upload_image' ] );
41 } );
42
43 add_action( 'elementor/editor/before_enqueue_scripts', function() {
44 wp_enqueue_script(
45 'elementor-ai',
46 $this->get_js_assets_url( 'ai' ),
47 [
48 'elementor-common',
49 'elementor-editor-modules',
50 'elementor-editor-document',
51 'elementor-packages-ui',
52 'elementor-packages-icons',
53 ],
54 ELEMENTOR_VERSION,
55 true
56 );
57
58 wp_localize_script(
59 'elementor-ai',
60 'ElementorAiConfig',
61 [
62 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
63 ]
64 );
65 } );
66
67 add_action( 'elementor/editor/after_enqueue_styles', function() {
68 wp_enqueue_style(
69 'elementor-ai',
70 $this->get_css_assets_url( 'modules/ai/editor' ),
71 [],
72 ELEMENTOR_VERSION
73 );
74 } );
75 }
76
77 public function ajax_ai_get_user_information( $data ) {
78 $app = $this->get_ai_app();
79
80 if ( ! $app->is_connected() ) {
81 return [
82 'is_connected' => false,
83 'connect_url' => $app->get_admin_url( 'authorize', [
84 'utm_source' => 'ai-popup',
85 'utm_campaign' => 'connect-account',
86 'utm_medium' => 'wp-dash',
87 'source' => 'generic',
88 ] ),
89 ];
90 }
91
92 $user_usage = wp_parse_args( $app->get_usage(), [
93 'hasAiSubscription' => false,
94 'usedQuota' => 0,
95 'quota' => 100,
96 ] );
97
98 return [
99 'is_connected' => true,
100 'is_get_started' => User::get_introduction_meta( 'ai_get_started' ),
101 'usage' => $user_usage,
102 ];
103 }
104
105 private function verify_permissions( $editor_post_id ) {
106 $document = Plugin::$instance->documents->get( $editor_post_id );
107
108 if ( ! $document ) {
109 throw new \Exception( 'Document not found' );
110 }
111
112 if ( ! $document->is_built_with_elementor() || ! $document->is_editable_by_current_user() ) {
113 throw new \Exception( 'Access denied' );
114 }
115 }
116
117 public function ajax_ai_get_image_prompt_enhancer( $data ) {
118 $this->verify_permissions( $data['editor_post_id'] );
119
120 $app = $this->get_ai_app();
121
122 if ( empty( $data['prompt'] ) ) {
123 throw new \Exception( 'Missing prompt' );
124 }
125
126 if ( ! $app->is_connected() ) {
127 throw new \Exception( 'not_connected' );
128 }
129
130 $result = $app->get_image_prompt_enhanced( $data['prompt'] );
131 if ( is_wp_error( $result ) ) {
132 throw new \Exception( $result->get_error_message() );
133 }
134
135 return [
136 'text' => $result['text'],
137 'response_id' => $result['responseId'],
138 'usage' => $result['usage'],
139 ];
140 }
141
142 public function ajax_ai_get_completion_text( $data ) {
143 $this->verify_permissions( $data['editor_post_id'] );
144
145 $app = $this->get_ai_app();
146
147 if ( empty( $data['prompt'] ) ) {
148 throw new \Exception( 'Missing prompt' );
149 }
150
151 if ( ! $app->is_connected() ) {
152 throw new \Exception( 'not_connected' );
153 }
154
155 $result = $app->get_completion_text( $data['prompt'] );
156 if ( is_wp_error( $result ) ) {
157 throw new \Exception( $result->get_error_message() );
158 }
159
160 return [
161 'text' => $result['text'],
162 'response_id' => $result['responseId'],
163 'usage' => $result['usage'],
164 ];
165 }
166
167 private function get_ai_app() : Ai {
168 return Plugin::$instance->common->get_component( 'connect' )->get_app( 'ai' );
169 }
170
171 public function ajax_ai_get_edit_text( $data ) {
172 $this->verify_permissions( $data['editor_post_id'] );
173
174 $app = $this->get_ai_app();
175
176 if ( empty( $data['input'] ) ) {
177 throw new \Exception( 'Missing input' );
178 }
179
180 if ( empty( $data['instruction'] ) ) {
181 throw new \Exception( 'Missing instruction' );
182 }
183
184 if ( ! $app->is_connected() ) {
185 throw new \Exception( 'not_connected' );
186 }
187
188 $result = $app->get_edit_text( $data['input'], $data['instruction'] );
189 if ( is_wp_error( $result ) ) {
190 throw new \Exception( $result->get_error_message() );
191 }
192
193 return [
194 'text' => $result['text'],
195 'response_id' => $result['responseId'],
196 'usage' => $result['usage'],
197 ];
198 }
199
200 public function ajax_ai_get_custom_code( $data ) {
201 $app = $this->get_ai_app();
202
203 if ( empty( $data['prompt'] ) ) {
204 throw new \Exception( 'Missing prompt' );
205 }
206
207 if ( empty( $data['language'] ) ) {
208 throw new \Exception( 'Missing language' );
209 }
210
211 if ( ! $app->is_connected() ) {
212 throw new \Exception( 'not_connected' );
213 }
214
215 $result = $app->get_custom_code( $data['prompt'], $data['language'] );
216 if ( is_wp_error( $result ) ) {
217 throw new \Exception( $result->get_error_message() );
218 }
219
220 return [
221 'text' => $result['text'],
222 'response_id' => $result['responseId'],
223 'usage' => $result['usage'],
224 ];
225 }
226
227 public function ajax_ai_get_custom_css( $data ) {
228 $this->verify_permissions( $data['editor_post_id'] );
229
230 $app = $this->get_ai_app();
231
232 if ( empty( $data['prompt'] ) ) {
233 throw new \Exception( 'Missing prompt' );
234 }
235
236 if ( empty( $data['html_markup'] ) ) {
237 $data['html_markup'] = '';
238 }
239
240 if ( empty( $data['element_id'] ) ) {
241 throw new \Exception( 'Missing element_id' );
242 }
243
244 if ( ! $app->is_connected() ) {
245 throw new \Exception( 'not_connected' );
246 }
247
248 $result = $app->get_custom_css( $data['prompt'], $data['html_markup'], $data['element_id'] );
249 if ( is_wp_error( $result ) ) {
250 throw new \Exception( $result->get_error_message() );
251 }
252
253 return [
254 'text' => $result['text'],
255 'response_id' => $result['responseId'],
256 'usage' => $result['usage'],
257 ];
258 }
259
260 public function ajax_ai_set_get_started( $data ) {
261 $app = $this->get_ai_app();
262
263 User::set_introduction_viewed( [
264 'introductionKey' => 'ai_get_started',
265 ] );
266
267 return $app->set_get_started();
268 }
269
270 public function ajax_ai_set_status_feedback( $data ) {
271 if ( empty( $data['response_id'] ) ) {
272 throw new \Exception( 'Missing response_id' );
273 }
274
275 $app = $this->get_ai_app();
276
277 if ( ! $app->is_connected() ) {
278 throw new \Exception( 'not_connected' );
279 }
280
281 $app->set_status_feedback( $data['response_id'] );
282
283 return [];
284 }
285
286 public function ajax_ai_get_text_to_image( $data ) {
287 $this->verify_permissions( $data['editor_post_id'] );
288
289 $app = $this->get_ai_app();
290
291 if ( empty( $data['prompt'] ) ) {
292 throw new \Exception( 'Missing prompt' );
293 }
294
295 if ( ! $app->is_connected() ) {
296 throw new \Exception( 'not_connected' );
297 }
298
299 $result = $app->get_text_to_image( $data['prompt'], $data['promptSettings'] );
300
301 if ( is_wp_error( $result ) ) {
302 throw new \Exception( $result->get_error_message() );
303 }
304
305 return [
306 'images' => $result['images'],
307 'response_id' => $result['responseId'],
308 'usage' => $result['usage'],
309 ];
310 }
311
312 public function ajax_ai_get_image_to_image( $data ) {
313 $this->verify_permissions( $data['editor_post_id'] );
314
315 $app = $this->get_ai_app();
316
317 if ( empty( $data['prompt'] ) ) {
318 throw new \Exception( 'Missing prompt' );
319 }
320
321 if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
322 throw new \Exception( 'Missing Image' );
323 }
324
325 if ( empty( $data['promptSettings'] ) ) {
326 throw new \Exception( 'Missing prompt settings' );
327 }
328
329 if ( ! $app->is_connected() ) {
330 throw new \Exception( 'not_connected' );
331 }
332
333 $result = $app->get_image_to_image( [
334 'prompt' => $data['prompt'],
335 'promptSettings' => $data['promptSettings'],
336 'attachment_id' => $data['image']['id'],
337 ] );
338
339 if ( is_wp_error( $result ) ) {
340 throw new \Exception( $result->get_error_message() );
341 }
342
343 return [
344 'images' => $result['images'],
345 'response_id' => $result['responseId'],
346 'usage' => $result['usage'],
347 ];
348 }
349
350 public function ajax_ai_get_image_to_image_upscale( $data ) {
351 $this->verify_permissions( $data['editor_post_id'] );
352
353 $app = $this->get_ai_app();
354
355 if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
356 throw new \Exception( 'Missing Image' );
357 }
358
359 if ( empty( $data['promptSettings'] ) ) {
360 throw new \Exception( 'Missing prompt settings' );
361 }
362
363 if ( ! $app->is_connected() ) {
364 throw new \Exception( 'not_connected' );
365 }
366
367 $result = $app->get_image_to_image_upscale( [
368 'promptSettings' => $data['promptSettings'],
369 'attachment_id' => $data['image']['id'],
370 ] );
371
372 if ( is_wp_error( $result ) ) {
373 throw new \Exception( $result->get_error_message() );
374 }
375
376 return [
377 'images' => $result['images'],
378 'response_id' => $result['responseId'],
379 'usage' => $result['usage'],
380 ];
381 }
382
383 public function ajax_ai_get_image_to_image_mask( $data ) {
384 $this->verify_permissions( $data['editor_post_id'] );
385
386 $app = $this->get_ai_app();
387
388 if ( empty( $data['prompt'] ) ) {
389 throw new \Exception( 'Missing prompt' );
390 }
391
392 if ( empty( $data['image'] ) || empty( $data['image']['id'] ) ) {
393 throw new \Exception( 'Missing Image' );
394 }
395
396 if ( empty( $data['promptSettings'] ) ) {
397 throw new \Exception( 'Missing prompt settings' );
398 }
399
400 if ( ! $app->is_connected() ) {
401 throw new \Exception( 'not_connected' );
402 }
403
404 if ( empty( $data['mask'] ) ) {
405 throw new \Exception( 'Missing Mask' );
406 }
407
408 $result = $app->get_image_to_image_mask( [
409 'prompt' => $data['prompt'],
410 'promptSettings' => $data['promptSettings'],
411 'attachment_id' => $data['image']['id'],
412 'mask' => $data['mask'],
413 ] );
414
415 if ( is_wp_error( $result ) ) {
416 throw new \Exception( $result->get_error_message() );
417 }
418
419 return [
420 'images' => $result['images'],
421 'response_id' => $result['responseId'],
422 'usage' => $result['usage'],
423 ];
424 }
425 public function ajax_ai_get_image_to_image_outpainting( $data ) {
426 $this->verify_permissions( $data['editor_post_id'] );
427
428 $app = $this->get_ai_app();
429
430 if ( empty( $data['prompt'] ) ) {
431 throw new \Exception( 'Missing prompt' );
432 }
433
434 if ( ! $app->is_connected() ) {
435 throw new \Exception( 'not_connected' );
436 }
437
438 if ( empty( $data['mask'] ) ) {
439 throw new \Exception( 'Missing Expended Image' );
440 }
441
442 $result = $app->get_image_to_image_out_painting( [
443 'prompt' => $data['prompt'],
444 'mask' => $data['mask'],
445 ] );
446
447 if ( is_wp_error( $result ) ) {
448 throw new \Exception( $result->get_error_message() );
449 }
450
451 return [
452 'images' => $result['images'],
453 'response_id' => $result['responseId'],
454 'usage' => $result['usage'],
455 ];
456 }
457
458 public function ajax_ai_upload_image( $data ) {
459 if ( empty( $data['image'] ) ) {
460 throw new \Exception( 'Missing image data' );
461 }
462 $image = $data['image'];
463
464 if ( empty( $image['image_url'] ) ) {
465 throw new \Exception( 'Missing image_url' );
466 }
467
468 $image_data = $this->upload_image( $image['image_url'], $data['prompt'], $data['editor_post_id'] );
469
470 if ( is_wp_error( $image_data ) ) {
471 throw new \Exception( $image_data->get_error_message() );
472 }
473
474 /*if ( ! empty( $image['use_gallery_image'] ) && ! empty( $image['id'] ) ) {
475 // todo: uncomment once endpoint is ready send checkpoint
476 // $app = $this->get_ai_app();
477 // $app->set_used_gallery_image( $image['id'] );
478 }*/
479
480 return [
481 'image' => array_merge( $image_data, $data ),
482 ];
483 }
484
485 private function upload_image( $image_url, $image_title, $parent_post_id = 0 ) {
486 if ( ! current_user_can( 'upload_files' ) ) {
487 throw new \Exception( 'Not Allowed to Upload images' );
488 }
489
490 $attachment_id = media_sideload_image( $image_url, $parent_post_id, $image_title, 'id' );
491
492 if ( ! empty( $attachment_id['error'] ) ) {
493 return new \WP_Error( 'upload_error', $attachment_id['error'] );
494 }
495
496 return [
497 'id' => $attachment_id,
498 'url' => wp_get_attachment_image_url( $attachment_id, 'full' ),
499 'alt' => $image_title,
500 'source' => 'library',
501 ];
502 }
503 }
504