add history to shop search
This commit is contained in:
@@ -72,12 +72,69 @@ final class ContextService
|
||||
return '';
|
||||
}
|
||||
|
||||
$maxLines = $full ? ContextServiceConfig::MAX_FULL_LINES : ContextServiceConfig::MAX_VISIBLE_REGULAR_LINES;
|
||||
$maxLines = $full
|
||||
? ContextServiceConfig::MAX_FULL_LINES
|
||||
: ContextServiceConfig::MAX_VISIBLE_REGULAR_LINES;
|
||||
|
||||
$selected = array_slice($lines, -$maxLines);
|
||||
|
||||
return implode("\n", $selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns as much recent history as possible within a character budget.
|
||||
*
|
||||
* Strategy:
|
||||
* - Preserve complete conversation turns whenever possible
|
||||
* - Prioritize the newest turns
|
||||
* - Only truncate when even the newest single turn is larger than the budget
|
||||
*
|
||||
* A turn starts with "Question: " and includes the corresponding assistant answer.
|
||||
*/
|
||||
public function buildUserContextWithinBudget(string $userId, int $maxChars): string
|
||||
{
|
||||
if ($maxChars <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$history = $this->readHistoryFile($userId);
|
||||
if ($history === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$turns = $this->splitHistoryIntoTurns($history);
|
||||
if ($turns === []) {
|
||||
return $this->truncateTurnToBudget($history, $maxChars);
|
||||
}
|
||||
|
||||
$selected = [];
|
||||
$currentLength = 0;
|
||||
|
||||
for ($i = count($turns) - 1; $i >= 0; $i--) {
|
||||
$turn = $turns[$i];
|
||||
$turnLength = mb_strlen($turn);
|
||||
$separatorLength = $selected === [] ? 0 : 2; // "\n\n"
|
||||
|
||||
if (($currentLength + $separatorLength + $turnLength) <= $maxChars) {
|
||||
array_unshift($selected, $turn);
|
||||
$currentLength += $separatorLength + $turnLength;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If nothing fits yet, keep at least the newest turn in truncated form.
|
||||
if ($selected === []) {
|
||||
$truncatedTurn = $this->truncateTurnToBudget($turn, $maxChars);
|
||||
if ($truncatedTurn !== '') {
|
||||
$selected[] = $truncatedTurn;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return implode("\n\n", $selected);
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a completed interaction to the user's history.
|
||||
*
|
||||
@@ -105,6 +162,82 @@ final class ContextService
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the raw history file contents for a user.
|
||||
*/
|
||||
private function readHistoryFile(string $userId): string
|
||||
{
|
||||
$path = $this->getHistoryPath($userId);
|
||||
|
||||
if (!is_file($path)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$content = file_get_contents($path);
|
||||
|
||||
if ($content === false) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return trim($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Splits append-only history into complete turns.
|
||||
*
|
||||
* Each turn starts with "Question: ".
|
||||
*/
|
||||
private function splitHistoryIntoTurns(string $history): array
|
||||
{
|
||||
$history = trim($history);
|
||||
if ($history === '') {
|
||||
return [];
|
||||
}
|
||||
|
||||
$parts = preg_split('/(?=^Question:\s)/m', $history);
|
||||
if ($parts === false) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$turns = [];
|
||||
|
||||
foreach ($parts as $part) {
|
||||
$part = trim($part);
|
||||
|
||||
if ($part === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$turns[] = $part;
|
||||
}
|
||||
|
||||
return $turns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Truncates a single turn to fit into the available budget.
|
||||
*
|
||||
* The start of the turn is preserved so the "Question: ..." marker remains intact.
|
||||
*/
|
||||
private function truncateTurnToBudget(string $turn, int $maxChars): string
|
||||
{
|
||||
$turn = trim($turn);
|
||||
|
||||
if ($turn === '' || $maxChars <= 0) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (mb_strlen($turn) <= $maxChars) {
|
||||
return $turn;
|
||||
}
|
||||
|
||||
if ($maxChars <= 3) {
|
||||
return mb_substr($turn, 0, $maxChars);
|
||||
}
|
||||
|
||||
return rtrim(mb_substr($turn, 0, $maxChars - 3)) . '...';
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the absolute history file path for a user.
|
||||
*/
|
||||
@@ -114,4 +247,4 @@ final class ContextService
|
||||
|
||||
return $this->historyDir . '/' . $safeUserId . '.txt';
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user