cd /news/artificial-intelligence/no-doctor-no-judge-no-app-understand… · home › topics › artificial-intelligence › article
[ARTICLE · art-164685] src=pub.towardsai.net ↗ pub= topic=artificial-intelligence verified=true sentiment=↑ positive

No Doctor, No Judge, No App Understands Them: Building Translation Data for 476M Indigenous People

An open-source toolkit called Uyari has produced 111,363 Spanish source sentences, each paired with translations in seven more languages, for $15.74 in Meta API calls, as the first step toward community-governed translation models for Indigenous languages. The project's first case is Shawi (Chayahuita), spoken by 17,241 mother-tongue speakers in the Peruvian Amazon, with the Shawi model published on Hugging Face and the code and data on GitHub; Uyari is competing in Meta's global AI hackathon. The effort targets a gap affecting roughly 476 million Indigenous people in 90 countries, including about 3.1 million people across four Latin American countries who cannot use their country's official language at all, and Peru's 859 registered interpreters covering 39 of 48 official Indigenous languages.

by read14 min views3 publishedNov 5, 2026

Millions of Indigenous people meet doctors, courts and forms in a language they do not fully understand. Uyari is an open toolkit that turns a community’s own translations into translation models between its language and the official languages its speakers need. The first case is Shawi, in the Peruvian Amazon.

A translation model is only as good as the sentences people translate for it, so this article is about those sentences: how Uyari designs, filters and prices the source corpus a native speaker translates, one sentence at a time. The result is 111,363 Spanish sentences about everyday community life, each with a twin in seven more languages, for $15.74 in Meta API calls.

How you can help. Uyari is competing in Meta’s global AI hackathon, and the interactions on this X post are what count: https://x.com/malexandersv/status/2117644114363920674. Like, repost and comment, then share it with your groups on WhatsApp, Telegram, Slack, Discord or LinkedIn. Every interaction helps take Uyari from a working prototype to something finished. The code and the data are open: https://github.com/malexandersalazar/uyari, and the Shawi model is on Hugging Face: https://huggingface.co/malexandersalazar/uyari-mt-cbt-nllb1.3b.

About 476 million Indigenous people live in 90 countries, more than 6% of humanity. They are nearly three times more likely to live in extreme poverty, and many meet doctors, consent forms, courts and civil registries in an official language they do not fully understand.

In just four Latin American countries, about 3.1 million people cannot use their country’s official language at all. Where they live, no doctor, no judge and no app understands them.

Mexico’s figure is a census count; the other three are estimates. Seventy percent of the world’s Indigenous people live in Asia and the Pacific.

Now put a face on those numbers. In Guatemala, the language barrier was “the most important obstacle” to Indigenous women’s use of reproductive health services, and their maternal mortality was more than twice that of non-Indigenous women: 166 versus 78 per 100,000 live births. In Mexico, Indigenous-language speakers aged 15 and over average 6.2 years of schooling; monolinguals average 1.4. In Peru, 859 registered interpreters cover 39 of 48 official Indigenous languages: about 5,200 mother-tongue speakers per interpreter, and nine languages with zero.

These are large languages. Mexico’s 7.4 million Indigenous-language speakers outnumber the speakers of Danish, Finnish or Norwegian, all of which your phone already translates.

The base models exist: open models for speech and translation cover more than 1,600 languages. Uyari adds the last mile: evaluated, community-governed models between each Indigenous language and the official language its speakers need, in text and in speech, for any language. A language is a folder; the code is the same for all of them. Uyari means “listen” in Quechua.

The first case is Shawi (Chayahuita), with 17,241 mother-tongue speakers in the Peruvian Amazon. It began with maternal health: Shawi communities meet health services that offer no support in their language. Shawi is the first case, not the main character. The method is, and it starts with the source sentences.

Machine text is cheap: the whole corpus, in eight languages, cost $15.74 in API calls. Parallel data for an Indigenous language is not. For Shawi, a native speaker reads a sentence in Spanish and writes it in Shawi, one sentence at a time. That hour is the expensive part, so the choice that matters most is which Spanish sentence goes in front of that person. It has three tests:

