PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / 2.4.3
Kubio AI Page Builder v2.4.3
2.8.4 2.8.3 2.8.2 2.8.1 trunk 1.0.0 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.7.0 1.7.1 1.7.2 1.7.3 1.8.0 1.8.1 1.8.2 1.9.0 2.0.0 2.1.1 2.1.2 2.1.3 2.2.0 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.3 2.3.4 2.4.0 2.4.1 2.4.2 2.4.3 2.4.5 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.6.1 2.6.2 2.6.3 2.6.5 2.6.6 2.6.7 2.7.0 2.7.1 2.7.2 2.7.3 2.8.0
kubio / lib / AI / utils.php
kubio / lib / AI Last commit date
SDApi 2 years ago admin-tab 1 year ago filters 1 year ago api.php 1 year ago index.php 2 years ago utils.php 1 year ago
utils.php
511 lines
1 <?php
2
3 use IlluminateAgnostic\Arr\Support\Arr;
4 use Kubio\Core\LodashBasic;
5 use Kubio\Core\Utils;
6 use Kubio\FileLog;
7 use Kubio\Flags;
8
9 function kubio_ai_content_languages() {
10 return array(
11 'ar_AR' => 'العربية (Arabic)',
12 'az_AZ' => 'Azərbaycan dili (Azerbaijani)',
13 'bn_BD' => 'বাংলা (Bengali)',
14 'cs_CZ' => 'Čeština (Czech)',
15 'cy_GB' => 'Cymraeg (Welsh)',
16 'da_DK' => 'Dansk (Danish)',
17 'de_DE' => 'Deutsch (German)',
18 'el_GR' => 'Ελληνικά (Greek)',
19 'en_US' => 'English US',
20 'en_GB' => 'English GB (United Kingdom English)',
21 'en_AU' => 'English AU (Australian English)',
22 'en_CA' => 'English CA (Canadian English)',
23 'es_ES' => 'Español (Spanish)',
24 'es_MX' => 'Español MX (Mexican Spanish)',
25 'et_EE' => 'Eesti keel (Estonian)',
26 'fa_IR' => 'فارسی (Persian)',
27 'fi_FI' => 'Suomi (Finnish)',
28 'fr_FR' => 'Français (French)',
29 'fr_CA' => 'Français CA (Canadian French)',
30 'ga_IE' => 'Gaeilge (Irish)',
31 'he_IL' => 'עברית (Hebrew)',
32 'hi_IN' => 'हिन्दी (Hindi)',
33 'hr_HR' => 'Hrvatski (Croatian)',
34 'hu_HU' => 'Magyar (Hungarian)',
35 'hy_AM' => 'Հայերեն (Armenian)',
36 'id_ID' => 'Bahasa Indonesia (Indonesian)',
37 'is_IS' => 'Íslenska (Icelandic)',
38 'it_IT' => 'Italiano (Italian)',
39 'ja_JP' => '日本語 (Japanese)',
40 'ka_GE' => 'ქართული (Georgian)',
41 'kk_KZ' => 'Қазақ тілі (Kazakh)',
42 'ko_KR' => '한국어 (Korean)',
43 'lt_LT' => 'Lietuvių kalba (Lithuanian)',
44 'lv_LV' => 'Latviešu valoda (Latvian)',
45 'ms_MY' => 'Bahasa Melayu (Malay)',
46 'nb_NO' => 'Norsk bokmål (Norwegian Bokmål)',
47 'nl_NL' => 'Nederlands (Dutch)',
48 'pl_PL' => 'Polski (Polish)',
49 'pt_PT' => 'Português (Portuguese)',
50 'pt_BR' => 'Português BR (Portuguese Brasil)',
51 'ro_RO' => 'Română (Romanian)',
52 'ru_RU' => 'Русский (Russian)',
53 'sk_SK' => 'Slovenčina (Slovak)',
54 'sl_SI' => 'Slovenščina (Slovenian)',
55 'sq_AL' => 'Shqip (Albanian)',
56 'sr_RS' => 'Српски (Serbian)',
57 'sv_SE' => 'Svenska (Swedish)',
58 'ta_IN' => 'தமிழ் (Tamil)',
59 'th_TH' => 'ไทย (Thai)',
60 'tr_TR' => 'Türkçe (Turkish)',
61 'uk_UA' => 'Українська (Ukrainian)',
62 'ur_PK' => 'اردو (Urdu)',
63 'vi_VN' => 'Tiếng Việt (Vietnamese)',
64 'zh_CN' => '中文 (Chinese Simplified)',
65 'zh_TW' => '中文 (Chinese Traditional)',
66 );
67 }
68
69
70 function kubio_ai_content_language_styles() {
71 return array(
72 'natural' => array(
73 'label' => __( 'Natural', 'kubio' ),
74 'description' => __( 'Is the default language style. It can adapt to some extent depending on the cues from the user\'s input.', 'kubio' ),
75 ),
76 'formal' => array(
77 'label' => __( 'Formal', 'kubio' ),
78 'description' => __( 'Used in official documents, academic papers, and professional communication, characterized by complex sentence structures, precise vocabulary, and avoidance of contractions and slang.', 'kubio' ),
79 ),
80 'informal' => array(
81 'label' => __( 'Informal', 'kubio' ),
82 'description' => __( 'Casual and relaxed style used in everyday conversations, personal emails, and informal writing. It often includes contractions, colloquialisms, and a more relaxed sentence structure.', 'kubio' ),
83 ),
84 'technical' => array(
85 'label' => __( 'Technical', 'kubio' ),
86 'description' => __( 'Specific to a particular field or industry, this style uses terminology and jargon understood by experts in that field. It aims for clear and precise communication within that domain.', 'kubio' ),
87 ),
88
89 'persuasive' => array(
90 'label' => __( 'Persuasive', 'kubio' ),
91 'description' => __( "Used to convince or influence the reader's opinion, often employing rhetoric, emotional appeals, and strong arguments to present a particular viewpoint.", 'kubio' ),
92 ),
93 'humorous' => array(
94 'label' => __( 'Humorous', 'kubio' ),
95 'description' => __( 'Intended to amuse the reader, this style uses wit, sarcasm, irony, and clever wordplay to evoke laughter or amusement.', 'kubio' ),
96 ),
97
98 );
99 }
100
101 function kubio_ai_business_types() {
102 return array(
103 array(
104 'label' => __( 'Business', 'kubio' ),
105 'value' => 'Business',
106 'description' => __( 'Resources and insights for starting, managing, and growing businesses.', 'kubio' ),
107 ),
108 array(
109 'label' => __( 'Services', 'kubio' ),
110 'value' => 'Services',
111 'description' => __( 'Promoting and detailing services offered by professionals or businesses.', 'kubio' ),
112 ),
113 array(
114 'label' => __( 'Consulting', 'kubio' ),
115 'value' => 'Consulting',
116 'description' => __( 'Offering expert advice, insights, and solutions in specialized fields.', 'kubio' ),
117 ),
118
119 array(
120 'label' => __( 'Art / Design Portfolio', 'kubio' ),
121 'value' => 'Art / Design Portfolio',
122 'description' => __( 'Showcasing artistic and design work, including portfolios, projects, and creative endeavors.', 'kubio' ),
123 ),
124
125 array(
126 'label' => __( 'Community & Non-profit', 'kubio' ),
127 'value' => 'Community & Non-profit',
128 'description' => __( 'Highlighting community initiatives, nonprofit organizations, and philanthropic efforts for social good.', 'kubio' ),
129 ),
130 array(
131 'label' => __( 'Personal', 'kubio' ),
132 'value' => 'Personal',
133 'description' => __( 'A platform for sharing personal experiences, thoughts, and interests.', 'kubio' ),
134 ),
135 array(
136 'label' => __( 'Event', 'kubio' ),
137 'value' => 'Event',
138 'description' => __( 'Information and details about upcoming events, conferences, or gatherings.', 'kubio' ),
139 ),
140
141 array(
142 'label' => __( 'Educational', 'kubio' ),
143 'value' => 'Educational',
144 'description' => __( 'Online presence for educational institutions, showcasing courses, programs, and achievements.', 'kubio' ),
145 ),
146
147 array(
148 'label' => __( 'Food & Drink', 'kubio' ),
149 'value' => 'Food & Drink',
150 'description' => __( 'Exploring culinary delights, recipes, and beverage-related content.', 'kubio' ),
151 ),
152
153 array(
154 'label' => __( 'Health & Fitness', 'kubio' ),
155 'value' => 'Health & Fitness',
156 'description' => __( 'Promoting a healthy lifestyle, fitness routines, and well-being tips.', 'kubio' ),
157 ),
158
159 array(
160 'label' => __( 'Fashion & Beauty', 'kubio' ),
161 'value' => 'Fashion & Beauty',
162 'description' => __( 'Showcasing the latest fashion trends, beauty tips, and style advice.', 'kubio' ),
163 ),
164
165 array(
166 'label' => __( 'Technology & Gadgets', 'kubio' ),
167 'value' => 'Technology & Gadgets',
168 'description' => __( 'Exploring the world of tech, gadgets, and digital innovations.', 'kubio' ),
169 ),
170
171 array(
172 'label' => __( 'Gaming', 'kubio' ),
173 'value' => 'Gaming',
174 'description' => __( 'Exploring the world of gaming, video games, and esports.', 'kubio' ),
175 ),
176
177 );
178 }
179
180 function kubio_ai_log( $type, $code, $prompts, $completion, $usage = array(), $call_id = null ) {
181
182 if ( defined( 'KUBIO_AI_LOG' ) && KUBIO_AI_LOG ) {
183 kubio_replace_base64_strings( $completion );
184
185 return FileLog::with_type( FileLog::JSONL_LOG )->$type(
186 'AI',
187 array(
188 'call_id' => $call_id,
189 'code' => $code,
190 'prompts' => $prompts,
191 'completion' => $completion,
192 'start_time' => Arr::get( $usage, 'start_time', 0 ),
193 'usage' => array_merge(
194 array(
195 'prompt_tokens' => 0,
196 'completion_tokens' => 0,
197 'total_tokens' => 0,
198 ),
199 $usage
200 ),
201 )
202 );
203 }
204 }
205
206 function kubio_replace_base64_strings( &$array, $max_length = 500, $replace_with = '[blob]' ) {
207 if ( ! is_array(
208 $array
209 ) ) {
210 return false;
211 }
212
213 foreach ( $array as $key => &$value ) {
214 if ( is_array( $value ) ) {
215 kubio_replace_base64_strings(
216 $value,
217 $max_length,
218 $replace_with
219 );
220 } elseif ( is_string( $value ) && strlen( $value ) > $max_length && kubio_is_base64( $value ) ) {
221 $array[ $key ] = $replace_with;
222 }
223 }
224 }
225
226 function kubio_is_base64( $string ) {
227 return base64_decode( $string, true ) !== false;
228 }
229
230 function kubio_ai_sd_xl_determine_appropriate_size( $width, $height ) {
231
232 $ar_range = 0.2;
233 $aspect_ratio = $width / $height;
234
235 $sizes = array(
236 640 => 1536,
237 768 => 1344,
238 832 => 1216,
239 896 => 1152,
240 1024 => 1024,
241 1152 => 896,
242 1216 => 832,
243 );
244
245 $heights_in_range = array();
246 foreach ( $sizes as $possible_height => $possible_width ) {
247 $possible_ar = $possible_width / $possible_height;
248 $ar_is_in_range = $aspect_ratio * ( 1 - $ar_range ) <= $possible_ar && $possible_ar <= $aspect_ratio * ( 1 + $ar_range );
249
250 if ( $ar_is_in_range ) {
251 $heights_in_range[] = $possible_height;
252 }
253 }
254
255 $final_height = empty( $heights_in_range ) ? 1024 : array_shift( $heights_in_range );
256
257 foreach ( $heights_in_range as $possible_height ) {
258 if ( $possible_height > $height ) {
259 break;
260 }
261
262 $final_height = $height;
263 }
264
265 return array( $sizes[ $final_height ], $final_height );
266 }
267
268 function kubio_ai_get_original_image_dimensions( $imag_url ) {
269
270 if ( ! function_exists( 'download_url' ) ) {
271 require_once ABSPATH . '/wp-admin/includes/file.php';
272 }
273
274 $temp_file = download_url( $imag_url );
275 $image_threshold = 0.2;
276
277 if ( is_wp_error( $temp_file ) ) {
278 return array(
279 'width' => 1920,
280 'height' => 1080,
281 'orientation' => 'landscape',
282 );
283 }
284
285 $image_size = getimagesize( $temp_file );
286
287 if ( $image_size === false ) {
288
289 return array(
290 'width' => 1920,
291 'height' => 1080,
292 'orientation' => 'landscape',
293 );
294 }
295
296 list($width, $height) = $image_size;
297
298 unlink( $temp_file );
299
300 $ratio = floor( $width / $height * 100 ) / 100;
301 $orientation = $ratio < 1 ? 'portrait' : 'landscape';
302
303 if ( ( 1 - $image_threshold ) < $ratio && $ratio < ( 1 + $image_threshold ) ) {
304 $orientation = 'square';
305 }
306
307 return array(
308 'width' => $width,
309 'height' => $height,
310 'orientation' => $orientation,
311 );
312
313 }
314
315 /**
316 *
317 * @param string $path
318 * @param array $payload
319 * @param array $extra
320 * @return mixed|null|WP_Error
321 */
322 function kubio_ai_call_api( $path, $payload = array(), $extra = array() ) {
323
324 $is_guest = isset( $_GET['is_guest'] ) && ! ! $_GET['is_guest'];
325 $skip_ai_cache = isset( $_GET['skip_ai_cache'] ) && ! ! $_GET['skip_ai_cache'];
326 $timeout = 120;
327 ini_set( 'max_execution_time', $timeout );
328 set_time_limit( $timeout );
329
330 $log = defined( 'KUBIO_AI_LOG' ) ? KUBIO_AI_LOG : false;
331 if ( ! $is_guest ) {
332 $base_url = Utils::getCloudURL( "/api/ai/$path" );
333 } else {
334 $base_url = Utils::getCloudURL( "/api/ai-guest/$path" );
335 }
336
337 $url = add_query_arg(
338 array(
339 'ai_debug' => $log ? 1 : 0,
340 ),
341 $base_url
342 );
343
344 $start_time = microtime( true );
345 $filter = "kubio_ai_response_{$path}";
346 // add a filter
347 if ( has_filter( $filter ) ) {
348 $response = apply_filters( $filter, $payload );
349
350 return $response;
351 }
352 $extra_headers = array();
353 if ( $skip_ai_cache ) {
354 $extra_headers['X-Kubio-AI-Skip-Cache'] = '1';
355 }
356 $response = wp_remote_post(
357 $url,
358 array(
359 'timeout' => $timeout - 1,
360 'sslverify' => false,
361 'headers' => array_merge(
362 array(
363 'Content-Type' => 'application/json',
364 'Accept' => 'application/json',
365 'X-Kubio-AI-Key' => kubio_ai_get_key(),
366 'X-Kubio-Site-UUID' => Flags::getSiteUUID(),
367 'X-Kubio-Site-URL' => get_bloginfo( 'url' ),
368 ),
369 $extra_headers
370 ),
371 'body' => json_encode(
372 array_merge(
373 array(
374 'params' => $payload,
375 ),
376 $extra
377 )
378 ),
379 )
380 );
381
382 if ( is_wp_error( $response ) ) {
383 return $response;
384 }
385
386 $code = wp_remote_retrieve_response_code( $response );
387
388 $result = null;
389 $debug_content = array();
390 $response_content = null;
391
392 if ( $code !== 200 ) {
393 $response_content = wp_remote_retrieve_body( $response );
394 $body = json_decode( $response_content, true );
395 $error = Arr::get( (array) $body, 'error', null );
396 if ( $error ) {
397 $result = new \WP_Error(
398 Arr::get( $error, 'code', '' ),
399 Arr::get( $error, 'message', '' ),
400 $response_content
401 );
402 } else {
403 $result = new \WP_Error(
404 $code,
405 // translators: %s is the error message
406 sprintf( __( 'AI Server error: %s', 'kubio' ), Arr::get( $error, 'message', '' ) ),
407 $response_content
408 );
409 }
410 } else {
411 $response_content = wp_remote_retrieve_body( $response );
412 $body = json_decode( $response_content, true );
413
414 $result = array(
415 'content' => Arr::get( is_array( $body ) ? $body : array(), 'content', null ),
416 'service_info' => (object) Arr::get( $body, 'service_info', array() ),
417 );
418
419 if ( ! is_array( $body ) ) {
420 $result = new WP_Error(
421 'ai_response_not_json',
422 __( 'AI response is invalid', 'kubio' ),
423 $response_content
424 );
425 } else {
426
427 $error = $body['error'];
428 $debug_content = Arr::get( $body, 'debug', array() );
429
430 if ( $error ) {
431 $result = new WP_Error(
432 $error['code'],
433 $error['message'],
434 array_merge(
435 array( 'debug' => LodashBasic::omit( $debug_content, array( 'messages' ) ) ),
436 $result
437 )
438 );
439 }
440 }
441 }
442
443 if ( $log ) {
444 $messages = array_merge(
445 array(
446 array(
447 'role' => 'api payload',
448 'content' => json_encode( $payload, JSON_PRETTY_PRINT ),
449 ),
450 ),
451 Arr::get(
452 $debug_content,
453 'messages',
454 array()
455 )
456 );
457
458 $log_response = Arr::get( $debug_content, 'response_raw', array() );
459
460 if ( is_wp_error( $result ) ) {
461
462 $response_messages = array();
463 foreach ( $result->get_all_error_data() as $error_data ) {
464 $error_data = Utils::maybeJSONDecode( $error_data );
465 if ( is_array( $error_data ) ) {
466 $response_messages[] = Arr::get( $error_data, 'debug', $error_data );
467 } else {
468 $response_messages[] = $error_data;
469 }
470 }
471
472 $log_response = array(
473 'error_codes' => $result->get_error_codes(),
474 'error_messages' => $result->get_error_messages(),
475 'response_messages' => $response_messages,
476 );
477 }
478
479 if ( $result === null ) {
480 $result = new WP_Error( 'ai_response_not_json', __( 'AI response is invalid ( Empty response )', 'kubio' ) );
481 $log_response = wp_remote_retrieve_body( $response );
482 }
483
484 $log_code = $path;
485 if ( strpos( $path, '/generate-page-section' ) !== false || strpos( $path, '/rephrase-page-section' ) !== false ) {
486 $log_code = sprintf( '%s ( %s )', $log_code, Arr::get( $payload, 'category', 'N/A' ) );
487 }
488
489 kubio_ai_log(
490 is_wp_error( $result ) ? 'error' : 'info',
491 $log_code,
492 $messages,
493 $log_response,
494 array(
495 'start_time' => $start_time,
496 'total_tokens' => Arr::get( $debug_content, 'total_tokens', 0 ),
497 'prompt_tokens' => Arr::get( $debug_content, 'prompt_tokens', 0 ),
498 'completion_tokens' => Arr::get( $debug_content, 'completion_tokens', 0 ),
499 ),
500 Arr::get( $_REQUEST, '__kubio_call_id', null )
501 );
502 }
503
504 if ( is_array( $result ) ) {
505 $result['upgrade_key'] = sprintf( 'ai:%s', apply_filters( 'kubio/ai/upgrade-key', base64_encode( kubio_ai_get_key() ) ) );
506 }
507
508 return $result;
509 }
510
511