Passed
Push — 1.11.x ( 649c39...063b4a )
by Angel Fernando Quiroz
09:50
created

AiHelperPlugin::getApiList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 3
c 1
b 0
f 0
dl 0
loc 7
rs 10
cc 1
nc 1
nop 0
1
<?php
2
/* For license terms, see /license.txt */
3
4
use Chamilo\PluginBundle\Entity\AiHelper\Requests;
5
use Doctrine\ORM\Tools\SchemaTool;
6
7
/**
8
 * Description of AiHelperPlugin.
9
 *
10
 * @author Christian Beeznest <[email protected]>
11
 */
12
class AiHelperPlugin extends Plugin
13
{
14
    public const TABLE_REQUESTS = 'plugin_ai_helper_requests';
15
    public const OPENAI_API = 'openai';
16
17
    protected function __construct()
18
    {
19
        $version = '1.1';
20
        $author = 'Christian Fasanando';
21
22
        $message = 'Description';
23
24
        $settings = [
25
            $message => 'html',
26
            'tool_enable' => 'boolean',
27
            'api_name' => [
28
                'type' => 'select',
29
                'options' => $this->getApiList(),
30
            ],
31
            'api_key' => 'text',
32
            'organization_id' => 'text',
33
            'tool_lp_enable' => 'boolean',
34
            'tool_quiz_enable' => 'boolean',
35
            'tokens_limit' => 'text',
36
        ];
37
38
        parent::__construct($version, $author, $settings);
39
    }
40
41
    /**
42
     * Get the list of apis availables.
43
     *
44
     * @return array
45
     */
46
    public function getApiList()
47
    {
48
        $list = [
49
            self::OPENAI_API => 'OpenAI',
50
        ];
51
52
        return $list;
53
    }
54
55
    /**
56
     * Get the completion text from openai.
57
     *
58
     * @return string
59
     */
60
    public function openAiGetCompletionText(
61
        string $prompt,
62
        string $toolName
63
    ) {
64
        if (!$this->validateUserTokensLimit(api_get_user_id())) {
65
            return [
66
                'error' => true,
67
                'message' => $this->get_lang('ErrorTokensLimit'),
68
            ];
69
        }
70
71
        require_once __DIR__.'/src/openai/OpenAi.php';
72
73
        $apiKey = $this->get('api_key');
74
        $organizationId = $this->get('organization_id');
75
76
        $ai = new OpenAi($apiKey, $organizationId);
77
78
        $temperature = 0.2;
79
        $model = 'text-davinci-003';
80
        $maxTokens = 2000;
81
        $frequencyPenalty = 0;
82
        $presencePenalty = 0.6;
83
        $topP = 1.0;
84
85
        $complete = $ai->completion([
86
            'model' => $model,
87
            'prompt' => $prompt,
88
            'temperature' => $temperature,
89
            'max_tokens' => $maxTokens,
90
            'frequency_penalty' => $frequencyPenalty,
91
            'presence_penalty' => $presencePenalty,
92
            'top_p' => $topP,
93
        ]);
94
95
        $result = json_decode($complete, true);
96
        $resultText = '';
97
        if (!empty($result['choices'])) {
98
            $resultText = $result['choices'][0]['text'];
99
            // saves information of user results.
100
            $values = [
101
                'user_id' => api_get_user_id(),
102
                'tool_name' => $toolName,
103
                'prompt' => $prompt,
104
                'prompt_tokens' => (int) $result['usage']['prompt_tokens'],
105
                'completion_tokens' => (int) $result['usage']['completion_tokens'],
106
                'total_tokens' => (int) $result['usage']['total_tokens'],
107
            ];
108
            $this->saveRequest($values);
109
        }
110
111
        return $resultText;
112
    }
113
114
    /**
115
     * Validates tokens limit of a user per current month.
116
     */
117
    public function validateUserTokensLimit(int $userId): bool
118
    {
119
        $em = Database::getManager();
120
        $repo = $em->getRepository('ChamiloPluginBundle:AiHelper\Requests');
121
122
        $startDate = api_get_utc_datetime(
123
            null,
124
            false,
125
            true)
126
            ->modify('first day of this month')->setTime(00, 00, 00)
0 ignored issues
show
Bug introduced by
A parse error occurred: The alleged octal '0' is invalid
Loading history...
127
        ;
128
        $endDate = api_get_utc_datetime(
129
            null,
130
            false,
131
            true)
132
            ->modify('last day of this month')->setTime(23, 59, 59)
133
        ;
134
135
        $qb = $repo->createQueryBuilder('e')
136
            ->select('sum(e.totalTokens) as total')
137
            ->andWhere('e.requestedAt BETWEEN :dateMin AND :dateMax')
138
            ->andWhere('e.userId = :user')
139
            ->setMaxResults(1)
140
            ->setParameters(
141
                [
142
                    'dateMin' => $startDate->format('Y-m-d h:i:s'),
143
                    'dateMax' => $endDate->format('Y-m-d h:i:s'),
144
                    'user' => $userId,
145
                ]
146
            );
147
        $result = $qb->getQuery()->getOneOrNullResult();
148
        $totalTokens = !empty($result) ? (int) $result['total'] : 0;
149
150
        $valid = true;
151
        $tokensLimit = $this->get('tokens_limit');
152
        if (!empty($tokensLimit)) {
153
            $valid = ($totalTokens <= (int) $tokensLimit);
154
        }
155
156
        return $valid;
157
    }
158
159
    /**
160
     * Get the plugin directory name.
161
     */
162
    public function get_name(): string
163
    {
164
        return 'ai_helper';
165
    }
166
167
    /**
168
     * Get the class instance.
169
     *
170
     * @staticvar AiHelperPlugin $result
171
     */
172
    public static function create(): AiHelperPlugin
173
    {
174
        static $result = null;
175
176
        return $result ?: $result = new self();
177
    }
178
179
    /**
180
     * Save user information of openai request.
181
     *
182
     * @return int
183
     */
184
    public function saveRequest(array $values)
185
    {
186
        $em = Database::getManager();
187
188
        $objRequest = new Requests();
189
        $objRequest
190
            ->setUserId($values['user_id'])
191
            ->setToolName($values['tool_name'])
192
            ->setRequestedAt(new DateTime())
193
            ->setRequestText($values['prompt'])
194
            ->setPromptTokens($values['prompt_tokens'])
195
            ->setCompletionTokens($values['completion_tokens'])
196
            ->setTotalTokens($values['total_tokens'])
197
        ;
198
        $em->persist($objRequest);
199
        $em->flush();
200
201
        return $objRequest->getId();
202
    }
203
204
    /**
205
     * Install the plugin. Set the database up.
206
     */
207
    public function install()
208
    {
209
        $em = Database::getManager();
210
211
        if ($em->getConnection()->getSchemaManager()->tablesExist([self::TABLE_REQUESTS])) {
212
            return;
213
        }
214
215
        $schemaTool = new SchemaTool($em);
216
        $schemaTool->createSchema(
217
            [
218
                $em->getClassMetadata(Requests::class),
219
            ]
220
        );
221
    }
222
223
    /**
224
     * Unistall plugin. Clear the database.
225
     */
226
    public function uninstall()
227
    {
228
        $em = Database::getManager();
229
230
        if (!$em->getConnection()->getSchemaManager()->tablesExist([self::TABLE_REQUESTS])) {
231
            return;
232
        }
233
234
        $schemaTool = new SchemaTool($em);
235
        $schemaTool->dropSchema(
236
            [
237
                $em->getClassMetadata(Requests::class),
238
            ]
239
        );
240
    }
241
}
242