PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 3.6.4
AI Engine – The Chatbot, AI Framework & MCP for WordPress v3.6.4
3.6.4 3.6.5 3.6.3 3.6.2 3.6.1 3.6.0 3.5.9 3.5.8 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
data 1 year ago engines 1 day ago exceptions 2 days ago modules 1 day ago query 2 days ago services 1 day ago admin.php 1 day ago api.php 3 weeks ago core.php 2 days ago discussion.php 1 year ago event.php 1 year ago init.php 2 days ago logging.php 1 year ago reply.php 2 days ago rest.php 1 day ago
reply.php
454 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 'accuracy' => 'none', // 'none', 'estimated', 'tokens', 'price', 'full'
13 ];
14 public $query = null;
15 public $type = 'text';
16 public $model = null; // Actual model used by the API (may differ from query model)
17
18 // Code interpreter code (separate from main content)
19 public $contentCode = '';
20
21 // Engine-specific extras kept on the reply during a single request (e.g. Google
22 // stores generated images, thoughts and grounding metadata here). Declared so PHP
23 // 8.2+ does not warn about dynamic property creation.
24 public $extraData = [];
25
26 // This is when models return a message that needs to be executed (functions, tools, etc)
27 public $needFeedbacks = [];
28 public $needClientActions = [];
29
30 // Tool/function calls actually executed during this turn, oldest first. Accumulated
31 // across the recursive feedback rounds (see Meow_MWAI_Engines_Core::run) so the final
32 // reply carries the whole chain, then stored in the discussion for the admin UI.
33 // Not exposed in jsonSerialize on purpose: arguments and results stay server-side.
34 public $toolCalls = [];
35
36 // What is KEPT for the discussion, not what is sent to the model: the request itself is
37 // untouched. These are copies written into mwai_chats.messages for the admin UI, so an
38 // MCP tool returning hundreds of KB, or a wp_write_blocks call carrying a whole article,
39 // would otherwise be duplicated into the discussion row and stay there forever.
40 public const TOOL_CALL_RESULT_LIMIT = 500;
41 // Long argument values are cut individually rather than by chopping the encoded blob:
42 // the panel shows the parameter names and pretty-prints the JSON, so the structure has
43 // to survive. Keys and scalars stay intact; only long strings shrink.
44 public const TOOL_CALL_ARG_VALUE_LIMIT = 200;
45 // Backstop for arguments made of many small values rather than one big one.
46 public const TOOL_CALL_ARGS_TOTAL_LIMIT = 4000;
47
48 public function __construct( $query = null ) {
49 $this->query = $query;
50 }
51
52 // Cut a string on a character boundary, so a truncated UTF-8 value never ends in a
53 // broken sequence that would make the stored JSON unreadable.
54 private static function truncate_text( $text, $limit ) {
55 if ( function_exists( 'mb_substr' ) ) {
56 if ( mb_strlen( $text, 'UTF-8' ) <= $limit ) {
57 return $text;
58 }
59 return mb_substr( $text, 0, $limit, 'UTF-8' );
60 }
61 if ( strlen( $text ) <= $limit ) {
62 return $text;
63 }
64 return substr( $text, 0, $limit );
65 }
66
67 private static function shrink_tool_arguments( $value, $depth = 0 ) {
68 if ( $depth > 6 ) {
69 return '[…]';
70 }
71 if ( is_array( $value ) ) {
72 $out = [];
73 foreach ( $value as $key => $item ) {
74 $out[$key] = self::shrink_tool_arguments( $item, $depth + 1 );
75 }
76 return $out;
77 }
78 if ( is_string( $value ) && strlen( $value ) > self::TOOL_CALL_ARG_VALUE_LIMIT ) {
79 // Say how much was dropped, so the panel never looks like the AI sent a short value.
80 return self::truncate_text( $value, self::TOOL_CALL_ARG_VALUE_LIMIT )
81 . '… [truncated, ' . size_format( strlen( $value ) ) . ']';
82 }
83 return $value;
84 }
85
86 public function add_tool_call( $name, $arguments = null, $result = null, $success = true ) {
87 $preview = is_string( $result ) ? $result : json_encode( $result );
88 if ( !is_string( $preview ) ) {
89 $preview = '';
90 }
91 if ( strlen( $preview ) > self::TOOL_CALL_RESULT_LIMIT ) {
92 $preview = self::truncate_text( $preview, self::TOOL_CALL_RESULT_LIMIT ) . '...';
93 }
94 $arguments = is_array( $arguments ) ? self::shrink_tool_arguments( $arguments ) : [];
95 // Many small values can still add up; fall back to the parameter names alone. Only
96 // the first few, because a call with hundreds of keys would otherwise produce a
97 // "summary" larger than the payload it replaces.
98 $encoded = json_encode( $arguments );
99 if ( is_string( $encoded ) && strlen( $encoded ) > self::TOOL_CALL_ARGS_TOTAL_LIMIT ) {
100 $keys = array_keys( $arguments );
101 $shown = array_slice( $keys, 0, 20 );
102 $summary = implode( ', ', $shown );
103 if ( count( $keys ) > count( $shown ) ) {
104 $summary .= ', and ' . ( count( $keys ) - count( $shown ) ) . ' more';
105 }
106 $arguments = [ '_truncated' => 'Arguments too large to store. Parameters: ' . $summary ];
107 }
108 $this->toolCalls[] = [
109 'name' => (string) $name,
110 'arguments' => $arguments,
111 'result' => $preview,
112 'success' => (bool) $success,
113 ];
114 }
115
116 #[\ReturnTypeWillChange]
117 public function jsonSerialize() {
118 $isEmbedding = false;
119 $embeddingsDimensions = null;
120 $embedddingsMessage = null;
121 if ( is_array( $this->results ) && count( $this->results ) > 0 ) {
122 $isEmbedding = is_array( $this->results[0] );
123 if ( $isEmbedding ) {
124 $embeddingsDimensions = count( $this->results[0] );
125 $embedddingsMessage = "A $embeddingsDimensions-dimensional embedding was returned.";
126 }
127 }
128 $data = [
129 'result' => $isEmbedding ? $embedddingsMessage : $this->result,
130 'results' => $isEmbedding ? [] : $this->results,
131 'usage' => $this->usage,
132 'system' => [
133 'class' => get_class( $this ),
134 ]
135 ];
136 if ( !empty( $this->needFeedbacks ) ) {
137 $data['needFeedbacks'] = $this->needFeedbacks;
138 }
139 if ( !empty( $this->needClientActions ) ) {
140 $data['needClientActions'] = $this->needClientActions;
141 }
142 if ( !empty( $this->contentCode ) ) {
143 $data['contentCode'] = $this->contentCode;
144 }
145 return $data;
146 }
147
148 public function set_usage( $usage ) {
149 $this->usage = $usage;
150 }
151
152 public function set_usage_accuracy( $accuracy ) {
153 $this->usage['accuracy'] = $accuracy;
154 }
155
156 public function set_id( $id ) {
157 $this->id = $id;
158 }
159
160 public function set_type( $type ) {
161 $this->type = $type;
162 }
163
164 public function set_model( $model ) {
165 $this->model = $model;
166 }
167
168 public function get_total_tokens() {
169 return isset( $this->usage['total_tokens'] ) ? $this->usage['total_tokens'] : 0;
170 }
171
172 public function get_in_tokens( $query = null ) {
173 $in_tokens = isset( $this->usage['prompt_tokens'] ) ? $this->usage['prompt_tokens'] : 0;
174 if ( empty( $in_tokens ) && $query ) {
175 $in_tokens = $query->get_in_tokens();
176 }
177 return $in_tokens;
178 }
179
180 public function get_out_tokens() {
181 $out_tokens = isset( $this->usage['completion_tokens'] ) ? $this->usage['completion_tokens'] : 0;
182 if ( empty( $out_tokens ) ) {
183 // NOTE: Only estimate when result is actually text. Embedding replies hold a
184 // float vector, image replies hold URLs/arrays, etc. — running estimate_tokens()
185 // on those JSON-encodes the structure and produces huge bogus counts (a 3072-d
186 // Gemini embedding estimated as ~13k tokens for a 50-char input). Anything that
187 // isn't a string has no meaningful "output token" count, so return 0.
188 if ( !is_string( $this->result ) ) {
189 return 0;
190 }
191 $out_tokens = Meow_MWAI_Core::estimate_tokens( $this->result );
192 }
193 return $out_tokens;
194 }
195
196 public function get_price() {
197 // If it's not set return null, but it can be 0
198 if ( !isset( $this->usage['price'] ) ) {
199 return null;
200 }
201 return $this->usage['price'];
202 }
203
204 public function get_usage_accuracy() {
205 return $this->usage['accuracy'] ?? 'none';
206 }
207
208 /**
209 * Returns the metric count for this reply, preferring tokens. Falls back to
210 * images or seconds for non-token-billed providers (legacy Imagen/Replicate
211 * per-image, Whisper, Sora). Equivalent to (and aliased by) get_units().
212 */
213 public function get_tokens() {
214 if ( isset( $this->usage['total_tokens'] ) ) {
215 return $this->usage['total_tokens'];
216 }
217 else if ( isset( $this->usage['images'] ) ) {
218 return $this->usage['images'];
219 }
220 else if ( isset( $this->usage['seconds'] ) ) {
221 return $this->usage['seconds'];
222 }
223 return null;
224 }
225
226 /**
227 * Legacy alias for get_tokens(). Kept indefinitely — third-party code
228 * reachable via the mwai_ai_reply filter may call it.
229 */
230 public function get_units() {
231 return $this->get_tokens();
232 }
233
234 public function get_type() {
235 return $this->type;
236 }
237
238 public function set_reply( $reply ) {
239 $this->result = $reply;
240 $this->results[] = [ $reply ];
241 }
242
243 public function replace( $search, $replace ) {
244 $this->result = str_replace( $search, $replace, $this->result );
245 $this->results = array_map( function ( $result ) use ( $search, $replace ) {
246 return str_replace( $search, $replace, $result );
247 }, $this->results );
248 }
249
250 private function extract_arguments( $funcArgs ) {
251 $finalArgs = [];
252 if ( is_string( $funcArgs ) ) {
253 $arguments = trim( str_replace( "\n", '', $funcArgs ) );
254 if ( substr( $arguments, 0, 1 ) == '{' ) {
255 $arguments = json_decode( $arguments, true );
256 $finalArgs = $arguments;
257 }
258 }
259 else if ( is_array( $funcArgs ) ) {
260 $finalArgs = $funcArgs;
261 }
262 return $finalArgs;
263 }
264
265 /**
266 * Set the choices from OpenAI as the results.
267 * The last (or only) result is set as the result.
268 * @param array $choices ID of the model to use.
269 */
270 public function set_choices( $choices, $rawMessage = null ) {
271 $this->results = [];
272
273 // Initialize feedback arrays at the start to accumulate across all choices
274 // This is important for engines like Google that split multiple function calls
275 // into separate choices
276 $this->needFeedbacks = [];
277 $this->needClientActions = [];
278
279 if ( is_array( $choices ) ) {
280 foreach ( $choices as $choice ) {
281
282 // It's chat completion
283 if ( isset( $choice['message'] ) ) {
284
285 // It's text content
286 if ( isset( $choice['message']['content'] ) ) {
287 $content = trim( $choice['message']['content'] );
288 $this->results[] = $content;
289 $this->result = $content;
290 }
291
292 // It's a tool call (OpenAI-style and Anthropic-style)
293 $toolCalls = [];
294 if ( isset( $choice['message']['tool_calls'] ) ) {
295 $tools = $choice['message']['tool_calls'];
296 foreach ( $tools as $tool ) {
297 if ( $tool['type'] === 'function' ) {
298 $toolCall = [
299 'toolId' => $tool['id'],
300 //'mode' => 'interactive',
301 'type' => 'tool_call',
302 'name' => trim( $tool['function']['name'] ),
303 'arguments' => $this->extract_arguments( $tool['function']['arguments'] ),
304 // Represent the original message that triggered the function call
305 'rawMessage' => $rawMessage ? $rawMessage : ( isset( $choice['_rawMessage'] ) ? $choice['_rawMessage'] : $choice['message'] ),
306 ];
307 $toolCalls[] = $toolCall;
308 }
309 }
310 }
311
312 // If it's a function call (Open-AI style; usually for a final execution)
313 if ( isset( $choice['message']['function_call'] ) ) {
314 $content = $choice['message']['function_call'];
315 $name = trim( $content['name'] );
316 $args = $content['arguments'] ?? $content['args'] ?? null;
317 $toolCalls[] = [
318 'toolId' => null,
319 'mode' => 'static',
320 'type' => 'function_call',
321 'name' => $name,
322 'arguments' => $this->extract_arguments( $args ),
323 'rawMessage' => $rawMessage ? $rawMessage : ( isset( $choice['_rawMessage'] ) ? $choice['_rawMessage'] : $choice['message'] ),
324 ];
325 }
326
327 // Deep copy tool calls BEFORE adding function references
328 // This prevents the "Duplicate value for 'tool_call_id'" error
329 // when the same function is called multiple times
330 // Note: We need to preserve the toolId for each tool call
331 if ( !empty( $toolCalls ) ) {
332 $toolCalls = json_decode( json_encode( $toolCalls ), true );
333 }
334
335 // Resolve the original function from the query
336 if ( !empty( $toolCalls ) ) {
337 foreach ( $toolCalls as &$toolCall ) {
338 if ( $toolCall['type'] !== 'function_call' && $toolCall['type'] !== 'tool_call' ) {
339 continue;
340 }
341 foreach ( $this->query->functions as $function ) {
342 if ( $function->name == $toolCall['name'] ) {
343 $toolCall['function'] = $function;
344 break;
345 }
346 }
347 }
348 // IMPORTANT: Unset the reference to avoid PHP's foreach reference bug
349 unset( $toolCall );
350 }
351
352 // Add tool calls to existing arrays instead of resetting them
353 // This is crucial for engines like Google that create multiple choices
354 // for multiple function calls in a single response
355 foreach ( $toolCalls as $tcIdx => $toolCall ) {
356 if ( $toolCall['function']->target !== 'js' ) {
357 $this->needFeedbacks[] = $toolCall;
358 }
359 else if ( $toolCall['function']->target === 'js' ) {
360 $this->needClientActions[] = $toolCall;
361 }
362 }
363 }
364
365 // It's text completion
366 else if ( isset( $choice['text'] ) ) {
367
368 // TODO: Assistants return an array (so actually not really a text completion)
369 // We should probably make this clearer and analyze all the outputs from different endpoints.
370 if ( is_array( $choice['text'] ) ) {
371 $text = trim( $choice['text']['value'] );
372 $this->results[] = $text;
373 $this->result = $text;
374 }
375 else {
376 $text = trim( $choice['text'] );
377 $this->results[] = $text;
378 $this->result = $text;
379 }
380 }
381
382 // It's url/image
383 else if ( isset( $choice['url'] ) ) {
384 $url = trim( $choice['url'] );
385 $this->results[] = $url;
386 $this->result = $url;
387 }
388 else if ( isset( $choice['b64_json'] ) ) {
389 // In that case we need to create a temporary file in WordPress to store the image, and return the URL for it.
390 global $mwai_core;
391
392 // Check if the query has explicitly disabled local download
393 if ( !empty( $this->query ) && $this->query instanceof Meow_MWAI_Query_Image && $this->query->localDownload === null ) {
394 // Query explicitly doesn't want local download, save as temporary upload
395 $localDownload = 'uploads';
396 $expiry = 1 * HOUR_IN_SECONDS; // 1 hour for temporary images
397 }
398 else {
399 // Use the user's AI-generated image settings. The Expiration
400 // setting displays "Never" as its default, so an unset option must
401 // mean never; letting it fall through to the uploaded-files TTL
402 // (1 hour) silently rotted images out of stored conversations.
403 $localDownload = $mwai_core->get_option( 'image_local_download' );
404 $expiryOption = $mwai_core->get_option( 'image_expires_download' );
405 $expiry = ( empty( $expiryOption ) || strtolower( (string) $expiryOption ) === 'never' )
406 ? 'never' : (int) $expiryOption;
407 }
408
409 // The expiry is in seconds, or 'never'.
410 $ttl = $expiry;
411
412 // Use 'library' or 'uploads' based on user settings
413 $target = ( $localDownload === 'library' ) ? 'library' : 'uploads';
414
415 // Prepare metadata similar to regular image queries
416 $metadata = [];
417 if ( !empty( $this->query ) ) {
418 $metadata['query_envId'] = $this->query->envId ?? null;
419 $metadata['query_session'] = $this->query->session ?? null;
420 $metadata['query_model'] = $this->query->model ?? 'gpt-image-1';
421 }
422
423 $url = $mwai_core->files->save_temp_image_from_b64( $choice['b64_json'], 'generated', $ttl, $target, $metadata );
424 if ( is_wp_error( $url ) ) {
425 return $url;
426 }
427 $this->results[] = $url;
428
429 // For chatbot display, append image markdown to the result
430 if ( !empty( $this->result ) ) {
431 $this->result .= "\n\n";
432 }
433 $this->result .= "![Generated Image]($url)";
434 }
435
436 // It's embedding
437 else if ( isset( $choice['embedding'] ) ) {
438 $content = $choice['embedding'];
439 $this->results[] = $content;
440 $this->result = $content;
441 }
442 }
443 }
444 else {
445 $this->result = $choices;
446 $this->results[] = $choices;
447 }
448 }
449
450 public function toJson() {
451 return json_encode( $this );
452 }
453 }
454