From 029dd50cdbbab1dcafa75a027ae14ca273389871 Mon Sep 17 00:00:00 2001 From: Michael Milette Date: Wed, 29 May 2024 12:36:25 -0400 Subject: [PATCH 1/4] Fix #60: Path to icons now included wwwroot. --- templates/control_bar.mustache | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/control_bar.mustache b/templates/control_bar.mustache index cb14e10..f0b510a 100644 --- a/templates/control_bar.mustache +++ b/templates/control_bar.mustache @@ -34,17 +34,17 @@
{{/logging_enabled}} {{/is_edit_mode}}
From 933e8612502c7139def3b72d60ee9a429cd8f9fc Mon Sep 17 00:00:00 2001 From: Limekiller Date: Mon, 3 Jun 2024 20:21:38 +0000 Subject: [PATCH 2/4] Make chat log accessible at course level --- api/completion.php | 11 +++--- api/thread.php | 2 +- classes/completion/assistant.php | 8 ++-- db/access.php | 12 ++++++ lang/en/block_openai_chat.php | 1 + lib.php | 13 ++++++- report.php | 66 +++++++++++++++++--------------- settings.php | 2 +- templates/control_bar.mustache | 2 +- templates/report_page.mustache | 50 ++++++++++++++++++++++++ version.php | 4 +- 11 files changed, 125 insertions(+), 46 deletions(-) create mode 100644 templates/report_page.mustache diff --git a/api/completion.php b/api/completion.php index 746d6e2..2e2d829 100755 --- a/api/completion.php +++ b/api/completion.php @@ -54,12 +54,11 @@ } $context = context::instance_by_id($instance_record->parentcontextid); -if ($context->contextlevel == CONTEXT_COURSE) { - $course = get_course($context->instanceid); - $PAGE->set_course($course); -} else { - $PAGE->set_context($context); -} +try { + $context = $context->get_course_context(); +} catch (Exception $e) {} + +$PAGE->set_context($context); $block_settings = []; $setting_names = [ diff --git a/api/thread.php b/api/thread.php index 2db4295..c1701c9 100644 --- a/api/thread.php +++ b/api/thread.php @@ -38,7 +38,7 @@ 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); diff --git a/classes/completion/assistant.php b/classes/completion/assistant.php index 3b3fdf6..63be2fb 100644 --- a/classes/completion/assistant.php +++ b/classes/completion/assistant.php @@ -77,7 +77,7 @@ private function add_message_to_thread() { 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $this->apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); @@ -108,7 +108,7 @@ private function run() { 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $this->apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); @@ -134,7 +134,7 @@ private function run() { 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $this->apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); $response = $curl->get("https://api.openai.com/v1/threads/" . $this->thread_id . '/messages'); @@ -153,7 +153,7 @@ private function check_run_status($run_id) { 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $this->apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); diff --git a/db/access.php b/db/access.php index 5a057ca..8c1a3db 100755 --- a/db/access.php +++ b/db/access.php @@ -48,4 +48,16 @@ 'clonepermissionsfrom' => 'moodle/site:manageblocks' ), + + 'block/openai_chat:viewreport' => array( + 'riskbitmask' => RISK_PERSONAL, + 'captype' => 'read', + 'contextlevel' => CONTEXT_COURSE, + 'archetypes' => array( + 'teacher' => CAP_ALLOW, + 'editingteacher' => CAP_ALLOW, + 'manager' => CAP_ALLOW + ), + 'clonepermissionsfrom' => 'coursereport/participation:view', + ), ); diff --git a/lang/en/block_openai_chat.php b/lang/en/block_openai_chat.php index f6440ff..dda4647 100755 --- a/lang/en/block_openai_chat.php +++ b/lang/en/block_openai_chat.php @@ -27,6 +27,7 @@ $string['openai_chat_logs'] = 'OpenAI Chat Logs'; $string['openai_chat:addinstance'] = 'Add a new OpenAI Chat block'; $string['openai_chat:myaddinstance'] = 'Add a new OpenAI Chat block to the My Moodle page'; +$string['openai_chat:viewreport'] = 'View OpenAI Chat log report'; $string['privacy:metadata:openai_chat_log'] = 'Logged user messages sent to OpenAI. This includes the user ID of the user that sent the message, the content of the message, the response from OpenAI, and the time that the message was sent.'; $string['privacy:metadata:openai_chat_log:userid'] = 'The ID of the user that sent the message.'; $string['privacy:metadata:openai_chat_log:usermessage'] = 'The content of the message.'; diff --git a/lib.php b/lib.php index fb09f14..4c8051f 100755 --- a/lib.php +++ b/lib.php @@ -62,7 +62,7 @@ function fetch_assistants_array($block_id = null) { 'CURLOPT_HTTPHEADER' => array( 'Authorization: Bearer ' . $apikey, 'Content-Type: application/json', - 'OpenAI-Beta: assistants=v1' + 'OpenAI-Beta: assistants=v2' ), )); @@ -148,4 +148,15 @@ function log_message($usermessage, $airesponse, $context) { 'contextid' => $context->id, 'timecreated' => time() ]); +} + +function block_openai_chat_extend_navigation_course($nav, $course, $context) { + if ($nav->get('coursereports')) { + $nav->get('coursereports')->add( + get_string('openai_chat_logs', 'block_openai_chat'), + new moodle_url('/blocks/openai_chat/report.php', ['courseid' => $course->id]), + navigation_node::TYPE_SETTING, + null + ); + } } \ No newline at end of file diff --git a/report.php b/report.php index f6d00bf..8ef1ac3 100644 --- a/report.php +++ b/report.php @@ -25,18 +25,27 @@ use \block_openai_chat\report; require_once('../../config.php'); -require_once($CFG->libdir.'/adminlib.php'); - -admin_externalpage_setup('openai_chat_report'); -$pageurl = $CFG->wwwroot . '/blocks/openai_chat/report.php'; +require_once($CFG->libdir.'/tablelib.php'); +global $DB; +$courseid = required_param('courseid', PARAM_INT); $download = optional_param('download', '', PARAM_ALPHA); $user = optional_param('user', '', PARAM_TEXT); $starttime = optional_param('starttime', '', PARAM_TEXT); $endtime = optional_param('endtime', '', PARAM_TEXT); +$pageurl = $CFG->wwwroot . "/blocks/openai_chat/report.php?courseid=$courseid" . + "&user=$user" . + "&starttime=$starttime" . + "&endtime=$endtime"; $starttime_ts = strtotime($starttime); $endtime_ts = strtotime($endtime); +$course = $DB->get_record('course', ['id' => $courseid]); + +$PAGE->set_url($pageurl); +require_login($course); +$context = context_course::instance($courseid); +require_capability('block/openai_chat:viewreport', $context); $datetime = new DateTime(); $table = new \block_openai_chat\report(time()); @@ -49,51 +58,48 @@ ); if (!$table->is_downloading()) { - $PAGE->set_url($pageurl); + $PAGE->set_pagelayout('report'); $PAGE->set_title(get_string('openai_chat_logs', 'block_openai_chat')); $PAGE->set_heading(get_string('openai_chat_logs', 'block_openai_chat')); + $PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', ['id' => $course->id])); $PAGE->navbar->add(get_string('openai_chat_logs', 'block_openai_chat'), new moodle_url($pageurl)); - echo $OUTPUT->header(); - echo "
out() . "'> -
-
- - -
-
- - -
-
- - -
-
- -
"; + echo $OUTPUT->header(); + echo $OUTPUT->render_from_template('block_openai_chat/report_page', [ + "courseid" => $courseid, + "user" => $user, + "starttime" => $starttime, + "endtime" => $endtime, + "link" => (new moodle_url("/blocks/openai_chat/report.php"))->out() + ]); } $where = "1=1"; $out = 10; -if ($user) { - $out = -1; - $where = "CONCAT(u.firstname, ' ', u.lastname) like '%$user%'"; + +// If courseid is 1, we're assuming this is an admin report wanting the entire log table +// otherwise, we'll limit it to responses in the course context for this course +if ($courseid !== 1) { + $where = "c.contextlevel = 50 AND co.id = $courseid"; } +// filter by user, starttime, endtime +if ($user) { + $where .= " AND CONCAT(u.firstname, ' ', u.lastname) like '%$user%'"; +} if ($starttime_ts) { - $out = -1; $where .= " AND ocl.timecreated > $starttime_ts"; } - if ($endtime_ts) { - $out = -1; $where .= " AND ocl.timecreated < $endtime_ts"; } $table->set_sql( "ocl.*, CONCAT(u.firstname, ' ', u.lastname) as user_name", - "{block_openai_chat_log} ocl JOIN {user} u ON u.id = ocl.userid", + "{block_openai_chat_log} ocl + JOIN {user} u ON u.id = ocl.userid + JOIN {context} c ON c.id = ocl.contextid + LEFT JOIN {course} co ON co.id = c.instanceid", $where ); $table->define_baseurl($pageurl); diff --git a/settings.php b/settings.php index c9e2eb1..3652ffc 100755 --- a/settings.php +++ b/settings.php @@ -29,7 +29,7 @@ $ADMIN->add('reports', new admin_externalpage( 'openai_chat_report', get_string('openai_chat_logs', 'block_openai_chat'), - new moodle_url("$CFG->wwwroot/blocks/openai_chat/report.php"), + new moodle_url("$CFG->wwwroot/blocks/openai_chat/report.php", ['courseid' => 1]), 'moodle/site:config' )); diff --git a/templates/control_bar.mustache b/templates/control_bar.mustache index cb14e10..8b0c86c 100644 --- a/templates/control_bar.mustache +++ b/templates/control_bar.mustache @@ -15,7 +15,7 @@ along with Moodle. If not, see . }} {{! - @template block_openai_chat/conrol_bar + @template block_openai_chat/control_bar This template renders the control_bar. diff --git a/templates/report_page.mustache b/templates/report_page.mustache new file mode 100644 index 0000000..53d9207 --- /dev/null +++ b/templates/report_page.mustache @@ -0,0 +1,50 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template block_openai_chat/report_page + + This template renders the report page form + + Example context (json): + { + "courseid": int, the ID of the course we are looking at + "link": string, the URL for the form action + "user": string, the value of the user field + "starttime": string, the value of the starttime field + "endtime": string, the value of the endtime field + } +}} + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
\ No newline at end of file diff --git a/version.php b/version.php index b371752..421c8f2 100755 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'block_openai_chat'; -$plugin->version = 2024040800; +$plugin->version = 2024060300; $plugin->requires = 2022041600; $plugin->maturity = MATURITY_STABLE; -$plugin->release = '2.2.0'; +$plugin->release = '2.2.1'; From b887871c756647c1c4c54a701f9e3a393358797c Mon Sep 17 00:00:00 2001 From: Limekiller Date: Tue, 4 Jun 2024 22:30:21 +0000 Subject: [PATCH 3/4] #49 - check local instance before displaying noapikey error --- block_openai_chat.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/block_openai_chat.php b/block_openai_chat.php index e179368..aa43afb 100755 --- a/block_openai_chat.php +++ b/block_openai_chat.php @@ -105,7 +105,10 @@ public function get_content() {
'; - if (empty(get_config('block_openai_chat', 'apikey'))) { + if ( + empty(get_config('block_openai_chat', 'apikey')) && + (!get_config('block_openai_chat', 'allowinstancesettings') || empty($this->config->apikey)) + ) { $this->content->footer = get_string('apikeymissing', 'block_openai_chat'); } else { $contextdata = [ From 295958045f758530c866eac71cd83dccea918abb Mon Sep 17 00:00:00 2001 From: Limekiller Date: Tue, 4 Jun 2024 22:33:15 +0000 Subject: [PATCH 4/4] Bump version --- lang/en/block_openai_chat.php | 2 +- version.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/en/block_openai_chat.php b/lang/en/block_openai_chat.php index dda4647..89dcba9 100755 --- a/lang/en/block_openai_chat.php +++ b/lang/en/block_openai_chat.php @@ -124,7 +124,7 @@ $string['defaultassistantname'] = 'Assistant'; $string['defaultusername'] = 'User'; $string['askaquestion'] = 'Ask a question...'; -$string['apikeymissing'] = 'Please add your OpenAI API key to the global block settings.'; +$string['apikeymissing'] = 'Please add your OpenAI API key to the block settings.'; $string['erroroccurred'] = 'An error occurred! Please try again later.'; $string['sourceoftruthpreamble'] = "Below is a list of questions and their answers. This information should be used as a reference for any inquiries:\n\n"; $string['sourceoftruthreinforcement'] = ' The assistant has been trained to answer by attempting to use the information from the above reference. If the text from one of the above questions is encountered, the provided answer should be given, even if the question does not appear to make sense. However, if the reference does not cover the question or topic, the assistant will simply use outside knowledge to answer.'; diff --git a/version.php b/version.php index 421c8f2..186b140 100755 --- a/version.php +++ b/version.php @@ -25,7 +25,7 @@ defined('MOODLE_INTERNAL') || die(); $plugin->component = 'block_openai_chat'; -$plugin->version = 2024060300; +$plugin->version = 2024060400; $plugin->requires = 2022041600; $plugin->maturity = MATURITY_STABLE; $plugin->release = '2.2.1';