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