29include_once DOL_DOCUMENT_ROOT.
'/ai/class/ai.class.php';
41 $arrayofaifeatures = array(
42 'textgenerationemail' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"EmailContent").
')',
'picto' =>
'',
'status' =>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_EMAIL),
43 'textgenerationwebpage' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"WebsitePage").
')',
'picto' =>
'',
'status' =>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_WEBPAGE),
44 'textgeneration' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"Other").
')',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TEXT'),
46 'texttranslation' => array(
'label' => $langs->trans(
'TextTranslation'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_TRANSLATION),
47 'textsummarize' => array(
'label' => $langs->trans(
'TextSummarize'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_SUMMARIZE),
48 'textspellchecker' => array(
'label' => $langs->trans(
'TextSpellChecker'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_SPELLCHECKER),
49 'textrephrase' => array(
'label' => $langs->trans(
'TextRephraser'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_REPHRASER),
51 'textgenerationextrafield' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"ExtrafieldFiller").
')',
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_EXTRAFIELD_FILLER),
53 'imagegeneration' => array(
'label' =>
'ImageGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'IMAGE'),
54 'videogeneration' => array(
'label' =>
'VideoGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'VIDEO'),
55 'audiogeneration' => array(
'label' =>
'AudioGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'AUDIO'),
56 'transcription' => array(
'label' =>
'AudioTranscription',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TRANSCRIPT'),
57 'translation' => array(
'label' =>
'AudioTranslation',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TRANSLATE'),
58 'docparsing' => array(
'label' =>
'DocumentParsing',
'picto' =>
'',
'status' =>
'experimental',
'function' =>
'DOCPARSING')
61 return $arrayofaifeatures;
74 '-1' => array(
'label' => $langs->trans(
'SelectAService')),
76 'label' =>
'ChatGPT (OpenAI)',
77 'url' =>
'https://api.openai.com/v1/',
78 'setup' =>
'https://platform.openai.com/account/api-keys',
79 'textgeneration' => array(
'default' =>
'gpt-5.2'),
80 'imagegeneration' => array(
'default' =>
'gpt-image-1.5'),
81 'audiogeneration' => array(
'default' =>
'gpt-audio-1.5'),
82 'videogeneration' => array(
'default' =>
'sora-2'),
83 'transcription' => array(
'default' =>
'whisper-large-v3-turbo'),
84 'translation' => array(
'default' =>
'whisper-large-v3-turbo'),
85 'docparsing' => array(
'default' =>
'gpt-5.2'),
86 'adapter_type' =>
'openai'
89 'label' =>
'Groq (LPU Inference)',
90 'url' =>
'https://api.groq.com/openai/v1/',
91 'setup' =>
'https://console.groq.com/keys',
92 'textgeneration' => array(
'default' =>
'llama-4-8b-instant'),
93 'imagegeneration' => array(
'default' =>
'na'),
94 'audiogeneration' => array(
'default' =>
'na'),
95 'videogeneration' => array(
'default' =>
'na'),
96 'transcription' => array(
'default' =>
'whisper-large-v3-turbo'),
97 'translation' => array(
'default' =>
'whisper-large-v3-turbo'),
98 'docparsing' => array(
'default' =>
'llama-4-70b-versatile'),
99 'adapter_type' =>
'openai'
102 'label' =>
'Mistral AI',
103 'url' =>
'https://api.mistral.ai/v1/',
104 'setup' =>
'https://console.mistral.ai/api-keys/',
105 'textgeneration' => array(
'default' =>
'mistral-small-latest',
'examples' =>
'mistral-tiny-latest, mistral-small-latest, mistral-medium-latest, mistral-large-latest'),
106 'imagegeneration' => array(
'default' =>
'na'),
107 'audiogeneration' => array(
'default' =>
'na'),
108 'videogeneration' => array(
'default' =>
'na'),
109 'transcription' => array(
'default' =>
'na'),
110 'translation' => array(
'default' =>
'na'),
111 'docparsing' => array(
'default' =>
'pixtral-12b-latest'),
112 'adapter_type' =>
'openai'
115 'label' =>
'DeepSeek',
116 'url' =>
'https://api.deepseek.com',
117 'setup' =>
'https://platform.deepseek.com/api_keys',
118 'textgeneration' => array(
'default' =>
'deepseek-v4'),
119 'imagegeneration' => array(
'default' =>
'deepseek-janus-2'),
120 'audiogeneration' => array(
'default' =>
'na'),
121 'videogeneration' => array(
'default' =>
'na'),
122 'transcription' => array(
'default' =>
'na'),
123 'translation' => array(
'default' =>
'na'),
124 'docparsing' => array(
'default' =>
'deepseek-v4'),
125 'adapter_type' =>
'openai'
127 'perplexity' => array(
128 'label' =>
'Perplexity (Sonar)',
129 'url' =>
'https://api.perplexity.ai',
130 'setup' =>
'https://www.perplexity.ai/settings/api',
131 'textgeneration' => array(
'default' =>
'sonar-pro'),
132 'imagegeneration' => array(
'default' =>
'na'),
133 'audiogeneration' => array(
'default' =>
'na'),
134 'videogeneration' => array(
'default' =>
'na'),
135 'transcription' => array(
'default' =>
'na'),
136 'translation' => array(
'default' =>
'na'),
137 'docparsing' => array(
'default' =>
'sonar-reasoning'),
138 'adapter_type' =>
'openai'
141 'label' =>
'Zhipu AI (GLM)',
142 'url' =>
'https://api.z.ai/api/paas/v4',
143 'setup' =>
'https://docs.z.ai/guides/overview/quick-start',
144 'textgeneration' => array(
'default' =>
'glm-5'),
145 'imagegeneration' => array(
'default' =>
'cogview-4'),
146 'audiogeneration' => array(
'default' =>
'cogvlm2-audio'),
147 'videogeneration' => array(
'default' =>
'cogvideox-2'),
148 'transcription' => array(
'default' =>
'na'),
149 'translation' => array(
'default' =>
'na'),
150 'docparsing' => array(
'default' =>
'glm-5'),
151 'adapter_type' =>
'openai'
155 'url' =>
'https://domainofapi.com/v1/',
156 'setup' =>
'Ask your AI provider how to get your API key',
157 'textgeneration' => array(
'default' =>
'tinyllama-1.1b'),
158 'imagegeneration' => array(
'default' =>
'mixtral-8x7b-32768'),
159 'audiogeneration' => array(
'default' =>
'mixtral-8x7b-32768'),
160 'videogeneration' => array(
'default' =>
'na'),
161 'transcription' => array(
'default' =>
'mixtral-8x7b-32768'),
162 'translation' => array(
'default' =>
'mixtral-8x7b-32768'),
163 'docparsing' => array(
'default' =>
'na'),
164 'adapter_type' =>
'openai'
167 'anthropic' => array(
168 'label' =>
'Anthropic (Claude)',
169 'url' =>
'https://api.anthropic.com/v1/',
170 'setup' =>
'https://console.anthropic.com/',
171 'textgeneration' => array(
'default' =>
'claude-opus-4-6'),
172 'imagegeneration' => array(
'default' =>
'na'),
173 'audiogeneration' => array(
'default' =>
'na'),
174 'videogeneration' => array(
'default' =>
'na'),
175 'transcription' => array(
'default' =>
'na'),
176 'translation' => array(
'default' =>
'na'),
177 'docparsing' => array(
'default' =>
'claude-opus-4-6'),
178 'adapter_type' =>
'anthropic'
181 'label' =>
'Google Gemini',
182 'url' =>
'https://generativelanguage.googleapis.com/v1beta/',
183 'setup' =>
'https://aistudio.google.com/',
184 'textgeneration' => array(
'default' =>
'gemini-3.1-pro-preview'),
185 'imagegeneration' => array(
'default' =>
'nano-banana-pro'),
186 'audiogeneration' => array(
'default' =>
'gemini-2.5-pro-tts'),
187 'videogeneration' => array(
'default' =>
'veo-3.1'),
188 'transcription' => array(
'default' =>
'gemini-3.1-pro-preview'),
189 'translation' => array(
'default' =>
'gemini-3.1-pro-preview'),
190 'docparsing' => array(
'default' =>
'gemini-3.1-pro-preview'),
191 'adapter_type' =>
'google'
216 return [
'success' =>
false,
'message' =>
'API Key is empty'];
220 if (!function_exists(
'getListOfAIServices')) {
221 return [
'success' =>
false,
'message' =>
'Configuration helper function missing.'];
225 $defUrl = $list[$service][
'url'] ??
'';
227 $defaultModel = $list[$service][
'model'] ??
'unknown';
233 $url = rtrim($url,
'/');
236 $headers = [
"Content-Type: application/json"];
244 if ($service ==
'google' || strpos($url,
'googleapis') !==
false) {
245 if (strpos($url,
':generateContent') ===
false) {
246 if (strpos($url,
'models') ===
false) {
247 $url .=
"/models/$model:generateContent";
249 $url .=
"/$model:generateContent";
252 $url .=
"?key=" . $key;
253 $data = [
"contents" => [ [
"parts" => [ [
"text" =>
"Hello"] ] ] ],
"generationConfig" => [
"maxOutputTokens" => 5]];
254 } elseif ($service ==
'anthropic' || strpos($url,
'anthropic') !==
false) {
255 if (strpos($url,
'messages') ===
false) $url .=
'/messages';
256 $headers[] =
"x-api-key: $key";
257 $headers[] =
"anthropic-version: 2023-06-01";
260 "messages" => [[
"role" =>
"user",
"content" =>
"Hello"]],
264 if (strpos($url,
'/chat/completions') ===
false) $url .=
'/chat/completions';
265 $headers[] =
"Authorization: Bearer $key";
269 "messages" => [[
"role" =>
"user",
"content" =>
"Hello"]],
276 curl_setopt($ch, CURLOPT_URL, $url);
277 curl_setopt($ch, CURLOPT_POST,
true);
278 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
279 curl_setopt($ch, CURLOPT_RETURNTRANSFER,
true);
280 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
281 curl_setopt($ch, CURLOPT_TIMEOUT, 10);
285 $result = curl_exec($ch);
286 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
287 $err = curl_error($ch);
291 return [
'success' =>
false,
'message' =>
"Curl Error: $err"];
294 if ($httpCode >= 200 && $httpCode < 300) {
295 return [
'success' =>
true,
'message' =>
"OK (HTTP $httpCode)."];
297 $json = json_decode($result,
true);
299 $msg = $json[
'error'][
'message'] ?? $json[
'message'] ?? substr($result, 0, 150);
300 return [
'success' =>
false,
'message' =>
"HTTP $httpCode. Error: $msg"];
320function ai_log_request(
$db, $user, $query, array $response, $provider,
float $time,
float $confidence, $status, $error =
'', $rawReq =
'', $rawRes =
'')
328 $tool = isset($response[
'tool']) ? (
string) $response[
'tool'] :
'';
331 $rawReq =
dol_substr($rawReq, 0, 60000) .
'... [Truncated]';
334 $rawResStr = (
string) $rawRes;
336 $rawResStr =
dol_substr($rawResStr, 0, 60000) .
'... [Truncated]';
339 $sql =
"INSERT INTO " . MAIN_DB_PREFIX .
"ai_request_log (";
340 $sql .=
"entity, date_request, fk_user, query_text, tool_name, provider, ";
341 $sql .=
"execution_time, confidence, status, error_msg, raw_request_payload, raw_response_payload";
342 $sql .=
") VALUES (";
343 $sql .= ((int)
$conf->entity) .
", ";
345 $sql .= ((int) $user->id) .
", ";
346 $sql .=
"'" .
$db->escape($query) .
"', ";
347 $sql .=
"'" .
$db->escape($tool) .
"', ";
348 $sql .=
"'" .
$db->escape($provider) .
"', ";
349 $sql .= ((float) $time) .
", ";
350 $sql .= ((float) $confidence) .
", ";
351 $sql .=
"'" .
$db->escape($status) .
"', ";
352 $sql .=
"'" .
$db->escape($error) .
"', ";
353 $sql .=
"'" .
$db->escape($rawReq) .
"', ";
354 $sql .=
"'" .
$db->escape($rawResStr) .
"'";
357 $resql =
$db->query($sql);
372 $arrayforaisummarize = array(
374 '50_w' =>
'SummarizeFiftyWords',
375 '100_w' =>
'SummarizeHundredWords',
376 '200_w' =>
'SummarizeTwoHundredWords',
377 '1_p' =>
'SummarizeOneParagraphs',
378 '2_p' =>
'SummarizeTwoParagraphs',
379 '25_pc' =>
'SummarizeTwentyFivePercent',
380 '50_pc' =>
'SummarizeFiftyPercent',
381 '75_pc' =>
'SummarizeSeventyFivePercent'
384 return $arrayforaisummarize;
394 $arrayforaierephrasestyle = array(
395 'spellchecker' =>
'RephraseSpellChecker',
396 'professional' =>
'RephraseStyleProfessional',
397 'humouristic' =>
'RephraseStyleHumouristic',
400 return $arrayforaierephrasestyle;
410 global $langs,
$conf;
412 $langs->load(
"agenda");
418 $head[$h][1] = $langs->trans(
"Settings");
419 $head[$h][2] =
'settings';
422 $head[$h][0] =
dol_buildpath(
"/ai/admin/custom_prompt.php", 1);
423 $head[$h][1] = $langs->trans(
"CustomPrompt");
424 $head[$h][2] =
'custom';
429 $head[$h][1] = $langs->trans(
"Assistant");
430 $head[$h][2] =
'assistant';
436 $head[$h][1] = $langs->trans(
"MCPServer");
437 $head[$h][2] =
'servermcp';
442 $head[$h][0] =
dol_buildpath(
"/ai/admin/configure_tools.php", 1);
443 $head[$h][1] = $langs->trans(
"ToolAccessControl");
444 $head[$h][2] =
'tools';
481 if (empty($serviceKey) || $serviceKey ===
'-1') {
487 return isset($services[$serviceKey][
'label']) ? (
string) $services[$serviceKey][
'label'] : (
string) $serviceKey;
498 global $langs, $user;
509 'ClearChatHistoryTitle',
536 'UnsupportedFileType',
549 'ConnectionBlockedHelp',
554 'BrowserNotSupported',
586 $ai_translations = array();
587 foreach ($keys as $key) {
588 $ai_translations[$key] = $langs->transnoentitiesnoconv($key);
590 $ai_translations[
'DownloadPdf'] = $langs->transnoentitiesnoconv(
"Download").
' PDF';
591 $ai_translations[
'CloudVoiceRequiresSecureContext'] = $langs->trans(
592 "CloudVoiceRequiresSecureContext",
600 if (is_object($user)) {
601 $namesource = $user->firstname ? $user->firstname : ($user->login ? $user->login :
'');
607 'labels' => $ai_translations,
613 'userInitial' => $userinitial,
627 global $langs, $user,
$conf;
634 $out .=
'<div class="ai-chat-container'.($mode ===
'popover' ?
' ai-in-popover' :
'').
'"';
636 if ($mode ===
'page') {
637 $out .=
' data-ai-autoinit="1"';
642 $out .=
'<div class="chat-header">';
643 if ($mode ===
'popover') {
645 $title =
img_picto(
'',
'fa-robot',
'', 0, 0, 0,
'',
'paddingright').$langs->trans(
"AIAssistant");
646 $title =
'<a href="'.dol_buildpath(
'/ai/assistant/index.php', 1).
'" class="ai-header-link" title="'.
dol_escape_htmltag($langs->trans(
"AIOpenFullPage")).
'">'.$title.
'</a>';
647 $out .=
'<h2>'.$title.
'</h2>';
650 $out .=
'<div class="chat-header-id">';
651 $out .=
'<span class="chat-header-avatar">'.img_picto(
'',
'fa-robot').
'</span>';
652 $out .=
'<span class="chat-header-text">';
653 $out .=
'<span class="chat-header-title">'.$langs->trans(
"AIAssistant").
'</span>';
655 if ($aiprovider !==
'') {
656 $out .=
'<span class="chat-header-status" title="'.dol_escape_htmltag($langs->trans(
"AIProviderInUse")).
'">'.
dol_escape_htmltag($aiprovider).
'</span>';
661 $out .=
'<div class="header-controls">';
664 $out .=
'<select id="model-select" class="engine-select model-select" title="'.dol_escape_htmltag($langs->trans(
"AIModelToUse")).
'">';
665 $out .=
'<option value="">'.$langs->transnoentitiesnoconv(
"AIModelAuto").
'</option>';
668 $out .=
'<select id="engine-select" class="engine-select">';
669 $out .=
'<option value="text">'.$langs->transnoentitiesnoconv(
"OptionTextOnly").
'</option>';
670 $out .=
'<option value="cloud">'.$langs->transnoentitiesnoconv(
"OptionCloudFast").
'</option>';
671 $out .=
'<option value="whisper">'.$langs->transnoentitiesnoconv(
"OptionWhisperLocal").
'</option>';
677 $out .=
'<button type="button" id="clear-btn" class="icon-btn" title="'.dol_escape_htmltag($langs->trans(
"ClearChatHistoryTitle")).
'">';
678 $out .=
img_picto(
'',
'fa-trash').
' <span class="ai-btn-label">'.$langs->trans(
"Clear").
'</span>';
680 if ($mode ===
'popover') {
682 $out .=
'<button type="button" id="ai-expand-btn" class="icon-btn ai-window-btn" title="'.dol_escape_htmltag($langs->trans(
"AIExpandPanel")).
'" data-title-expand="'.
dol_escape_htmltag($langs->trans(
"AIExpandPanel")).
'" data-title-reduce="'.
dol_escape_htmltag($langs->trans(
"AIReducePanel")).
'"><i class="fa fa-expand-alt"></i></button>';
683 $out .=
'<button type="button" id="ai-close-btn" class="icon-btn ai-window-btn" title="'.dol_escape_htmltag($langs->trans(
"Close")).
'"><i class="fa fa-times"></i></button>';
689 $out .=
'<div id="chat-history" class="chat-history">';
690 if ($mode ===
'popover') {
692 $out .=
'<div class="msg system">'.$langs->trans(
"AIWelcomeMessage").
'</div>';
697 $welcomename = $user->firstname ? $user->firstname : (is_object($user) ? $user->login :
'');
699 array(
'icon' =>
'fa-file-invoice-dollar',
'key' =>
'Invoices'),
700 array(
'icon' =>
'fa-chart-line',
'key' =>
'Revenue'),
701 array(
'icon' =>
'fa-coins',
'key' =>
'Finance'),
702 array(
'icon' =>
'fa-warehouse',
'key' =>
'Inventory'),
704 $out .=
'<div class="chat-welcome">';
705 $out .=
'<div class="chat-welcome-avatar">'.img_picto(
'',
'fa-robot').
'</div>';
706 $out .=
'<h2 class="chat-welcome-title">'.dol_escape_htmltag($langs->trans(
"AIGreeting", $welcomename)).
'</h2>';
707 $out .=
'<p class="chat-welcome-subtitle">'.dol_escape_htmltag($langs->trans(
"AIGreetingSubtitle")).
'</p>';
708 $out .=
'<div class="chat-welcome-actions">';
709 foreach ($quickcards as $card) {
710 $out .=
'<button type="button" class="ai-quick-card" data-prompt="'.dol_escape_htmltag($langs->transnoentitiesnoconv(
"AIQuick".$card[
'key'].
"Prompt")).
'">';
711 $out .=
'<span class="ai-quick-icon">'.img_picto(
'', $card[
'icon']).
'</span>';
712 $out .=
'<span class="ai-quick-text">';
713 $out .=
'<span class="ai-quick-title">'.dol_escape_htmltag($langs->trans(
"AIQuick".$card[
'key'].
"Title")).
'</span>';
714 $out .=
'<span class="ai-quick-desc">'.dol_escape_htmltag($langs->trans(
"AIQuick".$card[
'key'].
"Desc")).
'</span>';
725 $out .=
'<div class="chat-controls">';
729 $out .=
'<div id="file-chip-area" class="file-chip-area ai-hidden"></div>';
730 $out .=
'<div class="chat-input-pill">';
732 $out .=
'<div id="upload-wrapper" class="upload-wrapper">';
733 $out .=
'<input type="file" id="file-upload" accept=".pdf,.txt,.xml,.png,.jpg,.jpeg,.doc,.docx,.xls,.xlsx,.odt,.ods" style="display: none;">';
734 $out .=
'<button type="button" id="upload-btn" class="round-btn" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv(
"AttachFile")).
'">'.
img_picto(
'',
'fa-paperclip').
'</button>';
737 $out .=
'<div id="mic-wrapper" class="mic-wrapper ai-hidden">';
738 $out .=
'<button type="button" id="mic-btn" class="round-btn mic-btn" title="'.dol_escape_htmltag($langs->trans(
"ToggleMicrophone")).
'">'.
img_picto(
'',
'fa-microphone').
'</button>';
741 $out .=
'<textarea id="user-input" class="ia-input" rows="1"';
742 if (empty(
$conf->dol_optimize_smallscreen)) {
743 $out .=
' placeholder="'.dol_escape_htmltag($langs->trans(
"TypeYourQuestion")).
'"';
745 $out .=
' autocomplete="off" spellcheck="false"></textarea>';
747 $out .=
'<button type="button" id="send-btn" class="chat-send-btn" title="'.dol_escape_htmltag($langs->trans(
"SendPrompt")).
'">'.
img_picto(
'',
'fa-paper-plane').
'</button>';
751 $out .=
'<div id="status-bar"></div>';
testAIConnection(string $service, string $key, string $url)
Tests the connection to an AI service using its API key and URL by sending message "Hello".
getListOfAIFeatures()
Prepare admin pages header.
aiAdminPrepareHead()
Prepare admin pages header.
getListOfAIServices()
Get list of available ai services.
ai_log_request($db, $user, $query, array $response, $provider, float $time, float $confidence, $status, $error='', $rawReq='', $rawRes='')
Log AI Request with Raw Payloads.
getAiChatAssistantConfig()
Build the configuration array consumed by the AI Assistant chat frontend (ai/js/ai_assistant....
getListForAIRephraseStyle()
Get list for AI style of writing.
getAiAssistantProviderLabel()
Resolve the AI provider/service currently configured for the AI Assistant (e.g.
getListForAISummarize()
Get list for AI summarize.
getAiChatAssistantHtml($mode='page')
Build the HTML of the AI Assistant chat interface.
dol_now($mode='gmt')
Return date for now.
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
dol_strtoupper($string, $encoding="UTF-8")
Convert a string to upper.
dol_substr($string, $start, $length=null, $stringencoding='', $trunconbytes=0)
Make a substring.
dol_buildpath($path, $type=0, $returnemptyifnotfound=0)
Return path of url or filesystem.
complete_head_from_modules($conf, $langs, $object, &$head, &$h, $type, $mode='add', $filterorigmodule='')
Complete or removed entries into a head array (used to build tabs).
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
img_picto($titlealt, $picto, $moreatt='', $pictoisfullpath=0, $srconly=0, $notitle=0, $alt='', $morecss='', $marginleftonlyshort=2, $allowothertags=array())
Show picto whatever it's its name (generic function)
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Returns text escaped for inclusion in HTML alt or title or value tags, or into values of HTML input f...
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string