2
0
forked from Wavyzz/dolibarr

Enhance AI features

This commit is contained in:
ldestailleur
2025-04-08 11:42:46 +02:00
parent 9f7f1dbeff
commit 1bb7edea8b
6 changed files with 79 additions and 39 deletions

View File

@@ -81,8 +81,16 @@ $aiservice = getDolGlobalString('AI_API_SERVICE', 'chatgpt');
// Setup conf for AI model
$formSetup->formHiddenInputs['action'] = "updatefeaturemodel";
foreach ($arrayofaifeatures as $key => $val) {
$newkey = $key;
if (preg_match('/^text/', $key)) {
$newkey = 'textgeneration';
}
$item = $formSetup->newItem('AI_API_'.strtoupper($aiservice).'_MODEL_'.$val["function"]); // Name of constant must end with _KEY so it is encrypted when saved into database.
$item->nameText = $langs->trans("AI_API_MODEL_".$val["function"]);
if ($arrayofai[$aiservice][$newkey] != 'na') {
$item->nameText = $langs->trans("AI_API_MODEL_".$val["function"]).' <span class="opacitymedium">('.$langs->trans("Default").' = '.$arrayofai[$aiservice][$newkey].')</span>';
} else {
$item->nameText = $langs->trans("AI_API_MODEL_".$val["function"]).' <span class="opacitymedium">('.$langs->trans("None").')</span>';
}
$item->cssClass = 'minwidth500 input';
}
@@ -218,10 +226,15 @@ print load_fiche_titre($langs->trans($title), $linkback, 'title_setup');
$head = aiAdminPrepareHead();
print dol_get_fiche_head($head, 'custom', $langs->trans($title), -1, "ai");
//$newbutton = '<a href="'.$_SERVER["PHP_SELF"].'?action=create">'.$langs->trans("New").'</a>';
$newbutton = '';
$newcardbutton = dolGetButtonTitle($langs->trans('NewCustomPrompt'), '', 'fa fa-plus-circle', $_SERVER["PHP_SELF"].'?action=create', '', 1);
/*
$newbutton = '<a href="'.$_SERVER["PHP_SELF"].'?action=create" title="'.$langs->trans("NewCustomPrompt").'">';
$newbutton .= img_picto('', 'add');
$newbutton .= '</a>';
*/
print load_fiche_titre($langs->trans("AIPromptForFeatures", $arrayofai[$aiservice]['label']), $newcardbutton, '');
print load_fiche_titre($langs->trans("AIPromptForFeatures"), $newbutton, '');
if ($action == 'deleteproperty') {
$formconfirm = $form->formconfirm(
@@ -236,7 +249,8 @@ if ($action == 'deleteproperty') {
print $formconfirm;
}
if ($action == 'edit' || $action == 'deleteproperty') {
if ($action == 'create') {
$out .= '<div class="addcustomprompt hidden">';
$out = '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
$out .= '<input type="hidden" name="token" value="'.newToken().'">';
$out .= '<input type="hidden" name="action" value="update">';
@@ -245,7 +259,7 @@ if ($action == 'edit' || $action == 'deleteproperty') {
$out .= '<table class="noborder centpercent">';
$out .= '<thead>';
$out .= '<tr class="liste_titre">';
$out .= '<td>'.$langs->trans('Add').'</td>';
$out .= '<td>'.$langs->trans('NewCustomPrompt').'</td>';
$out .= '<td></td>';
$out .= '</tr>';
$out .= '</thead>';
@@ -320,6 +334,7 @@ if ($action == 'edit' || $action == 'deleteproperty') {
$out .= '</form>';
$out .= '<br><br><br>';
$out .= '</div>';
print $out;
}
@@ -382,13 +397,14 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') {
$out .= '<input type="submit" class="button small submitBtn reposition" name="modify" data-index="'.$key.'" value="'.dol_escape_htmltag($langs->trans("Save")).'"/>';
$out .= ' &nbsp; ';
$out .= '<br><br>';
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formmail.class.php';
$showlinktoai = $key; // 'textgeneration', 'imagegeneration', ...
$showlinktoailabel = $langs->trans("ToTest");
$formmail = new FormMail($db);
$htmlname = $key;
$out .= '<br><br>';
$onlyenhancements = $key;
// Fill $out
include DOL_DOCUMENT_ROOT.'/core/tpl/formlayoutai.tpl.php';
@@ -412,7 +428,7 @@ if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') {
if ($action == 'edit' || $action == 'create' || $action == 'deleteproperty') {
print load_fiche_titre($langs->trans("AIModelForFeature", $arrayofai[$aiservice]['label']), $newbutton, '');
print load_fiche_titre($langs->trans("AIModelForFeature", $arrayofai[$aiservice]['label']), '', '');
print $formSetup->generateOutput(true);
}

View File

@@ -153,6 +153,10 @@ class Ai
$postPrompt = $configurations[$function]['postPrompt'];
}
}
if (empty($prePrompt) && $function == 'texttranslation') {
$prePrompt = 'You are a translator, give only the translation with no comment and explanation';
}
$fullInstructions = $instructions.($postPrompt ? (preg_match('/[\.\!\?]$/', $instructions) ? '' : '.').' '.$postPrompt : '');
// Set payload string

View File

@@ -66,6 +66,7 @@ function getListOfAIServices()
'textgeneration' => 'gpt-3.5-turbo', // a lot of text transformation like: 'textgenerationemail', 'textgenerationwebpage', 'textgeneration', 'texttranslation', 'textsummarize'
'imagegeneration' => 'dall-e-3',
'audiogeneration' => 'tts-1',
'videogeneration' => 'na',
'transcription' => 'whisper-1', // audio to text
'translation' => 'whisper-1', // audio to text into another language
),
@@ -73,10 +74,11 @@ function getListOfAIServices()
'label' => 'Groq',
'url' => 'https://api.groq.com/openai/',
'textgeneration' => 'mixtral-8x7b-32768', // 'llama3-8b-8192', 'gemma-7b-it'
'imagegeneration' => 'mixtral-8x7b-32768',
'audiogeneration' => 'mixtral-8x7b-32768',
'transcription' => 'mixtral-8x7b-32768',
'translation' => 'mixtral-8x7b-32768',
'imagegeneration' => 'na',
'audiogeneration' => 'na',
'videogeneration' => 'na',
'transcription' => 'na',
'translation' => 'na',
),
'mistral' => array(
'label' => 'Mistral',
@@ -84,6 +86,7 @@ function getListOfAIServices()
'textgeneration' => 'open-mistral-7b',
'imagegeneration' => 'na',
'audiogeneration' => 'na',
'videogeneration' => 'na',
'transcription' => 'na',
'translation' => 'na',
),
@@ -93,6 +96,7 @@ function getListOfAIServices()
'textgeneration' => 'tinyllama-1.1b',
'imagegeneration' => 'mixtral-8x7b-32768',
'audiogeneration' => 'mixtral-8x7b-32768',
'videogeneration' => 'na',
'transcription' => 'mixtral-8x7b-32768',
'translation' => 'mixtral-8x7b-32768',
)

