88 public function generateContent($instructions, $model =
'auto', $function =
'textgeneration', $format =
'')
90 global $dolibarr_main_data_root;
95 if (empty($this->apiKey) && in_array($this->apiService, array(
'chatgpt',
'groq',
'mistral'))) {
96 return array(
'error' =>
true,
'message' =>
'API key is not defined for the AI enabled service ('.$this->apiService.
')');
101 if (empty($this->apiEndpoint) && $this->apiService ==
'custom' && !
getDolGlobalString(
'AI_API_CUSTOM_URL')) {
102 return array(
'error' =>
true,
'message' =>
'API URL is not defined for the AI enabled service ('.$this->apiService.
')');
106 if (empty($this->apiEndpoint)) {
108 if ($function ==
'imagegeneration') {
109 $this->apiEndpoint =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_URL', $arrayofai[$this->apiService][
'url']);
110 $this->apiEndpoint .= (preg_match(
'/\/$/', $this->apiEndpoint) ?
'' :
'/').
'images/generations';
111 } elseif ($function ==
'audiogeneration') {
112 $this->apiEndpoint =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_URL', $arrayofai[$this->apiService][
'url']);
113 $this->apiEndpoint .= (preg_match(
'/\/$/', $this->apiEndpoint) ?
'' :
'/').
'audio/speech';
114 } elseif ($function ==
'transcription') {
115 $this->apiEndpoint =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_URL', $arrayofai[$this->apiService][
'url']);
116 $this->apiEndpoint .= (preg_match(
'/\/$/', $this->apiEndpoint) ?
'' :
'/').
'transcriptions';
118 $this->apiEndpoint =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_URL', $arrayofai[$this->apiService][
'url']);
119 $this->apiEndpoint .= (preg_match(
'/\/$/', $this->apiEndpoint) ?
'' :
'/').
'chat/completions';
125 if (empty($model) || $model ==
'auto') {
127 if ($function ==
'imagegeneration') {
128 $model =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_MODEL_IMAGE', $arrayofai[$this->apiService][$function]);
129 } elseif ($function ==
'audiogeneration') {
130 $model =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_MODEL_AUDIO', $arrayofai[$this->apiService][$function]);
131 } elseif ($function ==
'transcription') {
132 $model =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_MODEL_TRANSCRIPT', $arrayofai[$this->apiService][$function]);
133 } elseif ($function ==
'translation') {
134 $model =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_MODEL_TRANSLATE', $arrayofai[$this->apiService][$function]);
137 $model =
getDolGlobalString(
'AI_API_'.strtoupper($this->apiService).
'_MODEL_TEXT', $arrayofai[$this->apiService][
'textgeneration']);
141 dol_syslog(
"Call API for apiKey=".substr($this->apiKey, 0, 5).
'***********, apiEndpoint='.$this->apiEndpoint.
", model=".$model);
144 if (empty($this->apiEndpoint)) {
145 throw new Exception(
'The AI service '.$this->apiService.
' is not yet supported for the type of request '.$function);
149 $configurations = json_decode($configurationsJson,
true);
154 if (isset($configurations[$function])) {
155 if (isset($configurations[$function][
'prePrompt'])) {
156 $prePrompt = $configurations[$function][
'prePrompt'];
159 if (isset($configurations[$function][
'postPrompt'])) {
160 $postPrompt = $configurations[$function][
'postPrompt'];
165 if (empty($prePrompt) && $function ==
'textgenerationemail') {
166 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_EMAIL;
168 if (empty($prePrompt) && $function ==
'textgenerationwebpage') {
169 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_WEBPAGE;
171 if (empty($prePrompt) && $function ==
'textgenerationextrafield') {
172 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_EXTRAFIELD_FILLER;
174 if (empty($prePrompt) && $function ==
'texttranslation') {
175 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_TEXT_TRANSLATION;
177 if (empty($prePrompt) && $function ==
'textsummarize') {
178 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_TEXT_SUMMARIZE;
180 if (empty($prePrompt) && $function ==
'textrephraser') {
181 $prePrompt = self::AI_DEFAULT_PROMPT_FOR_TEXT_REPHRASER;
184 $fullInstructions = $instructions.($postPrompt ? (preg_match(
'/[\.\!\?]$/', $instructions) ?
'' :
'.').
' '.$postPrompt :
'');
210 $arrayforpayload = array(
211 'messages' => array(array(
'role' =>
'user',
'content' => $fullInstructions)),
216 $addDateTimeContext =
false;
217 if ($addDateTimeContext) {
218 $prePrompt = ($prePrompt ? $prePrompt.(preg_match(
'/[\.\!\?]$/', $prePrompt) ?
'' :
'.').
' ' :
'').
'Today we are '.
dol_print_date(
dol_now(),
'dayhourtext');
221 $arrayforpayload[
'messages'][] = array(
'role' =>
'system',
'content' => $prePrompt);
230 $payload = json_encode($arrayforpayload);
233 'Authorization: Bearer ' . $this->apiKey,
234 'Content-Type: application/json'
238 if (@is_writable($dolibarr_main_data_root)) {
239 $outputfile = $dolibarr_main_data_root.
"/dolibarr_ai.log";
240 $fp = fopen($outputfile,
"w");
243 fwrite($fp, var_export($headers,
true).
"\n");
244 fwrite($fp, var_export($payload,
true).
"\n");
253 $response =
getURLContent($this->apiEndpoint,
'POST', $payload, 1, $headers, array(
'http',
'https'), $localurl);
255 if (empty($response[
'http_code'])) {
256 throw new Exception(
'API request failed. No http received');
258 if (!empty($response[
'http_code']) && $response[
'http_code'] != 200) {
259 if (in_array($response[
'http_code'], array(400, 401, 403, 429)) && !empty($response[
'content'])) {
260 $tmp = json_decode($response[
'content'],
true);
261 if (!empty($tmp[
'message'])) {
264 'message' => $tmp[
'message'],
265 'code' => (empty($response[
'http_code']) ? 0 : $response[
'http_code']),
266 'curl_error_no' => (empty($response[
'curl_error_no']) ? 0 : $response[
'curl_error_no']),
268 'service' => $this->apiService,
269 'function' => $function
273 throw new Exception(
'API request on AI endpoint '.$this->apiEndpoint.
' failed with status code '.$response[
'http_code'].(empty($response[
'content']) ?
'' :
' - '.$response[
'content']));
277 if (@is_writable($dolibarr_main_data_root)) {
278 $outputfile = $dolibarr_main_data_root.
"/dolibarr_ai.log";
279 $fp = fopen($outputfile,
"a");
282 fwrite($fp, var_export((empty($response[
'content']) ?
'No content result' : $response[
'content']),
true).
"\n");
292 $decodedResponse = json_decode($response[
'content'],
true);
295 if (!empty($decodedResponse[
'error'])) {
296 if (is_scalar($decodedResponse[
'error'])) {
297 $generatedContent = $decodedResponse[
'error'];
299 $generatedContent = var_export($decodedResponse[
'error'],
true);
302 $generatedContent = $decodedResponse[
'choices'][0][
'message'][
'content'];
307 if ($format ==
'html') {
309 dol_syslog(
"Result was detected as not HTML so we convert it into HTML.");
310 $generatedContent =
dol_nl2br($generatedContent);
312 dol_syslog(
"Result was detected as already HTML. Do nothing.");
320 return $generatedContent;
322 $errormessage = $e->getMessage();
323 if (!empty($response[
'content'])) {
324 $decodedResponse = json_decode($response[
'content'],
true);
327 if (!empty($decodedResponse[
'error'][
'message'])) {
328 $errormessage .=
' - '.$decodedResponse[
'error'][
'message'];
334 'message' => $errormessage,
335 'code' => (empty($response[
'http_code']) ? 0 : $response[
'http_code']),
336 'curl_error_no' => (empty($response[
'curl_error_no']) ? 0 : $response[
'curl_error_no']),
338 'service' => $this->apiService,
339 'function' => $function