This commit is contained in:
Frederico @ VilaRosa02 2025-09-09 10:06:07 +00:00
commit 2e01e34278
5 changed files with 237 additions and 0 deletions

77
LlamaCli.func.php Normal file
View File

@ -0,0 +1,77 @@
<?php
require_once __DIR__."/lib/index.php";
function LlamaCli(string $prompt, string $system = "You are a helpful assistant", array $options = []) {
// 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;
// 1. Parse the prompt and resolve actions "@"
$prompt = ResolveActions($prompt);
// $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 -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);
//
$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, array $options = []) { $options["parseCodeInOutput"] = false; return LlamaCli($prompt, $system,$options); }

View File

@ -0,0 +1,33 @@
<?php
function ExtractCodeSections(string $raw_output) {
$output = [];
$currentBlock = "";
$currentBlockLang = "";
foreach(explode("\n",$raw_output) as $line) {
if (substr($line,0,3) == "```") {
if (empty($currentBlockLang)) {
if (!empty($currentBlock)) {$output[] = trim($currentBlock); $currentBlock = "";}
$currentBlockLang = str_replace("```","",$line) ?? "code";
continue;
} else {
if (isset($output[$currentBlockLang]) && is_string($output[$currentBlockLang])) $output[$currentBlockLang] = [$output[$currentBlockLang]];
if (isset($output[$currentBlockLang]) && is_array($output[$currentBlockLang]))
$output[$currentBlockLang][] = trim($currentBlock);
else
$output[$currentBlockLang] = trim($currentBlock);
$currentBlock = "";
$currentBlockLang = "";
continue;
}
}
$currentBlock .= $line."\n";
}
$output[] = trim($currentBlock);
return $output;
}

View File

@ -0,0 +1,47 @@
<?php
function ResolveActions(string $text) {
if (preg_match("/@rss_reader ([\w:\/\.]+)/",$text,$matches)) {
$url = $matches[1];
// Initialize cURL
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $url,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_USERAGENT => "PHP cURL RSS Reader"
]);
$response = curl_exec($ch);
if (curl_errno($ch)) die("cURL error: " . curl_error($ch));
curl_close($ch);
// Parse as XML
$xml = @simplexml_load_string($response);
if (!$xml) die("Failed to parse XML.");
// Find first <title>
$firstTitle = '';
if (isset($xml->channel->item[0]->title)) {
// RSS 2.0 style
$firstTitle = (string)$xml->channel->item[0]->title;
} elseif (isset($xml->entry[0]->title)) {
// Atom style
$firstTitle = (string)$xml->entry[0]->title;
} elseif (isset($xml->title)) {
// fallback
$firstTitle = (string)$xml->title;
}
$text = str_replace($matches[0],$firstTitle,$text);
}
return $text;
}

6
lib/index.php Normal file
View File

@ -0,0 +1,6 @@
<?php
foreach(scandir(__DIR__) as $filename) {
if ($filename == "." || $filename == "..") continue;
if (substr($filename, -13) == ".function.php") include __DIR__."/$filename";
}

74
test.php Normal file
View File

@ -0,0 +1,74 @@
<?php require_once __DIR__."/LlamaCli.func.php";
// TEST 01: Simple query.
// $out = LlamaCli("What is the capital of France?"); print_r($out);
// TEST 02: Simple query with previous background conversation
// $out = LlamaCli("Portugal?","",["previousConversation"=>[["role"=>"user","content"=>"What is the capital of France?"],["role"=>"assistant","content"=>"Paris."]]]); print_r($out);
// TEST 03: Simple query with SYSTEM PRIMING message
//$summary = LlamaCli(file_get_contents("test_input_data.3.txt"),"You are an executive assistant that will summarize english text in 1 paragraph");
//$title = LlamaCli($summary[0],"You are an talented journalist that will produce a provocative headline title based on a summary of a text");
// TEST 04: RECURSIVE QUERY, to produce long-content from short-one. LONG-WRITING. ( GOAL: Learning from model deep knowledge )
// // -------- BOOK EXAMPLE ---------
//
// // 0. CATEGORY
// $category = "learning finnish";
// $expert = "teacher";
// $total_no_of_chapters = 3;
//
//
// // 1. TITLE
// $book_title = LlamaCli_raw("Write me a title for my new book about $category. Output title only, no options, no chat.","You are an expert $expert.");
//
//
// // 2. CHAPTER TITLES
// $sys_msg = "You are an expert $expert writing a book with the title $book_title with $total_no_of_chapters chapters";
// $chapters = []; $conv_hist = [];
//
// $msg = "Write me the title of my first chapter. Output title only, no options, no chat.";
// $conv_hist[] = ["role"=>"user","content"=>$msg];
// $conv_hist[] = ["role"=>"assistant","content"=>($chapters[] = LlamaCli_raw($msg,$sys_msg,["debug_level"=>0]))];
//
// for($no=1; $no < $total_no_of_chapters; $no++) {
// $msg = "Write me the title of chapter number $no.";
// $conv_hist[] = ["role"=>"user","content"=>$msg];
// $conv_hist[] = ["role"=>"assistant","content"=>($chapters[] = LlamaCli_raw($msg,$sys_msg,["previousConversation"=>$conv_hist, "debug_level"=>0]))];
//
// }
//
// // 3. CHAPTER CONTENTS
// $content = [];
// foreach($chapters as $chapter_title)
// $content[$chapter_title] = LlamaCli_raw(
// "Write 2 paragraphs for a chapter titled $chapter_title in a book called $book_title. Output content only, no chat.",
// "You are an expert $expert."
// );
//
// print_r([$book_title, $content]);
// TEST 05: CHAINED QUERY, to parse long-content and produce short one. SUMMARIZATION. ( GOAL: )
// $summaries = [];
// $content = file_get_contents("test_input_data.2.txt");
// $chunks = array_chunk(explode("\n",$content),80);
//
// foreach($chunks as $chunk) {
// $summaries[] = LlamaCli_raw(implode("\n",$chunk),"You are a legal executive assistant that will summarize a conversation in english between ex-husband and wife in 1 paragraph");
// }
// print_r($summaries);
// TEST 06: Resolve ACTIONS
echo LlamaCli_raw("translate this title to portuguese and finnish: @rss_reader https://feeds.bbci.co.uk/news/rss.xml cde def","");