Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Jetpack AI] Store post ids #28487

Merged
merged 6 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 40 additions & 4 deletions projects/plugins/jetpack/_inc/lib/class-jetpack-ai-helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ class Jetpack_AI_Helper {
*/
public static $image_generation_cache_timeout = MONTH_IN_SECONDS;

/**
* Stores the number of JetpackAI calls in case we want to mark AI-assisted posts some way.
*
* @var int
*/
public static $post_meta_with_ai_generation_number = '_jetpack_ai_calls';

/**
* Checks if a given request is allowed to get AI data from WordPress.com.
*
Expand Down Expand Up @@ -95,16 +102,39 @@ public static function transient_name_for_completion() {
return 'jetpack_openai_completion_' . get_current_user_id(); // Cache for each user, so that other users dont get weird cached version from somebody else.
}

/**
* Mark the edited post as "touched" by AI stuff.
*
* @param int $post_id Post ID for which the content is being generated.
* @return void
*/
private static function mark_post_as_ai_assisted( $post_id ) {
if ( ! $post_id ) {
return;
}
$previous = get_post_meta( $post_id, self::$post_meta_with_ai_generation_number, true );
if ( ! $previous ) {
$previous = 0;
} elseif ( ! is_numeric( $previous ) ) {
// Data corrupted, nothing to do.
return;
}
$new_value = intval( $previous ) + 1;
update_post_meta( $post_id, self::$post_meta_with_ai_generation_number, $new_value );
romarioraffington marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Get text back from WordPress.com based off a starting text.
*
* @param string $content The content that's already been typed in the block.
* @param int $post_id Post ID for which the content is being generated.
* @return mixed
*/
public static function get_gpt_completion( $content ) {
public static function get_gpt_completion( $content, $post_id ) {
$content = wp_strip_all_tags( $content );
$cache = get_transient( self::transient_name_for_completion() );
if ( $cache ) {
self::mark_post_as_ai_assisted( $post_id );
artpi marked this conversation as resolved.
Show resolved Hide resolved
return $cache;
}

Expand All @@ -125,12 +155,13 @@ public static function get_gpt_completion( $content ) {
\require_lib( 'openai' );
}

$result = ( new OpenAI( 'openai' ) )->request_gpt_completion( $content );
$result = ( new OpenAI( 'openai', array( 'post_id' => $post_id ) ) )->request_gpt_completion( $content );
if ( is_wp_error( $result ) ) {
return $result;
}
// 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.
set_transient( self::transient_name_for_completion(), $result, self::$text_completion_cooldown_seconds );
self::mark_post_as_ai_assisted( $post_id );
return $result;
}

Expand Down Expand Up @@ -159,6 +190,7 @@ public static function get_gpt_completion( $content ) {
return new WP_Error( $data->code, $data->message, $data->data );
}
set_transient( self::transient_name_for_completion(), $data, self::$text_completion_cooldown_seconds );
self::mark_post_as_ai_assisted( $post_id );

return $data;
}
Expand All @@ -167,11 +199,13 @@ public static function get_gpt_completion( $content ) {
* Get an array of image objects back from WordPress.com based off a prompt.
*
* @param string $prompt The prompt to generate images for.
* @param int $post_id Post ID for which the content is being generated.
* @return mixed
*/
public static function get_dalle_generation( $prompt ) {
public static function get_dalle_generation( $prompt, $post_id ) {
$cache = get_transient( self::transient_name_for_image_generation( $prompt ) );
if ( $cache ) {
self::mark_post_as_ai_assisted( $post_id );
return $cache;
}

Expand All @@ -192,11 +226,12 @@ public static function get_dalle_generation( $prompt ) {
\require_lib( 'openai' );
}

$result = ( new OpenAI( 'openai' ) )->request_dalle_generation( $prompt );
$result = ( new OpenAI( 'openai', array( 'post_id' => $post_id ) ) )->request_dalle_generation( $prompt );
if ( is_wp_error( $result ) ) {
return $result;
}
set_transient( self::transient_name_for_image_generation( $prompt ), $result, self::$image_generation_cache_timeout );
self::mark_post_as_ai_assisted( $post_id );
return $result;
}

Expand Down Expand Up @@ -225,6 +260,7 @@ public static function get_dalle_generation( $prompt ) {
return new WP_Error( $data->code, $data->message, $data->data );
}
set_transient( self::transient_name_for_image_generation( $prompt ), $data, self::$image_generation_cache_timeout );
self::mark_post_as_ai_assisted( $post_id );

return $data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public function register_routes() {
),
'args' => array(
'content' => array( 'required' => true ),
'token' => array( 'required' => false ),
'post_id' => array( 'required' => false ),
),
)
);
Expand All @@ -71,8 +71,8 @@ public function register_routes() {
'permission_callback' => array( 'Jetpack_AI_Helper', 'get_status_permission_check' ),
),
'args' => array(
'prompt' => array( 'required' => true ),
'token' => array( 'required' => false ),
'prompt' => array( 'required' => true ),
'post_id' => array( 'required' => false ),
),
)
);
Expand All @@ -84,7 +84,7 @@ public function register_routes() {
* @param WP_REST_Request $request The request.
*/
public function request_gpt_completion( $request ) {
return Jetpack_AI_Helper::get_gpt_completion( $request['content'] );
return Jetpack_AI_Helper::get_gpt_completion( $request['content'], $request['post_id'] );
}

/**
Expand All @@ -93,7 +93,7 @@ public function request_gpt_completion( $request ) {
* @param WP_REST_Request $request The request.
*/
public function request_dalle_generation( $request ) {
return Jetpack_AI_Helper::get_dalle_generation( $request['prompt'] );
return Jetpack_AI_Helper::get_dalle_generation( $request['prompt'], $request['post_id'] );
}
}

