Skip to content

Commit e7753e0

Browse files
committed
Pinecone vector store
1 parent 99b5a5e commit e7753e0

File tree

7 files changed

+69
-20
lines changed

7 files changed

+69
-20
lines changed

src/Providers/Embeddings/VoyageEmbeddingProvider.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ class VoyageEmbeddingProvider implements EmbeddingsProviderInterface
1010
protected Client $client;
1111

1212
public function __construct(
13-
protected string $key,
13+
string $key,
1414
protected string $model
1515
) {
1616
$this->client = new Client([
1717
'base_uri' => 'https://api.voyageai.com/v1/embeddings',
1818
'headers' => [
1919
'Accept' => 'application/json',
2020
'Content-Type' => 'application/json',
21-
'Authorization' => 'Bearer ' . $this->key,
21+
'Authorization' => 'Bearer ' . $key,
2222
],
2323
]);
2424
}

src/Providers/Log.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
use NeuronAI\Messages\AssistantMessage;
66
use NeuronAI\Messages\Message;
7+
use NeuronAI\Providers\AIProviderInterface;
78
use Psr\Log\LoggerInterface;
89

910
class Log implements AIProviderInterface

src/Providers/Mistral.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace NeuronAI\Providers;
44

5+
use GuzzleHttp\RequestOptions;
56
use NeuronAI\Messages\AssistantMessage;
67
use NeuronAI\Messages\Message;
78
use GuzzleHttp\Client;
@@ -55,7 +56,7 @@ public function chat(array|string $prompt): Message
5556
}
5657

5758
$result = $this->client->post('/chat/completions', [
58-
'json' => [
59+
RequestOptions::JSON => [
5960
'model' => $this->model,
6061
'messages' => $prompt,
6162
]

src/Providers/OpenAI.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace NeuronAI\Providers;
44

5+
use GuzzleHttp\RequestOptions;
56
use NeuronAI\Messages\AssistantMessage;
67
use NeuronAI\Messages\Message;
78
use GuzzleHttp\Client;
@@ -56,7 +57,7 @@ public function chat(array|string $prompt): Message
5657
}
5758

5859
$result = $this->client->post('/chat/completions', [
59-
'json' => [
60+
RequestOptions::JSON => [
6061
'model' => $this->model,
6162
'messages' => $prompt,
6263
]

src/RAG/VectorStore/ElasticsearchVectorStore.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,10 @@ class ElasticsearchVectorStore implements VectorStoreInterface
1313
/**
1414
* @throws \Exception
1515
*/
16-
public function __construct(protected Client $client, protected string $indexName)
17-
{
16+
public function __construct(
17+
protected Client $client,
18+
protected string $indexName
19+
) {
1820
/** @var Elasticsearch $existResponse */
1921
$existResponse = $client->indices()->exists(['index' => $indexName]);
2022
$existStatusCode = $existResponse->getStatusCode();
@@ -142,14 +144,13 @@ public function similaritySearch(array $embedding, int $k = 4, array $additional
142144
if (\array_key_exists('filter', $additionalArguments)) {
143145
$searchParams['body']['knn']['filter'] = $additionalArguments['filter'];
144146
}
145-
/** @var array{hits: array{hits: array{array{_source: array{embedding: float[], content: string, formattedContent: string, sourceType: string, sourceName: string, hash: string, chunkNumber: int}}}}} $rawResponse */
147+
146148
$rawResponse = $this->client->search($searchParams);
147149

148150
$documents = [];
149151
foreach ($rawResponse['hits']['hits'] as $hit) {
150-
$document = new Document();
152+
$document = new Document($hit['_source']['content']);
151153
$document->embedding = $hit['_source']['embedding'];
152-
$document->content = $hit['_source']['content'];
153154
$document->sourceType = $hit['_source']['sourceType'];
154155
$document->sourceName = $hit['_source']['sourceName'];
155156
$document->hash = $hit['_source']['hash'];
@@ -166,7 +167,6 @@ private function setVectorDimIfNotSet(int $vectorDim): void
166167
return;
167168
}
168169

169-
/** @var array{string: array{mappings: array{embedding: array{mapping: array{embedding: array{dims: int}}}}}} $response */
170170
$response = $this->client->indices()->getFieldMapping([
171171
'index' => $this->indexName,
172172
'fields' => 'embedding',

src/RAG/VectorStore/MemoryVectorStore.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,12 @@ class MemoryVectorStore implements VectorStoreInterface
1212
private array $documents = [];
1313

1414
public function __construct(
15-
protected SimilarityInterface $similarity = new CosineSimilarity()
16-
) {}
15+
protected ?SimilarityInterface $similarity = null
16+
) {
17+
if (is_null($this->similarity)) {
18+
$this->similarity = new CosineSimilarity();
19+
}
20+
}
1721

1822
public function addDocument(Document $document): void
1923
{

src/RAG/VectorStore/PineconeVectorStore.php

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,32 +2,74 @@
22

33
namespace NeuronAI\RAG\VectorStore;
44

5+
use GuzzleHttp\Client;
6+
use GuzzleHttp\RequestOptions;
57
use NeuronAI\RAG\Document;
6-
use \Probots\Pinecone\Client;
78

89
class PineconeVectorStore implements VectorStoreInterface
910
{
11+
protected Client $client;
12+
1013
public function __construct(
11-
protected Client $client,
12-
protected string $indexName
14+
string $key,
15+
protected string $indexName,
16+
array $spec,
17+
string $version = '2025-01'
1318
) {
14-
// todo: setup the vector index
19+
$this->client = new Client([
20+
'base_uri' => 'https://api.pinecone.io',
21+
'headers' => [
22+
'Accept' => 'application/json',
23+
'Content-Type' => 'application/json',
24+
'Api-Key' => $key,
25+
'X-Pinecone-API-Version' => $version,
26+
]
27+
]);
28+
29+
$response = $this->client->get("indexes/{$this->indexName}");
30+
31+
if ($response->getStatusCode() === 200) {
32+
return;
33+
}
1534

16-
// https://github.com/probots-io/pinecone-php
35+
// Create the index
36+
$this->client->post('indexes', [
37+
RequestOptions::JSON => [
38+
'name' => $indexName,
39+
'spec' => $spec,
40+
]
41+
]);
1742
}
1843

1944
public function addDocument(Document $document): void
2045
{
21-
// TODO: Implement addDocument() method.
46+
$this->addDocuments([$document]);
2247
}
2348

2449
public function addDocuments(array $documents): void
2550
{
26-
// TODO: Implement addDocuments() method.
51+
$this->client->post("indexes/{$this->indexName}/vectors/upsert", [
52+
RequestOptions::JSON => array_map(function (Document $document) {
53+
return [
54+
'id' => $document->id??uniqid(),
55+
'values' => $document->embedding,
56+
];
57+
}, $documents)
58+
]);
2759
}
2860

2961
public function similaritySearch(array $embedding, int $k = 4): iterable
3062
{
31-
// TODO: Implement similaritySearch() method.
63+
$result = $this->client->get("indexes/{$this->indexName}/query", [
64+
RequestOptions::QUERY => [
65+
'namespace' => '',
66+
'vector' => $embedding,
67+
'top_k' => $k,
68+
]
69+
])->getBody()->getContents();
70+
71+
$result = json_decode($result, true);
72+
73+
return $result['matches'];
3274
}
3375
}

0 commit comments

Comments
 (0)