Skip to main content
Version: 0.12

C FFI: Embeddings & Search

Embeddings, vector search, and hybrid search through the C FFI. For the concepts behind each step see the guide pages on Embedding Models, Vector Search, and Hybrid & Lexical Search.

Every atelico_* call returns ATELICO_OK (0) on success; JSON results come back through an out-pointer that the engine owns (do not free it).

:::info Changed in 0.12.1 atelico_embed is now atelico_embed_text, alongside new atelico_embed_image / atelico_embed_audio; atelico_classifier_predict is now atelico_classifier_predict_text, alongside atelico_classifier_predict_image / atelico_classifier_predict_audio. There are no compatibility aliases — rename any 0.12.0 calls. :::

Embed text

const char *resp = NULL;
atelico_embed_text(engine,
"{\"model\":\"in-memory::sentence-transformers/all-MiniLM-L6-v2\","
"\"input\":[\"The guard saw a thief enter the keep at midnight.\"]}",
&resp);
// Parse resp with your JSON lib -> data[0].embedding (384 floats).

// Direct cosine similarity between two strings:
float score = 0.0f;
atelico_embed_similarity(engine,
"in-memory::sentence-transformers/all-MiniLM-L6-v2",
"a knight's blade", "a warrior's sword", &score);

Create a store, insert, query

embed_dim must match the model (384 for MiniLM/bge-small, 768 for bge-base).

// 1. Create
uint64_t store_id = 0;
atelico_kvstore_create(engine,
"{\"store_id\":\"npc-memory\",\"db_path\":\"./data/npc-memory\",\"embed_dim\":384}",
&store_id);

// 2. Insert — key_embedding is the vector from atelico_embed (build the JSON
// however you like: sprintf, your JSON library, etc.)
atelico_kvstore_insert(engine, "npc-memory", entries_json);
// entries_json = [{"id":"mem-001",
// "key_text":"...",
// "key_embedding":[ ... 384 floats ... ],
// "facets":{"npc_id":"guard-01"},
// "priority":0.8}]

// 3. Query
const char *results = NULL;
atelico_kvstore_query(engine, "npc-memory", query_json, &results);
// query_json = {"query_embedding":[ ... ],
// "facet_filters":{"npc_id":"guard-01"},
// "limit":5}
// results = [{"id","key_text","similarity","priority","combined_score"}, ...]

uint64_t count = 0;
atelico_kvstore_count(engine, "npc-memory", "", &count);
atelico_kvstore_create_fts_index(engine, "npc-memory", "key_text");

const char *response = NULL;
atelico_kvstore_hybrid_query(engine, "npc-memory", hybrid_json, &response);
// hybrid_json = {"embeddings":[ ... ],"text":"thief keep",
// "fts_column":"key_text","limit":5,
// "vector_weight":0.6,"lexical_weight":0.4}

See Hybrid & Lexical Search for the scoring details and the lexical-only (atelico_kvstore_lexical_query) variant.

Embed images and audio

atelico_embed_image and atelico_embed_audio take a base64-encoded file in the request JSON and return the same EmbeddingResponse shape as atelico_embed_text. With a cross-modal model id the vectors share the text space.

// Image — model ids: "clip", "siglip", "dinov2-small", "dinov2-large".
// image is base64-encoded PNG/JPEG bytes.
const char *img_out = NULL;
atelico_embed_image(engine, "{\"model\":\"clip\",\"image\":\"<base64 PNG>\"}", &img_out);

// Audio — model id "clap". WAV / RIFF only (not MP3/FLAC).
const char *aud_out = NULL;
atelico_embed_audio(engine, "{\"model\":\"clap\",\"audio\":\"<base64 WAV>\"}", &aud_out);

atelico_embed_image / atelico_embed_audio read the model from the on-device cache and never launch a silent blocking download — gate with is_model_cached(model_id) and model_download_async(model_id) first. See Multimodal Embedding for the model table.

Classify text, images, and audio

atelico_classifier_load registers a trained classifier; the atelico_classifier_predict_* calls return a JSON result with a top label, its probability, and a top list of the top-k {label, probability} pairs.

atelico_classifier_load(engine, "steering", "/abs/path/to/models/steering");

// top_k is optional: omit for all labels ranked, 0 for just the top label
// (empty `top` list), N for the N best.
const char *text_out = NULL;
atelico_classifier_predict_text(engine,
"{\"model_id\":\"sentiment\",\"text\":\"I love this!\",\"top_k\":3}", &text_out);

// Image classifier over DINOv2-Small embeddings (labels e.g. "left"/"right").
const char *image_out = NULL;
atelico_classifier_predict_image(engine,
"{\"model_id\":\"steering\",\"image_path\":\"/abs/path/frame.png\",\"top_k\":0}",
&image_out);

// Audio classifier — WAV / RIFF input only.
const char *audio_out = NULL;
atelico_classifier_predict_audio(engine,
"{\"model_id\":\"ambience\",\"audio_path\":\"/abs/path/clip.wav\",\"top_k\":3}",
&audio_out);

The image/audio embedder the classifier was trained with ("dinov2-small", "clap") must be cached first. See Classifiers for training and the full result schema.