Across all 111,363 published chunks, internet, computadora, USB and disco duro appear zero times, while the modern things of the river are everywhere: lancha (634 chunks), motor (476), jabón (985), fósforo (410).

A language model writes the Spanish, and the pipeline treats it like any other data source: designed inputs, validated outputs, everything logged.

The design matrix lives in primary/spa_Latn/matrix.yaml. Every generation request is one cell of it, and every chunk keeps its cell's coordinates as columns, forever.

The seven categorical axes alone give 525,000 combinations. With 180 micro-scenarios and five length buckets, that becomes 472.5 million cells. The whole corpus is about 11,200 cells, 0.002% of the space, so the design decides which combinations every batch contains.

Here is one real cell from the first batch, paraphrase group viajedespl-instru-f42364d79d96:

domain    viaje_desplazamiento > viajar en canoa hasta el puebloact       instruccion            register  infantiltense     presente               polarity  negativoperson    dialogo_dos_personasprofile   niño                   tone      preocupadolength    muy_corta (3-8 words)  anchors   viajar; pesado; partir

A worried child, giving instructions in a two-person dialogue, about a canoe trip to town. Ten Spanish sentences came out of it. Three of them, with their Shawi translations:

Polarity is an axis because negation, commands and questions change how a sentence is built, and the corpus asks for each of them.

Three more dimensions, one line each. Anchor words: three per cell from 25 or 26 per domain (candela, hamaca, mosquitero); 97% to 99% appear in their group. Length buckets: 3 to 90 words, because “Espérame” and a health worker’s explanation both happen. Connected discourse: 12% of cells ask for 3 to 6 linked sentences, because pronouns and “because” live between sentences.

