diff --git a/main/lp/LpAiHelper.php b/main/lp/LpAiHelper.php new file mode 100644 index 0000000000..86ccaad66b --- /dev/null +++ b/main/lp/LpAiHelper.php @@ -0,0 +1,89 @@ +addElement('header', get_lang('LpAiGenerator')); + $form->addElement('text', 'lp_name', [get_lang('LpAiTopic'), get_lang('LpAiTopicHelp')]); + $form->addRule('lp_name', get_lang('ThisFieldIsRequired'), 'required'); + $form->addElement('number', 'nro_items', [get_lang('LpAiNumberOfItems'), get_lang('LpAiNumberOfItemsHelper')]); + $form->addRule('nro_items', get_lang('ThisFieldIsRequired'), 'required'); + $form->addElement('number', 'words_count', [get_lang('LpAiWordsCount'), get_lang('LpAiWordsCountHelper')]); + $form->addRule('words_count', get_lang('ThisFieldIsRequired'), 'required'); + + $generateUrl = api_get_path(WEB_PLUGIN_PATH).'ai_helper/tool/learnpath.php'; + $language = api_get_interface_language(); + $courseCode = api_get_course_id(); + $sessionId = api_get_session_id(); + $redirectSuccess = api_get_path(WEB_CODE_PATH).'lp/lp_controller.php?'.api_get_cidreq().'&action=add_item&type=step&isStudentView=false&lp_id='; + $form->addHtml(''); + + $form->addButton( + 'create_lp_button', + get_lang('CreateLp'), + '', + 'default', + 'default', + null, + ['id' => 'create-lp-ai'] + ); + + echo $form->returnForm(); + } +} diff --git a/main/lp/lp_add_ai_helper.php b/main/lp/lp_add_ai_helper.php new file mode 100644 index 0000000000..ca89cb67ce --- /dev/null +++ b/main/lp/lp_add_ai_helper.php @@ -0,0 +1,28 @@ + 'lp_controller.php?action=list&'.api_get_cidreq(), + 'name' => get_lang('LearningPaths'), +]; + +Display::display_header(get_lang('CreateLpWithAiHelper'), 'Learnpath'); + +echo '
'; +echo ''. + Display::return_icon( + 'back.png', + get_lang('ReturnToLearningPaths'), + '', + ICON_SIZE_MEDIUM + ).''; +echo '
'; + +$aiHelper = new LpAiHelper(); + +$aiHelper->aiHelperForm(); + +Display::display_footer(); diff --git a/main/lp/lp_controller.php b/main/lp/lp_controller.php index 95fc1281dd..7281a08ab0 100755 --- a/main/lp/lp_controller.php +++ b/main/lp/lp_controller.php @@ -738,6 +738,12 @@ switch ($action) { } require 'lp_add_category.php'; break; + case 'ai_helper': + if (!$is_allowed_to_edit) { + api_not_allowed(true); + } + require 'lp_add_ai_helper.php'; + break; case 'move_up_category': if (!$is_allowed_to_edit) { api_not_allowed(true); diff --git a/main/lp/lp_list.php b/main/lp/lp_list.php index bfcaa1f633..7122d694c8 100755 --- a/main/lp/lp_list.php +++ b/main/lp/lp_list.php @@ -122,6 +122,19 @@ if ($is_allowed_to_edit) { api_get_self().'?'.api_get_cidreq().'&action=add_lp_category' ); } + + if ('true' === api_get_plugin_setting('ai_helper', 'tool_enable')) { + $actionLeft .= Display::url( + Display::return_icon( + 'help.png', + get_lang('CreateLpWithAiHelper'), + [], + ICON_SIZE_MEDIUM + ), + api_get_self().'?'.api_get_cidreq().'&action=ai_helper' + ); + } + $actions = Display::toolbarAction('actions-lp', [$actionLeft]); } diff --git a/plugin/ai_helper/AiHelperPlugin.php b/plugin/ai_helper/AiHelperPlugin.php index 690dca32e5..d35dc1aa34 100644 --- a/plugin/ai_helper/AiHelperPlugin.php +++ b/plugin/ai_helper/AiHelperPlugin.php @@ -45,6 +45,46 @@ class AiHelperPlugin extends Plugin return $list; } + /** + * Get the completion text from openai. + * + * @return string + */ + public function openAiGetCompletionText(string $prompt) + { + require_once __DIR__.'/src/openai/OpenAi.php'; + + $apiKey = $this->get('api_key'); + $organizationId = $this->get('organization_id'); + + $ai = new OpenAi($apiKey, $organizationId); + + $temperature = 0.2; + $model = 'text-davinci-003'; + $maxTokens = 2000; + $frequencyPenalty = 0; + $presencePenalty = 0.6; + $topP = 1.0; + + $complete = $ai->completion([ + 'model' => $model, + 'prompt' => $prompt, + 'temperature' => $temperature, + 'max_tokens' => $maxTokens, + 'frequency_penalty' => $frequencyPenalty, + 'presence_penalty' => $presencePenalty, + 'top_p' => $topP, + ]); + + $result = json_decode($complete, true); + $resultText = ''; + if (!empty($result['choices'])) { + $resultText = trim($result['choices'][0]['text']); + } + + return $resultText; + } + /** * Get the plugin directory name. */ diff --git a/plugin/ai_helper/tool/learnpath.php b/plugin/ai_helper/tool/learnpath.php new file mode 100644 index 0000000000..e9d4dce22a --- /dev/null +++ b/plugin/ai_helper/tool/learnpath.php @@ -0,0 +1,104 @@ +getApiList(); +$apiName = $plugin->get('api_name'); + +if (!in_array($apiName, array_keys($apiList))) { + throw new Exception("Ai API is not available for this request."); +} + +switch ($apiName) { + case AiHelperPlugin::OPENAI_API: + + $courseLanguage = (string) $_REQUEST['language']; + $chaptersCount = (int) $_REQUEST['nro_items']; + $topic = (string) $_REQUEST['lp_name']; + $wordsCount = (int) $_REQUEST['words_count']; + $courseCode = (string) $_REQUEST['course_code']; + $sessionId = (int) $_REQUEST['session_id']; + + $messageGetItems = 'Generate the table of contents of a course in "%s" in %d or less chapters on the topic of "%s" in a list separated with comma, without chapter number'; + $prompt = sprintf($messageGetItems, $courseLanguage, $chaptersCount, $topic); + $resultText = $plugin->openAiGetCompletionText($prompt); + $lpItems = []; + if (!empty($resultText)) { + $items = explode(',', $resultText); + $position = 1; + foreach ($items as $item) { + $explodedItem = preg_split('/\d\./', $item); + $title = count($explodedItem) > 1 ? $explodedItem[1] : $explodedItem[0]; + if (!empty($title)) { + $lpItems[$position]['title'] = trim($title); + $messageGetItemContent = 'In the context of "%s", generate a document with HTML tags in "%s" with %d words of content or less, about "%s"'; + $promptItem = sprintf($messageGetItemContent, $topic, $courseLanguage, $wordsCount, $title); + $resultContentText = $plugin->openAiGetCompletionText($promptItem); + if (!empty($resultContentText)) { + $lpItems[$position]['content'] = trim($resultContentText); + } + $position++; + } + } + } + + // Create the learnpath and return the id generated. + $return = ['success' => false, 'lp_id' => 0]; + if (!empty($lpItems)) { + $lpId = learnpath::add_lp( + $courseCode, + $topic, + '', + 'chamilo', + 'manual' + ); + + if (!empty($lpId)) { + learnpath::toggle_visibility($lpId, 0); + $courseInfo = api_get_course_info($courseCode); + $lp = new \learnpath( + $courseCode, + $lpId, + api_get_user_id() + ); + $lp->generate_lp_folder($courseInfo, $topic); + + foreach ($lpItems as $dspOrder => $item) { + $documentId = $lp->create_document( + $courseInfo, + $item['content'], + $item['title'], + 'html' + ); + + if (!empty($documentId)) { + $lpItemId = $lp->add_item( + 0, + 0, + 'document', + $documentId, + $item['title'], + '', + 0, + 0, + api_get_user_id(), + $dspOrder + ); + } + } + } + $return = [ + 'success' => true, + 'lp_id' => $lpId, + ]; + } + echo json_encode($return); + break; +}