2025-03-24 16:28:14 +00:00
< ? php
2025-08-21 12:14:52 +01:00
namespace BookStack\Search\Queries\Services ;
2025-03-24 16:28:14 +00:00
use BookStack\Http\HttpRequestService ;
class OpenAiVectorQueryService implements VectorQueryService
{
2025-03-25 19:38:32 +00:00
protected string $key ;
protected string $endpoint ;
protected string $embeddingModel ;
protected string $queryModel ;
2025-03-24 16:28:14 +00:00
public function __construct (
2025-03-25 19:38:32 +00:00
protected array $options ,
2025-03-24 16:28:14 +00:00
protected HttpRequestService $http ,
) {
2025-03-25 19:38:32 +00:00
// TODO - Some kind of validation of options
$this -> key = $this -> options [ 'key' ] ? ? '' ;
$this -> endpoint = $this -> options [ 'endpoint' ] ? ? '' ;
$this -> embeddingModel = $this -> options [ 'embedding_model' ] ? ? '' ;
$this -> queryModel = $this -> options [ 'query_model' ] ? ? '' ;
2025-03-24 16:28:14 +00:00
}
protected function jsonRequest ( string $method , string $uri , array $data ) : array
{
$fullUrl = rtrim ( $this -> endpoint , '/' ) . '/' . ltrim ( $uri , '/' );
2025-03-25 19:38:32 +00:00
$client = $this -> http -> buildClient ( 30 );
2025-03-24 16:28:14 +00:00
$request = $this -> http -> jsonRequest ( $method , $fullUrl , $data )
-> withHeader ( 'Authorization' , 'Bearer ' . $this -> key );
$response = $client -> sendRequest ( $request );
return json_decode ( $response -> getBody () -> getContents (), true );
}
public function generateEmbeddings ( string $text ) : array
{
$response = $this -> jsonRequest ( 'POST' , 'v1/embeddings' , [
'input' => $text ,
2025-03-25 19:38:32 +00:00
'model' => $this -> embeddingModel ,
2025-03-24 16:28:14 +00:00
]);
return $response [ 'data' ][ 0 ][ 'embedding' ];
}
2025-03-24 19:51:48 +00:00
public function query ( string $input , array $context ) : string
{
$formattedContext = implode ( " \n " , $context );
$response = $this -> jsonRequest ( 'POST' , 'v1/chat/completions' , [
2025-03-25 19:38:32 +00:00
'model' => $this -> queryModel ,
2025-03-24 19:51:48 +00:00
'messages' => [
[
'role' => 'developer' ,
2025-03-25 19:38:32 +00:00
'content' => 'You are a helpful assistant providing search query responses. Be specific, factual and to-the-point in response. Don\'t try to converse or continue the conversation.'
2025-03-24 19:51:48 +00:00
],
[
'role' => 'user' ,
2025-03-25 19:38:32 +00:00
'content' => " Provide a response to the below given QUERY using the below given CONTEXT. The CONTEXT is split into parts via lines. Ignore any nonsensical lines of CONTEXT. \n QUERY: { $input } \n \n CONTEXT: { $formattedContext } " ,
2025-03-24 19:51:48 +00:00
]
],
]);
return $response [ 'choices' ][ 0 ][ 'message' ][ 'content' ] ? ? '' ;
}
2025-03-24 16:28:14 +00:00
}