diff --git a/lib/mlbackend/python/classes/processor.php b/lib/mlbackend/python/classes/processor.php new file mode 100644 index 00000000000..5bb40e8823b --- /dev/null +++ b/lib/mlbackend/python/classes/processor.php @@ -0,0 +1,166 @@ +. + +/** + * Python predictions processor + * + * @package mlbackend_python + * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +namespace mlbackend_python; + +defined('MOODLE_INTERNAL') || die(); + +/** + * Python predictions processor. + * + * @package mlbackend_python + * @copyright 2016 David Monllao {@link http://www.davidmonllao.com} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +class processor implements \core_analytics\predictor { + + const REQUIRED_PIP_PACKAGE_VERSION = '0.0.9'; + + public function is_ready() { + + # Check the installed pip package version. + $cmd = 'python -m moodleinspire.version'; + + $output = null; + $exitcode = null; + // Execute it sending the standard error to $output. + $result = exec($cmd . ' 2>&1', $output, $exitcode); + + if ($result === self::REQUIRED_PIP_PACKAGE_VERSION) { + return true; + } + + if ($exitcode != 0) { + return get_string('pythonpackagenotinstalled', 'mlbackend_python', $cmd); + } + + if ($result) { + $a = (object)array('installed' => $result, 'required' => self::REQUIRED_PIP_PACKAGE_VERSION); + return get_string('packageinstalledshouldbe', 'mlbackend_python', $a); + } + + return get_string('pythonpackagenotinstalled', 'mlbackend_python', $cmd); + } + + public function train($uniqueid, \stored_file $dataset, $outputdir) { + + $datasetpath = $this->get_file_path($dataset); + + $cmd = 'python -m moodleinspire.training ' . + escapeshellarg($uniqueid) . ' ' . + escapeshellarg($outputdir) . ' ' . + escapeshellarg($datasetpath); + + if (!PHPUNIT_TEST && CLI_SCRIPT) { + debugging($cmd, DEBUG_DEVELOPER); + } + + $output = null; + $exitcode = null; + $result = exec($cmd, $output, $exitcode); + + if (!$result) { + throw new \moodle_exception('errornopredictresults', 'analytics'); + } + + if (!$resultobj = json_decode($result)) { + throw new \moodle_exception('errorpredictwrongformat', 'analytics', '', json_last_error_msg()); + } + + if ($exitcode != 0) { + throw new \moodle_exception('errorpredictionsprocessor', 'analytics', '', implode(', ', $resultobj->errors)); + } + + return $resultobj; + } + + public function predict($uniqueid, \stored_file $dataset, $outputdir) { + + $datasetpath = $this->get_file_path($dataset); + + $cmd = 'python -m moodleinspire.prediction ' . + escapeshellarg($uniqueid) . ' ' . + escapeshellarg($outputdir) . ' ' . + escapeshellarg($datasetpath); + + if (!PHPUNIT_TEST && CLI_SCRIPT) { + debugging($cmd, DEBUG_DEVELOPER); + } + + $output = null; + $exitcode = null; + $result = exec($cmd, $output, $exitcode); + + if (!$result) { + throw new \moodle_exception('errornopredictresults', 'analytics'); + } + + if (!$resultobj = json_decode($result)) { + throw new \moodle_exception('errorpredictwrongformat', 'analytics', '', json_last_error_msg()); + } + + if ($exitcode != 0) { + throw new \moodle_exception('errorpredictionsprocessor', 'analytics', '', implode(', ', $resultobj->errors)); + } + + return $resultobj; + } + + public function evaluate($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir) { + + $datasetpath = $this->get_file_path($dataset); + + $cmd = 'python -m moodleinspire.evaluation ' . + escapeshellarg($uniqueid) . ' ' . + escapeshellarg($outputdir) . ' ' . + escapeshellarg($datasetpath) . ' ' . + escapeshellarg(\core_analytics\model::MIN_SCORE) . ' ' . + escapeshellarg($maxdeviation) . ' ' . + escapeshellarg($niterations); + + if (!PHPUNIT_TEST && CLI_SCRIPT) { + debugging($cmd, DEBUG_DEVELOPER); + } + + $output = null; + $exitcode = null; + $result = exec($cmd, $output, $exitcode); + + if (!$result) { + throw new \moodle_exception('errornopredictresults', 'analytics'); + } + + if (!$resultobj = json_decode($result)) { + throw new \moodle_exception('errorpredictwrongformat', 'analytics', '', json_last_error_msg()); + } + + return $resultobj; + } + + protected function get_file_path(\stored_file $file) { + // From moodle filesystem to the local file system. + // This is not ideal, but there is no read access to moodle filesystem files. + return $file->copy_content_to_temp('core_analytics'); + } +} diff --git a/lib/mlbackend/python/lang/en/mlbackend_python.php b/lib/mlbackend/python/lang/en/mlbackend_python.php new file mode 100644 index 00000000000..129d1adc158 --- /dev/null +++ b/lib/mlbackend/python/lang/en/mlbackend_python.php @@ -0,0 +1,5 @@ +required}" and the installed version is "{$a->installed}"'; +$string['pluginname'] = 'Python predictor'; +$string['pythonpackagenotinstalled'] = 'moodleinspire python package is not installed or there is a problem with it. Please execute "{$a}" from command line interface for more info'; diff --git a/lib/mlbackend/python/version.php b/lib/mlbackend/python/version.php new file mode 100644 index 00000000000..da2e6367f43 --- /dev/null +++ b/lib/mlbackend/python/version.php @@ -0,0 +1,29 @@ +. + +/** + * Version details. + * + * @package mlbackend_python + * @copyright 2017 David Monllao {@link http://www.davidmonllao.com/} + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ + +defined('MOODLE_INTERNAL') || die(); + +$plugin->version = 2017051500; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2017050500; // Requires this Moodle version. +$plugin->component = 'mlbackend_python'; // Full name of the plugin (used for diagnostics).