Skip to content

Commit

Permalink
Merge branch 'develop' into trunk
Browse files Browse the repository at this point in the history
  • Loading branch information
dkotter committed Jun 8, 2023
2 parents c2ddfb4 + f8eb022 commit 851b912
Show file tree
Hide file tree
Showing 45 changed files with 3,423 additions and 19,552 deletions.
3 changes: 2 additions & 1 deletion .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ dist
node_modules
tests/*
vendor/*
webpack.config.js
bin/*
hookdocs/*
2 changes: 2 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Directories
.git export-ignore
.github export-ignore
.husky export-ignore
.vscode export-ignore
bin export-ignore
docs export-ignore
Expand All @@ -19,6 +20,7 @@ tests export-ignore
.eslintignore export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.nvmrc export-ignore
.wp-env.json export-ignore
CHANGELOG.md export-ignore
classifai.zip export-ignore
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/dependency-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,9 @@ jobs:
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v3
- name: 'Dependency Review'
uses: actions/dependency-review-action@v1
- name: Dependency Review
uses: actions/dependency-review-action@v3
with:
license-check: true
vulnerability-check: false
config-file: 10up/.github/.github/dependency-review-config.yml@trunk
4 changes: 4 additions & 0 deletions .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

npx --no-install lint-staged
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v16
25 changes: 25 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file, per [the Ke

## [Unreleased] - TBD

## [2.2.1] - 2023-06-08
### Added
- Ability to generate images in the Classic Editor (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#471](https://github.com/10up/classifai/pull/471)).
- Ability to trigger Text-to-Speech generation in bulk (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#477](https://github.com/10up/classifai/pull/477)).
- Ability to trigger Text-to-Speech generation on an individual item from the post lists screen (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#477](https://github.com/10up/classifai/pull/477)).
- Custom `WP-CLI` command,`text_to_speech`, that can be used to generate Text-to-Speech data in bulk (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#478](https://github.com/10up/classifai/pull/478)).

### Changed
- Tweak the prompt that is used to generate excerpts (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#468](https://github.com/10up/classifai/pull/468)).
- Update the Dependency Review GitHub Action (props [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter) via [#464](https://github.com/10up/classifai/pull/464)).

### Fixed
- Resolve formatting issues in javascript files (props [@ravinderk](https://github.com/ravinderk), [@dkotter](https://github.com/dkotter) via [#461](https://github.com/10up/classifai/pull/461)).
- Correctly add terms to posts generated by Watson content classifiers (props [@ravinderk](https://github.com/ravinderk), [@iamdharmesh](https://github.com/iamdharmesh), [@dkotter](https://github.com/dkotter) via [#462](https://github.com/10up/classifai/pull/462)).
- Ensure we properly output data on the Site Health screen without causing errors (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#466](https://github.com/10up/classifai/pull/466)).
- Ensure the prompt we send to DALL·E never exceeds 1000 characters (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#467](https://github.com/10up/classifai/pull/467)).
- Ensure quotes aren't added around generated excerpts (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#468](https://github.com/10up/classifai/pull/468)).
- Remove extra slash from asset URLs (props [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#469](https://github.com/10up/classifai/pull/469)).
- Add proper docblocks to all custom hooks to ensure those show properly in our documentation site (props [@dkotter](https://github.com/dkotter), [@jeffpaul](https://github.com/jeffpaul) via [#470](https://github.com/10up/classifai/pull/470)).

### Security
- Bumped various dependencies (props [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter), [@ravinderk](https://github.com/ravinderk) via [#476](https://github.com/10up/classifai/pull/476)).
- Bump `atob` from 1.1.3 to 2.1.2 and `svg-react-loader` from 0.4.0 to 0.4.6 (props [@dependabot[bot]](https://github.com/apps/dependabot) via [#481](https://github.com/10up/classifai/pull/481)).

## [2.2.0] - 2023-05-22
### Added
- Convert text content into audio and output a "read-to-me" feature on the front-end to play this audio using Microsoft Azure's Text to Speech API (props [@Sidsector9](https://github.com/Sidsector9), [@iamdharmesh](https://github.com/iamdharmesh), [@ravinderk](https://github.com/ravinderk), [@jeffpaul](https://github.com/jeffpaul), [@dkotter](https://github.com/dkotter), [@pixeldevsio](https://github.com/pixeldevsio) via [#403](https://github.com/10up/classifai/pull/403)).
Expand Down Expand Up @@ -332,6 +356,7 @@ All notable changes to this project will be documented in this file, per [the Ke
- Initial closed source release

[Unreleased]: https://github.com/10up/classifai/compare/trunk...develop
[2.2.1]: https://github.com/10up/classifai/compare/2.2.0...2.2.1
[2.2.0]: https://github.com/10up/classifai/compare/2.1.0...2.2.0
[2.1.0]: https://github.com/10up/classifai/compare/2.0.0...2.1.0
[2.0.0]: https://github.com/10up/classifai/compare/1.8.1...2.0.0
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

[![E2E Testing](https://github.com/10up/classifai/actions/workflows/cypress.yml/badge.svg)](https://github.com/10up/classifai/actions/workflows/cypress.yml) [![PHPUnit Testing](https://github.com/10up/classifai/actions/workflows/test.yml/badge.svg)](https://github.com/10up/classifai/actions/workflows/test.yml) [![Linting](https://github.com/10up/classifai/actions/workflows/lint.yml/badge.svg)](https://github.com/10up/classifai/actions/workflows/lint.yml) [![CodeQL](https://github.com/10up/classifai/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/10up/classifai/actions/workflows/codeql-analysis.yml) [![Dependency Review](https://github.com/10up/classifai/actions/workflows/dependency-review.yml/badge.svg)](https://github.com/10up/classifai/actions/workflows/dependency-review.yml)

*You can learn more about ClassifAI's features at [ClassifAIPlugin.com](https://classifaiplugin.com/) and documentation at the [ClassifAI documentation site](https://10up.github.io/classifai/).*

## Table of Contents
* [Overview](#overview)
* [Features](#features)
Expand Down
2 changes: 1 addition & 1 deletion classifai.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Plugin URI: https://github.com/10up/classifai
* Update URI: https://classifaiplugin.com
* Description: Enhance your WordPress content with Artificial Intelligence and Machine Learning services.
* Version: 2.2.0
* Version: 2.2.1
* Requires at least: 5.7
* Requires PHP: 7.4
* Author: 10up
Expand Down
2 changes: 1 addition & 1 deletion config.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* declared here instead of a Class.
*/

