Skip to main content

Interacting with Chromia using the Python client

This lesson demonstrates how to use the Postchain Python client for semantic vector searches and to upload your movie data to your Chromia chain.

You will:

  • Initialize the Python client
  • Upload movie data using the add_movies operation in batches
  • Encode a user query into a vector using the same model as during the upload
  • Query the chain using Rell query templates

If you haven’t configured your .env file and installed the necessary dependencies yet, refer to the setup module.

1. Initialize the Python client

To connect to your deployed chain, load your environment and initialize the client as follows:

from postchain_client_py import BlockchainClient
from dotenv import load_dotenv
import os, json

load_dotenv()

async def get_client():
settings = {
"node_url_pool": json.loads(os.getenv("NODE_URL_POOL", "[]")),
"blockchain_rid": os.getenv("BLOCKCHAIN_RID")
}
return await BlockchainClient.create(settings)

2. Upload movies and vectors

Upload your movie data to the chain by calling the add_movies operation from your Rell module. This operation expects a list of flat movie structs, each containing metadata and a vector string.

Here’s how one movie entry looks (all fields are strings, except for wiki_id, which is an integer):

[
12345,
"The Matrix",
"A man discovers reality is a simulation...",
"1999-03-31",
"466000000",
"136",
"English",
"USA",
"Science Fiction, Action",
"[0.1, 0.2, ...]"
]

To upload in batches:

from postchain_client_py.blockchain_client import Operation, Transaction
from secp256k1 import PrivateKey

async def store_batch(client, batch):
private_key = PrivateKey(bytes.fromhex(os.getenv("PRIV_KEY")), raw=True)
public_key = private_key.pubkey.serialize()

operation = Operation(op_name="add_movies", args=[batch])
transaction = Transaction(
operations=[operation],
signers=[public_key],
blockchain_rid=os.getenv("BLOCKCHAIN_RID")
)

signed = await client.sign_transaction(transaction, private_key.private_key)
receipt = await client.send_transaction(signed, do_status_polling=True)

if receipt.status != 0:
raise Exception(f"Upload failed: {receipt.message}")

This mirrors the movie_input struct in Rell and effectively stores both metadata and vectors using store_vectors(...) under the hood.

Your Rell module defines get_movies_with_distance, a query template that returns both movie metadata and the vector distance.

You can call it from Python like this:

async def search_movies(query_vector, max_results=10):
payload = {
"context": 0,
"q_vector": query_vector,
"max_distance": "1.0",
"max_vectors": max_results,
"query_template": {"type": "get_movies_with_distance"}
}
client = await get_client()
return await client.query("query_closest_objects", payload)

4. Filter search results by genre

To add a genre filter, use the get_movies_with_filter template. It works similarly but requires an additional argument:

async def search_with_filter(query_vector, genre, max_results=10):
payload = {
"context": 0,
"q_vector": query_vector,
"max_distance": "1.0",
"max_vectors": max_results,
"query_template": {
"type": "get_movies_with_filter",
"args": {"genre_filter": genre}
}
}
client = await get_client()
return await client.query("query_closest_objects", payload)

5. Create the query vector

Encode the query vector using the same model selected during preprocessing. For example:

from sentence_transformers import SentenceTransformer
import os

model = SentenceTransformer(os.getenv("EMBEDDING_MODEL"))

def create_query_vector(prompt):
raw_vector = model.encode(prompt)
return "[" + ", ".join(f"{float(v)}" for v in raw_vector) + "]"
Ensure model consistency

To obtain meaningful results, use the exact same embedding model when uploading vectors to Chromia. A mismatch in dimensionality or encoding will lead to query failures or irrelevant results.

6. Interpret the results

Query responses provide a list of matching movies, each with complete metadata and a similarity score:

{
"movie": {
"wiki_id": 12345,
"title": "The Matrix",
"plot": "...",
...
},
"distance": "0.042"
}
  • The movie field contains all the Rell metadata for the match
  • The distance value indicates how close the vector is to your query — a lower distance signifies greater similarity

Summary

  • Use add_movies to upload movie metadata and vectors in a single batch operation
  • Fetch movies based on their vector similarity or filter by genre as needed
  • Ensure consistency in embedding models for accurate results