php-llm-agent/LlamaCli.func.php
2025-09-18 15:42:38 +00:00

102 lines
3.7 KiB
PHP

<?php
require_once __DIR__."/lib/index.php";
$debug_level = 0;
function LlamaCli(string|array $prompt, string $system = "You are a helpful assistant", array $options = []) {
//
// ---- 0. OPTIONS (Default and provided) -----
//
global $debug_level;
// Get the options passed
extract($options);
// Set defaults for what was not explicitly specified
$llamacpp_bin = $llamacpp_bin ?? "/home/frederico/llama.cpp/build/bin/llama-cli";
$llamacpp_model_path = $llamacpp_model_path ?? "/home/frederico/llama.cpp/models";
$llamacpp_model = $llamacpp_model ?? "Meta-Llama-3.1-8B-Instruct-Q4_K_M.gguf";
$parseCodeInOutput = $parseCodeInOutput ?? true;
$previousConversation = $previousConversation ?? []; // expects: [["role"=>"assistant","content"=>"How can I help you?"],["role"=>"user","content"=>"Tell me the capital of France"]]
$debug_level = $debug_level ?? 0;
$context_size = $context_size ?? 4096;
//
// ---- 1. INPUT TO LLM (DSL: adjustments needed) -----
//
// 1.1 Parse the prompt and resolve actions "@"
//if (is_array($prompt)) foreach($prompt as $i => $chunk) $prompt[$i] = ExpandFetcherCommands($chunk);
//else
$prompt = ExpandFetcherCommands($prompt);
// 1.2 Parse expanders / compressors
while(ParseExpandersIteratorsCompressors($prompt, "input",$options)) { }
if (is_array($prompt)) die("ERROR: at LLM stage, prompt is an array. Use '>(json|new-line)' compressor.");
// $llm_stdin = $prompt;
// Llama chat template
$llm_stdin = "<|start_header_id|>system<|end_header_id|>$system<|eot_id|>";
foreach($previousConversation as $message)
$llm_stdin .= "<|start_header_id|>{$message["role"]}<|end_header_id|>{$message["content"]}<|eot_id|>";
$llm_stdin .= "<|start_header_id|>user<|end_header_id|>$prompt<|eot_id|>";
$llm_stdin .= "<|start_header_id|>assistant<|end_header_id|>";
// Create a unique temporary file for STDIN, input data
$input_file_name = tempnam(sys_get_temp_dir(), 'tmp_');
if ($debug_level >= 4) file_put_contents("php://stderr","input_file_name $input_file_name content: $llm_stdin\n");
file_put_contents($input_file_name, $llm_stdin);
// Create a unique temporary file for STDERR, debug data
$debug_file_name = tempnam(sys_get_temp_dir(), 'tmp_');
if ($debug_file_name === false) die("Could not create temporary file\n");
$command = "$llamacpp_bin \
-m $llamacpp_model_path/$llamacpp_model \
-f $input_file_name \
-c $context_size \
-no-cnv \
--simple-io \
2> $debug_file_name ";
if ($debug_level >= 3) file_put_contents("php://stderr","Attempting command: $command\n");
$output = shell_exec($command);
// Save the DEBUG data from the LLM
$debug_data = file_get_contents($debug_file_name);
if ($debug_level >= 5) file_put_contents("php://stderr","debug_file_name $debug_file_name content: $debug_data\n");
// Clean TEMP files
if (file_exists($debug_file_name)) unlink($debug_file_name);
if (file_exists($input_file_name)) unlink($input_file_name);
//
// 5. Erase the input from the output
//
// 5.1 Llama specific model. produces in this format:
$output = str_replace("system$system", "", $output);
$output = str_replace("user$prompt"."assistant", "", $output);
foreach($previousConversation as $message)
$output = str_replace($message["role"].$message["content"],"",$output);
$output = str_replace("[end of text]", "", $output);
// 5.2 Generic input
//$output = str_replace($llm_stdin, "", $output);
// 5.3 Sanitize output
$output = trim($output);
if ($parseCodeInOutput)
$output = ExtractCodeSections($output);
return $output;
}
function LlamaCli_raw(string $prompt, string $system = "You are a helpful assistant", array $options = []) { $options["parseCodeInOutput"] = false; return LlamaCli($prompt, $system,$options); }