From ff214da0b435c58cdb0bc93141c96b5ac19323b4 Mon Sep 17 00:00:00 2001 From: emrgnt-cmplxty <68796651+emrgnt-cmplxty@users.noreply.github.com> Date: Tue, 17 Sep 2024 21:45:32 -0700 Subject: [PATCH] groups to collections (#1191) * checkin * collection to groups * Fix bug in deletion (#1190) * fix pr (#1192) * Feature/fix collection to groups (#1193) * fix pr * collect and raise kg extraction errors * cleanup --------- Co-authored-by: Nolan Tremelling <34580718+NolanTrem@users.noreply.github.com> --- .env.example | 2 +- .github/workflows/py-ci-cd.yml | 2 +- .../r2r-js-sdk-integration-tests.yml | 2 +- .../endpoint/add_user_to_collection.mdx | 4 + .../endpoint/add_user_to_group.mdx | 4 - .../endpoint/assign_document_to_group.mdx | 2 +- .../endpoint/collections_overview.mdx | 4 + .../endpoint/create_collection.mdx | 4 + docs/api-reference/endpoint/create_group.mdx | 4 - .../endpoint/delete_collection.mdx | 4 + docs/api-reference/endpoint/delete_group.mdx | 4 - .../api-reference/endpoint/get_collection.mdx | 4 + .../endpoint/get_collections_for_user.mdx | 4 + .../endpoint/get_document_collections.mdx | 4 + .../endpoint/get_document_groups.mdx | 4 - docs/api-reference/endpoint/get_group.mdx | 4 - .../endpoint/get_groups_for_user.mdx | 4 - .../endpoint/get_users_in_collection.mdx | 4 + .../endpoint/get_users_in_group.mdx | 4 - .../endpoint/groups_overview.mdx | 4 - .../endpoint/list_collections.mdx | 4 + docs/api-reference/endpoint/list_groups.mdx | 4 - .../remove_document_from_collection.mdx | 4 + .../endpoint/remove_document_from_group.mdx | 4 - .../endpoint/remove_user_from_collection.mdx | 4 + .../endpoint/remove_user_from_group.mdx | 4 - .../endpoint/update_collection.mdx | 4 + docs/api-reference/endpoint/update_group.mdx | 4 - docs/api-reference/openapi.json | 2 +- docs/cookbooks/collections.mdx | 263 ++++++++++++++++++ docs/cookbooks/graphrag.mdx | 4 +- docs/cookbooks/groups.mdx | 229 --------------- docs/cookbooks/user-auth.mdx | 4 +- docs/cookbooks/walkthrough.mdx | 8 +- docs/documentation/configuration/postgres.mdx | 2 +- docs/documentation/configuration/rag.mdx | 2 +- .../configuration/retrieval/vector-search.mdx | 4 +- .../deep-dive/providers/auth.mdx | 2 +- .../deep-dive/providers/database.mdx | 2 +- docs/documentation/deployment/azure.mdx | 2 +- .../troubleshooting/vector_store_issues.mdx | 2 +- .../installation/local-system.mdx | 4 +- docs/documentation/js-sdk/auth.mdx | 2 +- docs/documentation/js-sdk/retrieval.mdx | 4 +- docs/documentation/python-sdk/auth.mdx | 2 +- .../{groups.mdx => collections.mdx} | 168 +++++------ docs/documentation/python-sdk/ingestion.mdx | 2 +- docs/documentation/python-sdk/retrieval.mdx | 8 +- docs/documentation/quickstart.mdx | 2 +- docs/introduction.mdx | 2 +- docs/mint.json | 32 +-- go/sdk/pkg/sdk/management.go | 38 +-- go/sdk/pkg/sdk/retrieval.go | 4 +- js/sdk/src/models.tsx | 2 +- js/sdk/src/r2rClient.ts | 184 ++++++------ py/README.md | 2 +- py/cli/commands/ingestion.py | 2 - py/cli/commands/retrieval.py | 4 +- py/cli/utils/docker_utils.py | 2 +- py/compose.neo4j.yaml | 2 +- py/compose.yaml | 2 +- py/core/base/abstractions/document.py | 10 +- py/core/base/abstractions/search.py | 14 +- py/core/base/abstractions/user.py | 2 +- py/core/base/abstractions/vector.py | 4 +- py/core/base/api/models/__init__.py | 12 +- py/core/base/api/models/auth/responses.py | 2 +- .../base/api/models/management/responses.py | 14 +- py/core/examples/data/aristotle_v2.txt | 19 -- .../examples/scripts/run_group_workflow.py | 155 ++++++----- py/core/main/api/base_router.py | 2 - py/core/main/api/ingestion_router.py | 11 +- py/core/main/api/management_router.py | 211 +++++++------- py/core/main/api/retrieval_router.py | 38 ++- py/core/main/hatchet/restructure_workflow.py | 21 +- py/core/main/services/auth_service.py | 10 +- py/core/main/services/ingestion_service.py | 4 +- py/core/main/services/management_service.py | 218 ++++++++++----- py/core/pipes/ingestion/chunking_pipe.py | 2 +- py/core/pipes/ingestion/embedding_pipe.py | 4 +- py/core/pipes/kg/extraction.py | 23 +- py/core/pipes/kg/storage.py | 19 +- py/core/pipes/other/web_search_pipe.py | 2 +- py/core/pipes/retrieval/streaming_rag_pipe.py | 17 +- py/core/providers/auth/r2r_auth.py | 3 +- .../database/{group.py => collection.py} | 198 ++++++------- py/core/providers/database/document.py | 28 +- py/core/providers/database/postgres.py | 10 +- py/core/providers/database/relational.py | 5 +- py/core/providers/database/user.py | 88 +++--- .../providers/database/vecs/adapter/noop.py | 4 +- py/core/providers/database/vecs/collection.py | 22 +- py/core/providers/database/vector.py | 72 ++--- py/core/providers/kg/neo4j/provider.py | 2 - py/core/providers/orchestration/hatchet.py | 4 +- py/core/providers/parsing/r2r_parsing.py | 2 +- .../providers/parsing/unstructured_parsing.py | 2 +- py/r2r/__init__.py | 16 +- py/sdk/client.py | 8 +- py/sdk/management.py | 192 +++++++------ py/sdk/models.py | 18 +- 101 files changed, 1387 insertions(+), 1199 deletions(-) create mode 100644 docs/api-reference/endpoint/add_user_to_collection.mdx delete mode 100644 docs/api-reference/endpoint/add_user_to_group.mdx create mode 100644 docs/api-reference/endpoint/collections_overview.mdx create mode 100644 docs/api-reference/endpoint/create_collection.mdx delete mode 100644 docs/api-reference/endpoint/create_group.mdx create mode 100644 docs/api-reference/endpoint/delete_collection.mdx delete mode 100644 docs/api-reference/endpoint/delete_group.mdx create mode 100644 docs/api-reference/endpoint/get_collection.mdx create mode 100644 docs/api-reference/endpoint/get_collections_for_user.mdx create mode 100644 docs/api-reference/endpoint/get_document_collections.mdx delete mode 100644 docs/api-reference/endpoint/get_document_groups.mdx delete mode 100644 docs/api-reference/endpoint/get_group.mdx delete mode 100644 docs/api-reference/endpoint/get_groups_for_user.mdx create mode 100644 docs/api-reference/endpoint/get_users_in_collection.mdx delete mode 100644 docs/api-reference/endpoint/get_users_in_group.mdx delete mode 100644 docs/api-reference/endpoint/groups_overview.mdx create mode 100644 docs/api-reference/endpoint/list_collections.mdx delete mode 100644 docs/api-reference/endpoint/list_groups.mdx create mode 100644 docs/api-reference/endpoint/remove_document_from_collection.mdx delete mode 100644 docs/api-reference/endpoint/remove_document_from_group.mdx create mode 100644 docs/api-reference/endpoint/remove_user_from_collection.mdx delete mode 100644 docs/api-reference/endpoint/remove_user_from_group.mdx create mode 100644 docs/api-reference/endpoint/update_collection.mdx delete mode 100644 docs/api-reference/endpoint/update_group.mdx create mode 100644 docs/cookbooks/collections.mdx delete mode 100644 docs/cookbooks/groups.mdx rename docs/documentation/python-sdk/{groups.mdx => collections.mdx} (53%) rename py/core/providers/database/{group.py => collection.py} (69%) diff --git a/.env.example b/.env.example index 1a4afa661..5667c46c0 100644 --- a/.env.example +++ b/.env.example @@ -11,7 +11,7 @@ export POSTGRES_PASSWORD=your_password export POSTGRES_HOST=your_host export POSTGRES_PORT=your_port export POSTGRES_DBNAME=your_db -export POSTGRES_VECS_COLLECTION=your_vecs_collection +export POSTGRES_PROJECT_NAME=your_vecs_collection # Environment variables for KG provider (currently only Neo4j) # export NEO4J_USER=YOUR_NEO4J_USER diff --git a/.github/workflows/py-ci-cd.yml b/.github/workflows/py-ci-cd.yml index a0b77244b..5ec11d497 100644 --- a/.github/workflows/py-ci-cd.yml +++ b/.github/workflows/py-ci-cd.yml @@ -51,7 +51,7 @@ jobs: POSTGRES_PORT: ${{ secrets.POSTGRES_PORT }} POSTGRES_USER: ${{ secrets.POSTGRES_USER }} POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} - POSTGRES_VECS_COLLECTION: ${{ secrets.POSTGRES_VECS_COLLECTION }} + POSTGRES_PROJECT_NAME: ${{ secrets.POSTGRES_PROJECT_NAME }} steps: - name: Checkout code diff --git a/.github/workflows/r2r-js-sdk-integration-tests.yml b/.github/workflows/r2r-js-sdk-integration-tests.yml index 41d41167e..0a33dbb93 100644 --- a/.github/workflows/r2r-js-sdk-integration-tests.yml +++ b/.github/workflows/r2r-js-sdk-integration-tests.yml @@ -38,7 +38,7 @@ jobs: POSTGRES_PASSWORD: ${{ secrets.POSTGRES_PASSWORD }} POSTGRES_PORT: ${{ secrets.POSTGRES_PORT }} POSTGRES_DBNAME: ${{ secrets.POSTGRES_DBNAME }} - POSTGRES_VECS_COLLECTION: ${{ secrets.POSTGRES_VECS_COLLECTION }} + POSTGRES_PROJECT_NAME: ${{ secrets.POSTGRES_PROJECT_NAME }} OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | r2r serve --port=7272 > r2r_server.log 2>&1 & diff --git a/docs/api-reference/endpoint/add_user_to_collection.mdx b/docs/api-reference/endpoint/add_user_to_collection.mdx new file mode 100644 index 000000000..0453db573 --- /dev/null +++ b/docs/api-reference/endpoint/add_user_to_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Add User to Collection' +openapi: 'POST /v2/add_user_to_collection' +--- diff --git a/docs/api-reference/endpoint/add_user_to_group.mdx b/docs/api-reference/endpoint/add_user_to_group.mdx deleted file mode 100644 index 670dfa29a..000000000 --- a/docs/api-reference/endpoint/add_user_to_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Add User to Group' -openapi: 'POST /v2/add_user_to_group' ---- diff --git a/docs/api-reference/endpoint/assign_document_to_group.mdx b/docs/api-reference/endpoint/assign_document_to_group.mdx index a48115001..d3d4d561d 100644 --- a/docs/api-reference/endpoint/assign_document_to_group.mdx +++ b/docs/api-reference/endpoint/assign_document_to_group.mdx @@ -1,4 +1,4 @@ --- title: 'Assign Document to Group' -openapi: 'POST /v2/assign_document_to_group' +openapi: 'POST /v2/assign_document_to_collection' --- diff --git a/docs/api-reference/endpoint/collections_overview.mdx b/docs/api-reference/endpoint/collections_overview.mdx new file mode 100644 index 000000000..e517b654b --- /dev/null +++ b/docs/api-reference/endpoint/collections_overview.mdx @@ -0,0 +1,4 @@ +--- +title: 'Groups Overview' +openapi: 'GET /v2/collections_overview' +--- diff --git a/docs/api-reference/endpoint/create_collection.mdx b/docs/api-reference/endpoint/create_collection.mdx new file mode 100644 index 000000000..731d46bad --- /dev/null +++ b/docs/api-reference/endpoint/create_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Create Collection' +openapi: 'POST /v2/create_collection' +--- diff --git a/docs/api-reference/endpoint/create_group.mdx b/docs/api-reference/endpoint/create_group.mdx deleted file mode 100644 index d55060487..000000000 --- a/docs/api-reference/endpoint/create_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Create Group' -openapi: 'POST /v2/create_group' ---- diff --git a/docs/api-reference/endpoint/delete_collection.mdx b/docs/api-reference/endpoint/delete_collection.mdx new file mode 100644 index 000000000..6af466930 --- /dev/null +++ b/docs/api-reference/endpoint/delete_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Delete Collection' +openapi: 'DELETE /v2/delete_collection/{collection_id}' +--- diff --git a/docs/api-reference/endpoint/delete_group.mdx b/docs/api-reference/endpoint/delete_group.mdx deleted file mode 100644 index 7b061952e..000000000 --- a/docs/api-reference/endpoint/delete_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Delete Group' -openapi: 'DELETE /v2/delete_group/{group_id}' ---- diff --git a/docs/api-reference/endpoint/get_collection.mdx b/docs/api-reference/endpoint/get_collection.mdx new file mode 100644 index 000000000..a113fbba7 --- /dev/null +++ b/docs/api-reference/endpoint/get_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Collection' +openapi: 'GET /v2/get_collection/{collection_id}' +--- diff --git a/docs/api-reference/endpoint/get_collections_for_user.mdx b/docs/api-reference/endpoint/get_collections_for_user.mdx new file mode 100644 index 000000000..b18c27042 --- /dev/null +++ b/docs/api-reference/endpoint/get_collections_for_user.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Collections for User' +openapi: 'GET /v2/get_collections_for_user/{user_id}' +--- diff --git a/docs/api-reference/endpoint/get_document_collections.mdx b/docs/api-reference/endpoint/get_document_collections.mdx new file mode 100644 index 000000000..97854297e --- /dev/null +++ b/docs/api-reference/endpoint/get_document_collections.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Document Collections' +openapi: 'GET /v2/get_document_collections/{document_id}' +--- diff --git a/docs/api-reference/endpoint/get_document_groups.mdx b/docs/api-reference/endpoint/get_document_groups.mdx deleted file mode 100644 index 3c2c7af9f..000000000 --- a/docs/api-reference/endpoint/get_document_groups.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Document Groups' -openapi: 'GET /v2/get_document_groups/{document_id}' ---- diff --git a/docs/api-reference/endpoint/get_group.mdx b/docs/api-reference/endpoint/get_group.mdx deleted file mode 100644 index c60acfaa9..000000000 --- a/docs/api-reference/endpoint/get_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Group' -openapi: 'GET /v2/get_group/{group_id}' ---- diff --git a/docs/api-reference/endpoint/get_groups_for_user.mdx b/docs/api-reference/endpoint/get_groups_for_user.mdx deleted file mode 100644 index dcef56e83..000000000 --- a/docs/api-reference/endpoint/get_groups_for_user.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Groups for User' -openapi: 'GET /v2/get_groups_for_user/{user_id}' ---- diff --git a/docs/api-reference/endpoint/get_users_in_collection.mdx b/docs/api-reference/endpoint/get_users_in_collection.mdx new file mode 100644 index 000000000..6624b44ef --- /dev/null +++ b/docs/api-reference/endpoint/get_users_in_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Get Users in Collection' +openapi: 'GET /v2/get_users_in_collection/{collection_id}/{offset}/{limit}' +--- diff --git a/docs/api-reference/endpoint/get_users_in_group.mdx b/docs/api-reference/endpoint/get_users_in_group.mdx deleted file mode 100644 index 8cf910c3a..000000000 --- a/docs/api-reference/endpoint/get_users_in_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Get Users in Group' -openapi: 'GET /v2/get_users_in_group/{group_id}/{offset}/{limit}' ---- diff --git a/docs/api-reference/endpoint/groups_overview.mdx b/docs/api-reference/endpoint/groups_overview.mdx deleted file mode 100644 index 52c95343f..000000000 --- a/docs/api-reference/endpoint/groups_overview.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Groups Overview' -openapi: 'GET /v2/groups_overview' ---- diff --git a/docs/api-reference/endpoint/list_collections.mdx b/docs/api-reference/endpoint/list_collections.mdx new file mode 100644 index 000000000..12be4e260 --- /dev/null +++ b/docs/api-reference/endpoint/list_collections.mdx @@ -0,0 +1,4 @@ +--- +title: 'List Groups' +openapi: 'GET /v2/list_collections' +--- diff --git a/docs/api-reference/endpoint/list_groups.mdx b/docs/api-reference/endpoint/list_groups.mdx deleted file mode 100644 index fed9ff22c..000000000 --- a/docs/api-reference/endpoint/list_groups.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'List Groups' -openapi: 'GET /v2/list_groups' ---- diff --git a/docs/api-reference/endpoint/remove_document_from_collection.mdx b/docs/api-reference/endpoint/remove_document_from_collection.mdx new file mode 100644 index 000000000..3ad793363 --- /dev/null +++ b/docs/api-reference/endpoint/remove_document_from_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Remove Document from Group' +openapi: 'POST /v2/remove_document_from_collection' +--- diff --git a/docs/api-reference/endpoint/remove_document_from_group.mdx b/docs/api-reference/endpoint/remove_document_from_group.mdx deleted file mode 100644 index 6559a1bea..000000000 --- a/docs/api-reference/endpoint/remove_document_from_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Remove Document from Group' -openapi: 'POST /v2/remove_document_from_group' ---- diff --git a/docs/api-reference/endpoint/remove_user_from_collection.mdx b/docs/api-reference/endpoint/remove_user_from_collection.mdx new file mode 100644 index 000000000..77b5f9948 --- /dev/null +++ b/docs/api-reference/endpoint/remove_user_from_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Remove User from Collection' +openapi: 'POST /v2/remove_user_from_collection' +--- diff --git a/docs/api-reference/endpoint/remove_user_from_group.mdx b/docs/api-reference/endpoint/remove_user_from_group.mdx deleted file mode 100644 index e30779dc5..000000000 --- a/docs/api-reference/endpoint/remove_user_from_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Remove User from Group' -openapi: 'POST /v2/remove_user_from_group' ---- diff --git a/docs/api-reference/endpoint/update_collection.mdx b/docs/api-reference/endpoint/update_collection.mdx new file mode 100644 index 000000000..5c04d2d7d --- /dev/null +++ b/docs/api-reference/endpoint/update_collection.mdx @@ -0,0 +1,4 @@ +--- +title: 'Update Group' +openapi: 'GET /v2/update_collection' +--- diff --git a/docs/api-reference/endpoint/update_group.mdx b/docs/api-reference/endpoint/update_group.mdx deleted file mode 100644 index 04ac74501..000000000 --- a/docs/api-reference/endpoint/update_group.mdx +++ /dev/null @@ -1,4 +0,0 @@ ---- -title: 'Update Group' -openapi: 'GET /v2/update_group' ---- diff --git a/docs/api-reference/openapi.json b/docs/api-reference/openapi.json index 22be266bc..47d56ca72 100644 --- a/docs/api-reference/openapi.json +++ b/docs/api-reference/openapi.json @@ -1 +1 @@ -{"openapi":"3.1.0","info":{"title":"R2R Application API","version":"1.0.0"},"paths":{"/v2/ingest_files":{"post":{"summary":"Ingest Files App","description":"Ingest files into the system.\n\nThis endpoint supports multipart/form-data requests, enabling you to ingest files and their associated metadatas into R2R.\n\nA valid user authentication token is required to access this endpoint, as regular users can only ingest files for their own access. More expansive group permissioning is under development.","operationId":"ingest_files_app_v2_ingest_files_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ingest_files_app_v2_ingest_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_list_IngestionResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.ingest_files(\n file_paths=[\"pg_essay_1.html\", \"got.txt\"],\n metadatas=[{\"metadata_1\":\"some random metadata\"}, {\"metadata_2\": \"some other random metadata\"}],\n document_ids=None,\n versions=None\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/ingest_files\" \\\n -H \"Content-Type: multipart/form-data\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -F \"file=@pg_essay_1.html;type=text/html\" \\\n -F \"file=@got.txt;type=text/plain\" \\\n -F 'metadatas=[{},{}]' \\\n -F 'document_ids=null' \\\n -F 'versions=null'\n"}]}},"/v2/update_files":{"post":{"summary":"Update Files App","description":"Update existing files in the system.\n\nThis endpoint supports multipart/form-data requests, enabling you to update files and their associated metadatas into R2R.\n\nA valid user authentication token is required to access this endpoint, as regular users can only update their own files. More expansive group permissioning is under development.","operationId":"update_files_app_v2_update_files_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_update_files_app_v2_update_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdateResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.update_files(\n file_paths=[\"pg_essay_1_v2.txt\"],\n document_ids=[\"b4ac4dd6-5f27-596e-a55b-7cf242ca30aa\"]\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/update_files\" \\\n -H \"Content-Type: multipart/form-data\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -F \"file=@pg_essay_1_v2.txt;type=text/plain\" \\\n -F 'document_ids=[\"b4ac4dd6-5f27-596e-a55b-7cf242ca30aa\"]'\n"}]}},"/v2/health":{"get":{"summary":"Health Check","operationId":"health_check_v2_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v2/server_stats":{"get":{"summary":"Server Stats","operationId":"server_stats_v2_server_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_ServerStats_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/update_prompt":{"post":{"summary":"Update Prompt App","operationId":"update_prompt_app_v2_update_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_prompt_app_v2_update_prompt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/add_prompt":{"post":{"summary":"Add Prompt App","operationId":"add_prompt_app_v2_add_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_prompt_app_v2_add_prompt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_prompt/{prompt_name}":{"get":{"summary":"Get Prompt App","operationId":"get_prompt_app_v2_get_prompt__prompt_name__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"prompt_name","in":"path","required":true,"schema":{"type":"string","description":"Prompt name","title":"Prompt Name"},"description":"Prompt name"},{"name":"inputs","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"description":"JSON-encoded prompt inputs","title":"Inputs"},"description":"JSON-encoded prompt inputs"},{"name":"prompt_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Prompt override","title":"Prompt Override"},"description":"Prompt override"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/get_all_prompts":{"get":{"summary":"Get All Prompts App","operationId":"get_all_prompts_app_v2_get_all_prompts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_PromptResponse__"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/delete_prompt/{prompt_name}":{"delete":{"summary":"Delete Prompt App","operationId":"delete_prompt_app_v2_delete_prompt__prompt_name__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"prompt_name","in":"path","required":true,"schema":{"type":"string","description":"Prompt name","title":"Prompt Name"},"description":"Prompt name"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/analytics":{"get":{"summary":"Get Analytics App","operationId":"get_analytics_app_v2_analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"filter_criteria","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"default":{},"title":"Filter Criteria"}},{"name":"analysis_types","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"default":{},"title":"Analysis Types"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AnalyticsResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/logs":{"get":{"summary":"Logs App","operationId":"logs_app_v2_logs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_type_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"","title":"Run Type Filter"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_LogResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/app_settings":{"get":{"summary":"App Settings","operationId":"app_settings_v2_app_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AppSettingsResponse_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/score_completion":{"post":{"summary":"Score Completion","operationId":"score_completion_v2_score_completion_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_score_completion_v2_score_completion_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_ScoreCompletionResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/users_overview":{"get":{"summary":"Users Overview App","operationId":"users_overview_app_v2_users_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"default":[],"title":"User Ids"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_UserOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/delete":{"delete":{"summary":"Delete App","operationId":"delete_app_v2_delete_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"filters","in":"query","required":true,"schema":{"type":"string","description":"JSON-encoded filters","title":"Filters"},"description":"JSON-encoded filters"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/documents_overview":{"get":{"summary":"Documents Overview App","operationId":"documents_overview_app_v2_documents_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Document Ids"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/document_chunks/{document_id}":{"get":{"summary":"Document Chunks App","operationId":"document_chunks_app_v2_document_chunks__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentChunkResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/inspect_knowledge_graph":{"get":{"summary":"Inspect Knowledge Graph","operationId":"inspect_knowledge_graph_v2_inspect_knowledge_graph_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"print_descriptions","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Print Descriptions"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_str_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/groups_overview":{"get":{"summary":"Groups Overview App","operationId":"groups_overview_app_v2_groups_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Group Ids"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/create_group":{"post":{"summary":"Create Group App","operationId":"create_group_app_v2_create_group_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_create_group_app_v2_create_group_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_group/{group_id}":{"get":{"summary":"Get Group App","operationId":"get_group_app_v2_get_group__group_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Group Id"},"description":"Group ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/update_group":{"put":{"summary":"Update Group App","operationId":"update_group_app_v2_update_group_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_group_app_v2_update_group_put"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/delete_group/{group_id}":{"delete":{"summary":"Delete Group App","operationId":"delete_group_app_v2_delete_group__group_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Group Id"},"description":"Group ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/list_groups":{"get":{"summary":"List Groups App","operationId":"list_groups_app_v2_list_groups_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/add_user_to_group":{"post":{"summary":"Add User To Group App","operationId":"add_user_to_group_app_v2_add_user_to_group_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_user_to_group_app_v2_add_user_to_group_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AddUserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/remove_user_from_group":{"post":{"summary":"Remove User From Group App","operationId":"remove_user_from_group_app_v2_remove_user_from_group_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_remove_user_from_group_app_v2_remove_user_from_group_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_users_in_group/{group_id}":{"get":{"summary":"Get Users In Group App","operationId":"get_users_in_group_app_v2_get_users_in_group__group_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Group Id"},"description":"Group ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Pagination limit","default":100,"title":"Limit"},"description":"Pagination limit"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user_groups/{user_id}":{"get":{"summary":"Get Groups For User App","operationId":"get_groups_for_user_app_v2_user_groups__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","description":"User ID","title":"User Id"},"description":"User ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Pagination limit","default":100,"title":"Limit"},"description":"Pagination limit"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/assign_document_to_group":{"post":{"summary":"Assign Document To Group App","operationId":"assign_document_to_group_app_v2_assign_document_to_group_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_assign_document_to_group_app_v2_assign_document_to_group_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/remove_document_from_group":{"post":{"summary":"Remove Document From Group App","operationId":"remove_document_from_group_app_v2_remove_document_from_group_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_remove_document_from_group_app_v2_remove_document_from_group_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/document_groups/{document_id}":{"get":{"summary":"Document Groups App","operationId":"document_groups_app_v2_document_groups__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","description":"Document ID","title":"Document Id"},"description":"Document ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/group/{group_id}/documents":{"get":{"summary":"Documents In Group App","operationId":"documents_in_group_app_v2_group__group_id__documents_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"group_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Group Id"},"description":"Group ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/search":{"post":{"summary":"Search App","description":"Perform a search query on the vector database and knowledge graph.\n\nThis endpoint allows for complex filtering of search results using PostgreSQL-based queries.\nFilters can be applied to various fields such as document_id, and internal metadata values.\n\n\nAllowed operators include `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `in`, and `nin`.","operationId":"search_app_v2_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_search_app_v2_search_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_SearchResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.search(\n query=\"Who is Aristotle?\",\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n kg_search_settings={\n \"use_kg_search\": True, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": 0,\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7,\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n }\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/search\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"query\": \"Who is Aristotle?\",\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": true\n },\n \"kg_search_settings\": {\n \"use_kg_search\": true, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": 0,\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n }\n }'\n"}]}},"/v2/rag":{"post":{"summary":"Rag App","description":"Execute a RAG (Retrieval-Augmented Generation) query.\n\nThis endpoint combines search results with language model generation.\nIt supports the same filtering capabilities as the search endpoint,\nallowing for precise control over the retrieved context.\n\nThe generation process can be customized using the rag_generation_config parameter.","operationId":"rag_app_v2_rag_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_rag_app_v2_rag_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_RAGResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.rag(\n query=\"Who is Aristotle?\",\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n kg_search_settings={\n \"use_kg_search\": True,\n \"kg_search_type\": \"local\",\n \"kg_search_level\": 0,\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7,\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n },\n rag_generation_config={\n \"stream\": False,\n \"temperature\": 0.7,\n \"max_tokens\": 150\n }\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/rag\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"query\": \"Who is Aristotle?\",\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n \"kg_search_settings\": {\n \"use_kg_search\": true, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": 0,\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n },\n \"rag_generation_config\": {\n \"stream\": false,\n \"temperature\": 0.7,\n \"max_tokens\": 150\n }\n }'\n"}]}},"/v2/agent":{"post":{"summary":"Agent App","description":"Implement an agent-based interaction for complex query processing.\n\nThis endpoint supports multi-turn conversations and can handle complex queries\nby breaking them down into sub-tasks. It uses the same filtering capabilities\nas the search and RAG endpoints for retrieving relevant information.\n\nThe agent's behavior can be customized using the rag_generation_config and\ntask_prompt_override parameters.","operationId":"agent_app_v2_agent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_agent_app_v2_agent_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_RAGAgentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.agent(\n messages=[\n {\"role\": \"user\", \"content\": \"Who is the greatest philospher of all time?\"},\n {\"role\": \"assistant\", \"content\": \"Aristotle is widely considered the greatest philospher of all time.\"},\n {\"role\": \"user\", \"content\": \"Can you tell me more about him?\"}\n ],\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"5e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n rag_generation_config={\n \"stream\": False,\n \"temperature\": 0.7,\n \"max_tokens\": 200\n },\n include_title_if_available=True\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/agent\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"messages\": [\n {\"role\": \"user\", \"content\": \"Who is the greatest philospher of all time?\"},\n {\"role\": \"assistant\", \"content\": \"Aristotle is widely considered the greatest philospher of all time.\"},\n {\"role\": \"user\", \"content\": \"Can you tell me more about him?\"}\n ],\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"5e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": true\n },\n \"kg_search_settings\": {\n \"use_kg_search\": false # to enable this, please read the graphrag cookbook\n },\n \"rag_generation_config\": {\n \"stream\": false,\n \"temperature\": 0.7,\n \"max_tokens\": 200\n },\n \"include_title_if_available\": true\n }'\n"}]}},"/v2/register":{"post":{"summary":"Register App","description":"Register a new user with the given email and password.","operationId":"register_app_v2_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_register_app_v2_register_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/verify_email":{"post":{"summary":"Verify Email App","description":"Verify a user's email address.\n\nThis endpoint is used to confirm a user's email address using the verification code\nsent to their email after registration.","operationId":"verify_email_app_v2_verify_email_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_verify_email_app_v2_verify_email_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/login":{"post":{"summary":"Login App","description":"Authenticate a user and provide access tokens.\n\nThis endpoint authenticates a user using their email (username) and password,\nand returns access and refresh tokens upon successful authentication.","operationId":"login_app_v2_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_app_v2_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_TokenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/logout":{"post":{"summary":"Logout App","description":"Log out the current user.\n\nThis endpoint invalidates the user's current access token, effectively logging them out.","operationId":"logout_app_v2_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}}},"security":[{"OAuth2PasswordBearer":[]},{"HTTPBearer":[]}]}},"/v2/user":{"get":{"summary":"Get User App","description":"Get the current user's profile information.\n\nThis endpoint returns the profile information of the currently authenticated user.","operationId":"get_user_app_v2_user_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}}},"security":[{"HTTPBearer":[]}]},"put":{"summary":"Put User App","description":"Update the current user's profile information.\n\nThis endpoint allows the authenticated user to update their profile information.","operationId":"put_user_app_v2_user_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_put_user_app_v2_user_put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/refresh_access_token":{"post":{"summary":"Refresh Access Token App","description":"Refresh the access token using a refresh token.\n\nThis endpoint allows users to obtain a new access token using their refresh token.","operationId":"refresh_access_token_app_v2_refresh_access_token_post","requestBody":{"content":{"application/json":{"schema":{"type":"string","title":"Refresh Token","description":"Refresh token"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_TokenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/change_password":{"post":{"summary":"Change Password App","description":"Change the authenticated user's password.\n\nThis endpoint allows users to change their password by providing their current password\nand a new password.","operationId":"change_password_app_v2_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_change_password_app_v2_change_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/request_password_reset":{"post":{"summary":"Request Password Reset App","description":"Request a password reset for a user.\n\nThis endpoint initiates the password reset process by sending a reset link\nto the specified email address.","operationId":"request_password_reset_app_v2_request_password_reset_post","requestBody":{"content":{"application/json":{"schema":{"type":"string","format":"email","title":"Email","description":"User's email address"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/reset_password":{"post":{"summary":"Reset Password App","operationId":"reset_password_app_v2_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_reset_password_app_v2_reset_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}":{"delete":{"summary":"Delete User App","description":"Delete a user account.\n\nThis endpoint allows users to delete their own account or, for superusers,\nto delete any user account.","operationId":"delete_user_app_v2_user__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","description":"ID of the user to delete","title":"User Id"},"description":"ID of the user to delete"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_user_app_v2_user__user_id__delete"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/create_graph":{"post":{"summary":"Create Graph","description":"Creating a graph on your documents. This endpoint takes input a list of document ids and KGCreationSettings. If document IDs are not provided, the graph will be created on all documents in the system.\n\nThis step extracts the relevant entities and relationships from the documents and creates a graph based on the extracted information. You can view the graph through the neo4j browser.\n\nIn order to do GraphRAG, you will need to run the enrich_graph endpoint.","operationId":"create_graph_v2_create_graph_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_create_graph_v2_create_graph_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_KGCreationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/enrich_graph":{"post":{"summary":"Enrich Graph","description":"This endpoint enriches the graph with additional information. It creates communities of nodes based on their similarity and adds embeddings to the graph. This step is necessary for GraphRAG to work.","operationId":"enrich_graph_v2_enrich_graph_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_enrich_graph_v2_enrich_graph_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_KGEnrichmentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/openapi_spec":{"get":{"summary":"Openapi Spec","operationId":"openapi_spec_v2_openapi_spec_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AddUserResponse":{"properties":{"result":{"type":"boolean","title":"Result"}},"type":"object","required":["result"],"title":"AddUserResponse"},"AnalyticsResponse":{"properties":{"analytics_data":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Analytics Data"},"filtered_logs":{"type":"object","title":"Filtered Logs"}},"type":"object","required":["filtered_logs"],"title":"AnalyticsResponse"},"AppSettingsResponse":{"properties":{"config":{"type":"object","title":"Config"},"prompts":{"type":"object","title":"Prompts"}},"type":"object","required":["config","prompts"],"title":"AppSettingsResponse"},"Body_add_prompt_app_v2_add_prompt_post":{"properties":{"name":{"type":"string","title":"Name","description":"Prompt name"},"template":{"type":"string","title":"Template","description":"Prompt template"},"input_types":{"additionalProperties":{"type":"string"},"type":"object","title":"Input Types","description":"Input types","default":{}}},"type":"object","required":["name","template"],"title":"Body_add_prompt_app_v2_add_prompt_post"},"Body_add_user_to_group_app_v2_add_user_to_group_post":{"properties":{"user_id":{"type":"string","title":"User Id","description":"User ID"},"group_id":{"type":"string","title":"Group Id","description":"Group ID"}},"type":"object","required":["user_id","group_id"],"title":"Body_add_user_to_group_app_v2_add_user_to_group_post"},"Body_agent_app_v2_agent_post":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/Message-Input"},"type":"array","title":"Messages","description":"List of message objects"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"},"rag_generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"RAG generation configuration"},"task_prompt_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Prompt Override","description":"Task prompt override"},"include_title_if_available":{"type":"boolean","title":"Include Title If Available","description":"Includes document title in chunk response, if available.","default":true}},"type":"object","required":["messages"],"title":"Body_agent_app_v2_agent_post"},"Body_assign_document_to_group_app_v2_assign_document_to_group_post":{"properties":{"document_id":{"type":"string","title":"Document Id","description":"Document ID"},"group_id":{"type":"string","title":"Group Id","description":"Group ID"}},"type":"object","required":["document_id","group_id"],"title":"Body_assign_document_to_group_app_v2_assign_document_to_group_post"},"Body_change_password_app_v2_change_password_post":{"properties":{"current_password":{"type":"string","title":"Current Password","description":"Current password"},"new_password":{"type":"string","title":"New Password","description":"New password"}},"type":"object","required":["current_password","new_password"],"title":"Body_change_password_app_v2_change_password_post"},"Body_create_graph_v2_create_graph_post":{"properties":{"document_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Document Ids","description":"List of document IDs to create the graph on."},"kg_creation_settings":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/KGCreationSettings"}},{"type":"null"}],"title":"Kg Creation Settings","description":"Settings for the graph creation process."}},"type":"object","title":"Body_create_graph_v2_create_graph_post"},"Body_create_group_app_v2_create_group_post":{"properties":{"name":{"type":"string","title":"Name","description":"Group name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Group description","default":""}},"type":"object","required":["name"],"title":"Body_create_group_app_v2_create_group_post"},"Body_delete_user_app_v2_user__user_id__delete":{"properties":{"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password","description":"User's current password"},"delete_vector_data":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Delete Vector Data","description":"Whether to delete the user's vector data","default":false}},"type":"object","title":"Body_delete_user_app_v2_user__user_id__delete"},"Body_enrich_graph_v2_enrich_graph_post":{"properties":{"skip_clustering":{"type":"boolean","title":"Skip Clustering","description":"Whether to skip leiden clustering on the graph or not.","default":false},"force_enrichment":{"type":"boolean","title":"Force Enrichment","description":"Force Enrichment step even if graph creation is still in progress for some documents.","default":false},"kg_enrichment_settings":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/KGEnrichmentSettings"}},{"type":"null"}],"title":"Kg Enrichment Settings","description":"Settings for the graph enrichment process."}},"type":"object","title":"Body_enrich_graph_v2_enrich_graph_post"},"Body_ingest_files_app_v2_ingest_files_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"The list of paths of input files to ingest into the system."},"document_ids":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"string","format":"uuid"},"type":"array"}},{"type":"null"}],"title":"Document Ids","description":"An optional list of document ids for each file. If not provided, the system will generate a unique document id via the `generate_user_document_id` method."},"metadatas":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"object"},"type":"array"}},{"type":"null"}],"title":"Metadatas","description":"An optional list of JSON metadata to affix to each file"},"chunking_config":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/ChunkingConfig"}},{"type":"null"}],"title":"Chunking Config","description":"An optional dictionary to override the default chunking configuration for the ingestion process. If not provided, the system will use the default server-side chunking configuration."}},"type":"object","required":["files"],"title":"Body_ingest_files_app_v2_ingest_files_post"},"Body_login_app_v2_login_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"password"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_app_v2_login_post"},"Body_put_user_app_v2_user_put":{"properties":{"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email","description":"Updated email address"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Updated user name"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"Updated user bio"},"profile_picture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Picture","description":"Updated profile picture URL"}},"type":"object","title":"Body_put_user_app_v2_user_put"},"Body_rag_app_v2_rag_post":{"properties":{"query":{"type":"string","title":"Query","description":"RAG query"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"},"rag_generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"RAG generation configuration"},"rag_strategy":{"type":"string","title":"Rag Strategy","default":"default"},"task_prompt_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Prompt Override","description":"Task prompt override"},"include_title_if_available":{"type":"boolean","title":"Include Title If Available","description":"Includes document title in chunk response, if available.","default":true}},"type":"object","required":["query"],"title":"Body_rag_app_v2_rag_post"},"Body_register_app_v2_register_post":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"User's email address"},"password":{"type":"string","title":"Password","description":"User's password"}},"type":"object","required":["email","password"],"title":"Body_register_app_v2_register_post"},"Body_remove_document_from_group_app_v2_remove_document_from_group_post":{"properties":{"document_id":{"type":"string","title":"Document Id","description":"Document ID"},"group_id":{"type":"string","title":"Group Id","description":"Group ID"}},"type":"object","required":["document_id","group_id"],"title":"Body_remove_document_from_group_app_v2_remove_document_from_group_post"},"Body_remove_user_from_group_app_v2_remove_user_from_group_post":{"properties":{"user_id":{"type":"string","title":"User Id","description":"User ID"},"group_id":{"type":"string","title":"Group Id","description":"Group ID"}},"type":"object","required":["user_id","group_id"],"title":"Body_remove_user_from_group_app_v2_remove_user_from_group_post"},"Body_reset_password_app_v2_reset_password_post":{"properties":{"reset_token":{"type":"string","title":"Reset Token","description":"Password reset token"},"new_password":{"type":"string","title":"New Password","description":"New password"}},"type":"object","required":["reset_token","new_password"],"title":"Body_reset_password_app_v2_reset_password_post"},"Body_score_completion_v2_score_completion_post":{"properties":{"message_id":{"type":"string","title":"Message Id","description":"Message ID"},"score":{"type":"number","title":"Score","description":"Completion score"}},"type":"object","required":["message_id","score"],"title":"Body_score_completion_v2_score_completion_post"},"Body_search_app_v2_search_post":{"properties":{"query":{"type":"string","title":"Query","description":"Search query"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"}},"type":"object","required":["query"],"title":"Body_search_app_v2_search_post"},"Body_update_files_app_v2_update_files_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"The list of paths of input files to update in the system."},"document_ids":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"string","format":"uuid"},"type":"array"}},{"type":"null"}],"title":"Document Ids","description":"An optional list of document ids for each file. If not provided, the system will generate a unique document id via the `generate_user_document_id` method."},"metadatas":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"object"},"type":"array"}},{"type":"null"}],"title":"Metadatas","description":"An optional list of JSON metadata to affix to each file"},"chunking_config":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/ChunkingConfig"}},{"type":"null"}],"title":"Chunking Config","description":"An optional dictionary to override the default chunking configuration for the ingestion process. If not provided, the system will use the default server-side chunking configuration."}},"type":"object","required":["files"],"title":"Body_update_files_app_v2_update_files_post"},"Body_update_group_app_v2_update_group_put":{"properties":{"group_id":{"type":"string","title":"Group Id","description":"Group ID"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Updated group name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Updated group description"}},"type":"object","required":["group_id"],"title":"Body_update_group_app_v2_update_group_put"},"Body_update_prompt_app_v2_update_prompt_post":{"properties":{"name":{"type":"string","title":"Name","description":"Prompt name"},"template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template","description":"Prompt template"},"input_types":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Input Types","description":"Input types","default":{}}},"type":"object","required":["name"],"title":"Body_update_prompt_app_v2_update_prompt_post"},"Body_verify_email_app_v2_verify_email_post":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"User's email address"},"verification_code":{"type":"string","title":"Verification Code","description":"Email verification code"}},"type":"object","required":["email","verification_code"],"title":"Body_verify_email_app_v2_verify_email_post"},"ChunkingConfig":{"properties":{"provider":{"type":"string"},"method":{"type":"string"}},"type":"object","required":["provider","method"],"title":"ChunkingConfig","example":{"chunking_strategy":"by_title","combine_under_n_chars":128,"max_characters":1024,"method":"by_title","new_after_n_chars":512,"overlap":20,"provider":"unstructured_local","strategy":"auto"}},"DocumentChunkResponse":{"properties":{"fragment_id":{"type":"string","format":"uuid","title":"Fragment Id"},"extraction_id":{"type":"string","format":"uuid","title":"Extraction Id"},"document_id":{"type":"string","format":"uuid","title":"Document Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"group_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Group Ids"},"text":{"type":"string","title":"Text"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["fragment_id","extraction_id","document_id","user_id","group_ids","text","metadata"],"title":"DocumentChunkResponse"},"DocumentOverviewResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"type":{"type":"string","title":"Type"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"ingestion_status":{"type":"string","title":"Ingestion Status"},"restructuring_status":{"type":"string","title":"Restructuring Status"},"version":{"type":"string","title":"Version"},"group_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Group Ids"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["id","title","user_id","type","created_at","updated_at","ingestion_status","restructuring_status","version","group_ids","metadata"],"title":"DocumentOverviewResponse"},"GenerationConfig":{"properties":{"model":{"type":"string","title":"Model"},"temperature":{"type":"number","title":"Temperature"},"top_p":{"type":"number","title":"Top P"},"max_tokens_to_sample":{"type":"integer","title":"Max Tokens To Sample"},"stream":{"type":"boolean","title":"Stream"},"functions":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Functions"},"tools":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tools"},"add_generation_kwargs":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Add Generation Kwargs"},"api_base":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Base"}},"type":"object","title":"GenerationConfig","max_tokens_to_sample":1024,"model":"openai/gpt-4o","stream":false,"temperature":0.1,"top_p":1.0},"GenericMessageResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"GenericMessageResponse"},"GroupOverviewResponse":{"properties":{"group_id":{"type":"string","format":"uuid","title":"Group Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user_count":{"type":"integer","title":"User Count"},"document_count":{"type":"integer","title":"Document Count"}},"type":"object","required":["group_id","name","description","created_at","updated_at","user_count","document_count"],"title":"GroupOverviewResponse"},"GroupResponse":{"properties":{"group_id":{"type":"string","format":"uuid","title":"Group Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["group_id","name","description","created_at","updated_at"],"title":"GroupResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HybridSearchSettings":{"properties":{"full_text_weight":{"type":"number","title":"Full Text Weight","description":"Weight to apply to full text search","default":1.0},"semantic_weight":{"type":"number","title":"Semantic Weight","description":"Weight to apply to semantic search","default":5.0},"full_text_limit":{"type":"integer","title":"Full Text Limit","description":"Maximum number of results to return from full text search","default":200},"rrf_k":{"type":"integer","title":"Rrf K","description":"K-value for RRF (Rank Reciprocal Fusion)","default":50}},"type":"object","title":"HybridSearchSettings"},"IndexMeasure":{"type":"string","enum":["cosine_distance","l2_distance","max_inner_product"],"title":"IndexMeasure","description":"An enum representing the types of distance measures available for indexing.\n\nAttributes:\n cosine_distance (str): The cosine distance measure for indexing.\n l2_distance (str): The Euclidean (L2) distance measure for indexing.\n max_inner_product (str): The maximum inner product measure for indexing."},"IngestionResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the ingestion request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the ingestion request."},"document_id":{"type":"string","format":"uuid","title":"Document Id","description":"The ID of the document that was ingested."}},"type":"object","required":["message","task_id","document_id"],"title":"IngestionResponse","example":{"document_id":"9fbe403b-c11c-5aae-8ade-ef22980c3ad1","message":"Ingestion task queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGCreationResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the restructure request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the restructure request."}},"type":"object","required":["message","task_id"],"title":"KGCreationResponse","example":{"message":"Graph creation queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGCreationSettings":{"properties":{"max_knowledge_triples":{"type":"integer","title":"Max Knowledge Triples","description":"The maximum number of knowledge triples to extract from each chunk.","default":100},"generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"Configuration for text generation during graph enrichment."}},"type":"object","title":"KGCreationSettings","description":"Settings for knowledge graph creation."},"KGEnrichmentResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the restructure request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the restructure request."}},"type":"object","required":["message","task_id"],"title":"KGEnrichmentResponse","example":{"message":"Graph enrichment queued successfuly.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGEnrichmentSettings":{"properties":{"max_summary_input_length":{"type":"integer","title":"Max Summary Input Length","description":"The maximum length of the summary for a community.","default":65536},"generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"Configuration for text generation during graph enrichment."},"leiden_params":{"type":"object","title":"Leiden Params","description":"Parameters for the Leiden algorithm."}},"type":"object","title":"KGEnrichmentSettings","description":"Settings for knowledge graph enrichment."},"KGGlobalSearchResult":{"properties":{"query":{"type":"string","title":"Query"},"search_result":{"items":{"type":"string"},"type":"array","title":"Search Result"}},"type":"object","required":["query","search_result"],"title":"KGGlobalSearchResult","description":"Result of a global knowledge graph search operation.","query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"KGLocalSearchResult":{"properties":{"query":{"type":"string","title":"Query"},"entities":{"type":"object","title":"Entities"},"relationships":{"type":"object","title":"Relationships"},"communities":{"type":"object","title":"Communities"}},"type":"object","required":["query","entities","relationships","communities"],"title":"KGLocalSearchResult","description":"Result of a local knowledge graph search operation.","communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}},"KGSearchResult":{"properties":{"local_result":{"anyOf":[{"$ref":"#/components/schemas/KGLocalSearchResult"},{"type":"null"}]},"global_result":{"anyOf":[{"$ref":"#/components/schemas/KGGlobalSearchResult"},{"type":"null"}]}},"type":"object","title":"KGSearchResult","description":"Result of a knowledge graph search operation.","global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}},"KGSearchSettings":{"properties":{"use_kg_search":{"type":"boolean","title":"Use Kg Search","default":false},"kg_search_type":{"type":"string","title":"Kg Search Type","default":"global"},"kg_search_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kg Search Level"},"kg_search_generation_config":{"anyOf":[{"$ref":"#/components/schemas/GenerationConfig"},{"type":"null"}]},"max_community_description_length":{"type":"integer","title":"Max Community Description Length","default":65536},"max_llm_queries_for_global_search":{"type":"integer","title":"Max Llm Queries For Global Search","default":250},"local_search_limits":{"additionalProperties":{"type":"integer"},"type":"object","title":"Local Search Limits","default":{"__Entity__":20,"__Relationship__":20,"__Community__":20}}},"type":"object","title":"KGSearchSettings","kg_search_generation_config":{"max_tokens_to_sample":1024,"model":"openai/gpt-4o","stream":false,"temperature":0.1,"top_p":1.0},"kg_search_level":0,"kg_search_type":"global","local_search_limits":{"__Community__":20,"__Entity__":20,"__Relationship__":20},"max_community_description_length":65536,"max_llm_queries_for_global_search":250,"use_kg_search":true},"LogEntry":{"properties":{"key":{"type":"string","title":"Key"},"value":{"title":"Value"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","required":["key","value","timestamp"],"title":"LogEntry"},"LogResponse":{"properties":{"run_id":{"type":"string","format":"uuid","title":"Run Id"},"run_type":{"type":"string","title":"Run Type"},"entries":{"items":{"$ref":"#/components/schemas/LogEntry"},"type":"array","title":"Entries"},"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},"type":"object","required":["run_id","run_type","entries","timestamp","user_id"],"title":"LogResponse"},"Message-Input":{"properties":{"role":{"anyOf":[{"$ref":"#/components/schemas/MessageType"},{"type":"string"}],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"function_call":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Function Call"},"tool_calls":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"type":"object","required":["role"],"title":"Message"},"Message-Output":{"properties":{"role":{"anyOf":[{"$ref":"#/components/schemas/MessageType"},{"type":"string"}],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"function_call":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Function Call"},"tool_calls":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"type":"object","required":["role"],"title":"Message","content":"This is a test message.","role":"user"},"MessageType":{"type":"string","enum":["system","user","assistant","function","tool"],"title":"MessageType"},"PromptResponse":{"properties":{"name":{"type":"string","title":"Name"},"template":{"type":"string","title":"Template"},"input_types":{"additionalProperties":{"type":"string"},"type":"object","title":"Input Types"}},"type":"object","required":["name","template","input_types"],"title":"PromptResponse"},"RAGAgentResponse":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/Message-Output"},"type":"array","title":"Messages","description":"List of messages in the RAG agent response"}},"type":"object","required":["messages"],"title":"RAGAgentResponse","example":[{"content":"## You are a helpful assistant that can search for information.\n\nWhen asked a question, perform a search to find relevant information and provide a response.\n\nThe response should contain line-item attributions to relevent search results, and be as informative if possible.\nIf no relevant results are found, then state that no results were found.\nIf no obvious question is present, then do not carry out a search, and instead ask for clarification.","role":"system"},{"content":"You are a helpful assistant.","role":"system"},{"content":"Who is the greatest philospher of all time?","role":"user"},{"content":"Aristotle is widely considered the greatest philospher of all time.","role":"assistant"},{"content":"Can you tell me more about him?","role":"user"},{"function_call":{"arguments":"{\"query\":\"Aristotle biography\"}","name":"search"},"role":"assistant"},{"content":"1. Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.\n2. Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.\n3. Aristotle was born in 384 BC[C] in Stagira, Chalcidice,[2] about 55 km (34 miles) east of modern-day Thessaloniki.[3][4] His father, Nicomachus, was the personal physician to King Amyntas of Macedon. While he was young, Aristotle learned about biology and medical information, which was taught by his father.[5] Both of Aristotle's parents died when he was about thirteen, and Proxenus of Atarneus became his guardian.[6] Although little information about Aristotle's childhood has survived, he probably spent\n4. Aristotle was born in 384 BC[C] in Stagira, Chalcidice,[2] about 55 km (34 miles) east of modern-day Thessaloniki.[3][4] His father, Nicomachus, was the personal physician to King Amyntas of Macedon. While he was young, Aristotle learned about biology and medical information, which was taught by his father.[5] Both of Aristotle's parents died when he was about thirteen, and Proxenus of Atarneus became his guardian.[6] Although little information about Aristotle's childhood has survived, he probably spent\n5. Life\nIn general, the details of Aristotle's life are not well-established. The biographies written in ancient times are often speculative and historians only agree on a few salient points.[B]\n","name":"search","role":"function"},{"content":"Aristotle (384–322 BC) was an Ancient Greek philosopher and polymath whose contributions have had a profound impact on various fields of knowledge. Here are some key points about his life and work:\n\n1. **Early Life**: Aristotle was born in 384 BC in Stagira, Chalcidice, which is near modern-day Thessaloniki, Greece. His father, Nicomachus, was the personal physician to King Amyntas of Macedon, which exposed Aristotle to medical and biological knowledge from a young age [C].\n\n2. **Education and Career**: After the death of his parents, Aristotle was sent to Athens to study at Plato's Academy, where he remained for about 20 years. After Plato's death, Aristotle left Athens and eventually became the tutor of Alexander the Great [C].\n\n3. **Philosophical Contributions**: Aristotle founded the Lyceum in Athens, where he established the Peripatetic school of philosophy. His works cover a wide range of subjects, including metaphysics, ethics, politics, logic, biology, and aesthetics. His writings laid the groundwork for many modern scientific and philosophical inquiries [A].\n\n4. **Legacy**: Aristotle's influence extends beyond philosophy to the natural sciences, linguistics, economics, and psychology. His method of systematic observation and analysis has been foundational to the development of modern science [A].\n\nAristotle's comprehensive approach to knowledge and his systematic methodology have earned him a lasting legacy as one of the greatest philosophers of all time.\n\nSources:\n- [A] Aristotle's broad range of writings and influence on modern science.\n- [C] Details about Aristotle's early life and education.","role":"assistant"}]},"RAGResponse":{"properties":{"completion":{"title":"Completion","description":"The generated completion from the RAG process"},"search_results":{"$ref":"#/components/schemas/SearchResponse","description":"The search results used for the RAG process"}},"type":"object","required":["completion","search_results"],"title":"RAGResponse","example":{"completion":{"choices":[{"finish_reason":"stop","index":0,"message":{"content":"Paris is the capital of France.","role":"assistant"}}],"id":"chatcmpl-example123"},"search_results":{"kg_search_results":[{"global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}}],"vector_search_results":[{"document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","group_ids":[],"metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"}]}}},"ResultsWrapper_AddUserResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AddUserResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AddUserResponse]"},"ResultsWrapper_AnalyticsResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AnalyticsResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AnalyticsResponse]"},"ResultsWrapper_AppSettingsResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AppSettingsResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AppSettingsResponse]"},"ResultsWrapper_GenericMessageResponse_":{"properties":{"results":{"$ref":"#/components/schemas/GenericMessageResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[GenericMessageResponse]"},"ResultsWrapper_GroupResponse_":{"properties":{"results":{"$ref":"#/components/schemas/GroupResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[GroupResponse]"},"ResultsWrapper_KGCreationResponse_":{"properties":{"results":{"$ref":"#/components/schemas/KGCreationResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[KGCreationResponse]"},"ResultsWrapper_KGEnrichmentResponse_":{"properties":{"results":{"$ref":"#/components/schemas/KGEnrichmentResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[KGEnrichmentResponse]"},"ResultsWrapper_List_DocumentChunkResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/DocumentChunkResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[DocumentChunkResponse]]"},"ResultsWrapper_List_DocumentOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/DocumentOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[DocumentOverviewResponse]]"},"ResultsWrapper_List_GroupOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/GroupOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[GroupOverviewResponse]]"},"ResultsWrapper_List_GroupResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[GroupResponse]]"},"ResultsWrapper_List_LogResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/LogResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[LogResponse]]"},"ResultsWrapper_List_PromptResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/PromptResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[PromptResponse]]"},"ResultsWrapper_List_UserOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/UserOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[UserOverviewResponse]]"},"ResultsWrapper_RAGAgentResponse_":{"properties":{"results":{"$ref":"#/components/schemas/RAGAgentResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[RAGAgentResponse]"},"ResultsWrapper_RAGResponse_":{"properties":{"results":{"$ref":"#/components/schemas/RAGResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[RAGResponse]"},"ResultsWrapper_ScoreCompletionResponse_":{"properties":{"results":{"$ref":"#/components/schemas/ScoreCompletionResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[ScoreCompletionResponse]"},"ResultsWrapper_SearchResponse_":{"properties":{"results":{"$ref":"#/components/schemas/SearchResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[SearchResponse]"},"ResultsWrapper_ServerStats_":{"properties":{"results":{"$ref":"#/components/schemas/ServerStats"}},"type":"object","required":["results"],"title":"ResultsWrapper[ServerStats]"},"ResultsWrapper_TokenResponse_":{"properties":{"results":{"$ref":"#/components/schemas/TokenResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[TokenResponse]"},"ResultsWrapper_UpdatePromptResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UpdatePromptResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UpdatePromptResponse]"},"ResultsWrapper_UpdateResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UpdateResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UpdateResponse]"},"ResultsWrapper_UserResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UserResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UserResponse]"},"ResultsWrapper_list_IngestionResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/IngestionResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[list[IngestionResponse]]"},"ResultsWrapper_str_":{"properties":{"results":{"type":"string","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[str]"},"ScoreCompletionResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"ScoreCompletionResponse"},"SearchResponse":{"properties":{"vector_search_results":{"items":{"$ref":"#/components/schemas/VectorSearchResult"},"type":"array","title":"Vector Search Results","description":"List of vector search results"},"kg_search_results":{"anyOf":[{"items":{"$ref":"#/components/schemas/KGSearchResult"},"type":"array"},{"type":"null"}],"title":"Kg Search Results","description":"Knowledge graph search results, if applicable"}},"type":"object","required":["vector_search_results"],"title":"SearchResponse","example":{"kg_search_results":[{"global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}}],"vector_search_results":[{"document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","group_ids":[],"metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"}]}},"ServerStats":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"uptime_seconds":{"type":"number","title":"Uptime Seconds"},"cpu_usage":{"type":"number","title":"Cpu Usage"},"memory_usage":{"type":"number","title":"Memory Usage"}},"type":"object","required":["start_time","uptime_seconds","cpu_usage","memory_usage"],"title":"ServerStats"},"Token":{"properties":{"token":{"type":"string","title":"Token"},"token_type":{"type":"string","title":"Token Type"}},"type":"object","required":["token","token_type"],"title":"Token"},"TokenResponse":{"properties":{"access_token":{"$ref":"#/components/schemas/Token"},"refresh_token":{"$ref":"#/components/schemas/Token"}},"type":"object","required":["access_token","refresh_token"],"title":"TokenResponse"},"UpdatePromptResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"UpdatePromptResponse"},"UpdateResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the ingestion request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the ingestion request."},"document_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Document Ids","description":"The ID of the document that was ingested."}},"type":"object","required":["message","task_id","document_ids"],"title":"UpdateResponse","example":{"document_ids":["9fbe403b-c11c-5aae-8ade-ef22980c3ad1"],"message":"Update task queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"UserOverviewResponse":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"num_files":{"type":"integer","title":"Num Files"},"total_size_in_bytes":{"type":"integer","title":"Total Size In Bytes"},"document_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Document Ids"}},"type":"object","required":["user_id","num_files","total_size_in_bytes","document_ids"],"title":"UserOverviewResponse"},"UserResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active","default":true},"is_superuser":{"type":"boolean","title":"Is Superuser","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At","default":"2024-09-11T00:12:24.302892"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","default":"2024-09-11T00:12:24.302900"},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"group_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Group Ids","default":[]},"hashed_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hashed Password"},"verification_code_expiry":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verification Code Expiry"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio"},"profile_picture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Picture"}},"type":"object","required":["id","email"],"title":"UserResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VectorSearchResult":{"properties":{"fragment_id":{"type":"string","format":"uuid","title":"Fragment Id"},"extraction_id":{"type":"string","format":"uuid","title":"Extraction Id"},"document_id":{"type":"string","format":"uuid","title":"Document Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"group_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Group Ids"},"score":{"type":"number","title":"Score"},"text":{"type":"string","title":"Text"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["fragment_id","extraction_id","document_id","user_id","group_ids","score","text","metadata"],"title":"VectorSearchResult","description":"Result of a search operation.","document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","group_ids":[],"metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"},"VectorSearchSettings":{"properties":{"use_vector_search":{"type":"boolean","title":"Use Vector Search","description":"Whether to use vector search","default":true},"use_hybrid_search":{"type":"boolean","title":"Use Hybrid Search","description":"Whether to perform a hybrid search (combining vector and keyword search)","default":false},"filters":{"type":"object","title":"Filters","description":"Filters to apply to the vector search"},"search_limit":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Search Limit","description":"Maximum number of results to return","default":10},"selected_group_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Selected Group Ids","description":"Group IDs to search for"},"index_measure":{"$ref":"#/components/schemas/IndexMeasure","description":"The distance measure to use for indexing","default":"cosine_distance"},"include_values":{"type":"boolean","title":"Include Values","description":"Whether to include search score values in the search results","default":true},"include_metadatas":{"type":"boolean","title":"Include Metadatas","description":"Whether to include element metadata in the search results","default":true},"probes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Probes","description":"Number of ivfflat index lists to query. Higher increases accuracy but decreases speed.","default":10},"ef_search":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ef Search","description":"Size of the dynamic candidate list for HNSW index search. Higher increases accuracy but decreases speed.","default":40},"hybrid_search_settings":{"anyOf":[{"$ref":"#/components/schemas/HybridSearchSettings"},{"type":"null"}],"description":"Settings for hybrid search","default":{"full_text_weight":1.0,"semantic_weight":5.0,"full_text_limit":200,"rrf_k":50}},"search_strategy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search Strategy","description":"Search strategy to use (e.g., 'default', 'query_fusion', 'hyde')","default":"default"}},"type":"object","title":"VectorSearchSettings","ef_search":40,"filters":{"category":"technology"},"hybrid_search_settings":{"full_text_limit":200,"full_text_weight":1.0,"rrf_k":50,"semantic_weight":5.0},"include_metadata":true,"index_measure":"cosine_distance","probes":10,"search_limit":20,"selected_group_ids":["2acb499e-8428-543b-bd85-0d9098718220","3e157b3a-8469-51db-90d9-52e7d896b49b"],"use_hybrid_search":true,"use_vector_search":true}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"},"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"token"}}}}}} +{"openapi":"3.1.0","info":{"title":"R2R Application API","version":"1.0.0"},"paths":{"/v2/ingest_files":{"post":{"summary":"Ingest Files App","description":"Ingest files into the system.\n\nThis endpoint supports multipart/form-data requests, enabling you to ingest files and their associated metadatas into R2R.\n\nA valid user authentication token is required to access this endpoint, as regular users can only ingest files for their own access. More expansive group permissioning is under development.","operationId":"ingest_files_app_v2_ingest_files_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ingest_files_app_v2_ingest_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_list_IngestionResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.ingest_files(\n file_paths=[\"pg_essay_1.html\", \"got.txt\"],\n metadatas=[{\"metadata_1\":\"some random metadata\"}, {\"metadata_2\": \"some other random metadata\"}],\n document_ids=None,\n versions=None\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/ingest_files\" \\\n -H \"Content-Type: multipart/form-data\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -F \"file=@pg_essay_1.html;type=text/html\" \\\n -F \"file=@got.txt;type=text/plain\" \\\n -F 'metadatas=[{},{}]' \\\n -F 'document_ids=null' \\\n -F 'versions=null'\n"}]}},"/v2/retry_ingest_files":{"post":{"summary":"Retry Ingest Files","description":"Retry the ingestion of files into the system.\n\nThis endpoint allows you to retry the ingestion of files that have previously failed to ingest into R2R.\n\nA valid user authentication token is required to access this endpoint, as regular users can only retry the ingestion of their own files. More expansive group permissioning is under development.","operationId":"retry_ingest_files_v2_retry_ingest_files_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_retry_ingest_files_v2_retry_ingest_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_list_IngestionResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.ingest_files(\n file_paths=[\"pg_essay_1.html\", \"got.txt\"],\n metadatas=[{\"metadata_1\":\"some random metadata\"}, {\"metadata_2\": \"some other random metadata\"}],\n document_ids=None,\n versions=None\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/ingest_files\" \\\n -H \"Content-Type: multipart/form-data\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -F \"file=@pg_essay_1.html;type=text/html\" \\\n -F \"file=@got.txt;type=text/plain\" \\\n -F 'metadatas=[{},{}]' \\\n -F 'document_ids=null' \\\n -F 'versions=null'\n"}]}},"/v2/update_files":{"post":{"summary":"Update Files App","description":"Update existing files in the system.\n\nThis endpoint supports multipart/form-data requests, enabling you to update files and their associated metadatas into R2R.\n\nA valid user authentication token is required to access this endpoint, as regular users can only update their own files. More expansive group permissioning is under development.","operationId":"update_files_app_v2_update_files_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_update_files_app_v2_update_files_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdateResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.update_files(\n file_paths=[\"pg_essay_1_v2.txt\"],\n document_ids=[\"b4ac4dd6-5f27-596e-a55b-7cf242ca30aa\"]\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/update_files\" \\\n -H \"Content-Type: multipart/form-data\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -F \"file=@pg_essay_1_v2.txt;type=text/plain\" \\\n -F 'document_ids=[\"b4ac4dd6-5f27-596e-a55b-7cf242ca30aa\"]'\n"}]}},"/v2/health":{"get":{"summary":"Health Check","operationId":"health_check_v2_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v2/server_stats":{"get":{"summary":"Server Stats","operationId":"server_stats_v2_server_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_ServerStats_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/update_prompt":{"post":{"summary":"Update Prompt App","operationId":"update_prompt_app_v2_update_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_prompt_app_v2_update_prompt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/add_prompt":{"post":{"summary":"Add Prompt App","operationId":"add_prompt_app_v2_add_prompt_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_prompt_app_v2_add_prompt_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_prompt/{prompt_name}":{"get":{"summary":"Get Prompt App","operationId":"get_prompt_app_v2_get_prompt__prompt_name__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"prompt_name","in":"path","required":true,"schema":{"type":"string","description":"Prompt name","title":"Prompt Name"},"description":"Prompt name"},{"name":"inputs","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"description":"JSON-encoded prompt inputs","title":"Inputs"},"description":"JSON-encoded prompt inputs"},{"name":"prompt_override","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Prompt override","title":"Prompt Override"},"description":"Prompt override"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UpdatePromptResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/get_all_prompts":{"get":{"summary":"Get All Prompts App","operationId":"get_all_prompts_app_v2_get_all_prompts_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AllPromptsResponse_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/delete_prompt/{prompt_name}":{"delete":{"summary":"Delete Prompt App","operationId":"delete_prompt_app_v2_delete_prompt__prompt_name__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"prompt_name","in":"path","required":true,"schema":{"type":"string","description":"Prompt name","title":"Prompt Name"},"description":"Prompt name"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/analytics":{"get":{"summary":"Get Analytics App","operationId":"get_analytics_app_v2_analytics_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"filter_criteria","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"default":{},"title":"Filter Criteria"}},{"name":"analysis_types","in":"query","required":false,"schema":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"type":"object"}},{"type":"null"}],"default":{},"title":"Analysis Types"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AnalyticsResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/logs":{"get":{"summary":"Logs App","operationId":"logs_app_v2_logs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_type_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"default":"","title":"Run Type Filter"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_LogResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/app_settings":{"get":{"summary":"App Settings","operationId":"app_settings_v2_app_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AppSettingsResponse_"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/score_completion":{"post":{"summary":"Score Completion","operationId":"score_completion_v2_score_completion_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_score_completion_v2_score_completion_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_ScoreCompletionResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/users_overview":{"get":{"summary":"Users Overview App","operationId":"users_overview_app_v2_users_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"default":[],"title":"User Ids"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_UserOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/delete":{"delete":{"summary":"Delete App","operationId":"delete_app_v2_delete_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"filters","in":"query","required":true,"schema":{"type":"string","description":"JSON-encoded filters","title":"Filters"},"description":"JSON-encoded filters"}],"responses":{"204":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/download_file/{document_id}":{"get":{"summary":"Download File App","description":"Download a file by its document ID as a stream.","operationId":"download_file_app_v2_download_file__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","description":"Document ID","title":"Document Id"},"description":"Document ID"}],"responses":{"200":{"description":"Successful Response"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/documents_overview":{"get":{"summary":"Documents Overview App","operationId":"documents_overview_app_v2_documents_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_ids","in":"query","required":false,"schema":{"type":"array","items":{"type":"string"},"default":[],"title":"Document Ids"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/document_chunks/{document_id}":{"get":{"summary":"Document Chunks App","operationId":"document_chunks_app_v2_document_chunks__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","title":"Document Id"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentChunkResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/inspect_knowledge_graph":{"get":{"summary":"Inspect Knowledge Graph","operationId":"inspect_knowledge_graph_v2_inspect_knowledge_graph_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"print_descriptions","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Print Descriptions"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_str_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/collections_overview":{"get":{"summary":"Collections Overview App","operationId":"collections_overview_app_v2_collections_overview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_ids","in":"query","required":false,"schema":{"anyOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}],"title":"Collection Ids"}},{"name":"offset","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":0},{"type":"null"}],"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":1000,"minimum":1},{"type":"null"}],"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/create_collection":{"post":{"summary":"Create Collection App","operationId":"create_collection_app_v2_create_collection_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_create_collection_app_v2_create_collection_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_collection/{collection_id}":{"get":{"summary":"Get Collection App","operationId":"get_collection_app_v2_get_collection__collection_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Collection Id"},"description":"Group ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/update_collection":{"put":{"summary":"Update Collection App","operationId":"update_collection_app_v2_update_collection_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_update_collection_app_v2_update_collection_put"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GroupResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/delete_collection/{collection_id}":{"delete":{"summary":"Delete Collection App","operationId":"delete_collection_app_v2_delete_collection__collection_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Collection Id"},"description":"Group ID"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/list_collections":{"get":{"summary":"List Collections App","operationId":"list_collections_app_v2_list_collections_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/add_user_to_collection":{"post":{"summary":"Add User To Collection App","operationId":"add_user_to_collection_app_v2_add_user_to_collection_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_add_user_to_collection_app_v2_add_user_to_collection_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_AddUserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/remove_user_from_collection":{"post":{"summary":"Remove User From Collection App","operationId":"remove_user_from_collection_app_v2_remove_user_from_collection_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_remove_user_from_collection_app_v2_remove_user_from_collection_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/get_users_in_collection/{collection_id}":{"get":{"summary":"Get Users In Collection App","operationId":"get_users_in_collection_app_v2_get_users_in_collection__collection_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Collection Id"},"description":"Group ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Pagination limit","default":100,"title":"Limit"},"description":"Pagination limit"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user_collections/{user_id}":{"get":{"summary":"Get Collections For User App","operationId":"get_collections_for_user_app_v2_user_collections__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","description":"User ID","title":"User Id"},"description":"User ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"description":"Pagination offset","default":0,"title":"Offset"},"description":"Pagination offset"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Pagination limit","default":100,"title":"Limit"},"description":"Pagination limit"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/assign_document_to_collection":{"post":{"summary":"Assign Document To Collection App","operationId":"assign_document_to_collection_app_v2_assign_document_to_collection_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_assign_document_to_collection_app_v2_assign_document_to_collection_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/remove_document_from_collection":{"post":{"summary":"Remove Document From Collection App","operationId":"remove_document_from_collection_app_v2_remove_document_from_collection_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_remove_document_from_collection_app_v2_remove_document_from_collection_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/document_collections/{document_id}":{"get":{"summary":"Document Collections App","operationId":"document_collections_app_v2_document_collections__document_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"document_id","in":"path","required":true,"schema":{"type":"string","description":"Document ID","title":"Document Id"},"description":"Document ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_GroupResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/group/{collection_id}/documents":{"get":{"summary":"Documents In Collection App","operationId":"documents_in_collection_app_v2_group__collection_id__documents_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"collection_id","in":"path","required":true,"schema":{"type":"string","description":"Group ID","title":"Collection Id"},"description":"Group ID"},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_List_DocumentOverviewResponse__"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/search":{"post":{"summary":"Search App","description":"Perform a search query on the vector database and knowledge graph.\n\nThis endpoint allows for complex filtering of search results using PostgreSQL-based queries.\nFilters can be applied to various fields such as document_id, and internal metadata values.\n\n\nAllowed operators include `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `in`, and `nin`.","operationId":"search_app_v2_search_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_search_app_v2_search_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_SearchResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.search(\n query=\"Who is Aristotle?\",\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n kg_search_settings={\n \"use_kg_search\": True, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": \"0\",\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7,\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n }\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/search\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"query\": \"Who is Aristotle?\",\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": true\n },\n \"kg_search_settings\": {\n \"use_kg_search\": true, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": \"0\",\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n }\n }'\n"}]}},"/v2/rag":{"post":{"summary":"Rag App","description":"Execute a RAG (Retrieval-Augmented Generation) query.\n\nThis endpoint combines search results with language model generation.\nIt supports the same filtering capabilities as the search endpoint,\nallowing for precise control over the retrieved context.\n\nThe generation process can be customized using the rag_generation_config parameter.","operationId":"rag_app_v2_rag_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_rag_app_v2_rag_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_RAGResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.rag(\n query=\"Who is Aristotle?\",\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n kg_search_settings={\n \"use_kg_search\": True,\n \"kg_search_type\": \"local\",\n \"kg_search_level\": \"0\",\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7,\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n },\n rag_generation_config={\n \"stream\": False,\n \"temperature\": 0.7,\n \"max_tokens\": 150\n }\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/rag\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"query\": \"Who is Aristotle?\",\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"3e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n \"kg_search_settings\": {\n \"use_kg_search\": true, # graph needs to be constructed first\n \"kg_search_type\": \"local\",\n \"kg_search_level\": \"0\",\n \"kg_search_generation_config\": {\n \"model\": \"gpt-4o-mini\",\n \"temperature\": 0.7\n },\n \"local_search_limits\": {\n \"__Entity__\": 20,\n \"__Relationship__\": 20,\n \"__Community__\": 20,\n },\n \"max_community_description_length\": 65536,\n \"max_llm_queries_for_global_search\": 250\n },\n \"rag_generation_config\": {\n \"stream\": false,\n \"temperature\": 0.7,\n \"max_tokens\": 150\n }\n }'\n"}]}},"/v2/agent":{"post":{"summary":"Agent App","description":"Implement an agent-based interaction for complex query processing.\n\nThis endpoint supports multi-turn conversations and can handle complex queries\nby breaking them down into sub-tasks. It uses the same filtering capabilities\nas the search and RAG endpoints for retrieving relevant information.\n\nThe agent's behavior can be customized using the rag_generation_config and\ntask_prompt_override parameters.","operationId":"agent_app_v2_agent_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_agent_app_v2_agent_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_RAGAgentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}],"x-codeSamples":[{"lang":"Python","source":"from r2r import R2RClient\n\nclient = R2RClient(\"http://localhost:7272\")\n# when using auth, do client.login(...)\n\nresult = client.agent(\n messages=[\n {\"role\": \"user\", \"content\": \"Who is the greatest philospher of all time?\"},\n {\"role\": \"assistant\", \"content\": \"Aristotle is widely considered the greatest philospher of all time.\"},\n {\"role\": \"user\", \"content\": \"Can you tell me more about him?\"}\n ],\n vector_search_settings={\n \"use_vector_search\": True,\n \"filters\": {\"document_id\": {\"eq\": \"5e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": True\n },\n rag_generation_config={\n \"stream\": False,\n \"temperature\": 0.7,\n \"max_tokens\": 200\n },\n include_title_if_available=True\n)\n"},{"lang":"Shell","source":"curl -X POST \"https://api.example.com/agent\" \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer YOUR_API_KEY\" \\\n -d '{\n \"messages\": [\n {\"role\": \"user\", \"content\": \"Who is the greatest philospher of all time?\"},\n {\"role\": \"assistant\", \"content\": \"Aristotle is widely considered the greatest philospher of all time.\"},\n {\"role\": \"user\", \"content\": \"Can you tell me more about him?\"}\n ],\n \"vector_search_settings\": {\n \"use_vector_search\": true,\n \"filters\": {\"document_id\": {\"eq\": \"5e157b3a-8469-51db-90d9-52e7d896b49b\"}},\n \"search_limit\": 20,\n \"use_hybrid_search\": true\n },\n \"kg_search_settings\": {\n \"use_kg_search\": false # to enable this, please read the graphrag cookbook\n },\n \"rag_generation_config\": {\n \"stream\": false,\n \"temperature\": 0.7,\n \"max_tokens\": 200\n },\n \"include_title_if_available\": true\n }'\n"}]}},"/v2/register":{"post":{"summary":"Register App","description":"Register a new user with the given email and password.","operationId":"register_app_v2_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_register_app_v2_register_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/verify_email":{"post":{"summary":"Verify Email App","description":"Verify a user's email address.\n\nThis endpoint is used to confirm a user's email address using the verification code\nsent to their email after registration.","operationId":"verify_email_app_v2_verify_email_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_verify_email_app_v2_verify_email_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/login":{"post":{"summary":"Login App","description":"Authenticate a user and provide access tokens.\n\nThis endpoint authenticates a user using their email (username) and password,\nand returns access and refresh tokens upon successful authentication.","operationId":"login_app_v2_login_post","requestBody":{"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_login_app_v2_login_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_TokenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/logout":{"post":{"summary":"Logout App","description":"Log out the current user.\n\nThis endpoint invalidates the user's current access token, effectively logging them out.","operationId":"logout_app_v2_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}}},"security":[{"OAuth2PasswordBearer":[]},{"HTTPBearer":[]}]}},"/v2/user":{"get":{"summary":"Get User App","description":"Get the current user's profile information.\n\nThis endpoint returns the profile information of the currently authenticated user.","operationId":"get_user_app_v2_user_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}}},"security":[{"HTTPBearer":[]}]},"put":{"summary":"Put User App","description":"Update the current user's profile information.\n\nThis endpoint allows the authenticated user to update their profile information.","operationId":"put_user_app_v2_user_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_put_user_app_v2_user_put"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_UserResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/refresh_access_token":{"post":{"summary":"Refresh Access Token App","description":"Refresh the access token using a refresh token.\n\nThis endpoint allows users to obtain a new access token using their refresh token.","operationId":"refresh_access_token_app_v2_refresh_access_token_post","requestBody":{"content":{"application/json":{"schema":{"type":"string","title":"Refresh Token","description":"Refresh token"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_TokenResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/change_password":{"post":{"summary":"Change Password App","description":"Change the authenticated user's password.\n\nThis endpoint allows users to change their password by providing their current password\nand a new password.","operationId":"change_password_app_v2_change_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_change_password_app_v2_change_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/request_password_reset":{"post":{"summary":"Request Password Reset App","description":"Request a password reset for a user.\n\nThis endpoint initiates the password reset process by sending a reset link\nto the specified email address.","operationId":"request_password_reset_app_v2_request_password_reset_post","requestBody":{"content":{"application/json":{"schema":{"type":"string","format":"email","title":"Email","description":"User's email address"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/reset_password":{"post":{"summary":"Reset Password App","operationId":"reset_password_app_v2_reset_password_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_reset_password_app_v2_reset_password_post"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/user/{user_id}":{"delete":{"summary":"Delete User App","description":"Delete a user account.\n\nThis endpoint allows users to delete their own account or, for superusers,\nto delete any user account.","operationId":"delete_user_app_v2_user__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","description":"ID of the user to delete","title":"User Id"},"description":"ID of the user to delete"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_delete_user_app_v2_user__user_id__delete"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_GenericMessageResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v2/create_graph":{"post":{"summary":"Create Graph","description":"Creating a graph on your documents. This endpoint takes input a list of document ids and KGCreationSettings. If document IDs are not provided, the graph will be created on all documents in the system.\n\nThis step extracts the relevant entities and relationships from the documents and creates a graph based on the extracted information. You can view the graph through the neo4j browser.\n\nIn order to do GraphRAG, you will need to run the enrich_graph endpoint.","operationId":"create_graph_v2_create_graph_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_create_graph_v2_create_graph_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_KGCreationResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/enrich_graph":{"post":{"summary":"Enrich Graph","description":"This endpoint enriches the graph with additional information. It creates communities of nodes based on their similarity and adds embeddings to the graph. This step is necessary for GraphRAG to work.","operationId":"enrich_graph_v2_enrich_graph_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_enrich_graph_v2_enrich_graph_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResultsWrapper_KGEnrichmentResponse_"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v2/openapi_spec":{"get":{"summary":"Openapi Spec","operationId":"openapi_spec_v2_openapi_spec_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AddUserResponse":{"properties":{"result":{"type":"boolean","title":"Result"}},"type":"object","required":["result"],"title":"AddUserResponse"},"AllPromptsResponse":{"properties":{"prompts":{"additionalProperties":{"$ref":"#/components/schemas/PromptResponse"},"type":"object","title":"Prompts"}},"type":"object","required":["prompts"],"title":"AllPromptsResponse"},"AnalyticsResponse":{"properties":{"analytics_data":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Analytics Data"},"filtered_logs":{"type":"object","title":"Filtered Logs"}},"type":"object","required":["filtered_logs"],"title":"AnalyticsResponse"},"AppSettingsResponse":{"properties":{"config":{"type":"object","title":"Config"},"prompts":{"type":"object","title":"Prompts"}},"type":"object","required":["config","prompts"],"title":"AppSettingsResponse"},"Body_add_prompt_app_v2_add_prompt_post":{"properties":{"name":{"type":"string","title":"Name","description":"Prompt name"},"template":{"type":"string","title":"Template","description":"Prompt template"},"input_types":{"additionalProperties":{"type":"string"},"type":"object","title":"Input Types","description":"Input types","default":{}}},"type":"object","required":["name","template"],"title":"Body_add_prompt_app_v2_add_prompt_post"},"Body_add_user_to_collection_app_v2_add_user_to_collection_post":{"properties":{"user_id":{"type":"string","title":"User Id","description":"User ID"},"collection_id":{"type":"string","title":"Collection Id","description":"Group ID"}},"type":"object","required":["user_id","collection_id"],"title":"Body_add_user_to_collection_app_v2_add_user_to_collection_post"},"Body_agent_app_v2_agent_post":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/Message-Input"},"type":"array","title":"Messages","description":"List of message objects"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"},"rag_generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"RAG generation configuration"},"task_prompt_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Prompt Override","description":"Task prompt override"},"include_title_if_available":{"type":"boolean","title":"Include Title If Available","description":"Includes document title in chunk response, if available.","default":true}},"type":"object","required":["messages"],"title":"Body_agent_app_v2_agent_post"},"Body_assign_document_to_collection_app_v2_assign_document_to_collection_post":{"properties":{"document_id":{"type":"string","title":"Document Id","description":"Document ID"},"collection_id":{"type":"string","title":"Collection Id","description":"Group ID"}},"type":"object","required":["document_id","collection_id"],"title":"Body_assign_document_to_collection_app_v2_assign_document_to_collection_post"},"Body_change_password_app_v2_change_password_post":{"properties":{"current_password":{"type":"string","title":"Current Password","description":"Current password"},"new_password":{"type":"string","title":"New Password","description":"New password"}},"type":"object","required":["current_password","new_password"],"title":"Body_change_password_app_v2_change_password_post"},"Body_create_collection_app_v2_create_collection_post":{"properties":{"name":{"type":"string","title":"Name","description":"Group name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Group description","default":""}},"type":"object","required":["name"],"title":"Body_create_collection_app_v2_create_collection_post"},"Body_create_graph_v2_create_graph_post":{"properties":{"document_ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Document Ids","description":"List of document IDs to create the graph on."},"kg_creation_settings":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/KGCreationSettings"}},{"type":"null"}],"title":"Kg Creation Settings","description":"Settings for the graph creation process."}},"type":"object","title":"Body_create_graph_v2_create_graph_post"},"Body_delete_user_app_v2_user__user_id__delete":{"properties":{"password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Password","description":"User's current password"},"delete_vector_data":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Delete Vector Data","description":"Whether to delete the user's vector data","default":false}},"type":"object","title":"Body_delete_user_app_v2_user__user_id__delete"},"Body_enrich_graph_v2_enrich_graph_post":{"properties":{"skip_clustering":{"type":"boolean","title":"Skip Clustering","description":"Whether to skip leiden clustering on the graph or not.","default":false},"force_enrichment":{"type":"boolean","title":"Force Enrichment","description":"Force Enrichment step even if graph creation is still in progress for some documents.","default":false},"kg_enrichment_settings":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/KGEnrichmentSettings"}},{"type":"null"}],"title":"Kg Enrichment Settings","description":"Settings for the graph enrichment process."}},"type":"object","title":"Body_enrich_graph_v2_enrich_graph_post"},"Body_ingest_files_app_v2_ingest_files_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"The list of paths of input files to ingest into the system."},"document_ids":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"string","format":"uuid"},"type":"array"}},{"type":"null"}],"title":"Document Ids","description":"An optional list of document ids for each file. If not provided, the system will generate a unique document id via the `generate_user_document_id` method."},"metadatas":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"object"},"type":"array"}},{"type":"null"}],"title":"Metadatas","description":"An optional list of JSON metadata to affix to each file"},"chunking_config":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/ChunkingConfig"}},{"type":"null"}],"title":"Chunking Config","description":"An optional dictionary to override the default chunking configuration for the ingestion process. If not provided, the system will use the default server-side chunking configuration."}},"type":"object","required":["files"],"title":"Body_ingest_files_app_v2_ingest_files_post"},"Body_login_app_v2_login_post":{"properties":{"grant_type":{"anyOf":[{"type":"string","pattern":"password"},{"type":"null"}],"title":"Grant Type"},"username":{"type":"string","title":"Username"},"password":{"type":"string","title":"Password"},"scope":{"type":"string","title":"Scope","default":""},"client_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Id"},"client_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Secret"}},"type":"object","required":["username","password"],"title":"Body_login_app_v2_login_post"},"Body_put_user_app_v2_user_put":{"properties":{"email":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}],"title":"Email","description":"Updated email address"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Updated user name"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio","description":"Updated user bio"},"profile_picture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Picture","description":"Updated profile picture URL"}},"type":"object","title":"Body_put_user_app_v2_user_put"},"Body_rag_app_v2_rag_post":{"properties":{"query":{"type":"string","title":"Query","description":"RAG query"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"},"rag_generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"RAG generation configuration"},"task_prompt_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Task Prompt Override","description":"Task prompt override"},"include_title_if_available":{"type":"boolean","title":"Include Title If Available","description":"Includes document title in chunk response, if available.","default":false}},"type":"object","required":["query"],"title":"Body_rag_app_v2_rag_post"},"Body_register_app_v2_register_post":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"User's email address"},"password":{"type":"string","title":"Password","description":"User's password"}},"type":"object","required":["email","password"],"title":"Body_register_app_v2_register_post"},"Body_remove_document_from_collection_app_v2_remove_document_from_collection_post":{"properties":{"document_id":{"type":"string","title":"Document Id","description":"Document ID"},"collection_id":{"type":"string","title":"Collection Id","description":"Group ID"}},"type":"object","required":["document_id","collection_id"],"title":"Body_remove_document_from_collection_app_v2_remove_document_from_collection_post"},"Body_remove_user_from_collection_app_v2_remove_user_from_collection_post":{"properties":{"user_id":{"type":"string","title":"User Id","description":"User ID"},"collection_id":{"type":"string","title":"Collection Id","description":"Group ID"}},"type":"object","required":["user_id","collection_id"],"title":"Body_remove_user_from_collection_app_v2_remove_user_from_collection_post"},"Body_reset_password_app_v2_reset_password_post":{"properties":{"reset_token":{"type":"string","title":"Reset Token","description":"Password reset token"},"new_password":{"type":"string","title":"New Password","description":"New password"}},"type":"object","required":["reset_token","new_password"],"title":"Body_reset_password_app_v2_reset_password_post"},"Body_retry_ingest_files_v2_retry_ingest_files_post":{"properties":{"document_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Document Ids","description":"An optional list of document ids for each file. If not provided, the system will generate a unique document id via the `generate_user_document_id` method."}},"type":"object","required":["document_ids"],"title":"Body_retry_ingest_files_v2_retry_ingest_files_post"},"Body_score_completion_v2_score_completion_post":{"properties":{"message_id":{"type":"string","title":"Message Id","description":"Message ID"},"score":{"type":"number","title":"Score","description":"Completion score"}},"type":"object","required":["message_id","score"],"title":"Body_score_completion_v2_score_completion_post"},"Body_search_app_v2_search_post":{"properties":{"query":{"type":"string","title":"Query","description":"Search query"},"vector_search_settings":{"$ref":"#/components/schemas/VectorSearchSettings","description":"Vector search settings"},"kg_search_settings":{"$ref":"#/components/schemas/KGSearchSettings","description":"Knowledge graph search settings"}},"type":"object","required":["query"],"title":"Body_search_app_v2_search_post"},"Body_update_collection_app_v2_update_collection_put":{"properties":{"collection_id":{"type":"string","title":"Collection Id","description":"Group ID"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Updated group name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Updated group description"}},"type":"object","required":["collection_id"],"title":"Body_update_collection_app_v2_update_collection_put"},"Body_update_files_app_v2_update_files_post":{"properties":{"files":{"items":{"type":"string","format":"binary"},"type":"array","title":"Files","description":"The list of paths of input files to update in the system."},"document_ids":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"string","format":"uuid"},"type":"array"}},{"type":"null"}],"title":"Document Ids","description":"An optional list of document ids for each file. If not provided, the system will generate a unique document id via the `generate_user_document_id` method."},"metadatas":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"items":{"type":"object"},"type":"array"}},{"type":"null"}],"title":"Metadatas","description":"An optional list of JSON metadata to affix to each file"},"chunking_config":{"anyOf":[{"type":"string","contentMediaType":"application/json","contentSchema":{"$ref":"#/components/schemas/ChunkingConfig"}},{"type":"null"}],"title":"Chunking Config","description":"An optional dictionary to override the default chunking configuration for the ingestion process. If not provided, the system will use the default server-side chunking configuration."}},"type":"object","required":["files"],"title":"Body_update_files_app_v2_update_files_post"},"Body_update_prompt_app_v2_update_prompt_post":{"properties":{"name":{"type":"string","title":"Name","description":"Prompt name"},"template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template","description":"Prompt template"},"input_types":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Input Types","description":"Input types","default":{}}},"type":"object","required":["name"],"title":"Body_update_prompt_app_v2_update_prompt_post"},"Body_verify_email_app_v2_verify_email_post":{"properties":{"email":{"type":"string","format":"email","title":"Email","description":"User's email address"},"verification_code":{"type":"string","title":"Verification Code","description":"Email verification code"}},"type":"object","required":["email","verification_code"],"title":"Body_verify_email_app_v2_verify_email_post"},"ChunkingConfig":{"properties":{"provider":{"type":"string"}},"type":"object","title":"ChunkingConfig","example":{"chunking_strategy":"by_title","combine_under_n_chars":128,"max_characters":1024,"new_after_n_chars":512,"overlap":20,"provider":"unstructured_local","strategy":"auto"}},"DocumentChunkResponse":{"properties":{"fragment_id":{"type":"string","format":"uuid","title":"Fragment Id"},"extraction_id":{"type":"string","format":"uuid","title":"Extraction Id"},"document_id":{"type":"string","format":"uuid","title":"Document Id"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"collection_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Collection Ids"},"text":{"type":"string","title":"Text"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["fragment_id","extraction_id","document_id","user_id","collection_ids","text","metadata"],"title":"DocumentChunkResponse"},"DocumentOverviewResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"title":{"type":"string","title":"Title"},"user_id":{"type":"string","format":"uuid","title":"User Id"},"type":{"type":"string","title":"Type"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"ingestion_status":{"type":"string","title":"Ingestion Status"},"restructuring_status":{"type":"string","title":"Restructuring Status"},"version":{"type":"string","title":"Version"},"collection_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Collection Ids"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["id","title","user_id","type","created_at","updated_at","ingestion_status","restructuring_status","version","collection_ids","metadata"],"title":"DocumentOverviewResponse"},"GenerationConfig":{"properties":{"model":{"type":"string","title":"Model"},"temperature":{"type":"number","title":"Temperature"},"top_p":{"type":"number","title":"Top P"},"max_tokens_to_sample":{"type":"integer","title":"Max Tokens To Sample"},"stream":{"type":"boolean","title":"Stream"},"functions":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Functions"},"tools":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tools"},"add_generation_kwargs":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Add Generation Kwargs"},"api_base":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Base"}},"type":"object","title":"GenerationConfig","max_tokens_to_sample":1024,"model":"openai/gpt-4o","stream":false,"temperature":0.1,"top_p":1.0},"GenericMessageResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"GenericMessageResponse"},"GroupOverviewResponse":{"properties":{"collection_id":{"type":"string","format":"uuid","title":"Collection Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"user_count":{"type":"integer","title":"User Count"},"document_count":{"type":"integer","title":"Document Count"}},"type":"object","required":["collection_id","name","description","created_at","updated_at","user_count","document_count"],"title":"GroupOverviewResponse"},"GroupResponse":{"properties":{"collection_id":{"type":"string","format":"uuid","title":"Collection Id"},"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["collection_id","name","description","created_at","updated_at"],"title":"GroupResponse"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HybridSearchSettings":{"properties":{"full_text_weight":{"type":"number","title":"Full Text Weight","description":"Weight to apply to full text search","default":1.0},"semantic_weight":{"type":"number","title":"Semantic Weight","description":"Weight to apply to semantic search","default":5.0},"full_text_limit":{"type":"integer","title":"Full Text Limit","description":"Maximum number of results to return from full text search","default":200},"rrf_k":{"type":"integer","title":"Rrf K","description":"K-value for RRF (Rank Reciprocal Fusion)","default":50}},"type":"object","title":"HybridSearchSettings"},"IndexMeasure":{"type":"string","enum":["cosine_distance","l2_distance","max_inner_product"],"title":"IndexMeasure","description":"An enum representing the types of distance measures available for indexing.\n\nAttributes:\n cosine_distance (str): The cosine distance measure for indexing.\n l2_distance (str): The Euclidean (L2) distance measure for indexing.\n max_inner_product (str): The maximum inner product measure for indexing."},"IngestionResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the ingestion request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the ingestion request."},"document_id":{"type":"string","format":"uuid","title":"Document Id","description":"The ID of the document that was ingested."}},"type":"object","required":["message","task_id","document_id"],"title":"IngestionResponse","example":{"document_id":"9fbe403b-c11c-5aae-8ade-ef22980c3ad1","message":"Ingestion task queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGCreationResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the restructure request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the restructure request."}},"type":"object","required":["message","task_id"],"title":"KGCreationResponse","example":{"message":"Graph creation queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGCreationSettings":{"properties":{"entity_types":{"items":{"type":"string"},"type":"array","title":"Entity Types","description":"The types of entities to extract.","default":[]},"relation_types":{"items":{"type":"string"},"type":"array","title":"Relation Types","description":"The types of relations to extract.","default":[]},"fragment_merge_count":{"type":"integer","title":"Fragment Merge Count","description":"The number of fragments to merge into a single KG extraction.","default":4},"max_knowledge_triples":{"type":"integer","title":"Max Knowledge Triples","description":"The maximum number of knowledge triples to extract from each chunk.","default":100},"generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"Configuration for text generation during graph enrichment."}},"type":"object","title":"KGCreationSettings","description":"Settings for knowledge graph creation."},"KGEnrichmentResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the restructure request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the restructure request."}},"type":"object","required":["message","task_id"],"title":"KGEnrichmentResponse","example":{"message":"Graph enrichment queued successfuly.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"KGEnrichmentSettings":{"properties":{"max_description_input_length":{"type":"integer","title":"Max Description Input Length","description":"The maximum length of the description for a node in the graph.","default":8192},"max_summary_input_length":{"type":"integer","title":"Max Summary Input Length","description":"The maximum length of the summary for a community.","default":65536},"generation_config":{"$ref":"#/components/schemas/GenerationConfig","description":"Configuration for text generation during graph enrichment."},"leiden_params":{"type":"object","title":"Leiden Params","description":"Parameters for the Leiden algorithm."}},"type":"object","title":"KGEnrichmentSettings","description":"Settings for knowledge graph enrichment."},"KGGlobalSearchResult":{"properties":{"query":{"type":"string","title":"Query"},"search_result":{"items":{"type":"string"},"type":"array","title":"Search Result"}},"type":"object","required":["query","search_result"],"title":"KGGlobalSearchResult","description":"Result of a global knowledge graph search operation.","query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"KGLocalSearchResult":{"properties":{"query":{"type":"string","title":"Query"},"entities":{"type":"object","title":"Entities"},"relationships":{"type":"object","title":"Relationships"},"communities":{"type":"object","title":"Communities"}},"type":"object","required":["query","entities","relationships","communities"],"title":"KGLocalSearchResult","description":"Result of a local knowledge graph search operation.","communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}},"KGSearchResult":{"properties":{"local_result":{"anyOf":[{"$ref":"#/components/schemas/KGLocalSearchResult"},{"type":"null"}]},"global_result":{"anyOf":[{"$ref":"#/components/schemas/KGGlobalSearchResult"},{"type":"null"}]}},"type":"object","title":"KGSearchResult","description":"Result of a knowledge graph search operation.","global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}},"KGSearchSettings":{"properties":{"use_kg_search":{"type":"boolean","title":"Use Kg Search","default":false},"kg_search_type":{"type":"string","title":"Kg Search Type","default":"global"},"kg_search_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kg Search Level"},"kg_search_generation_config":{"anyOf":[{"$ref":"#/components/schemas/GenerationConfig"},{"type":"null"}]},"max_community_description_length":{"type":"integer","title":"Max Community Description Length","default":65536},"max_llm_queries_for_global_search":{"type":"integer","title":"Max Llm Queries For Global Search","default":250},"local_search_limits":{"additionalProperties":{"type":"integer"},"type":"object","title":"Local Search Limits","default":{"__Entity__":20,"__Relationship__":20,"__Community__":20}}},"type":"object","title":"KGSearchSettings","kg_search_generation_config":{"max_tokens_to_sample":1024,"model":"openai/gpt-4o","stream":false,"temperature":0.1,"top_p":1.0},"kg_search_level":"0","kg_search_type":"global","local_search_limits":{"__Community__":20,"__Entity__":20,"__Relationship__":20},"max_community_description_length":65536,"max_llm_queries_for_global_search":250,"use_kg_search":true},"LogEntry":{"properties":{"key":{"type":"string","title":"Key"},"value":{"title":"Value"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"}},"type":"object","required":["key","value","timestamp"],"title":"LogEntry"},"LogResponse":{"properties":{"run_id":{"type":"string","format":"uuid","title":"Run Id"},"run_type":{"type":"string","title":"Run Type"},"entries":{"items":{"$ref":"#/components/schemas/LogEntry"},"type":"array","title":"Entries"},"timestamp":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"}},"type":"object","required":["run_id","run_type","entries","timestamp","user_id"],"title":"LogResponse"},"Message-Input":{"properties":{"role":{"anyOf":[{"$ref":"#/components/schemas/MessageType"},{"type":"string"}],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"function_call":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Function Call"},"tool_calls":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"type":"object","required":["role"],"title":"Message"},"Message-Output":{"properties":{"role":{"anyOf":[{"$ref":"#/components/schemas/MessageType"},{"type":"string"}],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"function_call":{"anyOf":[{"type":"object"},{"type":"null"}],"title":"Function Call"},"tool_calls":{"anyOf":[{"items":{"type":"object"},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"type":"object","required":["role"],"title":"Message","content":"This is a test message.","role":"user"},"MessageType":{"type":"string","enum":["system","user","assistant","function","tool"],"title":"MessageType"},"PromptResponse":{"properties":{"name":{"type":"string","title":"Name"},"template":{"type":"string","title":"Template"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"input_types":{"additionalProperties":{"type":"string"},"type":"object","title":"Input Types"}},"type":"object","required":["name","template","created_at","updated_at","input_types"],"title":"PromptResponse"},"RAGAgentResponse":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/Message-Output"},"type":"array","title":"Messages","description":"List of messages in the RAG agent response"}},"type":"object","required":["messages"],"title":"RAGAgentResponse","example":[{"content":"## You are a helpful assistant that can search for information.\n\nWhen asked a question, perform a search to find relevant information and provide a response.\n\nThe response should contain line-item attributions to relevent search results, and be as informative if possible.\nIf no relevant results are found, then state that no results were found.\nIf no obvious question is present, then do not carry out a search, and instead ask for clarification.","role":"system"},{"content":"You are a helpful assistant.","role":"system"},{"content":"Who is the greatest philospher of all time?","role":"user"},{"content":"Aristotle is widely considered the greatest philospher of all time.","role":"assistant"},{"content":"Can you tell me more about him?","role":"user"},{"function_call":{"arguments":"{\"query\":\"Aristotle biography\"}","name":"search"},"role":"assistant"},{"content":"1. Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.\n2. Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.\n3. Aristotle was born in 384 BC[C] in Stagira, Chalcidice,[2] about 55 km (34 miles) east of modern-day Thessaloniki.[3][4] His father, Nicomachus, was the personal physician to King Amyntas of Macedon. While he was young, Aristotle learned about biology and medical information, which was taught by his father.[5] Both of Aristotle's parents died when he was about thirteen, and Proxenus of Atarneus became his guardian.[6] Although little information about Aristotle's childhood has survived, he probably spent\n4. Aristotle was born in 384 BC[C] in Stagira, Chalcidice,[2] about 55 km (34 miles) east of modern-day Thessaloniki.[3][4] His father, Nicomachus, was the personal physician to King Amyntas of Macedon. While he was young, Aristotle learned about biology and medical information, which was taught by his father.[5] Both of Aristotle's parents died when he was about thirteen, and Proxenus of Atarneus became his guardian.[6] Although little information about Aristotle's childhood has survived, he probably spent\n5. Life\nIn general, the details of Aristotle's life are not well-established. The biographies written in ancient times are often speculative and historians only agree on a few salient points.[B]\n","name":"search","role":"function"},{"content":"Aristotle (384–322 BC) was an Ancient Greek philosopher and polymath whose contributions have had a profound impact on various fields of knowledge. Here are some key points about his life and work:\n\n1. **Early Life**: Aristotle was born in 384 BC in Stagira, Chalcidice, which is near modern-day Thessaloniki, Greece. His father, Nicomachus, was the personal physician to King Amyntas of Macedon, which exposed Aristotle to medical and biological knowledge from a young age [C].\n\n2. **Education and Career**: After the death of his parents, Aristotle was sent to Athens to study at Plato's Academy, where he remained for about 20 years. After Plato's death, Aristotle left Athens and eventually became the tutor of Alexander the Great [C].\n\n3. **Philosophical Contributions**: Aristotle founded the Lyceum in Athens, where he established the Peripatetic school of philosophy. His works cover a wide range of subjects, including metaphysics, ethics, politics, logic, biology, and aesthetics. His writings laid the groundwork for many modern scientific and philosophical inquiries [A].\n\n4. **Legacy**: Aristotle's influence extends beyond philosophy to the natural sciences, linguistics, economics, and psychology. His method of systematic observation and analysis has been foundational to the development of modern science [A].\n\nAristotle's comprehensive approach to knowledge and his systematic methodology have earned him a lasting legacy as one of the greatest philosophers of all time.\n\nSources:\n- [A] Aristotle's broad range of writings and influence on modern science.\n- [C] Details about Aristotle's early life and education.","role":"assistant"}]},"RAGResponse":{"properties":{"completion":{"title":"Completion","description":"The generated completion from the RAG process"},"search_results":{"$ref":"#/components/schemas/SearchResponse","description":"The search results used for the RAG process"}},"type":"object","required":["completion","search_results"],"title":"RAGResponse","example":{"completion":{"choices":[{"finish_reason":"stop","index":0,"message":{"content":"Paris is the capital of France.","role":"assistant"}}],"id":"chatcmpl-example123"},"search_results":{"kg_search_results":[{"global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}}],"vector_search_results":[{"collection_ids":[],"document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"}]}}},"ResultsWrapper_AddUserResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AddUserResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AddUserResponse]"},"ResultsWrapper_AllPromptsResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AllPromptsResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AllPromptsResponse]"},"ResultsWrapper_AnalyticsResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AnalyticsResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AnalyticsResponse]"},"ResultsWrapper_AppSettingsResponse_":{"properties":{"results":{"$ref":"#/components/schemas/AppSettingsResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[AppSettingsResponse]"},"ResultsWrapper_GenericMessageResponse_":{"properties":{"results":{"$ref":"#/components/schemas/GenericMessageResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[GenericMessageResponse]"},"ResultsWrapper_GroupResponse_":{"properties":{"results":{"$ref":"#/components/schemas/GroupResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[GroupResponse]"},"ResultsWrapper_KGCreationResponse_":{"properties":{"results":{"$ref":"#/components/schemas/KGCreationResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[KGCreationResponse]"},"ResultsWrapper_KGEnrichmentResponse_":{"properties":{"results":{"$ref":"#/components/schemas/KGEnrichmentResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[KGEnrichmentResponse]"},"ResultsWrapper_List_DocumentChunkResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/DocumentChunkResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[DocumentChunkResponse]]"},"ResultsWrapper_List_DocumentOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/DocumentOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[DocumentOverviewResponse]]"},"ResultsWrapper_List_GroupOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/GroupOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[GroupOverviewResponse]]"},"ResultsWrapper_List_GroupResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/GroupResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[GroupResponse]]"},"ResultsWrapper_List_LogResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/LogResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[LogResponse]]"},"ResultsWrapper_List_UserOverviewResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/UserOverviewResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[List[UserOverviewResponse]]"},"ResultsWrapper_RAGAgentResponse_":{"properties":{"results":{"$ref":"#/components/schemas/RAGAgentResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[RAGAgentResponse]"},"ResultsWrapper_RAGResponse_":{"properties":{"results":{"$ref":"#/components/schemas/RAGResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[RAGResponse]"},"ResultsWrapper_ScoreCompletionResponse_":{"properties":{"results":{"$ref":"#/components/schemas/ScoreCompletionResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[ScoreCompletionResponse]"},"ResultsWrapper_SearchResponse_":{"properties":{"results":{"$ref":"#/components/schemas/SearchResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[SearchResponse]"},"ResultsWrapper_ServerStats_":{"properties":{"results":{"$ref":"#/components/schemas/ServerStats"}},"type":"object","required":["results"],"title":"ResultsWrapper[ServerStats]"},"ResultsWrapper_TokenResponse_":{"properties":{"results":{"$ref":"#/components/schemas/TokenResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[TokenResponse]"},"ResultsWrapper_UpdatePromptResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UpdatePromptResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UpdatePromptResponse]"},"ResultsWrapper_UpdateResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UpdateResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UpdateResponse]"},"ResultsWrapper_UserResponse_":{"properties":{"results":{"$ref":"#/components/schemas/UserResponse"}},"type":"object","required":["results"],"title":"ResultsWrapper[UserResponse]"},"ResultsWrapper_list_IngestionResponse__":{"properties":{"results":{"items":{"$ref":"#/components/schemas/IngestionResponse"},"type":"array","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[list[IngestionResponse]]"},"ResultsWrapper_str_":{"properties":{"results":{"type":"string","title":"Results"}},"type":"object","required":["results"],"title":"ResultsWrapper[str]"},"ScoreCompletionResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"ScoreCompletionResponse"},"SearchResponse":{"properties":{"vector_search_results":{"items":{"$ref":"#/components/schemas/VectorSearchResult"},"type":"array","title":"Vector Search Results","description":"List of vector search results"},"kg_search_results":{"anyOf":[{"items":{"$ref":"#/components/schemas/KGSearchResult"},"type":"array"},{"type":"null"}],"title":"Kg Search Results","description":"Knowledge graph search results, if applicable"}},"type":"object","required":["vector_search_results"],"title":"SearchResponse","example":{"kg_search_results":[{"global_result":{"query":"What were Aristotles key contributions to philosophy?","search_result":["### Aristotle's Key Contributions to Philosophy\n\nAristotle's extensive body of work laid the foundation for numerous fields within philosophy and beyond, significantly shaping the trajectory of Western thought. His systematic approach to data collection and analysis has had a lasting impact on modern scientific methods. Below, we explore some of his most influential contributions.\n\n#### Foundational Works and Systematic Approach\n\nAristotle's writings cover a broad spectrum of topics, including logic, biology, ethics, and political science. His key works such as 'Physics,' 'On the Soul,' and 'Nicomachean Ethics' delve into fundamental concepts like substance, memory, and the nature of the city [Data: Reports (1, 2, 3, 4, 5, +more)]. These texts not only provided a comprehensive framework for understanding various aspects of the natural and human world but also established methodologies that continue to influence contemporary scientific inquiry.\n\n#### Ethical and Political Philosophy\n\nIn 'Nicomachean Ethics,' Aristotle explores the concept of a virtuous character, emphasizing the importance of moral virtues and the development of good habits. His work 'Politics' further examines the structure and function of the city (polis), addressing issues related to property, trade, and governance. Aristotle's classification of political constitutions and his definition of the city as the natural political community have had a profound and enduring impact on political thought [Data: Reports (11, 12); Triples (21, 22, 23, 24, 25)].\n\n#### Theories on Memory and Perception\n\nAristotle's theories on memory and perception are articulated in his works 'On the Soul' and 'De Anima iii 3.' He defines memory as the retention of experiences shaped by sensation and discusses the faculty of imagination (phantasia). These theories have significantly influenced subsequent philosophical and psychological studies on cognition and perception [Data: Reports (13, 14); Triples (26, 27, 28, 29, 30)].\n\n#### Epistemology and Scientific Method\n\nAristotle's epistemology, known as immanent realism, is based on the study of things that exist or happen in the world. This approach emphasizes empirical observation and has been instrumental in shaping the development of scientific methods. His insistence on grounding knowledge in observable phenomena laid the groundwork for future empirical research [Data: Reports (3)].\n\n#### Engagement with Predecessors and Contemporaries\n\nAristotle was also known for his critical engagement with the ideas of his predecessors and contemporaries. For instance, he refuted Democritus's claim about the Milky Way and criticized Empedocles's materialist theory of 'survival of the fittest.' These critiques highlight Aristotle's active participation in the broader philosophical discourse of his time and his contributions to refining and advancing philosophical thought [Data: Reports (15, 16); Triples (31, 32, 33, 34, 35)].\n\n### Conclusion\n\nAristotle's contributions to philosophy are vast and multifaceted, encompassing ethics, politics, epistemology, and more. His works continue to be studied and revered for their depth, rigor, and enduring relevance. Through his systematic approach and critical engagement with existing ideas, Aristotle has left an indelible mark on the landscape of Western philosophy."]},"local_result":{"communities":{"0":{"summary":{"findings":[{"explanation":"Aristotle is credited with the earliest study of formal logic, and his conception of it was the dominant form of Western logic until the 19th-century advances in mathematical logic. His works compiled into a set of six books ...","summary":"Aristotle's Foundational Role in Logic"}],"rating":9.5,"rating_explanation":"The impact severity rating is high due to Aristotle's foundational influence on multiple disciplines and his enduring legacy in Western philosophy and science.","summary":"The community revolves around Aristotle, an ancient Greek philosopher and polymath, who made significant contributions to various fields including logic, biology, political science, and economics. His works, such as 'Politics' and 'Nicomachean Ethics', have influenced numerous disciplines and thinkers from antiquity through the Middle Ages and beyond. The relationships between his various works and the fields he contributed to highlight his profound impact on Western thought.","title":"Aristotle and His Contributions"}}},"entities":{"0":{"description":"Aristotle was an ancient Greek philosopher and polymath, recognized as the father of various fields including logic, biology, and political science. He authored significant works such as the *Nicomachean Ethics* and *Politics*, where he explored concepts of virtue, governance, and the nature of reality, while also critiquing Platos ideas. His teachings and observations laid the groundwork for numerous disciplines, influencing thinkers ...","name":"Aristotle"}},"query":"Who is Aristotle?","relationships":{}}}],"vector_search_results":[{"collection_ids":[],"document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"}]}},"ServerStats":{"properties":{"start_time":{"type":"string","format":"date-time","title":"Start Time"},"uptime_seconds":{"type":"number","title":"Uptime Seconds"},"cpu_usage":{"type":"number","title":"Cpu Usage"},"memory_usage":{"type":"number","title":"Memory Usage"}},"type":"object","required":["start_time","uptime_seconds","cpu_usage","memory_usage"],"title":"ServerStats"},"Token":{"properties":{"token":{"type":"string","title":"Token"},"token_type":{"type":"string","title":"Token Type"}},"type":"object","required":["token","token_type"],"title":"Token"},"TokenResponse":{"properties":{"access_token":{"$ref":"#/components/schemas/Token"},"refresh_token":{"$ref":"#/components/schemas/Token"}},"type":"object","required":["access_token","refresh_token"],"title":"TokenResponse"},"UpdatePromptResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"UpdatePromptResponse"},"UpdateResponse":{"properties":{"message":{"type":"string","title":"Message","description":"A message describing the result of the ingestion request."},"task_id":{"type":"string","format":"uuid","title":"Task Id","description":"The task ID of the ingestion request."},"document_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Document Ids","description":"The ID of the document that was ingested."}},"type":"object","required":["message","task_id","document_ids"],"title":"UpdateResponse","example":{"document_ids":["9fbe403b-c11c-5aae-8ade-ef22980c3ad1"],"message":"Update task queued successfully.","task_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96"}},"UserOverviewResponse":{"properties":{"user_id":{"type":"string","format":"uuid","title":"User Id"},"num_files":{"type":"integer","title":"Num Files"},"total_size_in_bytes":{"type":"integer","title":"Total Size In Bytes"},"document_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Document Ids"}},"type":"object","required":["user_id","num_files","total_size_in_bytes","document_ids"],"title":"UserOverviewResponse"},"UserResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"is_active":{"type":"boolean","title":"Is Active","default":true},"is_superuser":{"type":"boolean","title":"Is Superuser","default":false},"created_at":{"type":"string","format":"date-time","title":"Created At","default":"2024-09-17T16:37:09.481111"},"updated_at":{"type":"string","format":"date-time","title":"Updated At","default":"2024-09-17T16:37:09.481117"},"is_verified":{"type":"boolean","title":"Is Verified","default":false},"collection_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Collection Ids","default":[]},"hashed_password":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hashed Password"},"verification_code_expiry":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Verification Code Expiry"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"bio":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bio"},"profile_picture":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Picture"}},"type":"object","required":["id","email"],"title":"UserResponse"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VectorSearchResult":{"properties":{"fragment_id":{"type":"string","format":"uuid","title":"Fragment Id"},"extraction_id":{"type":"string","format":"uuid","title":"Extraction Id"},"document_id":{"type":"string","format":"uuid","title":"Document Id"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"collection_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Collection Ids"},"score":{"type":"number","title":"Score"},"text":{"type":"string","title":"Text"},"metadata":{"type":"object","title":"Metadata"}},"type":"object","required":["fragment_id","extraction_id","document_id","user_id","collection_ids","score","text","metadata"],"title":"VectorSearchResult","description":"Result of a search operation.","collection_ids":[],"document_id":"3e157b3a-8469-51db-90d9-52e7d896b49b","extraction_id":"3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09","fragment_id":"c68dc72e-fc23-5452-8f49-d7bd46088a96","metadata":{"associated_query":"What is the capital of France?","title":"example_document.pdf"},"score":0.23943702876567796,"text":"Example text from the document","user_id":"2acb499e-8428-543b-bd85-0d9098718220"},"VectorSearchSettings":{"properties":{"use_vector_search":{"type":"boolean","title":"Use Vector Search","description":"Whether to use vector search","default":true},"use_hybrid_search":{"type":"boolean","title":"Use Hybrid Search","description":"Whether to perform a hybrid search (combining vector and keyword search)","default":false},"filters":{"type":"object","title":"Filters","description":"Filters to apply to the vector search"},"search_limit":{"type":"integer","maximum":1000.0,"minimum":1.0,"title":"Search Limit","description":"Maximum number of results to return","default":10},"selected_collection_ids":{"items":{"type":"string","format":"uuid"},"type":"array","title":"Selected Collection Ids","description":"Group IDs to search for"},"index_measure":{"$ref":"#/components/schemas/IndexMeasure","description":"The distance measure to use for indexing","default":"cosine_distance"},"include_values":{"type":"boolean","title":"Include Values","description":"Whether to include search score values in the search results","default":true},"include_metadatas":{"type":"boolean","title":"Include Metadatas","description":"Whether to include element metadata in the search results","default":true},"probes":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Probes","description":"Number of ivfflat index lists to query. Higher increases accuracy but decreases speed.","default":10},"ef_search":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Ef Search","description":"Size of the dynamic candidate list for HNSW index search. Higher increases accuracy but decreases speed.","default":40},"hybrid_search_settings":{"anyOf":[{"$ref":"#/components/schemas/HybridSearchSettings"},{"type":"null"}],"description":"Settings for hybrid search","default":{"full_text_weight":1.0,"semantic_weight":5.0,"full_text_limit":200,"rrf_k":50}},"search_strategy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Search Strategy","description":"Search strategy to use (e.g., 'default', 'query_fusion', 'hyde')","default":"vanilla"}},"type":"object","title":"VectorSearchSettings","ef_search":40,"filters":{"category":"technology"},"hybrid_search_settings":{"full_text_limit":200,"full_text_weight":1.0,"rrf_k":50,"semantic_weight":5.0},"include_metadata":true,"index_measure":"cosine_distance","probes":10,"search_limit":20,"selected_collection_ids":["2acb499e-8428-543b-bd85-0d9098718220","3e157b3a-8469-51db-90d9-52e7d896b49b"],"use_hybrid_search":true,"use_vector_search":true}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"},"OAuth2PasswordBearer":{"type":"oauth2","flows":{"password":{"scopes":{},"tokenUrl":"token"}}}}}} \ No newline at end of file diff --git a/docs/cookbooks/collections.mdx b/docs/cookbooks/collections.mdx new file mode 100644 index 000000000..8925c1eea --- /dev/null +++ b/docs/cookbooks/collections.mdx @@ -0,0 +1,263 @@ +--- +title: 'Collections' +description: 'A comprehensive guide to creating collections in R2R' +icon: 'database' +--- + +## Introduction + +A collection in R2R is a logical grouping of users and documents that allows for efficient access control and organization. Collections enable you to manage permissions and access to documents at a group level, rather than individually. + +R2R provides robust document collection management, allowing developers to implement efficient access control and organization of users and documents. This cookbook will guide you through the collection capabilities in R2R. + +For user authentication, please refer to the [User Auth Cookbook](/cookbooks/user-auth). + + +Collection permissioning in R2R is still under development and as a result the is likely to API continue evolving in future releases. + + + +```mermaid +graph TD + A[User] --> B(Authentication) + B --> C{Authenticated?} + C -->|Yes| D[Authenticated User] + C -->|No| E[Guest User] + D --> F[Collection Management] + D --> G[Document Management] + D --> H[User Profile Management] + G --> I[CRUD Operations] + G --> J[Search & RAG] + D --> K[Logout] + L[Admin] --> M[Superuser Authentication] + M --> N[Superuser Capabilities] + N --> O[User Management] + N --> P[System-wide Document Access] + N --> Q[Analytics & Observability] + N --> R[Configuration Management] +``` +_A diagram showing user and collection management across r2r_ + +## Basic Usage + + +Collections currently follow a flat hierarchy wherein superusers are responsible for management operations. This functionality will expand as development on R2R continues. + + +### Creating a Collection + +Let's start by creating a new collection: + +```python +from r2r import R2RClient + +client = R2RClient("http://localhost:7272") # Replace with your R2R deployment URL + +# Assuming you're logged in as an admin or a user with appropriate permissions +# For testing, the default R2R implementation will grant superuser privileges to anon api calls +collection_result = client.create_collection("Marketing Team", "Collection for marketing department") + +print(f"Collection creation result: {collection_result}") +# {'results': {'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', 'description': 'Collection for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z'}} +``` + +### Getting Collection details + +To retrieve details about a specific collection: + +```python +collection_id = '123e4567-e89b-12d3-a456-426614174000' # Use the collection_id from the creation result +collection_details = client.get_collection(collection_id) + +print(f"Collection details: {collection_details}") +# {'results': {'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', 'description': 'Collection for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z'}} +``` + +### Updating a Collection + +You can update a collection's name or description: + +```python +update_result = client.update_collection(collection_id, name="Updated Marketing Team", description="New description for marketing team") + +print(f"Collection update result: {update_result}") +# {'results': {'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z'}} +``` + +### Listing Collections + +To get a list of all collections: + +```python +collections_list = client.list_collections() + +print(f"Collections list: {collections_list}") +# {'results': [{'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z'}, ...]} +``` + +## User Management in Collections + +### Adding a User to a Collection + +To add a user to a collection, you need both the user's ID and the collections's ID: + +```python +user_id = '456e789f-g01h-34i5-j678-901234567890' # This should be a valid user ID +add_user_result = client.add_user_to_collection(user_id, collection_id) + +print(f"Add user to collection result: {add_user_result}") +# {'results': {'message': 'User successfully added to the collection'}} +``` + +### Removing a User from a Collections + +Similarly, to remove a user from a collection: + +```python +remove_user_result = client.remove_user_from_collection(user_id, collection_id) + +print(f"Remove user from collection result: {remove_user_result}") +# {'results': None} +``` + +### Listing Users in a Collection + +To get a list of all users in a specific collection: + +```python +users_in_collection = client.get_users_in_collection(collection_id) + +print(f"Users in collection: {users_in_collection}") +# {'results': [{'user_id': '456e789f-g01h-34i5-j678-901234567890', 'email': 'user@example.com', 'name': 'John Doe', ...}, ...]} +``` + +### Getting Collections for a User + +To get all collections that a user is a member of: + +```python +user_collections = client.user_collections(user_id) + +print(f"User's collections: {user_collections}") +# {'results': [{'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', ...}, ...]} +``` + +## Document Management in Collections + +### Assigning a Document to a Collection + +To assign a document to a collection: + +```python +document_id = '789g012j-k34l-56m7-n890-123456789012' # This should be a valid document ID +assign_doc_result = client.assign_document_to_collection(document_id, collection_id) + +print(f"Assign document to collection result: {assign_doc_result}") +# {'results': {'message': 'Document successfully assigned to the collection'}} +``` + +### Removing a Document from a Collection + +To remove a document from a collection: + +```python +remove_doc_result = client.remove_document_from_collection(document_id, collection_id) + +print(f"Remove document from collection result: {remove_doc_result}") +# {'results': {'message': 'Document successfully removed from the collection'}} +``` + +### Listing Documents in a Collection + +To get a list of all documents in a specific collection: + +```python +docs_in_collection = client.documents_in_collection(collection_id) + +print(f"Documents in collection: {docs_in_collection}") +# {'results': [{'document_id': '789g012j-k34l-56m7-n890-123456789012', 'title': 'Marketing Strategy 2024', ...}, ...]} +``` + +### Getting Collections for a Document + +To get all collections that a document is assigned to: + +```python +document_collections = client.document_collections(document_id) + +print(f"Document's collections: {document_collections}") +# {'results': [{'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', ...}, ...]} +``` + +## Advanced Collection Management + +### Collection Overview + +To get an overview of collection, including user and document counts: + +```python +collections_overview = client.collections_overview() + +print(f"Collections overview: {collections_overview}") +# {'results': [{'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'user_count': 5, 'document_count': 10, ...}, ...]} +``` + +### Deleting a Collection + +To delete a collection: + +```python +delete_result = client.delete_collection(collection_id) + +print(f"Delete collection result: {delete_result}") +# {'results': {'message': 'Collection successfully deleted'}} +``` + +## Pagination and Filtering + +Many of the collection-related methods support pagination and filtering. Here are some examples: + +```python +# List collections with pagination +paginated_collection = client.list_collections(offset=10, limit=20) + +# Get users in a collection with pagination +paginated_users = client.get_users_in_collection(collection_id, offset=5, limit=10) + +# Get documents in a collection with pagination +paginated_docs = client.documents_in_collection(collection_id, offset=0, limit=50) + +# Get collections overview with specific collection IDs +specific_collections_overview = client.collections_overview(collection_ids=['id1', 'id2', 'id3']) +``` + +## Security Considerations + +When implementing collection permissions, consider the following security best practices: + +1. **Least Privilege Principle**: Assign the minimum necessary permissions to users and collections. +2. **Regular Audits**: Periodically review collection memberships and document assignments. +3. **Access Control**: Ensure that only authorized users (e.g., admins) can perform collection management operations. +4. **Logging and Monitoring**: Implement comprehensive logging for all collection-related actions. + +## Customizing Collection Permissions + +While R2R's current collection system follows a flat hierarchy, you can build more complex permission structures on top of it: + +1. **Custom Roles**: Implement application-level roles within collections (e.g., collection admin, editor, viewer). +2. **Hierarchical Collections**: Create a hierarchy by establishing parent-child relationships between collections in your application logic. +3. **Permission Inheritance**: Implement rules for permission inheritance based on collection memberships. + +## Troubleshooting + +Here are some common issues and their solutions: + +1. **Unable to Create/Modify Collections**: Ensure the user has superuser privileges. +2. **User Not Seeing Collection Content**: Verify that the user is correctly added to the collection and that documents are properly assigned. +3. **Performance Issues with Large Collections**: Use pagination when retrieving users or documents in large collections. + +## Conclusion + +R2R's collection permissioning system provides a foundation for implementing sophisticated access control in your applications. As the feature set evolves, more advanced capabilities will become available. Stay tuned to the R2R documentation for updates and new features related to collection permissions. + +For user authentication and individual user management, refer to the [User Auth Cookbook](/cookbooks/user-auth). For more advanced use cases or custom implementations, consult the R2R documentation or reach out to the community for support. diff --git a/docs/cookbooks/graphrag.mdx b/docs/cookbooks/graphrag.mdx index ffcd606bc..f9d314650 100644 --- a/docs/cookbooks/graphrag.mdx +++ b/docs/cookbooks/graphrag.mdx @@ -154,7 +154,7 @@ r2r documents-overview ``` ```bash Example Response -{'id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1', 'title': 'aristotle.txt', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', 'type': 'txt', 'created_at': '2024-09-05T18:20:47.921933Z', 'updated_at': '2024-09-05T18:20:47.921938Z', 'ingestion_status': 'success', 'restructuring_status': 'pending', 'version': 'v0', 'group_ids': [], 'metadata': {'version': 'v0'}} +{'id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1', 'title': 'aristotle.txt', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', 'type': 'txt', 'created_at': '2024-09-05T18:20:47.921933Z', 'updated_at': '2024-09-05T18:20:47.921938Z', 'ingestion_status': 'success', 'restructuring_status': 'pending', 'version': 'v0', 'collection_ids': [], 'metadata': {'version': 'v0'}} ``` When ingestion completes successfully for a given file we will find that `ingestion_status` reads `success` in the corresponding output. @@ -261,7 +261,7 @@ Vector search results: 'extraction_id': '92d78034-8447-5046-bf4d-e019932fbc20', 'document_id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', - 'group_ids': [], + 'collection_ids': [], 'score': 0.7393344796100582, 'text': 'Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.\n\nLittle is known about Aristotle's life. He was born in the city of Stagira in northern Greece during the Classical period. His father, Nicomachus, died when Aristotle was a child, and he was brought up by a guardian. At 17 or 18, he joined Plato's Academy in Athens and remained there until the age of 37 (c.\u2009347 BC). Shortly after Plato died, Aristotle left Athens and, at the request of Philip II of Macedon, tutored his son Alexander the Great beginning in 343 BC. He established a library in the Lyceum, which helped him to produce many of his hundreds of books on papyrus scrolls.\n\nThough Aristotle wrote many elegant treatises and dia ...", 'metadata': {'title': 'aristotle.txt', 'version': 'v0', 'file_name': 'tmpm3ceiqs__aristotle.txt', 'chunk_order': 0, 'document_type': 'txt', 'size_in_bytes': 73353, 'unstructured_filetype': 'text/plain', 'unstructured_languages': ['eng'], 'partitioned_by_unstructured': True, 'associatedQuery': 'Who is Aristotle?'}} diff --git a/docs/cookbooks/groups.mdx b/docs/cookbooks/groups.mdx deleted file mode 100644 index 0001b125f..000000000 --- a/docs/cookbooks/groups.mdx +++ /dev/null @@ -1,229 +0,0 @@ ---- -title: 'Group Permissions' -description: 'A comprehensive guide to group permissioning in R2R' -icon: 'users' ---- - -## Introduction - -R2R provides robust group management features, allowing developers to implement efficient access control and organization of users and documents. This cookbook will guide you through the group permissioning capabilities of R2R. - -For user authentication and management, please refer to the [User Auth Cookbook](/cookbooks/user-auth). - - -Group permissioning in R2R is still under development and as a result the API will likely evolve. - - -## Setup - -Ensure you have R2R installed and configured as described in the [installation guide](/documentation/installation). For this guide, we'll use the default configuration. Make sure `r2r serve` is running in your local environment or local Docker engine. - -## Basic Usage - - -Groups currently follow a flat hierarchy wherein superusers are responsible for management operations. This functionality will expand as development on R2R continues. - - -### Creating a Group - -Let's start by creating a new group: - -```python -from r2r import R2RClient - -client = R2RClient("http://localhost:7272") # Replace with your R2R deployment URL - -# Assuming you're logged in as an admin or a user with appropriate permissions -# For testing, the default R2R implementation will grant superuser privileges to anon api calls -group_result = client.create_group("Marketing Team", "Group for marketing department") -print(f"Group creation result: {group_result}") -# {'results': {'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', 'description': 'Group for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z'}} -``` - -### Getting Group Details - -To retrieve details about a specific group: - -```python -group_id = '123e4567-e89b-12d3-a456-426614174000' # Use the group_id from the creation result -group_details = client.get_group(group_id) -print(f"Group details: {group_details}") -# {'results': {'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', 'description': 'Group for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z'}} -``` - -### Updating a Group - -You can update a group's name or description: - -```python -update_result = client.update_group(group_id, name="Updated Marketing Team", description="New description for marketing team") -print(f"Group update result: {update_result}") -# {'results': {'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z'}} -``` - -### Listing Groups - -To get a list of all groups: - -```python -groups_list = client.list_groups() -print(f"Groups list: {groups_list}") -# {'results': [{'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z'}, ...]} -``` - -## User Management in Groups - -### Adding a User to a Group - -To add a user to a group, you need both the user's ID and the group's ID: - -```python -user_id = '456e789f-g01h-34i5-j678-901234567890' # This should be a valid user ID -add_user_result = client.add_user_to_group(user_id, group_id) -print(f"Add user to group result: {add_user_result}") -# {'results': {'message': 'User successfully added to the group'}} -``` - -### Removing a User from a Group - -Similarly, to remove a user from a group: - -```python -remove_user_result = client.remove_user_from_group(user_id, group_id) -print(f"Remove user from group result: {remove_user_result}") -# {'results': {'message': 'User successfully removed from the group'}} -``` - -### Listing Users in a Group - -To get a list of all users in a specific group: - -```python -users_in_group = client.get_users_in_group(group_id) -print(f"Users in group: {users_in_group}") -# {'results': [{'user_id': '456e789f-g01h-34i5-j678-901234567890', 'email': 'user@example.com', 'name': 'John Doe', ...}, ...]} -``` - -### Getting Groups for a User - -To get all groups that a user is a member of: - -```python -user_groups = client.user_groups(user_id) -print(f"User's groups: {user_groups}") -# {'results': [{'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', ...}, ...]} -``` - -## Document Management in Groups - -### Assigning a Document to a Group - -To assign a document to a group: - -```python -document_id = '789g012j-k34l-56m7-n890-123456789012' # This should be a valid document ID -assign_doc_result = client.assign_document_to_group(document_id, group_id) -print(f"Assign document to group result: {assign_doc_result}") -# {'results': {'message': 'Document successfully assigned to the group'}} -``` - -### Removing a Document from a Group - -To remove a document from a group: - -```python -remove_doc_result = client.remove_document_from_group(document_id, group_id) -print(f"Remove document from group result: {remove_doc_result}") -# {'results': {'message': 'Document successfully removed from the group'}} -``` - -### Listing Documents in a Group - -To get a list of all documents in a specific group: - -```python -docs_in_group = client.documents_in_group(group_id) -print(f"Documents in group: {docs_in_group}") -# {'results': [{'document_id': '789g012j-k34l-56m7-n890-123456789012', 'title': 'Marketing Strategy 2024', ...}, ...]} -``` - -### Getting Groups for a Document - -To get all groups that a document is assigned to: - -```python -document_groups = client.document_groups(document_id) -print(f"Document's groups: {document_groups}") -# {'results': [{'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', ...}, ...]} -``` - -## Advanced Group Management - -### Group Overview - -To get an overview of groups, including user and document counts: - -```python -groups_overview = client.groups_overview() -print(f"Groups overview: {groups_overview}") -# {'results': [{'group_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'user_count': 5, 'document_count': 10, ...}, ...]} -``` - -### Deleting a Group - -To delete a group: - -```python -delete_result = client.delete_group(group_id) -print(f"Delete group result: {delete_result}") -# {'results': {'message': 'Group successfully deleted'}} -``` - -## Pagination and Filtering - -Many of the group-related methods support pagination and filtering. Here are some examples: - -```python -# List groups with pagination -paginated_groups = client.list_groups(offset=10, limit=20) - -# Get users in a group with pagination -paginated_users = client.get_users_in_group(group_id, offset=5, limit=10) - -# Get documents in a group with pagination -paginated_docs = client.documents_in_group(group_id, offset=0, limit=50) - -# Get groups overview with specific group IDs -specific_groups_overview = client.groups_overview(group_ids=['id1', 'id2', 'id3']) -``` - -## Security Considerations - -When implementing group permissions, consider the following security best practices: - -1. **Least Privilege Principle**: Assign the minimum necessary permissions to users and groups. -2. **Regular Audits**: Periodically review group memberships and document assignments. -3. **Access Control**: Ensure that only authorized users (e.g., admins) can perform group management operations. -4. **Logging and Monitoring**: Implement comprehensive logging for all group-related actions. - -## Customizing Group Permissions - -While R2R's current group system follows a flat hierarchy, you can build more complex permission structures on top of it: - -1. **Custom Roles**: Implement application-level roles within groups (e.g., group admin, editor, viewer). -2. **Hierarchical Groups**: Create a hierarchy by establishing parent-child relationships between groups in your application logic. -3. **Permission Inheritance**: Implement rules for permission inheritance based on group memberships. - -## Troubleshooting - -Here are some common issues and their solutions: - -1. **Unable to Create/Modify Groups**: Ensure the user has superuser privileges. -2. **User Not Seeing Group Content**: Verify that the user is correctly added to the group and that documents are properly assigned. -3. **Performance Issues with Large Groups**: Use pagination when retrieving users or documents in large groups. - -## Conclusion - -R2R's group permissioning system provides a foundation for implementing sophisticated access control in your applications. As the feature set evolves, more advanced capabilities will become available. Stay tuned to the R2R documentation for updates and new features related to group permissions. - -For user authentication and individual user management, refer to the [User Auth Cookbook](/cookbooks/user-auth). For more advanced use cases or custom implementations, consult the R2R documentation or reach out to the community for support. diff --git a/docs/cookbooks/user-auth.mdx b/docs/cookbooks/user-auth.mdx index 2d0f88d67..b9b821bd5 100644 --- a/docs/cookbooks/user-auth.mdx +++ b/docs/cookbooks/user-auth.mdx @@ -104,7 +104,7 @@ Users can change their passwords and request password resets: ```python # Change password -change_password_result = client.change_password("old_password", "new_password") +change_password_result = client.change_password("password123", "new_password") # {"result": {"message": "Password changed successfully"}} # Request password reset @@ -126,7 +126,7 @@ profile = client.user() # {'results': {'email': 'user1@test.com', 'id': '76eea168-9f98-4672-af3b-2c26ec92d7f8', 'hashed_password': 'null', 'is_superuser': False, 'is_active': True, 'is_verified': True, 'verification_code_expiry': None, 'name': None, 'bio': None, 'profile_picture': None, 'created_at': '2024-07-16T23:06:42.123303Z', 'updated_at': '2024-07-16T23:22:48.256239Z'}} # Update user profile -update_result = client.update_user_profile({"name": "John Doe", "bio": "R2R enthusiast"}) +update_result = client.update_user(name="John Doe", bio="R2R enthusiast") # {'results': {'email': 'user1@test.com', 'id': '76eea168-9f98-4672-af3b-2c26ec92d7f8', 'hashed_password': 'null', 'is_superuser': False, 'is_active': True, 'is_verified': True, 'verification_code_expiry': None, 'name': 'John Doe', 'bio': 'R2R enthusiast', 'profile_picture': None, 'created_at': '2024-07-16T23:06:42.123303Z', 'updated_at': '2024-07-16T23:22:48.256239Z'}} ``` diff --git a/docs/cookbooks/walkthrough.mdx b/docs/cookbooks/walkthrough.mdx index c8aa1d4a2..b0dcabfda 100644 --- a/docs/cookbooks/walkthrough.mdx +++ b/docs/cookbooks/walkthrough.mdx @@ -107,7 +107,7 @@ R2R efficiently handles diverse document types using Postgres with pgvector, com Key features include: - Unique `document_id` generation for each ingested file -- User and group permissioning through `user_id` and `group_ids` +- User and collection permissions through `user_id` and `collection_ids` - Document versioning for tracking changes over time - Granular access to document content through chunk retrieval - Flexible deletion and update mechanisms @@ -165,7 +165,7 @@ This command initiates the ingestion process, producing output similar to: Key features of the ingestion process: 1. Unique `document_id` generation for each file -2. Metadata association, including `user_id` and `group_ids` for document management +2. Metadata association, including `user_id` and `collection_ids` for document management 3. Efficient parsing, chunking, and embedding of diverse file types @@ -222,7 +222,7 @@ This command returns document metadata, including: 'ingestion_status': 'success', 'restructuring_status': 'pending', 'version': 'v0', - 'group_ids': [], + 'collection_ids': [], 'metadata': {'title': 'aristotle.txt', 'version': 'v0'} } ... @@ -508,7 +508,7 @@ curl -X POST http://localhost:7272/v2/search \ 'extraction_id': '429976dd-4350-5033-b06d-8ffb67d7e8c8', 'document_id': '26e0b128-3043-5674-af22-a6f7b0e54769', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', - 'group_ids': [], + 'collection_ids': [], 'score': 0.285747126074015, 'text': 'Net\n loss attributable to Uber Technologies, Inc. was $496 million, a 93% improvement year-over-year, driven by a $1.6 billion pre-tax gain on the sale of ourATG\n Business to Aurora, a $1.6 billion pre-tax net benefit relating to Ubers equity investments, as well as reductions in our fixed cost structure and increasedvariable cost effi\nciencies. Net loss attributable to Uber Technologies, Inc. also included $1.2 billion of stock-based compensation expense.Adjusted', 'metadata': {'title': 'uber_2021.pdf', 'version': 'v0', 'chunk_order': 5, 'associatedQuery': "What was Uber's profit in 2020?"} diff --git a/docs/documentation/configuration/postgres.mdx b/docs/documentation/configuration/postgres.mdx index a6fb34b6d..97e4c435a 100644 --- a/docs/documentation/configuration/postgres.mdx +++ b/docs/documentation/configuration/postgres.mdx @@ -46,7 +46,7 @@ export POSTGRES_PASSWORD=your_postgres_password export POSTGRES_HOST=your_postgres_host export POSTGRES_PORT=your_postgres_port export POSTGRES_DBNAME=your_database_name -export POSTGRES_VECS_COLLECTION=your_vector_collection_name +export POSTGRES_PROJECT_NAME=your_vector_collection_name ``` ## Advanced Postgres Features in R2R diff --git a/docs/documentation/configuration/rag.mdx b/docs/documentation/configuration/rag.mdx index 9c62f57b7..17eb8b5ad 100644 --- a/docs/documentation/configuration/rag.mdx +++ b/docs/documentation/configuration/rag.mdx @@ -36,7 +36,7 @@ vector_search_settings = { "filters": {"metadata.document_type": "article"}, "search_limit": 20, "use_hybrid_search": True, - "selected_group_ids": ["c3291abf-8a4e-5d9d-80fd-232ef6fd8526"] + "selected_collection_ids": ["c3291abf-8a4e-5d9d-80fd-232ef6fd8526"] } # Configure graphRAG search diff --git a/docs/documentation/configuration/retrieval/vector-search.mdx b/docs/documentation/configuration/retrieval/vector-search.mdx index de7a0c0d3..b923007b5 100644 --- a/docs/documentation/configuration/retrieval/vector-search.mdx +++ b/docs/documentation/configuration/retrieval/vector-search.mdx @@ -13,7 +13,7 @@ vector_search_settings = { "filters": {"metadata.document_type": "article"}, "search_limit": 20, "use_hybrid_search": True, - "selected_group_ids": ["c3291abf-8a4e-5d9d-80fd-232ef6fd8526"] + "selected_collection_ids": ["c3291abf-8a4e-5d9d-80fd-232ef6fd8526"] } response = client.search("query", vector_search_settings=vector_search_settings) @@ -27,7 +27,7 @@ response = client.search("query", vector_search_settings=vector_search_settings) 2. `use_hybrid_search` (bool): Whether to perform a hybrid search (combining vector and keyword search) 3. `filters` (dict): Filters to apply to the vector search 4. `search_limit` (int): Maximum number of results to return (1-1000) -5. `selected_group_ids` (list[UUID]): Group IDs to search for +5. `selected_collection_ids` (list[UUID]): Group IDs to search for 6. `index_measure` (IndexMeasure): The distance measure to use for indexing (cosine_distance, l2_distance, or max_inner_product) 7. `include_values` (bool): Whether to include search score values in the search results 8. `include_metadatas` (bool): Whether to include element metadata in the search results diff --git a/docs/documentation/deep-dive/providers/auth.mdx b/docs/documentation/deep-dive/providers/auth.mdx index 3f303c34f..c988b40e1 100644 --- a/docs/documentation/deep-dive/providers/auth.mdx +++ b/docs/documentation/deep-dive/providers/auth.mdx @@ -101,7 +101,7 @@ The AuthProvider is responsible for providing functionality to support these cor 8. `confirm_password_reset`: Complete password reset 9. `verify_email`: Email verification 10. `get_user_profile`: Fetch user profile -11. `update_user_profile`: Modify user profile +11. `update_user`: Modify user profile 12. `delete_user_account`: Account deletion ## Implementation Guide diff --git a/docs/documentation/deep-dive/providers/database.mdx b/docs/documentation/deep-dive/providers/database.mdx index 2baa4b75c..54c48814a 100644 --- a/docs/documentation/deep-dive/providers/database.mdx +++ b/docs/documentation/deep-dive/providers/database.mdx @@ -40,7 +40,7 @@ export POSTGRES_PASSWORD=your_postgres_password export POSTGRES_HOST=your_postgres_host export POSTGRES_PORT=your_postgres_port export POSTGRES_DBNAME=your_database_name -export POSTGRES_VECS_COLLECTION=your_collection_name +export POSTGRES_PROJECT_NAME=your_collection_name ``` Environment variables take precedence over the config settings in case of conflicts. The R2R Docker includes configuration options that facilitate integration with a combined Postgres+pgvector database setup. diff --git a/docs/documentation/deployment/azure.mdx b/docs/documentation/deployment/azure.mdx index e03d5a66d..4f962eec9 100644 --- a/docs/documentation/deployment/azure.mdx +++ b/docs/documentation/deployment/azure.mdx @@ -151,7 +151,7 @@ Sample file ingestion completed. Ingest files response: [{'message': 'Ingestion task queued successfully.', 'task_id': '887f9f99-cc18-4c1e-8f61-facf1d212334', 'document_id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1'}] Vector search results: -{'fragment_id': 'ecc754cd-380d-585f-84ac-021542ef3c1d', 'extraction_id': '92d78034-8447-5046-bf4d-e019932fbc20', 'document_id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', 'group_ids': [], 'score': 0.7822163571248282, 'text': 'Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.', 'metadata': {'title': 'aristotle.txt', 'version': 'v0', 'chunk_order': 0, 'document_type': 'txt', 'unstructured_filetype': 'text/plain', 'unstructured_languages': ['eng'], 'partitioned_by_unstructured': True, 'associatedQuery': 'Who was aristotle?'}} +{'fragment_id': 'ecc754cd-380d-585f-84ac-021542ef3c1d', 'extraction_id': '92d78034-8447-5046-bf4d-e019932fbc20', 'document_id': '9fbe403b-c11c-5aae-8ade-ef22980c3ad1', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', 'collection_ids': [], 'score': 0.7822163571248282, 'text': 'Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.', 'metadata': {'title': 'aristotle.txt', 'version': 'v0', 'chunk_order': 0, 'document_type': 'txt', 'unstructured_filetype': 'text/plain', 'unstructured_languages': ['eng'], 'partitioned_by_unstructured': True, 'associatedQuery': 'Who was aristotle?'}} ... ``` diff --git a/docs/documentation/deployment/troubleshooting/vector_store_issues.mdx b/docs/documentation/deployment/troubleshooting/vector_store_issues.mdx index 7284432b6..0d9338a69 100644 --- a/docs/documentation/deployment/troubleshooting/vector_store_issues.mdx +++ b/docs/documentation/deployment/troubleshooting/vector_store_issues.mdx @@ -19,7 +19,7 @@ Vector storage is a crucial component in R2R (RAG to Riches) for efficient simil - `POSTGRES_HOST` - `POSTGRES_PORT` - `POSTGRES_DBNAME` - - `POSTGRES_VECS_COLLECTION` + - `POSTGRES_PROJECT_NAME` 3. **Check Docker Network:** If using Docker, ensure the R2R and Postgres containers are on the same network: diff --git a/docs/documentation/installation/local-system.mdx b/docs/documentation/installation/local-system.mdx index 29c7d5948..cdebe2b18 100644 --- a/docs/documentation/installation/local-system.mdx +++ b/docs/documentation/installation/local-system.mdx @@ -68,10 +68,10 @@ R2R requires connections to various services. Set up the following environment v export POSTGRES_HOST=$YOUR_POSTGRES_HOST export POSTGRES_PORT=$YOUR_POSTGRES_PORT export POSTGRES_DBNAME=$YOUR_POSTGRES_DBNAME - export POSTGRES_VECS_COLLECTION=$YOUR_VECS_COLLECTION # see note below + export POSTGRES_PROJECT_NAME=$YOUR_VECS_COLLECTION # see note below ``` - The `POSTGRES_VECS_COLLECTION` environment variable defines the collection within your Postgres database where R2R related tables reside. If the specified collection does not exist then it will be created by R2R during initialization. + The `POSTGRES_PROJECT_NAME` environment variable defines the collection within your Postgres database where R2R related tables reside. If the specified collection does not exist then it will be created by R2R during initialization. diff --git a/docs/documentation/js-sdk/auth.mdx b/docs/documentation/js-sdk/auth.mdx index 3cc736c57..ca66f1753 100644 --- a/docs/documentation/js-sdk/auth.mdx +++ b/docs/documentation/js-sdk/auth.mdx @@ -158,7 +158,7 @@ const refreshResponse = await client.refreshAccessToken(); Change the user's password: ```javascript -const changePasswordResult = await client.changePassword("old_password", "new_password"); +const changePasswordResult = await client.changePassword("password123", "new_password"); ``` diff --git a/docs/documentation/js-sdk/retrieval.mdx b/docs/documentation/js-sdk/retrieval.mdx index 5e1360678..cdaadf2ca 100644 --- a/docs/documentation/js-sdk/retrieval.mdx +++ b/docs/documentation/js-sdk/retrieval.mdx @@ -69,7 +69,7 @@ const searchResponse = await client.search("What was Uber's profit in 2020?"); Maximum number of results to return (1-1000). - + Group IDs to search for. @@ -268,7 +268,7 @@ const ragResponse = await client.rag("What was Uber's profit in 2020?"); Maximum number of results to return (1-1000). - + Group IDs to search for. diff --git a/docs/documentation/python-sdk/auth.mdx b/docs/documentation/python-sdk/auth.mdx index ebd8394e8..5b74a40cd 100644 --- a/docs/documentation/python-sdk/auth.mdx +++ b/docs/documentation/python-sdk/auth.mdx @@ -224,7 +224,7 @@ reset_confirm_result = client.confirm_password_reset("reset_token_here", "new_pa Update the user's profile information: ```python -update_result = client.update_user(**{"name": "John Doe", "bio": "R2R enthusiast"}) +update_result = client.update_user(name="John Doe", bio="R2R enthusiast") ``` diff --git a/docs/documentation/python-sdk/groups.mdx b/docs/documentation/python-sdk/collections.mdx similarity index 53% rename from docs/documentation/python-sdk/groups.mdx rename to docs/documentation/python-sdk/collections.mdx index 44162be5f..6b3b2e8c5 100644 --- a/docs/documentation/python-sdk/groups.mdx +++ b/docs/documentation/python-sdk/collections.mdx @@ -1,24 +1,26 @@ --- -title: 'Group Management' -description: 'Manage group permissions in R2R' +title: 'Collection Management' +description: 'Manage collections in R2R' --- -R2R provides a comprehensive set of group management features, allowing you to implement efficient access control and organization of users and documents in your applications. +A collection in R2R is a logical grouping of users and documents that allows for efficient access control and organization. Collections enable you to manage permissions and access to documents at a collection level, rather than individually. + +R2R provides a comprehensive set of collection features, allowing you to implement efficient access control and organization of users and documents in your applications. -Group permissioning in R2R is still under development and as a result the API will likely evolve. +Collection permissioning in R2R is still under development and as a result the API will likely evolve. -## Group Creation and Management +## Collection creation and Management -### Create a Group +### Create a Collection -Create a new group with a name and optional description: +Create a new collection with a name and optional description: ```python -create_group_response = client.create_group("Marketing Team", "Group for marketing department") +create_collection_response = client.create_collection("Marketing Team", "Collection for marketing department") ``` @@ -27,9 +29,9 @@ create_group_response = client.create_group("Marketing Team", "Group for marketi ```python { 'results': { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', - 'description': 'Group for marketing department', + 'description': 'Collection for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z' } @@ -39,12 +41,12 @@ create_group_response = client.create_group("Marketing Team", "Group for marketi -### Get Group Details +### Get Collection details -Retrieve details about a specific group: +Retrieve details about a specific collection: ```python -group_details = client.get_group('123e4567-e89b-12d3-a456-426614174000') +collection_details = client.get_collection('123e4567-e89b-12d3-a456-426614174000') ``` @@ -53,9 +55,9 @@ group_details = client.get_group('123e4567-e89b-12d3-a456-426614174000') ```python { 'results': { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Marketing Team', - 'description': 'Group for marketing department', + 'description': 'Collection for marketing department', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T22:53:47.524794Z' } @@ -65,12 +67,12 @@ group_details = client.get_group('123e4567-e89b-12d3-a456-426614174000') -### Update a Group +### Update a Collection -Update a group's name or description: +Update a collection's name or description: ```python -update_result = client.update_group('123e4567-e89b-12d3-a456-426614174000', +update_result = client.update_collection('123e4567-e89b-12d3-a456-426614174000', name="Updated Marketing Team", description="New description for marketing team") ``` @@ -81,7 +83,7 @@ update_result = client.update_group('123e4567-e89b-12d3-a456-426614174000', ```python { 'results': { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', @@ -93,12 +95,12 @@ update_result = client.update_group('123e4567-e89b-12d3-a456-426614174000', -### List Groups +### List Collections -Get a list of all groups: +Get a list of all collections: ```python -groups_list = client.list_groups() +collections_list = client.list_collections() ``` @@ -108,13 +110,13 @@ groups_list = client.list_groups() { 'results': [ { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z' }, - # ... other groups ... + # ... other collections ... ] } ``` @@ -122,14 +124,14 @@ groups_list = client.list_groups() -## User Management in Groups +## User Management in Collections -### Add User to Group +### Add User to Collection -Add a user to a group: +Add a user to a collection: ```python -add_user_result = client.add_user_to_group('456e789f-g01h-34i5-j678-901234567890', '123e4567-e89b-12d3-a456-426614174000') +add_user_result = client.add_user_to_collection('456e789f-g01h-34i5-j678-901234567890', '123e4567-e89b-12d3-a456-426614174000') ``` @@ -138,7 +140,7 @@ add_user_result = client.add_user_to_group('456e789f-g01h-34i5-j678-901234567890 ```python { 'results': { - 'message': 'User successfully added to the group' + 'message': 'User successfully added to the collection' } } ``` @@ -146,12 +148,12 @@ add_user_result = client.add_user_to_group('456e789f-g01h-34i5-j678-901234567890 -### Remove User from Group +### Remove User from Collection -Remove a user from a group: +Remove a user from a collection: ```python -remove_user_result = client.remove_user_from_group('456e789f-g01h-34i5-j678-901234567890', '123e4567-e89b-12d3-a456-426614174000') +remove_user_result = client.remove_user_from_collection('456e789f-g01h-34i5-j678-901234567890', '123e4567-e89b-12d3-a456-426614174000') ``` @@ -160,7 +162,7 @@ remove_user_result = client.remove_user_from_group('456e789f-g01h-34i5-j678-9012 ```python { 'results': { - 'message': 'User successfully removed from the group' + 'message': 'User successfully removed from the collection' } } ``` @@ -168,12 +170,12 @@ remove_user_result = client.remove_user_from_group('456e789f-g01h-34i5-j678-9012 -### List Users in Group +### List Users in Collection -Get a list of all users in a specific group: +Get a list of all users in a specific collection: ```python -users_in_group = client.get_users_in_group('123e4567-e89b-12d3-a456-426614174000') +users_in_collection = client.get_users_in_collection('123e4567-e89b-12d3-a456-426614174000') ``` @@ -196,12 +198,12 @@ users_in_group = client.get_users_in_group('123e4567-e89b-12d3-a456-426614174000 -### Get User's Groups +### Get User's Collections -Get all groups that a user is a member of: +Get all collections that a user is a member of: ```python -user_groups = client.user_groups('456e789f-g01h-34i5-j678-901234567890') +user_collections = client.user_collections('456e789f-g01h-34i5-j678-901234567890') ``` @@ -211,11 +213,11 @@ user_groups = client.user_groups('456e789f-g01h-34i5-j678-901234567890') { 'results': [ { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', - # ... other group details ... + # ... other Collection details ... }, - # ... other groups ... + # ... other collections ... ] } ``` @@ -223,14 +225,14 @@ user_groups = client.user_groups('456e789f-g01h-34i5-j678-901234567890') -## Document Management in Groups +## Document Management in Collections -### Assign Document to Group +### Assign Document to Collection -Assign a document to a group: +Assign a document to a collection: ```python -assign_doc_result = client.assign_document_to_group('789g012j-k34l-56m7-n890-123456789012', '123e4567-e89b-12d3-a456-426614174000') +assign_doc_result = client.assign_document_to_collection('789g012j-k34l-56m7-n890-123456789012', '123e4567-e89b-12d3-a456-426614174000') ``` @@ -239,7 +241,7 @@ assign_doc_result = client.assign_document_to_group('789g012j-k34l-56m7-n890-123 ```python { 'results': { - 'message': 'Document successfully assigned to the group' + 'message': 'Document successfully assigned to the collection' } } ``` @@ -247,12 +249,12 @@ assign_doc_result = client.assign_document_to_group('789g012j-k34l-56m7-n890-123 -### Remove Document from Group +### Remove Document from Collection -Remove a document from a group: +Remove a document from a collection: ```python -remove_doc_result = client.remove_document_from_group('789g012j-k34l-56m7-n890-123456789012', '123e4567-e89b-12d3-a456-426614174000') +remove_doc_result = client.remove_document_from_collection('789g012j-k34l-56m7-n890-123456789012', '123e4567-e89b-12d3-a456-426614174000') ``` @@ -261,7 +263,7 @@ remove_doc_result = client.remove_document_from_group('789g012j-k34l-56m7-n890-1 ```python { 'results': { - 'message': 'Document successfully removed from the group' + 'message': 'Document successfully removed from the collection' } } ``` @@ -269,12 +271,12 @@ remove_doc_result = client.remove_document_from_group('789g012j-k34l-56m7-n890-1 -### List Documents in Group +### List Documents in Collection -Get a list of all documents in a specific group: +Get a list of all documents in a specific collection: ```python -docs_in_group = client.documents_in_group('123e4567-e89b-12d3-a456-426614174000') +docs_in_collection = client.documents_in_collection('123e4567-e89b-12d3-a456-426614174000') ``` @@ -296,12 +298,12 @@ docs_in_group = client.documents_in_group('123e4567-e89b-12d3-a456-426614174000' -### Get Document's Groups +### Get Document's Collections -Get all groups that a document is assigned to: +Get all collections that a document is assigned to: ```python -document_groups = client.document_groups('789g012j-k34l-56m7-n890-123456789012') +document_collections = client.document_collections('789g012j-k34l-56m7-n890-123456789012') ``` @@ -311,11 +313,11 @@ document_groups = client.document_groups('789g012j-k34l-56m7-n890-123456789012') { 'results': [ { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', - # ... other group details ... + # ... other Collection details ... }, - # ... other groups ... + # ... other collections ... ] } ``` @@ -323,14 +325,14 @@ document_groups = client.document_groups('789g012j-k34l-56m7-n890-123456789012') -## Advanced Group Management +## Advanced Collection Management -### Group Overview +### Collection Overview -Get an overview of groups, including user and document counts: +Get an overview of collections, including user and document counts: ```python -groups_overview = client.groups_overview() +collections_overview = client.collections_overview() ``` @@ -340,7 +342,7 @@ groups_overview = client.groups_overview() { 'results': [ { - 'group_id': '123e4567-e89b-12d3-a456-426614174000', + 'collection_id': '123e4567-e89b-12d3-a456-426614174000', 'name': 'Updated Marketing Team', 'description': 'New description for marketing team', 'user_count': 5, @@ -348,7 +350,7 @@ groups_overview = client.groups_overview() 'created_at': '2024-07-16T22:53:47.524794Z', 'updated_at': '2024-07-16T23:15:30.123456Z' }, - # ... other groups ... + # ... other collections ... ] } ``` @@ -356,12 +358,12 @@ groups_overview = client.groups_overview() -### Delete a Group +### Delete a Collection -Delete a group: +Delete a collection: ```python -delete_result = client.delete_group('123e4567-e89b-12d3-a456-426614174000') +delete_result = client.delete_collection('123e4567-e89b-12d3-a456-426614174000') ``` @@ -380,31 +382,31 @@ delete_result = client.delete_group('123e4567-e89b-12d3-a456-426614174000') ## Pagination and Filtering -Many group-related methods support pagination and filtering: +Many collection-related methods support pagination and filtering: ```python -# List groups with pagination -paginated_groups = client.list_groups(offset=10, limit=20) +# List collections with pagination +paginated_collection = client.list_collections(offset=10, limit=20) -# Get users in a group with pagination -paginated_users = client.get_users_in_group('123e4567-e89b-12d3-a456-426614174000', offset=5, limit=10) +# Get users in a collection with pagination +paginated_users = client.get_users_in_collection('123e4567-e89b-12d3-a456-426614174000', offset=5, limit=10) -# Get documents in a group with pagination -paginated_docs = client.documents_in_group('123e4567-e89b-12d3-a456-426614174000', offset=0, limit=50) +# Get documents in a collection with pagination +paginated_docs = client.documents_in_collection('123e4567-e89b-12d3-a456-426614174000', offset=0, limit=50) -# Get groups overview with specific group IDs -specific_groups_overview = client.groups_overview(group_ids=['id1', 'id2', 'id3']) +# Get collections overview with specific collection IDs +specific_collections_overview = client.collections_overview(collection_ids=['id1', 'id2', 'id3']) ``` ## Security Considerations -When implementing group permissions, consider the following security best practices: +When implementing collection permissions, consider the following security best practices: 1. Always use HTTPS in production to encrypt data in transit. -2. Implement the principle of least privilege by assigning the minimum necessary permissions to users and groups. -3. Regularly audit group memberships and document assignments. -4. Ensure that only authorized users (e.g., admins) can perform group management operations. -5. Implement comprehensive logging for all group-related actions. +2. Implement the principle of least privilege by assigning the minimum necessary permissions to users and collections. +3. Regularly audit collection memberships and document assignments. +4. Ensure that only authorized users (e.g., admins) can perform collection management operations. +5. Implement comprehensive logging for all collection-related actions. 6. Consider implementing additional access controls or custom roles within your application logic for more fine-grained permissions. For more advanced use cases or custom implementations, refer to the R2R documentation or reach out to the community for support. diff --git a/docs/documentation/python-sdk/ingestion.mdx b/docs/documentation/python-sdk/ingestion.mdx index 53bae46a5..c39c19c70 100644 --- a/docs/documentation/python-sdk/ingestion.mdx +++ b/docs/documentation/python-sdk/ingestion.mdx @@ -228,7 +228,7 @@ documents_overview = client.documents_overview() { 'document_id': '93123a68-d668-51de-8291-92162730dc87', 'version': 'v0', - 'group_ids': [], + 'collection_ids': [], 'ingestion_status': 'success', 'restructuring_status': 'pending', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', diff --git a/docs/documentation/python-sdk/retrieval.mdx b/docs/documentation/python-sdk/retrieval.mdx index 72e3125d5..b551eb9b1 100644 --- a/docs/documentation/python-sdk/retrieval.mdx +++ b/docs/documentation/python-sdk/retrieval.mdx @@ -28,7 +28,7 @@ search_response = client.search("What was Uber's profit in 2020?") 'extraction_id': '2b8ff2e9-c135-573d-bf8a-7a2db60a0a11', 'document_id': '3e157b3a-8469-51db-90d9-52e7d896b49b', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', - 'group_ids': [], + 'collection_ids': [], 'score': 0.7449709925072809, 'text': 'Net\n loss attributable to Uber Technologies, Inc. was $496 million, a 93% improvement ...', 'metadata': {'title': 'uber_2021.pdf', 'version': 'v0', 'chunk_order': 5, 'associatedQuery': "What was Uber's profit in 2020?"} @@ -67,7 +67,7 @@ search_response = client.search("What was Uber's profit in 2020?") Maximum number of results to return (1-1000). - + Group IDs to search for. @@ -330,7 +330,7 @@ rag_response = client.rag("What was Uber's profit in 2020?") Maximum number of results to return (1-1000). - + Group IDs to search for. @@ -640,7 +640,7 @@ Note that any of the customization seen in AI powered search and RAG documentati Maximum number of results to return (1-1000). - + Group IDs to search for. diff --git a/docs/documentation/quickstart.mdx b/docs/documentation/quickstart.mdx index 7c71be14a..44142d674 100644 --- a/docs/documentation/quickstart.mdx +++ b/docs/documentation/quickstart.mdx @@ -99,7 +99,7 @@ Example output: 'extraction_id': '8edf5123-0a5c-568c-bf97-654b6adaf8dc', 'document_id': 'db02076e-989a-59cd-98d5-e24e15a0bd27', 'user_id': '2acb499e-8428-543b-bd85-0d9098718220', - 'group_ids': [], + 'collection_ids': [], 'score': 0.780314067545999, 'text': 'Aristotle[A] (Greek: Ἀριστοτέλης Aristotélēs, pronounced [aristotélɛːs]; 384–322 BC) was an Ancient Greek philosopher and polymath. His writings cover a broad range of subjects spanning the natural sciences, philosophy, linguistics, economics, politics, psychology, and the arts. As the founder of the Peripatetic school of philosophy in the Lyceum in Athens, he began the wider Aristotelian tradition that followed, which set the groundwork for the development of modern science.', 'metadata': { diff --git a/docs/introduction.mdx b/docs/introduction.mdx index e44e0148e..803ce148c 100644 --- a/docs/introduction.mdx +++ b/docs/introduction.mdx @@ -48,7 +48,7 @@ R2R (RAG to Riches), the Elasticsearch for RAG, bridges the gap between experime - Auth & Admin Features - [Web Development](/cookbooks/web-dev): Building webapps using R2R - [User Auth](/cookbooks/user-auth): Authenticating users - - [Group Permissions](/cookbooks/groups): Group permissions + - [Collections](/cookbooks/collections): Document collections - [Analytics & Observability](/cookbooks/observability): End-to-end logging and analytics - [Web Application](/cookbooks/application): Connecting with the R2R Application diff --git a/docs/mint.json b/docs/mint.json index 367e0104e..d3890efc5 100644 --- a/docs/mint.json +++ b/docs/mint.json @@ -99,7 +99,7 @@ "documentation/python-sdk/ingestion", "documentation/python-sdk/retrieval", "documentation/python-sdk/auth", - "documentation/python-sdk/groups", + "documentation/python-sdk/collections", "documentation/python-sdk/observability" ] }, @@ -323,21 +323,21 @@ ] }, { - "group": "Groups", + "group": "Collections", "pages": [ - "api-reference/endpoint/create_group", - "api-reference/endpoint/get_group", - "api-reference/endpoint/update_group", - "api-reference/endpoint/delete_group", - "api-reference/endpoint/list_groups", - "api-reference/endpoint/add_user_to_group", - "api-reference/endpoint/remove_user_from_group", - "api-reference/endpoint/get_users_in_group", - "api-reference/endpoint/get_groups_for_user", - "api-reference/endpoint/groups_overview", - "api-reference/endpoint/assign_document_to_group", - "api-reference/endpoint/remove_document_from_group", - "api-reference/endpoint/get_document_groups" + "api-reference/endpoint/create_collection", + "api-reference/endpoint/get_collection", + "api-reference/endpoint/update_collection", + "api-reference/endpoint/delete_collection", + "api-reference/endpoint/list_collections", + "api-reference/endpoint/add_user_to_collection", + "api-reference/endpoint/remove_user_from_collection", + "api-reference/endpoint/get_users_in_collection", + "api-reference/endpoint/get_collections_for_user", + "api-reference/endpoint/collections_overview", + "api-reference/endpoint/assign_document_to_collection", + "api-reference/endpoint/remove_document_from_collection", + "api-reference/endpoint/get_document_collections" ] }, @@ -393,7 +393,7 @@ "group": "Auth & Admin", "pages": [ "cookbooks/user-auth", - "cookbooks/groups", + "cookbooks/collections", "cookbooks/observability", "cookbooks/application" ] diff --git a/go/sdk/pkg/sdk/management.go b/go/sdk/pkg/sdk/management.go index 19c9c15ca..bb16d4144 100644 --- a/go/sdk/pkg/sdk/management.go +++ b/go/sdk/pkg/sdk/management.go @@ -421,7 +421,7 @@ func (m *Management) GroupsOverview(groupIDs []string, limit, offset *int) (map[ if len(groupIDs) > 0 { for _, id := range groupIDs { - params.Add("group_ids", id) + params.Add("collection_ids", id) } } if limit != nil { @@ -431,7 +431,7 @@ func (m *Management) GroupsOverview(groupIDs []string, limit, offset *int) (map[ params.Set("offset", strconv.Itoa(*offset)) } - endpoint := "groups_overview" + endpoint := "collections_overview" if len(params) > 0 { endpoint += "?" + params.Encode() } @@ -473,7 +473,7 @@ func (m *Management) CreateGroup(name string, description *string) (map[string]i return nil, fmt.Errorf("error marshaling request data: %w", err) } - result, err := m.client.makeRequest("POST", "create_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("POST", "create_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -497,7 +497,7 @@ func (m *Management) CreateGroup(name string, description *string) (map[string]i // A map containing the response from the server. // An error if the request fails, nil otherwise. func (m *Management) GetGroup(groupID string) (map[string]interface{}, error) { - endpoint := fmt.Sprintf("get_group/%s", url.PathEscape(groupID)) + endpoint := fmt.Sprintf("get_collection/%s", url.PathEscape(groupID)) result, err := m.client.makeRequest("GET", endpoint, nil, "application/json") if err != nil { @@ -526,7 +526,7 @@ func (m *Management) GetGroup(groupID string) (map[string]interface{}, error) { // An error if the request fails, nil otherwise. func (m *Management) UpdateGroup(groupID string, name, description *string) (map[string]interface{}, error) { data := map[string]interface{}{ - "group_id": groupID, + "collection_id": groupID, } if name != nil { data["name"] = *name @@ -540,7 +540,7 @@ func (m *Management) UpdateGroup(groupID string, name, description *string) (map return nil, fmt.Errorf("error marshaling request data: %w", err) } - result, err := m.client.makeRequest("PUT", "update_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("PUT", "update_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -564,7 +564,7 @@ func (m *Management) UpdateGroup(groupID string, name, description *string) (map // A map containing the response from the server. // An error if the request fails, nil otherwise. func (m *Management) DeleteGroup(groupID string) (map[string]interface{}, error) { - endpoint := fmt.Sprintf("delete_group/%s", url.PathEscape(groupID)) + endpoint := fmt.Sprintf("delete_collection/%s", url.PathEscape(groupID)) result, err := m.client.makeRequest("DELETE", endpoint, nil, "application/json") if err != nil { @@ -599,7 +599,7 @@ func (m *Management) ListGroups(offset, limit *int) (map[string]interface{}, err params.Set("limit", strconv.Itoa(*limit)) } - endpoint := "list_groups" + endpoint := "list_collections" if len(params) > 0 { endpoint += "?" + params.Encode() } @@ -631,7 +631,7 @@ func (m *Management) ListGroups(offset, limit *int) (map[string]interface{}, err func (m *Management) AddUserToGroup(userID, groupID string) (map[string]interface{}, error) { data := map[string]string{ "user_id": userID, - "group_id": groupID, + "collection_id": groupID, } jsonData, err := json.Marshal(data) @@ -639,7 +639,7 @@ func (m *Management) AddUserToGroup(userID, groupID string) (map[string]interfac return nil, fmt.Errorf("error marshaling request data: %w", err) } - result, err := m.client.makeRequest("POST", "add_user_to_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("POST", "add_user_to_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -666,7 +666,7 @@ func (m *Management) AddUserToGroup(userID, groupID string) (map[string]interfac func (m *Management) RemoveUserFromGroup(userID, groupID string) (map[string]interface{}, error) { data := map[string]string{ "user_id": userID, - "group_id": groupID, + "collection_id": groupID, } jsonData, err := json.Marshal(data) @@ -674,7 +674,7 @@ func (m *Management) RemoveUserFromGroup(userID, groupID string) (map[string]int return nil, fmt.Errorf("error marshaling request data: %w", err) } - result, err := m.client.makeRequest("POST", "remove_user_from_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("POST", "remove_user_from_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -709,7 +709,7 @@ func (m *Management) GetUsersInGroup(groupID string, offset, limit *int) (map[st params.Set("limit", strconv.Itoa(*limit)) } - endpoint := fmt.Sprintf("get_users_in_group/%s", url.PathEscape(groupID)) + endpoint := fmt.Sprintf("get_users_in_collection/%s", url.PathEscape(groupID)) if len(params) > 0 { endpoint += "?" + params.Encode() } @@ -738,7 +738,7 @@ func (m *Management) GetUsersInGroup(groupID string, offset, limit *int) (map[st // A map containing the response from the server. // An error if the request fails, nil otherwise. func (m *Management) GetGroupsForUser(userID string) (map[string]interface{}, error) { - endpoint := fmt.Sprintf("get_groups_for_user/%s", url.PathEscape(userID)) + endpoint := fmt.Sprintf("get_collections_for_user/%s", url.PathEscape(userID)) result, err := m.client.makeRequest("GET", endpoint, nil, "application/json") if err != nil { @@ -767,7 +767,7 @@ func (m *Management) GetGroupsForUser(userID string) (map[string]interface{}, er func (m *Management) AssignDocumentToGroup(documentID string, groupId string) (map[string]interface{}, error) { data := map[string]string{ "document_id": documentID, - "group_id": groupId, + "collection_id": groupId, } jsonData, err := json.Marshal(data) @@ -775,7 +775,7 @@ func (m *Management) AssignDocumentToGroup(documentID string, groupId string) (m return nil, err } - result, err := m.client.makeRequest("POST", "assign_document_to_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("POST", "assign_document_to_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -802,7 +802,7 @@ func (m *Management) AssignDocumentToGroup(documentID string, groupId string) (m func (m *Management) RemoveDocumentFromGroup(documentID string, groupId string) (map[string]interface{}, error) { data := map[string]string{ "document_id": documentID, - "group_id": groupId, + "collection_id": groupId, } jsonData, err := json.Marshal(data) @@ -810,7 +810,7 @@ func (m *Management) RemoveDocumentFromGroup(documentID string, groupId string) return nil, err } - result, err := m.client.makeRequest("POST", "remove_document_from_group", bytes.NewBuffer(jsonData), "application/json") + result, err := m.client.makeRequest("POST", "remove_document_from_collection", bytes.NewBuffer(jsonData), "application/json") if err != nil { return nil, err } @@ -834,7 +834,7 @@ func (m *Management) RemoveDocumentFromGroup(documentID string, groupId string) // A map containing the response from the server. // An error if the request fails, nil otherwise. func (m *Management) GetDocumentGroups(documentID string) (map[string]interface{}, error) { - endpoint := fmt.Sprintf("get_document_groups/%s", url.PathEscape(documentID)) + endpoint := fmt.Sprintf("get_document_collections/%s", url.PathEscape(documentID)) result, err := m.client.makeRequest("GET", endpoint, nil, "application/json") if err != nil { diff --git a/go/sdk/pkg/sdk/retrieval.go b/go/sdk/pkg/sdk/retrieval.go index 4e6203730..f022ab97e 100644 --- a/go/sdk/pkg/sdk/retrieval.go +++ b/go/sdk/pkg/sdk/retrieval.go @@ -17,7 +17,7 @@ type VectorSearchResult struct { ExtractionID string `json:"extraction_id"` DocumentID string `json:"document_id"` UserID string `json:"user_id"` - GroupIDs []string `json:"group_ids"` + GroupIDs []string `json:"collection_ids"` Score float64 `json:"score"` Text string `json:"text"` Metadata map[string]interface{} `json:"metadata"` @@ -40,7 +40,7 @@ type VectorSearchSettings struct { Filters map[string]interface{} `json:"filters"` SearchLimit int `json:"search_limit"` DoHybridSearch bool `json:"use_hybrid_search"` - SelectedGroupIDs []string `json:"selected_group_ids"` + SelectedGroupIDs []string `json:"selected_collection_ids"` } type KGSearchSettings struct { diff --git a/js/sdk/src/models.tsx b/js/sdk/src/models.tsx index 17708eb8f..09145c46d 100644 --- a/js/sdk/src/models.tsx +++ b/js/sdk/src/models.tsx @@ -40,7 +40,7 @@ export interface VectorSearchSettings { use_hybrid_search?: boolean; filters?: Record; search_limit?: number; - selected_group_ids?: string[]; + selected_collection_ids?: string[]; index_measure: IndexMeasure; include_values?: boolean; include_metadatas?: boolean; diff --git a/js/sdk/src/r2rClient.ts b/js/sdk/src/r2rClient.ts index df6ae9e3f..8ac8e6cb1 100644 --- a/js/sdk/src/r2rClient.ts +++ b/js/sdk/src/r2rClient.ts @@ -834,23 +834,23 @@ export class r2rClient { } /** - * Get an overview of existing groups. - * @param groupIds List of group IDs to get an overview for. - * @param limit The maximum number of groups to return. - * @param offset The offset to start listing groups from. + * Get an overview of existing collections. + * @param collectionIds List of collection IDs to get an overview for. + * @param limit The maximum number of collections to return. + * @param offset The offset to start listing collections from. * @returns */ - @feature("groupsOverview") - async groupsOverview( - groupIds?: string[], + @feature("collectionsOverview") + async collectionsOverview( + collectionIds?: string[], limit?: number, offset?: number, ): Promise> { this._ensureAuthenticated(); const params: Record = {}; - if (groupIds && groupIds.length > 0) { - params.group_ids = groupIds; + if (collectionIds && collectionIds.length > 0) { + params.collection_ids = collectionIds; } if (limit !== undefined) { params.limit = limit; @@ -859,17 +859,17 @@ export class r2rClient { params.offset = offset; } - return this._makeRequest("GET", "groups_overview", { params }); + return this._makeRequest("GET", "collections_overview", { params }); } /** - * Create a new group. - * @param name The name of the group. - * @param description The description of the group. + * Create a new collection. + * @param name The name of the collection. + * @param description The description of the collection. * @returns */ - @feature("createGroup") - async createGroup( + @feature("createCollection") + async createCollection( name: string, description?: string, ): Promise> { @@ -880,37 +880,37 @@ export class r2rClient { data.description = description; } - return this._makeRequest("POST", "create_group", { data }); + return this._makeRequest("POST", "create_collection", { data }); } /** - * Get a group by its ID. - * @param groupId The ID of the group to get. + * Get a collection by its ID. + * @param collectionId The ID of the collection to get. * @returns A promise that resolves to the response from the server. */ - @feature("getGroup") - async getGroup(groupId: string): Promise> { + @feature("getCollection") + async getCollection(collectionId: string): Promise> { this._ensureAuthenticated(); - return this._makeRequest("GET", `get_group/${encodeURIComponent(groupId)}`); + return this._makeRequest("GET", `get_collection/${encodeURIComponent(collectionId)}`); } /** - * Updates the name and description of a group. - * @param groupId The ID of the group to update. - * @param name The new name for the group. - * @param description The new description of the group. + * Updates the name and description of a collection. + * @param collectionId The ID of the collection to update. + * @param name The new name for the collection. + * @param description The new description of the collection. * @returns A promise that resolves to the response from the server. */ - @feature("updateGroup") - async updateGroup( - groupId: string, + @feature("updateCollection") + async updateCollection( + collectionId: string, name?: string, description?: string, ): Promise> { this._ensureAuthenticated(); - const data: { group_id: string; name?: string; description?: string } = { - group_id: groupId, + const data: { collection_id: string; name?: string; description?: string } = { + collection_id: collectionId, }; if (name !== undefined) { data.name = name; @@ -919,31 +919,31 @@ export class r2rClient { data.description = description; } - return this._makeRequest("PUT", "update_group", { data }); + return this._makeRequest("PUT", "update_collection", { data }); } /** - * Delete a group by its ID. - * @param groupId The ID of the group to delete. + * Delete a collection by its ID. + * @param collectionId The ID of the collection to delete. * @returns A promise that resolves to the response from the server. */ - @feature("deleteGroup") - async deleteGroup(groupId: string): Promise> { + @feature("deleteCollection") + async deleteCollection(collectionId: string): Promise> { this._ensureAuthenticated(); return this._makeRequest( "DELETE", - `delete_group/${encodeURIComponent(groupId)}`, + `delete_collection/${encodeURIComponent(collectionId)}`, ); } /** - * List all groups in the R2R deployment. - * @param offset The offset to start listing groups from. - * @param limit The maximum numberof groups to return. + * List all collections in the R2R deployment. + * @param offset The offset to start listing collections from. + * @param limit The maximum numberof collections to return. * @returns */ - @feature("listGroups") - async listGroups( + @feature("listCollections") + async listCollections( offset?: number, limit?: number, ): Promise> { @@ -957,53 +957,53 @@ export class r2rClient { params.limit = limit; } - return this._makeRequest("GET", "list_groups", { params }); + return this._makeRequest("GET", "list_collections", { params }); } /** - * Add a user to a group. + * Add a user to a collection. * @param userId The ID of the user to add. - * @param groupId The ID of the group to add the user to. + * @param collectionId The ID of the collection to add the user to. * @returns A promise that resolves to the response from the server. */ - @feature("addUserToGroup") - async addUserToGroup( + @feature("addUserToCollection") + async addUserToCollection( userId: string, - groupId: string, + collectionId: string, ): Promise> { this._ensureAuthenticated(); - return this._makeRequest("POST", "add_user_to_group", { - data: { user_id: userId, group_id: groupId }, + return this._makeRequest("POST", "add_user_to_collection", { + data: { user_id: userId, collection_id: collectionId }, }); } /** - * Remove a user from a group. + * Remove a user from a collection. * @param userId The ID of the user to remove. - * @param groupId The ID of the group to remove the user from. + * @param collectionId The ID of the collection to remove the user from. * @returns */ - @feature("removeUserFromGroup") - async removeUserFromGroup( + @feature("removeUserFromCollection") + async removeUserFromCollection( userId: string, - groupId: string, + collectionId: string, ): Promise> { this._ensureAuthenticated(); - return this._makeRequest("POST", "remove_user_from_group", { - data: { user_id: userId, group_id: groupId }, + return this._makeRequest("POST", "remove_user_from_collection", { + data: { user_id: userId, collection_id: collectionId }, }); } /** - * Get all users in a group. - * @param groupId The ID of the group to get users for. + * Get all users in a collection. + * @param collectionId The ID of the collection to get users for. * @param offset The offset to start listing users from. * @param limit The maximum number of users to return. * @returns A promise that resolves to the response from the server. */ - @feature("getUsersInGroup") - async getUsersInGroup( - groupId: string, + @feature("getUsersInCollection") + async getUsersInCollection( + collectionId: string, offset?: number, limit?: number, ): Promise> { @@ -1019,86 +1019,86 @@ export class r2rClient { return this._makeRequest( "GET", - `get_users_in_group/${encodeURIComponent(groupId)}`, + `get_users_in_collection/${encodeURIComponent(collectionId)}`, { params }, ); } /** - * Get all groups that a user is a member of. - * @param userId The ID of the user to get groups for. + * Get all collections that a user is a member of. + * @param userId The ID of the user to get collections for. * @returns A promise that resolves to the response from the server. */ - @feature("getGroupsForUser") - async getGroupsForUser(userId: string): Promise> { + @feature("getCollectionsForUser") + async getCollectionsForUser(userId: string): Promise> { this._ensureAuthenticated(); return this._makeRequest( "GET", - `get_groups_for_user/${encodeURIComponent(userId)}`, + `get_collections_for_user/${encodeURIComponent(userId)}`, ); } /** - * Assign a document to a group. + * Assign a document to a collection. * @param document_id The ID of the document to assign. - * @param group_id The ID of the group to assign the document to. + * @param collection_id The ID of the collection to assign the document to. * @returns */ - @feature("assignDocumentToGroup") - async assignDocumentToGroup( + @feature("assignDocumentToCollection") + async assignDocumentToCollection( document_id: string, - group_id: string, + collection_id: string, ): Promise { this._ensureAuthenticated(); - return this._makeRequest("POST", "assign_document_to_group", { - data: { document_id, group_id }, + return this._makeRequest("POST", "assign_document_to_collection", { + data: { document_id, collection_id }, }); } /** - * Remove a document from a group. + * Remove a document from a collection. * @param document_id The ID of the document to remove. - * @param group_id The ID of the group to remove the document from. + * @param collection_id The ID of the collection to remove the document from. * @returns A promise that resolves to the response from the server. */ - @feature("removeDocumentFromGroup") - async removeDocumentFromGroup( + @feature("removeDocumentFromCollection") + async removeDocumentFromCollection( document_id: string, - group_id: string, + collection_id: string, ): Promise { this._ensureAuthenticated(); - return this._makeRequest("POST", "remove_document_from_group", { - data: { document_id, group_id }, + return this._makeRequest("POST", "remove_document_from_collection", { + data: { document_id, collection_id }, }); } /** - * Get all groups that a document is assigned to. - * @param documentId The ID of the document to get groups for. + * Get all collections that a document is assigned to. + * @param documentId The ID of the document to get collections for. * @returns */ - @feature("getDocumentGroups") - async getDocumentGroups(documentId: string): Promise> { + @feature("getDocumentCollections") + async getDocumentCollections(documentId: string): Promise> { this._ensureAuthenticated(); return this._makeRequest( "GET", - `get_document_groups/${encodeURIComponent(documentId)}`, + `get_document_collections/${encodeURIComponent(documentId)}`, ); } /** - * Get all documents in a group. - * @param groupId The ID of the group to get documents for. + * Get all documents in a collection. + * @param collectionId The ID of the collection to get documents for. * @param offset The offset to start listing documents from. * @param limit The maximum number of documents to return. * @returns A promise that resolves to the response from the server. */ - @feature("getDocumentsInGroup") - async getDocumentsInGroup( - groupId: string, + @feature("getDocumentsInCollection") + async getDocumentsInCollection( + collectionId: string, offset?: number, limit?: number, ): Promise> { @@ -1114,7 +1114,7 @@ export class r2rClient { return this._makeRequest( "GET", - `group/${encodeURIComponent(groupId)}/documents`, + `collection/${encodeURIComponent(collectionId)}/documents`, { params }, ); } diff --git a/py/README.md b/py/README.md index eb34ee230..ecd653965 100644 --- a/py/README.md +++ b/py/README.md @@ -87,7 +87,7 @@ r2r --config-name=default serve - Auth & Admin Features - [Web Development](https://r2r-docs.sciphi.ai/cookbooks/web-dev): Building webapps using R2R - [User Auth](https://r2r-docs.sciphi.ai/cookbooks/user-auth): Authenticating users - - [Group Permissions](https://r2r-docs.sciphi.ai/cookbooks/groups): Group permissions + - [Collections](https://r2r-docs.sciphi.ai/cookbooks/collections): Document collections - [Analytics & Observability](https://r2r-docs.sciphi.ai/cookbooks/observability): End-to-end logging and analytics - [Web Application](https://r2r-docs.sciphi.ai/cookbooks/application): Connecting with the R2R Application diff --git a/py/cli/commands/ingestion.py b/py/cli/commands/ingestion.py index d4bcc0ed4..2414a6679 100644 --- a/py/cli/commands/ingestion.py +++ b/py/cli/commands/ingestion.py @@ -235,8 +235,6 @@ def ingest_sample_files_from_unstructured(ctx): file_paths = [os.path.join(folder, file) for file in os.listdir(folder)] - print(file_paths) - with timer(): response = client.ingest_files(file_paths) diff --git a/py/cli/commands/retrieval.py b/py/cli/commands/retrieval.py index 38f9345dc..a822a9521 100644 --- a/py/cli/commands/retrieval.py +++ b/py/cli/commands/retrieval.py @@ -75,7 +75,7 @@ def search(ctx, query, **kwargs): "filters", "search_limit", "use_hybrid_search", - "selected_group_ids", + "selected_collection_ids", "search_strategy", ] and v is not None @@ -190,7 +190,7 @@ def rag(ctx, query, **kwargs): "filters", "search_limit", "use_hybrid_search", - "selected_group_ids", + "selected_collection_ids", "search_strategy", ] and v is not None diff --git a/py/cli/utils/docker_utils.py b/py/cli/utils/docker_utils.py index 523f460ee..7b06eb6ee 100644 --- a/py/cli/utils/docker_utils.py +++ b/py/cli/utils/docker_utils.py @@ -255,7 +255,7 @@ def check_set_docker_env_vars( "POSTGRES_PASSWORD", "POSTGRES_PORT", "POSTGRES_DBNAME", - "POSTGRES_VECS_COLLECTION", + # "POSTGRES_PROJECT_NAME", TODO - uncomment in next release ] env_vars.extend(postgres_vars) diff --git a/py/compose.neo4j.yaml b/py/compose.neo4j.yaml index 689ef30d8..90dab47df 100644 --- a/py/compose.neo4j.yaml +++ b/py/compose.neo4j.yaml @@ -11,7 +11,7 @@ services: neo4j: image: neo4j:5.21.0 ports: - - "7474:7474" # HTTP + - "7475:7475" # HTTP - "7687:7687" # Bolt environment: - NEO4J_AUTH=${NEO4J_AUTH:-neo4j/ineedastrongerpassword} diff --git a/py/compose.yaml b/py/compose.yaml index 095db8e33..851060c85 100644 --- a/py/compose.yaml +++ b/py/compose.yaml @@ -123,7 +123,7 @@ services: - POSTGRES_HOST=${POSTGRES_HOST:-postgres} - POSTGRES_PORT=${POSTGRES_PORT:-5432} - POSTGRES_DBNAME=${POSTGRES_DBNAME:-postgres} - - POSTGRES_VECS_COLLECTION=${POSTGRES_VECS_COLLECTION:-${CONFIG_NAME:-vecs}} + - POSTGRES_PROJECT_NAME=${POSTGRES_PROJECT_NAME:-${CONFIG_NAME:-vecs}} # Neo4j - NEO4J_USER=${NEO4J_USER:-neo4j} - NEO4J_PASSWORD=${NEO4J_PASSWORD:-ineedastrongerpassword} diff --git a/py/core/base/abstractions/document.py b/py/core/base/abstractions/document.py index 3f0b7cc53..836e8df07 100644 --- a/py/core/base/abstractions/document.py +++ b/py/core/base/abstractions/document.py @@ -93,7 +93,7 @@ class DocumentType(str, Enum): class Document(R2RSerializable): id: UUID = Field(default_factory=uuid4) - group_ids: list[UUID] + collection_ids: list[UUID] user_id: UUID type: DocumentType metadata: dict @@ -135,7 +135,7 @@ class DocumentInfo(R2RSerializable): """Base class for document information handling.""" id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] user_id: UUID type: DocumentType metadata: dict @@ -154,7 +154,7 @@ def convert_to_db_entry(self): return { "document_id": self.id, - "group_ids": self.group_ids, + "collection_ids": self.collection_ids, "user_id": self.user_id, "type": self.type, "metadata": json.dumps(self.metadata), @@ -174,7 +174,7 @@ class DocumentExtraction(R2RSerializable): id: UUID document_id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] user_id: UUID data: DataType metadata: dict @@ -187,6 +187,6 @@ class DocumentFragment(R2RSerializable): extraction_id: UUID document_id: UUID user_id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] data: DataType metadata: dict diff --git a/py/core/base/abstractions/search.py b/py/core/base/abstractions/search.py index 4b6411ded..4dc92f93a 100644 --- a/py/core/base/abstractions/search.py +++ b/py/core/base/abstractions/search.py @@ -16,7 +16,7 @@ class VectorSearchResult(BaseModel): extraction_id: UUID document_id: UUID user_id: Optional[UUID] - group_ids: list[UUID] + collection_ids: list[UUID] score: float text: str metadata: dict[str, Any] @@ -33,7 +33,7 @@ def dict(self) -> dict: "extraction_id": self.extraction_id, "document_id": self.document_id, "user_id": self.user_id, - "group_ids": self.group_ids, + "collection_ids": self.collection_ids, "score": self.score, "text": self.text, "metadata": self.metadata, @@ -45,7 +45,7 @@ class Config: "extraction_id": "3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09", "document_id": "3e157b3a-8469-51db-90d9-52e7d896b49b", "user_id": "2acb499e-8428-543b-bd85-0d9098718220", - "group_ids": [], + "collection_ids": [], "score": 0.23943702876567796, "text": "Example text from the document", "metadata": { @@ -261,7 +261,7 @@ class VectorSearchSettings(BaseModel): ge=1, le=1_000, ) - selected_group_ids: list[UUID] = Field( + selected_collection_ids: list[UUID] = Field( default_factory=list, description="Group IDs to search for", ) @@ -301,7 +301,7 @@ class Config: "use_hybrid_search": True, "filters": {"category": "technology"}, "search_limit": 20, - "selected_group_ids": [ + "selected_collection_ids": [ "2acb499e-8428-543b-bd85-0d9098718220", "3e157b3a-8469-51db-90d9-52e7d896b49b", ], @@ -319,8 +319,8 @@ class Config: def model_dump(self, *args, **kwargs): dump = super().model_dump(*args, **kwargs) - dump["selected_group_ids"] = [ - str(uuid) for uuid in dump["selected_group_ids"] + dump["selected_collection_ids"] = [ + str(uuid) for uuid in dump["selected_collection_ids"] ] return dump diff --git a/py/core/base/abstractions/user.py b/py/core/base/abstractions/user.py index 26d2aaaca..305dfefb7 100644 --- a/py/core/base/abstractions/user.py +++ b/py/core/base/abstractions/user.py @@ -42,7 +42,7 @@ class UserStats(BaseModel): is_verified: bool created_at: datetime updated_at: datetime - group_ids: list[UUID] + collection_ids: list[UUID] num_files: int total_size_in_bytes: int document_ids: list[UUID] diff --git a/py/core/base/abstractions/vector.py b/py/core/base/abstractions/vector.py index 6a23ac23d..d2c9fca06 100644 --- a/py/core/base/abstractions/vector.py +++ b/py/core/base/abstractions/vector.py @@ -44,7 +44,7 @@ class VectorEntry(R2RSerializable): extraction_id: UUID document_id: UUID user_id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] vector: Vector text: str metadata: dict[str, Any] @@ -56,7 +56,7 @@ def __str__(self) -> str: f"extraction_id={self.extraction_id}, " f"document_id={self.document_id}, " f"user_id={self.user_id}, " - f"group_ids={self.group_ids}, " + f"collection_ids={self.collection_ids}, " f"vector={self.vector}, " f"text={self.text}, " f"metadata={self.metadata})" diff --git a/py/core/base/api/models/__init__.py b/py/core/base/api/models/__init__.py index 89a83a606..961c4234c 100644 --- a/py/core/base/api/models/__init__.py +++ b/py/core/base/api/models/__init__.py @@ -20,11 +20,11 @@ WrappedAddUserResponse, WrappedAnalyticsResponse, WrappedAppSettingsResponse, + WrappedCollectionListResponse, + WrappedCollectionOverviewResponse, + WrappedCollectionResponse, WrappedDocumentChunkResponse, WrappedDocumentOverviewResponse, - WrappedGroupListResponse, - WrappedGroupOverviewResponse, - WrappedGroupResponse, WrappedKnowledgeGraphResponse, WrappedLogResponse, WrappedPromptMessageResponse, @@ -84,10 +84,10 @@ "WrappedDocumentOverviewResponse", "WrappedDocumentChunkResponse", "WrappedKnowledgeGraphResponse", - "WrappedGroupResponse", - "WrappedGroupListResponse", + "WrappedCollectionResponse", + "WrappedCollectionListResponse", "WrappedAddUserResponse", - "WrappedGroupOverviewResponse", + "WrappedCollectionOverviewResponse", # Retrieval Responses "SearchResponse", "RAGResponse", diff --git a/py/core/base/api/models/auth/responses.py b/py/core/base/api/models/auth/responses.py index 46c6ca6b4..6601fa088 100644 --- a/py/core/base/api/models/auth/responses.py +++ b/py/core/base/api/models/auth/responses.py @@ -22,7 +22,7 @@ class UserResponse(R2RSerializable): created_at: datetime = datetime.now() updated_at: datetime = datetime.now() is_verified: bool = False - group_ids: list[UUID] = [] + collection_ids: list[UUID] = [] # Optional fields (to update or set at creation) hashed_password: Optional[str] = None diff --git a/py/core/base/api/models/management/responses.py b/py/core/base/api/models/management/responses.py index c9a7188e3..d542d7989 100644 --- a/py/core/base/api/models/management/responses.py +++ b/py/core/base/api/models/management/responses.py @@ -75,7 +75,7 @@ class DocumentOverviewResponse(BaseModel): ingestion_status: str restructuring_status: str version: str - group_ids: list[UUID] + collection_ids: list[UUID] metadata: Dict[str, Any] @@ -84,7 +84,7 @@ class DocumentChunkResponse(BaseModel): extraction_id: UUID document_id: UUID user_id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] text: str metadata: Dict[str, Any] @@ -93,7 +93,7 @@ class DocumentChunkResponse(BaseModel): class GroupResponse(BaseModel): - group_id: UUID + collection_id: UUID name: str description: Optional[str] created_at: datetime @@ -101,7 +101,7 @@ class GroupResponse(BaseModel): class GroupOverviewResponse(BaseModel): - group_id: UUID + collection_id: UUID name: str description: Optional[str] created_at: datetime @@ -128,7 +128,7 @@ class AddUserResponse(BaseModel): ] WrappedDocumentChunkResponse = ResultsWrapper[List[DocumentChunkResponse]] WrappedKnowledgeGraphResponse = ResultsWrapper[KnowledgeGraphResponse] -WrappedGroupResponse = ResultsWrapper[GroupResponse] -WrappedGroupListResponse = ResultsWrapper[List[GroupResponse]] -WrappedGroupOverviewResponse = ResultsWrapper[List[GroupOverviewResponse]] +WrappedCollectionResponse = ResultsWrapper[GroupResponse] +WrappedCollectionListResponse = ResultsWrapper[List[GroupResponse]] +WrappedCollectionOverviewResponse = ResultsWrapper[List[GroupOverviewResponse]] WrappedAddUserResponse = ResultsWrapper[AddUserResponse] diff --git a/py/core/examples/data/aristotle_v2.txt b/py/core/examples/data/aristotle_v2.txt index 83902f3b2..fa44c226e 100644 --- a/py/core/examples/data/aristotle_v2.txt +++ b/py/core/examples/data/aristotle_v2.txt @@ -7,22 +7,3 @@ Though Aristotle wrote many elegant treatises and dialogues for publication, onl Aristotle's views profoundly shaped medieval scholarship. The influence of his physical science extended from late antiquity and the Early Middle Ages into the Renaissance, and was not replaced systematically until the Enlightenment and theories such as classical mechanics were developed. He influenced Judeo-Islamic philosophies during the Middle Ages, as well as Christian theology, especially the Neoplatonism of the Early Church and the scholastic tradition of the Catholic Church. Aristotle was revered among medieval Muslim scholars as "The First Teacher", and among medieval Christians like Thomas Aquinas as simply "The Philosopher", while the poet Dante called him "the master of those who know". His works contain the earliest known formal study of logic, and were studied by medieval scholars such as Peter Abelard and Jean Buridan. Aristotle's influence on logic continued well into the 19th century. In addition, his ethics, although always influential, gained renewed interest with the modern advent of virtue ethics. - -Life -In general, the details of Aristotle's life are not well-established. The biographies written in ancient times are often speculative and historians only agree on a few salient points.[B] - -Aristotle was born in 384 BC[C] in Stagira, Chalcidice,[2] about 55 km (34 miles) east of modern-day Thessaloniki.[3][4] His father, Nicomachus, was the personal physician to King Amyntas of Macedon. While he was young, Aristotle learned about biology and medical information, which was taught by his father.[5] Both of Aristotle's parents died when he was about thirteen, and Proxenus of Atarneus became his guardian.[6] Although little information about Aristotle's childhood has survived, he probably spent some time within the Macedonian palace, making his first connections with the Macedonian monarchy.[7] - - -School of Aristotle in Mieza, Macedonia, Greece. -At the age of seventeen or eighteen, Aristotle moved to Athens to continue his education at Plato's Academy.[8] He probably experienced the Eleusinian Mysteries as he wrote when describing the sights one viewed at the Eleusinian Mysteries, "to experience is to learn" [παθείν μαθεĩν].[9] Aristotle remained in Athens for nearly twenty years before leaving in 348/47 BC. The traditional story about his departure records that he was disappointed with the Academy's direction after control passed to Plato's nephew Speusippus, although it is possible that he feared the anti-Macedonian sentiments in Athens at that time and left before Plato died.[10] Aristotle then accompanied Xenocrates to the court of his friend Hermias of Atarneus in Asia Minor. After the death of Hermias, Aristotle travelled with his pupil Theophrastus to the island of Lesbos, where together they researched the botany and zoology of the island and its sheltered lagoon. While in Lesbos, Aristotle married Pythias, either Hermias's adoptive daughter or niece. They had a daughter, whom they also named Pythias. In 343 BC, Aristotle was invited by Philip II of Macedon to become the tutor to his son Alexander.[11][12] - - -"Aristotle tutoring Alexander" by Jean Leon Gerome Ferris. -Aristotle was appointed as the head of the royal Academy of Macedon. During Aristotle's time in the Macedonian court, he gave lessons not only to Alexander but also to two other future kings: Ptolemy and Cassander.[13] Aristotle encouraged Alexander toward eastern conquest, and Aristotle's own attitude towards Persia was unabashedly ethnocentric. In one famous example, he counsels Alexander to be "a leader to the Greeks and a despot to the barbarians, to look after the former as after friends and relatives, and to deal with the latter as with beasts or plants".[13] By 335 BC, Aristotle had returned to Athens, establishing his own school there known as the Lyceum. Aristotle conducted courses at the school for the next twelve years. While in Athens, his wife Pythias died and Aristotle became involved with Herpyllis of Stagira. They had a son whom Aristotle named after his father, Nicomachus. If the Suda – an uncritical compilation from the Middle Ages – is accurate, he may also have had an erômenos, Palaephatus of Abydus.[14] - - -Portrait bust of Aristotle; an Imperial Roman (1st or 2nd century AD) copy of a lost bronze sculpture made by Lysippos. -This period in Athens, between 335 and 323 BC, is when Aristotle is believed to have composed many of his works.[12] He wrote many dialogues, of which only fragments have survived. Those works that have survived are in treatise form and were not, for the most part, intended for widespread publication; they are generally thought to be lecture aids for his students. His most important treatises include Physics, Metaphysics, Nicomachean Ethics, Politics, On the Soul and Poetics. Aristotle studied and made significant contributions to "logic, metaphysics, mathematics, physics, biology, botany, ethics, politics, agriculture, medicine, dance, and theatre."[15] - -Near the end of his life, Alexander and Aristotle became estranged over Alexander's relationship with Persia and Persians. A widespread tradition in antiquity suspected Aristotle of playing a role in Alexander's death, but the only evidence of this is an unlikely claim made some six years after the death.[16] Following Alexander's death, anti-Macedonian sentiment in Athens was rekindled. In 322 BC, Demophilus and Eurymedon the Hierophant reportedly denounced Aristotle for impiety,[17] prompting him to flee to his mother's family estate in Chalcis, on Euboea, at which occasion he was said to have stated: "I will not allow the Athenians to sin twice against philosophy"[18][19][20] – a reference to Athens's trial and execution of Socrates. He died in Chalcis, Euboea[2][21][15] of natural causes later that same year, having named his student Antipater as his chief executor and leaving a will in which he asked to be buried next to his wife.[22] diff --git a/py/core/examples/scripts/run_group_workflow.py b/py/core/examples/scripts/run_group_workflow.py index b7eab33c2..2f7bbf8a6 100644 --- a/py/core/examples/scripts/run_group_workflow.py +++ b/py/core/examples/scripts/run_group_workflow.py @@ -13,36 +13,40 @@ login_result = client.login("admin@example.com", "change_me_immediately") print("Admin login result:", login_result) - # Create two groups - print("\nCreating two groups...") - group1_result = client.create_group( - "TestGroup1", "A test group for document access" + # Create two collections + print("\nCreating two collections...") + collection1_result = client.create_collection( + "TestGroup1", "A test collection for document access" ) - group2_result = client.create_group("TestGroup2", "Another test group") - print("Group1 creation result:", group1_result) - print("Group2 creation result:", group2_result) - group1_id = group1_result["results"]["group_id"] - group2_id = group2_result["results"]["group_id"] - - # Get groups overview - print("\nGetting groups overview...") - groups_overview = client.groups_overview() - print("Groups overview:", groups_overview) - - # Get specific group - print("\nGetting specific group...") - group1_details = client.get_group(group1_id) - print("Group1 details:", group1_details) - - # List all groups - print("\nListing all groups...") - groups_list = client.list_groups() - print("Groups list:", groups_list) - - # Update a group + collection2_result = client.create_collection( + "TestGroup2", "Another test collection" + ) + print("Group1 creation result:", collection1_result) + print("Group2 creation result:", collection2_result) + collection1_id = collection1_result["results"]["collection_id"] + collection2_id = collection2_result["results"]["collection_id"] + + # Get collections overview + print("\nGetting collections overview...") + collections_overview = client.collections_overview() + print("Groups overview:", collections_overview) + + # Get specific collection + print("\nGetting specific collection...") + collection1_details = client.get_collection(collection1_id) + print("Group1 details:", collection1_details) + + # List all collections + print("\nListing all collections...") + collections_list = client.list_collections() + print("Groups list:", collections_list) + + # Update a collection print("\nUpdating Group1...") - update_result = client.update_group( - group1_id, name="UpdatedTestGroup1", description="Updated description" + update_result = client.update_collection( + collection1_id, + name="UpdatedTestGroup1", + description="Updated description", ) print("Group update result:", update_result) @@ -62,18 +66,22 @@ document1_id = ingestion_result1["results"]["processed_documents"][0]["id"] document2_id = ingestion_result2["results"]["processed_documents"][0]["id"] - # Assign documents to groups - print("\nAssigning documents to groups...") - assign_result1 = client.assign_document_to_group(document1_id, group1_id) - assign_result2 = client.assign_document_to_group(document2_id, group2_id) + # Assign documents to collections + print("\nAssigning documents to collections...") + assign_result1 = client.assign_document_to_collection( + document1_id, collection1_id + ) + assign_result2 = client.assign_document_to_collection( + document2_id, collection2_id + ) print("Document1 assignment result:", assign_result1) print("Document2 assignment result:", assign_result2) # document1_id = "c3291abf-8a4e-5d9d-80fd-232ef6fd8526" - # Get document groups - print("\nGetting groups for Document1...") - doc1_groups = client.document_groups(document1_id) - print("Document1 groups:", doc1_groups) + # Get document collections + print("\nGetting collections for Document1...") + doc1_collections = client.document_collections(document1_id) + print("Document1 collections:", doc1_collections) # Create three test users print("\nCreating three test users...") @@ -84,51 +92,51 @@ print("User2 creation result:", user2_result) print("User3 creation result:", user3_result) - # Add users to groups - print("\nAdding users to groups...") - add_user1_result = client.add_user_to_group( - user1_result["results"]["id"], group1_id + # Add users to collections + print("\nAdding users to collections...") + add_user1_result = client.add_user_to_collection( + user1_result["results"]["id"], collection1_id ) - add_user2_result = client.add_user_to_group( - user2_result["results"]["id"], group2_id + add_user2_result = client.add_user_to_collection( + user2_result["results"]["id"], collection2_id ) - add_user3_result1 = client.add_user_to_group( - user3_result["results"]["id"], group1_id + add_user3_result1 = client.add_user_to_collection( + user3_result["results"]["id"], collection1_id ) - add_user3_result2 = client.add_user_to_group( - user3_result["results"]["id"], group2_id + add_user3_result2 = client.add_user_to_collection( + user3_result["results"]["id"], collection2_id ) - print("Add user1 to group1 result:", add_user1_result) - print("Add user2 to group2 result:", add_user2_result) - print("Add user3 to group1 result:", add_user3_result1) - print("Add user3 to group2 result:", add_user3_result2) + print("Add user1 to collection1 result:", add_user1_result) + print("Add user2 to collection2 result:", add_user2_result) + print("Add user3 to collection1 result:", add_user3_result1) + print("Add user3 to collection2 result:", add_user3_result2) - # Get users in a group + # Get users in a collection print("\nGetting users in Group1...") - users_in_group1 = client.user_groups(group1_id) - print("Users in Group1:", users_in_group1) + users_in_collection1 = client.user_collections(collection1_id) + print("Users in Group1:", users_in_collection1) - # Get groups for a user - print("\nGetting groups for User3...") - user3_groups = client.user_groups(user3_result["results"]["id"]) - print("User3 groups:", user3_groups) + # Get collections for a user + print("\nGetting collections for User3...") + user3_collections = client.user_collections(user3_result["results"]["id"]) + print("User3 collections:", user3_collections) - # Get documents in a group + # Get documents in a collection print("\nGetting documents in Group1...") - docs_in_group1 = client.documents_in_group(group1_id) - print("Documents in Group1:", docs_in_group1) + docs_in_collection1 = client.documents_in_collection(collection1_id) + print("Documents in Group1:", docs_in_collection1) - # Remove user from group + # Remove user from collection print("\nRemoving User3 from Group1...") - remove_user_result = client.remove_user_from_group( - user3_result["results"]["id"], group1_id + remove_user_result = client.remove_user_from_collection( + user3_result["results"]["id"], collection1_id ) print("Remove user result:", remove_user_result) - # Remove document from group + # Remove document from collection print("\nRemoving Document1 from Group1...") - remove_doc_result = client.remove_document_from_group( - document1_id, group1_id + remove_doc_result = client.remove_document_from_collection( + document1_id, collection1_id ) print("Remove document result:", remove_doc_result) @@ -143,7 +151,7 @@ # Search for documents (should see document1 but not document2) print("\nUser1 searching for documents...") search_result_user1 = client.search( - "philosophy", {"selected_group_ids": [group1_id]} + "philosophy", {"selected_collection_ids": [collection1_id]} ) print("User1 search result:", search_result_user1) @@ -159,12 +167,13 @@ print("\nUser3 searching for documents...") try: search_result_user3 = client.search( - "philosophy", {"selected_group_ids": [group1_id, group2_id]} + "philosophy", + {"selected_collection_ids": [collection1_id, collection2_id]}, ) except Exception as e: print("User3 search result error:", e) search_result_user3 = client.search( - "philosophy", {"selected_group_ids": [group2_id]} + "philosophy", {"selected_collection_ids": [collection2_id]} ) print("User3 search result:", search_result_user3) @@ -178,10 +187,10 @@ # Login as admin again client.login("admin@example.com", "change_me_immediately") - # Delete the groups - print("Deleting the groups...") - client.delete_group(group1_id) - client.delete_group(group2_id) + # Delete the collections + print("Deleting the collections...") + client.delete_collection(collection1_id) + client.delete_collection(collection2_id) # Logout admin print("\nLogging out admin...") diff --git a/py/core/main/api/base_router.py b/py/core/main/api/base_router.py index 2015133f5..d6163421e 100644 --- a/py/core/main/api/base_router.py +++ b/py/core/main/api/base_router.py @@ -61,8 +61,6 @@ async def wrapper(*args, **kwargs): }, ) except Exception as e: - print("cc") - await self.service.logging_connection.log( run_id=run_id, key="error", diff --git a/py/core/main/api/ingestion_router.py b/py/core/main/api/ingestion_router.py index 6f3f80ae8..950da9218 100644 --- a/py/core/main/api/ingestion_router.py +++ b/py/core/main/api/ingestion_router.py @@ -89,7 +89,7 @@ async def ingest_files_app( This endpoint supports multipart/form-data requests, enabling you to ingest files and their associated metadatas into R2R. - A valid user authentication token is required to access this endpoint, as regular users can only ingest files for their own access. More expansive group permissioning is under development. + A valid user authentication token is required to access this endpoint, as regular users can only ingest files for their own access. More expansive collection permissioning is under development. """ self._validate_chunking_config(chunking_config) # Check if the user is a superuser @@ -103,9 +103,8 @@ async def ingest_files_app( status_code=403, message="Non-superusers cannot set user_id in metadata.", ) - - # If user is not a superuser, set user_id in metadata - metadata["user_id"] = str(auth_user.id) + # If user is not a superuser, set user_id in metadata + metadata["user_id"] = str(auth_user.id) file_datas = await self._process_files(files) @@ -181,7 +180,7 @@ async def retry_ingest_files( This endpoint allows you to retry the ingestion of files that have previously failed to ingest into R2R. - A valid user authentication token is required to access this endpoint, as regular users can only retry the ingestion of their own files. More expansive group permissioning is under development. + A valid user authentication token is required to access this endpoint, as regular users can only retry the ingestion of their own files. More expansive collection permissioning is under development. """ if not auth_user.is_superuser: documents_overview = await self.service.providers.database.relational.get_documents_overview( @@ -236,7 +235,7 @@ async def update_files_app( This endpoint supports multipart/form-data requests, enabling you to update files and their associated metadatas into R2R. - A valid user authentication token is required to access this endpoint, as regular users can only update their own files. More expansive group permissioning is under development. + A valid user authentication token is required to access this endpoint, as regular users can only update their own files. More expansive collection permissioning is under development. """ self._validate_chunking_config(chunking_config) if not auth_user.is_superuser: diff --git a/py/core/main/api/management_router.py b/py/core/main/api/management_router.py index 162ae3c28..22c6bfc34 100644 --- a/py/core/main/api/management_router.py +++ b/py/core/main/api/management_router.py @@ -15,12 +15,12 @@ WrappedAddUserResponse, WrappedAnalyticsResponse, WrappedAppSettingsResponse, + WrappedCollectionListResponse, + WrappedCollectionOverviewResponse, + WrappedCollectionResponse, WrappedDocumentChunkResponse, WrappedDocumentOverviewResponse, WrappedGetPromptsResponse, - WrappedGroupListResponse, - WrappedGroupOverviewResponse, - WrappedGroupResponse, WrappedKnowledgeGraphResponse, WrappedLogResponse, WrappedPromptMessageResponse, @@ -327,7 +327,7 @@ async def documents_overview_app( ] result = await self.service.documents_overview( user_ids=request_user_ids, - group_ids=auth_user.group_ids, + collection_ids=auth_user.collection_ids, document_ids=document_uuids, offset=offset, limit=limit, @@ -382,135 +382,148 @@ async def inspect_knowledge_graph( print_descriptions=print_descriptions, ) - @self.router.get("/groups_overview") + @self.router.get("/collections_overview") @self.base_endpoint - async def groups_overview_app( - group_ids: Optional[list[str]] = Query(None), + async def collections_overview_app( + collection_ids: Optional[list[str]] = Query(None), offset: Optional[int] = Query(0, ge=0), limit: Optional[int] = Query(100, ge=1, le=1000), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupOverviewResponse: + ) -> WrappedCollectionOverviewResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can call the `groups_overview` endpoint.", + "Only a superuser can call the `collections_overview` endpoint.", 403, ) - group_uuids = ( - [UUID(group_id) for group_id in group_ids] - if group_ids + collection_uuids = ( + [UUID(collection_id) for collection_id in collection_ids] + if collection_ids else None ) - return await self.service.groups_overview( - group_ids=group_uuids, offset=offset, limit=limit + return await self.service.collections_overview( + collection_ids=collection_uuids, offset=offset, limit=limit ) - @self.router.post("/create_group") + @self.router.post("/create_collection") @self.base_endpoint - async def create_group_app( - name: str = Body(..., description="Group name"), + async def create_collection_app( + name: str = Body(..., description="Collection name"), description: Optional[str] = Body( - "", description="Group description" + "", description="Collection description" ), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupResponse: + ) -> WrappedCollectionResponse: if not auth_user.is_superuser: - raise R2RException("Only a superuser can create groups.", 403) - return await self.service.create_group(name, description) + raise R2RException( + "Only a superuser can create collections.", 403 + ) + return await self.service.create_collection(name, description) - @self.router.get("/get_group/{group_id}") + @self.router.get("/get_collection/{collection_id}") @self.base_endpoint - async def get_group_app( - group_id: str = Path(..., description="Group ID"), + async def get_collection_app( + collection_id: str = Path(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupResponse: + ) -> WrappedCollectionResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can get group details.", 403 + "Only a superuser can get Collection details.", 403 ) - group_uuid = UUID(group_id) - result = await self.service.get_group(group_uuid) + collection_uuid = UUID(collection_id) + result = await self.service.get_collection(collection_uuid) return result - @self.router.put("/update_group") + @self.router.put("/update_collection") @self.base_endpoint - async def update_group_app( - group_id: str = Body(..., description="Group ID"), - name: Optional[str] = Body(None, description="Updated group name"), + async def update_collection_app( + collection_id: str = Body(..., description="Collection ID"), + name: Optional[str] = Body( + None, description="Updated collection name" + ), description: Optional[str] = Body( - None, description="Updated group description" + None, description="Updated collection description" ), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupResponse: + ) -> WrappedCollectionResponse: if not auth_user.is_superuser: - raise R2RException("Only a superuser can update groups.", 403) - group_uuid = UUID(group_id) - return await self.service.update_group( - group_uuid, name, description + raise R2RException( + "Only a superuser can update collections.", 403 + ) + collection_uuid = UUID(collection_id) + return await self.service.update_collection( + collection_uuid, name, description ) - @self.router.delete("/delete_group/{group_id}") + @self.router.delete("/delete_collection/{collection_id}") @self.base_endpoint - async def delete_group_app( - group_id: str = Path(..., description="Group ID"), + async def delete_collection_app( + collection_id: str = Path(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), ): if not auth_user.is_superuser: - raise R2RException("Only a superuser can delete groups.", 403) - group_uuid = UUID(group_id) - return await self.service.delete_group(group_uuid) + raise R2RException( + "Only a superuser can delete collections.", 403 + ) + collection_uuid = UUID(collection_id) + return await self.service.delete_collection(collection_uuid) - @self.router.get("/list_groups") + @self.router.get("/list_collections") @self.base_endpoint - async def list_groups_app( + async def list_collections_app( offset: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=1000), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupListResponse: + ) -> WrappedCollectionListResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can list all groups.", 403 + "Only a superuser can list all collections.", 403 ) - return await self.service.list_groups( + return await self.service.list_collections( offset=offset, limit=min(max(limit, 1), 1000) ) - @self.router.post("/add_user_to_group") + @self.router.post("/add_user_to_collection") @self.base_endpoint - async def add_user_to_group_app( + async def add_user_to_collection_app( user_id: str = Body(..., description="User ID"), - group_id: str = Body(..., description="Group ID"), + collection_id: str = Body(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), ) -> WrappedAddUserResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can add users to groups.", 403 + "Only a superuser can add users to collections.", 403 ) user_uuid = UUID(user_id) - group_uuid = UUID(group_id) - return await self.service.add_user_to_group(user_uuid, group_uuid) + collection_uuid = UUID(collection_id) + result = await self.service.add_user_to_collection( + user_uuid, collection_uuid + ) + return {"result": result} - @self.router.post("/remove_user_from_group") + @self.router.post("/remove_user_from_collection") @self.base_endpoint - async def remove_user_from_group_app( + async def remove_user_from_collection_app( user_id: str = Body(..., description="User ID"), - group_id: str = Body(..., description="Group ID"), + collection_id: str = Body(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), ): if not auth_user.is_superuser: raise R2RException( - "Only a superuser can remove users from groups.", 403 + "Only a superuser can remove users from collections.", 403 ) user_uuid = UUID(user_id) - group_uuid = UUID(group_id) - await self.service.remove_user_from_group(user_uuid, group_uuid) + collection_uuid = UUID(collection_id) + await self.service.remove_user_from_collection( + user_uuid, collection_uuid + ) return None # TODO - Proivde response model - @self.router.get("/get_users_in_group/{group_id}") + @self.router.get("/get_users_in_collection/{collection_id}") @self.base_endpoint - async def get_users_in_group_app( - group_id: str = Path(..., description="Group ID"), + async def get_users_in_collection_app( + collection_id: str = Path(..., description="Collection ID"), offset: int = Query(0, ge=0, description="Pagination offset"), limit: int = Query( 100, ge=1, le=1000, description="Pagination limit" @@ -519,18 +532,18 @@ async def get_users_in_group_app( ): if not auth_user.is_superuser: raise R2RException( - "Only a superuser can get users in a group.", 403 + "Only a superuser can get users in a collection.", 403 ) - group_uuid = UUID(group_id) - return await self.service.get_users_in_group( - group_id=group_uuid, + collection_uuid = UUID(collection_id) + return await self.service.get_users_in_collection( + collection_id=collection_uuid, offset=offset, limit=min(max(limit, 1), 1000), ) - @self.router.get("/user_groups/{user_id}") + @self.router.get("/user_collections/{user_id}") @self.base_endpoint - async def get_groups_for_user_app( + async def get_collections_for_user_app( user_id: str = Path(..., description="User ID"), offset: int = Query(0, ge=0, description="Pagination offset"), limit: int = Query( @@ -540,78 +553,80 @@ async def get_groups_for_user_app( ): if not auth_user.is_superuser: raise R2RException( - "Only a superuser can get groups for a user.", 403 + "Only a superuser can get collections for a user.", 403 ) user_uuid = UUID(user_id) - return await self.service.get_groups_for_user( + return await self.service.get_collections_for_user( user_uuid, offset, limit ) - @self.router.post("/assign_document_to_group") + @self.router.post("/assign_document_to_collection") @self.base_endpoint - async def assign_document_to_group_app( + async def assign_document_to_collection_app( document_id: str = Body(..., description="Document ID"), - group_id: str = Body(..., description="Group ID"), + collection_id: str = Body(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), ): if not auth_user.is_superuser: raise R2RException( - "Only a superuser can assign documents to groups.", 403 + "Only a superuser can assign documents to collections.", + 403, ) document_uuid = UUID(document_id) - group_uuid = UUID(group_id) - return await self.service.assign_document_to_group( - document_uuid, group_uuid + collection_uuid = UUID(collection_id) + return await self.service.assign_document_to_collection( + document_uuid, collection_uuid ) - @self.router.post("/remove_document_from_group") + @self.router.post("/remove_document_from_collection") @self.base_endpoint - async def remove_document_from_group_app( + async def remove_document_from_collection_app( document_id: str = Body(..., description="Document ID"), - group_id: str = Body(..., description="Group ID"), + collection_id: str = Body(..., description="Collection ID"), auth_user=Depends(self.service.providers.auth.auth_wrapper), ) -> None: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can remove documents from groups.", 403 + "Only a superuser can remove documents from collections.", + 403, ) document_uuid = UUID(document_id) - group_uuid = UUID(group_id) - await self.service.remove_document_from_group( - document_uuid, group_uuid + collection_uuid = UUID(collection_id) + await self.service.remove_document_from_collection( + document_uuid, collection_uuid ) return None - @self.router.get("/document_groups/{document_id}") + @self.router.get("/document_collections/{document_id}") @self.base_endpoint - async def document_groups_app( + async def document_collections_app( document_id: str = Path(..., description="Document ID"), offset: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=1000), auth_user=Depends(self.service.providers.auth.auth_wrapper), - ) -> WrappedGroupListResponse: + ) -> WrappedCollectionListResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can get the groups belonging to a document.", + "Only a superuser can get the collections belonging to a document.", 403, ) - return await self.service.document_groups( + return await self.service.document_collections( document_id, offset, limit ) - @self.router.get("/group/{group_id}/documents") + @self.router.get("/collection/{collection_id}/documents") @self.base_endpoint - async def documents_in_group_app( - group_id: str = Path(..., description="Group ID"), + async def documents_in_collection_app( + collection_id: str = Path(..., description="Collection ID"), offset: int = Query(0, ge=0), limit: int = Query(100, ge=1, le=1000), auth_user=Depends(self.service.providers.auth.auth_wrapper), ) -> WrappedDocumentOverviewResponse: if not auth_user.is_superuser: raise R2RException( - "Only a superuser can get documents in a group.", 403 + "Only a superuser can get documents in a collection.", 403 ) - group_uuid = UUID(group_id) - return await self.service.documents_in_group( - group_uuid, offset, limit + collection_uuid = UUID(collection_id) + return await self.service.documents_in_collection( + collection_uuid, offset, limit ) diff --git a/py/core/main/api/retrieval_router.py b/py/core/main/api/retrieval_router.py index ae88aa99f..84124b2d2 100644 --- a/py/core/main/api/retrieval_router.py +++ b/py/core/main/api/retrieval_router.py @@ -75,19 +75,27 @@ async def search_app( Allowed operators include `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, `like`, `ilike`, `in`, and `nin`. """ - user_groups = set(auth_user.group_ids) - selected_groups = set(vector_search_settings.selected_group_ids) - allowed_groups = user_groups.intersection(selected_groups) - if selected_groups - allowed_groups != set(): + user_collections = set(auth_user.collection_ids) + selected_collections = set( + vector_search_settings.selected_collection_ids + ) + allowed_collections = user_collections.intersection( + selected_collections + ) + if selected_collections - allowed_collections != set(): raise ValueError( - "User does not have access to the specified group(s): " - f"{selected_groups - allowed_groups}" + "User does not have access to the specified collection(s): " + f"{selected_collections - allowed_collections}" ) filters = { "$or": [ {"user_id": {"$eq": str(auth_user.id)}}, - {"group_ids": {"$overlap": list(allowed_groups)}}, + { + "collection_ids": { + "$overlap": list(allowed_collections) + } + }, ] } if vector_search_settings.filters != {}: @@ -141,11 +149,15 @@ async def rag_app( The generation process can be customized using the rag_generation_config parameter. """ - allowed_groups = set(auth_user.group_ids) + allowed_collections = set(auth_user.collection_ids) filters = { "$or": [ {"user_id": str(auth_user.id)}, - {"group_ids": {"$overlap": list(allowed_groups)}}, + { + "collection_ids": { + "$overlap": list(allowed_collections) + } + }, ] } if vector_search_settings.filters != {}: @@ -222,11 +234,15 @@ async def agent_app( """ # TODO - Don't just copy paste the same code, refactor this user = auth_user - allowed_groups = set(user.group_ids) + allowed_collections = set(user.collection_ids) filters = { "$or": [ {"user_id": str(user.id)}, - {"group_ids": {"$overlap": list(allowed_groups)}}, + { + "collection_ids": { + "$overlap": list(allowed_collections) + } + }, ] } if vector_search_settings.filters != {}: diff --git a/py/core/main/hatchet/restructure_workflow.py b/py/core/main/hatchet/restructure_workflow.py index 23f67b432..a80de4e87 100644 --- a/py/core/main/hatchet/restructure_workflow.py +++ b/py/core/main/hatchet/restructure_workflow.py @@ -46,7 +46,7 @@ async def kg_extract_and_store(self, context: Context) -> None: document_overview ) - await self.restructure_service.kg_extract_and_store( + errors = await self.restructure_service.kg_extract_and_store( document_id=document_id, generation_config=GenerationConfig( **input_data["generation_config"] @@ -58,10 +58,21 @@ async def kg_extract_and_store(self, context: Context) -> None: ) # Set restructure status to 'success' if completed successfully - document_overview.restructuring_status = RestructureStatus.SUCCESS - await self.restructure_service.providers.database.relational.upsert_documents_overview( - document_overview - ) + if len(errors) == 0: + document_overview.restructuring_status = ( + RestructureStatus.SUCCESS + ) + else: + document_overview.restructuring_status = ( + RestructureStatus.FAILURE + ) + await self.restructure_service.providers.database.relational.upsert_documents_overview( + document_overview + ) + raise R2RDocumentProcessingError( + error_message=f"Error in kg_extract_and_store, list of errors: {errors}", + document_id=document_id, + ) except Exception as e: # Set restructure status to 'failure' if an error occurred diff --git a/py/core/main/services/auth_service.py b/py/core/main/services/auth_service.py index 5d9d5f635..3049d2fa8 100644 --- a/py/core/main/services/auth_service.py +++ b/py/core/main/services/auth_service.py @@ -34,7 +34,7 @@ def __init__( @telemetry_event("RegisterUser") async def register(self, email: str, password: str) -> UserResponse: - return self.providers.auth.register(email, password) + return await self.providers.auth.register(email, password) @telemetry_event("VerifyEmail") async def verify_email(self, email: str, verification_code: str) -> bool: @@ -84,7 +84,7 @@ async def user(self, token: str) -> UserResponse: async def refresh_access_token( self, refresh_token: str ) -> dict[str, Token]: - return self.providers.auth.refresh_access_token(refresh_token) + return await self.providers.auth.refresh_access_token(refresh_token) @telemetry_event("ChangePassword") async def change_password( @@ -92,19 +92,19 @@ async def change_password( ) -> dict[str, str]: if not user: raise R2RException(status_code=404, message="User not found") - return self.providers.auth.change_password( + return await self.providers.auth.change_password( user, current_password, new_password ) @telemetry_event("RequestPasswordReset") async def request_password_reset(self, email: str) -> dict[str, str]: - return self.providers.auth.request_password_reset(email) + return await self.providers.auth.request_password_reset(email) @telemetry_event("ConfirmPasswordReset") async def confirm_password_reset( self, reset_token: str, new_password: str ) -> dict[str, str]: - return self.providers.auth.confirm_password_reset( + return await self.providers.auth.confirm_password_reset( reset_token, new_password ) diff --git a/py/core/main/services/ingestion_service.py b/py/core/main/services/ingestion_service.py index 05b6696f7..448f55e31 100644 --- a/py/core/main/services/ingestion_service.py +++ b/py/core/main/services/ingestion_service.py @@ -138,7 +138,7 @@ def _create_document_info( return DocumentInfo( id=document_id, user_id=user.id, - group_ids=metadata.get("group_ids", []), + collection_ids=metadata.get("collection_ids", []), type=DocumentType[file_extension.upper()], title=metadata.get("title", file_name.split("/")[-1]), metadata=metadata, @@ -162,7 +162,7 @@ async def parse_file( input=self.pipes.parsing_pipe.Input( message=Document( id=document_info.id, - group_ids=document_info.group_ids, + collection_ids=document_info.collection_ids, user_id=document_info.user_id, type=document_info.type, metadata={ diff --git a/py/core/main/services/management_service.py b/py/core/main/services/management_service.py index 8a539b531..819b251c0 100644 --- a/py/core/main/services/management_service.py +++ b/py/core/main/services/management_service.py @@ -267,31 +267,75 @@ async def delete( """ Takes a list of filters like "{key: {operator: value}, key: {operator: value}, ...}" - and deletes entries that match the filters. - - Then, deletes the corresponding entries from the documents overview table. + and deletes entries matching the given filters from both vector and relational databases. NOTE: This method is not atomic and may result in orphaned entries in the documents overview table. NOTE: This method assumes that filters delete entire contents of any touched documents. """ logger.info(f"Deleting entries with filters: {filters}") - results = self.providers.database.vector.delete(filters) - if not results: + + try: + vector_delete_results = self.providers.database.vector.delete( + filters + ) + except Exception as e: + logger.error(f"Error deleting from vector database: {e}") + vector_delete_results = {} + + document_ids_to_purge = set() + if vector_delete_results: + document_ids_to_purge.update( + doc_id + for doc_id in ( + result.get("document_id") + for result in vector_delete_results.values() + ) + if doc_id + ) + + relational_filters = {} + if "document_id" in filters: + relational_filters["filter_document_ids"] = [ + UUID(filters["document_id"]) + ] + if "user_id" in filters: + relational_filters["filter_user_ids"] = [UUID(filters["user_id"])] + if "group_ids" in filters: + relational_filters["filter_group_ids"] = [ + UUID(group_id) for group_id in filters["group_ids"] + ] + + try: + documents_overview = await self.providers.database.relational.get_documents_overview( + **relational_filters + ) + except Exception as e: + logger.error( + f"Error fetching documents from relational database: {e}" + ) + documents_overview = [] + + if documents_overview: + document_ids_to_purge.update(doc.id for doc in documents_overview) + + if not document_ids_to_purge: raise R2RException( status_code=404, message="No entries found for deletion." ) - document_ids_to_purge = { - doc_id - for doc_id in [ - result.get("document_id", None) for result in results.values() - ] - if doc_id - } for document_id in document_ids_to_purge: - await self.providers.database.relational.delete_from_documents_overview( - document_id - ) + try: + await self.providers.database.relational.delete_from_documents_overview( + str(document_id) + ) + logger.info( + f"Deleted document ID {document_id} from documents_overview." + ) + except Exception as e: + logger.error( + f"Error deleting document ID {document_id} from documents_overview: {e}" + ) + return None @telemetry_event("DownloadFile") @@ -306,7 +350,7 @@ async def download_file( async def documents_overview( self, user_ids: Optional[list[UUID]] = None, - group_ids: Optional[list[UUID]] = None, + collection_ids: Optional[list[UUID]] = None, document_ids: Optional[list[UUID]] = None, offset: Optional[int] = 0, limit: Optional[int] = 100, @@ -316,7 +360,7 @@ async def documents_overview( return await self.providers.database.relational.get_documents_overview( filter_document_ids=document_ids, filter_user_ids=user_ids, - filter_group_ids=group_ids, + filter_collection_ids=collection_ids, offset=offset, limit=limit, ) @@ -433,36 +477,44 @@ async def inspect_knowledge_graph( ) @telemetry_event("AssignDocumentToGroup") - async def assign_document_to_group(self, document_id: str, group_id: UUID): + async def assign_document_to_collection( + self, document_id: str, collection_id: UUID + ): - await self.providers.database.relational.assign_document_to_group( - document_id, group_id + await self.providers.database.relational.assign_document_to_collection( + document_id, collection_id ) - await self.providers.database.vector.assign_document_to_group( - document_id, group_id + self.providers.database.vector.assign_document_to_collection( + document_id, collection_id ) - return {"message": "Document assigned to group successfully"} + return {"message": "Document assigned to collection successfully"} @telemetry_event("RemoveDocumentFromGroup") - async def remove_document_from_group( - self, document_id: str, group_id: UUID + async def remove_document_from_collection( + self, document_id: str, collection_id: UUID ): - await self.providers.database.relational.remove_document_from_group( - document_id, group_id + await self.providers.database.relational.remove_document_from_collection( + document_id, collection_id ) - await self.providers.database.vector.remove_document_from_group( - document_id, group_id + self.providers.database.vector.remove_document_from_collection( + document_id, collection_id ) - return {"message": "Document removed from group successfully"} + return {"message": "Document removed from collection successfully"} @telemetry_event("DocumentGroups") - async def document_groups( + async def document_collections( self, document_id: str, offset: int = 0, limit: int = 100 ): - group_ids = await self.providers.database.relational.document_groups( - document_id, offset=offset, limit=limit + collection_ids = ( + await self.providers.database.relational.document_collections( + document_id, offset=offset, limit=limit + ) ) - return {"group_ids": [str(group_id) for group_id in group_ids]} + return { + "collection_ids": [ + str(collection_id) for collection_id in collection_ids + ] + } def _process_relationships( self, relationships: list[Tuple[str, str, str]] @@ -550,95 +602,115 @@ def _get_central_nodes( return sorted(centrality.items(), key=lambda x: x[1], reverse=True)[:5] @telemetry_event("CreateGroup") - async def create_group(self, name: str, description: str = "") -> UUID: - return await self.providers.database.relational.create_group( + async def create_collection( + self, name: str, description: str = "" + ) -> UUID: + return await self.providers.database.relational.create_collection( name, description ) @telemetry_event("GetGroup") - async def get_group(self, group_id: UUID) -> Optional[dict]: - return await self.providers.database.relational.get_group(group_id) + async def get_collection(self, collection_id: UUID) -> Optional[dict]: + return await self.providers.database.relational.get_collection( + collection_id + ) @telemetry_event("UpdateGroup") - async def update_group( - self, group_id: UUID, name: str = None, description: str = None + async def update_collection( + self, collection_id: UUID, name: str = None, description: str = None ) -> bool: - return await self.providers.database.relational.update_group( - group_id, name, description + return await self.providers.database.relational.update_collection( + collection_id, name, description ) @telemetry_event("DeleteGroup") - async def delete_group(self, group_id: UUID) -> bool: - await self.providers.database.relational.delete_group(group_id) - await self.providers.database.vector.delete_group(group_id) + async def delete_collection(self, collection_id: UUID) -> bool: + await self.providers.database.relational.delete_collection( + collection_id + ) + await self.providers.database.vector.delete_collection(collection_id) return True @telemetry_event("ListGroups") - async def list_groups( + async def list_collections( self, offset: int = 0, limit: int = 100 ) -> list[dict]: - return await self.providers.database.relational.list_groups( + return await self.providers.database.relational.list_collections( offset=offset, limit=limit ) @telemetry_event("AddUserToGroup") - async def add_user_to_group(self, user_id: UUID, group_id: UUID) -> bool: - return await self.providers.database.relational.add_user_to_group( - user_id, group_id + async def add_user_to_collection( + self, user_id: UUID, collection_id: UUID + ) -> bool: + return await self.providers.database.relational.add_user_to_collection( + user_id, collection_id ) @telemetry_event("RemoveUserFromGroup") - async def remove_user_from_group( - self, user_id: UUID, group_id: UUID + async def remove_user_from_collection( + self, user_id: UUID, collection_id: UUID ) -> bool: - return await self.providers.database.relational.remove_user_from_group( - user_id, group_id + return await self.providers.database.relational.remove_user_from_collection( + user_id, collection_id ) @telemetry_event("GetUsersInGroup") - async def get_users_in_group( - self, group_id: UUID, offset: int = 0, limit: int = 100 + async def get_users_in_collection( + self, collection_id: UUID, offset: int = 0, limit: int = 100 ) -> list[dict]: - return await self.providers.database.relational.get_users_in_group( - group_id, offset=offset, limit=limit + return ( + await self.providers.database.relational.get_users_in_collection( + collection_id, offset=offset, limit=limit + ) ) @telemetry_event("GetGroupsForUser") - async def get_groups_for_user( + async def get_collections_for_user( self, user_id: UUID, offset: int = 0, limit: int = 100 ) -> list[dict]: - return await self.providers.database.relational.get_groups_for_user( - user_id, offset, limit + return ( + await self.providers.database.relational.get_collections_for_user( + user_id, offset, limit + ) ) @telemetry_event("GroupsOverview") - async def groups_overview( + async def collections_overview( self, - group_ids: Optional[list[UUID]] = None, + collection_ids: Optional[list[UUID]] = None, offset: int = 0, limit: int = 100, *args, **kwargs, ): - return await self.providers.database.relational.get_groups_overview( - [str(ele) for ele in group_ids] if group_ids else None, - offset=offset, - limit=limit, + return ( + await self.providers.database.relational.get_collections_overview( + ( + [str(ele) for ele in collection_ids] + if collection_ids + else None + ), + offset=offset, + limit=limit, + ) ) @telemetry_event("GetDocumentsInGroup") - async def documents_in_group( - self, group_id: UUID, offset: int = 0, limit: int = 100 + async def documents_in_collection( + self, collection_id: UUID, offset: int = 0, limit: int = 100 ) -> list[dict]: - return await self.providers.database.relational.documents_in_group( - group_id, offset=offset, limit=limit + return ( + await self.providers.database.relational.documents_in_collection( + collection_id, offset=offset, limit=limit + ) ) @telemetry_event("DocumentGroups") - async def document_groups( + async def document_collections( self, document_id: str, offset: int = 0, limit: int = 100 ) -> list[str]: - return await self.providers.database.relational.document_groups( + return await self.providers.database.relational.document_collections( document_id, offset, limit ) diff --git a/py/core/pipes/ingestion/chunking_pipe.py b/py/core/pipes/ingestion/chunking_pipe.py index cad9a2baa..41da6ef44 100644 --- a/py/core/pipes/ingestion/chunking_pipe.py +++ b/py/core/pipes/ingestion/chunking_pipe.py @@ -74,7 +74,7 @@ async def _run_logic( extraction_id=item.id, document_id=item.document_id, user_id=item.user_id, - group_ids=item.group_ids, + collection_ids=item.collection_ids, data=chunk, metadata=item.metadata, ) diff --git a/py/core/pipes/ingestion/embedding_pipe.py b/py/core/pipes/ingestion/embedding_pipe.py index 65496450f..8dc4df30e 100644 --- a/py/core/pipes/ingestion/embedding_pipe.py +++ b/py/core/pipes/ingestion/embedding_pipe.py @@ -60,7 +60,7 @@ async def _process_batch( extraction_id=fragment.extraction_id, document_id=fragment.document_id, user_id=fragment.user_id, - group_ids=fragment.group_ids, + collection_ids=fragment.collection_ids, vector=Vector(data=raw_vector), text=fragment.data, metadata={ @@ -142,7 +142,7 @@ async def _process_fragment( extraction_id=fragment.extraction_id, document_id=fragment.document_id, user_id=fragment.user_id, - group_ids=fragment.group_ids, + collection_ids=fragment.collection_ids, vector=Vector(data=vectors[0]), text=fragment.data, metadata={**fragment.metadata}, diff --git a/py/core/pipes/kg/extraction.py b/py/core/pipes/kg/extraction.py index eb1231552..a30f5b731 100644 --- a/py/core/pipes/kg/extraction.py +++ b/py/core/pipes/kg/extraction.py @@ -18,6 +18,7 @@ PipeType, PromptProvider, R2RDocumentProcessingError, + R2RException, RunLoggingSingleton, Triple, ) @@ -26,6 +27,9 @@ logger = logging.getLogger(__name__) +MIN_VALID_KG_EXTRACTION_RESPONSE_LENGTH = 128 + + class ClientError(Exception): """Base class for client connection errors.""" @@ -104,7 +108,6 @@ async def extract_kg( ) for attempt in range(retries): - try: response = await self.llm_provider.aget_completion( messages, @@ -112,6 +115,7 @@ async def extract_kg( ) kg_extraction = response.choices[0].message.content + entity_pattern = ( r'\("entity"\${4}([^$]+)\${4}([^$]+)\${4}([^$]+)\)' ) @@ -119,6 +123,16 @@ async def extract_kg( def parse_fn(response_str: str) -> Any: entities = re.findall(entity_pattern, response_str) + + if ( + len(kg_extraction) + > MIN_VALID_KG_EXTRACTION_RESPONSE_LENGTH + and len(entities) == 0 + ): + raise R2RException( + "No entities found in the response string, the selected LLM likely failed to format it's response correctly.", + 400, + ) relationships = re.findall( relationship_pattern, response_str ) @@ -181,6 +195,7 @@ def parse_fn(response_str: str) -> Any: json.JSONDecodeError, KeyError, IndexError, + R2RException, ) as e: if attempt < retries - 1: await asyncio.sleep(delay) @@ -223,7 +238,7 @@ async def _run_logic( extraction_id=extraction["extraction_id"], document_id=extraction["document_id"], user_id=extraction["user_id"], - group_ids=extraction["group_ids"], + collection_ids=extraction["collection_ids"], data=extraction["text"], metadata=extraction["metadata"], ) @@ -263,7 +278,7 @@ async def _run_logic( yield await completed_task except Exception as e: logger.error(f"Error in Extracting KG Triples: {e}") - raise R2RDocumentProcessingError( + yield R2RDocumentProcessingError( document_id=document_id, error_message=str(e), - ) from e + ) diff --git a/py/core/pipes/kg/storage.py b/py/core/pipes/kg/storage.py index 35c965053..160a66890 100644 --- a/py/core/pipes/kg/storage.py +++ b/py/core/pipes/kg/storage.py @@ -1,6 +1,6 @@ import asyncio import logging -from typing import Any, AsyncGenerator, Optional, Tuple +from typing import Any, AsyncGenerator, List, Optional, Tuple from uuid import UUID from core.base import ( @@ -8,6 +8,7 @@ EmbeddingProvider, KGExtraction, PipeType, + R2RDocumentProcessingError, RunLoggingSingleton, ) from core.base.pipes.base_pipe import AsyncPipe @@ -18,7 +19,7 @@ class KGStoragePipe(AsyncPipe): class Input(AsyncPipe.Input): - message: AsyncGenerator[KGExtraction, None] + message: AsyncGenerator[List[R2RDocumentProcessingError], None] def __init__( self, @@ -72,14 +73,20 @@ async def _run_logic( run_id: UUID, *args: Any, **kwargs: Any, - ) -> AsyncGenerator[Tuple[int, int], None]: + ) -> AsyncGenerator[List[R2RDocumentProcessingError], None]: """ Executes the async knowledge graph storage pipe: storing knowledge graph extractions in the graph database. """ + batch_tasks = [] kg_batch = [] + errors = [] async for kg_extraction in input.message: + if isinstance(kg_extraction, R2RDocumentProcessingError): + errors.append(kg_extraction) + continue + kg_batch.append(kg_extraction) if len(kg_batch) >= self.storage_batch_size: # Schedule the storage task @@ -100,5 +107,7 @@ async def _run_logic( ) # Wait for all storage tasks to complete - results = await asyncio.gather(*batch_tasks) - yield results + await asyncio.gather(*batch_tasks) + + for error in errors: + yield error diff --git a/py/core/pipes/other/web_search_pipe.py b/py/core/pipes/other/web_search_pipe.py index c46e7e442..55d9af5ca 100644 --- a/py/core/pipes/other/web_search_pipe.py +++ b/py/core/pipes/other/web_search_pipe.py @@ -65,7 +65,7 @@ async def search( uuid.NAMESPACE_DNS, str(uuid.uuid4()) ), # Generate a new UUID for document_id user_id=None, # Web search results don't have a user_id - group_ids=[], # Web search results don't belong to any group + collection_ids=[], # Web search results don't belong to any group score=result.get( "score", 0 ), # TODO - Consider dynamically generating scores based on similarity diff --git a/py/core/pipes/retrieval/streaming_rag_pipe.py b/py/core/pipes/retrieval/streaming_rag_pipe.py index d733db22a..9046b9e46 100644 --- a/py/core/pipes/retrieval/streaming_rag_pipe.py +++ b/py/core/pipes/retrieval/streaming_rag_pipe.py @@ -21,7 +21,9 @@ class StreamingSearchRAGPipe(SearchRAGPipe): - VECTOR_SEARCH_STREAM_MARKER = "search" # TODO - change this to vector_search in next major release + VECTOR_SEARCH_STREAM_MARKER = ( + "search" # TODO - change this to vector_search in next major release + ) KG_LOCAL_SEARCH_STREAM_MARKER = "kg_local_search" KG_GLOBAL_SEARCH_STREAM_MARKER = "kg_global_search" COMPLETION_STREAM_MARKER = "completion" @@ -76,11 +78,18 @@ async def _run_logic( if search_results.kg_search_results[0].local_result: context += "KG Local Search Results:\n" yield f"<{self.KG_LOCAL_SEARCH_STREAM_MARKER}>" - yield json.dumps(search_results.kg_search_results[0].local_result.json()) - context += str(search_results.kg_search_results[0].local_result) + yield json.dumps( + search_results.kg_search_results[0].local_result.json() + ) + context += str( + search_results.kg_search_results[0].local_result + ) yield f"" - if search_results.kg_search_results and search_results.kg_search_results[0].global_result: + if ( + search_results.kg_search_results + and search_results.kg_search_results[0].global_result + ): context += "KG Global Search Results:\n" yield f"<{self.KG_GLOBAL_SEARCH_STREAM_MARKER}>" for result in search_results.kg_search_results: diff --git a/py/core/providers/auth/r2r_auth.py b/py/core/providers/auth/r2r_auth.py index 504ef2ad3..220add96c 100644 --- a/py/core/providers/auth/r2r_auth.py +++ b/py/core/providers/auth/r2r_auth.py @@ -125,7 +125,6 @@ async def register(self, email: str, password: str) -> Dict[str, str]: new_user = await self.db_provider.relational.create_user( email, password ) - if self.config.require_email_verification: # Generate verification code and send email verification_code = ( @@ -217,7 +216,7 @@ async def login(self, email: str, password: str) -> Dict[str, Token]: async def refresh_access_token( self, refresh_token: str ) -> Dict[str, Token]: - token_data = self.decode_token(refresh_token) + token_data = await self.decode_token(refresh_token) if token_data.token_type != "refresh": raise R2RException( status_code=401, message="Invalid refresh token" diff --git a/py/core/providers/database/group.py b/py/core/providers/database/collection.py similarity index 69% rename from py/core/providers/database/group.py rename to py/core/providers/database/collection.py index ed9ae0ffc..36d1dc1b1 100644 --- a/py/core/providers/database/group.py +++ b/py/core/providers/database/collection.py @@ -14,11 +14,11 @@ from .base import DatabaseMixin -class GroupMixin(DatabaseMixin): +class CollectionMixin(DatabaseMixin): async def create_table(self) -> None: query = f""" CREATE TABLE IF NOT EXISTS {self._get_table_name('groups')} ( - group_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), + collection_id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), name TEXT NOT NULL, description TEXT, created_at TIMESTAMPTZ DEFAULT NOW(), @@ -27,23 +27,23 @@ async def create_table(self) -> None: """ await self.execute_query(query) - async def group_exists(self, group_id: UUID) -> bool: + async def group_exists(self, collection_id: UUID) -> bool: """Check if a group exists.""" query = f""" SELECT 1 FROM {self._get_table_name('groups')} - WHERE group_id = $1 + WHERE collection_id = $1 """ - result = await self.execute_query(query, [group_id]) + result = await self.execute_query(query, [collection_id]) return bool(result) - async def create_group( + async def create_collection( self, name: str, description: str = "" ) -> GroupResponse: current_time = datetime.utcnow() query = f""" INSERT INTO {self._get_table_name('groups')} (name, description, created_at, updated_at) VALUES ($1, $2, $3, $4) - RETURNING group_id, name, description, created_at, updated_at + RETURNING collection_id, name, description, created_at, updated_at """ params = [name, description, current_time, current_time] @@ -57,7 +57,7 @@ async def create_group( ) return GroupResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -69,80 +69,80 @@ async def create_group( message=f"An error occurred while creating the group: {str(e)}", ) - async def get_group(self, group_id: UUID) -> GroupResponse: + async def get_collection(self, collection_id: UUID) -> GroupResponse: """Get a group by its ID.""" - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" - SELECT group_id, name, description, created_at, updated_at + SELECT collection_id, name, description, created_at, updated_at FROM {self._get_table_name('groups')} - WHERE group_id = $1 + WHERE collection_id = $1 """ - result = await self.fetchrow_query(query, [group_id]) + result = await self.fetchrow_query(query, [collection_id]) if not result: raise R2RException(status_code=404, message="Group not found") return GroupResponse( - group_id=result["group_id"], + collection_id=result["collection_id"], name=result["name"], description=result["description"], created_at=result["created_at"], updated_at=result["updated_at"], ) - async def update_group( - self, group_id: UUID, name: str, description: str + async def update_collection( + self, collection_id: UUID, name: str, description: str ) -> GroupResponse: """Update an existing group.""" - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" UPDATE {self._get_table_name('groups')} SET name = $1, description = $2, updated_at = NOW() - WHERE group_id = $3 - RETURNING group_id, name, description, created_at, updated_at + WHERE collection_id = $3 + RETURNING collection_id, name, description, created_at, updated_at """ result = await self.fetchrow_query( - query, [name, description, group_id] + query, [name, description, collection_id] ) if not result: raise R2RException(status_code=404, message="Group not found") return GroupResponse( - group_id=result["group_id"], + collection_id=result["collection_id"], name=result["name"], description=result["description"], created_at=result["created_at"], updated_at=result["updated_at"], ) - async def delete_group(self, group_id: UUID) -> None: - # Remove group_id from users + async def delete_collection(self, collection_id: UUID) -> None: + # Remove collection_id from users user_update_query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = array_remove(group_ids, $1) - WHERE $1 = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, $1) + WHERE $1 = ANY(collection_ids) """ - await self.execute_query(user_update_query, [group_id]) + await self.execute_query(user_update_query, [collection_id]) # Delete the group delete_query = f""" DELETE FROM {self._get_table_name('groups')} - WHERE group_id = $1 + WHERE collection_id = $1 """ - result = await self.execute_query(delete_query, [group_id]) + result = await self.execute_query(delete_query, [collection_id]) if result == "DELETE 0": raise R2RException(status_code=404, message="Group not found") - async def list_groups( + async def list_collections( self, offset: int = 0, limit: int = 100 ) -> list[GroupResponse]: """List groups with pagination.""" query = f""" - SELECT group_id, name, description, created_at, updated_at + SELECT collection_id, name, description, created_at, updated_at FROM {self._get_table_name('groups')} ORDER BY name OFFSET $1 @@ -153,7 +153,7 @@ async def list_groups( return [] return [ GroupResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -162,23 +162,23 @@ async def list_groups( for row in results ] - async def get_groups_by_ids( - self, group_ids: list[UUID] + async def get_collections_by_ids( + self, collection_ids: list[UUID] ) -> list[GroupResponse]: query = f""" - SELECT group_id, name, description, created_at, updated_at + SELECT collection_id, name, description, created_at, updated_at FROM {self._get_table_name("groups")} - WHERE group_id = ANY($1) + WHERE collection_id = ANY($1) """ - results = await self.fetch_query(query, [group_ids]) - if len(results) != len(group_ids): + results = await self.fetch_query(query, [collection_ids]) + if len(results) != len(collection_ids): raise R2RException( status_code=404, - message=f"These groups were not found: {set(group_ids) - {row['group_id'] for row in results}}", + message=f"These groups were not found: {set(collection_ids) - {row['collection_id'] for row in results}}", ) return [ GroupResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -187,48 +187,50 @@ async def get_groups_by_ids( for row in results ] - async def add_user_to_group(self, user_id: UUID, group_id: UUID) -> bool: + async def add_user_to_collection( + self, user_id: UUID, collection_id: UUID + ) -> bool: """Add a user to a group.""" - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = array_append(group_ids, $1) - WHERE user_id = $2 AND NOT ($1 = ANY(group_ids)) + SET collection_ids = array_append(collection_ids, $1) + WHERE user_id = $2 AND NOT ($1 = ANY(collection_ids)) RETURNING user_id """ - result = await self.fetchrow_query(query, [group_id, user_id]) + result = await self.fetchrow_query(query, [collection_id, user_id]) return bool(result) - async def remove_user_from_group( - self, user_id: UUID, group_id: UUID + async def remove_user_from_collection( + self, user_id: UUID, collection_id: UUID ) -> None: """Remove a user from a group.""" - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = array_remove(group_ids, $1) - WHERE user_id = $2 AND $1 = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, $1) + WHERE user_id = $2 AND $1 = ANY(collection_ids) RETURNING user_id """ - result = await self.fetchrow_query(query, [group_id, user_id]) + result = await self.fetchrow_query(query, [collection_id, user_id]) if not result: raise R2RException( status_code=404, - message="User is not a member of the specified group", + message="User is not a member of the specified collection", ) - async def get_users_in_group( - self, group_id: UUID, offset: int = 0, limit: int = 100 + async def get_users_in_collection( + self, collection_id: UUID, offset: int = 0, limit: int = 100 ) -> list[UserResponse]: """ Get all users in a specific group with pagination. Args: - group_id (UUID): The ID of the group to get users from. + collection_id (UUID): The ID of the group to get users from. offset (int): The number of users to skip. limit (int): The maximum number of users to return. @@ -238,19 +240,19 @@ async def get_users_in_group( Raises: R2RException: If the group doesn't exist. """ - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" SELECT u.user_id, u.email, u.is_active, u.is_superuser, u.created_at, u.updated_at, - u.is_verified, u.group_ids, u.name, u.bio, u.profile_picture + u.is_verified, u.collection_ids, u.name, u.bio, u.profile_picture FROM {self._get_table_name('users')} u - WHERE $1 = ANY(u.group_ids) + WHERE $1 = ANY(u.collection_ids) ORDER BY u.name OFFSET $2 LIMIT $3 """ - results = await self.fetch_query(query, [group_id, offset, limit]) + results = await self.fetch_query(query, [collection_id, offset, limit]) return [ UserResponse( @@ -261,7 +263,7 @@ async def get_users_in_group( created_at=row["created_at"], updated_at=row["updated_at"], is_verified=row["is_verified"], - group_ids=row["group_ids"], + collection_ids=row["collection_ids"], name=row["name"], bio=row["bio"], profile_picture=row["profile_picture"], @@ -271,13 +273,13 @@ async def get_users_in_group( for row in results ] - async def documents_in_group( - self, group_id: UUID, offset: int = 0, limit: int = 100 + async def documents_in_collection( + self, collection_id: UUID, offset: int = 0, limit: int = 100 ) -> list[DocumentInfo]: """ Get all documents in a specific group with pagination. Args: - group_id (UUID): The ID of the group to get documents from. + collection_id (UUID): The ID of the group to get documents from. offset (int): The number of documents to skip. limit (int): The maximum number of documents to return. Returns: @@ -285,17 +287,17 @@ async def documents_in_group( Raises: R2RException: If the group doesn't exist. """ - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" SELECT d.document_id, d.user_id, d.type, d.metadata, d.title, d.version, d.size_in_bytes, d.ingestion_status, d.created_at, d.updated_at FROM {self._get_table_name('document_info')} d - WHERE $1 = ANY(d.group_ids) + WHERE $1 = ANY(d.collection_ids) ORDER BY d.created_at DESC OFFSET $2 LIMIT $3 """ - results = await self.fetch_query(query, [group_id, offset, limit]) + results = await self.fetch_query(query, [collection_id, offset, limit]) return [ DocumentInfo( id=row["document_id"], @@ -308,34 +310,34 @@ async def documents_in_group( ingestion_status=IngestionStatus(row["ingestion_status"]), created_at=row["created_at"], updated_at=row["updated_at"], - group_ids=[group_id], + collection_ids=[collection_id], ) for row in results ] - async def get_groups_overview( + async def get_collections_overview( self, - group_ids: Optional[list[UUID]] = None, + collection_ids: Optional[list[UUID]] = None, offset: int = 0, limit: int = 100, ) -> list[GroupOverviewResponse]: """Get an overview of groups, optionally filtered by group IDs, with pagination.""" query = f""" WITH group_overview AS ( - SELECT g.group_id, g.name, g.description, g.created_at, g.updated_at, + SELECT g.collection_id, g.name, g.description, g.created_at, g.updated_at, COUNT(DISTINCT u.user_id) AS user_count, COUNT(DISTINCT d.document_id) AS document_count FROM {self._get_table_name('groups')} g - LEFT JOIN {self._get_table_name('users')} u ON g.group_id = ANY(u.group_ids) - LEFT JOIN {self._get_table_name('document_info')} d ON g.group_id = ANY(d.group_ids) + LEFT JOIN {self._get_table_name('users')} u ON g.collection_id = ANY(u.collection_ids) + LEFT JOIN {self._get_table_name('document_info')} d ON g.collection_id = ANY(d.collection_ids) """ params = [] - if group_ids: - query += " WHERE g.group_id = ANY($1)" - params.append(group_ids) + if collection_ids: + query += " WHERE g.collection_id = ANY($1)" + params.append(collection_ids) query += """ - GROUP BY g.group_id, g.name, g.description, g.created_at, g.updated_at + GROUP BY g.collection_id, g.name, g.description, g.created_at, g.updated_at ) SELECT * FROM group_overview ORDER BY name @@ -349,7 +351,7 @@ async def get_groups_overview( results = await self.fetch_query(query, params) return [ GroupOverviewResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -360,13 +362,13 @@ async def get_groups_overview( for row in results ] - async def get_groups_for_user( + async def get_collections_for_user( self, user_id: UUID, offset: int = 0, limit: int = 100 ) -> list[GroupResponse]: query = f""" - SELECT g.group_id, g.name, g.description, g.created_at, g.updated_at + SELECT g.collection_id, g.name, g.description, g.created_at, g.updated_at FROM {self._get_table_name('groups')} g - JOIN {self._get_table_name('users')} u ON g.group_id = ANY(u.group_ids) + JOIN {self._get_table_name('users')} u ON g.collection_id = ANY(u.collection_ids) WHERE u.user_id = $1 ORDER BY g.name OFFSET $2 @@ -376,7 +378,7 @@ async def get_groups_for_user( return [ GroupResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -385,22 +387,22 @@ async def get_groups_for_user( for row in results ] - async def assign_document_to_group( - self, document_id: UUID, group_id: UUID + async def assign_document_to_collection( + self, document_id: UUID, collection_id: UUID ) -> None: """ Assign a document to a group. Args: document_id (UUID): The ID of the document to assign. - group_id (UUID): The ID of the group to assign the document to. + collection_id (UUID): The ID of the group to assign the document to. Raises: R2RException: If the group doesn't exist, if the document is not found, or if there's a database error. """ try: - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") # First, check if the document exists @@ -420,12 +422,12 @@ async def assign_document_to_group( # If document exists, proceed with the assignment assign_query = f""" UPDATE {self._get_table_name('document_info')} - SET group_ids = array_append(group_ids, $1) - WHERE document_id = $2 AND NOT ($1 = ANY(group_ids)) + SET collection_ids = array_append(collection_ids, $1) + WHERE document_id = $2 AND NOT ($1 = ANY(collection_ids)) RETURNING document_id """ result = await self.fetchrow_query( - assign_query, [group_id, document_id] + assign_query, [collection_id, document_id] ) if not result: @@ -444,13 +446,13 @@ async def assign_document_to_group( message=f"An error '{e}' occurred while assigning the document to the group", ) - async def document_groups( + async def document_collections( self, document_id: UUID, offset: int = 0, limit: int = 100 ) -> list[GroupResponse]: query = f""" - SELECT g.group_id, g.name, g.description, g.created_at, g.updated_at + SELECT g.collection_id, g.name, g.description, g.created_at, g.updated_at FROM {self._get_table_name('groups')} g - JOIN {self._get_table_name('document_info')} d ON g.group_id = ANY(d.group_ids) + JOIN {self._get_table_name('document_info')} d ON g.collection_id = ANY(d.collection_ids) WHERE d.document_id = $1 ORDER BY g.name OFFSET $2 @@ -460,7 +462,7 @@ async def document_groups( return [ GroupResponse( - group_id=row["group_id"], + collection_id=row["collection_id"], name=row["name"], description=row["description"], created_at=row["created_at"], @@ -469,29 +471,29 @@ async def document_groups( for row in results ] - async def remove_document_from_group( - self, document_id: UUID, group_id: UUID + async def remove_document_from_collection( + self, document_id: UUID, collection_id: UUID ) -> None: """ Remove a document from a group. Args: document_id (UUID): The ID of the document to remove. - group_id (UUID): The ID of the group to remove the document from. + collection_id (UUID): The ID of the group to remove the document from. Raises: R2RException: If the group doesn't exist or if the document is not in the group. """ - if not await self.group_exists(group_id): + if not await self.group_exists(collection_id): raise R2RException(status_code=404, message="Group not found") query = f""" UPDATE {self._get_table_name('document_info')} - SET group_ids = array_remove(group_ids, $1) - WHERE document_id = $2 AND $1 = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, $1) + WHERE document_id = $2 AND $1 = ANY(collection_ids) RETURNING document_id """ - result = await self.fetchrow_query(query, [group_id, document_id]) + result = await self.fetchrow_query(query, [collection_id, document_id]) if not result: raise R2RException( diff --git a/py/core/providers/database/document.py b/py/core/providers/database/document.py index 6e9fddb20..93c937f5d 100644 --- a/py/core/providers/database/document.py +++ b/py/core/providers/database/document.py @@ -38,7 +38,7 @@ def __init__(self, *args, **kwargs): self._get_table_name("document_info"), self.metadata, Column("document_id", UUID, primary_key=True), - Column("group_ids", ARRAY(UUID)), + Column("collection_ids", ARRAY(UUID)), Column("user_id", UUID), Column("type", String), Column("metadata", JSON), @@ -56,7 +56,7 @@ async def create_table(self): query = f""" CREATE TABLE IF NOT EXISTS {self._get_table_name('document_info')} ( document_id UUID PRIMARY KEY, - group_ids UUID[], + collection_ids UUID[], user_id UUID, type TEXT, metadata JSONB, @@ -69,8 +69,8 @@ async def create_table(self): updated_at TIMESTAMPTZ DEFAULT NOW(), ingestion_attempt_number INT DEFAULT 0 ); - CREATE INDEX IF NOT EXISTS idx_group_ids_{self.collection_name} - ON {self._get_table_name('document_info')} USING GIN (group_ids); + CREATE INDEX IF NOT EXISTS idx_collection_ids_{self.collection_name} + ON {self._get_table_name('document_info')} USING GIN (collection_ids); """ await self.execute_query(query) @@ -142,14 +142,14 @@ async def upsert_documents_overview( update_query = f""" UPDATE {self._get_table_name('document_info')} - SET group_ids = $1, user_id = $2, type = $3, metadata = $4, + SET collection_ids = $1, user_id = $2, type = $3, metadata = $4, title = $5, version = $6, size_in_bytes = $7, ingestion_status = $8, restructuring_status = $9, updated_at = $10, ingestion_attempt_number = $11 WHERE document_id = $12 """ await conn.execute( update_query, - db_entry["group_ids"], + db_entry["collection_ids"], db_entry["user_id"], db_entry["type"], db_entry["metadata"], @@ -165,7 +165,7 @@ async def upsert_documents_overview( else: insert_query = f""" INSERT INTO {self._get_table_name('document_info')} - (document_id, group_ids, user_id, type, metadata, title, version, + (document_id, collection_ids, user_id, type, metadata, title, version, size_in_bytes, ingestion_status, restructuring_status, created_at, updated_at, ingestion_attempt_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) @@ -173,7 +173,7 @@ async def upsert_documents_overview( await conn.execute( insert_query, db_entry["document_id"], - db_entry["group_ids"], + db_entry["collection_ids"], db_entry["user_id"], db_entry["type"], db_entry["metadata"], @@ -222,7 +222,7 @@ async def get_documents_overview( self, filter_user_ids: Optional[list[UUID]] = None, filter_document_ids: Optional[list[UUID]] = None, - filter_group_ids: Optional[list[UUID]] = None, + filter_collection_ids: Optional[list[UUID]] = None, offset: int = 0, limit: int = 100, ) -> list[DocumentInfo]: @@ -240,9 +240,9 @@ async def get_documents_overview( params.append(filter_user_ids) param_index += 1 - if filter_group_ids: - conditions.append(f"group_ids && ${param_index}") - params.append(filter_group_ids) + if filter_collection_ids: + conditions.append(f"collection_ids && ${param_index}") + params.append(filter_collection_ids) param_index += 1 base_query = f""" @@ -253,7 +253,7 @@ async def get_documents_overview( base_query += " WHERE " + " AND ".join(conditions) query = f""" - SELECT document_id, group_ids, user_id, type, metadata, title, version, + SELECT document_id, collection_ids, user_id, type, metadata, title, version, size_in_bytes, ingestion_status, created_at, updated_at, restructuring_status {base_query} ORDER BY created_at DESC @@ -272,7 +272,7 @@ async def get_documents_overview( return [ DocumentInfo( id=row["document_id"], - group_ids=row["group_ids"], + collection_ids=row["collection_ids"], user_id=row["user_id"], type=DocumentType(row["type"]), metadata=json.loads(row["metadata"]), diff --git a/py/core/providers/database/postgres.py b/py/core/providers/database/postgres.py index b857791b1..040a0f456 100644 --- a/py/core/providers/database/postgres.py +++ b/py/core/providers/database/postgres.py @@ -68,18 +68,20 @@ def __init__( ) self.db_name = db_name - collection_name = config.vecs_collection or os.getenv( - "POSTGRES_VECS_COLLECTION" + collection_name = ( + config.vecs_collection + or os.getenv("POSTGRES_PROJECT_NAME") + or os.getenv("POSTGRES_VECS_COLLECTION") ) if not collection_name: raise ValueError( - "Error, please set a valid POSTGRES_VECS_COLLECTION environment variable or set a 'vecs_collection' in the 'database' settings of your `r2r.toml`." + "Error, please set a valid POSTGRES_PROJECT_NAME environment variable or set a 'vecs_collection' in the 'database' settings of your `r2r.toml`." ) self.collection_name = collection_name if not all([user, password, host, port, db_name, collection_name]): raise ValueError( - "Error, please set the POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DBNAME, and POSTGRES_VECS_COLLECTION environment variables to use pgvector database." + "Error, please set the POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, POSTGRES_PORT, POSTGRES_DBNAME, and POSTGRES_PROJECT_NAME environment variables to use pgvector database." ) # Check if it's a Unix socket connection diff --git a/py/core/providers/database/relational.py b/py/core/providers/database/relational.py index 887fb5b3b..0d57147b4 100644 --- a/py/core/providers/database/relational.py +++ b/py/core/providers/database/relational.py @@ -4,17 +4,18 @@ import asyncpg from core.providers.database.base import DatabaseMixin +from core.providers.database.collection import CollectionMixin from core.providers.database.document import DocumentMixin -from core.providers.database.group import GroupMixin from core.providers.database.tokens import BlacklistedTokensMixin from core.providers.database.user import UserMixin +from core.providers.database.collection import CollectionMixin logger = logging.getLogger(__name__) class PostgresRelationalDBProvider( DocumentMixin, - GroupMixin, + CollectionMixin, BlacklistedTokensMixin, UserMixin, ): diff --git a/py/core/providers/database/user.py b/py/core/providers/database/user.py index 0ebd4791f..58dd3d890 100644 --- a/py/core/providers/database/user.py +++ b/py/core/providers/database/user.py @@ -26,7 +26,7 @@ async def create_table(self): profile_picture TEXT, reset_token TEXT, reset_token_expiry TIMESTAMPTZ, - group_ids UUID[] NULL, + collection_ids UUID[] NULL, created_at TIMESTAMPTZ DEFAULT NOW(), updated_at TIMESTAMPTZ DEFAULT NOW() ); @@ -34,7 +34,7 @@ async def create_table(self): await self.execute_query(query) async def get_user_by_id(self, user_id: UUID) -> Optional[UserResponse]: - query = ( + query, _ = ( QueryBuilder(self._get_table_name("users")) .select( [ @@ -49,7 +49,7 @@ async def get_user_by_id(self, user_id: UUID) -> Optional[UserResponse]: "name", "profile_picture", "bio", - "group_ids", + "collection_ids", ] ) .where("user_id = $1") @@ -72,7 +72,7 @@ async def get_user_by_id(self, user_id: UUID) -> Optional[UserResponse]: name=result["name"], profile_picture=result["profile_picture"], bio=result["bio"], - group_ids=result["group_ids"], + collection_ids=result["collection_ids"], ) async def get_user_by_email(self, email: str) -> UserResponse: @@ -91,7 +91,7 @@ async def get_user_by_email(self, email: str) -> UserResponse: "name", "profile_picture", "bio", - "group_ids", + "collection_ids", ] ) .where("email = $1") @@ -114,7 +114,7 @@ async def get_user_by_email(self, email: str) -> UserResponse: name=result["name"], profile_picture=result["profile_picture"], bio=result["bio"], - group_ids=result["group_ids"], + collection_ids=result["collection_ids"], ) if result else None @@ -134,9 +134,9 @@ async def create_user(self, email: str, password: str) -> UserResponse: hashed_password = self.crypto_provider.get_password_hash(password) query = f""" INSERT INTO {self._get_table_name('users')} - (email, user_id, hashed_password, group_ids) + (email, user_id, hashed_password, collection_ids) VALUES ($1, $2, $3, $4) - RETURNING user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, group_ids + RETURNING user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, collection_ids """ result = await self.fetchrow_query( query, [email, generate_id_from_label(email), hashed_password, []] @@ -155,7 +155,7 @@ async def create_user(self, email: str, password: str) -> UserResponse: is_verified=result["is_verified"], created_at=result["created_at"], updated_at=result["updated_at"], - group_ids=result["group_ids"], + collection_ids=result["collection_ids"], hashed_password=hashed_password, ) @@ -163,9 +163,9 @@ async def update_user(self, user: UserResponse) -> UserResponse: query = f""" UPDATE {self._get_table_name('users')} SET email = $1, is_superuser = $2, is_active = $3, is_verified = $4, updated_at = NOW(), - name = $5, profile_picture = $6, bio = $7, group_ids = $8 + name = $5, profile_picture = $6, bio = $7, collection_ids = $8 WHERE user_id = $9 - RETURNING user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, name, profile_picture, bio, group_ids + RETURNING user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, name, profile_picture, bio, collection_ids """ result = await self.fetchrow_query( query, @@ -177,7 +177,7 @@ async def update_user(self, user: UserResponse) -> UserResponse: user.name, user.profile_picture, user.bio, - user.group_ids, + user.collection_ids, user.id, ], ) @@ -198,18 +198,20 @@ async def update_user(self, user: UserResponse) -> UserResponse: name=result["name"], profile_picture=result["profile_picture"], bio=result["bio"], - group_ids=result["group_ids"], + collection_ids=result["collection_ids"], ) async def delete_user(self, user_id: UUID) -> None: - # Get the groups the user belongs to - group_query = f""" - SELECT group_ids FROM {self._get_table_name('users')} + # Get the collections the user belongs to + collection_query = f""" + SELECT collection_ids FROM {self._get_table_name('users')} WHERE user_id = $1 """ - group_result = await self.fetchrow_query(group_query, [user_id]) + collection_result = await self.fetchrow_query( + collection_query, [user_id] + ) - if not group_result: + if not collection_result: raise R2RException(status_code=404, message="User not found") # Remove user from documents @@ -243,7 +245,7 @@ async def update_user_password( async def get_all_users(self) -> list[UserResponse]: query = f""" - SELECT user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, group_ids + SELECT user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, collection_ids FROM {self._get_table_name('users')} """ results = await self.fetch_query(query) @@ -258,7 +260,7 @@ async def get_all_users(self) -> list[UserResponse]: is_verified=result["is_verified"], created_at=result["created_at"], updated_at=result["updated_at"], - group_ids=result["group_ids"], + collection_ids=result["collection_ids"], ) for result in results ] @@ -331,50 +333,52 @@ async def remove_reset_token(self, user_id: UUID): """ await self.execute_query(query, [user_id]) - async def remove_user_from_all_groups(self, user_id: UUID): + async def remove_user_from_all_collections(self, user_id: UUID): query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = ARRAY[]::UUID[] + SET collection_ids = ARRAY[]::UUID[] WHERE user_id = $1 """ await self.execute_query(query, [user_id]) - async def add_user_to_group(self, user_id: UUID, group_id: UUID) -> None: + async def add_user_to_collection( + self, user_id: UUID, collection_id: UUID + ) -> None: if not await self.get_user_by_id(user_id): raise R2RException(status_code=404, message="User not found") query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = array_append(group_ids, $1) - WHERE user_id = $2 AND NOT ($1 = ANY(group_ids)) + SET collection_ids = array_append(collection_ids, $1) + WHERE user_id = $2 AND NOT ($1 = ANY(collection_ids)) RETURNING user_id """ result = await self.fetchrow_query( - query, [group_id, user_id] + query, [collection_id, user_id] ) # fetchrow instead of execute_query if not result: raise R2RException( - status_code=400, message="User already in group" + status_code=400, message="User already in collection" ) return None - async def remove_user_from_group( - self, user_id: UUID, group_id: UUID + async def remove_user_from_collection( + self, user_id: UUID, collection_id: UUID ) -> None: if not await self.get_user_by_id(user_id): raise R2RException(status_code=404, message="User not found") query = f""" UPDATE {self._get_table_name('users')} - SET group_ids = array_remove(group_ids, $1) - WHERE user_id = $2 AND $1 = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, $1) + WHERE user_id = $2 AND $1 = ANY(collection_ids) RETURNING user_id """ - result = await self.fetchrow_query(query, [group_id, user_id]) + result = await self.fetchrow_query(query, [collection_id, user_id]) if not result: raise R2RException( status_code=400, - message="User is not a member of the specified group", + message="User is not a member of the specified collection", ) return None @@ -386,17 +390,17 @@ async def mark_user_as_superuser(self, user_id: UUID): """ await self.execute_query(query, [user_id]) - async def get_users_in_group( - self, group_id: UUID, offset: int = 0, limit: int = 100 + async def get_users_in_collection( + self, collection_id: UUID, offset: int = 0, limit: int = 100 ) -> list[UserResponse]: query = f""" - SELECT user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, name, profile_picture, bio, group_ids + SELECT user_id, email, is_superuser, is_active, is_verified, created_at, updated_at, name, profile_picture, bio, collection_ids FROM {self._get_table_name('users')} - WHERE $1 = ANY(group_ids) + WHERE $1 = ANY(collection_ids) ORDER BY email OFFSET $2 LIMIT $3 """ - results = await self.fetch_query(query, [group_id, offset, limit]) + results = await self.fetch_query(query, [collection_id, offset, limit]) return [ UserResponse( @@ -410,7 +414,7 @@ async def get_users_in_group( name=row["name"], profile_picture=row["profile_picture"], bio=row["bio"], - group_ids=row["group_ids"], + collection_ids=row["collection_ids"], ) for row in results ] @@ -455,14 +459,14 @@ async def get_users_overview( u.is_verified, u.created_at, u.updated_at, - u.group_ids, + u.collection_ids, COUNT(d.document_id) AS num_files, COALESCE(SUM(d.size_in_bytes), 0) AS total_size_in_bytes, ARRAY_AGG(d.document_id) FILTER (WHERE d.document_id IS NOT NULL) AS document_ids FROM {self._get_table_name('users')} u LEFT JOIN {self._get_table_name('document_info')} d ON u.user_id = d.user_id {' WHERE u.user_id = ANY($3::uuid[])' if user_ids else ''} - GROUP BY u.user_id, u.email, u.is_superuser, u.is_active, u.is_verified, u.created_at, u.updated_at, u.group_ids + GROUP BY u.user_id, u.email, u.is_superuser, u.is_active, u.is_verified, u.created_at, u.updated_at, u.collection_ids ) SELECT * FROM user_docs @@ -486,7 +490,7 @@ async def get_users_overview( is_verified=row[4], created_at=row[5], updated_at=row[6], - group_ids=row[7] or [], + collection_ids=row[7] or [], num_files=row[8], total_size_in_bytes=row[9], document_ids=row[10] or [], diff --git a/py/core/providers/database/vecs/adapter/noop.py b/py/core/providers/database/vecs/adapter/noop.py index 157dcb46e..3e4056860 100644 --- a/py/core/providers/database/vecs/adapter/noop.py +++ b/py/core/providers/database/vecs/adapter/noop.py @@ -47,7 +47,7 @@ def __call__( extraction_id, document_id, user_id, - group_ids, + collection_ids, vec, text, metadata, @@ -57,7 +57,7 @@ def __call__( str(extraction_id), str(document_id), str(user_id), - [str(gid) for gid in group_ids], + [str(gid) for gid in collection_ids], vec, text, metadata or {}, diff --git a/py/core/providers/database/vecs/collection.py b/py/core/providers/database/vecs/collection.py index 8a643c3fd..91543f98d 100644 --- a/py/core/providers/database/vecs/collection.py +++ b/py/core/providers/database/vecs/collection.py @@ -197,7 +197,7 @@ class Collection: "extraction_id", "document_id", "user_id", - "group_ids", + "collection_ids", ] def __init__( @@ -243,7 +243,7 @@ def __init__( ) elif len(reported_dimensions) > 1: raise MismatchedDimension( - "Mismatch in the reported dimensions of the selected vector collection and embedding model. Correct the selected embedding model or specify a new vector collection by modifying the `POSTGRES_VECS_COLLECTION` environment variable." + "Mismatch in the reported dimensions of the selected vector collection and embedding model. Correct the selected embedding model or specify a new vector collection by modifying the `POSTGRES_PROJECT_NAME` environment variable." ) def __repr__(self): @@ -312,7 +312,7 @@ def _create_if_not_exists(self): ) if len(reported_dimensions) > 1: raise MismatchedDimension( - "Mismatch in the reported dimensions of the selected vector collection and embedding model. Correct the selected embedding model or specify a new vector collection by modifying the `POSTGRES_VECS_COLLECTION` environment variable." + "Mismatch in the reported dimensions of the selected vector collection and embedding model. Correct the selected embedding model or specify a new vector collection by modifying the `POSTGRES_PROJECT_NAME` environment variable." ) if not collection_dimension: @@ -400,7 +400,7 @@ def upsert( "extraction_id": record[1], "document_id": record[2], "user_id": record[3], - "group_ids": record[4], + "collection_ids": record[4], "vec": record[5], "text": record[6], "metadata": record[7], @@ -415,7 +415,7 @@ def upsert( extraction_id=stmt.excluded.extraction_id, document_id=stmt.excluded.document_id, user_id=stmt.excluded.user_id, - group_ids=stmt.excluded.group_ids, + collection_ids=stmt.excluded.collection_ids, vec=stmt.excluded.vec, text=stmt.excluded.text, metadata=stmt.excluded.metadata, @@ -593,7 +593,7 @@ def semantic_search( self.table.c.extraction_id, self.table.c.document_id, self.table.c.user_id, - self.table.c.group_ids, + self.table.c.collection_ids, self.table.c.text, ] if search_settings.include_values: @@ -646,7 +646,7 @@ def full_text_search( self.table.c.extraction_id, self.table.c.document_id, self.table.c.user_id, - self.table.c.group_ids, + self.table.c.collection_ids, self.table.c.text, self.table.c.metadata, rank_function, @@ -668,7 +668,7 @@ def full_text_search( extraction_id=str(r.extraction_id), document_id=str(r.document_id), user_id=str(r.user_id), - group_ids=r.group_ids, + collection_ids=r.collection_ids, text=r.text, score=float(r.rank), metadata=r.metadata, @@ -715,7 +715,7 @@ def parse_condition(key, value): elif op == "$contains": return column.contains(clause) elif op == "$any": - if key == "group_ids": + if key == "collection_ids": # Use ANY for UUID array comparison return func.array_to_string(column, ",").like( f"%{clause}%" @@ -1077,7 +1077,9 @@ def _build_table(name: str, meta: MetaData, dimension: int) -> Table: Column("document_id", postgresql.UUID, nullable=False), Column("user_id", postgresql.UUID, nullable=False), Column( - "group_ids", postgresql.ARRAY(postgresql.UUID), server_default="{}" + "collection_ids", + postgresql.ARRAY(postgresql.UUID), + server_default="{}", ), Column("vec", Vector(dimension), nullable=False), Column("text", postgresql.TEXT, nullable=True), diff --git a/py/core/providers/database/vector.py b/py/core/providers/database/vector.py index 7f66b0926..bd8338e39 100644 --- a/py/core/providers/database/vector.py +++ b/py/core/providers/database/vector.py @@ -82,7 +82,7 @@ def upsert(self, entry: VectorEntry) -> None: entry.extraction_id, entry.document_id, entry.user_id, - entry.group_ids, + entry.collection_ids, entry.vector.data, entry.text, entry.metadata, @@ -103,7 +103,7 @@ def upsert_entries(self, entries: list[VectorEntry]) -> None: entry.extraction_id, entry.document_id, entry.user_id, - entry.group_ids, + entry.collection_ids, entry.vector.data, entry.text, entry.metadata, @@ -128,7 +128,7 @@ def semantic_search( extraction_id=result[1], document_id=result[2], user_id=result[3], - group_ids=result[4], + collection_ids=result[4], text=result[5], score=1 - float(result[6]), metadata=result[7], @@ -267,7 +267,7 @@ def hybrid_search( extraction_id=result["data"].extraction_id, document_id=result["data"].document_id, user_id=result["data"].user_id, - group_ids=result["data"].group_ids, + collection_ids=result["data"].collection_ids, text=result["data"].text, score=result["rrf_score"], metadata={ @@ -311,85 +311,87 @@ def delete( return self.collection.delete(filters=filters) - def assign_document_to_group( - self, document_id: str, group_id: str + def assign_document_to_collection( + self, document_id: str, collection_id: str ) -> None: """ - Assign a document to a group in the vector database. + Assign a document to a collection in the vector database. Args: document_id (str): The ID of the document to assign. - group_id (str): The ID of the group to assign the document to. + collection_id (str): The ID of the collection to assign the document to. Raises: ValueError: If the collection is not initialized. """ if self.collection is None: raise ValueError( - "Please call `initialize_collection` before attempting to run `assign_document_to_group`." + "Please call `initialize_collection` before attempting to run `assign_document_to_collection`." ) table_name = self.collection.table.name query = text( f""" UPDATE vecs."{table_name}" - SET group_ids = array_append(group_ids, :group_id) - WHERE document_id = :document_id AND NOT (:group_id = ANY(group_ids)) + SET collection_ids = array_append(collection_ids, :collection_id) + WHERE document_id = :document_id AND NOT (:collection_id = ANY(collection_ids)) RETURNING document_id """ ) with self.vx.Session() as sess: result = sess.execute( - query, {"document_id": document_id, "group_id": group_id} + query, + {"document_id": document_id, "collection_id": collection_id}, ) sess.commit() if result.rowcount == 0: logger.warning( - f"Document {document_id} not found or already assigned to group {group_id}" + f"Document {document_id} not found or already assigned to collection {collection_id}" ) - def remove_document_from_group( - self, document_id: str, group_id: str + def remove_document_from_collection( + self, document_id: str, collection_id: str ) -> None: """ - Remove a document from a group in the vector database. + Remove a document from a collection in the vector database. Args: document_id (str): The ID of the document to remove. - group_id (str): The ID of the group to remove the document from. + collection_id (str): The ID of the collection to remove the document from. Raises: ValueError: If the collection is not initialized. """ if self.collection is None: raise ValueError( - "Please call `initialize_collection` before attempting to run `remove_document_from_group`." + "Please call `initialize_collection` before attempting to run `remove_document_from_collection`." ) table_name = self.collection.table.name query = text( f""" UPDATE vecs."{table_name}" - SET group_ids = array_remove(group_ids, :group_id) - WHERE document_id = :document_id AND :group_id = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, :collection_id) + WHERE document_id = :document_id AND :collection_id = ANY(collection_ids) RETURNING document_id """ ) with self.vx.Session() as sess: result = sess.execute( - query, {"document_id": document_id, "group_id": group_id} + query, + {"document_id": document_id, "collection_id": collection_id}, ) sess.commit() if result.rowcount == 0: logger.warning( - f"Document {document_id} not found in group {group_id} or already removed" + f"Document {document_id} not found in collection {collection_id} or already removed" ) - def remove_group_from_documents(self, group_id: str) -> None: + def remove_collection_from_documents(self, collection_id: str) -> None: if self.collection is None: raise ValueError("Collection is not initialized.") @@ -397,13 +399,13 @@ def remove_group_from_documents(self, group_id: str) -> None: query = text( f""" UPDATE vecs."{table_name}" - SET group_ids = array_remove(group_ids, :group_id) - WHERE :group_id = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, :collection_id) + WHERE :collection_id = ANY(collection_ids) """ ) with self.vx.Session() as sess: - sess.execute(query, {"group_id": group_id}) + sess.execute(query, {"collection_id": collection_id}) sess.commit() def delete_user(self, user_id: str) -> None: @@ -423,12 +425,12 @@ def delete_user(self, user_id: str) -> None: sess.execute(query, {"user_id": user_id}) sess.commit() - def delete_group(self, group_id: str) -> None: + def delete_collection(self, collection_id: str) -> None: """ - Remove the specified group ID from all documents in the vector database. + Remove the specified collection ID from all documents in the vector database. Args: - group_id (str): The ID of the group to remove from all documents. + collection_id (str): The ID of the collection to remove from all documents. Raises: ValueError: If the collection is not initialized. @@ -440,18 +442,18 @@ def delete_group(self, group_id: str) -> None: query = text( f""" UPDATE vecs."{table_name}" - SET group_ids = array_remove(group_ids, :group_id) - WHERE :group_id = ANY(group_ids) + SET collection_ids = array_remove(collection_ids, :collection_id) + WHERE :collection_id = ANY(collection_ids) """ ) with self.vx.Session() as sess: - result = sess.execute(query, {"group_id": group_id}) + result = sess.execute(query, {"collection_id": collection_id}) sess.commit() affected_rows = result.rowcount logger.info( - f"Removed group {group_id} from {affected_rows} documents." + f"Removed collection {collection_id} from {affected_rows} documents." ) def get_document_chunks( @@ -464,7 +466,7 @@ def get_document_chunks( table_name = self.collection.table.name query = text( f""" - SELECT fragment_id, extraction_id, document_id, user_id, group_ids, text, metadata + SELECT fragment_id, extraction_id, document_id, user_id, collection_ids, text, metadata FROM vecs."{table_name}" WHERE document_id = :document_id ORDER BY CAST(metadata->>'chunk_order' AS INTEGER) @@ -485,7 +487,7 @@ def get_document_chunks( "extraction_id": result[1], "document_id": result[2], "user_id": result[3], - "group_ids": result[4], + "collection_ids": result[4], "text": result[5], "metadata": result[6], } diff --git a/py/core/providers/kg/neo4j/provider.py b/py/core/providers/kg/neo4j/provider.py index a3a25e276..df1060839 100644 --- a/py/core/providers/kg/neo4j/provider.py +++ b/py/core/providers/kg/neo4j/provider.py @@ -506,8 +506,6 @@ def perform_graph_clustering(self, leiden_params: dict) -> Tuple[int, int]: } )""" - # print(GRAPH_PROJECTION_QUERY) - result = self.structured_query(GRAPH_PROJECTION_QUERY) # step 2: run the hierarchical leiden algorithm on the graph. diff --git a/py/core/providers/orchestration/hatchet.py b/py/core/providers/orchestration/hatchet.py index b668f438b..9a1b97eba 100644 --- a/py/core/providers/orchestration/hatchet.py +++ b/py/core/providers/orchestration/hatchet.py @@ -38,6 +38,4 @@ async def start_worker(self): "Worker not initialized. Call get_worker() first." ) - # loop = asyncio.get_event_loop() - print("Starting worker....") - task = asyncio.create_task(self.worker.async_start()) + asyncio.create_task(self.worker.async_start()) diff --git a/py/core/providers/parsing/r2r_parsing.py b/py/core/providers/parsing/r2r_parsing.py index e90ac347e..720f061ce 100644 --- a/py/core/providers/parsing/r2r_parsing.py +++ b/py/core/providers/parsing/r2r_parsing.py @@ -85,7 +85,7 @@ async def parse( id=generate_id_from_label(f"{document.id}-{iteration}"), document_id=document.id, user_id=document.user_id, - group_ids=document.group_ids, + collection_ids=document.collection_ids, data=text, metadata=document.metadata, ) diff --git a/py/core/providers/parsing/unstructured_parsing.py b/py/core/providers/parsing/unstructured_parsing.py index 1189a410e..91715b716 100644 --- a/py/core/providers/parsing/unstructured_parsing.py +++ b/py/core/providers/parsing/unstructured_parsing.py @@ -233,7 +233,7 @@ async def parse( id=generate_id_from_label(f"{document.id}-{iteration}"), document_id=document.id, user_id=document.user_id, - group_ids=document.group_ids, + collection_ids=document.collection_ids, data=text, metadata=metadata, ) diff --git a/py/r2r/__init__.py b/py/r2r/__init__.py index 5b07351d6..5fbfc83a7 100644 --- a/py/r2r/__init__.py +++ b/py/r2r/__init__.py @@ -16,14 +16,14 @@ "__version__", ] -try: - import core - from core import * - - __all__ += core.__all__ -except ImportError: - # Core dependencies not installed - pass +# try: +import core +from core import * + +__all__ += core.__all__ +# except ImportError: +# # Core dependencies not installed +# pass # Add a function to get the version diff --git a/py/sdk/client.py b/py/sdk/client.py index da90521b6..7f8093b09 100644 --- a/py/sdk/client.py +++ b/py/sdk/client.py @@ -87,7 +87,7 @@ def __init__( self.client = custom_client or httpx.AsyncClient(timeout=timeout) self.timeout = timeout - # Initialize method groups + # Initialize methods grouop self._auth = AuthMethods self._ingestion = IngestionMethods self._management = ManagementMethods @@ -95,9 +95,9 @@ def __init__( self._retrieval = RetrievalMethods self._server = ServerMethods - # Collect all methods from the method groups + # Collect all methods from the methods group self._methods = {} - for group in [ + for collection in [ self._auth, self._ingestion, self._management, @@ -106,7 +106,7 @@ def __init__( self._server, ]: for name, method in inspect.getmembers( - group, predicate=inspect.isfunction + collection, predicate=inspect.isfunction ): if not name.startswith("_"): self._methods[name] = method diff --git a/py/sdk/management.py b/py/sdk/management.py index b9a839547..1feb9ccce 100644 --- a/py/sdk/management.py +++ b/py/sdk/management.py @@ -343,46 +343,46 @@ async def inspect_knowledge_graph( ) @staticmethod - async def groups_overview( + async def collections_overview( client, - group_ids: Optional[list[str]] = None, + collection_ids: Optional[list[str]] = None, offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - Get an overview of existing groups. + Get an overview of existing collections. Args: - group_ids (Optional[list[str]]): List of group IDs to get an overview for. - limit (Optional[int]): The maximum number of groups to return. - offset (Optional[int]): The offset to start listing groups from. + collection_ids (Optional[list[str]]): List of collection IDs to get an overview for. + limit (Optional[int]): The maximum number of collections to return. + offset (Optional[int]): The offset to start listing collections from. Returns: - dict: The overview of groups in the system. + dict: The overview of collections in the system. """ params = {} - if group_ids: - params["group_ids"] = group_ids + if collection_ids: + params["collection_ids"] = collection_ids if offset: params["offset"] = offset if limit: params["limit"] = limit return await client._make_request( - "GET", "groups_overview", params=params + "GET", "collections_overview", params=params ) @staticmethod - async def create_group( + async def create_collection( client, name: str, description: Optional[str] = None, ) -> dict: """ - Create a new group. + Create a new collection. Args: - name (str): The name of the group. - description (Optional[str]): The description of the group. + name (str): The name of the collection. + description (Optional[str]): The description of the collection. Returns: dict: The response from the server. @@ -391,66 +391,72 @@ async def create_group( if description is not None: data["description"] = description - return await client._make_request("POST", "create_group", json=data) + return await client._make_request( + "POST", "create_collection", json=data + ) @staticmethod - async def get_group( + async def get_collection( client, - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Get a group by its ID. + Get a collection by its ID. Args: - group_id (str): The ID of the group to get. + collection_id (str): The ID of the collection to get. Returns: - dict: The group data. + dict: The collection data. """ - return await client._make_request("GET", f"get_group/{str(group_id)}") + return await client._make_request( + "GET", f"get_collection/{str(collection_id)}" + ) @staticmethod - async def update_group( + async def update_collection( client, - group_id: Union[str, UUID], + collection_id: Union[str, UUID], name: Optional[str] = None, description: Optional[str] = None, ) -> dict: """ - Updates the name and description of a group. + Updates the name and description of a collection. Args: - group_id (str): The ID of the group to update. - name (Optional[str]): The new name for the group. - description (Optional[str]): The new description of the group. + collection_id (str): The ID of the collection to update. + name (Optional[str]): The new name for the collection. + description (Optional[str]): The new description of the collection. Returns: dict: The response from the server. """ - data = {"group_id": str(group_id)} + data = {"collection_id": str(collection_id)} if name is not None: data["name"] = name if description is not None: data["description"] = description - return await client._make_request("PUT", "update_group", json=data) + return await client._make_request( + "PUT", "update_collection", json=data + ) @staticmethod - async def delete_group( + async def delete_collection( client, - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Delete a group by its ID. + Delete a collection by its ID. Args: - group_id (str): The ID of the group to delete. + collection_id (str): The ID of the collection to delete. Returns: dict: The response from the server. """ return await client._make_request( - "DELETE", f"delete_group/{str(group_id)}" + "DELETE", f"delete_collection/{str(collection_id)}" ) @staticmethod @@ -461,10 +467,10 @@ async def delete_user( delete_vector_data: bool = False, ) -> dict: """ - Delete a group by its ID. + Delete a collection by its ID. Args: - group_id (str): The ID of the group to delete. + collection_id (str): The ID of the collection to delete. Returns: dict: The response from the server. @@ -482,93 +488,95 @@ async def delete_user( ) @staticmethod - async def list_groups( + async def list_collections( client, offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - List all groups in the R2R deployment. + List all collections in the R2R deployment. Args: - offset (Optional[int]): The offset to start listing groups from. - limit (Optional[int]): The maximum number of groups to return. + offset (Optional[int]): The offset to start listing collections from. + limit (Optional[int]): The maximum number of collections to return. Returns: - dict: The list of groups. + dict: The list of collections. """ params = {} if offset is not None: params["offset"] = offset if limit is not None: params["limit"] = limit - return await client._make_request("GET", "list_groups", params=params) + return await client._make_request( + "GET", "list_collections", params=params + ) @staticmethod - async def add_user_to_group( + async def add_user_to_collection( client, user_id: Union[str, UUID], - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Add a user to a group. + Add a user to a collection. Args: user_id (str): The ID of the user to add. - group_id (str): The ID of the group to add the user to. + collection_id (str): The ID of the collection to add the user to. Returns: dict: The response from the server. """ data = { "user_id": str(user_id), - "group_id": str(group_id), + "collection_id": str(collection_id), } return await client._make_request( - "POST", "add_user_to_group", json=data + "POST", "add_user_to_collection", json=data ) @staticmethod - async def remove_user_from_group( + async def remove_user_from_collection( client, user_id: Union[str, UUID], - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Remove a user from a group. + Remove a user from a collection. Args: user_id (str): The ID of the user to remove. - group_id (str): The ID of the group to remove the user from. + collection_id (str): The ID of the collection to remove the user from. Returns: dict: The response from the server. """ data = { "user_id": str(user_id), - "group_id": str(group_id), + "collection_id": str(collection_id), } return await client._make_request( - "POST", "remove_user_from_group", json=data + "POST", "remove_user_from_collection", json=data ) @staticmethod - async def get_users_in_group( + async def get_users_in_collection( client, - group_id: Union[str, UUID], + collection_id: Union[str, UUID], offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - Get all users in a group. + Get all users in a collection. Args: - group_id (str): The ID of the group to get users for. + collection_id (str): The ID of the collection to get users for. offset (Optional[int]): The offset to start listing users from. limit (Optional[int]): The maximum number of users to return. Returns: - dict: The list of users in the group. + dict: The list of users in the collection. """ params = {} if offset is not None: @@ -576,24 +584,26 @@ async def get_users_in_group( if limit is not None: params["limit"] = limit return await client._make_request( - "GET", f"get_users_in_group/{str(group_id)}", params=params + "GET", + f"get_users_in_collection/{str(collection_id)}", + params=params, ) @staticmethod - async def user_groups( + async def user_collections( client, user_id: Union[str, UUID], offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - Get all groups that a user is a member of. + Get all collections that a user is a member of. Args: - user_id (str): The ID of the user to get groups for. + user_id (str): The ID of the user to get collections for. Returns: - dict: The list of groups that the user is a member of. + dict: The list of collections that the user is a member of. """ params = {} if offset is not None: @@ -602,77 +612,77 @@ async def user_groups( params["limit"] = limit if not params: return await client._make_request( - "GET", f"user_groups/{str(user_id)}" + "GET", f"user_collections/{str(user_id)}" ) else: return await client._make_request( - "GET", f"user_groups/{str(user_id)}", params=params + "GET", f"user_collections/{str(user_id)}", params=params ) @staticmethod - async def assign_document_to_group( + async def assign_document_to_collection( client, document_id: Union[str, UUID], - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Assign a document to a group. + Assign a document to a collection. Args: document_id (str): The ID of the document to assign. - group_id (str): The ID of the group to assign the document to. + collection_id (str): The ID of the collection to assign the document to. Returns: dict: The response from the server. """ data = { "document_id": str(document_id), - "group_id": str(group_id), + "collection_id": str(collection_id), } return await client._make_request( - "POST", "assign_document_to_group", json=data + "POST", "assign_document_to_collection", json=data ) # TODO: Verify that this method is implemented, also, should be a PUT request @staticmethod - async def remove_document_from_group( + async def remove_document_from_collection( client, document_id: Union[str, UUID], - group_id: Union[str, UUID], + collection_id: Union[str, UUID], ) -> dict: """ - Remove a document from a group. + Remove a document from a collection. Args: document_id (str): The ID of the document to remove. - group_id (str): The ID of the group to remove the document from. + collection_id (str): The ID of the collection to remove the document from. Returns: dict: The response from the server. """ data = { "document_id": str(document_id), - "group_id": str(group_id), + "collection_id": str(collection_id), } return await client._make_request( - "POST", "remove_document_from_group", json=data + "POST", "remove_document_from_collection", json=data ) @staticmethod - async def document_groups( + async def document_collections( client, document_id: Union[str, UUID], offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - Get all groups that a document is assigned to. + Get all collections that a document is assigned to. Args: - document_id (str): The ID of the document to get groups for. + document_id (str): The ID of the document to get collections for. Returns: - dict: The list of groups that the document is assigned to. + dict: The list of collections that the document is assigned to. """ params = {} if offset is not None: @@ -681,30 +691,32 @@ async def document_groups( params["limit"] = limit if not params: return await client._make_request( - "GET", f"document_groups/{str(document_id)}", params=params + "GET", + f"document_collections/{str(document_id)}", + params=params, ) else: return await client._make_request( - "GET", f"document_groups/{str(document_id)}" + "GET", f"document_collections/{str(document_id)}" ) @staticmethod - async def documents_in_group( + async def documents_in_collection( client, - group_id: Union[str, UUID], + collection_id: Union[str, UUID], offset: Optional[int] = None, limit: Optional[int] = None, ) -> dict: """ - Get all documents in a group. + Get all documents in a collection. Args: - group_id (str): The ID of the group to get documents for. + collection_id (str): The ID of the collection to get documents for. offset (Optional[int]): The offset to start listing documents from. limit (Optional[int]): The maximum number of documents to return. Returns: - dict: The list of documents in the group. + dict: The list of documents in the collection. """ params = {} if offset is not None: @@ -712,5 +724,5 @@ async def documents_in_group( if limit is not None: params["limit"] = limit return await client._make_request( - "GET", f"group/{str(group_id)}/documents", params=params + "GET", f"collection/{str(collection_id)}/documents", params=params ) diff --git a/py/sdk/models.py b/py/sdk/models.py index d95312085..7c2151fb4 100644 --- a/py/sdk/models.py +++ b/py/sdk/models.py @@ -340,7 +340,7 @@ class VectorSearchSettings(BaseModel): ge=1, le=1_000, ) - selected_group_ids: list[UUID] = Field( + selected_collection_ids: list[UUID] = Field( default_factory=list, description="Group IDs to search for", ) @@ -376,7 +376,7 @@ class Config: "use_hybrid_search": True, "filters": {"category": "technology"}, "search_limit": 20, - "selected_group_ids": [ + "selected_collection_ids": [ "2acb499e-8428-543b-bd85-0d9098718220", "3e157b3a-8469-51db-90d9-52e7d896b49b", ], @@ -394,8 +394,8 @@ class Config: def model_dump(self, *args, **kwargs): dump = super().model_dump(*args, **kwargs) - dump["selected_group_ids"] = [ - str(uuid) for uuid in dump["selected_group_ids"] + dump["selected_collection_ids"] = [ + str(uuid) for uuid in dump["selected_collection_ids"] ] return dump @@ -490,7 +490,7 @@ class UserResponse(BaseModel): created_at: datetime = datetime.now() updated_at: datetime = datetime.now() is_verified: bool = False - group_ids: list[UUID] = [] + collection_ids: list[UUID] = [] # Optional fields (to update or set at creation) hashed_password: Optional[str] = None @@ -507,7 +507,7 @@ class VectorSearchResult(BaseModel): extraction_id: UUID document_id: UUID user_id: UUID - group_ids: list[UUID] + collection_ids: list[UUID] score: float text: str metadata: dict[str, Any] @@ -524,7 +524,7 @@ def dict(self) -> dict: "extraction_id": self.extraction_id, "document_id": self.document_id, "user_id": self.user_id, - "group_ids": self.group_ids, + "collection_ids": self.collection_ids, "score": self.score, "text": self.text, "metadata": self.metadata, @@ -536,7 +536,7 @@ class Config: "extraction_id": "3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09", "document_id": "3e157b3a-8469-51db-90d9-52e7d896b49b", "user_id": "2acb499e-8428-543b-bd85-0d9098718220", - "group_ids": [], + "collection_ids": [], "score": 0.23943702876567796, "text": "Example text from the document", "metadata": { @@ -603,7 +603,7 @@ class Config: "extraction_id": "3f3d47f3-8baf-58eb-8bc2-0171fb1c6e09", "document_id": "3e157b3a-8469-51db-90d9-52e7d896b49b", "user_id": "2acb499e-8428-543b-bd85-0d9098718220", - "group_ids": [], + "collection_ids": [], "score": 0.23943702876567796, "text": "Paris is the capital and most populous city of France.", "metadata": {