Async Python client for Vector Store API
Project description
Vector Store Client
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
jsonschemapackage 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_commandmethod, 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
- Check the server schema: Identify the new command and its parameters in
/api/commands. - Update the mapping: Add a new entry to
_method_mapwith the public method name, server command, and parameter list. - 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_commandwith the correct arguments.
- (Optional) Add docstrings and examples: Document the new method for users.
- 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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
539ceb2c8fa2e3f553c38075d8e09e4ed3878a91acc12db571bcde7cc37d7eef
|
|
| MD5 |
da46580a0a765b0a55a72e6031e9c871
|
|
| BLAKE2b-256 |
4dd833a7a91447967a4115a1470ac363274b411c03c1db8b9dd7f8868c39f12e
|
File details
Details for the file vector_store_client-0.1.0-py3-none-any.whl.
File metadata
- Download URL: vector_store_client-0.1.0-py3-none-any.whl
- Upload date:
- Size: 29.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eedb9a99ebfb7bf0d32ce9624a528708e27437e467afdc1211f8d2864df1ef55
|
|
| MD5 |
5641c94fb2a35b9372dec51670bcebf8
|
|
| BLAKE2b-256 |
3caa8e05b261964d8f553be6aba013437007e9cca7f1d5ff3b609202f6e28a1c
|