$plugin_version = '2.2.0';
$plugin_version = '2.2.1';

if ( file_exists( __DIR__ . '/.commit' ) ) {
$plugin_version .= '-' . file_get_contents( __DIR__ . '/.commit' );
Expand Down
41 changes: 41 additions & 0 deletions hookdocs/wp-cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,47 @@ The following WP-CLI commands are supported by ClassifAI:

default: `false`

* `wp classifai text_to_speech <post_ids> [--post_type=<post_type>] [--post_status=<post_status>] [--per_page=<per_page>] [--dry-run=<bool>]`

Batch generation of text-to-speech data using Microsoft Azure's Text to Speech API.

* `<post_ids>`: A comma-delimited list of post IDs to generate text-to-speech for. Used if post_type is `false` or absent.

default: `null`

* `[--post_type=<post_type>]`: Batch process items belonging to this post type. If `false` or absent, will rely on `post_ids`.

default: `false`

options:

* any post type name

* `[--post_status=<post_status>]`: Batch process items that have this post status. Defaults to `publish`.

default: `publish`

options:

* any post status name

* `[--per_page=<int>]`: How many items should be processed at a time. Will still process all items but will do it in batches matching this number. Defaults to 100.

default: `100`

options:

* N, max number of items to process at a time

* `[--dry-run=<bool>]`: Whether to run as a dry-run. Defaults to `true`, so will run in dry-run mode unless this is set to `false`.

default: `true`

options:

* `true` to run in dry-run mode
* `false` to run in normal mode

### Image Processing Commands

* `wp classifai image <attachment_ids> [--limit=<int>] [--skip=<skip>] [--force]`
Expand Down
132 changes: 97 additions & 35 deletions includes/Classifai/Admin/BulkActions.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
namespace Classifai\Admin;

use Classifai\Providers\Azure\ComputerVision;
use Classifai\Providers\Azure\TextToSpeech;
use Classifai\Providers\OpenAI\Embeddings;
use Classifai\Providers\OpenAI\Whisper;
use Classifai\Providers\OpenAI\Whisper\Transcribe;
Expand Down Expand Up @@ -41,6 +42,11 @@ public function can_register() {
*/
private $whisper;

/**
* @var \Classifai\Providers\Azure\TextToSpeech
*/
private $text_to_speech;

/**
* Register the actions needed.
*/
Expand All @@ -55,25 +61,32 @@ public function register() {
* Register bulk actions for language processing.
*/
public function register_language_processing_hooks() {
$this->embeddings = new Embeddings( false );
$settings = $this->embeddings->get_settings();
$embeddings_post_types = [];
$nlu_post_types = get_supported_post_types();

// Set up the save post handler if we have any post types for NLU.
if ( ! empty( $nlu_post_types ) ) {
$this->embeddings = new Embeddings( false );
$embedding_settings = $this->embeddings->get_settings();
$embeddings_post_types = [];
$nlu_post_types = get_supported_post_types();
$this->text_to_speech = new TextToSpeech( false );
$text_to_speech_post_types = $this->text_to_speech->get_supported_post_types();

// Set up the save post handler if we have any post types.
if ( ! empty( $nlu_post_types ) || ! empty( $text_to_speech_post_types ) ) {
$this->save_post_handler = new SavePostHandler();
}

// Set up the embeddings post types if the feature is enabled. Otherwise clear our embeddings handler.
if ( isset( $settings['enable_classification'] ) && 1 === (int) $settings['enable_classification'] ) {
if ( isset( $embedding_settings['enable_classification'] ) && 1 === (int) $embedding_settings['enable_classification'] ) {
$embeddings_post_types = $this->embeddings->supported_post_types();
} else {
$this->embeddings = null;
}

// Clear our TextToSpeech handler if no post types are set up.
if ( empty( $text_to_speech_post_types ) ) {
$this->text_to_speech = null;
}

// Merge our post types together and make them unique.
$post_types = array_unique( array_merge( $embeddings_post_types, $nlu_post_types ) );
$post_types = array_unique( array_merge( $embeddings_post_types, $nlu_post_types, $text_to_speech_post_types ) );

if ( empty( $post_types ) ) {
return;
Expand Down Expand Up @@ -104,14 +117,29 @@ public function register_image_processing_hooks() {
}

/**
* Register Classifai bulk action.
* Register language processing bulk actions.
*
* @param array $bulk_actions Current bulk actions.
*
* @return array
*/
public function register_bulk_actions( $bulk_actions ) {
$bulk_actions['classify'] = __( 'Classify', 'classifai' );
$nlu_post_types = get_supported_post_types();

if (
! empty( $nlu_post_types ) ||
( is_a( $this->embeddings, '\Classifai\Providers\OpenAI\Embeddings' ) && ! empty( $this->embeddings->supported_post_types() ) )
) {
$bulk_actions['classify'] = __( 'Classify', 'classifai' );
}

if (
is_a( $this->text_to_speech, '\Classifai\Providers\Azure\TextToSpeech' ) &&
in_array( get_current_screen()->post_type, $this->text_to_speech->get_supported_post_types(), true )
) {
$bulk_actions['text_to_speech'] = __( 'Text to speech', 'classifai' );
}

return $bulk_actions;
}

Expand Down Expand Up @@ -145,7 +173,7 @@ public function register_media_bulk_actions( $bulk_actions ) {
}

/**
* Handle bulk actions.
* Handle language processing bulk actions.
*
* @param string $redirect_to Redirect URL after bulk actions.
* @param string $doaction Action ID.
Expand All @@ -154,24 +182,44 @@ public function register_media_bulk_actions( $bulk_actions ) {
* @return string
*/
public function bulk_action_handler( $redirect_to, $doaction, $post_ids ) {
if ( 'classify' !== $doaction ) {
if (
empty( $post_ids ) ||
! in_array( $doaction, [ 'classify', 'text_to_speech' ], true )
) {
return $redirect_to;
}

$action = '';

foreach ( $post_ids as $post_id ) {
// Handle NLU classification.
if ( is_a( $this->save_post_handler, '\Classifai\Admin\SavePostHandler' ) ) {
$this->save_post_handler->classify( $post_id );
if ( 'classify' === $doaction ) {
// Handle NLU classification.
if ( is_a( $this->save_post_handler, '\Classifai\Admin\SavePostHandler' ) ) {
$action = 'classified';
$this->save_post_handler->classify( $post_id );
}

// Handle OpenAI Embeddings classification.
if ( is_a( $this->embeddings, '\Classifai\Providers\OpenAI\Embeddings' ) ) {
$action = 'classified';
$this->embeddings->generate_embeddings_for_post( $post_id );
}
}

// Handle OpenAI Embeddings classification.
if ( is_a( $this->embeddings, '\Classifai\Providers\OpenAI\Embeddings' ) ) {
$this->embeddings->generate_embeddings_for_post( $post_id );
if ( 'text_to_speech' === $doaction ) {
// Handle Azure Text to Speech generation.
if (
is_a( $this->text_to_speech, '\Classifai\Providers\Azure\TextToSpeech' ) &&
is_a( $this->save_post_handler, '\Classifai\Admin\SavePostHandler' )
) {
$action = 'text_to_speech';
$this->save_post_handler->synthesize_speech( $post_id );
}
}
}

$redirect_to = remove_query_arg( [ 'bulk_classified', 'bulk_scanned', 'bulk_cropped', 'bulk_transcribed' ], $redirect_to );
$redirect_to = add_query_arg( 'bulk_classified', count( $post_ids ), $redirect_to );
$redirect_to = remove_query_arg( [ 'bulk_classified', 'bulk_text_to_speech', 'bulk_scanned', 'bulk_cropped', 'bulk_transcribed' ], $redirect_to );
$redirect_to = add_query_arg( rawurlencode( "bulk_{$action}" ), count( $post_ids ), $redirect_to );

return esc_url_raw( $redirect_to );
}
Expand Down Expand Up @@ -213,7 +261,7 @@ public function media_bulk_action_handler( $redirect_to, $doaction, $attachment_
}
}

$redirect_to = remove_query_arg( [ 'bulk_classified', 'bulk_scanned', 'bulk_cropped', 'bulk_transcribed' ], $redirect_to );
$redirect_to = remove_query_arg( [ 'bulk_classified', 'bulk_text_to_speech', 'bulk_scanned', 'bulk_cropped', 'bulk_transcribed' ], $redirect_to );
$redirect_to = add_query_arg( rawurlencode( "bulk_{$action}" ), count( $attachment_ids ), $redirect_to );

return esc_url_raw( $redirect_to );
Expand All @@ -224,19 +272,25 @@ public function media_bulk_action_handler( $redirect_to, $doaction, $attachment_
*/
public function bulk_action_admin_notice() {

$classified = ! empty( $_GET['bulk_classified'] ) ? intval( wp_unslash( $_GET['bulk_classified'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$scanned = ! empty( $_GET['bulk_scanned'] ) ? intval( wp_unslash( $_GET['bulk_scanned'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$cropped = ! empty( $_GET['bulk_cropped'] ) ? intval( wp_unslash( $_GET['bulk_cropped'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$transcribed = ! empty( $_GET['bulk_transcribed'] ) ? intval( wp_unslash( $_GET['bulk_transcribed'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$classified = ! empty( $_GET['bulk_classified'] ) ? intval( wp_unslash( $_GET['bulk_classified'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$text_to_speech = ! empty( $_GET['bulk_text_to_speech'] ) ? intval( wp_unslash( $_GET['bulk_text_to_speech'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$post_type = ! empty( $_GET['post_type'] ) ? sanitize_text_field( wp_unslash( $_GET['post_type'] ) ) : 'post'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$scanned = ! empty( $_GET['bulk_scanned'] ) ? intval( wp_unslash( $_GET['bulk_scanned'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$cropped = ! empty( $_GET['bulk_cropped'] ) ? intval( wp_unslash( $_GET['bulk_cropped'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$transcribed = ! empty( $_GET['bulk_transcribed'] ) ? intval( wp_unslash( $_GET['bulk_transcribed'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

if ( ! $classified && ! $scanned && ! $cropped && ! $transcribed ) {
if ( ! $classified && ! $text_to_speech && ! $scanned && ! $cropped && ! $transcribed ) {
return;
}

if ( $classified ) {
$classified_posts_count = $classified;
$post_type = 'post';
$post_type = $post_type;
$action = __( 'Classified', 'classifai' );
} elseif ( $text_to_speech ) {
$classified_posts_count = $text_to_speech;
$post_type = $post_type;
$action = __( 'Text to speech conversion done for', 'classifai' );
} elseif ( $scanned ) {
$classified_posts_count = $scanned;
$post_type = 'image';
Expand Down Expand Up @@ -297,15 +351,23 @@ public function register_row_action( $actions, $post ) {
$post_types = array_merge( $post_types, $this->embeddings->supported_post_types() );
}

if ( ! in_array( $post->post_type, $post_types, true ) ) {
return $actions;
if ( in_array( $post->post_type, $post_types, true ) ) {
$actions['classify'] = sprintf(
'<a href="%s">%s</a>',
esc_url( wp_nonce_url( admin_url( sprintf( 'edit.php?action=classify&ids=%d&post_type=%s', $post->ID, $post->post_type ) ), 'bulk-posts' ) ),
esc_html__( 'Classify', 'classifai' )
);
}

$actions['classify'] = sprintf(
'<a href="%s">%s</a>',
esc_url( wp_nonce_url( admin_url( sprintf( 'edit.php?action=classify&ids=%d&post_type=%s', $post->ID, $post->post_type ) ), 'bulk-posts' ) ),
esc_html__( 'Classify', 'classifai' )
);
if ( is_a( $this->text_to_speech, '\Classifai\Providers\Azure\TextToSpeech' ) ) {
if ( in_array( $post->post_type, $this->text_to_speech->get_supported_post_types(), true ) ) {
$actions['text_to_speech'] = sprintf(
'<a href="%s">%s</a>',
esc_url( wp_nonce_url( admin_url( sprintf( 'edit.php?action=text_to_speech&ids=%d&post_type=%s', $post->ID, $post->post_type ) ), 'bulk-posts' ) ),
esc_html__( 'Text to speech', 'classifai' )
);
}
}

return $actions;
}
Expand Down
3 changes: 2 additions & 1 deletion includes/Classifai/Admin/SavePostHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ public function synthesize_speech( $post_id ) {
);
}

if ( ! current_user_can( 'edit_post', $post_id ) ) {
// We skip the user cap check if running under WP-CLI.
if ( ! current_user_can( 'edit_post', $post_id ) && ( ! defined( 'WP_CLI' ) || ! WP_CLI ) ) {
return new \WP_Error(
'azure_text_to_speech_user_not_authorized',
esc_html__( 'Unauthorized user.', 'classifai' )
Expand Down
Loading

0 comments on commit 851b912

Please sign in to comment.