PluginProbe
Elementor Website Builder – more than just a page builder / 3.16.2
Elementor Website Builder – more than just a page builder v3.16.2
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 / connect / ai.php

ai.php in Elementor Website Builder – more than just a page builder 3.16.2, at modules/ai/connect/ai.php

481 lines 11.7 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\Connect;
3
4 use Elementor\Core\Common\Modules\Connect\Apps\Library;
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly
8 }
9
10 class Ai extends Library {
11 const API_URL = 'https://my.elementor.com/api/v2/ai/';
12
13 const STYLE_PRESET = 'style_preset';
14 const IMAGE_TYPE = 'image_type';
15 const IMAGE_STRENGTH = 'image_strength';
16 const ASPECT_RATIO = 'ratio';
17 const IMAGE_RESOLUTION = 'image_resolution';
18
19 const PROMPT = 'prompt';
20
21 public function get_title() {
22 return esc_html__( 'AI', 'elementor' );
23 }
24
25 protected function get_api_url() {
26 return static::API_URL . '/';
27 }
28
29 public function get_usage() {
30 return $this->ai_request(
31 'POST',
32 'status/check',
33 [
34 'api_version' => ELEMENTOR_VERSION,
35 'site_lang' => get_bloginfo( 'language' ),
36 ]
37 );
38 }
39
40 /**
41 * get_file_payload
42 * @param $filename
43 * @param $file_type
44 * @param $file_path
45 * @param $boundary
46 *
47 * @return string
48 */
49 private function get_file_payload( $filename, $file_type, $file_path, $boundary ) {
50 $name = $filename ?? basename( $file_path );
51 $mine_type = 'image' === $file_type ? image_type_to_mime_type( exif_imagetype( $file_path ) ) : $file_type;
52 $payload = '';
53 // Upload the file
54 $payload .= '--' . $boundary;
55 $payload .= "\r\n";
56 $payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"; filename="' . esc_attr( $name ) . '"' . "\r\n";
57 $payload .= 'Content-Type: ' . $mine_type . "\r\n";
58 $payload .= "\r\n";
59 $payload .= file_get_contents( $file_path );
60 $payload .= "\r\n";
61
62 return $payload;
63 }
64
65 private function get_upload_request_body( $body, $file, $boundary, $file_name = '' ) {
66 $payload = '';
67 // add all body fields as standard POST fields:
68 foreach ( $body as $name => $value ) {
69 $payload .= '--' . $boundary;
70 $payload .= "\r\n";
71 $payload .= 'Content-Disposition: form-data; name="' . esc_attr( $name ) . '"' . "\r\n\r\n";
72 $payload .= $value;
73 $payload .= "\r\n";
74 }
75
76 if ( is_array( $file ) ) {
77 foreach ( $file as $key => $file_data ) {
78 $payload .= $this->get_file_payload( $file_data['name'], $file_data['type'], $file_data['path'], $boundary );
79 }
80 } else {
81 $image_mime = image_type_to_mime_type( exif_imagetype( $file ) );
82 // @todo: add validation for supported image types
83
84 if ( empty( $file_name ) ) {
85 $file_name = basename( $file );
86 }
87 $payload .= $this->get_file_payload( $file_name, $image_mime, $file, $boundary );
88 }
89
90 $payload .= '--' . $boundary . '--';
91
92 return $payload;
93 }
94
95 private function ai_request( $method, $endpoint, $body, $file = false, $file_name = '' ) {
96 $headers = [
97 'x-elementor-ai-version' => '2',
98 ];
99
100 if ( $file ) {
101 $boundary = wp_generate_password( 24, false );
102 $body = $this->get_upload_request_body( $body, $file, $boundary, $file_name );
103 // add content type header
104 $headers['Content-Type'] = 'multipart/form-data; boundary=' . $boundary;
105 }
106
107 return $this->http_request(
108 $method,
109 $endpoint,
110 [
111 'timeout' => 50,
112 'headers' => $headers,
113 'body' => $body,
114 ],
115 [
116 'return_type' => static::HTTP_RETURN_TYPE_ARRAY,
117 ]
118 );
119 }
120
121 public function set_get_started() {
122 return $this->ai_request(
123 'POST',
124 'status/get-started',
125 [
126 'api_version' => ELEMENTOR_VERSION,
127 'site_lang' => get_bloginfo( 'language' ),
128 ]
129 );
130 }
131
132 public function set_status_feedback( $response_id ) {
133 return $this->ai_request(
134 'POST',
135 'status/feedback/' . $response_id,
136 [
137 'api_version' => ELEMENTOR_VERSION,
138 'site_lang' => get_bloginfo( 'language' ),
139 ]
140 );
141 }
142
143 public function set_used_gallery_image( $image_id ) {
144 return $this->ai_request(
145 'POST',
146 'status/used-gallery-image/' . $image_id,
147 [
148 'api_version' => ELEMENTOR_VERSION,
149 'site_lang' => get_bloginfo( 'language' ),
150 ]
151 );
152 }
153
154 public function get_completion_text( $prompt, $context = [] ) {
155 return $this->ai_request(
156 'POST',
157 'text/completion',
158 [
159 'prompt' => $prompt,
160 'context' => wp_json_encode( $context ),
161 'api_version' => ELEMENTOR_VERSION,
162 'site_lang' => get_bloginfo( 'language' ),
163 ]
164 );
165 }
166
167 /**
168 * get_image_prompt_enhanced
169 * @param $prompt
170 *
171 * @return mixed|\WP_Error
172 */
173 public function get_image_prompt_enhanced( $prompt, $context = [] ) {
174 return $this->ai_request(
175 'POST',
176 'text/enhance-image-prompt',
177 [
178 'prompt' => $prompt,
179 'context' => wp_json_encode( $context ),
180 'api_version' => ELEMENTOR_VERSION,
181 'site_lang' => get_bloginfo( 'language' ),
182 ]
183 );
184 }
185
186 public function get_edit_text( $input, $instruction, $context = [] ) {
187 return $this->ai_request(
188 'POST',
189 'text/edit',
190 [
191 'input' => $input,
192 'instruction' => $instruction,
193 'context' => wp_json_encode( $context ),
194 'api_version' => ELEMENTOR_VERSION,
195 'site_lang' => get_bloginfo( 'language' ),
196 ]
197 );
198 }
199
200 public function get_custom_code( $prompt, $language, $context = [] ) {
201 return $this->ai_request(
202 'POST',
203 'text/custom-code',
204 [
205 'prompt' => $prompt,
206 'language' => $language,
207 'context' => wp_json_encode( $context ),
208 'api_version' => ELEMENTOR_VERSION,
209 'site_lang' => get_bloginfo( 'language' ),
210 ]
211 );
212 }
213
214 public function get_custom_css( $prompt, $html_markup, $element_id, $context = [] ) {
215 return $this->ai_request(
216 'POST',
217 'text/custom-css',
218 [
219 'prompt' => $prompt,
220 'html_markup' => $html_markup,
221 'element_id' => $element_id,
222 'context' => wp_json_encode( $context ),
223 'api_version' => ELEMENTOR_VERSION,
224 'site_lang' => get_bloginfo( 'language' ),
225 ]
226 );
227 }
228
229 /**
230 * get_text_to_image
231 * @param $prompt
232 * @param $prompt_settings
233 *
234 * @return mixed|\WP_Error
235 */
236 public function get_text_to_image( $prompt, $prompt_settings, $context = [] ) {
237 return $this->ai_request(
238 'POST',
239 'image/text-to-image',
240 [
241 self::PROMPT => $prompt,
242 self::IMAGE_TYPE => $prompt_settings[ self::IMAGE_TYPE ] . '/' . $prompt_settings[ self::STYLE_PRESET ],
243 self::ASPECT_RATIO => $prompt_settings[ self::ASPECT_RATIO ],
244 'context' => wp_json_encode( $context ),
245 'api_version' => ELEMENTOR_VERSION,
246 'site_lang' => get_bloginfo( 'language' ),
247 ]
248 );
249 }
250
251 /**
252 * get_image_to_image
253 * @param $image_data
254 *
255 * @return mixed|\WP_Error
256 * @throws \Exception
257 */
258 public function get_image_to_image( $image_data, $context = [] ) {
259 $image_file = get_attached_file( $image_data['attachment_id'] );
260
261 if ( ! $image_file ) {
262 throw new \Exception( 'Image file not found' );
263 }
264
265 $result = $this->ai_request(
266 'POST',
267 'image/image-to-image',
268 [
269 self::PROMPT => $image_data[ self::PROMPT ],
270 self::IMAGE_TYPE => $image_data['promptSettings'][ self::IMAGE_TYPE ] . '/' . $image_data['promptSettings'][ self::STYLE_PRESET ],
271 self::IMAGE_STRENGTH => $image_data['promptSettings'][ self::IMAGE_STRENGTH ],
272 self::ASPECT_RATIO => $image_data['promptSettings'][ self::ASPECT_RATIO ],
273 'context' => wp_json_encode( $context ),
274 'api_version' => ELEMENTOR_VERSION,
275 'site_lang' => get_bloginfo( 'language' ),
276 ],
277 $image_file,
278 'image'
279 );
280
281 return $result;
282 }
283
284 /**
285 * get_image_to_image_upscale
286 * @param $image_data
287 *
288 * @return mixed|\WP_Error
289 * @throws \Exception
290 */
291 public function get_image_to_image_upscale( $image_data, $context = [] ) {
292 $image_file = get_attached_file( $image_data['attachment_id'] );
293
294 if ( ! $image_file ) {
295 throw new \Exception( 'Image file not found' );
296 }
297
298 $result = $this->ai_request(
299 'POST',
300 'image/image-to-image/upscale',
301 [
302 self::IMAGE_RESOLUTION => $image_data['promptSettings']['upscale_to'],
303 'context' => wp_json_encode( $context ),
304 'api_version' => ELEMENTOR_VERSION,
305 'site_lang' => get_bloginfo( 'language' ),
306 ],
307 $image_file,
308 'image'
309 );
310
311 return $result;
312 }
313
314 /**
315 * get_image_to_image_remove_background
316 * @param $image_data
317 *
318 * @return mixed|\WP_Error
319 * @throws \Exception
320 */
321 public function get_image_to_image_remove_background( $image_data, $context = [] ) {
322 $image_file = get_attached_file( $image_data['attachment_id'] );
323
324 if ( ! $image_file ) {
325 throw new \Exception( 'Image file not found' );
326 }
327
328 $result = $this->ai_request(
329 'POST',
330 'image/image-to-image/remove-background',
331 [
332 'context' => wp_json_encode( $context ),
333 'api_version' => ELEMENTOR_VERSION,
334 'site_lang' => get_bloginfo( 'language' ),
335 ],
336 $image_file,
337 'image'
338 );
339
340 return $result;
341 }
342
343 /**
344 * get_image_to_image_remove_text
345 * @param $image_data
346 *
347 * @return mixed|\WP_Error
348 * @throws \Exception
349 */
350 public function get_image_to_image_replace_background( $image_data, $context = [] ) {
351 $image_file = get_attached_file( $image_data['attachment_id'] );
352
353 if ( ! $image_file ) {
354 throw new \Exception( 'Image file not found' );
355 }
356
357 $result = $this->ai_request(
358 'POST',
359 'image/image-to-image/replace-background',
360 [
361 self::PROMPT => $image_data[ self::PROMPT ],
362 'context' => wp_json_encode( $context ),
363 'api_version' => ELEMENTOR_VERSION,
364 'site_lang' => get_bloginfo( 'language' ),
365 ],
366 $image_file,
367 'image'
368 );
369
370 return $result;
371 }
372
373 /**
374 * store_temp_file
375 * used to store a temp file for the AI request and deletes it once the request is done
376 * @param $file_content
377 * @param $file_ext
378 *
379 * @return string
380 */
381 private function store_temp_file( $file_content, $file_ext = '' ) {
382 $temp_file = str_replace( '.tmp', '', wp_tempnam() . $file_ext );
383 file_put_contents( $temp_file, $file_content );
384 // make sure the temp file is deleted on shutdown
385 register_shutdown_function( function () use ( $temp_file ) {
386 if ( file_exists( $temp_file ) ) {
387 unlink( $temp_file );
388 }
389 } );
390 return $temp_file;
391 }
392
393 /**
394 * get_image_to_image_out_painting
395 * @param $image_data
396 *
397 * @return mixed|\WP_Error
398 * @throws \Exception
399 */
400 public function get_image_to_image_out_painting( $image_data, $context = [] ) {
401 $img_content = str_replace( ' ', '+', $image_data['mask'] );
402 $img_content = substr( $img_content, strpos( $img_content, ',' ) + 1 );
403 $img_content = base64_decode( $img_content );
404 $mask_file = $this->store_temp_file( $img_content, '.png' );
405
406 if ( ! $mask_file ) {
407 throw new \Exception( 'Expended Image file not found' );
408 }
409
410 $result = $this->ai_request(
411 'POST',
412 'image/image-to-image/outpainting',
413 [
414 self::PROMPT => $image_data[ self::PROMPT ],
415 self::IMAGE_TYPE => '',
416 'context' => wp_json_encode( $context ),
417 'api_version' => ELEMENTOR_VERSION,
418 'site_lang' => get_bloginfo( 'language' ),
419 ],
420 [
421 [
422 'name' => 'image',
423 'type' => 'image',
424 'path' => $mask_file,
425 ],
426 ]
427 );
428
429 return $result;
430 }
431
432 /**
433 * get_image_to_image_mask
434 * @param $image_data
435 *
436 * @return mixed|\WP_Error
437 * @throws \Exception
438 */
439 public function get_image_to_image_mask( $image_data, $context = [] ) {
440 $image_file = get_attached_file( $image_data['attachment_id'] );
441 $mask_file = $this->store_temp_file( $image_data['mask'], '.svg' );
442
443 if ( ! $image_file ) {
444 throw new \Exception( 'Image file not found' );
445 }
446
447 if ( ! $mask_file ) {
448 throw new \Exception( 'Mask file not found' );
449 }
450
451 $result = $this->ai_request(
452 'POST',
453 'image/image-to-image/inpainting',
454 [
455 self::PROMPT => $image_data[ self::PROMPT ],
456 self::IMAGE_TYPE => $image_data['promptSettings'][ self::IMAGE_TYPE ] . '/' . $image_data['promptSettings'][ self::STYLE_PRESET ],
457 self::IMAGE_STRENGTH => $image_data['promptSettings'][ self::IMAGE_STRENGTH ],
458 'context' => wp_json_encode( $context ),
459 'api_version' => ELEMENTOR_VERSION,
460 'site_lang' => get_bloginfo( 'language' ),
461 ],
462 [
463 [
464 'name' => 'image',
465 'type' => 'image',
466 'path' => $image_file,
467 ],
468 [
469 'name' => 'mask_image',
470 'type' => 'image/svg+xml',
471 'path' => $mask_file,
472 ],
473 ]
474 );
475
476 return $result;
477 }
478
479 protected function init() {}
480 }
481