The planner (src/uyari/gen/plan.py) assigns tense, polarity and person by round-robin: T[i % 5], P[(i // 5) % 5], X[(i // 25) % 5]. Every 125 consecutive cells form a full factorial of the three. Everything else comes from a seeded random generator, so the same batch name always gives the same plan.

In the 100K run’s published cells, every tense, polarity and person value holds 1,998 to 2,000 cells. Registers range from 1,930 to 2,054; speaker profiles from 776 to 875. Tense, polarity and person change the verb itself, so the planner guarantees every combination; a register or a profile can wobble by a few percent.

Micro-scenarios cycle too (i % 180), so each of the 180 got 52 to 58 cells and every domain 635 to 696. The first batch covered 4 domains and 37 micro-scenarios; the 100K run covers all 15 and all 180.

One more idea holds the pipeline together: the paraphrase group. One cell is one request, ten texts, one custom_id: the join key for splits, deduplication and model comparison. --regen-from <batch> rebuilds existing cells exactly, which is how you compare two models on identical inputs.

src/uyari/gen/prompts.py holds a Spanish system prompt that names the target ("será traducido al shawi (chayahuita), una lengua amazónica del Perú"). The user prompt renders the cell and the rules: content that could exist in a rural Amazonian community, in clear, everyday, concrete Spanish; vaccines or paperwork allowed, "en lenguaje llano que un hablante explicaría a un vecino", in the plain words a speaker would use with a neighbor. One rule is oddly specific: write "niño" with its ñ.

Then the prompt is frozen. prompt_version is a SHA-256 over the system prompt, the template rendered on four probe units and every prompt axis of the matrix. It is pv-337a163d411a, it is stamped on all 111,363 chunks from both generators, and a test fails if it changes. Validation thresholds sit outside the hash, so tuning a post-processing rule keeps every batch comparable.

Before anything leaves the machine, --estimate prints a cost range. Every generation run has a hard cap of $1, the project a $150 budget, and every call lands in a ledger. Every raw response is cached before it is parsed, so each request is paid exactly once (a test asserts it), and a changed validation rule rebuilds the batch from the cache at zero cost.

That discipline made scale boring. On 3 November 2026 the 100K run went out as five batches: a 10,000-text pilot, then four of 22,500. Each big batch cost about $0.48, inside the $1 cap. The pilot ran at 401 texts per minute with eight requests in flight.

After a tolerant JSON parse (src/uyari/gen/collect.py), every text runs seven checks in order: empty, zero words, over 120 words, banned term, more than 30% outside its length bucket, Spanish check, exact duplicate.

The banned list, verbatim from matrix.yaml:

semáforo, supermercado, rascacielos, ascensor, autopista, centro comercial, estación de metro, estación del metro, wifi, internet, smartphone, teléfono inteligente, computadora, aplicación móvil, tarjeta de crédito, cajero automático, oficina corporativa, shopping

Traffic light, supermarket, skyscraper, elevator, highway, mall, metro, wifi, computer, credit card, ATM. The prompt asks for rural content; the list makes it a guarantee, plurals included. Hits in 111,363 published chunks: 0. The guarantee covers exactly what the list names: celular and teléfono, outside it, appear in five chunks, such as one asking a young person to sit down “sin celular de bulla”.

Length is a deliberate compromise. Both models drift short, most in the longest bucket. On the same 200 cells, 94.5% of the first batch and 89.0% of the Muse batch land inside the strict bucket. Over the 100K run it is 85.8%: 99.9% of very short texts, 58.6% of very long ones. The ±30% tolerance keeps the one paid text in seven that runs a few words short.

The Spanish check combines three signals: function words, Spanish-only characters, and 60% of words already in the published Spanish. Short valid sentences such as “Traería plátano verde bien fresco” pass on the second or third: over all 111,363 chunks, function words alone flag 1,143; characters clear 991 of them, the lexicon 152.

In the 100K run, the gate rejected 73 of 100,000 texts: 65 for length, almost all one to three words short (24 where a long text needs 25), and 8 exact duplicates such as “Cruzaríamos el río con cuidadito”. Every rejection has a line in failures.jsonl with its reason, along with the rarer events: one response with 18 texts instead of 10, one that failed to parse, two timeouts.

src/uyari/gen/dedup.py publishes a batch in two passes, keeping the first occurrence. Exact: NFC, casefold, collapsed whitespace. Near: paraphrase-multilingual-MiniLM-L12-v2 embeddings, cosine ≥ 0.92, blocked by domain, with the whole published primary indexed first, so a new text close to anything already published is dropped too.

The middle row is the honest one. The embedding barely sees “no”, so “¿Sentirías nostalgia al verme?” was dropped at 0.945 next to its own negation, the very contrast section 3 asks for. At 23 of 2,000, the threshold stays: a sentence translated twice spends a speaker’s hour twice.

At scale, the same pass became a gauge. Across the 100K run it removed 539 texts (0.54%), and the rate quadrupled, from 0.22% to 0.88%, as the corpus already published grew from 12,000 to 89,000 chunks.

Each micro-scenario got about 550 new sentences in the run. The more sentences a micro-scenario such as “ir a traer agua del río” holds, the more often a new one lands next to an old one, and the dedup rate shows it first. Below 1%, it is cheap insurance.

Each cell produces ten paraphrases. A chunk-level split would put a test sentence’s siblings in training, and the score would measure memory. So the unit of the split is the paraphrase group. The first assignment drew about 300 translated chunks each for validation and test, as whole groups stratified by domain, ordered by a salted SHA-256: 328 and 322 today. Later groups are hashed, 5% each. Splits are frozen, and every language copies them.

I measured what that buys on the 3,578 chunks sent for Shawi translation, with the same embedding model.

Siblings sit closer than strangers: median cosine 0.59 inside a group, 0.34 between groups of the same domain. Under a random chunk split (20 seeds, same sizes), 99.7% of test chunks would have a sibling in training. Under the group split, 0%. The share of test chunks with a training neighbor at 0.8 or above drops from 30.9% to 12.1%.

The first 10,000 chunks were generated in June 2026 with Claude Opus 4.8. The 101,363 since then come from Meta’s Muse Spark 1.3 Contributor. To make the switch measurable, I regenerated 200 cells of the first batch with the identical prompt. Only the model changed.

Muse Spark cost $0.0214 per 1,000 published chunks, exact from the ledger: 3.3% of the first batch’s ~$0.64, the repository’s token-count estimate at list price with the batch discount. Its Spanish is slightly more varied; the price is length discipline, which the ±30% gate absorbs. The 100K run held that rate at scale: $2.12 for 99,386 chunks.

Why the Contributor tier? Muse Spark 1.3 is a complete, capable model, and this tier sells it at a very low price because Meta may use the prompts and completions for training. Here that trade is right: the prompt is matrix parameters, the output is synthetic everyday Spanish, and both are free of anything sensitive, private or business-specific. It is one of the best use cases I have found for it. The same trade is why Muse Spark never sees Shawi: every call declares what data it carries, and the code refuses to send Indigenous-language text to a model that may train on it.

A Shawi translation is made from Spanish, and Spanish is one official language among many. uyari primary translate gives every Spanish chunk a machine-translated twin with the same chunk_id. Split, domain and paraphrase group are copied from the Spanish row, so a test sentence stays in test in every language: 111,363 of 111,363 match. Every row says origin=machine_translated and names its model and prompt version; each answer is checked for one item per id, 1 to 150 words, and a change from the Spanish.

One id:

chunk_id  759f2be01d0542ada0363a9f9f909ad0spa  No remes tan rápido, hermanoeng  Don't row so fast, brotherpor  Não reme tão rápido, irmãofra  Ne rame pas si vite, frèredeu  Rudere nicht so schnell, Bruderita  Non remare così in fretta, fratellohin  इतनी तेज़ी से चप्पू मत चलाओ, भाईtha  อย่าพายเร็วขนาดนั้น พี่ชายcbt  Ama iya manuhtun maikesu   (human)

The build data-2026.11-six joins the 3,575 human Shawi translations to six official languages (Spanish, English, Portuguese, French, German, Italian): 21,450 rows, twelve translation directions, one human effort. The Shawi side is always human; beyond Spanish, the official-language references are machine-made, and the model cards say so. Hindi and Thai are translated too; the current build uses the six above. All seven cost $13.58 for 779,541 translations: about 1.7 cents per 1,000 sentences per language.

The six-language build already trains a model. Meta’s open-weight NLLB-200 distilled 1.3B, fine-tuned on that build, is public on Hugging Face as uyari-mt-cbt-nllb1.3b (CC BY-NC 4.0): one model for all twelve directions, and it runs on a CPU.

On the held-out test set (322 segments), it scores chrF++ 43.2 Spanish→Shawi and 45.8 Shawi→Spanish, against a retrieval floor of 23.4 and 22.0, the score of returning the human translation of the most similar training sentence. The twelve directions average 44.0. The civic domain (vaccines, identity documents, the health post) scores lowest: 35.5 Spanish→Shawi against 42.3 to 45.3 in the other three, and it has the fewest pairs, 129.

111,363 Spanish chunks, 3.04 million words, 11,205 paraphrase groups, 15 domains, 180 micro-scenarios, one prompt version, twinned in seven languages, for $15.74 of the $150 budget in Meta API calls. Muse Spark took the corpus from 10,000 sentences to 111,363 in every language. That growth is official-language text ready for translators: the 3,575 Shawi pairs (3.2%) come from the first batch, and the 107,788 others wait for their Shawi side.

Health and civic life, where this case started, has 13,697 Spanish chunks across two domains. Its Shawi pairs number 129, all civic: the health domain itself (a child with fever, a bad headache, curing with forest plants) has none yet. The language’s own NEEDS.md asks for 300 to 500 health and civic pairs next. The bottleneck now is the speaker's hour.

In a low-resource language, the scarce resource is a speaker’s hour. A machine writes a thousand Spanish sentences for two cents and puts them into seven more languages for twelve more; a person translates them one at a time. So design the source like an experiment, gate it like a pipeline, and spend a speaker’s hour only on sentences from their world.

The single most useful thing you can do now is like, repost and comment on https://x.com/malexandersv/status/2117644114363920674, and share it with your groups.

No Doctor, No Judge, No App Understands Them: Building Translation Data for 476M Indigenous People was originally published in Towards AI on Medium, where people are continuing the conversation by highlighting and responding to this story.

── more in #artificial-intelligence 4 stories · sorted by recency
── more on @uyari 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/no-doctor-no-judge-n…] indexed:0 read:14min 2026-11-05 · —