Skip to content

Commit bce6de6

Browse files
junaidbinfarooqchr-hertel
authored andcommitted
feat(store): Integrate supabase into the store package
- Adds support for supabase feat(store): Integrate supabase into the store package - Adds bundle integration - Adds an entry into the stores factory for supabase docs(store): Integrate supabase into the store package - Adds documentation for the new store integration patch example, default envs and docs after test
1 parent 10b13d3 commit bce6de6

File tree

11 files changed

+757
-0
lines changed

11 files changed

+757
-0
lines changed

docs/components/store.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ You can find more advanced usage in combination with an Agent using the store fo
4848
* `Similarity Search with Symfony Cache (RAG)`_
4949
* `Similarity Search with Typesense (RAG)`_
5050
* `Similarity Search with Weaviate (RAG)`_
51+
* `Similarity Search with Supabase (RAG)`_
5152

5253
.. note::
5354

@@ -70,6 +71,7 @@ Supported Stores
7071
* `Pinecone`_ (requires `probots-io/pinecone-php` as additional dependency)
7172
* `Postgres`_ (requires `ext-pdo`)
7273
* `Qdrant`_
74+
* `Supabase`_ (requires manual database setup)
7375
* `SurrealDB`_
7476
* `Symfony Cache`_ (requires `symfony/cache` as additional dependency)
7577
* `Typesense`_
@@ -137,6 +139,7 @@ This leads to a store implementing two methods::
137139
.. _`Similarity Search with Qdrant (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/qdrant.php
138140
.. _`Similarity Search with SurrealDB (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/surrealdb.php
139141
.. _`Similarity Search with Typesense (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/typesense.php
142+
.. _`Similarity Search with Supabase (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/supabase.php
140143
.. _`Similarity Search with Weaviate (RAG)`: https://github.com/symfony/ai/blob/main/examples/rag/weaviate.php
141144
.. _`Azure AI Search`: https://azure.microsoft.com/products/ai-services/ai-search
142145
.. _`Chroma`: https://www.trychroma.com/
@@ -154,3 +157,4 @@ This leads to a store implementing two methods::
154157
.. _`Typesense`: https://typesense.org/
155158
.. _`Symfony Cache`: https://symfony.com/doc/current/components/cache.html
156159
.. _`Weaviate`: https://weaviate.io/
160+
.. _`Supabase`: https://https://supabase.com/

docs/components/store/supabase.rst

Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
Supabase Bridge
2+
===============
3+
4+
The Supabase bridge provides vector storage capabilities using `pgvector`_ extension through the REST API.
5+
6+
.. note::
7+
8+
Unlike the Postgres Store, the Supabase Store requires manual setup of the database schema because Supabase doesn't
9+
allow arbitrary SQL execution via REST API.
10+
11+
Requirements
12+
~~~~~~~~~~~~
13+
14+
* Enable `pgvector extension`_ in the relevant schema of your Supabase project for using `vector`_ column types.
15+
* Add columns for embedding (type `vector`) and metadata (type `jsonb`) to your table
16+
* Pre-configured RPC `function`_ for similarity search
17+
18+
See section below for detailed SQL commands.
19+
20+
Database Setup
21+
--------------
22+
23+
Execute the following SQL commands in your Supabase SQL Editor:
24+
25+
Enable ``pgvector`` extension
26+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27+
28+
.. code-block:: sql
29+
30+
CREATE EXTENSION IF NOT EXISTS vector;
31+
32+
Create the `documents` table
33+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34+
35+
.. code-block:: sql
36+
37+
CREATE TABLE IF NOT EXISTS documents (
38+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
39+
embedding vector(768) NOT NULL,
40+
metadata JSONB
41+
);
42+
43+
Create the similarity search function
44+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
45+
46+
.. code-block:: sql
47+
48+
CREATE OR REPLACE FUNCTION match_documents(
49+
query_embedding vector(768),
50+
match_count int DEFAULT 10,
51+
match_threshold float DEFAULT 0.0
52+
)
53+
RETURNS TABLE (
54+
id UUID,
55+
embedding vector,
56+
metadata JSONB,
57+
score float
58+
)
59+
LANGUAGE sql
60+
AS $$
61+
SELECT
62+
documents.id,
63+
documents.embedding,
64+
documents.metadata,
65+
1- (documents.embedding <=> query_embedding) AS score
66+
FROM documents
67+
WHERE 1- (documents.embedding <=> query_embedding) >= match_threshold
68+
ORDER BY documents.embedding <=> query_embedding ASC
69+
LIMIT match_count;
70+
$$;
71+
72+
Create an index for better performance
73+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
74+
75+
.. code-block:: sql
76+
77+
CREATE INDEX IF NOT EXISTS documents_embedding_idx
78+
ON documents USING ivfflat (embedding vector_cosine_ops);
79+
80+
Configuration
81+
-------------
82+
83+
Basic Configuration
84+
~~~~~~~~~~~~~~~~~~~
85+
86+
.. code-block:: php
87+
88+
use Symfony\AI\Store\Bridge\Supabase\Store;
89+
use Symfony\Component\HttpClient\HttpClient;
90+
91+
$store = new Store(
92+
HttpClient::create(),
93+
'https://your-project.supabase.co',
94+
'your-anon-key',
95+
'documents', // table name
96+
'embedding', // vector field name
97+
768, // vector dimension (depending on your embedding model)
98+
'match_documents' // function name
99+
);
100+
101+
Bundle Configuration
102+
~~~~~~~~~~~~~~~~~~~~
103+
104+
.. code-block:: yaml
105+
106+
# config/packages/ai.yaml
107+
ai:
108+
store:
109+
supabase:
110+
my_supabase_store:
111+
url: 'https://your-project.supabase.co'
112+
api_key: '%env(SUPABASE_API_KEY)%'
113+
table: 'documents'
114+
vector_field: 'embedding'
115+
vector_dimension: 768
116+
function_name: 'match_documents'
117+
118+
Environment Variables
119+
~~~~~~~~~~~~~~~~~~~~~
120+
121+
.. code-block:: bash
122+
123+
# .env.local
124+
SUPABASE_URL=https://your-project.supabase.co
125+
SUPABASE_API_KEY=your-supabase-anon-key
126+
127+
Usage
128+
-----
129+
130+
Adding Documents
131+
~~~~~~~~~~~~~~~~
132+
133+
.. code-block:: php
134+
135+
use Symfony\AI\Platform\Vector\Vector;
136+
use Symfony\AI\Store\Document\Metadata;
137+
use Symfony\AI\Store\Document\VectorDocument;
138+
use Symfony\Component\Uid\Uuid;
139+
140+
$document = new VectorDocument(
141+
Uuid::v4(),
142+
new Vector([0.1, 0.2, 0.3, /* ... 768 dimensions */]),
143+
new Metadata(['title' => 'My Document', 'category' => 'example'])
144+
);
145+
146+
$store->add($document);
147+
148+
Querying Documents
149+
~~~~~~~~~~~~~~~~~~
150+
151+
.. code-block:: php
152+
153+
$queryVector = new Vector([0.1, 0.2, 0.3, /* ... 768 dimensions */]);
154+
155+
$results = $store->query($queryVector, [
156+
'max_items' => 10,
157+
'min_score' => 0.7
158+
]);
159+
160+
foreach ($results as $document) {
161+
echo "ID: " . $document->id . "\n";
162+
echo "Score: " . $document->score . "\n";
163+
echo "Metadata: " . json_encode($document->metadata->getArrayCopy()) . "\n";
164+
}
165+
166+
Customization
167+
-------------
168+
169+
You can customize the Supabase setup for different requirements:
170+
171+
Table Name
172+
~~~~~~~~~~
173+
174+
Change ``documents`` to your preferred table name in both the SQL setup and configuration.
175+
176+
Vector Field Name
177+
~~~~~~~~~~~~~~~~~
178+
179+
Change ``embedding`` to your preferred field name in both the SQL setup and configuration.
180+
181+
Vector Dimension
182+
~~~~~~~~~~~~~~~~
183+
184+
Change ``768`` to match your embedding model's dimensions in both the SQL setup and configuration.
185+
186+
Distance Metric
187+
~~~~~~~~~~~~~~~
188+
189+
* Cosine: ``<=>`` (default, recommended for most embeddings)
190+
* Euclidean: ``<->``
191+
* Inner Product: ``<#>``
192+
193+
Index Type
194+
~~~~~~~~~~
195+
196+
* ``ivfflat``: Good balance of speed and accuracy
197+
* ``hnsw``: Better for high-dimensional vectors (requires PostgreSQL 14+)
198+
199+
Limitations
200+
-----------
201+
202+
* Manual schema setup required (no automatic table creation)
203+
* Limited to Supabase's REST API capabilities
204+
* Requires pre-configured RPC functions for complex queries
205+
* Vector dimension must be consistent across all documents
206+
207+
Performance Considerations
208+
--------------------------
209+
210+
* Use appropriate index types based on your vector dimensions
211+
* Consider using ``hnsw`` indexes for high-dimensional vectors
212+
* Batch document insertions when possible (up to 200 documents per request)
213+
* Monitor your Supabase usage limits and quotas
214+
215+
Security Considerations
216+
-----------------------
217+
218+
* Use row-level security (RLS) policies if needed
219+
* Consider using service role keys for server-side operations
220+
* Validate vector dimensions in your application code
221+
* Implement proper error handling for API failures
222+
223+
.. _`pgvector`: https://github.com/pgvector/pgvector
224+
.. _`pgvector extension`: https://supabase.com/docs/guides/database/extensions/pgvector
225+
.. _`vector`: https://supabase.com/docs/guides/ai/vector-columns
226+
.. _`function`: https://supabase.com/docs/guides/database/functions

examples/.env

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,3 +156,11 @@ SCALEWAY_SECRET_KEY=
156156

157157
# For using DeepSeek
158158
DEEPSEEK_API_KEY=
159+
160+
# Supabase (store)
161+
SUPABASE_URL=
162+
SUPABASE_API_KEY=
163+
SUPABASE_TABLE=documents
164+
SUPABASE_VECTOR_FIELD=embedding
165+
SUPABASE_VECTOR_DIMENSION=768 # when using Ollama with nomic-embed-text
166+
SUPABASE_MATCH_FUNCTION=match_documents

examples/rag/supabase.php

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\AI\Agent\Agent;
13+
use Symfony\AI\Agent\Toolbox\AgentProcessor;
14+
use Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch;
15+
use Symfony\AI\Agent\Toolbox\Toolbox;
16+
use Symfony\AI\Fixtures\Movies;
17+
use Symfony\AI\Platform\Bridge\Ollama\PlatformFactory;
18+
use Symfony\AI\Platform\Message\Message;
19+
use Symfony\AI\Platform\Message\MessageBag;
20+
use Symfony\AI\Store\Bridge\Supabase\Store;
21+
use Symfony\AI\Store\Document\Loader\InMemoryLoader;
22+
use Symfony\AI\Store\Document\Metadata;
23+
use Symfony\AI\Store\Document\TextDocument;
24+
use Symfony\AI\Store\Document\Vectorizer;
25+
use Symfony\AI\Store\Indexer;
26+
use Symfony\Component\Uid\Uuid;
27+
28+
require_once dirname(__DIR__).'/bootstrap.php';
29+
30+
$store = new Store(
31+
httpClient: http_client(),
32+
url: env('SUPABASE_URL'),
33+
apiKey: env('SUPABASE_API_KEY'),
34+
table: env('SUPABASE_TABLE'),
35+
vectorFieldName: env('SUPABASE_VECTOR_FIELD'),
36+
vectorDimension: (int) env('SUPABASE_VECTOR_DIMENSION'),
37+
functionName: env('SUPABASE_MATCH_FUNCTION'),
38+
);
39+
40+
$documents = [];
41+
42+
foreach (Movies::all() as $movie) {
43+
$documents[] = new TextDocument(
44+
id: Uuid::v4(),
45+
content: 'Title: '.$movie['title'].\PHP_EOL.'Director: '.$movie['director'].\PHP_EOL.'Description: '.$movie['description'],
46+
metadata: new Metadata($movie),
47+
);
48+
}
49+
50+
$platform = PlatformFactory::create(env('OLLAMA_HOST_URL'), http_client());
51+
52+
$vectorizer = new Vectorizer($platform, env('OLLAMA_EMBEDDINGS'));
53+
$loader = new InMemoryLoader($documents);
54+
$indexer = new Indexer($loader, $vectorizer, $store, logger: logger());
55+
$indexer->index();
56+
57+
$similaritySearch = new SimilaritySearch($vectorizer, $store);
58+
$toolbox = new Toolbox([$similaritySearch], logger: logger());
59+
$processor = new AgentProcessor($toolbox);
60+
$agent = new Agent($platform, env('OLLAMA_LLM'), [$processor], [$processor]);
61+
62+
$messages = new MessageBag(
63+
Message::forSystem('Please answer all user questions only using SimilaritySearch function.'),
64+
Message::ofUser('Which movie fits the theme of technology?')
65+
);
66+
67+
$result = $agent->call($messages);
68+
69+
echo $result->getContent().\PHP_EOL;

src/ai-bundle/config/options.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,24 @@
647647
->end()
648648
->end()
649649
->end()
650+
->arrayNode('supabase')
651+
->useAttributeAsKey('name')
652+
->arrayPrototype()
653+
->children()
654+
->stringNode('http_client')
655+
->cannotBeEmpty()
656+
->defaultValue('http_client')
657+
->info('Service ID of the HTTP client to use')
658+
->end()
659+
->stringNode('url')->isRequired()->cannotBeEmpty()->end()
660+
->stringNode('api_key')->isRequired()->cannotBeEmpty()->end()
661+
->stringNode('table')->end()
662+
->stringNode('vector_field')->end()
663+
->integerNode('vector_dimension')->end()
664+
->stringNode('function_name')->end()
665+
->end()
666+
->end()
667+
->end()
650668
->arrayNode('typesense')
651669
->useAttributeAsKey('name')
652670
->arrayPrototype()

0 commit comments

Comments
 (0)