PluginProbe ʕ •ᴥ•ʔ
Kubio AI Page Builder / 2.4.0
Kubio AI Page Builder v2.4.0
2.8.5 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 2 years ago api.php 2 years ago index.php 2 years ago utils.php 2 years ago
utils.php
497 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 $timeout = 120;
324 ini_set( 'max_execution_time', $timeout );
325 set_time_limit( $timeout );
326
327 $log = defined( 'KUBIO_AI_LOG' ) ? KUBIO_AI_LOG : false;
328
329 $base_url = Utils::getCloudURL( "/api/ai/$path" );
330 $url = add_query_arg(
331 array(
332 'ai_debug' => $log ? 1 : 0,
333 ),
334 $base_url
335 );
336
337 $start_time = microtime( true );
338 $filter = "kubio_ai_response_{$path}";
339 // add a filter
340 if ( has_filter( $filter ) ) {
341 $response = apply_filters( $filter, $payload );
342
343 return $response;
344 }
345
346 $response = wp_remote_post(
347 $url,
348 array(
349 'timeout' => $timeout - 1,
350 'sslverify' => false,
351 'headers' => array(
352 'Content-Type' => 'application/json',
353 'Accept' => 'application/json',
354 'X-Kubio-AI-Key' => kubio_ai_get_key(),
355 'X-Kubio-Site-UUID' => Flags::getSiteUUID(),
356 'X-Kubio-Site-URL' => get_bloginfo( 'url' ),
357 ),
358 'body' => json_encode(
359 array_merge(
360 array(
361 'params' => $payload,
362 ),
363 $extra
364 )
365 ),
366 )
367 );
368
369 if ( is_wp_error( $response ) ) {
370 return $response;
371 }
372
373 $code = wp_remote_retrieve_response_code( $response );
374
375 $result = null;
376 $debug_content = array();
377 $response_content = null;
378
379 if ( $code !== 200 ) {
380 $response_content = wp_remote_retrieve_body( $response );
381 $body = json_decode( $response_content, true );
382 $error = Arr::get( (array) $body, 'error', null );
383 if ( $error ) {
384 $result = new \WP_Error(
385 Arr::get( $error, 'code', '' ),
386 Arr::get( $error, 'message', '' ),
387 $response_content
388 );
389 } else {
390 $result = new \WP_Error(
391 $code,
392 // translators: %s is the error message
393 sprintf( __( 'AI Server error: %s', 'kubio' ), Arr::get( $error, 'message', '' ) ),
394 $response_content
395 );
396 }
397 } else {
398 $response_content = wp_remote_retrieve_body( $response );
399 $body = json_decode( $response_content, true );
400
401 $result = array(
402 'content' => Arr::get( is_array( $body ) ? $body : array(), 'content', null ),
403 'service_info' => (object) Arr::get( $body, 'service_info', array() ),
404 );
405
406 if ( ! is_array( $body ) ) {
407 $result = new WP_Error(
408 'ai_response_not_json',
409 __( 'AI response is invalid', 'kubio' ),
410 $response_content
411 );
412 } else {
413
414 $error = $body['error'];
415 $debug_content = Arr::get( $body, 'debug', array() );
416
417 if ( $error ) {
418 $result = new WP_Error(
419 $error['code'],
420 $error['message'],
421 array_merge(
422 array( 'debug' => LodashBasic::omit( $debug_content, array( 'messages' ) ) ),
423 $result
424 )
425 );
426 }
427 }
428 }
429
430 if ( $log ) {
431 $messages = array_merge(
432 array(
433 array(
434 'role' => 'api payload',
435 'content' => json_encode( $payload, JSON_PRETTY_PRINT ),
436 ),
437 ),
438 Arr::get(
439 $debug_content,
440 'messages',
441 array()
442 )
443 );
444
445 $log_response = Arr::get( $debug_content, 'response_raw', array() );
446
447 if ( is_wp_error( $result ) ) {
448
449 $response_messages = array();
450 foreach ( $result->get_all_error_data() as $error_data ) {
451 $error_data = Utils::maybeJSONDecode( $error_data );
452 if ( is_array( $error_data ) ) {
453 $response_messages[] = Arr::get( $error_data, 'debug', $error_data );
454 } else {
455 $response_messages[] = $error_data;
456 }
457 }
458
459 $log_response = array(
460 'error_codes' => $result->get_error_codes(),
461 'error_messages' => $result->get_error_messages(),
462 'response_messages' => $response_messages,
463 );
464 }
465
466 if ( $result === null ) {
467 $result = new WP_Error( 'ai_response_not_json', __( 'AI response is invalid ( Empty response )', 'kubio' ) );
468 $log_response = wp_remote_retrieve_body( $response );
469 }
470
471 $log_code = $path;
472 if ( strpos( $path, '/generate-page-section' ) !== false || strpos( $path, '/rephrase-page-section' ) !== false ) {
473 $log_code = sprintf( '%s ( %s )', $log_code, Arr::get( $payload, 'category', 'N/A' ) );
474 }
475
476 kubio_ai_log(
477 is_wp_error( $result ) ? 'error' : 'info',
478 $log_code,
479 $messages,
480 $log_response,
481 array(
482 'start_time' => $start_time,
483 'total_tokens' => Arr::get( $debug_content, 'total_tokens', 0 ),
484 'prompt_tokens' => Arr::get( $debug_content, 'prompt_tokens', 0 ),
485 'completion_tokens' => Arr::get( $debug_content, 'completion_tokens', 0 ),
486 ),
487 Arr::get( $_REQUEST, '__kubio_call_id', null )
488 );
489 }
490
491 if ( is_array( $result ) ) {
492 $result['upgrade_key'] = sprintf( 'ai:%s', apply_filters( 'kubio/ai/upgrade-key', base64_encode( kubio_ai_get_key() ) ) );
493 }
494
495 return $result;
496 }
497