diff --git a/ai/classes/aiprovider.php b/ai/classes/aiprovider.php index 56dda3dc1fb46..b6bf2c4509863 100644 --- a/ai/classes/aiprovider.php +++ b/ai/classes/aiprovider.php @@ -9,6 +9,7 @@ class AIProvider extends persistent { // Ultimately this would extend a persistent. const CONTEXT_ALL_MY_COURSES = -1; + const TABLE = "aiprovider"; protected static function define_properties() { @@ -31,13 +32,13 @@ protected static function define_properties() 'baseurl' => [ 'type' => PARAM_URL ], - 'embeddings' => [ + 'embeddingsurl' => [ 'type' => PARAM_URL ], 'embeddingmodel' => [ 'type' => PARAM_ALPHANUMEXT ], - 'completions' => [ + 'completionsurl' => [ 'type' => PARAM_URL ], 'completionmodel' => [ @@ -150,10 +151,10 @@ public function get_settings_for_user($user) { $mycourseids = enrol_get_my_courses(array('id', 'cacherev'), 'id', 0, [], false); $onlyenrolledcourses = $this->get('onlyenrolledcourses'); $courseids = []; - if ($this->get('context') == self::CONTEXT_ALL_MY_COURSES) { + if ($this->get('contextid') == self::CONTEXT_ALL_MY_COURSES) { $courseids = array_keys($mycourseids); } else { - $context = \context::instance_by_id($this->get('context')); + $context = \context::instance_by_id($this->get('contextid')); if ($context->contextlevel == CONTEXT_COURSE) { // Check that the specific course is also in the user's list of courses. $courseids = array_intersect([$context->instanceid], $mycourseids); @@ -187,40 +188,41 @@ public function get_settings_for_user($user) { */ public static function get_records($filters = [], $sort = '', $order = 'ASC', $skip = 0, $limit = 0) { global $_ENV; - - $records = []; - $fake = new static(0, (object) [ - 'id' => 1, - 'name' => "Open AI Provider (hardcoded)", - 'enabled' => true, - 'allowembeddings' => true, - 'allowchat' => true, - 'baseurl' => 'https://api.openai.com/v1/', - 'embeddings' => 'embeddings', - 'embeddingmodel' => 'text-embedding-3-small', - 'completions' => 'chat/completions', - 'completionmodel' => 'gpt-4-turbo-preview', - 'apikey'=> $_ENV['OPENAIKEY'], - 'contextid' => \context_system::instance()->id, - //null, // Global AI Provider - 'onlyenrolledcourses' => true - ]); - array_push($records, $fake); - $fake = new static(0, (object) [ - 'id' => 2, - 'name' => "Ollama AI Provider (hard coded)", - 'enabled' => true, - 'allowembeddings' => true, - 'allowchat' => true, - 'baseurl' => 'http://127.0.0.1:11434/api/', - 'embeddings' => 'embeddings', - 'embeddingmodel' => '', - 'completions' => 'chat', - 'completionmodel' => 'llama2', - 'contextid' => null, // Global AI Provider - 'onlyenrolledcourses' => true - ]); - array_push($records, $fake); + $records = parent::get_records($filters, $sort, $order, $skip, $limit); +// $records = []; +// $fake = new static(0, (object) [ +// 'id' => 1, +// 'name' => "Open AI Provider (hardcoded)", +// 'enabled' => true, +// 'allowembeddings' => true, +// 'allowchat' => true, +// 'baseurl' => 'https://api.openai.com/v1/', +// 'embeddings' => 'embeddings', +// 'embeddingmodel' => 'text-embedding-3-small', +// 'completions' => 'chat/completions', +// 'completionmodel' => 'gpt-4-turbo-preview', +// 'apikey'=> $_ENV['OPENAIKEY'], +// 'contextid' => \context_system::instance()->id, +// //null, // Global AI Provider +// 'onlyenrolledcourses' => true +// ]); +// array_push($records, $fake); +// $fake = new static(0, (object) [ +// 'id' => 2, +// 'name' => "Ollama AI Provider (hard coded)", +// 'enabled' => true, +// 'allowembeddings' => true, +// 'allowchat' => true, +// 'baseurl' => 'http://127.0.0.1:11434/api/', +// 'embeddings' => 'embeddings', +// 'embeddingmodel' => '', +// 'completions' => 'chat', +// 'completionmodel' => 'llama2', +// 'contextid' => null, // Global AI Provider +// 'onlyenrolledcourses' => true +// ]); +// array_push($records, $fake); +/* $fake = new static(0, (object) [ 'id' => 3, 'name' => "Ollama AI Provider (hard coded) Misc Category only", @@ -236,7 +238,7 @@ public static function get_records($filters = [], $sort = '', $order = 'ASC', $s 'onlyenrolledcourses' => true, ]); array_push($records, $fake); - +*/ $targetcontextid = $filters['contextid'] ?? null; $targetcontext = null; if (is_null($targetcontextid)) { diff --git a/ai/classes/form/openaiapiprovider.php b/ai/classes/form/openaiapiprovider.php index 9c827b4e5fecc..3ce2bd34346a7 100644 --- a/ai/classes/form/openaiapiprovider.php +++ b/ai/classes/form/openaiapiprovider.php @@ -32,7 +32,8 @@ public function definition() { $mform->addRule('name', null, 'required', null, 'client'); $mform->addRule('name', get_string('maximumchars', '', 255), 'maxlength', 255, 'client'); $mform->addHelpButton('name', 'providername', 'ai'); - + $mform->addElement('advcheckbox', 'enabled', get_string('enabled', 'ai')); + $mform->addHelpButton('enabled', 'enabled', 'ai'); // Client Secret. $mform->addElement('text','baseurl', get_string('baseurl', 'ai')); $mform->setType('baseurl', PARAM_URL); @@ -44,14 +45,14 @@ public function definition() { $mform->addElement('advcheckbox', 'allowchat', get_string('allowchat', 'ai')); $mform->addHelpButton('allowchat', 'allowchat', 'ai'); - $mform->addElement('text','completions', get_string('completionspath', 'ai')); + $mform->addElement('text','completionsurl', get_string('completionspath', 'ai')); $mform->addElement('text','completionmodel', get_string('completionmodel', 'ai')); - $mform->disabledIf('completions', 'allowchat', 'notchecked'); + $mform->disabledIf('completionsurl', 'allowchat', 'notchecked'); $mform->disabledIf('completionmodel', 'allowchat', 'notchecked'); $mform->addElement('advcheckbox', 'allowembeddings', get_string('allowembeddings', 'ai')); $mform->addHelpButton('allowembeddings', 'allowembeddings', 'ai'); - $mform->addElement('text','embeddings', get_string('embeddingspath', 'ai')); + $mform->addElement('text','embeddingsurl', get_string('embeddingspath', 'ai')); $mform->addElement('text','embeddingmodel', get_string('embeddingmodel', 'ai')); $mform->disabledIf('embeddings', 'allowembeddings', 'notchecked'); $mform->disabledIf('embeddingmodel', 'allowembeddings', 'notchecked'); @@ -87,8 +88,8 @@ public function definition() { $mform->addElement('hidden', 'onlyenrolledcourses', ); $mform->setType('onlyenrolledcourses', PARAM_RAW); - $mform->addElement('hidden', 'enabled', true); - $mform->setType('enabled', PARAM_ALPHA); +// $mform->addElement('hidden', 'enabled', true); +// $mform->setType('enabled', PARAM_ALPHA); $mform->addElement('hidden', 'type', $this->_customdata['type']); $mform->setType('type', PARAM_ALPHANUM); diff --git a/ai/classes/output/index_page.php b/ai/classes/output/index_page.php index c07ee04881f22..faa106facb639 100644 --- a/ai/classes/output/index_page.php +++ b/ai/classes/output/index_page.php @@ -52,7 +52,7 @@ public function providers_table($providers) { $context = "System"; } $completion = $provider->get('allowchat'); - $embeddings = $provider->get('embeddings'); + $embeddings = $provider->get('allowembeddings'); $status = $provider->get('enabled'); // Set up cells. diff --git a/ai/index.php b/ai/index.php index f480f05d19d0e..d64cb6bf90299 100644 --- a/ai/index.php +++ b/ai/index.php @@ -21,11 +21,11 @@ // We're using pid as "id" is used to specify contextids. $providerid = optional_param('pid', '', PARAM_RAW); $incontextid = optional_param('contextid', null, PARAM_RAW); - -$context = !is_null($incontextid) ? \context::instance_by_id($incontextid) : null; +//var_dump($incontextid); +$context = !empty($incontextid) ? \context::instance_by_id($incontextid) : null; if (empty($context)) { - $strheading = get_string(get_string('pluginname', 'ai')); + $strheading = get_string('pluginname', 'ai'); } else { $strheading = get_string('aiprovidersin', 'ai', $context->get_context_name()); } @@ -36,21 +36,24 @@ $mform = null; if ($providerid) { - $provider = core\ai\api::get_provider($providerid); + $provider = api::get_provider($providerid); if (!$provider) { throw new moodle_exception('invaliddata'); } } if ($action == api::ACTION_EDIT_PROVIDER) { + if ($provider) { // Edit + $type = "openaipi";// Should store in and read from provider. } else { // Create new + $type = required_param('type', PARAM_RAW); } $mform = new \core_ai\form\openaiapiprovider(null, [ 'persistent' => $provider, - 'type' => required_param('type', PARAM_RAW), + 'type' => $type, 'contextid' => $incontextid ]); } @@ -81,6 +84,7 @@ $mform->display(); echo $OUTPUT->footer(); } + exit; } else if ($action == api::ACTION_REMOVE_PROVIDER) { // Handle remove. } else { diff --git a/lib/db/install.xml b/lib/db/install.xml index 802a5f592b0a1..b6bf503793b7e 100644 --- a/lib/db/install.xml +++ b/lib/db/install.xml @@ -1,5 +1,5 @@ - @@ -4844,5 +4844,29 @@ + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/lib/db/upgrade.php b/lib/db/upgrade.php index 13bd8b7e6dd97..d5abfa87efbbe 100644 --- a/lib/db/upgrade.php +++ b/lib/db/upgrade.php @@ -1129,5 +1129,42 @@ function xmldb_main_upgrade($oldversion) { upgrade_main_savepoint(true, 2024030500.02); } + if ($oldversion < 2024032600.01) { + + // Define table aiprovider to be created. + $table = new xmldb_table('aiprovider'); + + // Adding fields to table aiprovider. + $table->add_field('id', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, XMLDB_SEQUENCE, null); + $table->add_field('usermodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('timecreated', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('timemodified', XMLDB_TYPE_INTEGER, '10', null, XMLDB_NOTNULL, null, '0'); + $table->add_field('name', XMLDB_TYPE_CHAR, '255', null, XMLDB_NOTNULL, null, null); + $table->add_field('enabled', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1'); + $table->add_field('apikey', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('allowembeddings', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1'); + $table->add_field('allowchat', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1'); + $table->add_field('baseurl', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('embeddingsurl', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('completionsurl', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('embeddingmodel', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('completionmodel', XMLDB_TYPE_TEXT, null, null, null, null, null); + $table->add_field('contextid', XMLDB_TYPE_INTEGER, '10', null, null, null, '0'); + $table->add_field('onlyenrolledcourses', XMLDB_TYPE_INTEGER, '2', null, XMLDB_NOTNULL, null, '1'); + + // Adding keys to table aiprovider. + $table->add_key('primary', XMLDB_KEY_PRIMARY, ['id']); + $table->add_key('usermodified', XMLDB_KEY_FOREIGN, ['usermodified'], 'user', ['id']); + + // Conditionally launch create table for aiprovider. + if (!$dbman->table_exists($table)) { + $dbman->create_table($table); + } + + // Main savepoint reached. + upgrade_main_savepoint(true, 2024032600.02); + } + + return true; } diff --git a/mod/xaichat/view.php b/mod/xaichat/view.php index 825f2c1c3aca7..c91e4ad1572a7 100644 --- a/mod/xaichat/view.php +++ b/mod/xaichat/view.php @@ -27,6 +27,7 @@ require_once(__DIR__.'/lib.php'); use core_ai\api; +use core_ai\aiclient; use mod_xaichat\aichatform; // Course module id. @@ -83,7 +84,7 @@ } $stepnow = 0; $totalsteps = 4; - $aiclient = new \core\ai\AIClient($aiprovider); + $aiclient = new AIClient($aiprovider); $progress = new \progress_bar(); $progress->create();