PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.2.63
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.2.63
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 / engines / anthropic.php
ai-engine / classes / engines Last commit date
anthropic.php 2 years ago core.php 2 years ago factory.php 2 years ago google.php 2 years ago huggingface.php 2 years ago openai.php 2 years ago openrouter.php 2 years ago
anthropic.php
280 lines
1 <?php
2
3 class Meow_MWAI_Engines_Anthropic extends Meow_MWAI_Engines_OpenAI
4 {
5
6 // Streaming
7 protected $streamInTokens = null;
8 protected $streamOutTokens = null;
9
10 public function __construct( $core, $env )
11 {
12 parent::__construct( $core, $env );
13 }
14
15 protected function set_environment() {
16 $env = $this->env;
17 $this->apiKey = $env['apikey'];
18 }
19
20 protected function build_url( $query, $endpoint = null ) {
21 $endpoint = apply_filters( 'mwai_anthropic_endpoint', 'https://api.anthropic.com/v1', $this->env );
22 if ( $query instanceof Meow_MWAI_Query_Text ) {
23 $url = trailingslashit( $endpoint ) . 'messages';
24 }
25 else {
26 throw new Exception( 'AI Engine: Unsupported query type.' );
27 }
28 return $url;
29 }
30
31 protected function build_headers( $query ) {
32 parent::build_headers( $query );
33 $headers = array(
34 'Content-Type' => 'application/json',
35 'x-api-key' => $this->apiKey,
36 'anthropic-version' => '2023-06-01',
37 'User-Agent' => 'AI Engine',
38 );
39 return $headers;
40 }
41
42 public function final_checks( Meow_MWAI_Query_Base $query ) {
43 // We skip this completely.
44 // maxMessages is handed in build_messages().
45 }
46
47 protected function build_messages( $query ) {
48 $messages = [];
49
50 // Then, if any, we need to add the 'messages', they are already formatted.
51 foreach ( $query->messages as $message ) {
52 $messages[] = $message;
53 }
54
55 // Handle the maxMessages
56 if ( !empty( $query->maxMessages ) ) {
57 $messages = array_slice( $messages, -$query->maxMessages );
58 }
59
60 // If the first message is not a 'user' role, we remove it.
61 if ( !empty( $messages ) && $messages[0]['role'] !== 'user' ) {
62 array_shift( $messages );
63 }
64
65 // Finally, we need to add the message
66 // If there is a file (image), we need to sent the data (not the URL, as it's not supported by Anthropic yet).
67 $fileUrl = $query->get_file_url();
68
69 if ( !empty( $fileUrl ) ) {
70 // Currently, Claude supports the base64 source type for images, and the image/jpeg, image/png, image/gif, and image/webp media types: https://docs.anthropic.com/claude/reference/messages-examples#vision.
71 $mime = $query->get_file_mime_type();
72 $messages[] = [
73 'role' => 'user',
74 'content' => [
75 [
76 "type" => "text",
77 "text" => $query->get_message()
78 ],
79 [
80 "type" => "image",
81 "source" => [
82 "type" => "base64",
83 "media_type" => $mime,
84 "data" => $query->get_file_data()
85 ]
86 ]
87 ]
88 ];
89 }
90 else {
91 $messages[] = [ 'role' => 'user', 'content' => $query->get_message() ];
92 }
93
94 return $messages;
95 }
96
97 protected function build_body( $query, $streamCallback = null, $extra = null ) {
98 if ( $query instanceof Meow_MWAI_Query_Text ) {
99 $body = array(
100 "model" => $query->model,
101 "max_tokens" => $query->maxTokens,
102 "temperature" => $query->temperature,
103 "stream" => !is_null( $streamCallback ),
104 );
105
106 if ( !empty( $query->stop ) ) {
107 $body['stop'] = $query->stop;
108 }
109
110 // First, we need to add the first message (the instructions).
111 if ( !empty( $query->instructions ) ) {
112 $body['system'] = $query->instructions;
113 }
114
115 // If there is a context, we need to add it.
116 if ( !empty( $query->context ) ) {
117 if ( empty( $body['system'] ) ) {
118 $body['system'] = "";
119 }
120 $body['system'] = empty( $body['system'] ) ? '' : $body['system'] . "\n\n";
121 $body['system'] = $body['system'] . "Context:\n\n" . $query->context;
122 }
123
124 $body['messages'] = $this->build_messages( $query );
125 return $body;
126 }
127 else {
128 throw new Exception( 'AI Engine: Unsupported query type.' );
129 }
130 }
131
132 protected function stream_data_handler( $json ) {
133 $content = null;
134
135 // Get the data
136 if ( isset( $json['type'] ) && $json['type'] === 'message_start' ) {
137 $usage = $json['message']['usage'];
138 $this->streamInTokens = $usage['input_tokens'];
139 $this->inModel = $json['message']['model'];
140 $this->inId = $json['message']['id'];
141 }
142 else if ( isset( $json['type'] ) && ( $json['type'] === 'delta' || $json['type'] === 'content_block_delta' ) ) {
143 $content = $json['delta']['text'];
144 }
145 else if ( isset( $json['type'] ) && $json['type'] === 'message_delta' ) {
146 $usage = $json['usage'];
147 $this->streamOutTokens = $usage['output_tokens'];
148 }
149 else if ( isset( $json['type'] ) && $json['type'] === 'error' ) {
150 $error = $json['error'];
151 $message = $error['message'];
152 throw new Exception( $message );
153 }
154
155 // Avoid some endings
156 $endings = [ "<|im_end|>", "</s>" ];
157 if ( in_array( $content, $endings ) ) {
158 $content = null;
159 }
160
161 return ( $content === '0' || !empty( $content ) ) ? $content : null;
162 }
163
164 public function run_completion_query( $query, $streamCallback = null ) : Meow_MWAI_Reply {
165 if ( !is_null( $streamCallback ) ) {
166 $this->streamCallback = $streamCallback;
167 add_action( 'http_api_curl', [ $this, 'stream_handler' ], 10, 3 );
168 }
169
170 $body = $this->build_body( $query, $streamCallback );
171 $url = $this->build_url( $query );
172 $headers = $this->build_headers( $query );
173 $options = $this->build_options( $headers, $body );
174
175 try {
176 $res = $this->run_query( $url, $options, $streamCallback );
177 $reply = new Meow_MWAI_Reply( $query );
178
179 $returned_id = null;
180 $returned_model = $this->inModel;
181 $returned_choices = [];
182
183 if ( !is_null( $streamCallback ) ) {
184 // Streamed data
185 if ( empty( $this->streamContent ) ) {
186 $json = json_decode( $this->streamBuffer, true );
187 if ( isset( $json['error']['message'] ) ) {
188 throw new Exception( $json['error']['message'] );
189 }
190 }
191 $returned_id = $this->inId;
192 $returned_model = $this->inModel ? $this->inModel : $query->model;
193 $returned_in_tokens = !is_null( $this->streamInTokens ) ? $this->streamInTokens : null;
194 $returned_out_tokens = !is_null( $this->streamOutTokens ) ? $this->streamOutTokens : null;
195 $returned_choices = [
196 [
197 'message' => [
198 'content' => $this->streamContent,
199 //'function_call' => $this->streamFunctionCall
200 ]
201 ]
202 ];
203 }
204 else {
205 // Regular data
206 $data = $res['data'];
207 if ( empty( $data ) ) {
208 throw new Exception( 'No content received (res is null).' );
209 }
210 if ( !$data['model'] ) {
211 error_log( print_r( $data, 1 ) );
212 throw new Exception( 'Invalid response (no model information).' );
213 }
214 $returned_id = $data['id'];
215 $returned_model = $data['model'];
216 $returned_in_tokens = isset( $data['usage']['input_tokens'] ) ? $data['usage']['input_tokens'] : null;
217 $returned_out_tokens = isset( $data['usage']['output_tokens'] ) ? $data['usage']['output_tokens'] : null;
218 // There is only one choice with
219 $returned_choices = [ [
220 'message' => [
221 'content' => $data['content'][0]['text'],
222 //'function_call' => $data['choices'][0]['delta']['function_call']
223 ]
224 ] ];
225 }
226
227 $reply->set_choices( $returned_choices );
228 if ( !empty( $returned_id ) ) {
229 $reply->set_id( $returned_id );
230 }
231
232 // Handle tokens.
233 $this->handle_tokens_usage( $reply, $query, $returned_model, $returned_in_tokens, $returned_out_tokens );
234
235 return $reply;
236 }
237 catch ( Exception $e ) {
238 $error = $e->getMessage();
239 $json = json_decode( $error, true );
240 if ( json_last_error() === JSON_ERROR_NONE ) {
241 if ( isset( $json['error'] ) && isset( $json['error']['message'] ) ) {
242 $error = $json['error']['message'];
243 }
244 }
245 error_log( $error );
246 $service = $this->get_service_name();
247 $message = "From $service: " . $error;
248 throw new Exception( $message );
249 }
250 }
251
252 protected function get_service_name() {
253 return "Anthropic";
254 }
255
256 public function get_models() {
257 return apply_filters( 'mwai_anthropic_models', MWAI_ANTHROPIC_MODELS );
258 }
259
260 static public function get_models_static() {
261 return MWAI_ANTHROPIC_MODELS;
262 }
263
264 public function handle_tokens_usage( $reply, $query, $returned_model,
265 $returned_in_tokens, $returned_out_tokens, $returned_price = null ) {
266 $returned_in_tokens = !is_null( $returned_in_tokens ) ?
267 $returned_in_tokens : $reply->get_in_tokens( $query );
268 $returned_out_tokens = !is_null( $returned_out_tokens ) ?
269 $returned_out_tokens : $reply->get_out_tokens();
270 if ( !empty( $reply->id ) ) {
271 // Would be cool to retrieve the usage from the API, but it's not possible.
272 }
273 $usage = $this->core->record_tokens_usage( $returned_model, $returned_in_tokens, $returned_out_tokens );
274 $reply->set_usage( $usage );
275 }
276
277 public function get_price( Meow_MWAI_Query_Base $query, Meow_MWAI_Reply $reply ) {
278 return parent::get_price( $query, $reply );
279 }
280 }