mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
updated realtime, create endpoint , resources, registers
This commit is contained in:
@@ -48,7 +48,8 @@ _APP_DB_PORT_DOCUMENTSDB=27017
|
||||
_APP_DB_ADAPTER_VECTORDB=postgresql
|
||||
_APP_DB_HOST_VECTORDB=postgresql
|
||||
_APP_DB_PORT_VECTORDB=5432
|
||||
OLLAMA_MODELS=embeddinggemma
|
||||
_APP_EMBEDDING_MODELS=embeddinggemma
|
||||
_APP_EMBEDDING_ENDPOINT='http://ollama:11434/api/embed'
|
||||
_APP_STORAGE_DEVICE=Local
|
||||
_APP_STORAGE_S3_ACCESS_KEY=
|
||||
_APP_STORAGE_S3_SECRET=
|
||||
|
||||
@@ -172,6 +172,7 @@ jobs:
|
||||
Databases/Legacy,
|
||||
Databases/TablesDB,
|
||||
Databases/DocumentsDB,
|
||||
Databases/VectorDB,
|
||||
Functions,
|
||||
FunctionsSchedule,
|
||||
GraphQL,
|
||||
|
||||
@@ -106,7 +106,6 @@ return [
|
||||
'$id' => ID::custom('embeddings'),
|
||||
'type' => Database::VAR_VECTOR,
|
||||
'required' => true,
|
||||
'size' => 128,
|
||||
'signed' => false,
|
||||
'array' => false,
|
||||
'filters' => [],
|
||||
|
||||
@@ -119,7 +119,7 @@ $register->set('pools', function () {
|
||||
'pass' => System::getEnv('_APP_DB_PASS', ''),
|
||||
'path' => System::getEnv('_APP_DB_SCHEMA', ''),
|
||||
]);
|
||||
$fallbackForVECTORDB = 'db_main=' . AppwriteURL::unparse([
|
||||
$fallbackForVectorDB = 'db_main=' . AppwriteURL::unparse([
|
||||
'scheme' => System::getEnv('_APP_DB_ADAPTER_VECTORDB', 'postgresql'),
|
||||
'host' => System::getEnv('_APP_DB_HOST_VECTORDB', 'postgresql'),
|
||||
'port' => System::getEnv('_APP_DB_PORT_VECTORDB', '5432'),
|
||||
@@ -156,7 +156,7 @@ $register->set('pools', function () {
|
||||
],
|
||||
'vectordb' => [
|
||||
'type' => 'database',
|
||||
'dsns' => System::getEnv('_APP_CONNECTIONS_DATABASE_VECTORDB', $fallbackForVECTORDB),
|
||||
'dsns' => System::getEnv('_APP_CONNECTIONS_DATABASE_VECTORDB', $fallbackForVectorDB),
|
||||
'multiple' => true,
|
||||
'schemes' => ['postgresql'],
|
||||
],
|
||||
@@ -400,6 +400,9 @@ $register->set('smtp', function () {
|
||||
$register->set('geodb', function () {
|
||||
return new Reader(__DIR__ . '/../assets/dbip/dbip-country-lite-2024-09.mmdb');
|
||||
});
|
||||
$register->set('embeddingAgent', function () {
|
||||
return System::getEnv('_APP_EMBEDDING_ENDPOINT', 'http://ollama:11434/api/embed');
|
||||
});
|
||||
$register->set('passwordsDictionary', function () {
|
||||
$content = \file_get_contents(__DIR__ . '/../assets/security/10k-common-passwords');
|
||||
$content = explode("\n", $content);
|
||||
|
||||
@@ -1170,9 +1170,8 @@ App::setResource('transactionState', function (Database $dbForProject, callable
|
||||
return new TransactionState($dbForProject, $getDatabasesDB);
|
||||
}, ['dbForProject', 'getDatabasesDB']);
|
||||
|
||||
App::setResource('embeddingAgent', function () {
|
||||
// TODO: ollama endpoint should be taken from env in cloud(for autoscaling)
|
||||
App::setResource('embeddingAgent', function ($register) {
|
||||
$adapter = new Ollama();
|
||||
$adapter->setEndpoint('http://ollama:11434/api/embed');
|
||||
$adapter->setEndpoint($register->get('embeddingAgent'));
|
||||
return new Agent($adapter);
|
||||
});
|
||||
}, ['register']);
|
||||
|
||||
+58
-56
@@ -276,6 +276,7 @@ services:
|
||||
volumes:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
- ./vendor:/usr/src/code/vendor
|
||||
depends_on:
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- postgresql
|
||||
@@ -751,6 +752,7 @@ services:
|
||||
- ./app:/usr/src/code/app
|
||||
- ./src:/usr/src/code/src
|
||||
- ./tests:/usr/src/code/tests
|
||||
- ./vendor:/usr/src/code/vendor
|
||||
depends_on:
|
||||
- ${_APP_DB_HOST:-mongodb}
|
||||
- postgresql
|
||||
@@ -1125,55 +1127,55 @@ services:
|
||||
- MARIADB_AUTO_UPGRADE=1
|
||||
command: "mysqld --innodb-flush-method=fsync"
|
||||
|
||||
# mongodb:
|
||||
# image: mongo:8.0.10
|
||||
# container_name: appwrite-mongodb
|
||||
# <<: *x-logging
|
||||
# networks:
|
||||
# - appwrite
|
||||
# volumes:
|
||||
# - appwrite-mongodb:/data/db
|
||||
# - appwrite-mongodb-keyfile:/data/keyfile
|
||||
# - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
|
||||
# - ./mongo-entrypoint.sh:/mongo-entrypoint.sh:ro
|
||||
# ports:
|
||||
# - "27017:27017"
|
||||
# environment:
|
||||
# - MONGO_INITDB_ROOT_USERNAME=root
|
||||
# - MONGO_INITDB_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
# - MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA}
|
||||
# - MONGO_INITDB_USERNAME=${_APP_DB_USER}
|
||||
# - MONGO_INITDB_PASSWORD=${_APP_DB_PASS}
|
||||
# entrypoint: ["/bin/bash", "/mongo-entrypoint.sh"]
|
||||
# healthcheck:
|
||||
# test: |
|
||||
# bash -c "
|
||||
# if mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval 'rs.status().ok' 2>/dev/null | grep -q 1; then
|
||||
# exit 0
|
||||
# else
|
||||
# mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval \"
|
||||
# rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'appwrite-mongodb:27017'}]})
|
||||
# \" 2>/dev/null || exit 1
|
||||
# fi
|
||||
# "
|
||||
# interval: 10s
|
||||
# timeout: 10s
|
||||
# retries: 10
|
||||
# start_period: 30s
|
||||
mongodb:
|
||||
image: mongo:8.0.10
|
||||
container_name: appwrite-mongodb
|
||||
<<: *x-logging
|
||||
networks:
|
||||
- appwrite
|
||||
volumes:
|
||||
- appwrite-mongodb:/data/db
|
||||
- appwrite-mongodb-keyfile:/data/keyfile
|
||||
- ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro
|
||||
- ./mongo-entrypoint.sh:/mongo-entrypoint.sh:ro
|
||||
ports:
|
||||
- "27017:27017"
|
||||
environment:
|
||||
- MONGO_INITDB_ROOT_USERNAME=root
|
||||
- MONGO_INITDB_ROOT_PASSWORD=${_APP_DB_ROOT_PASS}
|
||||
- MONGO_INITDB_DATABASE=${_APP_DB_SCHEMA}
|
||||
- MONGO_INITDB_USERNAME=${_APP_DB_USER}
|
||||
- MONGO_INITDB_PASSWORD=${_APP_DB_PASS}
|
||||
entrypoint: ["/bin/bash", "/mongo-entrypoint.sh"]
|
||||
healthcheck:
|
||||
test: |
|
||||
bash -c "
|
||||
if mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval 'rs.status().ok' 2>/dev/null | grep -q 1; then
|
||||
exit 0
|
||||
else
|
||||
mongosh -u root -p ${_APP_DB_ROOT_PASS} --authenticationDatabase admin --quiet --eval \"
|
||||
rs.initiate({_id: 'rs0', members: [{_id: 0, host: 'appwrite-mongodb:27017'}]})
|
||||
\" 2>/dev/null || exit 1
|
||||
fi
|
||||
"
|
||||
interval: 10s
|
||||
timeout: 10s
|
||||
retries: 10
|
||||
start_period: 30s
|
||||
|
||||
# appwrite-mongo-express:
|
||||
# image: mongo-express
|
||||
# container_name: appwrite-mongo-express
|
||||
# networks:
|
||||
# - appwrite
|
||||
# ports:
|
||||
# - "8082:8081"
|
||||
# environment:
|
||||
# ME_CONFIG_MONGODB_URL: "mongodb://root:${_APP_DB_ROOT_PASS}@appwrite-mongodb:27017/?replicaSet=rs0&directConnection=true"
|
||||
# ME_CONFIG_BASICAUTH_USERNAME: ${_APP_DB_USER}
|
||||
# ME_CONFIG_BASICAUTH_PASSWORD: ${_APP_DB_PASS}
|
||||
# depends_on:
|
||||
# - mongodb
|
||||
appwrite-mongo-express:
|
||||
image: mongo-express
|
||||
container_name: appwrite-mongo-express
|
||||
networks:
|
||||
- appwrite
|
||||
ports:
|
||||
- "8082:8081"
|
||||
environment:
|
||||
ME_CONFIG_MONGODB_URL: "mongodb://root:${_APP_DB_ROOT_PASS}@appwrite-mongodb:27017/?replicaSet=rs0&directConnection=true"
|
||||
ME_CONFIG_BASICAUTH_USERNAME: ${_APP_DB_USER}
|
||||
ME_CONFIG_BASICAUTH_PASSWORD: ${_APP_DB_PASS}
|
||||
depends_on:
|
||||
- mongodb
|
||||
|
||||
|
||||
postgresql:
|
||||
@@ -1198,17 +1200,17 @@ services:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ollama.dockerfile
|
||||
args:
|
||||
MODELS: ${_APP_EMBEDDING_MODELS:-embeddinggemma}
|
||||
# duration to keep model in memory
|
||||
OLLAMA_KEEP_ALIVE: 24h
|
||||
container_name: ollama
|
||||
ports:
|
||||
- "11434:11434"
|
||||
restart: unless-stopped
|
||||
# persistent for caching models across restarts and preloading
|
||||
volumes:
|
||||
- ollama_models:/root/.ollama
|
||||
environment:
|
||||
- MODELS=${OLLAMA_MODELS:-embeddinggemma}
|
||||
# duration to keep model in memory
|
||||
- OLLAMA_KEEP_ALIVE=24h
|
||||
- _APP_EMBEDDING_MODELS:/root/.ollama
|
||||
networks:
|
||||
- appwrite
|
||||
|
||||
@@ -1310,8 +1312,8 @@ networks:
|
||||
|
||||
volumes:
|
||||
appwrite-mariadb:
|
||||
# appwrite-mongodb:
|
||||
# appwrite-mongodb-keyfile:
|
||||
appwrite-mongodb:
|
||||
appwrite-mongodb-keyfile:
|
||||
appwrite-postgresql:
|
||||
appwrite-redis:
|
||||
appwrite-cache:
|
||||
@@ -1322,4 +1324,4 @@ volumes:
|
||||
appwrite-sites:
|
||||
appwrite-builds:
|
||||
appwrite-config:
|
||||
ollama_models:
|
||||
_APP_EMBEDDING_MODELS:
|
||||
+5
-3
@@ -1,8 +1,10 @@
|
||||
FROM ollama/ollama:latest
|
||||
FROM ollama/ollama:0.12.7
|
||||
|
||||
# Preload specific models
|
||||
ENV MODELS="embeddinggemma"
|
||||
ENV OLLAMA_KEEP_ALIVE=24h
|
||||
ARG MODELS
|
||||
# needed to set in the environment
|
||||
ARG OLLAMA_KEEP_ALIVE
|
||||
ENV OLLAMA_KEEP_ALIVE=${OLLAMA_KEEP_ALIVE:-24h}
|
||||
|
||||
# Pre-pull models at build time for Docker layer caching
|
||||
RUN ollama serve & \
|
||||
|
||||
@@ -684,8 +684,10 @@ class Event
|
||||
];
|
||||
break;
|
||||
case 'documentsdb':
|
||||
case 'vectordb':
|
||||
// sending the type itself(eg: documentsdb, vectordb)
|
||||
$eventMap = [
|
||||
'databases' => 'documentsdb'
|
||||
'databases' => $database->getAttribute('type')
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -299,6 +299,7 @@ class Realtime extends MessagingAdapter
|
||||
case 'databases':
|
||||
case 'tablesdb':
|
||||
case 'documentsdb':
|
||||
case 'vectordb':
|
||||
$resource = $parts[4] ?? '';
|
||||
if (in_array($resource, ['columns', 'attributes', 'indexes'])) {
|
||||
$channels[] = 'console';
|
||||
@@ -434,6 +435,7 @@ class Realtime extends MessagingAdapter
|
||||
break;
|
||||
|
||||
case 'documentsdb':
|
||||
case 'vectordb':
|
||||
$channels[] = 'documents';
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents";
|
||||
$channels[] = "{$basePrefix}.{$databaseId}.collections.{$resourceId}.documents.{$payloadId}";
|
||||
|
||||
@@ -140,22 +140,11 @@ class Create extends CollectionAction
|
||||
attributes:$attributes,
|
||||
indexes:$indexes
|
||||
);
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception($this->getDuplicateException());
|
||||
} catch (IndexException) {
|
||||
throw new Exception($this->getInvalidIndexException());
|
||||
} catch (LimitException) {
|
||||
throw new Exception($this->getLimitException());
|
||||
}
|
||||
|
||||
// Create attribute metadata documents in the attributes table
|
||||
// This is necessary so that indexes can find the attributes when they're created
|
||||
foreach ($collections['defaultAttributes'] as $attributeConfig) {
|
||||
$key = \is_string($attributeConfig['$id']) ? $attributeConfig['$id'] : (string)$attributeConfig['$id'];
|
||||
$size = $key === 'embeddings' ? $dimensions : ($attributeConfig['size'] ?? 0);
|
||||
|
||||
try {
|
||||
$attributeDoc = new Document([
|
||||
// Create attribute metadata documents in the attributes table
|
||||
// This is necessary so that indexes can find the attributes when they're created
|
||||
$attributeDocs = array_map(function ($attributeConfig) use ($database, $collection, $databaseId, $collectionId, $dimensions) {
|
||||
$key = \is_string($attributeConfig['$id']) ? $attributeConfig['$id'] : (string) $attributeConfig['$id'];
|
||||
return new Document([
|
||||
'$id' => ID::custom($database->getSequence() . '_' . $collection->getSequence() . '_' . $key),
|
||||
'key' => $key,
|
||||
'databaseInternalId' => $database->getSequence(),
|
||||
@@ -164,7 +153,7 @@ class Create extends CollectionAction
|
||||
'collectionId' => $collectionId,
|
||||
'type' => $attributeConfig['type'],
|
||||
'status' => 'available',
|
||||
'size' => $size,
|
||||
'size' => $dimensions,
|
||||
'required' => $attributeConfig['required'] ?? false,
|
||||
'signed' => $attributeConfig['signed'] ?? false,
|
||||
'default' => $attributeConfig['default'] ?? null,
|
||||
@@ -174,11 +163,14 @@ class Create extends CollectionAction
|
||||
'filters' => $attributeConfig['filters'] ?? [],
|
||||
'options' => $attributeConfig['options'] ?? [],
|
||||
]);
|
||||
|
||||
$dbForProject->createDocument('attributes', $attributeDoc);
|
||||
} catch (DuplicateException) {
|
||||
// Attribute already exists, skip
|
||||
}
|
||||
}, $collections['defaultAttributes']);
|
||||
$dbForProject->createDocuments('attributes', $attributeDocs);
|
||||
} catch (DuplicateException) {
|
||||
throw new Exception($this->getDuplicateException());
|
||||
} catch (IndexException) {
|
||||
throw new Exception($this->getInvalidIndexException());
|
||||
} catch (LimitException) {
|
||||
throw new Exception($this->getLimitException());
|
||||
}
|
||||
|
||||
$queueForEvents
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ class Create extends CreateDocumentAction
|
||||
{
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'createVectorDBDocument';
|
||||
return 'createTextEmbedding';
|
||||
}
|
||||
|
||||
protected function getResponseModel(): string
|
||||
@@ -144,7 +144,7 @@ class Create extends CreateDocumentAction
|
||||
}
|
||||
|
||||
$list = new Document([
|
||||
'embeddings' => array_map(fn($d) => $d, $results),
|
||||
'embeddings' => array_map(fn ($d) => $d, $results),
|
||||
'total' => \count($results),
|
||||
]);
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Bulk
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Create as CreateDocument;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Delete as DeleteDocument;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Get as GetDocument;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Text\Create as CreateTextEmbeddings;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Update as UpdateDocument;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Upsert as UpsertDocument;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\XList as ListDocuments;
|
||||
@@ -29,7 +30,6 @@ use Appwrite\Platform\Modules\Databases\Http\VectorDB\Update as UpdateVectorData
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Usage\Get as GetVectorDatabaseUsage;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Usage\XList as ListVectorDatabaseUsage;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\XList as ListVectorDatabases;
|
||||
use Appwrite\Platform\Modules\Databases\Http\VectorDB\Collections\Documents\Text\Create as CreateTextEmbeddings;
|
||||
use Utopia\Platform\Service;
|
||||
|
||||
class VectorDB extends Base
|
||||
@@ -87,7 +87,8 @@ class VectorDB extends Base
|
||||
$service->addAction(DeleteDocuments::getName(), new DeleteDocuments());
|
||||
}
|
||||
|
||||
private function registerEmbeddingActions(Service $service):void{
|
||||
$service->addAction(CreateTextEmbeddings::getName(),new CreateTextEmbeddings());
|
||||
private function registerEmbeddingActions(Service $service): void
|
||||
{
|
||||
$service->addAction(CreateTextEmbeddings::getName(), new CreateTextEmbeddings());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ use Appwrite\Utopia\Response\Model\DetectionFramework;
|
||||
use Appwrite\Utopia\Response\Model\DetectionRuntime;
|
||||
use Appwrite\Utopia\Response\Model\DevKey;
|
||||
use Appwrite\Utopia\Response\Model\Document as ModelDocument;
|
||||
use Appwrite\Utopia\Response\Model\Embedding;
|
||||
use Appwrite\Utopia\Response\Model\Error;
|
||||
use Appwrite\Utopia\Response\Model\ErrorDev;
|
||||
use Appwrite\Utopia\Response\Model\Execution;
|
||||
@@ -144,6 +145,7 @@ use Appwrite\Utopia\Response\Model\UsageUsers;
|
||||
use Appwrite\Utopia\Response\Model\User;
|
||||
use Appwrite\Utopia\Response\Model\Variable;
|
||||
use Appwrite\Utopia\Response\Model\VcsContent;
|
||||
use Appwrite\Utopia\Response\Model\VectorDBCollection;
|
||||
use Appwrite\Utopia\Response\Model\Webhook;
|
||||
use Exception;
|
||||
use JsonException;
|
||||
@@ -500,10 +502,10 @@ class Response extends SwooleResponse
|
||||
->setModel(new BaseList('Embedding list', self::MODEL_EMBEDDING_LIST, 'embeddings', self::MODEL_EMBEDDING))
|
||||
// Entities
|
||||
->setModel(new Database())
|
||||
->setModel(new \Appwrite\Utopia\Response\Model\Embedding())
|
||||
->setModel(new Embedding())
|
||||
// Collection API Models
|
||||
->setModel(new Collection())
|
||||
->setModel(new \Appwrite\Utopia\Response\Model\VectorDBCollection())
|
||||
->setModel(new VectorDBCollection())
|
||||
->setModel(new Attribute())
|
||||
->setModel(new AttributeList())
|
||||
->setModel(new AttributeString())
|
||||
|
||||
@@ -4299,4 +4299,192 @@ class RealtimeCustomClientTest extends Scope
|
||||
|
||||
$client->close();
|
||||
}
|
||||
|
||||
public function testChannelVectorDB()
|
||||
{
|
||||
$user = $this->getUser();
|
||||
$session = $user['session'] ?? '';
|
||||
$projectId = $this->getProject()['$id'];
|
||||
|
||||
$client = $this->getWebsocket(['documents', 'collections'], [
|
||||
'origin' => 'http://localhost',
|
||||
'cookie' => 'a_session_' . $projectId . '=' . $session
|
||||
]);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('connected', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertCount(2, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains('collections', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['user']);
|
||||
$this->assertEquals($user['$id'], $response['data']['user']['$id']);
|
||||
|
||||
// Create VectorDB database
|
||||
$database = $this->client->call(Client::METHOD_POST, '/vectordb', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'databaseId' => ID::unique(),
|
||||
'name' => 'Actors VDB',
|
||||
]);
|
||||
|
||||
$databaseId = $database['body']['$id'];
|
||||
|
||||
// Create collection in VectorDB
|
||||
$actors = $this->client->call(Client::METHOD_POST, '/vectordb/' . $databaseId . '/collections', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'collectionId' => ID::unique(),
|
||||
'name' => 'Actors',
|
||||
'permissions' => [
|
||||
Permission::create(Role::user($this->getUser()['$id'])),
|
||||
],
|
||||
'documentSecurity' => true,
|
||||
'dimensions' => 3,
|
||||
]);
|
||||
|
||||
$actorsId = $actors['body']['$id'];
|
||||
|
||||
// Create document in VectorDB
|
||||
$document = $this->client->call(Client::METHOD_POST, '/vectordb/' . $databaseId . '/collections/' . $actorsId . '/documents', array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'documentId' => ID::unique(),
|
||||
'data' => [
|
||||
'embeddings' => [1.0, 0.0, 0.0],
|
||||
'metadata' => ['name' => 'Chris Evans']
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
|
||||
$documentId = $document['body']['$id'];
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
// vectordb channels should include 3 items like documentsdb
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertContains('documents', $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertIsArray($response['data']['payload']['embeddings']);
|
||||
$this->assertCount(3, $response['data']['payload']['embeddings']);
|
||||
$this->assertEquals('Chris Evans', $response['data']['payload']['metadata']['name']);
|
||||
|
||||
// Update document
|
||||
$this->client->call(Client::METHOD_PATCH, '/vectordb/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'data' => [
|
||||
'embeddings' => [0.0, 1.0, 0.0],
|
||||
'metadata' => ['name' => 'Chris Evans 2']
|
||||
],
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertIsArray($response['data']['payload']['embeddings']);
|
||||
$this->assertEquals('Chris Evans 2', $response['data']['payload']['metadata']['name']);
|
||||
|
||||
// Delete document
|
||||
$this->client->call(Client::METHOD_DELETE, '/vectordb/' . $databaseId . '/collections/' . $actorsId . '/documents/' . $documentId, array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()));
|
||||
|
||||
$response = json_decode($client->receive(), true);
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $documentId, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents', $response['data']['channels']);
|
||||
|
||||
// Bulk create two documents
|
||||
$this->client->call(Client::METHOD_POST, "/vectordb/{$databaseId}/collections/{$actorsId}/documents", array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
'x-appwrite-key' => $this->getProject()['apiKey']
|
||||
]), [
|
||||
'documents' => [
|
||||
[
|
||||
'embeddings' => [1.0, 0.0, 0.0],
|
||||
'metadata' => ['name' => 'Robert Downey Jr.'],
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
],
|
||||
[
|
||||
'embeddings' => [0.0, 1.0, 0.0],
|
||||
'metadata' => ['name' => 'Scarlett Johansson'],
|
||||
'$permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
// Receive first bulk document event
|
||||
$response = json_decode($client->receive(), true);
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $response['data']['payload']['$id'] . '.create', $response['data']['events']);
|
||||
$this->assertContains('vectordb.*.collections.*.documents.*.create', $response['data']['events']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.*.documents.*.create', $response['data']['events']);
|
||||
$this->assertContains('vectordb.*.collections.' . $actorsId . '.documents.*.create', $response['data']['events']);
|
||||
$this->assertNotEmpty($response['data']['payload']);
|
||||
$this->assertIsArray($response['data']['payload']);
|
||||
|
||||
// Receive second bulk document event
|
||||
$response = json_decode($client->receive(), true);
|
||||
$this->assertArrayHasKey('type', $response);
|
||||
$this->assertArrayHasKey('data', $response);
|
||||
$this->assertEquals('event', $response['type']);
|
||||
$this->assertNotEmpty($response['data']);
|
||||
$this->assertArrayHasKey('timestamp', $response['data']);
|
||||
$this->assertCount(3, $response['data']['channels']);
|
||||
$this->assertContains('vectordb.' . $databaseId . '.collections.' . $actorsId . '.documents.' . $response['data']['payload']['$id'] . '.create', $response['data']['events']);
|
||||
|
||||
$client->close();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user