processor.php 6.44 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<?php
// 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 <http://www.gnu.org/licenses/>.

/**
 * 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 {

38
39
40
    /**
     * The required version of the python package that performs all calculations.
     */
41
    const REQUIRED_PIP_PACKAGE_VERSION = '0.0.2';
42

43
44
45
46
47
    /**
     * Is the plugin ready to be used?.
     *
     * @return bool
     */
48
49
    public function is_ready() {

50
        // Check the installed pip package version.
51
        $cmd = 'python -m moodlemlbackend.version';
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73

        $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);
    }

74
75
76
77
78
79
80
81
    /**
     * Trains a machine learning algorithm with the provided dataset.
     *
     * @param string $uniqueid
     * @param \stored_file $dataset
     * @param string $outputdir
     * @return \stdClass
     */
82
83
    public function train($uniqueid, \stored_file $dataset, $outputdir) {

84
        // Obtain the physical route to the file.
85
86
        $datasetpath = $this->get_file_path($dataset);

87
        $cmd = 'python -m moodlemlbackend.training ' .
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
            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;
    }

115
116
117
118
119
120
121
122
    /**
     * Returns predictions for the provided dataset samples.
     *
     * @param string $uniqueid
     * @param \stored_file $dataset
     * @param string $outputdir
     * @return \stdClass
     */
123
124
    public function predict($uniqueid, \stored_file $dataset, $outputdir) {

125
        // Obtain the physical route to the file.
126
127
        $datasetpath = $this->get_file_path($dataset);

128
        $cmd = 'python -m moodlemlbackend.prediction ' .
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
            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;
    }

156
157
158
159
160
161
162
163
164
165
    /**
     * Evaluates the provided dataset.
     *
     * @param string $uniqueid
     * @param float $maxdeviation
     * @param int $niterations
     * @param \stored_file $dataset
     * @param string $outputdir
     * @return \stdClass
     */
166
167
    public function evaluate($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir) {

168
        // Obtain the physical route to the file.
169
170
        $datasetpath = $this->get_file_path($dataset);

171
        $cmd = 'python -m moodlemlbackend.evaluation ' .
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
            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;
    }

198
199
200
201
202
203
    /**
     * Returns the path to the dataset file.
     *
     * @param \stored_file $file
     * @return string
     */
204
205
206
207
208
209
    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');
    }
}