PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.1.3
Jetpack – WP Security, Backup, Speed, & Growth v12.1.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / _inc / lib / class-jetpack-ai-helper.php
jetpack / _inc / lib Last commit date
admin-pages 3 years ago core-api 3 years ago debugger 3 years ago markdown 4 years ago class-jetpack-ai-helper.php 3 years ago class-jetpack-currencies.php 5 years ago class-jetpack-google-drive-helper.php 3 years ago class-jetpack-instagram-gallery-helper.php 3 years ago class-jetpack-mapbox-helper.php 3 years ago class-jetpack-podcast-feed-locator.php 5 years ago class-jetpack-podcast-helper.php 3 years ago class-jetpack-recommendations.php 4 years ago class-jetpack-tweetstorm-helper.php 3 years ago class-jetpack-wizard.php 5 years ago class.color.php 4 years ago class.core-rest-api-endpoints.php 3 years ago class.jetpack-automatic-install-skin.php 4 years ago class.jetpack-iframe-embed.php 4 years ago class.jetpack-keyring-service-helper.php 4 years ago class.jetpack-password-checker.php 3 years ago class.jetpack-photon-image-sizes.php 3 years ago class.jetpack-photon-image.php 4 years ago class.jetpack-search-performance-logger.php 4 years ago class.media-extractor.php 3 years ago class.media-summary.php 3 years ago class.media.php 3 years ago components.php 3 years ago debugger.php 4 years ago functions.wp-notify.php 4 years ago icalendar-reader.php 3 years ago markdown.php 3 years ago plans.php 4 years ago plugins.php 4 years ago tonesque.php 3 years ago widgets.php 4 years ago
class-jetpack-ai-helper.php
279 lines
1 <?php
2 /**
3 * API helper for the AI blocks.
4 *
5 * @package automattic/jetpack
6 * @since 11.8
7 */
8
9 use Automattic\Jetpack\Connection\Client;
10 use Automattic\Jetpack\Connection\Manager;
11 use Automattic\Jetpack\Status;
12
13 /**
14 * Class Jetpack_AI_Helper
15 *
16 * @since 11.8
17 */
18 class Jetpack_AI_Helper {
19 /**
20 * Allow new completion every X seconds. Will return cached result otherwise.
21 *
22 * @var int
23 */
24 public static $text_completion_cooldown_seconds = 15;
25
26 /**
27 * Cache images for a prompt for a month.
28 *
29 * @var int
30 */
31 public static $image_generation_cache_timeout = MONTH_IN_SECONDS;
32
33 /**
34 * Stores the number of JetpackAI calls in case we want to mark AI-assisted posts some way.
35 *
36 * @var int
37 */
38 public static $post_meta_with_ai_generation_number = '_jetpack_ai_calls';
39
40 /**
41 * Checks if a given request is allowed to get AI data from WordPress.com.
42 *
43 * @param WP_REST_Request $request Full details about the request.
44 *
45 * @return true|WP_Error True if the request has access, WP_Error object otherwise.
46 */
47 public static function get_status_permission_check( $request ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter, VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
48
49 /*
50 * This may need to be updated
51 * to take into account the different ways we can make requests
52 * (from a WordPress.com site, from a Jetpack site).
53 */
54 if ( ! current_user_can( 'edit_posts' ) ) {
55 return new WP_Error(
56 'rest_forbidden',
57 __( 'Sorry, you are not allowed to access Jetpack AI help on this site.', 'jetpack' ),
58 array( 'status' => rest_authorization_required_code() )
59 );
60 }
61
62 return true;
63 }
64
65 /**
66 * Return true if these features should be active on the current site.
67 * Currently, it's limited to WPCOM Simple and Atomic.
68 */
69 public static function is_enabled() {
70 $default = false;
71
72 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
73 $default = true;
74 } elseif ( ( new Automattic\Jetpack\Status\Host() )->is_woa_site() ) {
75 $default = true;
76 }
77
78 /**
79 * Filter whether the AI features are enabled in the Jetpack plugin.
80 *
81 * @since 11.8
82 *
83 * @param bool $default Are AI features enabled? Defaults to false.
84 */
85 return apply_filters( 'jetpack_ai_enabled', $default );
86 }
87
88 /**
89 * Get the name of the transient for image generation. Unique per prompt and allows for reuse of results for the same prompt across entire WPCOM.
90 * I expext "puppy" to always be from cache.
91 *
92 * @param string $prompt - Supplied prompt.
93 */
94 public static function transient_name_for_image_generation( $prompt ) {
95 return 'jetpack_openai_image_' . md5( $prompt );
96 }
97
98 /**
99 * Get the name of the transient for text completion. Unique per user, but not per text. Serves more as a cooldown.
100 */
101 public static function transient_name_for_completion() {
102 return 'jetpack_openai_completion_' . get_current_user_id(); // Cache for each user, so that other users dont get weird cached version from somebody else.
103 }
104
105 /**
106 * Mark the edited post as "touched" by AI stuff.
107 *
108 * @param int $post_id Post ID for which the content is being generated.
109 * @return void
110 */
111 private static function mark_post_as_ai_assisted( $post_id ) {
112 if ( ! $post_id ) {
113 return;
114 }
115 $previous = get_post_meta( $post_id, self::$post_meta_with_ai_generation_number, true );
116 if ( ! $previous ) {
117 $previous = 0;
118 } elseif ( ! is_numeric( $previous ) ) {
119 // Data corrupted, nothing to do.
120 return;
121 }
122 $new_value = intval( $previous ) + 1;
123 update_post_meta( $post_id, self::$post_meta_with_ai_generation_number, $new_value );
124 }
125
126 /**
127 * Get text back from WordPress.com based off a starting text.
128 *
129 * @param string $content The content that's already been typed in the block.
130 * @param int $post_id Post ID for which the content is being generated.
131 * @return mixed
132 */
133 public static function get_gpt_completion( $content, $post_id ) {
134 $content = wp_strip_all_tags( $content );
135 $cache = get_transient( self::transient_name_for_completion() );
136 if ( $cache ) {
137 return $cache;
138 }
139
140 if ( ( new Status() )->is_offline_mode() ) {
141 return new WP_Error(
142 'dev_mode',
143 __( 'Jetpack AI is not available in offline mode.', 'jetpack' )
144 );
145 }
146
147 $site_id = Manager::get_site_id();
148 if ( is_wp_error( $site_id ) ) {
149 return $site_id;
150 }
151
152 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
153 if ( ! class_exists( 'OpenAI' ) ) {
154 \require_lib( 'openai' );
155 }
156
157 // Set the content for chatGPT endpoint
158 $data = array(
159 array(
160 'role' => 'user',
161 'content' => $content,
162 ),
163 );
164
165 $result = ( new OpenAI( 'openai', array( 'post_id' => $post_id ) ) )->request_chat_completion( $data );
166
167 if ( is_wp_error( $result ) ) {
168 return $result;
169 }
170
171 $response = $result->choices[0]->message->content;
172
173 // In case of Jetpack we are setting a transient on the WPCOM and not the remote site. I think the 'get_current_user_id' may default for the connection owner at this point but we'll deal with this later.
174 set_transient( self::transient_name_for_completion(), $response, self::$text_completion_cooldown_seconds );
175 self::mark_post_as_ai_assisted( $post_id );
176 return $response;
177 }
178
179 $response = Client::wpcom_json_api_request_as_user(
180 sprintf( '/sites/%d/jetpack-ai/completions', $site_id ),
181 2,
182 array(
183 'method' => 'post',
184 'headers' => array( 'content-type' => 'application/json' ),
185 ),
186 wp_json_encode(
187 array(
188 'content' => $content,
189 )
190 ),
191 'wpcom'
192 );
193
194 if ( is_wp_error( $response ) ) {
195 return $response;
196 }
197
198 $data = json_decode( wp_remote_retrieve_body( $response ) );
199
200 if ( wp_remote_retrieve_response_code( $response ) >= 400 ) {
201 return new WP_Error( $data->code, $data->message, $data->data );
202 }
203 set_transient( self::transient_name_for_completion(), $data, self::$text_completion_cooldown_seconds );
204 self::mark_post_as_ai_assisted( $post_id );
205
206 return $data;
207 }
208
209 /**
210 * Get an array of image objects back from WordPress.com based off a prompt.
211 *
212 * @param string $prompt The prompt to generate images for.
213 * @param int $post_id Post ID for which the content is being generated.
214 * @return mixed
215 */
216 public static function get_dalle_generation( $prompt, $post_id ) {
217 $cache = get_transient( self::transient_name_for_image_generation( $prompt ) );
218 if ( $cache ) {
219 self::mark_post_as_ai_assisted( $post_id );
220 return $cache;
221 }
222
223 if ( ( new Status() )->is_offline_mode() ) {
224 return new WP_Error(
225 'dev_mode',
226 __( 'Jetpack AI is not available in offline mode.', 'jetpack' )
227 );
228 }
229
230 $site_id = Manager::get_site_id();
231 if ( is_wp_error( $site_id ) ) {
232 return $site_id;
233 }
234
235 if ( defined( 'IS_WPCOM' ) && IS_WPCOM ) {
236 if ( ! class_exists( 'OpenAI' ) ) {
237 \require_lib( 'openai' );
238 }
239
240 $result = ( new OpenAI( 'openai', array( 'post_id' => $post_id ) ) )->request_dalle_generation( $prompt );
241 if ( is_wp_error( $result ) ) {
242 return $result;
243 }
244 set_transient( self::transient_name_for_image_generation( $prompt ), $result, self::$image_generation_cache_timeout );
245 self::mark_post_as_ai_assisted( $post_id );
246 return $result;
247 }
248
249 $response = Client::wpcom_json_api_request_as_user(
250 sprintf( '/sites/%d/jetpack-ai/images/generations', $site_id ),
251 2,
252 array(
253 'method' => 'post',
254 'headers' => array( 'content-type' => 'application/json' ),
255 ),
256 wp_json_encode(
257 array(
258 'prompt' => $prompt,
259 )
260 ),
261 'wpcom'
262 );
263
264 if ( is_wp_error( $response ) ) {
265 return $response;
266 }
267
268 $data = json_decode( wp_remote_retrieve_body( $response ) );
269
270 if ( wp_remote_retrieve_response_code( $response ) >= 400 ) {
271 return new WP_Error( $data->code, $data->message, $data->data );
272 }
273 set_transient( self::transient_name_for_image_generation( $prompt ), $data, self::$image_generation_cache_timeout );
274 self::mark_post_as_ai_assisted( $post_id );
275
276 return $data;
277 }
278 }
279