1. Go to this page and download the library: Download boehmmatthias/smartsearch library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
boehmmatthias / smartsearch example snippets
use BoehmMatthias\SmartSearch\Service\VectorService;
class MyEventListener
{
public function __construct(
private readonly VectorService $vectorService,
) {}
public function afterSave(MyRecord $record): void
{
$this->vectorService->embedAndStore(
collection: 'my-extension-articles',
identifier: $record->getUid(),
text: $record->getTitle() . "\n\n" . strip_tags($record->getBodyText()),
);
}
}
$hits = $this->vectorService->findSimilar(
collection: 'my-extension-articles',
query: 'how do I configure caching?',
topK: 5,
);
// Returns: [['identifier' => '42', 'score' => 0.87], ['identifier' => '7', 'score' => 0.74], ...]
// Sorted by cosine similarity descending. 'identifier' is always a string.
foreach ($hits as $hit) {
$record = $this->recordRepository->findByUid((int)$hit['identifier']);
// filter by threshold if needed: if ($hit['score'] < 0.30) continue;
}
use BoehmMatthias\SmartSearch\Service\GenerationService;
use BoehmMatthias\SmartSearch\Service\VectorService;
use BoehmMatthias\SmartSearch\Configuration\SmartSearchConfiguration;
class SearchController
{
public function __construct(
private readonly VectorService $vectorService,
private readonly GenerationService $generationService,
private readonly SmartSearchConfiguration $configuration,
) {}
public function answerAction(string $question): string
{
// 1. Find the most relevant documents
$hits = $this->vectorService->findSimilar(
collection: 'my-extension-articles',
query: $question,
topK: $this->configuration->getRagTopK(),
);
// 2. Filter by semantic threshold
$threshold = $this->configuration->getSemanticThreshold();
$hits = array_filter($hits, fn($h) => $h['score'] >= $threshold);
if (empty($hits)) {
return 'No relevant documents found.';
}
// 3. Build context blocks — one string per source document
$maxChars = $this->configuration->getDocumentContextLength();
$contextBlocks = [];
foreach ($hits as $hit) {
$record = $this->recordRepository->findByUid((int)$hit['identifier']);
$excerpt = mb_substr(strip_tags($record->getBodyText()), 0, $maxChars);
$contextBlocks[] = sprintf('[%d] %s\n%s', $record->getUid(), $record->getTitle(), $excerpt);
}
// 4. Generate a grounded answer
return $this->generationService->generate(
query: $question,
contextBlocks: $contextBlocks,
);
// The system prompt instructs the model to answer only from the provided
// documents and to cite sources by their identifier (e.g. [42]).
}
}
use BoehmMatthias\SmartSearch\Repository\VectorRepository;
// Remove a single entry
$this->vectorRepository->deleteByIdentifier('my-extension-articles', (string)$uid);
// Remove all entries in a collection (e.g. before a full reindex)
$this->vectorRepository->deleteByCollection('my-extension-articles');
use BoehmMatthias\SmartSearch\Service\ModelAvailabilityService;
if ($this->modelAvailabilityService->isEmbeddingServerAvailable()) {
// offer semantic search
}
if ($this->modelAvailabilityService->isGenerationServerAvailable()) {
// offer RAG answers
}
namespace MyVendor\MyExtension\Embedding;
use BoehmMatthias\SmartSearch\Embedding\EmbeddingClientInterface;
final class OpenAiEmbeddingClient implements EmbeddingClientInterface
{
public function __construct(
private readonly string $apiKey,
private readonly string $model = 'text-embedding-3-small',
) {}
/** @return float[] */
public function embed(string $text): array
{
// Call the OpenAI embeddings API and return the float array.
// ...
}
}
$vectorRepository->deleteByCollection('your-collection');
// then re-call embedAndStore() for all records
Loading please wait ...
Before you can download the PHP files, the dependencies should be resolved. This can take some minutes. Please be patient.