diff --git a/mod/glossary/classes/ai/mod_assist_info.php b/mod/glossary/classes/ai/mod_assist_info.php new file mode 100644 index 0000000000000..50288548855d4 --- /dev/null +++ b/mod/glossary/classes/ai/mod_assist_info.php @@ -0,0 +1,160 @@ +. + +namespace mod_glossary\ai; + +use aiplacement_modassist\action_process_response; +use context; +use core_ai\aiactions\base as action_base; + +/** + * Class mod_assist_info. + * + * @package mod_glossary + * @copyright 2024 Laurent David + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class mod_assist_info extends \aiplacement_modassist\mod_assist_info { + /** + * Get the list of actions that are available for this placement. + * + * @return array + */ + public function get_base_action_list(): array { + return [ + \core_ai\aiactions\generate_text::class, + ]; + } + + /** + * Add the form definitions for the action. + * + * @param \MoodleQuickForm $mform + * @param string $action + * @return void + * @throws \coding_exception + */ + public function add_action_form_definitions(\MoodleQuickForm $mform, string $action): void { + switch ($action) { + case 'glossary-add-entry': + $this->add_glossary_add_entry_form_definitions($mform); + break; + } + } + + /** + * Add the form definitions for the glossary add entry action. + * + * @param \MoodleQuickForm $mform + * @return void + * @throws \coding_exception + */ + protected function add_glossary_add_entry_form_definitions(\MoodleQuickForm $mform): void { + $mform->addElement('text', + 'topic', + get_string('aiaction:addentries:topic', 'mod_glossary'), ['size' => 50] + ); + $mform->setType('topic', PARAM_TEXT); + $options = array_combine(range(1, 20), range(1, 20)); + $mform->addElement('select', 'itemcount', get_string('aiaction:addentries:itemcount', 'mod_glossary'), $options); + $mform->setDefault('itemcount', 10); + $mform->setType('itemscount', PARAM_INT); + } + + /** + * Get relevant AI action to retrieve content + * + * @param context $context + * @param string $action + * @param object $actiondata + * @return action_base|null + */ + public function get_ai_action(context $context, string $action, object $actiondata): ?action_base { + global $DB; + $cm = get_coursemodule_from_id('glossary', $context->instanceid); + $entries = $DB->get_records_sql("SELECT e.*, u.firstname, u.lastname, u.email, u.picture + FROM {glossary} g, {glossary_entries} e, {user} u + WHERE g.id = ? + AND e.glossaryid = g.id + ORDER BY e.timemodified ASC", [$cm->instance]); + switch ($action) { + case 'glossary-add-entry': + $prompttext = $this->get_system_instructions($action) . "\n"; + $existingentries = join(",", array_column($entries, 'concept')); + $prompttext .= "Existing entries: $existingentries\n"; + $prompttext .= "Number of entries to create: " . $actiondata->itemcount . "\n"; + $prompttext .= "Topic is:" . $actiondata->topic . "\n"; + $action = new \core_ai\aiactions\generate_text( + contextid: $context->id, + userid: $actiondata->userid, + prompttext: $prompttext, + ); + return $action; + } + return null; + } + + /** + * Get system instructions for the action. + * + * @param string $action + * @return string + */ + protected function get_system_instructions(string $action): string { + switch ($action) { + case 'glossary-add-entry': + return get_string('aiaction:addentries:instructions', 'mod_glossary'); + } + return ''; + } + + /** + * Process action response + * + * @param context $context + * @param string $action + * @param string $generatedcontent + * @return action_process_response|null + */ + public function process_response(context $context, string $action, + string $generatedcontent): ?action_process_response { + global $DB, $USER; + $cm = get_coursemodule_from_id('glossary', $context->instanceid); + switch ($action) { + case 'glossary-add-entry': + $newentries = explode("\n", $generatedcontent); + // Parse as csv. + foreach ($newentries as $entry) { + $entry = str_getcsv($entry, ";"); + $entryobj = new \stdClass(); + $entryobj->concept = trim($entry[0]); + $entryobj->definition = trim($entry[1]); + $entryobj->glossaryid = $cm->instance; + $entryobj->userid = $USER->id; + $entryobj->timecreated = time(); + $entryobj->timemodified = time(); + $DB->insert_record('glossary_entries', $entryobj); + } + return new action_process_response( + success:true, + actionname: $action, + successmessage: get_string('aiaction:addentries:success', 'mod_glossary', count($newentries)) + ); + } + return null; + } + +} \ No newline at end of file diff --git a/mod/glossary/classes/ai/output/assist_actions.php b/mod/glossary/classes/ai/output/assist_actions.php new file mode 100644 index 0000000000000..1dc39520a98f0 --- /dev/null +++ b/mod/glossary/classes/ai/output/assist_actions.php @@ -0,0 +1,40 @@ +. + +namespace mod_glossary\ai\output; + +use core\output\renderer_base; + +/** + * Class mod_assist_widget. + * + * @package aiplacement_modassist + * @copyright 2024 Laurent David + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class assist_actions implements \renderable, \templatable { + public function export_for_template(renderer_base $output) { + return [ + 'actions' => [ + [ + 'action' => 'glossary-add-entry', + 'title' => get_string('aiaction:addentries', 'mod_glossary'), + 'description' => get_string('aiaction:addentries:description', 'mod_glossary'), + ], + ], + ]; + } +} diff --git a/mod/glossary/classes/output/standard_action_bar.php b/mod/glossary/classes/output/standard_action_bar.php index d6edaa3f032db..8afd47a40dc0d 100644 --- a/mod/glossary/classes/output/standard_action_bar.php +++ b/mod/glossary/classes/output/standard_action_bar.php @@ -16,8 +16,8 @@ namespace mod_glossary\output; -use moodle_url; use context_module; +use moodle_url; use renderable; use renderer_base; use single_button; @@ -75,8 +75,8 @@ class standard_action_bar implements renderable, templatable { * @throws \coding_exception */ public function __construct(object $cm, object $module, object $displayformat, string $mode, string $hook, - string $sortkey, string $sortorder, int $offset, int $pagelimit, int $fullsearch, - string $tab, string $defaulttab) { + string $sortkey, string $sortorder, int $offset, int $pagelimit, int $fullsearch, + string $tab, string $defaulttab) { $this->cm = $cm; $this->module = $module; $this->displayformat = $displayformat; @@ -105,12 +105,31 @@ public function __construct(object $cm, object $module, object $displayformat, s public function export_for_template(renderer_base $output) { return [ 'addnewbutton' => $this->create_add_button($output), + 'aimodassistinfo' => \aiplacement_modassist\output\assist_ui::get_action_buttons( + context_module::instance($this->cm->id) + ), 'searchbox' => $this->create_search_box(), 'tools' => $this->get_additional_tools($output), 'tabjumps' => $this->generate_tab_jumps($output) ]; } + /** + * Render the add entry button + * + * @param renderer_base $output + * @return \stdClass|null + */ + private function create_add_button(renderer_base $output): ?\stdClass { + if (!has_capability('mod/glossary:write', $this->context)) { + return null; + } + $btn = new single_button(new moodle_url('/mod/glossary/edit.php', ['cmid' => $this->cm->id]), + get_string('addsingleentry', 'glossary'), 'post', single_button::BUTTON_PRIMARY); + + return $btn->export_for_template($output); + } + /** * Render the search box with the checkbox * @@ -149,22 +168,6 @@ private function create_search_box(): array { return $data; } - /** - * Render the add entry button - * - * @param renderer_base $output - * @return \stdClass|null - */ - private function create_add_button(renderer_base $output): ?\stdClass { - if (!has_capability('mod/glossary:write', $this->context)) { - return null; - } - $btn = new single_button(new moodle_url('/mod/glossary/edit.php', ['cmid' => $this->cm->id]), - get_string('addsingleentry', 'glossary'), 'post', single_button::BUTTON_PRIMARY); - - return $btn->export_for_template($output); - } - /** * Render the additional tools required by the glossary * @@ -195,12 +198,12 @@ private function get_additional_tools(renderer_base $output): array { if (has_capability('mod/glossary:manageentries', $this->context) or $this->module->allowprintview) { $params = array( - 'id' => $this->cm->id, - 'mode' => $this->mode, - 'hook' => $this->hook, - 'sortkey' => $this->sortkey, + 'id' => $this->cm->id, + 'mode' => $this->mode, + 'hook' => $this->hook, + 'sortkey' => $this->sortkey, 'sortorder' => $this->sortorder, - 'offset' => $this->offset, + 'offset' => $this->offset, 'pagelimit' => $this->pagelimit ); $printurl = new moodle_url('/mod/glossary/print.php', $params); @@ -209,8 +212,8 @@ private function get_additional_tools(renderer_base $output): array { } if (!empty($CFG->enablerssfeeds) && !empty($CFG->glossary_enablerssfeeds) - && $this->module->rsstype && $this->module->rssarticles - && has_capability('mod/glossary:view', $this->context)) { + && $this->module->rsstype && $this->module->rssarticles + && has_capability('mod/glossary:view', $this->context)) { require_once("$CFG->libdir/rsslib.php"); $string = get_string('rssfeed', 'glossary'); $url = new moodle_url(rss_get_url($this->context->id, $USER->id, 'mod_glossary', $this->cm->instance)); diff --git a/mod/glossary/lang/en/glossary.php b/mod/glossary/lang/en/glossary.php index 308cf35acf2e3..bfbcaff0dd924 100644 --- a/mod/glossary/lang/en/glossary.php +++ b/mod/glossary/lang/en/glossary.php @@ -28,6 +28,15 @@ $string['addentry'] = 'Add a new entry'; $string['addsingleentry'] = 'Add entry'; $string['addingcomment'] = 'Add a comment'; +$string['aiaction:addentries'] = 'Add entries'; +$string['aiaction:addentries:description'] = 'Add entries to the glossary'; +$string['aiaction:addentries:instructions'] = 'You should provide a set of new entries to the glossary on the specified topic. +The format of the entries should be as follows (csv): "term";"definition". Each entry should be separated by a new line. +You should ignore existing entries.'; +$string['aiaction:addentries:itemcount'] = 'Number of entries'; +$string['aiaction:addentries:success'] = '{$a} entries have been added successfully'; +$string['aiaction:addentries:topic'] = 'Topic of the entries'; +$string['aiaction:addentries:topic_helper'] = 'Write a simple description of the topic the entries should be about...';; $string['alias'] = 'Keyword'; $string['aliases'] = 'Keyword(s)'; $string['aliases_help'] = 'Each glossary entry can have an associated list of keywords (or aliases). If the entry is auto-linked, then any keywords will also be auto-linked. @@ -343,3 +352,4 @@ // Deprecated since 4.5. $string['tagsdeleted'] = 'Glossary tags have been deleted'; + diff --git a/mod/glossary/templates/standard_action_menu.mustache b/mod/glossary/templates/standard_action_menu.mustache index 0457a105b5444..476a26f66d87d 100644 --- a/mod/glossary/templates/standard_action_menu.mustache +++ b/mod/glossary/templates/standard_action_menu.mustache @@ -123,7 +123,9 @@ {{> core/single_button }} {{/addnewbutton}} - + {{#aimodassistinfo}} + {{> aiplacement_modassist/action_buttons}} + {{/aimodassistinfo}}
{{#tools}} {{#button}}