Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
 
17
namespace aiprovider_openai\form;
18
 
19
use aiprovider_openai\helper;
20
use core_ai\form\action_settings_form;
21
 
22
/**
23
 * Base action settings form for OpenAI provider.
24
 *
25
 * @package    aiprovider_openai
26
 * @copyright  2025 Huong Nguyen <huongnv13@gmail.com>
27
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
28
 */
29
class action_form extends action_settings_form {
30
    /**
31
     * @var array Action configuration.
32
     */
33
    protected array $actionconfig;
34
    /**
35
     * @var string|null Return URL.
36
     */
37
    protected ?string $returnurl;
38
    /**
39
     * @var string Action name.
40
     */
41
    protected string $actionname;
42
    /**
43
     * @var string Action class.
44
     */
45
    protected string $action;
46
    /**
47
     * @var int Provider ID.
48
     */
49
    protected int $providerid;
50
    /**
51
     * @var string Provider name.
52
     */
53
    protected string $providername;
54
 
55
    #[\Override]
56
    protected function definition(): void {
57
        $mform = $this->_form;
58
        $this->actionconfig = $this->_customdata['actionconfig']['settings'] ?? [];
59
        $this->returnurl = $this->_customdata['returnurl'] ?? null;
60
        $this->actionname = $this->_customdata['actionname'];
61
        $this->action = $this->_customdata['action'];
62
        $this->providerid = $this->_customdata['providerid'] ?? 0;
63
        $this->providername = $this->_customdata['providername'] ?? 'aiprovider_openai';
64
 
65
        $mform->addElement('header', 'generalsettingsheader', get_string('general', 'core'));
66
    }
67
 
68
    #[\Override]
69
    public function set_data($data): void {
70
        if (!empty($data['modelextraparams'])) {
71
            $data['modelextraparams'] = json_encode(json_decode($data['modelextraparams']), JSON_PRETTY_PRINT);
72
        }
73
        parent::set_data($data);
74
    }
75
 
76
    #[\Override]
77
    public function get_data(): ?\stdClass {
78
        $data = parent::get_data();
79
 
80
        if ($data) {
81
            if (isset($data->modeltemplate)) {
82
                if ($data->modeltemplate === 'custom') {
83
                    $data->model = $data->custommodel;
84
                } else {
85
                    // Set the model to the selected model template.
86
                    $data->model = $data->modeltemplate;
87
 
88
                    // Cast settings to their intended types.
89
                    if ($data->model === 'gpt-4o' || $data->model === 'o1') {
90
                        if (isset($data->top_p)) {
91
                            $data->top_p = floatval($data->top_p);
92
                        }
93
                        if (isset($data->max_completion_tokens)) {
94
                            $data->max_completion_tokens = intval($data->max_completion_tokens);
95
                        }
96
                        if (isset($data->presence_penalty)) {
97
                            $data->presence_penalty = floatval($data->presence_penalty);
98
                        }
99
                        if (isset($data->frequency_penalty)) {
100
                            $data->frequency_penalty = floatval($data->frequency_penalty);
101
                        }
102
                    }
103
                }
104
            }
105
            // Unset the model template.
106
            unset($data->custommodel);
107
            unset($data->modeltemplate);
108
 
109
            // Unset any false-y values.
110
            $data = (object) array_filter((array) $data);
111
        }
112
 
113
        return $data;
114
    }
115
 
116
    #[\Override]
117
    public function validation($data, $files): array {
118
        $errors = parent::validation($data, $files);
119
 
120
        // Validate the extra parameters.
121
        if (!empty($data['modelextraparams'])) {
122
            json_decode($data['modelextraparams']);
123
            if (json_last_error() !== JSON_ERROR_NONE) {
124
                $errors['modelextraparams'] = get_string('invalidjson', 'aiprovider_openai');
125
            }
126
        }
127
 
128
        // Validate the model.
129
        if ($data['modeltemplate'] === 'custom' && empty($data['custommodel'])) {
130
            $errors['custommodel'] = get_string('required');
131
        }
132
 
133
        return $errors;
134
    }
135
 
136
    #[\Override]
137
    public function get_defaults(): array {
138
        $data = parent::get_defaults();
139
 
140
        unset(
141
            $data['modeltemplate'],
142
            $data['custommodel'],
143
            $data['modelextraparams'],
144
        );
145
 
146
        return $data;
147
    }
148
 
149
    /**
150
     * Add model fields to the form.
151
     *
152
     * @param int $modeltype Model type.
153
     */
154
    protected function add_model_fields(int $modeltype): void {
155
        global $PAGE;
156
        $PAGE->requires->js_call_amd('aiprovider_openai/modelchooser', 'init');
157
        $mform = $this->_form;
158
        $actionname = $this->actionname;
159
 
160
        // Action model to use.
161
        $mform->addElement(
162
            'select',
163
            'modeltemplate',
164
            get_string("action:{$this->actionname}:model", 'aiprovider_openai'),
165
            $this->get_model_list($modeltype),
166
            ['data-modelchooser-field' => 'selector'],
167
        );
168
        $mform->setType('modeltemplate', PARAM_TEXT);
169
        $mform->addRule('modeltemplate', null, 'required', null, 'client');
170
        if (!empty($this->actionconfig['model']) &&
171
                (!array_key_exists($this->actionconfig['model'], $this->get_model_list($modeltype)) ||
172
                !empty($this->actionconfig['modelextraparams']))) {
173
            $defaultmodel = 'custom';
174
        } else if (empty($this->actionconfig['model'])) {
175
            $defaultmodel = ($actionname === 'generate_image') ? 'dall-e-3' : 'gpt-4o';
176
        } else {
177
            $defaultmodel = $this->actionconfig['model'];
178
        }
179
        $mform->setDefault('modeltemplate', $defaultmodel);
180
        $mform->addHelpButton('modeltemplate', "action:{$this->actionname}:model", 'aiprovider_openai');
181
 
182
        $mform->addElement('hidden', 'model', $defaultmodel);
183
        $mform->setType('model', PARAM_TEXT);
184
 
185
        $mform->addElement('text', 'custommodel', get_string('custom_model_name', 'aiprovider_openai'));
186
        $mform->setType('custommodel', PARAM_TEXT);
187
        $mform->setDefault('custommodel', $this->actionconfig['model'] ?? '');
188
        $mform->hideIf('custommodel', 'modeltemplate', 'neq', 'custom');
189
 
190
        $mform->registerNoSubmitButton('updateactionsettings');
191
        $mform->addElement(
192
            'submit',
193
            'updateactionsettings',
194
            'updateactionsettings',
195
            ['data-modelchooser-field' => 'updateButton', 'class' => 'd-none']
196
        );
197
    }
198
 
199
    /**
200
     * Get the list of models.
201
     *
202
     * @param int $modeltype Model type.
203
     * @return array List of models.
204
     */
205
    protected function get_model_list(int $modeltype): array {
206
        $models = [];
207
        $models['custom'] = get_string('custom', 'core_form');
208
        foreach (helper::get_model_classes() as $class) {
209
            $model = new $class();
210
            if (in_array($modeltype, $model->model_type())) {
211
                $models[$model->get_model_name()] = $model->get_model_display_name();
212
            }
213
        }
214
        return $models;
215
    }
216
}