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