Expand Down
4 changes: 4 additions & 0 deletions projects/plugins/jetpack/changelog/jetpack-ai-store-post-id
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Mark posts using Jetpack AI features. Introducing the _jetpack_ai_calls meta field to indicate that a post has performed AI calls.
16 changes: 14 additions & 2 deletions projects/plugins/jetpack/extensions/blocks/ai-image/edit.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import apiFetch from '@wordpress/api-fetch';
import { useBlockProps, store as blockEditorStore } from '@wordpress/block-editor';
import { createBlock } from '@wordpress/blocks';
Expand Down Expand Up @@ -27,7 +28,8 @@ function getImagesFromOpenAI(
setAttributes,
setLoadingImages,
setResultImages,
setErrorMessage
setErrorMessage,
postId
) {
setLoadingImages( true );
setErrorMessage( null );
Expand All @@ -38,6 +40,7 @@ function getImagesFromOpenAI(
method: 'POST',
data: {
prompt,
post_id: postId,
},
} )
.then( res => {
Expand Down Expand Up @@ -74,6 +77,7 @@ export default function Edit( { attributes, setAttributes, clientId } ) {
const errorButtonText = __( 'Retry', 'jetpack' );
const successButtonText = __( 'Submit', 'jetpack' );
const submitButtonText = errorMessage ? errorButtonText : successButtonText;
const { tracks } = useAnalytics();

const { mediaUpload } = useSelect( select => {
const { getSettings } = select( blockEditorStore );
Expand All @@ -82,6 +86,7 @@ export default function Edit( { attributes, setAttributes, clientId } ) {
mediaUpload: settings.mediaUpload,
};
}, [] );
const postId = useSelect( select => select( 'core/editor' ).getCurrentPostId() );

const submit = () => {
setLoadingImages( false );
Expand All @@ -92,8 +97,12 @@ export default function Edit( { attributes, setAttributes, clientId } ) {
setAttributes,
setLoadingImages,
setResultImages,
setErrorMessage
setErrorMessage,
postId
);
tracks.recordEvent( 'jetpack_ai_dalle_generation', {
post_id: postId,
} );
};

const ImageWithSelect = ( { image, inModal = false } ) => {
Expand Down Expand Up @@ -166,6 +175,9 @@ export default function Edit( { attributes, setAttributes, clientId } ) {
setLoadingImages( false );
},
} );
tracks.recordEvent( 'jetpack_ai_dalle_generation_upload', {
post_id: postId,
} );
};

return (
Expand Down
23 changes: 19 additions & 4 deletions projects/plugins/jetpack/extensions/blocks/ai-paragraph/edit.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import './editor.scss';

import { useAnalytics } from '@automattic/jetpack-shared-extension-utils';
import apiFetch from '@wordpress/api-fetch';
import { useBlockProps } from '@wordpress/block-editor';
import { Placeholder, Button, Spinner } from '@wordpress/components';
Expand Down Expand Up @@ -27,7 +28,8 @@ function getSuggestionFromOpenAI(
setAttributes,
formattedPrompt,
setLoadingCompletion,
setErrorMessage
setErrorMessage,
postId
) {
const needsAtLeast = 36;
if ( formattedPrompt.length < needsAtLeast ) {
Expand All @@ -46,7 +48,10 @@ function getSuggestionFromOpenAI(
}
setErrorMessage( '' );

const data = { content: formattedPrompt };
const data = {
content: formattedPrompt,
post_id: postId,
};
setLoadingCompletion( true );
setAttributes( { requestedPrompt: true } ); // This will prevent double submitting.
apiFetch( {
Expand Down Expand Up @@ -176,9 +181,11 @@ function preparePromptBasedOnEditorState( select ) {
export default function Edit( { attributes, setAttributes } ) {
const [ loadingCompletion, setLoadingCompletion ] = useState( true );
const [ errorMessage, setErrorMessage ] = useState( '' );
const { tracks } = useAnalytics();

// Here is where we craft the prompt.
const formattedPrompt = useSelect( preparePromptBasedOnEditorState, [] );
const postId = useSelect( select => select( 'core/editor' ).getCurrentPostId() );

//useEffect hook is called only once when block is first rendered.
useEffect( () => {
Expand All @@ -188,8 +195,12 @@ export default function Edit( { attributes, setAttributes } ) {
setAttributes,
formattedPrompt,
setLoadingCompletion,
setErrorMessage
setErrorMessage,
postId
);
tracks.recordEvent( 'jetpack_ai_gpt3_completion_automatic', {
post_id: postId,
} );
}
}, [ setAttributes, attributes ] ); // eslint-disable-line react-hooks/exhaustive-deps

Expand All @@ -204,8 +215,12 @@ export default function Edit( { attributes, setAttributes } ) {
setAttributes,
formattedPrompt,
setLoadingCompletion,
setErrorMessage
setErrorMessage,
postId
);
tracks.recordEvent( 'jetpack_ai_gpt3_completion_manual', {
post_id: postId,
} );
} }
romarioraffington marked this conversation as resolved.
Show resolved Hide resolved
>
{ __( 'Retry', 'jetpack' ) }
Expand Down