PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 All 140 releases
learnpress / inc / Ajax / AI / OpenAiAjax.php

OpenAiAjax.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.9, at inc/Ajax/AI/OpenAiAjax.php

550 lines 17.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\Ajax\AI;
4
5 use Exception;
6 use LearnPress;
7 use LearnPress\Ajax\AbstractAjax;
8 use LearnPress\Helpers\Config;
9 use LearnPress\Helpers\Template;
10 use LearnPress\Models\CourseModel;
11 use LearnPress\Models\CoursePostModel;
12 use LearnPress\Models\PostModel;
13 use LearnPress\Models\QuizPostModel;
14 use LearnPress\Models\UserModel;
15 use LearnPress\Services\CourseService;
16 use LearnPress\Services\OpenAiService;
17 use LearnPress\TemplateHooks\Admin\AI\AdminCreateCourseAITemplate;
18 use LearnPress\TemplateHooks\Admin\AI\AdminEditCourseCurriculumWithAITemplate;
19 use LearnPress\TemplateHooks\Admin\AI\AdminEditWithAITemplate;
20 use LP_Helper;
21 use LP_Request;
22 use LP_REST_Response;
23 use LP_WP_Filesystem;
24 use Throwable;
25
26 /**
27 * class OpenAiAjax
28 * Handle request Open AI
29 *
30 * @since 4.3.0
31 * @version 1.0.0
32 */
33 class OpenAiAjax extends AbstractAjax {
34 /**
35 * Generate prompt course with AI
36 */
37 public function openai_generate_prompt_course() {
38 $response = new LP_REST_Response();
39
40 try {
41 // Check permission
42 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
43 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
44 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
45 }
46
47 $data_str = LP_Request::get_param( 'data' );
48 $params = LP_Helper::json_decode( $data_str, true );
49 $prompt = Config::instance()->get( 'prompt-create-course', 'settings/openAi', compact( 'params' ) );
50
51 $response->data = $prompt;
52 $response->status = 'success';
53 $response->message = __( 'Generate prompt successfully!', 'learnpress' );
54 } catch ( Throwable $e ) {
55 $response->message = $e->getMessage();
56 }
57
58 wp_send_json( $response );
59 }
60
61 /**
62 * Generate data course with prompt submitted
63 */
64 public function openai_generate_data_course() {
65 $response = new LP_REST_Response();
66
67 try {
68 // Check permission
69 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
70 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
71 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
72 }
73
74 $data_str = LP_Request::get_param( 'data' );
75 $params = LP_Helper::json_decode( $data_str, true );
76 $prompt = $params['lp-openai-prompt-generated-field'] ?? '';
77 $args = [
78 'prompt' => $prompt,
79 ];
80
81 $result = OpenAiService::instance()->send_request( $args );
82 $lp_structure_data = $result['lp_structure_data'] ?? [];
83 if ( count( $lp_structure_data ) > 0 ) {
84 $result['lp_structure_course'] = $lp_structure_data[0] ?? '';
85 if ( empty( $result['lp_structure_course'] )
86 || ! is_array( $result['lp_structure_course'] ) ) {
87 throw new Exception( __( 'Error: no data structure course generated!', 'learnpress' ) );
88 }
89
90 $result['lp_html_preview'] = AdminCreateCourseAITemplate::html_preview_with_data( $result['lp_structure_course'] );
91 }
92
93 $response->data = $result;
94 $response->status = 'success';
95 $response->message = __( 'Generate course successfully!', 'learnpress' );
96 } catch ( Throwable $e ) {
97 $response->message = $e->getMessage();
98 }
99
100 wp_send_json( $response );
101 }
102
103 /**
104 * Create course with data generated
105 */
106 public function openai_create_course() {
107 $response = new LP_REST_Response();
108
109 try {
110 // Check permission
111 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
112 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
113 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
114 }
115
116 $data_str = LP_Request::get_param( 'data' );
117 $data = LP_Helper::json_decode( $data_str, true );
118 $data_structure_course = $data['lp_structure_course'] ?? [];
119 $is_course_builder = ! empty( $data['is_course_builder'] );
120 if ( empty( $data_structure_course ) ) {
121 throw new Exception( __( 'Invalid data to create course!', 'learnpress' ) );
122 }
123
124 $courseService = CourseService::instance();
125
126 $data_info_main = [
127 'post_title' => $data_structure_course['course_title'] ?? 'AI Generated Course',
128 'post_content' => $data_structure_course['course_description'] ?? '',
129 'post_status' => 'draft',
130 'post_author' => get_current_user_id(),
131 ];
132 $coursePostModel = $courseService->create_info_main( $data_info_main );
133
134 // Create section
135 $data_sections = $data_structure_course['sections'] ?? [];
136 foreach ( $data_sections as $data_section ) {
137 $section_name = $data_section['section_title'] ?? '';
138 $section_description = $data_section['section_description'] ?? '';
139 $lesson_items = $data_section['lessons'] ?? [];
140 $quiz_items = $data_section['quizzes'] ?? [];
141
142 $courseSectionModel = $coursePostModel->add_section(
143 [
144 'section_name' => $section_name,
145 'section_description' => $section_description,
146 ]
147 );
148
149 // Create lesson items for section
150 foreach ( $lesson_items as $lesson_item ) {
151 $lesson_name = $lesson_item['lesson_title'] ?? '';
152 $lesson_description = $lesson_item['lesson_description'] ?? '';
153
154 $courseSectionModel->create_item_and_add(
155 [
156 'item_title' => $lesson_name,
157 'item_type' => LP_LESSON_CPT,
158 'item_content' => $lesson_description,
159 ]
160 );
161 }
162
163 // Create quiz items for section
164 foreach ( $quiz_items as $quiz_item ) {
165 $quiz_name = $quiz_item['quiz_title'] ?? '';
166 $quiz_description = $quiz_item['quiz_description'] ?? '';
167
168 $courseSectionQuizModel = $courseSectionModel->create_item_and_add(
169 [
170 'item_title' => $quiz_name,
171 'item_type' => LP_QUIZ_CPT,
172 'item_content' => $quiz_description,
173 ]
174 );
175 $quizPostModel = QuizPostModel::find( $courseSectionQuizModel->item_id, true );
176
177 // Create questions for quiz
178 $question_items = $quiz_item['questions'] ?? [];
179 foreach ( $question_items as $question_item ) {
180 $question_name = $question_item['question_title'] ?? '';
181 $question_description = $question_item['question_description'] ?? '';
182 $options = $question_item['options'] ?? [];
183 $correct_answer = $question_item['correct_answer'] ?? '';
184
185 $data_answers = [];
186 foreach ( $options as $index => $option ) {
187 $data_answers[] = [
188 'title' => $option,
189 'is_true' => ( $option === $correct_answer ) ? 'yes' : 'no',
190 'order' => $index + 1,
191 ];
192 }
193
194 $quizPostModel->create_question_and_add(
195 [
196 'question_title' => $question_name,
197 'question_content' => $question_description,
198 'question_type' => 'single_choice',
199 'question_options' => $data_answers,
200 ]
201 );
202 }
203 }
204 }
205
206 $course_edit_url = $coursePostModel->get_edit_link();
207 if ( $is_course_builder ) {
208 $course_edit_url = \LearnPress\CourseBuilder\CourseBuilder::get_tab_link(
209 'courses',
210 $coursePostModel->get_id()
211 );
212 }
213
214 $response->data->edit_course_url = $course_edit_url;
215 $response->data->button_label = __( 'Redirecting...', 'learnpress' );
216 $response->status = 'success';
217 $response->message = __( 'Create Course Successfully! Redirecting to course detail...', 'learnpress' );
218 } catch ( Throwable $e ) {
219 $response->message = $e->getMessage();
220 }
221
222 wp_send_json( $response );
223 }
224
225 /**
226 * Generate prompt title with AI
227 */
228 public function openai_generate_prompt() {
229 $response = new LP_REST_Response();
230
231 try {
232 // Check permission
233 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
234 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
235 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
236 }
237
238 $data_str = LP_Request::get_param( 'data' );
239 $params = LP_Helper::json_decode( $data_str, true );
240 $lp_prompt_type = $params['lp-prompt-type'] ?? '';
241
242 switch ( $lp_prompt_type ) {
243 case 'course-description':
244 $prompt = Config::instance()->get( 'prompt-create-description-course', 'settings/openAi', compact( 'params' ) );
245 break;
246 case 'course-title':
247 $prompt = Config::instance()->get( 'prompt-create-title-course', 'settings/openAi', compact( 'params' ) );
248 break;
249 case 'course-image':
250 $prompt = Config::instance()->get( 'prompt-create-image-course', 'settings/openAi', compact( 'params' ) );
251 break;
252 case 'course-curriculum':
253 $prompt = Config::instance()->get( 'prompt-curriculum-course', 'settings/openAi', compact( 'params' ) );
254 break;
255 case $lp_prompt_type:
256 $prompt = apply_filters( 'lp-prompt-type', '', $lp_prompt_type, $params );
257 break;
258 default:
259 $prompt = '';
260 break;
261 }
262
263 $response->data = $prompt;
264 $response->status = 'success';
265 $response->message = __( 'Generate prompt successfully!', 'learnpress' );
266 } catch ( Throwable $e ) {
267 $response->message = $e->getMessage();
268 }
269
270 wp_send_json( $response );
271 }
272
273 /**
274 * Generate data course with prompt submitted
275 */
276 public function openai_generate_data() {
277 $response = new LP_REST_Response();
278
279 try {
280 // Check permission
281 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
282 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
283 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
284 }
285
286 $data_str = LP_Request::get_param( 'data' );
287 $params = LP_Helper::json_decode( $data_str, true );
288 $prompt = $params['lp-openai-prompt-generated-field'] ?? '';
289 $args = [
290 'prompt' => $prompt,
291 ];
292
293 $result = OpenAiService::instance()->send_request( $args );
294 $lp_structure_data = $result['lp_structure_data'] ?? [];
295 $result['lp_html_preview'] = '';
296 if ( count( $lp_structure_data ) > 0 ) {
297 $lp_prompt_type = $params['lp-prompt-type'] ?? '';
298 switch ( $lp_prompt_type ) {
299 case 'course-description':
300 case 'course-title':
301 $results = $lp_structure_data[0];
302 if ( isset( $results['results'] ) ) {
303 $results = $results['results'];
304 } else {
305 throw new Exception(
306 __(
307 'Error: No data was generated. The requested data may be large, increase the Max Tokens in settings and try again.',
308 'learnpress'
309 )
310 );
311 }
312
313 foreach ( $results as $index => $data_item ) {
314 $data_item = $data_item['item'] ?? '';
315 $args = [
316 'index' => $index,
317 'value' => $data_item,
318 'target-apply' => $params['target-apply'] ?? '',
319 ];
320 $result['lp_html_preview'] .= AdminEditWithAITemplate::instance()->html_list_results( $args );
321 }
322 break;
323 case 'course-curriculum':
324 $result['lp_structure_course'] = $lp_structure_data[0];
325 $result['lp_html_preview'] = AdminEditCourseCurriculumWithAITemplate::html_preview_with_data(
326 $result['lp_structure_course']
327 );
328 break;
329 case $lp_prompt_type:
330 $result['lp_html_preview'] = apply_filters( 'lp-openai-render-data-generated', '', $lp_prompt_type, $lp_structure_data );
331 break;
332 default:
333 break;
334 }
335 }
336
337 $result['lp_html_preview'] .= sprintf(
338 '<input type="hidden" name="lp-openai-generated-data" value="%s" />',
339 Template::convert_data_to_json( $lp_structure_data )
340 );
341
342 $response->data = $result;
343 $response->status = 'success';
344 $response->message = __( 'Generate course successfully!', 'learnpress' );
345 } catch ( Throwable $e ) {
346 $response->message = $e->getMessage();
347 }
348
349 wp_send_json( $response );
350 }
351
352 /**
353 * Generate image with prompt submitted
354 * Send data to Open AI to generate image
355 *
356 * @since 4.3.0
357 * @version 1.0.0
358 */
359 public function openai_generate_image() {
360 $response = new LP_REST_Response();
361
362 try {
363 // Check permission
364 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
365 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
366 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
367 }
368
369 $data_str = LP_Request::get_param( 'data' );
370 $params = LP_Helper::json_decode( $data_str, true );
371 $prompt = $params['lp-openai-prompt-generated-field'] ?? '';
372 $args = [
373 'prompt' => $prompt,
374 'n' => intval( $params['outputs'] ?? 1 ),
375 'size' => '1024x1024',
376 ];
377
378 $result = OpenAiService::instance()->send_request_create_image( $args );
379 $html_image = '';
380 $result['lp_html_preview'] = '';
381 $data = $result['data'] ?? [];
382 if ( ! empty( $data ) ) {
383 $result['lp_html_preview'] = '<div class="lp-ai-images-warp">';
384 foreach ( $data as $index => $data_item ) {
385 $image_base_64 = $data_item['b64_json'] ?? '';
386 $image_url = $data_item['url'] ?? '';
387
388 if ( ! empty( $image_url ) ) {
389 $html_image = sprintf(
390 '<img src="%s" alt="AI Generated Image" />',
391 esc_url( $image_url )
392 );
393 } elseif ( ! empty( $image_base_64 ) ) {
394 $html_image = sprintf(
395 '<img src="data:image/png;base64,%s" alt="AI Generated Image" />',
396 esc_attr( $image_base_64 )
397 );
398 }
399
400 if ( empty( $html_image ) ) {
401 continue;
402 }
403
404 $result['lp_html_preview'] .= '<div class="lp-ai-image-item">';
405 $result['lp_html_preview'] .= $html_image;
406 $result['lp_html_preview'] .= sprintf(
407 '<button class="lp-btn-ai-apply-image lp-button" type="button"
408 data-send="%s">%s
409 </button>',
410 Template::convert_data_to_json(
411 [
412 'action' => 'openai_apply_image_feature',
413 'image-url' => ! empty( $image_url ) ? $image_url : '',
414 'image-base64' => ! empty( $image_base_64 ) ? $image_base_64 : '',
415 'id_url' => 'apply-image-feature',
416 ]
417 ),
418 __( 'Apply Image', 'learnpress' )
419 );
420 $result['lp_html_preview'] .= '</div>';
421 }
422 $result['lp_html_preview'] .= '</div>';
423 }
424
425 $response->data = $result;
426 $response->status = 'success';
427 $response->message = __( 'Generate image successfully!', 'learnpress' );
428 } catch ( Throwable $e ) {
429 $response->message = $e->getMessage();
430 }
431
432 wp_send_json( $response );
433 }
434
435 /**
436 * Apply image feature to post
437 * Upload image to media and set as feature image for post
438 *
439 * @since 4.3.0
440 * @version 1.0.2
441 */
442 public function openai_apply_image_feature() {
443 $response = new LP_REST_Response();
444
445 try {
446 set_time_limit( 0 );
447 // Check permission
448 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
449 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
450 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
451 }
452
453 $data_str = $_POST['data'] ?? '';
454 $params = LP_Helper::json_decode( wp_unslash( $data_str ), true );
455 $image_base64 = $params['image-base64'] ?? '';
456 $image_url = $params['image-url'] ?? '';
457
458 $params = LP_Helper::sanitize_params_submitted( $params );
459 $post_id = $params['post-id'] ?? '';
460 $post_title = $params['post-title'] ?? uniqid();
461 $post_slug = sanitize_title( $post_title );
462
463 if ( empty( $post_id ) ) {
464 throw new Exception( __( 'Invalid post ID.', 'learnpress' ) );
465 }
466
467 // Check permission
468 $post_type = get_post_type( $post_id );
469 if ( $post_type === LP_COURSE_CPT ) {
470 $coursePostModel = CoursePostModel::find( $post_id, true );
471 if ( ! $coursePostModel ) {
472 throw new Exception( __( 'Invalid course ID.', 'learnpress' ) );
473 }
474
475 if ( ! $coursePostModel->check_capabilities_update() ) {
476 throw new Exception(
477 __( 'You do not have permission to perform this action.', 'learnpress' )
478 );
479 }
480 } else {
481 $course_item_types = CourseModel::item_types_support();
482 if ( ! in_array( $post_type, $course_item_types ) ) {
483 throw new Exception( __( 'Invalid post type.', 'learnpress' ) );
484 }
485
486 $postModel = PostModel::find_by_id( $post_id, true );
487 $postModel->check_capabilities_update_item_course();
488 }
489
490 if ( ! function_exists( 'media_handle_sideload' ) ) {
491 require_once ABSPATH . 'wp-admin/includes/media.php';
492 require_once ABSPATH . 'wp-admin/includes/file.php';
493 require_once ABSPATH . 'wp-admin/includes/image.php';
494 }
495
496 // model gpt-image-1 only return base64, so don't need to download from url
497 if ( ! empty( $image_base64 ) ) {
498 $decoded_image = base64_decode( $image_base64 );
499 if ( false === $decoded_image || '' === $decoded_image ) {
500 throw new Exception( __( 'Invalid image data.', 'learnpress' ) );
501 }
502
503 $image_info = @getimagesizefromstring( $decoded_image );
504 if ( false === $image_info ) {
505 throw new Exception( __( 'Decoded data is not a valid image.', 'learnpress' ) );
506 }
507
508 $tmp = wp_tempnam();
509 $lp_wp_filesystem = LP_WP_Filesystem::instance();
510 $put_contents_result = $lp_wp_filesystem->put_contents( $tmp, $decoded_image );
511 if ( ! $put_contents_result || ! is_readable( $tmp ) ) {
512 throw new Exception( __( 'Decoded image is not readable.', 'learnpress' ) );
513 }
514 $filename = sanitize_file_name( $post_slug . '-' . uniqid() . '.png' );
515 } else {
516 throw new Exception( __( 'No image data provided.', 'learnpress' ) );
517 }
518
519 $file_array = [
520 'name' => $filename,
521 'tmp_name' => $tmp,
522 ];
523 $attachment_id = media_handle_sideload( $file_array, $post_id );
524
525 if ( ! is_wp_error( $attachment_id ) ) {
526 set_post_thumbnail( $post_id, $attachment_id );
527 } else {
528 throw new Exception( $attachment_id->get_error_message() );
529 }
530
531 $args = [
532 'src' => wp_get_attachment_url( $attachment_id ),
533 'post-id' => $post_id,
534 'attachment-id' => $attachment_id,
535 ];
536
537 $response->data->html_image = AdminEditWithAITemplate::instance()->html_feature_image_created( $args );
538 $response->data->attachment_id = $attachment_id;
539 $response->status = 'success';
540 $response->message = __( 'Apply image successfully!', 'learnpress' );
541 } catch ( Throwable $e ) {
542 $response->message = $e->getMessage();
543 }
544
545 set_time_limit( LearnPress::$time_limit_default_of_sever );
546
547 wp_send_json( $response );
548 }
549 }
550