diff --git a/htdocs/ai/admin/custom_prompt.php b/htdocs/ai/admin/custom_prompt.php index 8acc7721ba0..b562a322008 100644 --- a/htdocs/ai/admin/custom_prompt.php +++ b/htdocs/ai/admin/custom_prompt.php @@ -305,6 +305,7 @@ if ($action == 'edit' || $action == 'deleteproperty') { $out .= $form->buttonsSaveCancel("Add", ""); $out .= ''; + $out .= '


'; print $out; @@ -365,7 +366,7 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') { $out .= ''; $out .= ''; $out .= ''; - $out .= ''; + $out .= ''; $out .= '   '; include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; diff --git a/htdocs/ai/admin/setup.php b/htdocs/ai/admin/setup.php index cd3eec1c01b..cdd54cb957f 100644 --- a/htdocs/ai/admin/setup.php +++ b/htdocs/ai/admin/setup.php @@ -176,17 +176,22 @@ $out = ''; if ($functioncode) { $labeloffeature = empty($arrayofaifeatures[GETPOST('functioncode')]['label']) ? 'Undefined' : $arrayofaifeatures[GETPOST('functioncode')]['label']; - $out .= $langs->trans("Test").' '.$labeloffeature.'...

'; + //$out .= $langs->trans("Test").' '.$labeloffeature.'...

'; if (GETPOST('functioncode') == 'textgenerationemail') { - $showlinktoai = 1; + $key = 'textgenerationemail'; // The HTML ID of field to fill + + include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php'; + $showlinktoai = $key; // 'textgeneration', 'imagegeneration', ... + $showlinktoailabel = $langs->trans("Test").' '.$labeloffeature; $showlinktolayout = 0; + $formmail = new FormMail($db); + $htmlname = $key; + // Fill $out + include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php'; - $neweditor = new DolEditor('aicontenttotest', $content); - $out .= $neweditor->Create(1); - - $out .= $form->buttonsSaveCancel("Test"); + $out .= '
'; } else { $out .= $langs->trans("FeatureNotYetAvailable").'

'; $functioncode = ''; diff --git a/htdocs/ai/ajax/generate_content.php b/htdocs/ai/ajax/generate_content.php index 0f1e1f76a92..0cd6a125970 100644 --- a/htdocs/ai/ajax/generate_content.php +++ b/htdocs/ai/ajax/generate_content.php @@ -81,15 +81,17 @@ $format = empty($jsonData['format']) ? '' : $jsonData['format']; $generatedContent = $ai->generateContent($instructions, 'auto', $function, $format); -if (is_array($generatedContent) && $generatedContent['error']) { +if (is_null($generatedContent) || (is_array($generatedContent) && $generatedContent['error'])) { // Output error if (!empty($generatedContent['code']) && $generatedContent['code'] == 429) { print "Quota or allowed period exceeded. Retry Later !"; - } elseif ($generatedContent['code'] >= 400) { + } elseif (!empty($generatedContent['code']) && $generatedContent['code'] >= 400) { print "Error : " . $generatedContent['message']; print '
'.$langs->trans('ErrorGoToModuleSetup').''; - } else { + } elseif (!empty($generatedContent['message'])) { print "Error returned by API call: " . $generatedContent['message']; + } else { + print "Error API returned no answer"; } } else { if ($function == 'textgenerationemail' || $function == 'textgenerationwebpage') { diff --git a/htdocs/ai/class/ai.class.php b/htdocs/ai/class/ai.class.php index 922df84dcbb..3f6a5d6eb78 100644 --- a/htdocs/ai/class/ai.class.php +++ b/htdocs/ai/class/ai.class.php @@ -80,6 +80,8 @@ class Ai */ public function generateContent($instructions, $model = 'auto', $function = 'textgeneration', $format = '') { + global $dolibarr_main_data_root; + if (empty($this->apiKey)) { return array('error' => true, 'message' => 'API key is not defined for the AI enabled service ('.$this->apiService.')'); } @@ -199,7 +201,7 @@ class Ai $postPrompt = $configurations[$function]['postPrompt']; } } - $fullInstructions = ($prePrompt ? $prePrompt.' ' : '').$instructions.($postPrompt ? '. '.$postPrompt : ''); + $fullInstructions = $instructions.($postPrompt ? (preg_match('/[\.\!\?]$/', $instructions) ? '' : '.').' '.$postPrompt : ''); // Set payload string /*{ @@ -224,18 +226,46 @@ class Ai "temperature": 0.7, "top_p": 0.95 }*/ - $payload = json_encode([ - 'messages' => [ - ['role' => 'user', 'content' => $fullInstructions] - ], - 'model' => $model, - //'stream' => false - ]); - $headers = ([ + $arrayforpayload = array( + 'messages' => array(array('role' => 'user', 'content' => $fullInstructions)), + 'model' => $model, + ); + + // Add a system message + $addDateTimeContext = 0; + if ($addDateTimeContext) { + $prePrompt = ($prePrompt ? $prePrompt.(preg_match('/[\.\!\?]$/', $prePrompt) ? '' : '.').' ' : '').'Today we are '.dol_print_date(dol_now(), 'dayhourtext'); + } + $arrayforpayload['messages'][] = array('role' => 'system', 'content' => $prePrompt); + + /* + $arrayforpayload['temperature'] = 0.7; + $arrayforpayload['max_tokens'] = -1; + $arrayforpayload['stream'] = false; + */ + + $payload = json_encode($arrayforpayload); + + $headers = array( 'Authorization: Bearer ' . $this->apiKey, 'Content-Type: application/json' - ]); + ); + + if (getDolGlobalString("AI_DEBUG")) { + if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir + $outputfile = $dolibarr_main_data_root."/dolibarr_ai.log"; + $fp = fopen($outputfile, "w"); // overwrite + + if ($fp) { + fwrite($fp, var_export($headers, true)."\n"); + fwrite($fp, var_export($payload, true)."\n"); + + fclose($fp); + dolChmod($outputfile); + } + } + } $localurl = 2; // Accept both local and external endpoints $response = getURLContent($this->apiEndpoint, 'POST', $payload, 1, $headers, array('http', 'https'), $localurl); @@ -248,7 +278,17 @@ class Ai } if (getDolGlobalString("AI_DEBUG")) { - dol_syslog("response content = ".var_export($response['content'], true)); + if (@is_writable($dolibarr_main_data_root)) { // Avoid fatal error on fopen with open_basedir + $outputfile = $dolibarr_main_data_root."/dolibarr_ai.log"; + $fp = fopen($outputfile, "a"); + + if ($fp) { + fwrite($fp, var_export((empty($response['content']) ? 'No content result' : $response['content']), true)."\n"); + + fclose($fp); + dolChmod($outputfile); + } + } } // Decode JSON response diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index 81efbf470a7..ce57b90a4c7 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -1483,24 +1483,26 @@ class CMailFile $outputfile = $dolibarr_main_data_root."/dolibarr_mail.log"; $fp = fopen($outputfile, "w"); // overwrite - if ($this->sendmode == 'mail') { - fwrite($fp, $this->headers); - fwrite($fp, $this->eol); // This eol is added by the mail function, so we add it in log - fwrite($fp, $this->message); - } elseif ($this->sendmode == 'smtps') { - fwrite($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on - } elseif ($this->sendmode == 'swiftmailer') { - fwrite($fp, "smtpheader=\n".$this->message->getHeaders()->toString()."\n"); - fwrite($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on - } + if ($fp) { + if ($this->sendmode == 'mail') { + fwrite($fp, $this->headers); + fwrite($fp, $this->eol); // This eol is added by the mail function, so we add it in log + fwrite($fp, $this->message); + } elseif ($this->sendmode == 'smtps') { + fwrite($fp, $this->smtps->log); // this->smtps->log is filled only if MAIN_MAIL_DEBUG was set to on + } elseif ($this->sendmode == 'swiftmailer') { + fwrite($fp, "smtpheader=\n".$this->message->getHeaders()->toString()."\n"); + fwrite($fp, $this->logger->dump()); // this->logger is filled only if MAIN_MAIL_DEBUG was set to on + } - fclose($fp); - dolChmod($outputfile); + fclose($fp); + dolChmod($outputfile); - // Move dolibarr_mail.log into a dolibarr_mail.log.v123456789 - if (getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')) { - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - archiveOrBackupFile($outputfile, getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')); + // Move dolibarr_mail.log into a dolibarr_mail.log.v123456789 + if (getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')) { + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + archiveOrBackupFile($outputfile, getDolGlobalInt('MAIN_MAIL_DEBUG_LOG_WITH_DATE')); + } } } } diff --git a/htdocs/core/class/html.formmail.class.php b/htdocs/core/class/html.formmail.class.php index 6eac18f33e0..c3904969a64 100644 --- a/htdocs/core/class/html.formmail.class.php +++ b/htdocs/core/class/html.formmail.class.php @@ -1493,6 +1493,7 @@ class FormMail extends Form * @param string $format Format for output ('', 'html', ...) * @param string $htmlContent HTML name of WYSIWYG field * @return string HTML code to ask AI instruction and autofill result + * TODO Move into a file html.formai.class.php */ public function getSectionForAIPrompt($function = 'textgeneration', $format = '', $htmlContent = 'message') { @@ -1502,7 +1503,7 @@ class FormMail extends Form $htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent); - $out = '