diff --git a/classes/base_connector.php b/classes/base_connector.php index c91f151..c521cd5 100644 --- a/classes/base_connector.php +++ b/classes/base_connector.php @@ -16,7 +16,6 @@ namespace local_ai_manager; -use aitool_chatgpt\instance; use core\http_client; use core_plugin_manager; use local_ai_manager\local\prompt_response; @@ -199,7 +198,7 @@ final public static function get_all_connectors(): array { * @param ClientExceptionInterface $exception the exception which has been thrown * @return request_response a request_response object containing the necessary information in a standardized way */ - protected function create_error_response_from_exception(ClientExceptionInterface $exception): request_response { + final protected function create_error_response_from_exception(ClientExceptionInterface $exception): request_response { $message = ''; // This is actually pretty bad, but it does not seem possible to get to these kind of errors through some kind of // Guzzle API functions, so we have to hope the cURL error messages are kinda stable. @@ -210,18 +209,22 @@ protected function create_error_response_from_exception(ClientExceptionInterface $message = get_string('exception_curl', 'local_ai_manager'); } } else { - switch ($exception->getCode()) { - case 401: - $message = get_string('exception_http401', 'local_ai_manager'); - break; - case 429: - $message = get_string('exception_http429', 'local_ai_manager'); - break; - case 500: - $message = get_string('exception_http500', 'local_ai_manager'); - break; - default: - $message = get_string('exception_default', 'local_ai_manager'); + $message = $this->get_custom_error_message($exception->getCode(), $exception); + if (empty($message)) { + // If the tool specific connector does not provide a customized error message, we use our defaults. + switch ($exception->getCode()) { + case 401: + $message = get_string('exception_http401', 'local_ai_manager'); + break; + case 429: + $message = get_string('exception_http429', 'local_ai_manager'); + break; + case 500: + $message = get_string('exception_http500', 'local_ai_manager'); + break; + default: + $message = get_string('exception_default', 'local_ai_manager'); + } } } $debuginfo = $exception->getMessage() . '\n' . $exception->getTraceAsString() . '\n'; @@ -253,4 +256,18 @@ protected function get_headers(): array { public function allowed_mimetypes(): array { return []; } + + /** + * Provides a custom error message for a given error code. + * + * This method is intended to be overwritten by subclasses to provide customized error information. + * + * @param int $code the error code from the request of the external AI tool + * @param ?ClientExceptionInterface $exception the exception (if there is any) to extract additional information from, + * can be null if no exception had been thrown + * @return string the localized error message string + */ + protected function get_custom_error_message(int $code, ?ClientExceptionInterface $exception = null): string { + return ''; + } } diff --git a/tools/chatgpt/classes/connector.php b/tools/chatgpt/classes/connector.php index be50336..1857fcb 100644 --- a/tools/chatgpt/classes/connector.php +++ b/tools/chatgpt/classes/connector.php @@ -19,6 +19,7 @@ use local_ai_manager\local\prompt_response; use local_ai_manager\local\unit; use local_ai_manager\local\usage; +use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\StreamInterface; /** @@ -150,4 +151,21 @@ protected function get_headers(): array { public function allowed_mimetypes(): array { return ['image/png', 'image/jpeg', 'image/webp', 'image/gif']; } + + #[\Override] + protected function get_custom_error_message(int $code, ?ClientExceptionInterface $exception = null): string { + $message = ''; + switch ($code) { + case 400: + if (method_exists($exception, 'getResponse') && !empty($exception->getResponse())) { + $responsebody = json_decode($exception->getResponse()->getBody()->getContents()); + if (property_exists($responsebody, 'error') && property_exists($responsebody->error, 'code') + && $responsebody->error->code === 'content_filter') { + $message = get_string('err_contentfilter', 'aitool_chatgpt'); + } + } + break; + } + return $message; + } } diff --git a/tools/chatgpt/lang/de/aitool_chatgpt.php b/tools/chatgpt/lang/de/aitool_chatgpt.php index 1fa7cf6..a184a48 100644 --- a/tools/chatgpt/lang/de/aitool_chatgpt.php +++ b/tools/chatgpt/lang/de/aitool_chatgpt.php @@ -24,5 +24,6 @@ */ $string['adddescription'] = 'ChatGPT ist ein vielseitiges KI-Modell, das für natürliche Sprachinteraktionen wie Kundensupport, virtuelle Assistenzen, Content-Erstellung und mehr eingesetzt wird.'; +$string['err_contentfilter'] = 'Ihre Anfrage wurde vom Inhaltsfilter des KI-Tools zurückgewiesen. Ihr Prompt enthält vermutlich eine Anweisung, die nicht erlaubt ist.'; $string['pluginname'] = 'ChatGPT'; $string['privacy:metadata'] = 'Das Subplugin des ai_manager Plugins "ChatGPT" speichert keine personenbezogenen Daten.'; diff --git a/tools/chatgpt/lang/en/aitool_chatgpt.php b/tools/chatgpt/lang/en/aitool_chatgpt.php index 9d934e7..b7b19a9 100644 --- a/tools/chatgpt/lang/en/aitool_chatgpt.php +++ b/tools/chatgpt/lang/en/aitool_chatgpt.php @@ -24,5 +24,6 @@ */ $string['adddescription'] = 'ChatGPT is a versatile AI model used for natural language interactions such as customer support, virtual assistants, content creation and more.'; +$string['err_contentfilter'] = 'Your request was rejected as a result of the content filter of the external tool. Your prompt probably requests something that is not allowed.'; $string['pluginname'] = 'ChatGPT'; $string['privacy:metadata'] = 'The local ai_manager tool subplugin "ChatGPT" does not store any personal data.'; diff --git a/tools/dalle/classes/connector.php b/tools/dalle/classes/connector.php index 1b59592..091c5f2 100644 --- a/tools/dalle/classes/connector.php +++ b/tools/dalle/classes/connector.php @@ -21,6 +21,7 @@ use local_ai_manager\local\prompt_response; use local_ai_manager\local\unit; use local_ai_manager\local\usage; +use Psr\Http\Client\ClientExceptionInterface; use Psr\Http\Message\StreamInterface; /** @@ -123,4 +124,21 @@ public function get_available_options(): array { } return $options; } + + #[\Override] + protected function get_custom_error_message(int $code, ?ClientExceptionInterface $exception = null): string { + $message = ''; + switch ($code) { + case 400: + if (method_exists($exception, 'getResponse') && !empty($exception->getResponse())) { + $responsebody = json_decode($exception->getResponse()->getBody()->getContents()); + if (property_exists($responsebody, 'error') && property_exists($responsebody->error, 'code') + && $responsebody->error->code === 'content_policy_violation') { + $message = get_string('err_contentpolicyviolation', 'aitool_dalle'); + } + } + break; + } + return $message; + } } diff --git a/tools/dalle/lang/de/aitool_dalle.php b/tools/dalle/lang/de/aitool_dalle.php index 994d5dd..08c936d 100644 --- a/tools/dalle/lang/de/aitool_dalle.php +++ b/tools/dalle/lang/de/aitool_dalle.php @@ -24,5 +24,6 @@ */ $string['adddescription'] = 'Dall-E ist ein KI-Modell von OpenAI, das darauf spezialisiert ist, aus Textbeschreibungen Bilder zu generieren.'; +$string['err_contentpolicyviolation'] = 'Ihre Anfrage wurde vom Sicherheitssystem des KI-Tools zurückgewiesen. Ihr Prompt enthält vermutlich eine Anweisung, die nicht erlaubt ist.'; $string['pluginname'] = 'Dall-E'; $string['privacy:metadata'] = 'Das Subplugin des ai_manager Plugins "Dall-E" speichert keine personenbezogenen Daten.'; diff --git a/tools/dalle/lang/en/aitool_dalle.php b/tools/dalle/lang/en/aitool_dalle.php index fca6a26..3b002c3 100644 --- a/tools/dalle/lang/en/aitool_dalle.php +++ b/tools/dalle/lang/en/aitool_dalle.php @@ -24,5 +24,6 @@ */ $string['adddescription'] = 'Dall-E is an AI model from OpenAI that specializes in generating images from text descriptions.'; +$string['err_contentpolicyviolation'] = 'Your request was rejected as a result of our safety system. Your prompt probably requests something that is not allowed.'; $string['pluginname'] = 'Dall-E'; $string['privacy:metadata'] = 'The local ai_manager tool subplugin "Dall-E" does not store any personal data.';