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