Passed
Pull Request — master (#6087)
by
unknown
07:41
created

OpenAiProvider::generateQuestions()   B

Complexity

Conditions 7
Paths 14

Size

Total Lines 55
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
eloc 37
nc 14
nop 4
dl 0
loc 55
rs 8.3946
c 1
b 0
f 0

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Chamilo\CoreBundle\Service\AI;
6
7
use Chamilo\CoreBundle\Settings\SettingsManager;
8
use Symfony\Contracts\HttpClient\HttpClientInterface;
9
10
class OpenAiProvider implements AiProviderInterface
11
{
12
    private string $apiUrl;
13
    private string $apiKey;
14
    private string $model;
15
    private float $temperature;
16
    private string $organizationId;
17
    private int $monthlyTokenLimit;
18
    private HttpClientInterface $httpClient;
19
20
    public function __construct(HttpClientInterface $httpClient, SettingsManager $settingsManager)
21
    {
22
        $this->httpClient = $httpClient;
23
24
        // Get AI providers from settings
25
        $configJson = $settingsManager->getSetting('ai_helpers.ai_providers', true);
26
        $config = json_decode($configJson, true) ?? [];
27
28
        if (!isset($config['openai'])) {
29
            throw new \RuntimeException('OpenAI configuration is missing.');
30
        }
31
32
        $this->apiUrl = $config['openai']['url'] ?? 'https://api.openai.com/v1';
33
        $this->apiKey = $config['openai']['api_key'] ?? '';
34
        $this->model = $config['openai']['model'] ?? 'gpt-3.5-turbo';
35
        $this->temperature = $config['openai']['temperature'] ?? 0.7;
36
        $this->organizationId = $config['openai']['organization_id'] ?? '';
37
        $this->monthlyTokenLimit = $config['openai']['monthly_token_limit'] ?? 10000;
38
39
        if (empty($this->apiKey)) {
40
            throw new \RuntimeException('OpenAI API key is missing.');
41
        }
42
    }
43
44
    public function generateQuestions(string $topic, int $numQuestions, string $questionType, string $language): ?string
45
    {
46
        $prompt = sprintf(
47
            'Generate %d "%s" questions in Aiken format in the %s language about "%s".',
48
            $numQuestions, $questionType, $language, $topic
49
        );
50
51
        $payload = [
52
            'model' => $this->model,
53
            'prompt' => $prompt,
54
            'temperature' => $this->temperature,
55
            'max_tokens' => 2000,
56
            'frequency_penalty' => 0,
57
            'presence_penalty' => 0.6,
58
            'top_p' => 1.0,
59
        ];
60
61
        try {
62
            $response = $this->httpClient->request('POST', $this->apiUrl . '/completions', [
63
                'headers' => [
64
                    'Authorization' => 'Bearer ' . $this->apiKey,
65
                    'Content-Type' => 'application/json',
66
                ],
67
                'body' => json_encode($payload),
68
            ]);
69
70
            $statusCode = $response->getStatusCode();
71
            $responseContent = $response->getContent(false);
72
73
            if ($statusCode === 200) {
74
                $data = json_decode($responseContent, true);
75
76
                return $data['choices'][0]['text'] ?? null;
77
            }
78
79
            $errorData = json_decode($responseContent, true);
80
81
            if (isset($errorData['error']['code'])) {
82
                switch ($errorData['error']['code']) {
83
                    case 'insufficient_quota':
84
                        throw new \Exception("You have exceeded your OpenAI quota. Please check your OpenAI plan.");
85
                    case 'invalid_api_key':
86
                        throw new \Exception("Invalid API key. Please check your OpenAI configuration.");
87
                    case 'server_error':
88
                        throw new \Exception("OpenAI encountered an internal error. Try again later.");
89
                    default:
90
                        throw new \Exception("An error occurred: " . $errorData['error']['message']);
91
                }
92
            }
93
94
            throw new \Exception("Unexpected error from OpenAI.");
95
96
        } catch (\Exception $e) {
97
            error_log("ERROR - OpenAI Request failed: " . $e->getMessage());
98
            return "Error: " . $e->getMessage();
99
        }
100
    }
101
}
102