Skip to content

Commit 6e82e2f

Browse files
committed
fix(examples): hardcoded headers removed && authentication improved
1 parent 64d0d10 commit 6e82e2f

File tree

4 files changed

+80
-63
lines changed

4 files changed

+80
-63
lines changed

examples/.env

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ MEILISEARCH_API_KEY=changeMe
8383
LMSTUDIO_HOST_URL=http://127.0.0.1:1234
8484

8585
# Qdrant
86-
QDRANT_HOST='http://127.0.0.1:6333'
86+
QDRANT_HOST=http://127.0.0.1:6333
8787
QDRANT_SERVICE_API_KEY=changeMe
8888

8989
# SurrealDB

examples/store/surrealdb-similarity-search.php

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,24 +24,17 @@
2424
use Symfony\AI\Store\Document\TextDocument;
2525
use Symfony\AI\Store\Document\Vectorizer;
2626
use Symfony\AI\Store\Indexer;
27-
use Symfony\Component\Dotenv\Dotenv;
2827
use Symfony\Component\HttpClient\HttpClient;
2928
use Symfony\Component\Uid\Uuid;
3029

31-
require_once dirname(__DIR__).'/vendor/autoload.php';
32-
(new Dotenv())->loadEnv(dirname(__DIR__).'/.env');
33-
34-
if (!isset($_SERVER['OPENAI_API_KEY'], $_SERVER['SURREALDB_HOST'], $_SERVER['SURREALDB_USER'], $_SERVER['SURREALDB_PASS'])) {
35-
echo 'Please set OPENAI_API_KEY, SURREALDB_HOST, SURREALDB_USER and SURREALDB_PASS environment variables.'.\PHP_EOL;
36-
exit(1);
37-
}
30+
require_once dirname(__DIR__).'/bootstrap.php';
3831

3932
// initialize the store
4033
$store = new Store(
4134
httpClient: HttpClient::create(),
42-
endpointUrl: $_SERVER['SURREALDB_HOST'],
43-
user: $_SERVER['SURREALDB_USER'],
44-
password: $_SERVER['SURREALDB_PASS'],
35+
endpointUrl: env('SURREALDB_HOST'),
36+
user: env('SURREALDB_USER'),
37+
password: env('SURREALDB_PASS'),
4538
namespace: 'default',
4639
database: 'movies',
4740
table: 'movies',
@@ -69,7 +62,7 @@
6962
$model = new GPT(GPT::GPT_4O_MINI);
7063

7164
$similaritySearch = new SimilaritySearch($platform, $embeddings, $store);
72-
$toolbox = Toolbox::create($similaritySearch);
65+
$toolbox = new Toolbox([$similaritySearch], logger: logger());
7366
$processor = new AgentProcessor($toolbox);
7467
$agent = new Agent($platform, $model, [$processor], [$processor]);
7568

src/store/src/Bridge/SurrealDB/Store.php

Lines changed: 33 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,76 +27,58 @@
2727
*/
2828
final class Store implements InitializableStoreInterface, VectorStoreInterface
2929
{
30+
private string $authenticationToken = '';
31+
3032
public function __construct(
3133
private readonly HttpClientInterface $httpClient,
3234
private readonly string $endpointUrl,
33-
#[\SensitiveParameter]
34-
private readonly string $user,
35-
#[\SensitiveParameter]
36-
private readonly string $password,
37-
#[\SensitiveParameter]
38-
private readonly string $namespace,
39-
#[\SensitiveParameter]
40-
private readonly string $database,
35+
#[\SensitiveParameter] private readonly string $user,
36+
#[\SensitiveParameter] private readonly string $password,
37+
#[\SensitiveParameter] private readonly string $namespace,
38+
#[\SensitiveParameter] private readonly string $database,
4139
private readonly string $table = 'vectors',
4240
private readonly string $vectorFieldName = '_vectors',
4341
private readonly string $strategy = 'cosine',
4442
private readonly int $embeddingsDimension = 1536,
43+
private readonly bool $isNamespacedUser = false,
4544
) {
4645
}
4746

4847
public function add(VectorDocument ...$documents): void
4948
{
50-
$authenticationToken = $this->authenticate([]);
51-
5249
foreach ($documents as $document) {
53-
$this->request('POST', \sprintf('key/%s', $this->table), $this->convertToIndexableArray($document), [
54-
'Surreal-NS' => $this->namespace,
55-
'Surreal-DB' => $this->database,
56-
'Authorization' => \sprintf('Bearer %s', $authenticationToken),
57-
]);
50+
$this->request('POST', \sprintf('key/%s', $this->table), $this->convertToIndexableArray($document));
5851
}
5952
}
6053

6154
public function query(Vector $vector, array $options = [], ?float $minScore = null): array
6255
{
63-
$authenticationToken = $this->authenticate($options);
64-
6556
$vectors = json_encode($vector->getData());
6657

6758
$results = $this->request('POST', 'sql', \sprintf(
6859
'SELECT id, %s, _metadata, vector::similarity::%s(%s, %s) AS distance FROM %s WHERE %s <|2|> %s;',
6960
$this->vectorFieldName, $this->strategy, $this->vectorFieldName, $vectors, $this->table, $this->vectorFieldName, $vectors,
70-
), [
71-
'Surreal-NS' => $this->namespace,
72-
'Surreal-DB' => $this->database,
73-
'Authorization' => \sprintf('Bearer %s', $authenticationToken),
74-
]);
61+
));
7562

7663
return array_map($this->convertToVectorDocument(...), $results[0]['result']);
7764
}
7865

