PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.6
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.6
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 4.2.0 All 139 releases
learnpress / inc / Ajax / AI / OpenAiAjax.php

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

551 lines 18.0 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 'overview'
212 );
213 }
214
215 $response->data->edit_course_url = $course_edit_url;
216 $response->data->button_label = __( 'Redirecting...', 'learnpress' );
217 $response->status = 'success';
218 $response->message = __( 'Create Course Successfully! Redirecting to course detail...', 'learnpress' );
219 } catch ( Throwable $e ) {
220 $response->message = $e->getMessage();
221 }
222
223 wp_send_json( $response );
224 }
225
226 /**
227 * Generate prompt title with AI
228 */
229 public function openai_generate_prompt() {
230 $response = new LP_REST_Response();
231
232 try {
233 // Check permission
234 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
235 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
236 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
237 }
238
239 $data_str = LP_Request::get_param( 'data' );
240 $params = LP_Helper::json_decode( $data_str, true );
241 $lp_prompt_type = $params['lp-prompt-type'] ?? '';
242
243 switch ( $lp_prompt_type ) {
244 case 'course-description':
245 $prompt = Config::instance()->get( 'prompt-create-description-course', 'settings/openAi', compact( 'params' ) );
246 break;
247 case 'course-title':
248 $prompt = Config::instance()->get( 'prompt-create-title-course', 'settings/openAi', compact( 'params' ) );
249 break;
250 case 'course-image':
251 $prompt = Config::instance()->get( 'prompt-create-image-course', 'settings/openAi', compact( 'params' ) );
252 break;
253 case 'course-curriculum':
254 $prompt = Config::instance()->get( 'prompt-curriculum-course', 'settings/openAi', compact( 'params' ) );
255 break;
256 case $lp_prompt_type:
257 $prompt = apply_filters( 'lp-prompt-type', '', $lp_prompt_type, $params );
258 break;
259 default:
260 $prompt = '';
261 break;
262 }
263
264 $response->data = $prompt;
265 $response->status = 'success';
266 $response->message = __( 'Generate prompt successfully!', 'learnpress' );
267 } catch ( Throwable $e ) {
268 $response->message = $e->getMessage();
269 }
270
271 wp_send_json( $response );
272 }
273
274 /**
275 * Generate data course with prompt submitted
276 */
277 public function openai_generate_data() {
278 $response = new LP_REST_Response();
279
280 try {
281 // Check permission
282 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
283 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
284 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
285 }
286
287 $data_str = LP_Request::get_param( 'data' );
288 $params = LP_Helper::json_decode( $data_str, true );
289 $prompt = $params['lp-openai-prompt-generated-field'] ?? '';
290 $args = [
291 'prompt' => $prompt,
292 ];
293
294 $result = OpenAiService::instance()->send_request( $args );
295 $lp_structure_data = $result['lp_structure_data'] ?? [];
296 $result['lp_html_preview'] = '';
297 if ( count( $lp_structure_data ) > 0 ) {
298 $lp_prompt_type = $params['lp-prompt-type'] ?? '';
299 switch ( $lp_prompt_type ) {
300 case 'course-description':
301 case 'course-title':
302 $results = $lp_structure_data[0];
303 if ( isset( $results['results'] ) ) {
304 $results = $results['results'];
305 } else {
306 throw new Exception(
307 __(
308 'Error: No data was generated. The requested data may be large, increase the Max Tokens in settings and try again.',
309 'learnpress'
310 )
311 );
312 }
313
314 foreach ( $results as $index => $data_item ) {
315 $data_item = $data_item['item'] ?? '';
316 $args = [
317 'index' => $index,
318 'value' => $data_item,
319 'target-apply' => $params['target-apply'] ?? '',
320 ];
321 $result['lp_html_preview'] .= AdminEditWithAITemplate::instance()->html_list_results( $args );
322 }
323 break;
324 case 'course-curriculum':
325 $result['lp_structure_course'] = $lp_structure_data[0];
326 $result['lp_html_preview'] = AdminEditCourseCurriculumWithAITemplate::html_preview_with_data(
327 $result['lp_structure_course']
328 );
329 break;
330 case $lp_prompt_type:
331 $result['lp_html_preview'] = apply_filters( 'lp-openai-render-data-generated', '', $lp_prompt_type, $lp_structure_data );
332 break;
333 default:
334 break;
335 }
336 }
337
338 $result['lp_html_preview'] .= sprintf(
339 '<input type="hidden" name="lp-openai-generated-data" value="%s" />',
340 Template::convert_data_to_json( $lp_structure_data )
341 );
342
343 $response->data = $result;
344 $response->status = 'success';
345 $response->message = __( 'Generate course successfully!', 'learnpress' );
346 } catch ( Throwable $e ) {
347 $response->message = $e->getMessage();
348 }
349
350 wp_send_json( $response );
351 }
352
353 /**
354 * Generate image with prompt submitted
355 * Send data to Open AI to generate image
356 *
357 * @since 4.3.0
358 * @version 1.0.0
359 */
360 public function openai_generate_image() {
361 $response = new LP_REST_Response();
362
363 try {
364 // Check permission
365 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
366 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
367 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
368 }
369
370 $data_str = LP_Request::get_param( 'data' );
371 $params = LP_Helper::json_decode( $data_str, true );
372 $prompt = $params['lp-openai-prompt-generated-field'] ?? '';
373 $args = [
374 'prompt' => $prompt,
375 'n' => intval( $params['outputs'] ?? 1 ),
376 'size' => '1024x1024',
377 ];
378
379 $result = OpenAiService::instance()->send_request_create_image( $args );
380 $html_image = '';
381 $result['lp_html_preview'] = '';
382 $data = $result['data'] ?? [];
383 if ( ! empty( $data ) ) {
384 $result['lp_html_preview'] = '<div class="lp-ai-images-warp">';
385 foreach ( $data as $index => $data_item ) {
386 $image_base_64 = $data_item['b64_json'] ?? '';
387 $image_url = $data_item['url'] ?? '';
388
389 if ( ! empty( $image_url ) ) {
390 $html_image = sprintf(
391 '<img src="%s" alt="AI Generated Image" />',
392 esc_url( $image_url )
393 );
394 } elseif ( ! empty( $image_base_64 ) ) {
395 $html_image = sprintf(
396 '<img src="data:image/png;base64,%s" alt="AI Generated Image" />',
397 esc_attr( $image_base_64 )
398 );
399 }
400
401 if ( empty( $html_image ) ) {
402 continue;
403 }
404
405 $result['lp_html_preview'] .= '<div class="lp-ai-image-item">';
406 $result['lp_html_preview'] .= $html_image;
407 $result['lp_html_preview'] .= sprintf(
408 '<button class="lp-btn-ai-apply-image lp-button" type="button"
409 data-send="%s">%s
410 </button>',
411 Template::convert_data_to_json(
412 [
413 'action' => 'openai_apply_image_feature',
414 'image-url' => ! empty( $image_url ) ? $image_url : '',
415 'image-base64' => ! empty( $image_base_64 ) ? $image_base_64 : '',
416 'id_url' => 'apply-image-feature',
417 ]
418 ),
419 __( 'Apply Image', 'learnpress' )
420 );
421 $result['lp_html_preview'] .= '</div>';
422 }
423 $result['lp_html_preview'] .= '</div>';
424 }
425
426 $response->data = $result;
427 $response->status = 'success';
428 $response->message = __( 'Generate image successfully!', 'learnpress' );
429 } catch ( Throwable $e ) {
430 $response->message = $e->getMessage();
431 }
432
433 wp_send_json( $response );
434 }
435
436 /**
437 * Apply image feature to post
438 * Upload image to media and set as feature image for post
439 *
440 * @since 4.3.0
441 * @version 1.0.2
442 */
443 public function openai_apply_image_feature() {
444 $response = new LP_REST_Response();
445
446 try {
447 set_time_limit( 0 );
448 // Check permission
449 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
450 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
451 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
452 }
453
454 $data_str = $_POST['data'] ?? '';
455 $params = LP_Helper::json_decode( wp_unslash( $data_str ), true );
456 $image_base64 = $params['image-base64'] ?? '';
457 $image_url = $params['image-url'] ?? '';
458
459 $params = LP_Helper::sanitize_params_submitted( $params );
460 $post_id = $params['post-id'] ?? '';
461 $post_title = $params['post-title'] ?? uniqid();
462 $post_slug = sanitize_title( $post_title );
463
464 if ( empty( $post_id ) ) {
465 throw new Exception( __( 'Invalid post ID.', 'learnpress' ) );
466 }
467
468 // Check permission
469 $post_type = get_post_type( $post_id );
470 if ( $post_type === LP_COURSE_CPT ) {
471 $coursePostModel = CoursePostModel::find( $post_id, true );
472 if ( ! $coursePostModel ) {
473 throw new Exception( __( 'Invalid course ID.', 'learnpress' ) );
474 }
475
476 if ( ! $coursePostModel->check_capabilities_update() ) {
477 throw new Exception(
478 __( 'You do not have permission to perform this action.', 'learnpress' )
479 );
480 }
481 } else {
482 $course_item_types = CourseModel::item_types_support();
483 if ( ! in_array( $post_type, $course_item_types ) ) {
484 throw new Exception( __( 'Invalid post type.', 'learnpress' ) );
485 }
486
487 $postModel = PostModel::find_by_id( $post_id, true );
488 $postModel->check_capabilities_update_item_course();
489 }
490
491 if ( ! function_exists( 'media_handle_sideload' ) ) {
492 require_once ABSPATH . 'wp-admin/includes/media.php';
493 require_once ABSPATH . 'wp-admin/includes/file.php';
494 require_once ABSPATH . 'wp-admin/includes/image.php';
495 }
496
497 // model gpt-image-1 only return base64, so don't need to download from url
498 if ( ! empty( $image_base64 ) ) {
499 $decoded_image = base64_decode( $image_base64 );
500 if ( false === $decoded_image || '' === $decoded_image ) {
501 throw new Exception( __( 'Invalid image data.', 'learnpress' ) );
502 }
503
504 $image_info = @getimagesizefromstring( $decoded_image );
505 if ( false === $image_info ) {
506 throw new Exception( __( 'Decoded data is not a valid image.', 'learnpress' ) );
507 }
508
509 $tmp = wp_tempnam();
510 $lp_wp_filesystem = LP_WP_Filesystem::instance();
511 $put_contents_result = $lp_wp_filesystem->put_contents( $tmp, $decoded_image );
512 if ( ! $put_contents_result || ! is_readable( $tmp ) ) {
513 throw new Exception( __( 'Decoded image is not readable.', 'learnpress' ) );
514 }
515 $filename = sanitize_file_name( $post_slug . '-' . uniqid() . '.png' );
516 } else {
517 throw new Exception( __( 'No image data provided.', 'learnpress' ) );
518 }
519
520 $file_array = [
521 'name' => $filename,
522 'tmp_name' => $tmp,
523 ];
524 $attachment_id = media_handle_sideload( $file_array, $post_id );
525
526 if ( ! is_wp_error( $attachment_id ) ) {
527 set_post_thumbnail( $post_id, $attachment_id );
528 } else {
529 throw new Exception( $attachment_id->get_error_message() );
530 }
531
532 $args = [
533 'src' => wp_get_attachment_url( $attachment_id ),
534 'post-id' => $post_id,
535 'attachment-id' => $attachment_id,
536 ];
537
538 $response->data->html_image = AdminEditWithAITemplate::instance()->html_feature_image_created( $args );
539 $response->data->attachment_id = $attachment_id;
540 $response->status = 'success';
541 $response->message = __( 'Apply image successfully!', 'learnpress' );
542 } catch ( Throwable $e ) {
543 $response->message = $e->getMessage();
544 }
545
546 set_time_limit( LearnPress::$time_limit_default_of_sever );
547
548 wp_send_json( $response );
549 }
550 }
551