Skip to content

Commit

Permalink
MBS-9385: Add custom error handling for content filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
PhMemmel committed Oct 29, 2024
1 parent 00c7d2c commit 488f8bc
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 13 deletions.
44 changes: 31 additions & 13 deletions classes/base_connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,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.
Expand All @@ -210,18 +210,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';
Expand Down Expand Up @@ -253,4 +257,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 '';
}
}
18 changes: 18 additions & 0 deletions tools/chatgpt/classes/connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions tools/chatgpt/lang/de/aitool_chatgpt.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
1 change: 1 addition & 0 deletions tools/chatgpt/lang/en/aitool_chatgpt.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
18 changes: 18 additions & 0 deletions tools/dalle/classes/connector.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand Down Expand Up @@ -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;
}
}
1 change: 1 addition & 0 deletions tools/dalle/lang/de/aitool_dalle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
1 change: 1 addition & 0 deletions tools/dalle/lang/en/aitool_dalle.php
Original file line number Diff line number Diff line change
Expand Up @@ -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.';

0 comments on commit 488f8bc

Please sign in to comment.