{ status, data } * GET aisentic/v1/eventin-ai/connection -> { is_connected, token_form_url } * * Banner images (type "image") are out of scope for now: one AI image costs * hundreds of credits. The old Eventin AI plugin made them with DALL-E. * * The answers have the same shape as the old eventin-ai/v1 routes, so the copied React code works unchanged. */ class Eventin_Ai_Controller extends Base_Rest_Controller { /** * Namespace. * * @var string */ protected $namespace = 'aisentic/v1'; /** * Base. * * @var string */ protected $rest_base = 'eventin-ai'; /** * Makes the text generator. * * @var callable */ private $text_factory; /** * Constructor. The factories are for tests; production uses the defaults. * * @param callable|null $text_factory Returns an Eventin_Ai_Text_Generator. */ public function __construct( ?callable $text_factory = null ) { $this->text_factory = $text_factory ?? static fn() => Eventin_Ai_Text_Generator::from_settings( new Settings() ); } /** * Register routes. Only when Eventin is active. * * @return void */ public function register_routes() { if ( ! class_exists( 'Wpeventin' ) ) { return; } register_rest_route( $this->namespace, '/' . $this->rest_base . '/generate', [ 'methods' => WP_REST_Server::CREATABLE, 'callback' => [ $this, 'generate' ], 'permission_callback' => [ $this, 'can_manage_events' ], ] ); register_rest_route( $this->namespace, '/' . $this->rest_base . '/connection', [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'connection' ], 'permission_callback' => [ $this, 'can_manage_options' ], ] ); } /** * Same rule as the old plugin. * * @return bool */ public function can_manage_events(): bool { return current_user_can( 'etn_manage_event' ); } /** * Same rule as the old plugin. * * @return bool */ public function can_manage_options(): bool { return current_user_can( 'manage_options' ); } /** * Make event text. * * @param WP_REST_Request $request Request. * @return WP_REST_Response|WP_Error */ public function generate( WP_REST_Request $request ) { $input = json_decode( $request->get_body(), true ); $input = is_array( $input ) ? $input : []; $type = sanitize_text_field( (string) ( $input['type'] ?? '' ) ); $prompt = sanitize_textarea_field( (string) ( $input['prompt'] ?? '' ) ); if ( '' === $type ) { return $this->invalid( __( 'Please provide prompt type.', 'aisentic' ) ); } if ( '' === $prompt ) { return $this->invalid( __( 'Please provide prompt.', 'aisentic' ) ); } if ( 'image' === $type ) { return $this->invalid( __( 'Banner images with AI are not available yet.', 'aisentic' ) ); } if ( ! in_array( $type, Eventin_Ai_Text_Generator::TYPES, true ) ) { return $this->invalid( __( 'Unknown prompt type.', 'aisentic' ) ); } $policy = new Policy(); $rate_limit = (int) ( new Settings() )->get( 'general.rateLimitPerMinute', 20 ); if ( $policy->isRateLimited( 'eventin_ai_' . $policy->getRequestIdentifier(), $rate_limit ) ) { return new WP_Error( 'aisentic_rate_limited', __( 'Too many requests. Please wait a minute and try again.', 'aisentic' ), [ 'status' => 429 ] ); } try { $data = ( $this->text_factory )()->generate( $type, $prompt ); return new WP_REST_Response( [ 'status' => 'success', 'data' => $data, ], 200 ); } catch ( Eventin_Ai_Exception $e ) { return new WP_Error( 'aisentic_eventin_ai_failed', $e->getMessage(), [ 'status' => 502 ] ); } catch ( \Throwable $e ) { Log::error( 'Eventin AI generation failed', [ 'type' => $type, 'message' => $e->getMessage(), ] ); return new WP_Error( 'aisentic_eventin_ai_failed', Ai_Error_Message::from_throwable( $e, __( 'The AI request failed. Please try again.', 'aisentic' ) ), [ 'status' => 502 ] ); } } /** * Is the selected provider ready? * * @return WP_REST_Response */ public function connection(): WP_REST_Response { return new WP_REST_Response( [ 'is_connected' => Llm_Provider_Factory::has_credentials( new Settings() ), 'token_form_url' => admin_url( 'admin.php?page=aisentic#/settings/ai-configuration' ), ], 200 ); } /** * 422 error. * * @param string $message Message. * @return WP_Error */ private function invalid( string $message ): WP_Error { return new WP_Error( 'aisentic_eventin_ai_invalid', $message, [ 'status' => 422 ] ); } }