7966
public function initialize(array $options = []): void
8067
{
81-
$authenticationToken = $this->authenticate($options);
68+
$this->authenticate();
8269

8370
$this->request('POST', 'sql', \sprintf(
8471
'DEFINE INDEX %s_vectors ON %s FIELDS %s MTREE DIMENSION %d DIST %s TYPE F32',
8572
$this->table, $this->table, $this->vectorFieldName, $this->embeddingsDimension, $this->strategy
86-
), [
87-
'Surreal-NS' => $this->namespace,
88-
'Surreal-DB' => $this->database,
89-
'Authorization' => \sprintf('Bearer %s', $authenticationToken),
90-
]);
73+
));
9174
}
9275

9376
/**
9477
* @param array<string, mixed>|string $payload
95-
* @param array<string, mixed> $extraHeaders
9678
*
9779
* @return array<string|int, mixed>
9880
*/
99-
private function request(string $method, string $endpoint, array|string $payload, array $extraHeaders = []): array
81+
private function request(string $method, string $endpoint, array|string $payload): array
10082
{
10183
$url = \sprintf('%s/%s', $this->endpointUrl, $endpoint);
10284

@@ -111,10 +93,13 @@ private function request(string $method, string $endpoint, array|string $payload
11193
}
11294

11395
$response = $this->httpClient->request($method, $url, array_merge($finalPayload, [
114-
'headers' => array_merge($extraHeaders, [
96+
'headers' => [
11597
'Accept' => 'application/json',
11698
'Content-Type' => 'application/json',
117-
]),
99+
'Surreal-NS' => $this->namespace,
100+
'Surreal-DB' => $this->database,
101+
'Authorization' => \sprintf('Bearer %s', $this->authenticationToken),
102+
],
118103
]));
119104

120105
return $response->toArray();
@@ -154,29 +139,35 @@ private function convertToVectorDocument(array $data): VectorDocument
154139
);
155140
}
156141

157-
/**
158-
* @param array{
159-
* namespacedUser?: bool
160-
* } $options The namespacedUser option is used to determine if the user is root or not, if not, both the namespace and database must be specified
161-
*/
162-
private function authenticate(array $options): string
142+
private function authenticate(): void
163143
{
144+
if ('' !== $this->authenticationToken) {
145+
return;
146+
}
147+
164148
$authenticationPayload = [
165149
'user' => $this->user,
166150
'pass' => $this->password,
167151
];
168152

169-
if (\array_key_exists('namespacedUser', $options) && !$options['namespacedUser']) {
153+
if ($this->isNamespacedUser) {
170154
$authenticationPayload['ns'] = $this->namespace;
171155
$authenticationPayload['db'] = $this->database;
172156
}
173157

174-
$authenticationResponse = $this->request('POST', 'signin', $authenticationPayload);
158+
$authenticationResponse = $this->httpClient->request('POST', \sprintf('%s/signin', $this->endpointUrl), [
159+
'headers' => [
160+
'Accept' => 'application/json',
161+
],
162+
'json' => $authenticationPayload,
163+
]);
164+
165+
$payload = $authenticationResponse->toArray();
175166

176-
if (!\array_key_exists('token', $authenticationResponse)) {
167+
if (!\array_key_exists('token', $payload)) {
177168
throw new RuntimeException('The SurrealDB authentication response does not contain a token.');
178169
}
179170

180-
return $authenticationResponse['token'];
171+
$this->authenticationToken = $payload['token'];
181172
}
182173
}

src/store/tests/Bridge/SurrealDB/StoreTest.php

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,22 @@ public function testStoreCannotAddOnInvalidResponse(): void
101101
], [
102102
'http_code' => 200,
103103
]),
104+
new JsonMockResponse([
105+
[
106+
'result' => 'DEFINE INDEX test_vectors ON movies FIELDS _vectors MTREE DIMENSION 1275 DIST cosine TYPE F32',
107+
'status' => 'OK',
108+
'time' => '263.208µs',
109+
],
110+
], [
111+
'http_code' => 200,
112+
]),
104113
new JsonMockResponse([], [
105114
'http_code' => 400,
106115
]),
107116
], 'http://localhost:8000');
108117

