3 namespace BookStack\Search\Vectors;
5 use BookStack\Entities\Models\Entity;
6 use BookStack\Search\Vectors\Services\VectorQueryService;
7 use Illuminate\Support\Facades\DB;
9 class EntityVectorGenerator
11 public function __construct(
12 protected VectorQueryServiceProvider $vectorQueryServiceProvider
16 public function generateAndStore(Entity $entity): void
18 $vectorService = $this->vectorQueryServiceProvider->get();
20 $text = $this->entityToPlainText($entity);
21 $chunks = $this->chunkText($text);
22 $embeddings = $this->chunksToEmbeddings($chunks, $vectorService);
24 $this->deleteExistingEmbeddingsForEntity($entity);
25 $this->storeEmbeddings($embeddings, $chunks, $entity);
28 protected function deleteExistingEmbeddingsForEntity(Entity $entity): void
31 ->where('entity_type', '=', $entity->getMorphClass())
32 ->where('entity_id', '=', $entity->id)
36 protected function storeEmbeddings(array $embeddings, array $textChunks, Entity $entity): void
40 foreach ($embeddings as $index => $embedding) {
41 $text = $textChunks[$index];
43 'entity_id' => $entity->id,
44 'entity_type' => $entity->getMorphClass(),
45 'embedding' => DB::raw('VEC_FROMTEXT("[' . implode(',', $embedding) . ']")'),
50 // TODO - Chunk inserts
51 SearchVector::query()->insert($toInsert);
55 * @param string[] $chunks
56 * @return float[] array
58 protected function chunksToEmbeddings(array $chunks, VectorQueryService $vectorQueryService): array
61 foreach ($chunks as $index => $chunk) {
62 $embeddings[$index] = $vectorQueryService->generateEmbeddings($chunk);
70 protected function chunkText(string $text): array
72 // TODO - Join adjacent smaller chunks up
73 return array_filter(array_map(function (string $section): string {
74 return trim($section);
75 }, explode("\n", $text)));
78 protected function entityToPlainText(Entity $entity): string
80 $text = $entity->name . "\n\n" . $entity->{$entity->textField};