PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 2.5.0
AI Engine – The Chatbot, AI Framework & MCP for WordPress v2.5.0
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 / openrouter.php
ai-engine / classes / engines Last commit date
anthropic.php 2 years ago core.php 1 year ago factory.php 2 years ago google.php 2 years ago huggingface.php 2 years ago openai.php 1 year ago openrouter.php 2 years ago
openrouter.php
179 lines
1 <?php
2
3 class Meow_MWAI_Engines_OpenRouter extends Meow_MWAI_Engines_OpenAI
4 {
5
6 public function __construct( $core, $env )
7 {
8 parent::__construct( $core, $env );
9 }
10
11 protected function set_environment() {
12 $env = $this->env;
13 $this->apiKey = $env['apikey'];
14 }
15
16 protected function build_url( $query, $endpoint = null ) {
17 $endpoint = apply_filters( 'mwai_openrouter_endpoint', 'https://openrouter.ai/api/v1', $this->env );
18 $url = parent::build_url( $query, $endpoint );
19 return $url;
20 }
21
22 protected function build_headers( $query ) {
23 parent::build_headers( $query );
24 $site_url = apply_filters( 'mwai_openrouter_site_url', get_site_url(), $query );
25 $site_name = apply_filters( 'mwai_openrouter_site_name', get_bloginfo( 'name' ), $query );
26 $headers = array(
27 'Content-Type' => 'application/json',
28 'Authorization' => 'Bearer ' . $this->apiKey,
29 'HTTP-Referer' => $site_url,
30 'X-Title' => $site_name,
31 'User-Agent' => 'AI Engine',
32 );
33 return $headers;
34 }
35
36 private function truncate_float( $number, $precision = 4 ) {
37 $factor = pow( 10, $precision );
38 return floor( $number * $factor ) / $factor;
39 }
40
41 protected function get_service_name() {
42 return "OpenRouter";
43 }
44
45 public function get_models() {
46 return $this->core->get_engine_models( 'openrouter' );
47 }
48
49 public function handle_tokens_usage( $reply, $query, $returned_model,
50 $returned_in_tokens, $returned_out_tokens, $returned_price = null ) {
51
52 // If streaming is not enabled, we probably have all the data we need
53 $everything_is_set = !is_null( $returned_model ) && !is_null( $returned_in_tokens ) && !is_null( $returned_out_tokens );
54
55 // Clean up the data
56 $returned_in_tokens = !is_null( $returned_in_tokens ) ?
57 $returned_in_tokens : $reply->get_in_tokens( $query );
58 $returned_out_tokens = !is_null( $returned_out_tokens ) ?
59 $returned_out_tokens : $reply->get_out_tokens();
60 $returned_price = !is_null( $returned_price ) ?
61 $returned_price : $reply->get_price();
62
63 // If everything is not set, we can make a request to get the usage data
64 if ( !empty( $reply->id ) && !$everything_is_set ) {
65 $url = 'https://openrouter.ai/api/v1/generation?id=' . $reply->id;
66 try {
67 $ch = curl_init();
68 curl_setopt( $ch, CURLOPT_URL, $url );
69 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
70 curl_setopt( $ch, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer ' . $this->apiKey ] );
71 curl_setopt( $ch, CURLOPT_USERAGENT, 'AI Engine' );
72 $res = curl_exec( $ch );
73 curl_close( $ch );
74 $res = json_decode( $res, true );
75 if ( isset( $res['data'] ) ) {
76 $data = $res['data'];
77 $returned_model = $data['model'];
78 $returned_in_tokens = $data['tokens_prompt'];
79 $returned_out_tokens = $data['tokens_completion'];
80 $returned_price = $data['total_cost'];
81 }
82 }
83 catch ( Exception $e ) {
84 $this->core->log( '❌ (OpenRouter) ' . $e->getMessage() );
85 }
86 }
87
88 // Record the usage
89 $usage = $this->core->record_tokens_usage(
90 $returned_model,
91 $returned_in_tokens,
92 $returned_out_tokens,
93 $returned_price
94 );
95
96 // Set the usage in the reply
97 $reply->set_usage( $usage );
98 }
99
100 public function get_price( Meow_MWAI_Query_Base $query, Meow_MWAI_Reply $reply ) {
101 $price = $reply->get_price();
102 if ( is_null( $price ) ) {
103 $price = parent::get_price( $query, $reply );
104 }
105 return $price;
106 }
107
108 public function retrieve_models() {
109 $url = 'https://openrouter.ai/api/v1/models';
110 $response = wp_remote_get( $url );
111 if ( is_wp_error( $response ) ) {
112 throw new Exception( 'AI Engine: ' . $response->get_error_message() );
113 }
114 $body = json_decode( $response['body'], true );
115 $models = array();
116 foreach ( $body['data'] as $model ) {
117 $family = "n/a";
118 $maxCompletionTokens = 4096;
119 $maxContextualTokens = 8096;
120 $priceIn = 0;
121 $priceOut = 0;
122 $family = explode( '/', $model['id'] )[0];
123 if ( isset( $model['top_provider']['max_completion_tokens'] ) ) {
124 $maxCompletionTokens = (int)$model['top_provider']['max_completion_tokens'];
125 }
126 if ( isset( $model['context_length'] ) ) {
127 $maxContextualTokens = (int)$model['context_length'];
128 }
129 if ( isset( $model['pricing']['prompt'] ) && $model['pricing']['prompt'] > 0 ) {
130 $priceIn = floatval( $model['pricing']['prompt'] ) * 1000;
131 $priceIn = $this->truncate_float( $priceIn );
132 }
133 if ( isset( $model['pricing']['completion'] ) && $model['pricing']['completion'] > 0 ) {
134 $priceOut = floatval( $model['pricing']['completion'] ) * 1000;
135 $priceOut = $this->truncate_float( $priceOut );
136 }
137
138 $tags = [ 'core', 'chat' ];
139 // If the name contains (beta), (alpha) or (preview), add 'preview' tag and remove from name
140 if ( preg_match( '/\((beta|alpha|preview)\)/i', $model['name'], $matches ) ) {
141 $tags[] = 'preview';
142 $model['name'] = preg_replace( '/\((beta|alpha|preview)\)/i', '', $model['name'] );
143 }
144
145 // Vision Support
146 // Unfortunately, OpenRouter does not provide a way know if a model is vision or not
147
148 // If the name includes 'Vision', add 'vision' tag
149 if ( preg_match( '/vision/i', $model['name'], $matches ) ) {
150 $tags[] = 'vision';
151 }
152 // If the name includes 'gpt-4o', add 'vision' tag
153 else if ( preg_match( '/gpt-4o/i', $model['name'], $matches ) ) {
154 $tags[] = 'vision';
155 }
156 // If the name includes 'flash', add 'vision' tag
157 else if ( preg_match( '/flash/i', $model['name'], $matches ) ) {
158 $tags[] = 'vision';
159 }
160
161 $models[] = array(
162 'model' => $model['id'],
163 'name' => trim( $model['name'] ),
164 'family' => $family,
165 'mode' => 'chat',
166 'price' => array(
167 'in' => $priceIn,
168 'out' => $priceOut,
169 ),
170 'type' => 'token',
171 'unit' => 1 / 1000,
172 'maxCompletionTokens' => $maxCompletionTokens,
173 'maxContextualTokens' => $maxContextualTokens,
174 'tags' => $tags
175 );
176 }
177 return $models;
178 }
179 }