Skip to main content

Async Python client for Vector Store API

Project description

Vector Store Client

PyPI version Python versions License: MIT

Async Python client for Vector Store API. Provides convenient interface for storing and searching vector embeddings.

Русская версия документации

Features

  • ✨ Fully async API
  • 🔍 Vector and text search
  • 📝 Automatic text vectorization
  • 🛡️ Strong typing
  • 🧪 Full test coverage
  • 📚 Comprehensive documentation

Installation

pip install vector-store-client

Quick Start

from vector_store_client import VectorStoreClient

async def main():
    # Initialize client
    client = VectorStoreClient(base_url="http://localhost:8007")
    
    # Create record from text
    record_id = await client.create_text_record(
        text="Example text to vectorize",
        metadata={"source": "example"}
    )
    
    # Search similar records
    results = await client.search_by_text(
        text="similar text",
        limit=5
    )
    
    for result in results:
        print(f"Score: {result.score}, Text: {result.text}")

Documentation

Full documentation is available at Read the Docs.

Basic Operations

Creating Records

# Create from vector
record_id = await client.create_record(
    vector=[0.1, 0.2, ...],  # 384-dimensional vector
    metadata={"key": "value"}
)

# Create from text
record_id = await client.create_text_record(
    text="Example text",
    metadata={"source": "example"},
    model="default"  # optional
)

Search

# Search by vector
results = await client.search_by_vector(
    vector=[0.1, 0.2, ...],
    limit=5
)

# Search by text
results = await client.search_by_text(
    text="query text",
    limit=5
)

# Filter by metadata
results = await client.filter_records(
    criteria={"source": "example"},
    limit=10
)

Development

Installing Development Dependencies

pip install -e ".[dev]"

Running Tests

pytest

Linting and Formatting

# Code formatting
black .
isort .

# Type checking
mypy .

# Linting
ruff check .

License

This project is licensed under the MIT License - see the LICENSE file for details.

Dynamic API adaptation and abstraction layer

Overview

Vector Store Client is designed to work with evolving server APIs. The client automatically loads the server's command schema at runtime and provides a stable, user-friendly interface, regardless of changes in the server's internal API. This is achieved through a dynamic mapping (adapter) layer that connects the client's public methods to the actual server commands and parameters.

How it works

  • Schema loading: On initialization, the client fetches the server's command schema (e.g., from /api/commands).
  • Mapping layer: The client maintains a mapping between its stable public methods (such as create_record, search_by_text, etc.) and the actual server commands and parameters, as defined in the loaded schema.
  • Validation: All parameters are validated against the server schema using the jsonschema package before sending any request.
  • Adaptability: If the server API changes (e.g., command names, parameter structure), only the mapping layer needs to be updated, not the public interface or user code.

Benefits

  • Stable API for users: Your code does not break if the server API changes.
  • Automatic validation: All parameters are checked against the live server schema.
  • Easy maintenance: Adapting to server changes requires only updating the mapping, not rewriting the client.
  • Extensible: New server commands can be exposed by simply adding new mappings.

Example usage

import asyncio
from vector_store_client import VectorStoreClient

async def main():
    # Create client and load schema
    client = await VectorStoreClient.create(base_url="http://localhost:8007")

    # Create a record (public method, stable signature)
    record_id = await client.create_record(
        vector=[0.1] * 384,
        metadata={"source": "example"}
    )
    print("Created record:", record_id)

    # Search by text (public method, stable signature)
    results = await client.search_by_text(
        text="example query",
        limit=5
    )
    for result in results:
        print(f"Score: {result.score}, Text: {result.text}")

    # You can also call any server command directly (advanced)
    # This will be validated against the live schema
    raw_result = await client.call_command("search_by_vector", vector=[0.1]*384, limit=3)
    print("Raw search result:", raw_result)

asyncio.run(main())

How to adapt to server API changes

If the server changes its API (e.g., renames a command, changes parameter names), update only the mapping layer in the client. The public methods and user code remain unchanged.


See the documentation and code for more details on the mapping/adapter mechanism and how to extend or customize it for your needs.

Ideology and implementation of the abstraction/mapping layer

Why an abstraction/mapping layer?

