PluginProbe ʕ •ᴥ•ʔ
AI Engine – The Chatbot, AI Framework & MCP for WordPress / 3.2.3
AI Engine – The Chatbot, AI Framework & MCP for WordPress v3.2.3
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 / perplexity.php
ai-engine / classes / engines Last commit date
anthropic.php 8 months ago chatml.php 7 months ago core.php 8 months ago factory.php 8 months ago google.php 7 months ago mistral.php 9 months ago open-router.php 7 months ago openai.php 7 months ago perplexity.php 10 months ago replicate.php 7 months ago
perplexity.php
199 lines
1 <?php
2
3 class Meow_MWAI_Engines_Perplexity extends Meow_MWAI_Engines_ChatML {
4 // Streaming
5 protected $streamInTokens = null;
6 protected $streamOutTokens = null;
7 protected $streamContent = null;
8 protected $streamBuffer = null;
9 protected $inCitations = null;
10
11 public function __construct( $core, $env ) {
12 parent::__construct( $core, $env );
13 }
14
15 protected function set_environment() {
16 $env = $this->env;
17 $this->apiKey = $env['apikey'] ?? null;
18 }
19
20 protected function get_service_name() {
21 return 'Perplexity';
22 }
23
24 public function get_models() {
25 return apply_filters( 'mwai_perplexity_models', MWAI_PERPLEXITY_MODELS );
26 }
27
28 public static function get_models_static() {
29 return MWAI_PERPLEXITY_MODELS;
30 }
31
32 protected function build_url( $query, $endpoint = null ) {
33 $endpoint = apply_filters( 'mwai_perplexity_endpoint', 'https://api.perplexity.ai', $this->env );
34 return rtrim( $endpoint, '/' ) . '/chat/completions';
35 }
36
37 protected function build_messages( $query ) {
38 $messages = parent::build_messages( $query );
39 $filtered = [];
40 $haveSeenUser = false;
41 foreach ( $messages as $message ) {
42 if ( !$haveSeenUser ) {
43 if ( $message['role'] === 'assistant' ) {
44 continue;
45 }
46 if ( $message['role'] === 'user' ) {
47 $haveSeenUser = true;
48 }
49 $filtered[] = $message;
50 }
51 else {
52 $filtered[] = $message;
53 }
54 }
55
56 return $filtered;
57 }
58
59 protected function build_headers( $query ) {
60 if ( $query->apiKey ) {
61 $this->apiKey = $query->apiKey;
62 }
63 if ( empty( $this->apiKey ) ) {
64 throw new Exception( 'No Perplexity API Key provided. Check your settings.' );
65 }
66 return [
67 'Content-Type' => 'application/json',
68 'Authorization' => 'Bearer ' . $this->apiKey,
69 'User-Agent' => 'AI Engine',
70 ];
71 }
72
73 protected function build_body( $query, $streamCallback = null, $extra = null ) {
74 $body = parent::build_body( $query, $streamCallback, $extra );
75 return $body;
76 }
77
78 public function reset_stream() {
79 $this->inCitations = null;
80 return parent::reset_stream();
81 }
82
83 // Let's override the stream handler only to capture the citations
84 protected function stream_data_handler( $json ) {
85 if ( isset( $json['citations'] ) ) {
86 $this->inCitations = $json['citations'];
87 }
88 return parent::stream_data_handler( $json );
89 }
90
91 /**
92 * In Perplexity, we intercept the final choices and insert citations
93 * as ([domain1](https://...), [domain2](https://...))
94 * based on [1][2][3] references in the text.
95 */
96 protected function finalize_choices( $choices, $responseData, $query ) {
97 $citations = isset( $responseData['citations'] ) ? $responseData['citations'] : null;
98 if ( empty( $citations ) && !empty( $this->inCitations ) ) {
99 $citations = $this->inCitations;
100 }
101 if ( empty( $citations ) ) {
102 return parent::finalize_choices( $choices, $responseData, $query );
103 }
104
105 foreach ( $choices as &$choice ) {
106 if ( isset( $choice['message']['content'] ) && is_string( $choice['message']['content'] ) ) {
107 $content = $choice['message']['content'];
108 $content = preg_replace_callback( '/\[(\d+)\](?:\s*\[(\d+)\])*/', function ( $matches ) use ( $citations ) {
109 preg_match_all( '/\[(\d+)\]/', $matches[0], $refs );
110 $links = [];
111 foreach ( $refs[1] as $refNumber ) {
112 $index = (int) $refNumber - 1;
113 if ( isset( $citations[$index] ) ) {
114 $url = $citations[$index];
115 $domain = parse_url( $url, PHP_URL_HOST );
116 if ( !empty( $domain ) ) {
117 $domain = str_replace( 'www.', '', $domain );
118 }
119 $links[] = '[' . $domain . '](' . $url . ')';
120 }
121 }
122 // If we gathered at least one link, return them all in a parenthetical group
123 // e.g. " ([google.com](https://google.com), [othersite.io](https://othersite.io))"
124 // Otherwise, just return the original matches (fallback).
125 return !empty( $links ) ? ' (' . implode( ', ', $links ) . ')' : $matches[0];
126 }, $content );
127 $choice['message']['content'] = $content;
128 }
129 }
130
131 return $choices;
132 }
133
134 /**
135 * Connection check for Perplexity API
136 * Tests the API key by listing async chat completions
137 */
138 public function connection_check() {
139 try {
140 // Build the URL for async completions list endpoint
141 $endpoint = apply_filters( 'mwai_perplexity_endpoint', 'https://api.perplexity.ai', $this->env );
142 $url = rtrim( $endpoint, '/' ) . '/async/chat/completions?limit=1';
143
144 // Build headers with API key
145 if ( empty( $this->apiKey ) ) {
146 throw new Exception( 'No Perplexity API Key provided. Check your settings.' );
147 }
148
149 $headers = [
150 'Authorization' => 'Bearer ' . $this->apiKey,
151 'User-Agent' => 'AI Engine',
152 ];
153
154 $options = [
155 'headers' => $headers,
156 'method' => 'GET',
157 'timeout' => 10,
158 'sslverify' => false
159 ];
160
161 // Make the request
162 $response = wp_remote_get( $url, $options );
163
164 if ( is_wp_error( $response ) ) {
165 throw new Exception( $response->get_error_message() );
166 }
167
168 $body = wp_remote_retrieve_body( $response );
169 $data = json_decode( $body, true );
170
171 // Check if response has expected structure
172 if ( !is_array( $data ) || !array_key_exists( 'requests', $data ) ) {
173 throw new Exception( 'Invalid response from Perplexity API' );
174 }
175
176 // Get available models from our constants
177 $models = $this->get_models();
178 $modelNames = array_map( function( $model ) {
179 return $model['model'] ?? $model['name'] ?? 'unknown';
180 }, array_slice( $models, 0, 5 ) );
181
182 return [
183 'success' => true,
184 'service' => 'Perplexity',
185 'message' => 'Connection successful',
186 'details' => [
187 'endpoint' => $endpoint,
188 'model_count' => count( $models ),
189 'sample_models' => $modelNames
190 ]
191 ];
192 }
193 catch ( Exception $e ) {
194 throw new Exception( 'Perplexity connection failed: ' . $e->getMessage() );
195 }
196 }
197
198 }
199