diff --git a/amd/build/vertexcachestatus.min.js b/amd/build/vertexcachestatus.min.js new file mode 100644 index 0000000..e4d3f9b --- /dev/null +++ b/amd/build/vertexcachestatus.min.js @@ -0,0 +1,11 @@ +define("local_ai_manager/vertexcachestatus",["exports","core/templates","core/ajax","core/notification","core/str"],(function(_exports,_templates,_ajax,_notification,_str){var obj; +/** + * Module rendering the warning box to inform the users about misleading AI results. + * + * @module local_ai_manager/vertexcachestatus + * @copyright 2024 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,_templates=(obj=_templates)&&obj.__esModule?obj:{default:obj};_exports.init=async selector=>{const statusElement=document.querySelector(selector),refreshButton=statusElement.querySelector('[data-action="refresh"]'),enableCachingButton=statusElement.querySelector('[data-action="enablecaching"]'),disableCachingButton=statusElement.querySelector('[data-action="disablecaching"]'),serviceaccountinfoTextArea=document.getElementById("id_serviceaccountjson");let serviceaccountinfo=serviceaccountinfoTextArea.value;serviceaccountinfoTextArea.addEventListener("input",(event=>{serviceaccountinfo=event.target.value})),refreshButton.addEventListener("click",(async event=>{event.preventDefault(),await updateCachingStatusDisplay(serviceaccountinfo,statusElement)})),enableCachingButton&&enableCachingButton.addEventListener("click",(async event=>{event.preventDefault(),enableCachingButton.disabled=!0,await updateCachingStatus(serviceaccountinfo,statusElement,!0)})),disableCachingButton&&disableCachingButton.addEventListener("click",(async event=>{event.preventDefault(),disableCachingButton.disabled=!0,await updateCachingStatus(serviceaccountinfo,statusElement,!1)}))};const updateCachingStatusDisplay=async(serviceaccountinfo,statusElement)=>{let queryResult=null;try{queryResult=await(serviceaccountinfo=>(0,_ajax.call)([{methodname:"local_ai_manager_vertex_cache_status",args:{serviceaccountinfo:serviceaccountinfo}}])[0])(serviceaccountinfo)}catch(error){return void await(0,_notification.exception)(error)}if(200!==queryResult.code){const errorTitleString=await(0,_str.getString)("vertex_error_cachestatus","local_ai_manager");await(0,_notification.alert)(errorTitleString,queryResult.error)}const templateContext={cachingEnabled:queryResult.cachingEnabled,noStatus:!1},{html:html,js:js}=await _templates.default.renderForPromise("local_ai_manager/vertexcachestatus",templateContext);_templates.default.replaceNode(statusElement,html,js)},updateCachingStatus=async(serviceaccountinfo,statusElement,newstatus)=>{let queryResult=null;try{queryResult=await((serviceaccountinfo,newstatus)=>(0,_ajax.call)([{methodname:"local_ai_manager_vertex_cache_status",args:{serviceaccountinfo:serviceaccountinfo,newstatus:newstatus}}])[0])(serviceaccountinfo,newstatus)}catch(error){return void await(0,_notification.exception)(error)}if(200===queryResult.code)await updateCachingStatusDisplay(serviceaccountinfo,statusElement);else{const errorTitleString=await(0,_str.getString)("vertex_error_cachestatus","local_ai_manager");await(0,_notification.alert)(errorTitleString,queryResult.error)}}})); + +//# sourceMappingURL=vertexcachestatus.min.js.map \ No newline at end of file diff --git a/amd/build/vertexcachestatus.min.js.map b/amd/build/vertexcachestatus.min.js.map new file mode 100644 index 0000000..24cea6f --- /dev/null +++ b/amd/build/vertexcachestatus.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"vertexcachestatus.min.js","sources":["../src/vertexcachestatus.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * Module rendering the warning box to inform the users about misleading AI results.\n *\n * @module local_ai_manager/vertexcachestatus\n * @copyright 2024 ISB Bayern\n * @author Philipp Memmel\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport Templates from 'core/templates';\nimport {call as fetchMany} from 'core/ajax';\nimport {alert as alertModal, exception as displayException} from 'core/notification';\nimport {getString} from 'core/str';\n\n/**\n * Fetches the current cache status of the specified service account.\n *\n * @param {string} serviceaccountinfo the stringified JSON with the service account info\n */\nconst fetchCurrentCacheStatus = (serviceaccountinfo) => fetchMany([{\n methodname: 'local_ai_manager_vertex_cache_status',\n args: {\n serviceaccountinfo\n }\n}])[0];\n\n/**\n * Updates the current cache status.\n *\n * @param {string} serviceaccountinfo the stringified JSON with the service account info\n * @param {boolean} newstatus true if the cache should be enabled, false if it should be disabled\n */\nconst setCurrentCacheStatus = (serviceaccountinfo, newstatus) => fetchMany([{\n methodname: 'local_ai_manager_vertex_cache_status',\n args: {\n serviceaccountinfo,\n newstatus\n }\n}])[0];\n\n/**\n * Controls and renders the Google Vertex AI cache status elements.\n *\n * @param {string} selector the CSS selector of the status element to operate on\n */\nexport const init = async(selector) => {\n const statusElement = document.querySelector(selector);\n const refreshButton = statusElement.querySelector('[data-action=\"refresh\"]');\n const enableCachingButton = statusElement.querySelector('[data-action=\"enablecaching\"]');\n const disableCachingButton = statusElement.querySelector('[data-action=\"disablecaching\"]');\n const serviceaccountinfoTextArea = document.getElementById('id_serviceaccountjson');\n let serviceaccountinfo = serviceaccountinfoTextArea.value;\n // We want to keep track of the current serviceaccountinfo data, also if the user changes it.\n serviceaccountinfoTextArea.addEventListener('input', (event) => {\n serviceaccountinfo = event.target.value;\n });\n\n refreshButton.addEventListener('click', async(event) => {\n event.preventDefault();\n await updateCachingStatusDisplay(serviceaccountinfo, statusElement);\n });\n\n if (enableCachingButton) {\n enableCachingButton.addEventListener('click', async(event) => {\n event.preventDefault();\n enableCachingButton.disabled = true;\n await updateCachingStatus(serviceaccountinfo, statusElement, true);\n });\n }\n if (disableCachingButton) {\n disableCachingButton.addEventListener('click', async(event) => {\n event.preventDefault();\n disableCachingButton.disabled = true;\n await updateCachingStatus(serviceaccountinfo, statusElement, false);\n });\n }\n};\n\n/**\n * Updates the caching status display.\n *\n * @param {string} serviceaccountinfo the stringified JSON with the service account info\n * @param {string} statusElement the HTML element to operate on\n */\nconst updateCachingStatusDisplay = async(serviceaccountinfo, statusElement) => {\n let queryResult = null;\n try {\n queryResult = await fetchCurrentCacheStatus(serviceaccountinfo);\n } catch (error) {\n await displayException(error);\n return;\n }\n if (queryResult.code !== 200) {\n const errorTitleString = await getString('vertex_error_cachestatus', 'local_ai_manager');\n await alertModal(errorTitleString, queryResult.error);\n }\n const templateContext = {\n cachingEnabled: queryResult.cachingEnabled,\n noStatus: false\n };\n\n const {html, js} = await Templates.renderForPromise('local_ai_manager/vertexcachestatus', templateContext);\n Templates.replaceNode(statusElement, html, js);\n};\n\n/**\n * Updates the caching status and updates the DOM to reflect the current state.\n *\n * @param {string} serviceaccountinfo the stringified JSON with the service account info\n * @param {string} statusElement the HTML element to operate on\n * @param {boolean} newstatus the status to set the caching configuration to (true or false)\n */\nconst updateCachingStatus = async(serviceaccountinfo, statusElement, newstatus) => {\n let queryResult = null;\n try {\n queryResult = await setCurrentCacheStatus(serviceaccountinfo, newstatus);\n } catch (error) {\n await displayException(error);\n return;\n }\n if (queryResult.code !== 200) {\n const errorTitleString = await getString('vertex_error_cachestatus', 'local_ai_manager');\n await alertModal(errorTitleString, queryResult.error);\n return;\n }\n await updateCachingStatusDisplay(serviceaccountinfo, statusElement);\n};\n"],"names":["async","statusElement","document","querySelector","selector","refreshButton","enableCachingButton","disableCachingButton","serviceaccountinfoTextArea","getElementById","serviceaccountinfo","value","addEventListener","event","target","preventDefault","updateCachingStatusDisplay","disabled","updateCachingStatus","queryResult","methodname","args","fetchCurrentCacheStatus","error","code","errorTitleString","templateContext","cachingEnabled","noStatus","html","js","Templates","renderForPromise","replaceNode","newstatus","setCurrentCacheStatus"],"mappings":";;;;;;;;8JA4DoBA,MAAAA,iBACVC,cAAgBC,SAASC,cAAcC,UACvCC,cAAgBJ,cAAcE,cAAc,2BAC5CG,oBAAsBL,cAAcE,cAAc,iCAClDI,qBAAuBN,cAAcE,cAAc,kCACnDK,2BAA6BN,SAASO,eAAe,6BACvDC,mBAAqBF,2BAA2BG,MAEpDH,2BAA2BI,iBAAiB,SAAUC,QAClDH,mBAAqBG,MAAMC,OAAOH,SAGtCN,cAAcO,iBAAiB,SAASZ,MAAAA,QACpCa,MAAME,uBACAC,2BAA2BN,mBAAoBT,kBAGrDK,qBACAA,oBAAoBM,iBAAiB,SAASZ,MAAAA,QAC1Ca,MAAME,iBACNT,oBAAoBW,UAAW,QACzBC,oBAAoBR,mBAAoBT,eAAe,MAGjEM,sBACAA,qBAAqBK,iBAAiB,SAASZ,MAAAA,QAC3Ca,MAAME,iBACNR,qBAAqBU,UAAW,QAC1BC,oBAAoBR,mBAAoBT,eAAe,aAWnEe,2BAA6BhB,MAAMU,mBAAoBT,qBACrDkB,YAAc,SAEdA,iBApEyBT,CAAAA,qBAAuB,cAAU,CAAC,CAC/DU,WAAY,uCACZC,KAAM,CACFX,mBAAAA,uBAEJ,GA+DwBY,CAAwBZ,oBAC9C,MAAOa,yBACC,2BAAiBA,UAGF,MAArBJ,YAAYK,KAAc,OACpBC,uBAAyB,kBAAU,2BAA4B,0BAC/D,uBAAWA,iBAAkBN,YAAYI,aAE7CG,gBAAkB,CACpBC,eAAgBR,YAAYQ,eAC5BC,UAAU,IAGRC,KAACA,KAADC,GAAOA,UAAYC,mBAAUC,iBAAiB,qCAAsCN,oCAChFO,YAAYhC,cAAe4B,KAAMC,KAUzCZ,oBAAsBlB,MAAMU,mBAAoBT,cAAeiC,iBAC7Df,YAAc,SAEdA,iBAnFsB,EAACT,mBAAoBwB,aAAc,cAAU,CAAC,CACxEd,WAAY,uCACZC,KAAM,CACFX,mBAAAA,mBACAwB,UAAAA,cAEJ,GA6EwBC,CAAsBzB,mBAAoBwB,WAChE,MAAOX,yBACC,2BAAiBA,UAGF,MAArBJ,YAAYK,WAKVR,2BAA2BN,mBAAoBT,0BAJ3CwB,uBAAyB,kBAAU,2BAA4B,0BAC/D,uBAAWA,iBAAkBN,YAAYI"} \ No newline at end of file diff --git a/amd/src/vertexcachestatus.js b/amd/src/vertexcachestatus.js new file mode 100644 index 0000000..c279271 --- /dev/null +++ b/amd/src/vertexcachestatus.js @@ -0,0 +1,142 @@ +// 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 . + +/** + * Module rendering the warning box to inform the users about misleading AI results. + * + * @module local_ai_manager/vertexcachestatus + * @copyright 2024 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +import Templates from 'core/templates'; +import {call as fetchMany} from 'core/ajax'; +import {alert as alertModal, exception as displayException} from 'core/notification'; +import {getString} from 'core/str'; + +/** + * Fetches the current cache status of the specified service account. + * + * @param {string} serviceaccountinfo the stringified JSON with the service account info + */ +const fetchCurrentCacheStatus = (serviceaccountinfo) => fetchMany([{ + methodname: 'local_ai_manager_vertex_cache_status', + args: { + serviceaccountinfo + } +}])[0]; + +/** + * Updates the current cache status. + * + * @param {string} serviceaccountinfo the stringified JSON with the service account info + * @param {boolean} newstatus true if the cache should be enabled, false if it should be disabled + */ +const setCurrentCacheStatus = (serviceaccountinfo, newstatus) => fetchMany([{ + methodname: 'local_ai_manager_vertex_cache_status', + args: { + serviceaccountinfo, + newstatus + } +}])[0]; + +/** + * Controls and renders the Google Vertex AI cache status elements. + * + * @param {string} selector the CSS selector of the status element to operate on + */ +export const init = async(selector) => { + const statusElement = document.querySelector(selector); + const refreshButton = statusElement.querySelector('[data-action="refresh"]'); + const enableCachingButton = statusElement.querySelector('[data-action="enablecaching"]'); + const disableCachingButton = statusElement.querySelector('[data-action="disablecaching"]'); + const serviceaccountinfoTextArea = document.getElementById('id_serviceaccountjson'); + let serviceaccountinfo = serviceaccountinfoTextArea.value; + // We want to keep track of the current serviceaccountinfo data, also if the user changes it. + serviceaccountinfoTextArea.addEventListener('input', (event) => { + serviceaccountinfo = event.target.value; + }); + + refreshButton.addEventListener('click', async(event) => { + event.preventDefault(); + await updateCachingStatusDisplay(serviceaccountinfo, statusElement); + }); + + if (enableCachingButton) { + enableCachingButton.addEventListener('click', async(event) => { + event.preventDefault(); + enableCachingButton.disabled = true; + await updateCachingStatus(serviceaccountinfo, statusElement, true); + }); + } + if (disableCachingButton) { + disableCachingButton.addEventListener('click', async(event) => { + event.preventDefault(); + disableCachingButton.disabled = true; + await updateCachingStatus(serviceaccountinfo, statusElement, false); + }); + } +}; + +/** + * Updates the caching status display. + * + * @param {string} serviceaccountinfo the stringified JSON with the service account info + * @param {string} statusElement the HTML element to operate on + */ +const updateCachingStatusDisplay = async(serviceaccountinfo, statusElement) => { + let queryResult = null; + try { + queryResult = await fetchCurrentCacheStatus(serviceaccountinfo); + } catch (error) { + await displayException(error); + return; + } + if (queryResult.code !== 200) { + const errorTitleString = await getString('vertex_error_cachestatus', 'local_ai_manager'); + await alertModal(errorTitleString, queryResult.error); + } + const templateContext = { + cachingEnabled: queryResult.cachingEnabled, + noStatus: false + }; + + const {html, js} = await Templates.renderForPromise('local_ai_manager/vertexcachestatus', templateContext); + Templates.replaceNode(statusElement, html, js); +}; + +/** + * Updates the caching status and updates the DOM to reflect the current state. + * + * @param {string} serviceaccountinfo the stringified JSON with the service account info + * @param {string} statusElement the HTML element to operate on + * @param {boolean} newstatus the status to set the caching configuration to (true or false) + */ +const updateCachingStatus = async(serviceaccountinfo, statusElement, newstatus) => { + let queryResult = null; + try { + queryResult = await setCurrentCacheStatus(serviceaccountinfo, newstatus); + } catch (error) { + await displayException(error); + return; + } + if (queryResult.code !== 200) { + const errorTitleString = await getString('vertex_error_cachestatus', 'local_ai_manager'); + await alertModal(errorTitleString, queryResult.error); + return; + } + await updateCachingStatusDisplay(serviceaccountinfo, statusElement); +}; diff --git a/classes/external/vertex_cache_status.php b/classes/external/vertex_cache_status.php new file mode 100644 index 0000000..0b6cf7a --- /dev/null +++ b/classes/external/vertex_cache_status.php @@ -0,0 +1,109 @@ +. + +namespace local_ai_manager\external; + +use core_external\external_api; +use core_external\external_function_parameters; +use core_external\external_single_structure; +use core_external\external_value; +use local_ai_manager\local\aitool_option_vertexai_authhandler; + +/** + * Web service to check and update the Google Vertex AI cache status. + * + * @package local_ai_manager + * @copyright 2024 ISB Bayern + * @author Philipp Memmel + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class vertex_cache_status extends external_api { + /** + * Describes the parameters. + * + * @return external_function_parameters + */ + public static function execute_parameters(): external_function_parameters { + return new external_function_parameters([ + 'serviceaccountinfo' => new external_value(PARAM_RAW, + 'The JSON string containing the service account information of the used Google Account', + VALUE_REQUIRED), + 'newstatus' => new external_value(PARAM_BOOL, + 'The status to which the caching config should be set to', + VALUE_DEFAULT, + null), + ]); + } + + /** + * Retrieve the purpose config. + * + * @param string $serviceaccountinfo The service account info stringified JSON + * @return array associative array containing the result of the request + */ + public static function execute(string $serviceaccountinfo, ?bool $newstatus = null): array { + [ + 'serviceaccountinfo' => $serviceaccountinfo, + 'newstatus' => $newstatus, + ] = self::validate_parameters(self::execute_parameters(), + [ + 'serviceaccountinfo' => $serviceaccountinfo, + 'newstatus' => $newstatus, + ]); + $context = \context_system::instance(); + self::validate_context($context); + require_capability('local/ai_manager:managevertexcache', $context); + + $vertexaiauthhandler = new aitool_option_vertexai_authhandler(0, $serviceaccountinfo); + if (!is_null($newstatus)) { + try { + $cachingchangeresult = $vertexaiauthhandler->set_google_cache_status($newstatus); + } catch (\moodle_exception $exception) { + return ['code' => 500, 'error' => $exception->getMessage()]; + } + return $cachingchangeresult ? ['code' => 200, 'cachingstatus' => $newstatus] : + ['code' => 500, 'error' => 'COULD NOT SET THE CACHING STATUS']; + } else { + // Variable $newstatus is null, so we just want to query and return the result. + try { + $currentcachingstatus = $vertexaiauthhandler->get_google_cache_status(); + } catch (\moodle_exception $exception) { + return ['code' => 500, 'error' => $exception->getMessage()]; + } + return ['code' => 200, 'cachingEnabled' => $currentcachingstatus]; + } + } + + /** + * Describes the return structure of the service. + * + * @return external_single_structure the return structure + */ + public static function execute_returns(): external_single_structure { + $singlestructuredefinition = []; + $singlestructuredefinition['code'] = new external_value(PARAM_INT, + 'Status code of the request', + VALUE_REQUIRED); + $singlestructuredefinition['cachingEnabled'] = new external_value(PARAM_BOOL, + 'If the Google Vertex AI cache is enabled', VALUE_OPTIONAL); + $singlestructuredefinition['error'] = new external_value(PARAM_TEXT, + 'Error message if there is an error', VALUE_OPTIONAL); + return new external_single_structure( + $singlestructuredefinition, + 'Object containing the tools configured for each purpose' + ); + } +} diff --git a/classes/local/aitool_option_vertexai.php b/classes/local/aitool_option_vertexai.php index 3a4e9c4..2c9bb12 100644 --- a/classes/local/aitool_option_vertexai.php +++ b/classes/local/aitool_option_vertexai.php @@ -35,9 +35,14 @@ class aitool_option_vertexai { * @param \MoodleQuickForm $mform the mform object */ public static function extend_form_definition(\MoodleQuickForm $mform): void { + global $OUTPUT; $mform->freeze('endpoint'); $mform->addElement('textarea', 'serviceaccountjson', get_string('serviceaccountjson', 'local_ai_manager'), ['rows' => '20']); + $vertexcachestatushtml = $OUTPUT->render_from_template('local_ai_manager/vertexcachestatus', ['noStatus' => true]); + $mform->addElement('static', 'vertexcachestatus', + get_string('vertexcachestatus', 'local_ai_manager'), + $vertexcachestatushtml, ['class' => 'mw-100']); } /** diff --git a/classes/local/aitool_option_vertexai_authhandler.php b/classes/local/aitool_option_vertexai_authhandler.php index 7b84826..dfc2104 100644 --- a/classes/local/aitool_option_vertexai_authhandler.php +++ b/classes/local/aitool_option_vertexai_authhandler.php @@ -34,7 +34,7 @@ class aitool_option_vertexai_authhandler { * Constructor for the auth handler. */ public function __construct( - /** @var int The ID of the instance being used. Will be used as key for the cache handling. */ + /** @var int The ID of the instance being used. Will be used as key for the cache handling. */ private readonly int $instanceid, /** @var string The serviceaccountinfo stringified JSON */ private readonly string $serviceaccountinfo @@ -165,4 +165,65 @@ public function is_expired_accesstoken_reason_for_failing(request_response $requ return !empty(array_filter($content['error']['details'], fn($details) => $details['reason'] === 'ACCESS_TOKEN_EXPIRED')); } + /** + * Retrieves and checks the cache status from Google's AI Platform. + * + * Makes an HTTP GET request to the AI Platform cache configuration endpoint + * using the project ID from the service account information. The method + * verifies if the cache is enabled by checking the 'disableCache' key in the + * response. + * + * @return bool true if the cache is enabled, false if the cache is disabled + * @throws \moodle_exception if the HTTP request to retrieve the cache status fails. + */ + public function get_google_cache_status(): bool { + $client = new http_client([ + 'timeout' => get_config('local_ai_manager', 'requesttimeout'), + ]); + + $options['headers'] = [ + 'Authorization' => 'Bearer ' . $this->get_access_token(), + ]; + + $serviceaccountinfo = json_decode($this->serviceaccountinfo); + $projectid = trim($serviceaccountinfo->project_id); + + $response = $client->get('https://europe-west3-aiplatform.googleapis.com/v1beta1/projects/' . $projectid . '/cacheConfig', + $options); + if ($response->getStatusCode() !== 200) { + throw new \moodle_exception('Error retrieving cache status', '', '', '', $response->getBody()->getContents()); + } else { + $result = json_decode($response->getBody()->getContents(), true); + return !array_key_exists('disableCache', $result); + } + } + + /** + * Sets the Google cache status for the specified project. + * + * @param bool $status Determines whether the cache should be enabled or disabled. + * @return bool Returns true if the cache status was successfully set, false otherwise. + */ + public function set_google_cache_status(bool $status): bool { + $client = new http_client([ + 'timeout' => get_config('local_ai_manager', 'requesttimeout'), + ]); + $options['headers'] = [ + 'Authorization' => 'Bearer ' . $this->get_access_token(), + ]; + + $serviceaccountinfo = json_decode($this->serviceaccountinfo); + $projectid = trim($serviceaccountinfo->project_id); + + $data = [ + 'name' => 'projects/' . $projectid . '/cacheConfig', + 'disableCache' => !$status, + ]; + + $options['body'] = json_encode($data); + + $response = $client->patch('https://europe-west3-aiplatform.googleapis.com/v1beta1/projects/' . $projectid . '/cacheConfig', + $options); + return $response->getStatusCode() === 200; + } } diff --git a/db/access.php b/db/access.php index 4477985..fa3ae33 100755 --- a/db/access.php +++ b/db/access.php @@ -110,5 +110,16 @@ 'manager' => CAP_ALLOW, ], ], - + 'local/ai_manager:managevertexcache' => [ + 'captype' => 'write', + 'contextlevel' => CONTEXT_SYSTEM, + 'archetypes' => [ + 'user' => CAP_PREVENT, + 'guest' => CAP_PREVENT, + 'student' => CAP_PREVENT, + 'teacher' => CAP_PREVENT, + 'editingteacher' => CAP_PREVENT, + 'manager' => CAP_ALLOW, + ], + ], ]; diff --git a/db/services.php b/db/services.php index 99783fc..841c6ca 100755 --- a/db/services.php +++ b/db/services.php @@ -54,4 +54,12 @@ 'ajax' => true, 'capabilities' => 'local/ai_manager:use', ], + 'local_ai_manager_vertex_cache_status' => [ + 'classname' => 'local_ai_manager\external\vertex_cache_status', + 'description' => 'Fetch and update the Google Vertex AI caching status', + 'type' => 'write', + 'ajax' => true, + 'capabilities' => '', + ], + ]; diff --git a/lang/de/local_ai_manager.php b/lang/de/local_ai_manager.php index 9a27b4f..367a14b 100644 --- a/lang/de/local_ai_manager.php +++ b/lang/de/local_ai_manager.php @@ -211,4 +211,11 @@ $string['userwithusageonlyshown'] = 'Die Tabelle zeigt nur Benutzer, die diesen Einsatzzweck bereits genutzt haben.'; $string['verifyssl'] = 'SSL-Zertifikate verifizieren'; $string['verifyssldesc'] = 'Wenn aktiviert, werden Verbindungen zu externen KI-Tools nur dann hergestellt, wenn die Zertifikate verifiziert werden können. Diese Option sollte in Produktionsumgebungen nicht deaktiviert werden!'; +$string['vertex_cachingdisabled'] = 'Caching deaktiviert'; +$string['vertex_cachingenabled'] = 'Caching aktiviert'; +$string['vertex_disablecaching'] = 'Caching deaktivieren'; +$string['vertex_enablecaching'] = 'Caching aktivieren'; +$string['vertex_error_cachestatus'] = 'Fehler beim Abfragen/Ändern der Vertex-AI-Cache-Konfiguration'; +$string['vertex_nocachestatus'] = 'Klicken Sie auf den Neu-Laden-Button, um den aktuellen Caching-Status von Vertex AI abzufragen.'; +$string['vertexcachestatus'] = 'Cache-Status von Vertex AI abfragen und ändern'; $string['within'] = 'innerhalb von'; diff --git a/lang/en/local_ai_manager.php b/lang/en/local_ai_manager.php index ed904a6..6523df3 100644 --- a/lang/en/local_ai_manager.php +++ b/lang/en/local_ai_manager.php @@ -211,4 +211,11 @@ $string['userwithusageonlyshown'] = 'Only users who already have used this purpose are being shown in this table.'; $string['verifyssl'] = 'Verify SSL certificates'; $string['verifyssldesc'] = 'If enabled, connections to the AI tools will only be established if the certificates can properly be verified. Only recommended to disable for development use!'; +$string['vertex_cachingdisabled'] = 'Caching disabled'; +$string['vertex_cachingenabled'] = 'Caching enabled'; +$string['vertex_disablecaching'] = 'Disable Caching'; +$string['vertex_enablecaching'] = 'Enable Caching'; +$string['vertex_error_cachestatus'] = 'Error while querying/updating the Vertex AI caching configuration'; +$string['vertex_nocachestatus'] = 'Click the refresh button to query the current Vertex AI cache status.'; +$string['vertexcachestatus'] = 'Query and change Vertex AI cache status'; $string['within'] = 'in'; diff --git a/styles.css b/styles.css index d72c427..4ffb0b1 100644 --- a/styles.css +++ b/styles.css @@ -142,3 +142,15 @@ body.limitcontentwidth #page-content { .dark .local_ai_manager-info-warning .local_ai_manager-info-warning-link { color: #60616d; } + +.local_ai_manager-caching_enabled { + color: #f00; +} + +.local_ai_manager-caching_disabled { + color: #00bf00; +} + +#page-local-ai_manager-edit_instance [data-name="vertexcachestatus"] { + width: 100%; +} \ No newline at end of file diff --git a/templates/vertexcachestatus.mustache b/templates/vertexcachestatus.mustache new file mode 100644 index 0000000..f5bb2f5 --- /dev/null +++ b/templates/vertexcachestatus.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 local_ai_manager/vertexcachestatus + + Template for showing and editing the Google Vertex AI cache status. + + Example context (json): + { + "noStatus": false, + "cachingEnabled": true + } +}} +
+ {{#noStatus}} +
{{#str}}vertex_nocachestatus, local_ai_manager{{/str}}
+ {{/noStatus}} + {{^noStatus}} +
+ {{#cachingEnabled}} +
{{#str}}vertex_cachingenabled, local_ai_manager{{/str}}
+ + {{/cachingEnabled}} + {{^cachingEnabled}} +
{{#str}}vertex_cachingdisabled, local_ai_manager{{/str}}
+ + {{/cachingEnabled}} +
+ {{/noStatus}} +
+
+{{#js}} + require(['local_ai_manager/vertexcachestatus'], function(vertexcachestatus) { + vertexcachestatus.init('#local_ai_manager-vertexcachestatus-{{uniqid}}'); + }); +{{/js}} diff --git a/tests/ai_manager_utils_test.php b/tests/ai_manager_utils_test.php index 49a2591..27b41bb 100644 --- a/tests/ai_manager_utils_test.php +++ b/tests/ai_manager_utils_test.php @@ -17,6 +17,7 @@ namespace local_ai_manager; use Firebase\JWT\JWT; +use local_ai_manager\local\aitool_option_vertexai_authhandler; use stdClass; /** diff --git a/version.php b/version.php index 00b7534..7cd9193 100644 --- a/version.php +++ b/version.php @@ -24,7 +24,7 @@ */ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2024120200; +$plugin->version = 2024120400; $plugin->requires = 2024042200; $plugin->release = '0.0.3'; $plugin->component = 'local_ai_manager';