Modern APIs evolve: command names, parameters, and even the set of available operations may change over time. Relying directly on the server's raw API makes your client code fragile and hard to maintain. The abstraction/mapping layer in Vector Store Client solves this by providing:

  • Stable, user-friendly methods: The client exposes a fixed set of high-level methods (e.g., create_record, search_by_text) that remain unchanged even if the server API changes.
  • Loose coupling: The mapping layer decouples your code from the server's internal details. If the server changes, only the mapping needs to be updated.
  • Automatic validation: All parameters are checked against the live server schema before any request is sent.
  • Extensibility: New server features can be exposed by simply adding new mappings and wrapper methods.

How the mapping layer works

  • On startup, the client loads the server's command schema (e.g., from /api/commands).
  • The client maintains a mapping (dictionary or class attribute) that links each public method to the corresponding server command and parameter names.
  • Each public method:
    • Accepts stable, user-friendly arguments.
    • Translates them (if needed) to the actual server command and parameter names using the mapping.
    • Calls the universal call_command method, which validates and sends the request.
  • If the server API changes, only the mapping and (optionally) the wrapper method need to be updated.

Example mapping (Python):

_method_map = {
    "create_record": {"command": "create_record", "params": ["vector", "metadata", "session_id", "message_id", "timestamp"]},
    "search_by_text": {"command": "search_by_text", "params": ["text", "limit", "model", "include_vectors", "include_metadata"]},
    # ... add more as needed
}

Example wrapper method:

async def create_record(self, vector, metadata=None, session_id=None, message_id=None, timestamp=None, **kwargs):
    return await self.call_command(
        self._method_map["create_record"]["command"],
        vector=vector,
        metadata=metadata,
        session_id=session_id,
        message_id=message_id,
        timestamp=timestamp,
        **kwargs
    )

Checklist for adding a new public method

  1. Check the server schema: Identify the new command and its parameters in /api/commands.
  2. Update the mapping: Add a new entry to _method_map with the public method name, server command, and parameter list.
  3. Implement the wrapper: Write a new public method in the client that:
    • Accepts user-friendly arguments.
    • Maps them to the server command and parameters using _method_map.
    • Calls call_command with the correct arguments.
  4. (Optional) Add docstrings and examples: Document the new method for users.
  5. Test: Add or update tests to cover the new method, ensuring it works with the live schema and server.

Example: Adding a new method delete_by_filter

Suppose the server adds a command delete_by_filter.

  • Step 1: Find its parameters in /api/commands (e.g., criteria, limit).
  • Step 2: Update mapping:
_method_map = {
    # ...
    "delete_by_filter": {"command": "delete_by_filter", "params": ["criteria", "limit"]},
}
  • Step 3: Implement wrapper:
async def delete_by_filter(self, criteria, limit=100):
    return await self.call_command(
        self._method_map["delete_by_filter"]["command"],
        criteria=criteria,
        limit=limit
    )
  • Step 4: Add docstring and usage example.
  • Step 5: Add tests for the new method.

By following this approach, you ensure your client remains robust, maintainable, and easy to extend as the server evolves.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

vector_store_client-0.1.0.tar.gz (35.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

vector_store_client-0.1.0-py3-none-any.whl (29.1 kB view details)

Uploaded Python 3

File details

Details for the file vector_store_client-0.1.0.tar.gz.

File metadata

  • Download URL: vector_store_client-0.1.0.tar.gz
  • Upload date:
  • Size: 35.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.3

File hashes

Hashes for vector_store_client-0.1.0.tar.gz
Algorithm Hash digest
SHA256 539ceb2c8fa2e3f553c38075d8e09e4ed3878a91acc12db571bcde7cc37d7eef
MD5 da46580a0a765b0a55a72e6031e9c871
BLAKE2b-256 4dd833a7a91447967a4115a1470ac363274b411c03c1db8b9dd7f8868c39f12e

See more details on using hashes here.

File details

Details for the file vector_store_client-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for vector_store_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 eedb9a99ebfb7bf0d32ce9624a528708e27437e467afdc1211f8d2864df1ef55
MD5 5641c94fb2a35b9372dec51670bcebf8
BLAKE2b-256 3caa8e05b261964d8f553be6aba013437007e9cca7f1d5ff3b609202f6e28a1c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page