28include_once DOL_DOCUMENT_ROOT.
'/ai/class/ai.class.php';
40 $arrayofaifeatures = array(
41 'textgenerationemail' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"EmailContent").
')',
'picto' =>
'',
'status' =>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_EMAIL),
42 'textgenerationwebpage' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"WebsitePage").
')',
'picto' =>
'',
'status' =>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_WEBPAGE),
43 'textgeneration' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"Other").
')',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TEXT'),
45 'texttranslation' => array(
'label' => $langs->trans(
'TextTranslation'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_TRANSLATION),
46 'textsummarize' => array(
'label' => $langs->trans(
'TextSummarize'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_SUMMARIZE),
47 'textspellchecker' => array(
'label' => $langs->trans(
'TextSpellChecker'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_SPELLCHECKER),
48 'textrephrase' => array(
'label' => $langs->trans(
'TextRephraser'),
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_TEXT_REPHRASER),
50 'textgenerationextrafield' => array(
'label' => $langs->trans(
'TextGeneration').
' ('.$langs->trans(
"ExtrafieldFiller").
')',
'picto' =>
'',
'status'=>
'dolibarr',
'function' =>
'TEXT',
'placeholder' => Ai::AI_DEFAULT_PROMPT_FOR_EXTRAFIELD_FILLER),
52 'imagegeneration' => array(
'label' =>
'ImageGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'IMAGE'),
53 'videogeneration' => array(
'label' =>
'VideoGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'VIDEO'),
54 'audiogeneration' => array(
'label' =>
'AudioGeneration',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'AUDIO'),
55 'transcription' => array(
'label' =>
'AudioTranscription',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TRANSCRIPT'),
56 'translation' => array(
'label' =>
'AudioTranslation',
'picto' =>
'',
'status' =>
'notused',
'function' =>
'TRANSLATE'),
57 'docparsing' => array(
'label' =>
'DocumentParsing',
'picto' =>
'',
'status' =>
'experimental',
'function' =>
'DOCPARSING')
60 return $arrayofaifeatures;
73 '-1' => array(
'label' => $langs->trans(
'SelectAService')),
75 'label' =>
'ChatGPT (OpenAI)',
76 'url' =>
'https://api.openai.com/v1/',
77 'setup' =>
'https://platform.openai.com/account/api-keys',
78 'textgeneration' => array(
'default' =>
'gpt-5.2'),
79 'imagegeneration' => array(
'default' =>
'gpt-image-1.5'),
80 'audiogeneration' => array(
'default' =>
'gpt-audio-1.5'),
81 'videogeneration' => array(
'default' =>
'sora-2'),
82 'transcription' => array(
'default' =>
'whisper-large-v3-turbo'),
83 'translation' => array(
'default' =>
'whisper-large-v3-turbo'),
84 'docparsing' => array(
'default' =>
'gpt-5.2'),
85 'adapter_type' =>
'openai'
88 'label' =>
'Groq (LPU Inference)',
89 'url' =>
'https://api.groq.com/openai/v1/',
90 'setup' =>
'https://console.groq.com/keys',
91 'textgeneration' => array(
'default' =>
'llama-4-8b-instant'),
92 'imagegeneration' => array(
'default' =>
'na'),
93 'audiogeneration' => array(
'default' =>
'na'),
94 'videogeneration' => array(
'default' =>
'na'),
95 'transcription' => array(
'default' =>
'whisper-large-v3-turbo'),
96 'translation' => array(
'default' =>
'whisper-large-v3-turbo'),
97 'docparsing' => array(
'default' =>
'llama-4-70b-versatile'),
98 'adapter_type' =>
'openai'
101 'label' =>
'Mistral AI',
102 'url' =>
'https://api.mistral.ai/v1/',
103 'setup' =>
'https://console.mistral.ai/api-keys/',
104 'textgeneration' => array(
'default' =>
'mistral-small-latest',
'examples' =>
'mistral-tiny-latest, mistral-small-latest, mistral-medium-latest, mistral-large-latest'),
105 'imagegeneration' => array(
'default' =>
'na'),
106 'audiogeneration' => array(
'default' =>
'na'),
107 'videogeneration' => array(
'default' =>
'na'),
108 'transcription' => array(
'default' =>
'na'),
109 'translation' => array(
'default' =>
'na'),
110 'docparsing' => array(
'default' =>
'pixtral-12b-latest'),
111 'adapter_type' =>
'openai'
114 'label' =>
'DeepSeek',
115 'url' =>
'https://api.deepseek.com',
116 'setup' =>
'https://platform.deepseek.com/api_keys',
117 'textgeneration' => array(
'default' =>
'deepseek-v4'),
118 'imagegeneration' => array(
'default' =>
'deepseek-janus-2'),
119 'audiogeneration' => array(
'default' =>
'na'),
120 'videogeneration' => array(
'default' =>
'na'),
121 'transcription' => array(
'default' =>
'na'),
122 'translation' => array(
'default' =>
'na'),
123 'docparsing' => array(
'default' =>
'deepseek-v4'),
124 'adapter_type' =>
'openai'
126 'perplexity' => array(
127 'label' =>
'Perplexity (Sonar)',
128 'url' =>
'https://api.perplexity.ai',
129 'setup' =>
'https://www.perplexity.ai/settings/api',
130 'textgeneration' => array(
'default' =>
'sonar-pro'),
131 'imagegeneration' => array(
'default' =>
'na'),
132 'audiogeneration' => array(
'default' =>
'na'),
133 'videogeneration' => array(
'default' =>
'na'),
134 'transcription' => array(
'default' =>
'na'),
135 'translation' => array(
'default' =>
'na'),
136 'docparsing' => array(
'default' =>
'sonar-reasoning'),
137 'adapter_type' =>
'openai'
140 'label' =>
'Zhipu AI (GLM)',
141 'url' =>
'https://api.z.ai/api/paas/v4',
142 'setup' =>
'https://docs.z.ai/guides/overview/quick-start',
143 'textgeneration' => array(
'default' =>
'glm-5'),
144 'imagegeneration' => array(
'default' =>
'cogview-4'),
145 'audiogeneration' => array(
'default' =>
'cogvlm2-audio'),
146 'videogeneration' => array(
'default' =>
'cogvideox-2'),
147 'transcription' => array(
'default' =>
'na'),
148 'translation' => array(
'default' =>
'na'),
149 'docparsing' => array(
'default' =>
'glm-5'),
150 'adapter_type' =>
'openai'
154 'url' =>
'https://domainofapi.com/v1/',
155 'setup' =>
'Ask your AI provider how to get your API key',
156 'textgeneration' => array(
'default' =>
'tinyllama-1.1b'),
157 'imagegeneration' => array(
'default' =>
'mixtral-8x7b-32768'),
158 'audiogeneration' => array(
'default' =>
'mixtral-8x7b-32768'),
159 'videogeneration' => array(
'default' =>
'na'),
160 'transcription' => array(
'default' =>
'mixtral-8x7b-32768'),
161 'translation' => array(
'default' =>
'mixtral-8x7b-32768'),
162 'docparsing' => array(
'default' =>
'na'),
163 'adapter_type' =>
'openai'
166 'anthropic' => array(
167 'label' =>
'Anthropic (Claude)',
168 'url' =>
'https://api.anthropic.com/v1/',
169 'setup' =>
'https://console.anthropic.com/',
170 'textgeneration' => array(
'default' =>
'claude-opus-4-6'),
171 'imagegeneration' => array(
'default' =>
'na'),
172 'audiogeneration' => array(
'default' =>
'na'),
173 'videogeneration' => array(
'default' =>
'na'),
174 'transcription' => array(
'default' =>
'na'),
175 'translation' => array(
'default' =>
'na'),
176 'docparsing' => array(
'default' =>
'claude-opus-4-6'),
177 'adapter_type' =>
'anthropic'
180 'label' =>
'Google Gemini',
181 'url' =>
'https://generativelanguage.googleapis.com/v1beta/',
182 'setup' =>
'https://aistudio.google.com/',
183 'textgeneration' => array(
'default' =>
'gemini-3.1-pro-preview'),
184 'imagegeneration' => array(
'default' =>
'nano-banana-pro'),
185 'audiogeneration' => array(
'default' =>
'gemini-2.5-pro-tts'),
186 'videogeneration' => array(
'default' =>
'veo-3.1'),
187 'transcription' => array(
'default' =>
'gemini-3.1-pro-preview'),
188 'translation' => array(
'default' =>
'gemini-3.1-pro-preview'),
189 'docparsing' => array(
'default' =>
'gemini-3.1-pro-preview'),
190 'adapter_type' =>
'google'
215 return [
'success' =>
false,
'message' =>
'API Key is empty'];
219 if (!function_exists(
'getListOfAIServices')) {
220 return [
'success' =>
false,
'message' =>
'Configuration helper function missing.'];
224 $defUrl = $list[$service][
'url'] ??
'';
226 $defaultModel = $list[$service][
'model'] ??
'unknown';
232 $url = rtrim($url,
'/');
235 $headers = [
"Content-Type: application/json"];
243 if ($service ==
'google' || strpos($url,
'googleapis') !==
false) {
244 if (strpos($url,
':generateContent') ===
false) {
245 if (strpos($url,
'models') ===
false) {
246 $url .=
"/models/$model:generateContent";
248 $url .=
"/$model:generateContent";
251 $url .=
"?key=" . $key;
252 $data = [
"contents" => [ [
"parts" => [ [
"text" =>
"Hello"] ] ] ],
"generationConfig" => [
"maxOutputTokens" => 5]];
253 } elseif ($service ==
'anthropic' || strpos($url,
'anthropic') !==
false) {
254 if (strpos($url,
'messages') ===
false) $url .=
'/messages';
255 $headers[] =
"x-api-key: $key";
256 $headers[] =
"anthropic-version: 2023-06-01";
259 "messages" => [[
"role" =>
"user",
"content" =>
"Hello"]],
263 if (strpos($url,
'/chat/completions') ===
false) $url .=
'/chat/completions';
264 $headers[] =
"Authorization: Bearer $key";
268 "messages" => [[
"role" =>
"user",
"content" =>
"Hello"]],
275 curl_setopt($ch, CURLOPT_URL, $url);
276 curl_setopt($ch, CURLOPT_POST,
true);
277 curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
278 curl_setopt($ch, CURLOPT_RETURNTRANSFER,
true);
279 curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
280 curl_setopt($ch, CURLOPT_TIMEOUT, 10);
284 $result = curl_exec($ch);
285 $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
286 $err = curl_error($ch);
290 return [
'success' =>
false,
'message' =>
"Curl Error: $err"];
293 if ($httpCode >= 200 && $httpCode < 300) {
294 return [
'success' =>
true,
'message' =>
"OK (HTTP $httpCode)."];
296 $json = json_decode($result,
true);
298 $msg = $json[
'error'][
'message'] ?? $json[
'message'] ?? substr($result, 0, 150);
299 return [
'success' =>
false,
'message' =>
"HTTP $httpCode. Error: $msg"];
319function ai_log_request(
$db, $user, $query, array $response, $provider,
float $time,
float $confidence, $status, $error =
'', $rawReq =
'', $rawRes =
'')
327 $tool = isset($response[
'tool']) ? (
string) $response[
'tool'] :
'';
330 $rawReq =
dol_substr($rawReq, 0, 60000) .
'... [Truncated]';
333 $rawResStr = (
string) $rawRes;
335 $rawResStr =
dol_substr($rawResStr, 0, 60000) .
'... [Truncated]';
338 $sql =
"INSERT INTO " . MAIN_DB_PREFIX .
"ai_request_log (";
339 $sql .=
"entity, date_request, fk_user, query_text, tool_name, provider, ";
340 $sql .=
"execution_time, confidence, status, error_msg, raw_request_payload, raw_response_payload";
341 $sql .=
") VALUES (";
342 $sql .= ((int)
$conf->entity) .
", ";
344 $sql .= ((int) $user->id) .
", ";
345 $sql .=
"'" .
$db->escape($query) .
"', ";
346 $sql .=
"'" .
$db->escape($tool) .
"', ";
347 $sql .=
"'" .
$db->escape($provider) .
"', ";
348 $sql .= ((float) $time) .
", ";
349 $sql .= ((float) $confidence) .
", ";
350 $sql .=
"'" .
$db->escape($status) .
"', ";
351 $sql .=
"'" .
$db->escape($error) .
"', ";
352 $sql .=
"'" .
$db->escape($rawReq) .
"', ";
353 $sql .=
"'" .
$db->escape($rawResStr) .
"'";
356 $resql =
$db->query($sql);
371 $arrayforaisummarize = array(
373 '50_w' =>
'SummarizeFiftyWords',
374 '100_w' =>
'SummarizeHundredWords',
375 '200_w' =>
'SummarizeTwoHundredWords',
376 '1_p' =>
'SummarizeOneParagraphs',
377 '2_p' =>
'SummarizeTwoParagraphs',
378 '25_pc' =>
'SummarizeTwentyFivePercent',
379 '50_pc' =>
'SummarizeFiftyPercent',
380 '75_pc' =>
'SummarizeSeventyFivePercent'
383 return $arrayforaisummarize;
393 $arrayforaierephrasestyle = array(
394 'spellchecker' =>
'RephraseSpellChecker',
395 'professional' =>
'RephraseStyleProfessional',
396 'humouristic' =>
'RephraseStyleHumouristic',
399 return $arrayforaierephrasestyle;
409 global $langs,
$conf;
411 $langs->load(
"agenda");
417 $head[$h][1] = $langs->trans(
"Settings");
418 $head[$h][2] =
'settings';
421 $head[$h][0] =
dol_buildpath(
"/ai/admin/custom_prompt.php", 1);
422 $head[$h][1] = $langs->trans(
"CustomPrompt");
423 $head[$h][2] =
'custom';
428 $head[$h][1] = $langs->trans(
"Assistant");
429 $head[$h][2] =
'assistant';
435 $head[$h][1] = $langs->trans(
"MCPServer");
436 $head[$h][2] =
'servermcp';
441 $head[$h][0] =
dol_buildpath(
"/ai/admin/configure_tools.php", 1);
442 $head[$h][1] = $langs->trans(
"ToolAccessControl");
443 $head[$h][2] =
'tools';
480 if (empty($serviceKey) || $serviceKey ===
'-1') {
486 return isset($services[$serviceKey][
'label']) ? (
string) $services[$serviceKey][
'label'] : (
string) $serviceKey;
497 global $langs, $user;
508 'ClearChatHistoryTitle',
535 'UnsupportedFileType',
548 'ConnectionBlockedHelp',
553 'BrowserNotSupported',
578 $ai_translations = array();
579 foreach ($keys as $key) {
580 $ai_translations[$key] = $langs->transnoentitiesnoconv($key);
582 $ai_translations[
'DownloadPdf'] = $langs->transnoentitiesnoconv(
"Download").
' PDF';
583 $ai_translations[
'CloudVoiceRequiresSecureContext'] = $langs->trans(
584 "CloudVoiceRequiresSecureContext",
592 if (is_object($user)) {
593 $namesource = $user->firstname ? $user->firstname : ($user->login ? $user->login :
'');
599 'labels' => $ai_translations,
604 'token' => newToken(),
605 'userInitial' => $userinitial,
619 global $langs, $user;
626 $out .=
'<div class="ai-chat-container'.($mode ===
'popover' ?
' ai-in-popover' :
'').
'"';
628 if ($mode ===
'page') {
629 $out .=
' data-ai-autoinit="1"';
634 $out .=
'<div class="chat-header">';
635 if ($mode ===
'popover') {
637 $title =
img_picto(
'',
'fa-robot',
'', 0, 0, 0,
'',
'paddingright').$langs->trans(
"AIAssistant");
638 $title =
'<a href="'.dol_buildpath(
'/ai/assistant/index.php', 1).
'" class="ai-header-link" title="'.
dol_escape_htmltag($langs->trans(
"AIOpenFullPage")).
'">'.$title.
'</a>';
639 $out .=
'<h2>'.$title.
'</h2>';
642 $out .=
'<div class="chat-header-id">';
643 $out .=
'<span class="chat-header-avatar">'.img_picto(
'',
'fa-robot').
'</span>';
644 $out .=
'<span class="chat-header-text">';
645 $out .=
'<span class="chat-header-title">'.$langs->trans(
"AIAssistant").
'</span>';
647 if ($aiprovider !==
'') {
648 $out .=
'<span class="chat-header-status" title="'.dol_escape_htmltag($langs->trans(
"AIProviderInUse")).
'">'.
dol_escape_htmltag($aiprovider).
'</span>';
653 $out .=
'<div class="header-controls">';
655 $out .=
'<select id="engine-select" class="engine-select">';
656 $out .=
'<option value="text">'.$langs->transnoentitiesnoconv(
"OptionTextOnly").
'</option>';
657 $out .=
'<option value="cloud">'.$langs->transnoentitiesnoconv(
"OptionCloudFast").
'</option>';
658 $out .=
'<option value="whisper">'.$langs->transnoentitiesnoconv(
"OptionWhisperLocal").
'</option>';
659 $out .=
'<option value="local_docs">'.$langs->transnoentitiesnoconv(
"OptionLocalParsing").
'</option>';
660 $out .=
'<option value="cloud_docs">'.$langs->transnoentitiesnoconv(
"OptionCloudParsing").
'</option>';
663 $out .=
'<button type="button" id="clear-btn" class="icon-btn" title="'.dol_escape_htmltag($langs->trans(
"ClearChatHistoryTitle")).
'">';
664 $out .=
img_picto(
'',
'fa-trash').
' <span class="ai-btn-label">'.$langs->trans(
"Clear").
'</span>';
666 if ($mode ===
'popover') {
668 $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>';
669 $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>';
675 $out .=
'<div id="chat-history" class="chat-history">';
676 if ($mode ===
'popover') {
678 $out .=
'<div class="msg system">'.$langs->trans(
"AIWelcomeMessage").
'</div>';
683 $welcomename = $user->firstname ? $user->firstname : (is_object($user) ? $user->login :
'');
685 array(
'icon' =>
'fa-file-invoice-dollar',
'key' =>
'Invoices'),
686 array(
'icon' =>
'fa-chart-line',
'key' =>
'Revenue'),
687 array(
'icon' =>
'fa-coins',
'key' =>
'Finance'),
688 array(
'icon' =>
'fa-warehouse',
'key' =>
'Inventory'),
690 $out .=
'<div class="chat-welcome">';
691 $out .=
'<div class="chat-welcome-avatar">'.img_picto(
'',
'fa-robot').
'</div>';
692 $out .=
'<h2 class="chat-welcome-title">'.dol_escape_htmltag($langs->trans(
"AIGreeting", $welcomename)).
'</h2>';
693 $out .=
'<p class="chat-welcome-subtitle">'.dol_escape_htmltag($langs->trans(
"AIGreetingSubtitle")).
'</p>';
694 $out .=
'<div class="chat-welcome-actions">';
695 foreach ($quickcards as $card) {
696 $out .=
'<button type="button" class="ai-quick-card" data-prompt="'.dol_escape_htmltag($langs->transnoentitiesnoconv(
"AIQuick".$card[
'key'].
"Prompt")).
'">';
697 $out .=
'<span class="ai-quick-icon">'.img_picto(
'', $card[
'icon']).
'</span>';
698 $out .=
'<span class="ai-quick-text">';
699 $out .=
'<span class="ai-quick-title">'.dol_escape_htmltag($langs->trans(
"AIQuick".$card[
'key'].
"Title")).
'</span>';
700 $out .=
'<span class="ai-quick-desc">'.dol_escape_htmltag($langs->trans(
"AIQuick".$card[
'key'].
"Desc")).
'</span>';
711 $out .=
'<div class="chat-controls">';
712 $out .=
'<div class="chat-input-pill">';
714 $out .=
'<div id="upload-wrapper" class="upload-wrapper hidden">';
715 $out .=
'<input type="file" id="file-upload" accept=".pdf,.txt,.xml,.png,.jpg,.jpeg,.doc,.docx,.xls,.xlsx,.odt,.ods" style="display: none;">';
716 $out .=
'<button type="button" id="upload-btn" class="round-btn" title="'.dol_escape_htmltag($langs->transnoentitiesnoconv(
"AttachFile")).
'">'.
img_picto(
'',
'fa-paperclip').
'</button>';
719 $out .=
'<div id="mic-wrapper" class="mic-wrapper hidden">';
720 $out .=
'<button type="button" id="mic-btn" class="round-btn mic-btn" title="'.dol_escape_htmltag($langs->trans(
"ToggleMicrophone")).
'">'.
img_picto(
'',
'fa-microphone').
'</button>';
723 $out .=
'<textarea id="user-input" class="ia-input" rows="1" placeholder="'.dol_escape_htmltag($langs->trans(
"TypeYourQuestion")).
'" autocomplete="off" spellcheck="false"></textarea>';
725 $out .=
'<button type="button" id="send-btn" class="chat-send-btn" title="'.dol_escape_htmltag($langs->trans(
"SendPrompt")).
'">'.
img_picto(
'',
'fa-paper-plane').
'</button>';
729 $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.
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_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
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.
dol_print_error($db=null, $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
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.
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
buildzip.php