109118
$store = new Store($httpClient, 'http://localhost:8000', 'test', 'test', 'test', 'test', 'test');
119+
$store->initialize();
110120

111121
self::expectException(ClientException::class);
112122
self::expectExceptionMessage('HTTP 400 returned for "http://localhost:8000/key/test".');
@@ -124,12 +134,22 @@ public function testStoreCannotAddOnInvalidAddResponse(): void
124134
], [
125135
'http_code' => 200,
126136
]),
137+
new JsonMockResponse([
138+
[
139+
'result' => 'DEFINE INDEX test_vectors ON movies FIELDS _vectors MTREE DIMENSION 1275 DIST cosine TYPE F32',
140+
'status' => 'OK',
141+
'time' => '263.208µs',
142+
],
143+
], [
144+
'http_code' => 200,
145+
]),
127146
new JsonMockResponse([], [
128147
'http_code' => 400,
129148
]),
130149
], 'http://localhost:8000');
131150

132151
$store = new Store($httpClient, 'http://localhost:8000', 'test', 'test', 'test', 'test', 'test');
152+
$store->initialize();
133153

134154
self::expectException(ClientException::class);
135155
self::expectExceptionMessage('HTTP 400 returned for "http://localhost:8000/key/test".');
@@ -147,6 +167,15 @@ public function testStoreCanAdd(): void
147167
], [
148168
'http_code' => 200,
149169
]),
170+
new JsonMockResponse([
171+
[
172+
'result' => 'DEFINE INDEX test_vectors ON movies FIELDS _vectors MTREE DIMENSION 1275 DIST cosine TYPE F32',
173+
'status' => 'OK',
174+
'time' => '263.208µs',
175+
],
176+
], [
177+
'http_code' => 200,
178+
]),
150179
new JsonMockResponse([
151180
[
152181
'result' => [
@@ -174,10 +203,11 @@ public function testStoreCanAdd(): void
174203
], 'http://localhost:8000');
175204

176205
$store = new Store($httpClient, 'http://localhost:8000', 'test', 'test', 'test', 'test', 'test');
206+
$store->initialize();
177207

178208
$store->add(new VectorDocument(Uuid::v4(), new Vector(array_fill(0, 1275, 0.1))));
179209

180-
self::assertSame(2, $httpClient->getRequestsCount());
210+
self::assertSame(3, $httpClient->getRequestsCount());
181211
}
182212

183213
public function testStoreCannotQueryOnInvalidResponse(): void
@@ -190,6 +220,15 @@ public function testStoreCannotQueryOnInvalidResponse(): void
190220
], [
191221
'http_code' => 200,
192222
]),
223+
new JsonMockResponse([
224+
[
225+
'result' => 'DEFINE INDEX test_vectors ON movies FIELDS _vectors MTREE DIMENSION 1275 DIST cosine TYPE F32',
226+
'status' => 'OK',
227+
'time' => '263.208µs',
228+
],
229+
], [
230+
'http_code' => 200,
231+
]),
193232
new JsonMockResponse([
194233
[
195234
'result' => [
@@ -214,19 +253,13 @@ public function testStoreCannotQueryOnInvalidResponse(): void
214253
], [
215254
'http_code' => 200,
216255
]),
217-
new JsonMockResponse([
218-
'code' => 200,
219-
'details' => 'Authentication succeeded.',
220-
'token' => 'bar',
221-
], [
222-
'http_code' => 200,
223-
]),
224256
new JsonMockResponse([], [
225257
'http_code' => 400,
226258
]),
227259
], 'http://localhost:8000');
228260

229261
$store = new Store($httpClient, 'http://localhost:8000', 'test', 'test', 'test', 'test', 'test');
262+
$store->initialize();
230263

231264
$store->add(new VectorDocument(Uuid::v4(), new Vector(array_fill(0, 1275, 0.1))));
232265

0 commit comments

Comments
 (0)