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