14 / 15Module 4: A deep dive into the codeAdvanced
Work with Chromia through the Python client
This lesson shows you how to upload your movie data to your Chromia chain and run semantic vector searches against it with the Postchain Python client.
The steps are:
- Set up the Python client
- Send movie data to the chain in batches through the
add_moviesoperation - Turn a user query into a vector with the same model you used for the upload
- Search the chain through Rell query templates
Complete the setup module first if your .env file isn't configured or the required dependencies aren't installed.
1. Initialize the Python client
Load your environment variables and create a client that points to your deployed chain:
from postchain_client_py import BlockchainClientfrom dotenv import load_dotenvimport os, jsonload_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
You send movie data to the chain through the add_movies operation defined in your Rell module. It takes a list of flat movie structs, and each struct holds the movie's metadata plus its vector as a string.
A single movie entry looks like this. Every field is a string except 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, ...]"]Send the entries in batches:
from postchain_client_py.blockchain_client import Operation, Transactionfrom secp256k1 import PrivateKeyasync 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}")Each entry matches the movie_input struct in Rell. Internally, the operation saves both the metadata and the vectors by calling store_vectors(...).
3. Run a semantic search
The query template get_movies_with_distance in your Rell module returns each matching movie's metadata together with its vector distance.
Call it from Python:
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 restrict results to a genre, call the get_movies_with_filter template instead. It behaves the same way but takes one extra 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
Generate the query vector with the same model you chose during preprocessing, for example:
from sentence_transformers import SentenceTransformerimport osmodel = 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) + "]"6. Interpret the results
A query returns a list of matching movies. Each item includes the full metadata and a similarity score:
{ "movie": { "wiki_id": 12345, "title": "The Matrix", "plot": "...", ... }, "distance": "0.042"}movieholds all the Rell metadata for the matched entrydistancemeasures how far the stored vector is from your query vector; the smaller the value, the more similar the movie
Summary
- Call
add_moviesto upload movie metadata and vectors together as a batch operation - Retrieve movies by vector similarity, optionally narrowed down by genre
- Use the same embedding model throughout to get accurate results