Chromia
Start Building

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_movies operation
  • 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:

python
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:

python
[    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:

python
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(...).

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:

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:

python
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:

python
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:

python
{    "movie": {        "wiki_id": 12345,        "title": "The Matrix",        "plot": "...",        ...    },    "distance": "0.042"}
  • movie holds all the Rell metadata for the matched entry
  • distance measures how far the stored vector is from your query vector; the smaller the value, the more similar the movie

Summary

  • Call add_movies to 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
Written for this site from Chromia’s public course. Code samples are the course’s own.