PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 1.4.0
AI Engine – The Chatbot, AI Framework & MCP for WordPress v1.4.0
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 / core.php
ai-engine / classes Last commit date
modules 3 years ago admin.php 3 years ago ai.php 3 years ago answer.php 3 years ago api.php 3 years ago core.php 3 years ago init.php 3 years ago openai.php 3 years ago query.php 3 years ago queryembed.php 3 years ago queryimage.php 3 years ago querytext.php 3 years ago querytranscribe.php 3 years ago rest.php 3 years ago security.php 3 years ago ui.php 3 years ago
core.php
633 lines
1 <?php
2
3 require_once( MWAI_PATH . '/vendor/autoload.php' );
4 require_once( MWAI_PATH . '/constants/init.php' );
5
6 use Rahul900day\Gpt3Encoder\Encoder;
7
8 define( 'MWAI_IMG_WAND', MWAI_URL . '/images/wand.png' );
9 define( 'MWAI_IMG_WAND_HTML', "<img style='height: 22px; margin-bottom: -5px; margin-right: 8px;'
10 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
11 define( 'MWAI_IMG_WAND_HTML_XS', "<img style='height: 16px; margin-bottom: -2px;'
12 src='" . MWAI_IMG_WAND . "' alt='AI Wand' />" );
13 class Meow_MWAI_Core
14 {
15 public $admin = null;
16 public $is_rest = false;
17 public $is_cli = false;
18 public $site_url = null;
19 public $ai = null;
20 private $option_name = 'mwai_options';
21 private $themes_option_name = 'mwai_themes';
22 private $chatbots_option_name = 'mwai_chatbots';
23 public $defaultChatbotParams = MWAI_CHATBOT_PARAMS;
24
25 public function __construct() {
26 $this->site_url = get_site_url();
27 $this->is_rest = MeowCommon_Helpers::is_rest();
28 $this->is_cli = defined( 'WP_CLI' ) && WP_CLI;
29 $this->ai = new Meow_MWAI_AI( $this );
30 add_action( 'plugins_loaded', array( $this, 'init' ) );
31 }
32
33 function init() {
34 global $mwai;
35 $mwai = new Meow_MWAI_API();
36 new Meow_MWAI_Security( $this );
37 if ( $this->is_rest ) {
38 new Meow_MWAI_Rest( $this );
39 }
40 if ( is_admin() ) {
41 new Meow_MWAI_Admin( $this );
42 new Meow_MWAI_Modules_Assistants( $this );
43 }
44 else {
45 //new Meow_MWAI_UI( $this );
46 if ( $this->get_option( 'shortcode_chat' ) ) {
47 new Meow_MWAI_Modules_Chatbot();
48 }
49 }
50
51 // Advanced core
52 if ( class_exists( 'MeowPro_MWAI_Core' ) ) {
53 new MeowPro_MWAI_Core( $this );
54 }
55
56 // Dynamic max tokens
57 if ( $this->get_option( 'dynamic_max_tokens' ) ) {
58 add_filter( 'mwai_estimate_tokens', array( $this, 'dynamic_max_tokens' ), 10, 2 );
59 }
60 }
61
62 #region Roles & Capabilities
63
64 function can_access_settings() {
65 return apply_filters( 'mwai_allow_setup', current_user_can( 'manage_options' ) );
66 }
67
68 function can_access_features() {
69 $editor_or_admin = current_user_can( 'editor' ) || current_user_can( 'administrator' );
70 return apply_filters( 'mwai_allow_usage', $editor_or_admin );
71 }
72
73 #endregion
74
75 #region Text-Related Helpers
76
77 // Clean the text perfectly, resolve shortcodes, etc, etc.
78 function cleanText( $rawText = "" ) {
79 $text = html_entity_decode( $rawText );
80 $text = wp_strip_all_tags( $text );
81 $text = preg_replace( '/[\r\n]+/', "\n", $text );
82 return $text . " ";
83
84 // Before simplification:
85 // $text = strip_tags( $rawText );
86 // $text = strip_shortcodes( $text );
87 // $text = html_entity_decode( $text );
88 // $text = preg_replace( '/[\r\n]+/', "\n", $text );
89 // $sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
90 // foreach ( $sentences as $key => $sentence ) {
91 // $sentences[$key] = trim( $sentence );
92 // }
93 // $text = implode( " ", $sentences );
94 // $text = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $text );
95 // return $text . " ";
96 }
97
98 // Make sure there are no duplicate sentences, and keep the length under a maximum length.
99 function cleanSentences( $text, $maxTokens = 512 ) {
100 //$sentences = preg_split( '/(?<=[.?!])(?=[a-zA-Z ])/', $text );
101 $sentences = preg_split('/(?<=[.?!。.!?])+/u', $text);
102 $hashes = array();
103 $uniqueSentences = array();
104 $length = 0;
105 foreach ( $sentences as $sentence ) {
106 $sentence = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $sentence );
107 $hash = md5( $sentence );
108 if ( !in_array( $hash, $hashes ) ) {
109 $tokensCount = apply_filters( 'mwai_estimate_tokens', 0, $sentence );
110 if ( $length + $tokensCount > $maxTokens ) {
111 continue;
112 }
113 $hashes[] = $hash;
114 $uniqueSentences[] = $sentence;
115 $length += $tokensCount;
116 }
117 }
118 $freshText = implode( " ", $uniqueSentences );
119 $freshText = preg_replace( '/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $freshText );
120 return $freshText;
121 }
122
123 function getCleanPostContent( $postId ) {
124 $post = get_post( $postId );
125 if ( !$post ) {
126 return false;
127 }
128 $post->post_content = apply_filters( 'the_content', $post->post_content );
129 $text = $this->cleanText( $post->post_content );
130 $text = $this->cleanSentences( $text );
131 return $text;
132 }
133
134 function markdown_to_html( $content ) {
135 $Parsedown = new Parsedown();
136 $content = $Parsedown->text( $content );
137 return $content;
138 }
139
140 function get_post_language( $postId ) {
141 $locale = get_locale();
142 $code = strtolower( substr( $locale, 0, 2 ) );
143 $lang_codes = array(
144 'aa' => 'Afar',
145 'ab' => 'Abkhazian',
146 'af' => 'Afrikaans',
147 'ak' => 'Akan',
148 'sq' => 'Albanian',
149 'am' => 'Amharic',
150 'ar' => 'Arabic',
151 'an' => 'Aragonese',
152 'hy' => 'Armenian',
153 'as' => 'Assamese',
154 'av' => 'Avaric',
155 'ae' => 'Avestan',
156 'ay' => 'Aymara',
157 'az' => 'Azerbaijani',
158 'ba' => 'Bashkir',
159 'bm' => 'Bambara',
160 'eu' => 'Basque',
161 'be' => 'Belarusian',
162 'bn' => 'Bengali',
163 'bh' => 'Bihari',
164 'bi' => 'Bislama',
165 'bs' => 'Bosnian',
166 'br' => 'Breton',
167 'bg' => 'Bulgarian',
168 'my' => 'Burmese',
169 'ca' => 'Catalan; Valencian',
170 'ch' => 'Chamorro',
171 'ce' => 'Chechen',
172 'zh' => 'Chinese',
173 'cu' => 'Church Slavic; Old Slavonic; Church Slavonic; Old Bulgarian; Old Church Slavonic',
174 'cv' => 'Chuvash',
175 'kw' => 'Cornish',
176 'co' => 'Corsican',
177 'cr' => 'Cree',
178 'cs' => 'Czech',
179 'da' => 'Danish',
180 'dv' => 'Divehi; Dhivehi; Maldivian',
181 'nl' => 'Dutch; Flemish',
182 'dz' => 'Dzongkha',
183 'en' => 'English',
184 'eo' => 'Esperanto',
185 'et' => 'Estonian',
186 'ee' => 'Ewe',
187 'fo' => 'Faroese',
188 'fj' => 'Fijjian',
189 'fi' => 'Finnish',
190 'fr' => 'French',
191 'fy' => 'Western Frisian',
192 'ff' => 'Fulah',
193 'ka' => 'Georgian',
194 'de' => 'German',
195 'gd' => 'Gaelic; Scottish Gaelic',
196 'ga' => 'Irish',
197 'gl' => 'Galician',
198 'gv' => 'Manx',
199 'el' => 'Greek, Modern',
200 'gn' => 'Guarani',
201 'gu' => 'Gujarati',
202 'ht' => 'Haitian; Haitian Creole',
203 'ha' => 'Hausa',
204 'he' => 'Hebrew',
205 'hz' => 'Herero',
206 'hi' => 'Hindi',
207 'ho' => 'Hiri Motu',
208 'hu' => 'Hungarian',
209 'ig' => 'Igbo',
210 'is' => 'Icelandic',
211 'io' => 'Ido',
212 'ii' => 'Sichuan Yi',
213 'iu' => 'Inuktitut',
214 'ie' => 'Interlingue',
215 'ia' => 'Interlingua (International Auxiliary Language Association)',
216 'id' => 'Indonesian',
217 'ik' => 'Inupiaq',
218 'it' => 'Italian',
219 'jv' => 'Javanese',
220 'ja' => 'Japanese',
221 'kl' => 'Kalaallisut; Greenlandic',
222 'kn' => 'Kannada',
223 'ks' => 'Kashmiri',
224 'kr' => 'Kanuri',
225 'kk' => 'Kazakh',
226 'km' => 'Central Khmer',
227 'ki' => 'Kikuyu; Gikuyu',
228 'rw' => 'Kinyarwanda',
229 'ky' => 'Kirghiz; Kyrgyz',
230 'kv' => 'Komi',
231 'kg' => 'Kongo',
232 'ko' => 'Korean',
233 'kj' => 'Kuanyama; Kwanyama',
234 'ku' => 'Kurdish',
235 'lo' => 'Lao',
236 'la' => 'Latin',
237 'lv' => 'Latvian',
238 'li' => 'Limburgan; Limburger; Limburgish',
239 'ln' => 'Lingala',
240 'lt' => 'Lithuanian',
241 'lb' => 'Luxembourgish; Letzeburgesch',
242 'lu' => 'Luba-Katanga',
243 'lg' => 'Ganda',
244 'mk' => 'Macedonian',
245 'mh' => 'Marshallese',
246 'ml' => 'Malayalam',
247 'mi' => 'Maori',
248 'mr' => 'Marathi',
249 'ms' => 'Malay',
250 'mg' => 'Malagasy',
251 'mt' => 'Maltese',
252 'mo' => 'Moldavian',
253 'mn' => 'Mongolian',
254 'na' => 'Nauru',
255 'nv' => 'Navajo; Navaho',
256 'nr' => 'Ndebele, South; South Ndebele',
257 'nd' => 'Ndebele, North; North Ndebele',
258 'ng' => 'Ndonga',
259 'ne' => 'Nepali',
260 'nn' => 'Norwegian Nynorsk; Nynorsk, Norwegian',
261 'nb' => 'Bokmål, Norwegian, Norwegian Bokmål',
262 'no' => 'Norwegian',
263 'ny' => 'Chichewa; Chewa; Nyanja',
264 'oc' => 'Occitan, Provençal',
265 'oj' => 'Ojibwa',
266 'or' => 'Oriya',
267 'om' => 'Oromo',
268 'os' => 'Ossetian; Ossetic',
269 'pa' => 'Panjabi; Punjabi',
270 'fa' => 'Persian',
271 'pi' => 'Pali',
272 'pl' => 'Polish',
273 'pt' => 'Portuguese',
274 'ps' => 'Pushto',
275 'qu' => 'Quechua',
276 'rm' => 'Romansh',
277 'ro' => 'Romanian',
278 'rn' => 'Rundi',
279 'ru' => 'Russian',
280 'sg' => 'Sango',
281 'sa' => 'Sanskrit',
282 'sr' => 'Serbian',
283 'hr' => 'Croatian',
284 'si' => 'Sinhala; Sinhalese',
285 'sk' => 'Slovak',
286 'sl' => 'Slovenian',
287 'se' => 'Northern Sami',
288 'sm' => 'Samoan',
289 'sn' => 'Shona',
290 'sd' => 'Sindhi',
291 'so' => 'Somali',
292 'st' => 'Sotho, Southern',
293 'es' => 'Spanish; Castilian',
294 'sc' => 'Sardinian',
295 'ss' => 'Swati',
296 'su' => 'Sundanese',
297 'sw' => 'Swahili',
298 'sv' => 'Swedish',
299 'ty' => 'Tahitian',
300 'ta' => 'Tamil',
301 'tt' => 'Tatar',
302 'te' => 'Telugu',
303 'tg' => 'Tajik',
304 'tl' => 'Tagalog',
305 'th' => 'Thai',
306 'bo' => 'Tibetan',
307 'ti' => 'Tigrinya',
308 'to' => 'Tonga (Tonga Islands)',
309 'tn' => 'Tswana',
310 'ts' => 'Tsonga',
311 'tk' => 'Turkmen',
312 'tr' => 'Turkish',
313 'tw' => 'Twi',
314 'ug' => 'Uighur; Uyghur',
315 'uk' => 'Ukrainian',
316 'ur' => 'Urdu',
317 'uz' => 'Uzbek',
318 've' => 'Venda',
319 'vi' => 'Vietnamese',
320 'vo' => 'Volapük',
321 'cy' => 'Welsh',
322 'wa' => 'Walloon',
323 'wo' => 'Wolof',
324 'xh' => 'Xhosa',
325 'yi' => 'Yiddish',
326 'yo' => 'Yoruba',
327 'za' => 'Zhuang; Chuang',
328 'zu' => 'Zulu',
329 );
330 $humanLanguage = strtr( $code, $lang_codes );
331 $lang = apply_filters( 'wpml_post_language_details', null, $postId );
332 if ( !empty( $lang ) ) {
333 $locale = $lang['locale'];
334 $humanLanguage = $lang['display_name'];
335 }
336 return strtolower( "$locale ($humanLanguage)" );
337 }
338 #endregion
339
340 #region Users/Sessions Helpers
341
342 function get_session_id() {
343 if ( isset( $_COOKIE['mwai_session_id'] ) ) {
344 return $_COOKIE['mwai_session_id'];
345 }
346 return "N/A";
347 }
348
349 // Get the UserID from the data, or from the current user
350 function get_user_id( $data = null ) {
351 if ( isset( $data ) && isset( $data['userId'] ) ) {
352 return (int)$data['userId'];
353 }
354 if ( is_user_logged_in() ) {
355 $current_user = wp_get_current_user();
356 if ( $current_user->ID > 0 ) {
357 return $current_user->ID;
358 }
359 }
360 return null;
361 }
362
363 function getUserData() {
364 $user = wp_get_current_user();
365 $placeholders = array(
366 'FIRST_NAME' => get_user_meta($user->ID, 'first_name', true),
367 'LAST_NAME' => get_user_meta($user->ID, 'last_name', true),
368 'USER_LOGIN' => $user->data->user_login,
369 'DISPLAY_NAME' => $user->data->display_name,
370 'AVATAR_URL' => get_avatar_url( get_current_user_id() ),
371 );
372 return $placeholders;
373 }
374
375 function get_ip_address( $data = null ) {
376 if ( isset( $data ) && isset( $data['ip'] ) ) {
377 $data['ip'] = (string)$data['ip'];
378 }
379 else {
380 if ( isset( $_SERVER['REMOTE_ADDR'] ) ) {
381 $data['ip'] = sanitize_text_field( $_SERVER['REMOTE_ADDR'] );
382 }
383 else if ( isset( $_SERVER['HTTP_CLIENT_IP'] ) ) {
384 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_CLIENT_IP'] );
385 }
386 else if ( isset( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {
387 $data['ip'] = sanitize_text_field( $_SERVER['HTTP_X_FORWARDED_FOR'] );
388 }
389 }
390 return $data['ip'];
391 }
392
393 #endregion
394
395 #region Other Helpers
396
397 function isUrl( $url ) {
398 return strpos( $url, 'http' ) === 0 ? true : false;
399 }
400
401 function getPostTypes() {
402 $excluded = array( 'attachment', 'revision', 'nav_menu_item' );
403 $post_types = array();
404 $types = get_post_types( array( 'public' => true ), 'objects' );
405 foreach ( $types as $type ) {
406 if ( in_array( $type->name, $excluded ) ) {
407 continue;
408 }
409 $post_types[] = array(
410 'name' => $type->labels->name,
411 'type' => $type->name,
412 );
413 }
414 return $post_types;
415 }
416
417 function getCleanPost( $post ) {
418 if ( is_object( $post ) ) {
419 $post = (array)$post;
420 }
421 $language = $this->get_post_language( $post['ID'] );
422 $content = apply_filters( 'mwai_pre_post_content', $post['post_content'], $post['ID'] );
423 $content = $this->cleanText( $content );
424 $content = apply_filters( 'mwai_post_content', $content, $post['ID'] );
425 $title = $post['post_title'];
426 $excerpt = $post['post_excerpt'];
427 $url = get_permalink( $post['ID'] );
428 $checksum = wp_hash( $content . $title . $url );
429 return [
430 'postId' => $post['ID'],
431 'title' => $title,
432 'content' => $content,
433 'excerpt' => $excerpt,
434 'url' => $url,
435 'language' => $language,
436 'checksum' => $checksum,
437 ];
438 }
439
440 #endregion
441
442 #region Usage & Costs
443
444 public function dynamic_max_tokens( $tokens, $text ) {
445 // Approximation (fast, no lib)
446 $asciiCount = 0;
447 $nonAsciiCount = 0;
448 for ( $i = 0; $i < mb_strlen( $text ); $i++ ) {
449 $char = mb_substr( $text, $i, 1 );
450 if ( ord( $char ) < 128 ) {
451 $asciiCount++;
452 }
453 else {
454 $nonAsciiCount++;
455 }
456 }
457 $asciiTokens = $asciiCount / 3.5;
458 $nonAsciiTokens = $nonAsciiCount * 2.5;
459 $tokens = $asciiTokens + $nonAsciiTokens;
460
461 // More exact (slower, and lib)
462 if ( PHP_VERSION_ID >= 70400 && function_exists( 'mb_convert_encoding' ) ) {
463 try {
464 $token_array = Encoder::encode( $text );
465 if ( !empty( $token_array ) ) {
466 $tokens = count( $token_array );
467 }
468 }
469 catch ( Exception $e ) {
470 error_log( $e->getMessage() );
471 }
472 }
473
474 $tokens = $tokens;
475 return (int)$tokens;
476 }
477
478 public function record_tokens_usage( $model, $prompt_tokens, $completion_tokens = 0 ) {
479 if ( !is_numeric( $prompt_tokens ) ) {
480 throw new Exception( 'Record usage: prompt_tokens is not a number.' );
481 }
482 if ( !is_numeric( $completion_tokens ) ) {
483 $completion_tokens = 0;
484 }
485 if ( !$model ) {
486 throw new Exception( 'Record usage: model is missing.' );
487 }
488 $usage = $this->get_option( 'openai_usage' );
489 $month = date( 'Y-m' );
490 if ( !isset( $usage[$month] ) ) {
491 $usage[$month] = array();
492 }
493 if ( !isset( $usage[$month][$model] ) ) {
494 $usage[$month][$model] = array(
495 'prompt_tokens' => 0,
496 'completion_tokens' => 0,
497 'total_tokens' => 0
498 );
499 }
500 $usage[$month][$model]['prompt_tokens'] += $prompt_tokens;
501 $usage[$month][$model]['completion_tokens'] += $completion_tokens;
502 $usage[$month][$model]['total_tokens'] += $prompt_tokens + $completion_tokens;
503 $this->update_option( 'openai_usage', $usage );
504 return [
505 'prompt_tokens' => $prompt_tokens,
506 'completion_tokens' => $completion_tokens,
507 'total_tokens' => $prompt_tokens + $completion_tokens
508 ];
509 }
510
511 public function record_images_usage( $model, $resolution, $images ) {
512 if ( !$model || !$resolution || !$images ) {
513 throw new Exception( 'Missing parameters for record_image_usage.' );
514 }
515 $usage = $this->get_option( 'openai_usage' );
516 $month = date( 'Y-m' );
517 if ( !isset( $usage[$month] ) ) {
518 $usage[$month] = array();
519 }
520 if ( !isset( $usage[$month][$model] ) ) {
521 $usage[$month][$model] = array(
522 'resolution' => array(),
523 'images' => 0
524 );
525 }
526 if ( !isset( $usage[$month][$model]['resolution'][$resolution] ) ) {
527 $usage[$month][$model]['resolution'][$resolution] = 0;
528 }
529 $usage[$month][$model]['resolution'][$resolution] += $images;
530 $usage[$month][$model]['images'] += $images;
531 $this->update_option( 'openai_usage', $usage );
532 return [
533 'resolution' => $resolution,
534 'images' => $images
535 ];
536 }
537
538 #endregion
539
540 #region Options
541 function getThemes() {
542 $themes = get_option( $this->themes_option_name, [] );
543 if ( empty( $themes ) ) {
544 $themes = [ [
545 'type' => 'internal',
546 'name' => 'ChatGPT',
547 'themeId' => 'chatgpt',
548 'settings' => [],
549 'style' => ""
550 ] ];
551 }
552 return $themes;
553 }
554
555 function updateThemes( $themes ) {
556 update_option( $this->themes_option_name, $themes );
557 return $themes;
558 }
559
560 function getChatbots() {
561 $chatbots = get_option( $this->chatbots_option_name, [] );
562 if ( empty( $chatbots ) ) {
563 $chatbots = [ array_merge( MWAI_CHATBOT_PARAMS, ['name' => 'Default', 'chatId' => 'default' ] ) ];
564 }
565 foreach ( $chatbots as $chatbot ) {
566 foreach ( MWAI_CHATBOT_PARAMS as $key => $value ) {
567 if ( !isset( $chatbot[$key] ) ) {
568 $chatbot[$key] = $value;
569 }
570 }
571 }
572 return $chatbots;
573 }
574
575 function updateChatbots( $chatbots ) {
576 update_option( $this->chatbots_option_name, $chatbots );
577 return $chatbots;
578 }
579
580 function get_all_options() {
581 $options = get_option( $this->option_name, null );
582 foreach ( MWAI_OPTIONS as $key => $value ) {
583 if ( !isset( $options[$key] ) ) {
584 $options[$key] = $value;
585 }
586 if ( $key === 'languages' ) {
587 // TODO: If we decide to make a set of options for languages, we can keep it in the settings
588 $options[$key] = MWAI_LANGUAGES;
589 $options[$key] = apply_filters( 'mwai_languages', $options[$key] );
590 }
591 }
592 $options['shortcode_chat_default_params'] = MWAI_CHATBOT_PARAMS;
593 $options['default_limits'] = MWAI_LIMITS;
594 $options['openai_models'] = MWAI_OPENAI_MODELS;
595 return $options;
596 }
597
598 // Validate and keep the options clean and logical.
599 function sanitize_options() {
600 $options = $this->get_all_options();
601 $needs_update = false;
602
603 // We can sanitize our future options here, let's always remember it.
604 // Now, it is empty...
605
606 if ( $needs_update ) {
607 update_option( $this->option_name, $options, false );
608 }
609 return $options;
610 }
611
612 function update_options( $options ) {
613 if ( !update_option( $this->option_name, $options, false ) ) {
614 return false;
615 }
616 $options = $this->sanitize_options();
617 return $options;
618 }
619
620 function update_option( $option, $value ) {
621 $options = $this->get_all_options();
622 $options[$option] = $value;
623 return $this->update_options( $options );
624 }
625
626 function get_option( $option, $default = null ) {
627 $options = $this->get_all_options();
628 return $options[$option] ?? $default;
629 }
630 #endregion
631 }
632
633 ?>