PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.8.0
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.8.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 / reply.php
ai-engine / classes Last commit date
engines 1 year ago modules 1 year ago queries 1 year ago admin.php 1 year ago api.php 1 year ago core.php 1 year ago discussion.php 1 year ago init.php 1 year ago logging.php 1 year ago reply.php 1 year ago rest.php 1 year ago
reply.php
279 lines
1 <?php
2
3 class Meow_MWAI_Reply implements JsonSerializable {
4 public $id = null;
5 public $result = '';
6 public $results = [];
7 public $usage = [
8 'prompt_tokens' => 0,
9 'completion_tokens' => 0,
10 'total_tokens' => 0,
11 'price' => null,
12 ];
13 public $query = null;
14 public $type = 'text';
15
16 // This is when models return a message that needs to be executed (functions, tools, etc)
17 public $needFeedbacks = [];
18 public $needClientActions = [];
19
20 public function __construct( $query = null ) {
21 $this->query = $query;
22 }
23
24 #[\ReturnTypeWillChange]
25 public function jsonSerialize() {
26 $isEmbedding = false;
27 $embeddingsDimensions = null;
28 $embedddingsMessage = null;
29 if ( is_array( $this->results ) && count( $this->results ) > 0 ) {
30 $isEmbedding = is_array( $this->results[0] );
31 if ( $isEmbedding ) {
32 $embeddingsDimensions = count( $this->results[0] );
33 $embedddingsMessage = "A $embeddingsDimensions-dimensional embedding was returned.";
34 }
35 }
36 $data = [
37 'result' => $isEmbedding ? $embedddingsMessage : $this->result,
38 'results' => $isEmbedding ? [] : $this->results,
39 'usage' => $this->usage,
40 'system' => [
41 'class' => get_class( $this ),
42 ]
43 ];
44 if ( !empty( $this->needFeedbacks ) ) {
45 $data['needFeedbacks'] = $this->needFeedbacks;
46 }
47 if ( !empty( $this->needClientActions ) ) {
48 $data['needClientActions'] = $this->needClientActions;
49 }
50 return $data;
51 }
52
53 public function set_usage( $usage ) {
54 $this->usage = $usage;
55 }
56
57 public function set_id( $id ) {
58 $this->id = $id;
59 }
60
61 public function set_type( $type ) {
62 $this->type = $type;
63 }
64
65 public function get_total_tokens() {
66 return $this->usage['total_tokens'];
67 }
68
69 public function get_in_tokens( $query = null ) {
70 $in_tokens = $this->usage['prompt_tokens'];
71 if ( empty( $in_tokens ) && $query ) {
72 $in_tokens = $query->get_in_tokens();
73 }
74 return $in_tokens;
75 }
76
77 public function get_out_tokens() {
78 $out_tokens = $this->usage['completion_tokens'];
79 if ( empty( $out_tokens ) ) {
80 $out_tokens = Meow_MWAI_Core::estimate_tokens( $this->result );
81 }
82 return $out_tokens;
83 }
84
85 public function get_price() {
86 // If it's not set return null, but it can be 0
87 if ( !isset( $this->usage['price'] ) ) {
88 return null;
89 }
90 return $this->usage['price'];
91 }
92
93 public function get_units() {
94 if ( isset( $this->usage['total_tokens'] ) ) {
95 return $this->usage['total_tokens'];
96 }
97 else if ( isset( $this->usage['images'] ) ) {
98 return $this->usage['images'];
99 }
100 else if ( isset( $this->usage['seconds'] ) ) {
101 return $this->usage['seconds'];
102 }
103 return null;
104 }
105
106 public function get_type() {
107 return $this->type;
108 }
109
110 public function set_reply( $reply ) {
111 $this->result = $reply;
112 $this->results[] = [ $reply ];
113 }
114
115 public function replace( $search, $replace ) {
116 $this->result = str_replace( $search, $replace, $this->result );
117 $this->results = array_map( function( $result ) use ( $search, $replace ) {
118 return str_replace( $search, $replace, $result );
119 }, $this->results );
120 }
121
122 private function extract_arguments( $funcArgs ) {
123 $finalArgs = [];
124 if ( is_string( $funcArgs ) ) {
125 $arguments = trim( str_replace( "\n", "", $funcArgs ) );
126 if ( substr( $arguments, 0, 1 ) == '{' ) {
127 $arguments = json_decode( $arguments, true );
128 $finalArgs = $arguments;
129 }
130 }
131 else if ( is_array( $funcArgs ) ) {
132 $finalArgs = $funcArgs;
133 }
134 return $finalArgs;
135 }
136
137 /**
138 * Set the choices from OpenAI as the results.
139 * The last (or only) result is set as the result.
140 * @param array $choices ID of the model to use.
141 */
142 public function set_choices( $choices, $rawMessage = null) {
143 $this->results = [];
144 if ( is_array( $choices ) ) {
145 foreach ( $choices as $choice ) {
146
147 // It's chat completion
148 if ( isset( $choice['message'] ) ) {
149
150 // It's text content
151 if ( isset( $choice['message']['content'] ) ) {
152 $content = trim( $choice['message']['content'] );
153 $this->results[] = $content;
154 $this->result = $content;
155 }
156
157 // It's a tool call (OpenAI-style and Anthropic-style)
158 $toolCalls = [];
159 if ( isset( $choice['message']['tool_calls'] ) ) {
160 $tools = $choice['message']['tool_calls'];
161 foreach ( $tools as $tool ) {
162 if ( $tool['type'] === 'function' ) {
163 $toolCalls[] = [
164 'toolId' => $tool['id'],
165 //'mode' => 'interactive',
166 'type' => 'tool_call',
167 'name' => trim( $tool['function']['name'] ),
168 'arguments' => $this->extract_arguments( $tool['function']['arguments'] ),
169 // Represent the original message that triggered the function call
170 'rawMessage' => $rawMessage ? $rawMessage : $choice['message'],
171 ];
172 }
173 }
174 }
175
176 // If it's a function call (Open-AI style; usually for a final execution)
177 if ( isset( $choice['message']['function_call'] ) ) {
178 $content = $choice['message']['function_call'];
179 $name = trim( $content['name'] );
180 $args = $content['arguments'] ?? $content['args'] ?? null;
181 $toolCalls[] = [
182 'toolId' => null,
183 'mode' => 'static',
184 'type' => 'function_call',
185 'name' => $name,
186 'arguments' => $this->extract_arguments( $args ),
187 'rawMessage' => $rawMessage ? $rawMessage : $choice['message'],
188 ];
189 }
190
191 // Resolve the original function from the query
192 if ( !empty( $toolCalls ) ) {
193 foreach ( $toolCalls as &$toolCall ) {
194 if ( $toolCall['type'] !== 'function_call' && $toolCall['type'] !== 'tool_call' ) {
195 continue;
196 }
197 foreach ( $this->query->functions as $function ) {
198 if ( $function->name == $toolCall['name'] ) {
199 $toolCall['function'] = $function;
200 break;
201 }
202 }
203 }
204 }
205
206 // NOTE: Anaheim proposed that fix to avoid the error "Duplicate value for 'tool_call_id'"
207 // This happens when the same function is called twice; we need to investigate.
208 $toolCallsDeepCopy = array_map( function( $toolCall ) {
209 return is_array( $toolCall ) ? array_merge( [], $toolCall ) : $toolCall;
210 }, $toolCalls);
211 $toolCalls = $toolCallsDeepCopy;
212
213 // Let's separate the Feedbacks (PHP code) and Client Actions (JS code)
214 $this->needFeedbacks = [];
215 $this->needClientActions = [];
216 foreach ( $toolCalls as $toolCall ) {
217 if ( $toolCall['function']->target !== 'js' ) {
218 $this->needFeedbacks[] = $toolCall;
219 }
220 else if ( $toolCall['function']->target === 'js' ) {
221 $this->needClientActions[] = $toolCall;
222 }
223 }
224 }
225
226 // It's text completion
227 else if ( isset( $choice['text'] ) ) {
228
229 // TODO: Assistants return an array (so actually not really a text completion)
230 // We should probably make this clearer and analyze all the outputs from different endpoints.
231 if ( is_array( $choice['text'] ) ) {
232 $text = trim( $choice['text']['value'] );
233 $this->results[] = $text;
234 $this->result = $text;
235 }
236 else {
237 $text = trim( $choice['text'] );
238 $this->results[] = $text;
239 $this->result = $text;
240 }
241 }
242
243 // It's url/image
244 else if ( isset( $choice['url'] ) ) {
245 // TODO: DALL-E 2 and 3 were using URLs, but now they are using b64_json (gpt-image-1 kind of enforced it)
246 $url = trim( $choice['url'] );
247 $this->results[] = $url;
248 $this->result = $url;
249 }
250
251 else if ( isset( $choice['b64_json'] ) ) {
252 // In that case we need to create a temporary file in WordPress to store the image, and return the URL for it.
253 global $mwai_core;
254 $url = $mwai_core->files->save_temp_image_from_b64( $choice['b64_json'] );
255 if ( is_wp_error( $url ) ) {
256 return $url;
257 }
258 $this->results[] = $url;
259 $this->result = $url;
260 }
261
262 // It's embedding
263 else if ( isset( $choice['embedding'] ) ) {
264 $content = $choice['embedding'];
265 $this->results[] = $content;
266 $this->result = $content;
267 }
268 }
269 }
270 else {
271 $this->result = $choices;
272 $this->results[] = $choices;
273 }
274 }
275
276 public function toJson() {
277 return json_encode( $this );
278 }
279 }