Skip to content

Commit 6f5861f

Browse files
feat: search vector store (#559)
* feat(vector-stores): implement search method * chore(vector-stores): Add search documentation * test(vectore-stores): search resource and response * chore: remove extra newlines
1 parent fe10efb commit 6f5861f

File tree

12 files changed

+436
-0
lines changed

12 files changed

+436
-0
lines changed

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,40 @@ foreach ($response->data as $result) {
19291929
$response->toArray(); // ['object' => 'list', ...]]
19301930
```
19311931

1932+
#### `search`
1933+
1934+
Search a vector store for relevant chunks based on a query and file attributes filter.
1935+
1936+
```php
1937+
$response = $client->vectorStores()->search(
1938+
vectorStoreId: 'vs_vzfQhlTWVUl38QGqQAoQjeDF',
1939+
parameters: [
1940+
'query' => 'What is the return policy?',
1941+
'max_num_results' => 5,
1942+
'filters' => [],
1943+
'rewrite_query' => false
1944+
]
1945+
);
1946+
1947+
$response->object; // 'vector_store.search_results.page'
1948+
$response->searchQuery; // 'What is the return policy?'
1949+
$response->hasMore; // false
1950+
$response->nextPage; // null
1951+
foreach ($response->data as $file) {
1952+
$result->fileId; // 'file-fUU0hFRuQ1GzhOweTNeJlCXG'
1953+
$result->filename; // 'return_policy.pdf'
1954+
$result->score; // 0.95
1955+
$result->attributes; // ['category' => 'customer_service']
1956+
1957+
foreach ($result->content as $content) {
1958+
$content->type; // 'text'
1959+
$content->text; // 'Our return policy allows customers to return items within 30 days...'
1960+
}
1961+
}
1962+
1963+
$response->toArray(); // ['object' => 'vector_store.search_results.page', ...]
1964+
```
1965+
19321966
### `Vector Store File Batches` Resource
19331967

19341968
#### `create`

src/Contracts/Resources/VectorStoresContract.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace OpenAI\Contracts\Resources;
44

5+
use OpenAI\Responses\VectorStores\Search\VectorStoreSearchResponse;
56
use OpenAI\Responses\VectorStores\VectorStoreDeleteResponse;
67
use OpenAI\Responses\VectorStores\VectorStoreListResponse;
78
use OpenAI\Responses\VectorStores\VectorStoreResponse;
@@ -62,4 +63,13 @@ public function files(): VectorStoresFilesContract;
6263
* @see https://platform.openai.com/docs/api-reference/vector-stores-file-batches
6364
*/
6465
public function batches(): VectorStoresFileBatchesContract;
66+
67+
/**
68+
* Search a vector store for relevant chunks based on a query and file attributes filter.
69+
*
70+
* @see https://platform.openai.com/docs/api-reference/vector-stores/search
71+
*
72+
* @param array<string, mixed> $parameters
73+
*/
74+
public function search(string $vectorStoreId, array $parameters = []): VectorStoreSearchResponse;
6575
}

src/Resources/VectorStores.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use OpenAI\Contracts\Resources\VectorStoresContract;
88
use OpenAI\Contracts\Resources\VectorStoresFileBatchesContract;
99
use OpenAI\Contracts\Resources\VectorStoresFilesContract;
10+
use OpenAI\Responses\VectorStores\Search\VectorStoreSearchResponse;
1011
use OpenAI\Responses\VectorStores\VectorStoreDeleteResponse;
1112
use OpenAI\Responses\VectorStores\VectorStoreListResponse;
1213
use OpenAI\Responses\VectorStores\VectorStoreResponse;
@@ -117,4 +118,21 @@ public function batches(): VectorStoresFileBatchesContract
117118
{
118119
return new VectorStoresFileBatches($this->transporter);
119120
}
121+
122+
/**
123+
* Search a vector store for relevant chunks based on a query and file attributes filter.
124+
*
125+
* @see https://platform.openai.com/docs/api-reference/vector-stores/search
126+
*
127+
* @param array<string, mixed> $parameters
128+
*/
129+
public function search(string $vectorStoreId, array $parameters = []): VectorStoreSearchResponse
130+
{
131+
$payload = Payload::create("vector_stores/{$vectorStoreId}/search", $parameters);
132+
133+
/** @var Response<array{object: string, search_query: string|array<mixed>, data: array<int, array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>, has_more: bool, next_page: ?string}> $response */
134+
$response = $this->transporter->requestObject($payload);
135+
136+
return VectorStoreSearchResponse::from($response->data(), $response->meta());
137+
}
120138
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\VectorStores\Search;
6+
7+
use OpenAI\Contracts\ResponseContract;
8+
use OpenAI\Contracts\ResponseHasMetaInformationContract;
9+
use OpenAI\Responses\Concerns\ArrayAccessible;
10+
use OpenAI\Responses\Concerns\HasMetaInformation;
11+
use OpenAI\Responses\Meta\MetaInformation;
12+
use OpenAI\Testing\Responses\Concerns\Fakeable;
13+
14+
/**
15+
* @implements ResponseContract<array{object: string, search_query: string|array<mixed>, data: array<int, array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>, has_more: bool, next_page: ?string}>
16+
*/
17+
final class VectorStoreSearchResponse implements ResponseContract, ResponseHasMetaInformationContract
18+
{
19+
/**
20+
* @use ArrayAccessible<array{object: string, search_query: string|array<mixed>, data: array<int, array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>, has_more: bool, next_page: ?string}>
21+
*/
22+
use ArrayAccessible;
23+
24+
use Fakeable;
25+
use HasMetaInformation;
26+
27+
/**
28+
* @param array<int, VectorStoreSearchResponseFile> $data
29+
* @param string|array<mixed> $searchQuery
30+
*/
31+
private function __construct(
32+
public readonly string $object,
33+
public readonly string|array $searchQuery,
34+
public readonly array $data,
35+
public readonly bool $hasMore,
36+
public readonly ?string $nextPage,
37+
private readonly MetaInformation $meta,
38+
) {}
39+
40+
/**
41+
* Acts as static factory, and returns a new Response instance.
42+
*
43+
* @param array{object: string, search_query: string|array<mixed>, data: array<int, array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>, has_more: bool, next_page: ?string} $attributes
44+
*/
45+
public static function from(array $attributes, MetaInformation $meta): self
46+
{
47+
$data = array_map(
48+
static fn (array $result): VectorStoreSearchResponseFile => VectorStoreSearchResponseFile::from($result),
49+
$attributes['data']
50+
);
51+
52+
return new self(
53+
$attributes['object'],
54+
$attributes['search_query'],
55+
$data,
56+
$attributes['has_more'],
57+
$attributes['next_page'],
58+
$meta,
59+
);
60+
}
61+
62+
/**
63+
* {@inheritDoc}
64+
*
65+
* @return array{object: string, search_query: string|array<mixed>, data: array<int, array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>, has_more: bool, next_page: ?string}
66+
*/
67+
public function toArray(): array
68+
{
69+
return [
70+
'object' => $this->object,
71+
'search_query' => $this->searchQuery,
72+
'data' => array_map(
73+
static fn (VectorStoreSearchResponseFile $item): array => $item->toArray(),
74+
$this->data
75+
),
76+
'has_more' => $this->hasMore,
77+
'next_page' => $this->nextPage,
78+
];
79+
}
80+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\VectorStores\Search;
6+
7+
use OpenAI\Contracts\ResponseContract;
8+
use OpenAI\Responses\Concerns\ArrayAccessible;
9+
use OpenAI\Testing\Responses\Concerns\Fakeable;
10+
11+
/**
12+
* @implements ResponseContract<array{type: string, text: string}>
13+
*/
14+
final class VectorStoreSearchResponseContent implements ResponseContract
15+
{
16+
/**
17+
* @use ArrayAccessible<array{type: string, text: string}>
18+
*/
19+
use ArrayAccessible;
20+
21+
use Fakeable;
22+
23+
private function __construct(
24+
public readonly string $type,
25+
public readonly string $text,
26+
) {}
27+
28+
/**
29+
* Acts as static factory, and returns a new Response instance.
30+
*
31+
* @param array{type: string, text: string} $attributes
32+
*/
33+
public static function from(array $attributes): self
34+
{
35+
return new self(
36+
$attributes['type'],
37+
$attributes['text'],
38+
);
39+
}
40+
41+
/**
42+
* {@inheritDoc}
43+
*/
44+
public function toArray(): array
45+
{
46+
return [
47+
'type' => $this->type,
48+
'text' => $this->text,
49+
];
50+
}
51+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace OpenAI\Responses\VectorStores\Search;
6+
7+
use OpenAI\Contracts\ResponseContract;
8+
use OpenAI\Responses\Concerns\ArrayAccessible;
9+
use OpenAI\Testing\Responses\Concerns\Fakeable;
10+
11+
/**
12+
* @implements ResponseContract<array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>
13+
*/
14+
final class VectorStoreSearchResponseFile implements ResponseContract
15+
{
16+
/**
17+
* @use ArrayAccessible<array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>}>
18+
*/
19+
use ArrayAccessible;
20+
21+
use Fakeable;
22+
23+
/**
24+
* @param array<string, mixed> $attributes
25+
* @param array<int, VectorStoreSearchResponseContent> $content
26+
*/
27+
private function __construct(
28+
public readonly string $fileId,
29+
public readonly string $filename,
30+
public readonly float $score,
31+
public readonly array $attributes,
32+
public readonly array $content,
33+
) {}
34+
35+
/**
36+
* Acts as static factory, and returns a new Response instance.
37+
*
38+
* @param array{file_id: string, filename: string, score: float, attributes: array<string, mixed>, content: array<int, array{type: string, text: string}>} $attributes
39+
*/
40+
public static function from(array $attributes): self
41+
{
42+
$content = array_map(
43+
static fn (array $content): VectorStoreSearchResponseContent => VectorStoreSearchResponseContent::from($content),
44+
$attributes['content'],
45+
);
46+
47+
return new self(
48+
$attributes['file_id'],
49+
$attributes['filename'],
50+
$attributes['score'],
51+
$attributes['attributes'],
52+
$content,
53+
);
54+
}
55+
56+
/**
57+
* {@inheritDoc}
58+
*/
59+
public function toArray(): array
60+
{
61+
return [
62+
'file_id' => $this->fileId,
63+
'filename' => $this->filename,
64+
'score' => $this->score,
65+
'attributes' => $this->attributes,
66+
'content' => array_map(
67+
static fn (VectorStoreSearchResponseContent $content): array => $content->toArray(),
68+
$this->content,
69+
),
70+
];
71+
}
72+
}

src/Testing/Resources/VectorStoresTestResource.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
use OpenAI\Contracts\Resources\VectorStoresFileBatchesContract;
77
use OpenAI\Contracts\Resources\VectorStoresFilesContract;
88
use OpenAI\Resources\VectorStores;
9+
use OpenAI\Responses\VectorStores\Search\VectorStoreSearchResponse;
910
use OpenAI\Responses\VectorStores\VectorStoreDeleteResponse;
1011
use OpenAI\Responses\VectorStores\VectorStoreListResponse;
1112
use OpenAI\Responses\VectorStores\VectorStoreResponse;
@@ -45,6 +46,14 @@ public function list(array $parameters = []): VectorStoreListResponse
4546
return $this->record(__FUNCTION__, func_get_args());
4647
}
4748

49+
/**
50+
* @param array<string, mixed> $parameters
51+
*/
52+
public function search(string $vectorStoreId, array $parameters = []): VectorStoreSearchResponse
53+
{
54+
return $this->record(__FUNCTION__, func_get_args());
55+
}
56+
4857
public function files(): VectorStoresFilesContract
4958
{
5059
return new VectorStoresFilesTestResource($this->fake);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php
2+
3+
namespace OpenAI\Testing\Responses\Fixtures\VectorStores\Search;
4+
5+
final class VectorStoreSearchResponseContentFixture
6+
{
7+
public const ATTRIBUTES = [
8+
'type' => 'text',
9+
'text' => 'Sample text content from the vector store.',
10+
];
11+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
namespace OpenAI\Testing\Responses\Fixtures\VectorStores\Search;
4+
5+
final class VectorStoreSearchResponseFileFixture
6+
{
7+
public const ATTRIBUTES = [
8+
'file_id' => 'file_abc123',
9+
'filename' => 'document.pdf',
10+
'score' => 0.95,
11+
'attributes' => [
12+
'author' => 'John Doe',
13+
'date' => '2023-01-01',
14+
],
15+
'content' => [
16+
VectorStoreSearchResponseContentFixture::ATTRIBUTES,
17+
],
18+
];
19+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
namespace OpenAI\Testing\Responses\Fixtures\VectorStores\Search;
4+
5+
final class VectorStoreSearchResponseFixture
6+
{
7+
public const ATTRIBUTES = [
8+
'object' => 'vector_store.search_results.page',
9+
'search_query' => 'What is the return policy?',
10+
'data' => [
11+
VectorStoreSearchResponseFileFixture::ATTRIBUTES,
12+
[
13+
'file_id' => 'file_xyz789',
14+
'filename' => 'notes.txt',
15+
'score' => 0.89,
16+
'attributes' => [
17+
'author' => 'Jane Smith',
18+
'date' => '2023-01-02',
19+
],
20+
'content' => [
21+
[
22+
'type' => 'text',
23+
'text' => 'Sample text content from the vector store.',
24+
],
25+
],
26+
],
27+
],
28+
'has_more' => false,
29+
'next_page' => null,
30+
];
31+
}

0 commit comments

Comments
 (0)