Mindloom’s ML capabilities rest on a bilingual (English + Spanish) technical content corpus assembled from public sources, cleaned and labelled across 8 thematic categories. From that corpus, a two-notebook pipeline produces a singleDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/No-Country-simulation/G9-LATAM-Team-58/llms.txt
Use this file to discover all available pages before exploring further.
model.joblib artifact that the inference service loads at startup. This page covers how both are built — from raw data through training to the moment the artifact lands in OCI Object Storage.
The Corpus
The corpus is stored as JSONL files — one record per line — in thedata/processed/ directory. Three files are produced and uploaded to OCI Object Storage:
| File | Purpose |
|---|---|
processed/train_corpus.jsonl | Training split |
processed/test_corpus.jsonl | English evaluation split |
processed/test_corpus_es.jsonl | Spanish evaluation split (cross-lingual transfer) |
An additional
quality field (derived from source engagement signals — votes on Stack Overflow, reactions on Dev.to) is used internally by the ETL notebook for weighted sampling. It is not persisted in the contents table and does not appear in the training features.Data Sources
The corpus draws from three public sources, chosen to cover all 8 categories across both languages:Kaggle StackSample
stackoverflow/stacksample — English questions labelled via weighted tag votingDev.to API
Technical articles in both English and Spanish — the closest match to the content Mindloom indexes
Stack Exchange Dumps
es.stackoverflow.com for Spanish; security, dba, and softwareengineering for underrepresented categoriesCategory Labels
Every document is assigned exactly one of the 8 categories. The labelling rules live inCATEGORY_TAGS inside the EDA/ETL notebook.
| Category |
|---|
| Backend |
| Frontend |
| Móvil |
| Datos e IA |
| DevOps y Cloud |
| Bases de datos |
| Seguridad |
| Fundamentos |
EDA and ETL Notebook
File:data/TechMind_01_EDA_ETL.ipynb — runs in Google Colab.
This notebook handles the full data preparation pipeline:
Extraction
Fetches data from Kaggle (via Colab Secrets credentials), the Dev.to API, and Stack Exchange archive dumps.
Exploration and cleaning
Performs EDA, removes low-quality documents, normalizes text, and applies deduplication.
Category labelling
Maps source tags and metadata to one of the 8 Mindloom categories using
CATEGORY_TAGS.Use
random_state=42 on every sampling operation and stratified split in this notebook. Without it, two runs of the same code on the same source data will produce different class distributions and make metrics non-reproducible.Model Training Notebook
File:notebook/TechMind_02_Model_Training.ipynb — runs in Google Colab or Jupyter.
This notebook reads the processed JSONL files from OCI Object Storage and trains the full pipeline. It requires processed/*.jsonl to already be uploaded by the EDA/ETL notebook.
Embed the full corpus
Encodes every document body with
"passage: " prefix using intfloat/multilingual-e5-small, producing L2-normalized float32 vectors. This covers the complete corpus, not just the training split.Train TF-IDF and SVD baseline
Fits a
TfidfVectorizer (baseline_vectorizer) on the training text, then fits TruncatedSVD on the resulting matrix. Also fits a separate TfidfVectorizer (keyword_vectorizer) for keyword extraction.Train the main classifier
Builds hybrid features (E5 embedding concatenated with SVD-reduced TF-IDF, both L2-normalized) and trains a
LogisticRegression classifier.Train K-means and UMAP
Fits
KMeans and UMAP on the corpus embeddings. Both are stored as fitted model objects so the inference service can assign cluster IDs and map coordinates to documents it never saw during training.Evaluate
Computes macro-F1 on the English and Spanish test sets. Metrics are stored in the
meta dict and returned by GET /model/info.The Serialized Artifact
The training notebook serializes a Pythondict to model.joblib using joblib.dump(). Every key in this dict is a contract: the inference service reads them by name, and renaming or removing a key is a breaking change that will crash the service at startup.
| Key | Type | Description |
|---|---|---|
classifier | LogisticRegression | Main classifier (E5 + SVD-reduced TF-IDF features → category) |
label_encoder | LabelEncoder | Maps integer indices ↔ category name strings |
keyword_vectorizer | TfidfVectorizer | Bilingual keyword extraction (top 5 terms per document) |
baseline_vectorizer | TfidfVectorizer | Input to SVD and to the explainability baseline |
baseline_classifier | LogisticRegression | Explainability baseline; coefficients used in _get_explanation() |
svd | TruncatedSVD | Reduces TF-IDF matrix to svd_components dimensions |
kmeans | KMeans | Assigns cluster IDs to new content at request time |
umap_reducer | UMAP | Projects new content to 2D map coordinates at request time |
meta | dict | Version, embedding model name, dim, feature_dim, svd_components, E5 prefixes, categories, metrics, train_size |
meta["embedding_model"] stores the name of the transformer (e.g., "intfloat/multilingual-e5-small"). The inference service uses this name to load the model from the local HuggingFace cache baked into the Docker image. Transformer weights are never stored in the joblib — doing so would inflate the artifact from ~0.24 MB to ~470 MB.The meta Dict Structure
The meta dict is returned verbatim by GET /model/info. Its fields map directly to the ModelInfoResponse Pydantic schema:
Publishing a New Model
To promote a retrained model to production: The inference service readsmodels/latest.txt on every startup. The next container restart will automatically download and load the new version — no Docker image rebuild or API redeployment required.