View File

@@ -93,12 +93,13 @@ class FormAI extends Form
/**
* Return Html code for AI instructions of message and autofill result
*
* @param string $function Function ('textgenerationmail', 'textgenerationwebpage', ...)
* @param string $format Format for output ('', 'html', ...)
* @param string $htmlContent HTML name of WYSIWYG field
* @return string HTML code to ask AI instructions and autofill result
* @param string $function Function ('textgenerationemail', 'textgenerationwebpage', ...)
* @param string $format Format for output ('', 'html', ...)
* @param string $htmlContent HTML name of WYSIWYG field
* @param string $onlyenhancements Show only this enhancement features (show all if '')
* @return string HTML code to ask AI instructions and autofill result
*/
public function getSectionForAIEnhancement($function = 'textgeneration', $format = '', $htmlContent = 'message')
public function getSectionForAIEnhancement($function = 'textgeneration', $format = '', $htmlContent = 'message', $onlyenhancements = '')
{
global $langs, $form;
require_once DOL_DOCUMENT_ROOT."/ai/lib/ai.lib.php";
@@ -115,26 +116,34 @@ class FormAI extends Form
$htmlContent = preg_replace('/[^a-z0-9_]/', '', $htmlContent);
$out = '<!-- getSectionForAIEnhancement -->';
$out .= '<div id="ai_dropdown'.$htmlContent.'" class="dropdown-menu ai_dropdown ai_dropdown'.$htmlContent.' paddingtop paddingbottom">';
$out .= '<div id="ai_textgeneration'.$htmlContent.'" class="ai_textgeneration'.$htmlContent.' paddingtop paddingbottom ai_feature">';
//$out .= '<span>'.$langs->trans("FillMessageWithAIContent").'</span>';
$out .= '<textarea class="centpercent textarea-ai_feature" data-functionai="textgeneration" id="ai_instructions'.$htmlContent.'" name="instruction" placeholder="'.$langs->trans("EnterYourAIPromptHere").'..." /></textarea>';
$out .= '<input id="generate_button'.$htmlContent.'" type="button" class="button smallpaddingimp" disabled data-functionai="textgeneration" value="'.$langs->trans('Generate').'"/>';
$out .= '</div>';
$out .= '<br>';
$out = '';
if (empty($onlyenhancements) || in_array($onlyenhancements, array('textgenerationemail', 'textgenerationwebpage'))) {
$out .= '<div id="ai_textgeneration'.$htmlContent.'" class="ai_textgeneration'.$htmlContent.' paddingtop paddingbottom ai_feature">';
//$out .= '<span>'.$langs->trans("FillMessageWithAIContent").'</span>';
$out .= '<textarea class="centpercent textarea-ai_feature" data-functionai="textgeneration" id="ai_instructions'.$htmlContent.'" name="instruction" placeholder="'.$langs->trans("EnterYourAIPromptHere").'..." /></textarea>';
$out .= '<input id="generate_button'.$htmlContent.'" type="button" class="button smallpaddingimp" disabled data-functionai="textgeneration" value="'.$langs->trans('Generate').'"/>';
$out .= '</div>';
}
$out .= '<div id="ai_translation'.$htmlContent.'" class="ai_translation'.$htmlContent.' paddingtop paddingbottom ai_feature">';
$out .= img_picto('', 'language', 'class="pictofixedwidth paddingrightonly"');
$out .= $formadmin->select_language("", "ai_translation".$htmlContent."_select", 0, array(), $langs->trans("TranslateByAI").'...', 0, 0, 'minwidth250 ai_translation'.$htmlContent.'_select');
$out .= '</div>';
$out .= '<br>';
if (empty($onlyenhancements) || in_array($onlyenhancements, array('texttranslation'))) {
$out .= ($out ? '<br>' : '');
$out .= '<div id="ai_translation'.$htmlContent.'" class="ai_translation'.$htmlContent.' paddingtop paddingbottom ai_feature">';
$out .= img_picto('', 'language', 'class="pictofixedwidth paddingrightonly"');
$out .= $formadmin->select_language("", "ai_translation".$htmlContent."_select", 0, array(), $langs->trans("TranslateByAI").'...', 0, 0, 'minwidth250 ai_translation'.$htmlContent.'_select');
$out .= '</div>';
}
$summarizearray = getListForAISummarize();
$out .= '<div id="ai_summarize'.$htmlContent.'" class="ai_summarize'.$htmlContent.' paddingtop paddingbottom ai_feature">';
$out .= img_picto('', 'edit', 'class="pictofixedwidth paddingrightonly"');
$out .= $form->selectarray("ai_summarize".$htmlContent."_select", $summarizearray, 0, $langs->trans("SummarizeByAI").'...', 0, 0, 'minwidth250 ai_summarize'.$htmlContent.'_select', 1);
$out .= '</div>';
if (empty($onlyenhancements) || in_array($onlyenhancements, array('textsummarize'))) {
$summarizearray = getListForAISummarize();
$out .= ($out ? '<br>' : '');
$out .= '<div id="ai_summarize'.$htmlContent.'" class="ai_summarize'.$htmlContent.' paddingtop paddingbottom ai_feature">';
$out .= img_picto('', 'edit', 'class="pictofixedwidth paddingrightonly"');
$out .= $form->selectarray("ai_summarize".$htmlContent."_select", $summarizearray, 0, $langs->trans("SummarizeByAI").'...', 0, 0, 'minwidth250 ai_summarize'.$htmlContent.'_select', 1);
$out .= '</div>';
}
$out = '<!-- getSectionForAIEnhancement -->'.$out;
$out = '<div id="ai_dropdown'.$htmlContent.'" class="dropdown-menu ai_dropdown ai_dropdown'.$htmlContent.' paddingtop paddingbottom">'.$out;
$out .= '<div id="ai_status_message'.$htmlContent.'" class="fieldrequired hideobject marginrightonly margintoponly">';
$out .= $messageaiwait;

View File

@@ -117,6 +117,7 @@ if ($showlinktoai) {
</script>
';
}
if ($showlinktolayout) {
if (!empty($formwebsite) && is_object($formwebsite)) {
$out .= $formwebsite->getContentPageTemplate($htmlname);
@@ -126,13 +127,18 @@ if ($showlinktolayout) {
} else {
$out .= '<!-- No link to the layout feature, $formmail->withlayout must be set to a string use case, module WYSIWYG must be enabled and MAIN_EMAIL_USE_LAYOUT must be set -->';
}
if ($showlinktoai) {
if (empty($formai) || $formai instanceof FormAI) {
include_once DOL_DOCUMENT_ROOT.'/core/class/html.formai.class.php';
$formai = new FormAI($db);
}
$out .= $formai->getAjaxAICallFunction();
$out .= $formai->getSectionForAIEnhancement($showlinktoai, $formmail->withaiprompt, $htmlname);
if (empty($onlyenhancements)) {
$onlyenhancements = '';
}
$out .= $formai->getSectionForAIEnhancement($showlinktoai, $formmail->withaiprompt, $htmlname, $onlyenhancements);
} else {
$out .= '<!-- No link to the AI feature, $formmail->withaiprompt must be set to the ai feature and module ai must be enabled -->';
}

View File

@@ -2546,7 +2546,9 @@ TextTranslation=Text translation
ImageGeneration=Image generation
VideoGeneration=Video generation
AudioGeneration=Audio generation
AIPromptForFeatures=AI custom prompts or models for features
AIPromptForFeatures=AI custom prompts for features (AI service %s)
AIModelForFeature=AI model for features (AI service %s)
NewCustomPrompt=New custom prompt
AudioTranscription=Audio transcription
AudioTranslation=Audio translation
EnterAnIP=Enter an IP address
@@ -2643,7 +2645,6 @@ PDF_XXX_SHOW_PRICE_INCL_TAX=Show column Price including tax
AvailableWithSomePDFTemplatesOnly=Feature not supported on old PDF templates
SelectAService=Select the kind of service to use
SelectFeatureToTest=Select the feature to test
AIModelForFeature=AI model for features (AI service %s)
communityRepo=Community repository
online=Online
NotConnected=Not connected