Skip to content

Commit

Permalink
Option to bulk generate alt texts (#6)
Browse files Browse the repository at this point in the history
* feat: add a bulk actions option

* feat: bulk generate modal

* style: fix PHPCS

* feat: generator status

* refactor: use `Map` for generation state

* feat: scrollable state table

* fix: `setAltGenerationMap` race condition

* feat: status icons

* fix: api save

* feat: custom prompt

* feat: grid view mode support

* fix: refresh grid view mode on alt generation complete

* fix: remove test code

* feat: cancel alt generation on modal close
  • Loading branch information
rafaucau authored Apr 19, 2024
1 parent fd75fb1 commit 065f76b
Show file tree
Hide file tree
Showing 20 changed files with 934 additions and 23 deletions.
16 changes: 15 additions & 1 deletion alt-text-generator-gpt-vision.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* Plugin Name: AI Alt Text Generator for GPT Vision
* Plugin URI: https://github.com/android-com-pl/wp-ai-alt-generator
* Description: Automatically generate alternative text for images using OpenAI's GPT Vision API.
* Version: 2.0.3
* Version: 2.1.0
* Requires at least: 6.3
* Requires PHP: 8.1
* Author: android.com.pl
Expand Down Expand Up @@ -36,9 +36,17 @@ class AltGeneratorPlugin {
public function __construct() {
add_filter( 'wp_generate_attachment_metadata', [ AltGenerator::class, 'on_attachment_upload' ], 10, 3 );
add_action( 'rest_api_init', [ ( new Api() ), 'register_routes' ] );

add_action( 'enqueue_block_editor_assets', fn()=> $this->enqueue_script( 'editor' ) );
add_action( 'wp_enqueue_media', fn()=> $this->enqueue_script( 'media-modal', true ) );
add_action( 'admin_enqueue_scripts', fn()=> $this->enqueue_attachment_edit_page_script() );

add_action( 'load-upload.php', fn()=> $this->enqueue_script( 'media-upload', true ) );
add_filter(
'bulk_actions-upload',
fn( $actions ) => $actions + [ 'generate_alt_text' => __( 'Generate Alternative Text', 'alt-text-generator-gpt-vision' ) ]
);

add_action( 'activated_plugin', [ $this,'redirect_to_plugin_settings_after_activation' ] );
add_filter( 'plugin_row_meta', [ $this, 'plugin_row_meta' ], 10, 2 );
}
Expand All @@ -62,6 +70,12 @@ private function enqueue_script( string $file_name, array|bool $args = false ):
$handle = "acpl/ai-alt-generator/$file_name";
wp_enqueue_script( $handle, ACPL_AI_ALT_PLUGIN_URL . "build/$file_name.js", $asset_file['dependencies'], $asset_file['version'], $args );
wp_set_script_translations( $handle, 'alt-text-generator-gpt-vision' );

foreach ( $asset_file['dependencies'] as $dependency ) {
if ( 'wp-components' === $dependency ) {
wp_enqueue_style( 'wp-components' );
}
}
}

private function enqueue_attachment_edit_page_script(): void {
Expand Down
35 changes: 22 additions & 13 deletions includes/AltGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AltGenerator {
const API_URL = 'https://api.openai.com/v1/chat/completions';
const MODEL = 'gpt-4-vision-preview';

public static function generate_alt_text( int $attachment_id ): string|WP_Error {
public static function generate_alt_text( int $attachment_id, string $user_prompt = '' ): string|WP_Error {
if ( ! wp_attachment_is_image( $attachment_id ) ) {
return ErrorCodes::Not_image->to_wp_error( [ 'attachment_id' => $attachment_id ] );
}
Expand All @@ -24,13 +24,6 @@ public static function generate_alt_text( int $attachment_id ): string|WP_Error
$locale = get_locale();
$language = locale_get_display_language( $locale );

$user_prompt = apply_filters(
'acpl/ai_alt_generator/user_prompt',
"Generate a high-quality and concise alt text in $language ($locale) for the provided image without adding any additional comments.",
$locale,
$language
);

$image_mime_type = get_post_mime_type( $attachment_id );
$image_base64 = self::get_image_as_base64( $attachment_id );

Expand All @@ -51,12 +44,28 @@ public static function generate_alt_text( int $attachment_id ): string|WP_Error
[
'model' => self::MODEL,
'messages' => [
[
'role' => 'system',
'content' => apply_filters(
'acpl/ai_alt_generator/system_prompt',
"Generate a high-quality and concise alt text in $language ($locale) for the provided image without adding any additional comments.",
$attachment_id,
$locale,
$language
),
],
[
'role' => 'user',
'content' => [
[
'type' => 'text',
'text' => $user_prompt,
'text' => apply_filters(
'acpl/ai_alt_generator/user_prompt',
$user_prompt,
$attachment_id,
$locale,
$language
),
],
[
'type' => 'image_url',
Expand All @@ -79,7 +88,7 @@ public static function generate_alt_text( int $attachment_id ): string|WP_Error

$completion = json_decode( wp_remote_retrieve_body( $api_response ), true );

if ( $completion['error'] ) {
if ( isset( $completion['error'] ) ) {
return new WP_Error(
$completion['error']['code'],
// translators: %s is the error message from OpenAI's API.
Expand All @@ -90,12 +99,12 @@ public static function generate_alt_text( int $attachment_id ): string|WP_Error
return $completion['choices'][0]['message']['content'] ?? '';
}

public static function generate_and_set_alt_text( int $attachment_id ): ?string {
$alt_text = self::generate_alt_text( $attachment_id );
public static function generate_and_set_alt_text( int $attachment_id, string $user_prompt = '' ): string|WP_Error|null {
$alt_text = self::generate_alt_text( $attachment_id, $user_prompt );
if ( is_wp_error( $alt_text ) ) {
AltGeneratorPlugin::error_log( $alt_text );

return null;
return $alt_text;
}

if ( ! empty( $alt_text ) ) {
Expand Down
22 changes: 20 additions & 2 deletions includes/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,31 @@
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

class Api {
public function register_routes(): void {
register_rest_route(
'acpl',
'/ai-alt-generator',
[
'methods' => 'POST',
'methods' => WP_REST_Server::CREATABLE,
'args' => [
'attachment_id' => [
'required' => true,
'type' => 'integer',
],
'user_prompt' => [
'required' => false,
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
],
'save' => [
'required' => false,
'type' => 'boolean',
'default' => false,
'description' => esc_html__( 'Saves the generated alt text to the image when enabled.', 'alt-text-generator-gpt-vision' ),
],
],
'callback' => [ $this, 'generate_alt_text' ],
'permission_callback' => fn() => current_user_can( 'edit_posts' ),
Expand All @@ -27,8 +39,14 @@ public function register_routes(): void {

public function generate_alt_text( WP_REST_Request $request ): WP_REST_Response|WP_Error {
$attachment_id = $request->get_param( 'attachment_id' );
$save_alt = $request->get_param( 'save' );
$user_prompt = $request->get_param( 'user_prompt' ) ?? '';

$alt_text = AltGenerator::generate_alt_text( $attachment_id );
if ( $save_alt ) {
$alt_text = AltGenerator::generate_and_set_alt_text( $attachment_id, $user_prompt );
} else {
$alt_text = AltGenerator::generate_alt_text( $attachment_id, $user_prompt );
}

if ( is_wp_error( $alt_text ) ) {
return $alt_text;
Expand Down
Loading

0 comments on commit 065f76b

Please sign in to comment.