1
0
mirror of https://github.com/BookStackApp/BookStack.git synced 2025-07-31 15:24:31 +03:00

Vectors: Got basic LLM querying working using vector search context

This commit is contained in:
Dan Brown
2025-03-24 19:51:48 +00:00
parent 8452099a5b
commit 0ffcb3d4aa
8 changed files with 114 additions and 2 deletions

View File

@ -6,6 +6,7 @@ use BookStack\Entities\Queries\PageQueries;
use BookStack\Entities\Queries\QueryPopular;
use BookStack\Entities\Tools\SiblingFetcher;
use BookStack\Http\Controller;
use BookStack\Search\Vectors\VectorSearchRunner;
use Illuminate\Http\Request;
class SearchController extends Controller
@ -139,4 +140,19 @@ class SearchController extends Controller
return view('entities.list-basic', ['entities' => $entities, 'style' => 'compact']);
}
public function searchQuery(Request $request, VectorSearchRunner $runner)
{
$query = $request->get('query', '');
if ($query) {
$results = $runner->run($query);
} else {
$results = null;
}
return view('search.query', [
'results' => $results,
]);
}
}

View File

@ -42,7 +42,7 @@ class EntityVectorGenerator
$toInsert[] = [
'entity_id' => $entity->id,
'entity_type' => $entity->getMorphClass(),
'embedding' => DB::raw('STRING_TO_VECTOR("[' . implode(',', $embedding) . ']")'),
'embedding' => DB::raw('VEC_FROMTEXT("[' . implode(',', $embedding) . ']")'),
'text' => $text,
];
}

View File

@ -33,4 +33,25 @@ class OpenAiVectorQueryService implements VectorQueryService
return $response['data'][0]['embedding'];
}
public function query(string $input, array $context): string
{
$formattedContext = implode("\n", $context);
$response = $this->jsonRequest('POST', 'v1/chat/completions', [
'model' => 'gpt-4o',
'messages' => [
[
'role' => 'developer',
'content' => 'You are a helpful assistant providing search query responses. Be specific, factual and to-the-point in response.'
],
[
'role' => 'user',
'content' => "Provide a response to the below given QUERY using the below given CONTEXT\nQUERY: {$input}\n\nCONTEXT: {$formattedContext}",
]
],
]);
return $response['choices'][0]['message']['content'] ?? '';
}
}

View File

@ -9,4 +9,13 @@ interface VectorQueryService
* @return float[]
*/
public function generateEmbeddings(string $text): array;
/**
* Query the LLM service using the given user input, and
* relevant context text retrieved locally via a vector search.
* Returns the response output text from the LLM.
*
* @param string[] $context
*/
public function query(string $input, array $context): string;
}

View File

@ -0,0 +1,33 @@
<?php
namespace BookStack\Search\Vectors;
class VectorSearchRunner
{
public function __construct(
protected VectorQueryServiceProvider $vectorQueryServiceProvider
) {
}
public function run(string $query): array
{
$queryService = $this->vectorQueryServiceProvider->get();
$queryVector = $queryService->generateEmbeddings($query);
// TODO - Apply permissions
// TODO - Join models
$topMatches = SearchVector::query()->select('text', 'entity_type', 'entity_id')
->selectRaw('VEC_DISTANCE_COSINE(VEC_FROMTEXT("[' . implode(',', $queryVector) . ']"), embedding) as distance')
->orderBy('distance', 'asc')
->limit(10)
->get();
$matchesText = array_values(array_map(fn (SearchVector $match) => $match->text, $topMatches->all()));
$llmResult = $queryService->query($query, $matchesText);
return [
'llm_result' => $llmResult,
'entity_matches' => $topMatches->toArray()
];
}
}