An Owens Valley Paiute (Northern Paiute) language dictionary β a Vue 3 PWA deployed to Cloudflare Pages with D1 + Vectorize search.
- π Built from .lift XML files (SIL FieldWorks format)
- π Hybrid search: D1 FTS5 full-text + Vectorize semantic search when online
- π΄ Works offline with TF-IDF fallback from cached data (PWA)
- π Light/dark mode with persistent preference
- π± Fully responsive design
- π² Random word discovery and word of the day
- π€ MCP server for AI assistant integration
- π REST API via Cloudflare Pages Functions
- Install dependencies:
npm install-
Place your
.liftdictionary file in the project root asdictionary.lift -
Build the data files and frontend:
npm run build- Seed the Cloudflare databases:
npx wrangler login # authenticate with Cloudflare
npm run seed:d1 # seed D1 database
VECTORIZE_API_TOKEN=xxx node build-scripts/seed-vectorize.js # seed Vectorize- Deploy:
npm run deploy- Preview locally:
npm run preview # runs on :8788 with Cloudflare FunctionsWhen you receive a new .lift file:
npm run build:data # 1. Parse .lift β JSON
npm run seed:d1 # 2. Re-seed D1 (drops and recreates tables)
VECTORIZE_API_TOKEN=xxx node build-scripts/seed-vectorize.js # 3. Re-seed Vectorize
npm run deploy # 4. Build and deploydictionary-static/
βββ build-scripts/ # Build-time data processing & DB seeding
β βββ parse-lift.js # Parses .lift XML into JSON
β βββ d1-schema.sql # D1 database schema (FTS5, paiute_forms)
β βββ seed-d1.js # Seeds D1 from generated JSON
β βββ seed-vectorize.js # Generates embeddings & seeds Vectorize
βββ functions/api/ # Cloudflare Pages Functions
β βββ _db.js # D1/Vectorize query helpers
β βββ _shared.js # Shared utilities (CORS, formatting)
β βββ mcp.js # MCP server (JSON-RPC 2.0)
β βββ search.js # English search (FTS5 + Vectorize)
β βββ search-paiute.js # Paiute fuzzy search
β βββ search-sentences.js # Sentence search
β βββ browse.js # Alphabetical browse
β βββ word/[id].js # Word lookup
β βββ word-of-the-day.js # Word of the day
β βββ random-word.js # Random word
β βββ random-sentence.js # Random sentence
βββ src/
β βββ views/ # Page components
β β βββ Home.vue # Search with Words/Sentences tabs
β β βββ Browse.vue # Alphabetical browsing
β β βββ Word.vue # Word detail page
β β βββ Pronunciation.vue # Pronunciation guide
β β βββ About.vue # About page
β βββ services/
β β βββ data.js # Loads JSON data for offline use
β β βββ smart-search.js # TF-IDF search (offline fallback)
β β βββ search-api.js # Online search via API
β β βββ utils.js # Paiute fuzzy matching utilities
β βββ router/
β βββ index.js # Vue Router configuration
βββ public/data/ # Generated JSON (gitignored)
βββ dictionary.lift # Source dictionary file (place here)
Online: PWA/API/MCP β D1 FTS5 + Vectorize semantic search β hybrid scored results
Offline: PWA β local TF-IDF from cached words.json/sentences.json
- D1 FTS5: Full-text search with porter stemming on English definitions/glosses
- Vectorize: Semantic vector search using
@cf/baai/bge-base-en-v1.5embeddings (768 dims, cosine similarity) - Hybrid scoring:
score = (vectorize_similarity * 0.6) + (fts5_rank * 0.4) - Paiute fuzzy: Phonetically-aware matching (k/g, t/d, s/z, u/u equivalence) with Levenshtein distance
- TF-IDF (offline): Term frequency-inverse document frequency with cosine similarity
| Binding | Service | Purpose |
|---|---|---|
DB |
D1 (kubishi-dictionary) |
Word/sentence storage, FTS5 search |
VECTORIZE_WORDS |
Vectorize (kubishi-words) |
Word semantic search (768 dims) |
VECTORIZE_SENTENCES |
Vectorize (kubishi-sentences) |
Sentence semantic search (768 dims) |
AI |
Workers AI | Query embedding generation at search time |
All endpoints are under /api/.
| Endpoint | Description |
|---|---|
GET /api/search?q=water |
Search by English meaning/definition |
GET /api/search-paiute?q=paa |
Search by Paiute word (fuzzy matching) |
GET /api/word/:id |
Look up a word by ID |
GET /api/browse?letter=T |
Browse alphabetically by letter |
GET /api/word-of-the-day |
Get the word of the day |
GET /api/random-word |
Get a random word |
GET /api/search-sentences?q=mountain |
Search example sentences |
GET /api/random-sentence |
Get a random sentence |
Common query parameters: limit (max results), skip (pagination offset).
The dictionary exposes an MCP (Model Context Protocol) endpoint at /api/mcp, allowing Claude and other MCP-compatible AI assistants to search and browse the dictionary directly.
{
"mcp_servers": [{
"type": "url",
"url": "https://kubishi.com/api/mcp",
"name": "kubishi-dictionary"
}],
"tools": [{
"type": "mcp_toolset",
"mcp_server_name": "kubishi-dictionary"
}]
}{
"mcpServers": {
"kubishi-dictionary": {
"command": "npx",
"args": ["mcp-remote", "https://kubishi.com/api/mcp"]
}
}
}| Tool | Description |
|---|---|
search_english |
Search by English meaning or definition |
search_paiute |
Fuzzy search by Paiute word form |
lookup_word |
Get a word by its ID |
browse_words |
Browse entries alphabetically |
get_letter_counts |
Word counts per starting letter |
word_of_the_day |
Get today's featured word |
random_word |
Get a random dictionary entry |
search_sentences |
Search example sentences |
random_sentence |
Get a random example sentence |
npx @modelcontextprotocol/inspectorSelect Streamable HTTP and enter the MCP endpoint URL.
This project expects a standard SIL FieldWorks .lift (Lexicon Interchange FormaT) XML dictionary file. The parser extracts:
- Lexical entries (words and headwords)
- Forms in multiple writing systems
- Senses with definitions and glosses
- Example sentences with translations
- Grammatical information (part of speech)
- Entry dates and GUIDs
Edit src/assets/style.css to customize colors and appearance. CSS variables make it easy:
--bg-primary,--bg-secondaryβ Background colors--text-primary,--text-secondaryβ Text colors--accent-primaryβ Accent/link color- All variables have separate dark mode values
- Update
src/views/About.vuewith your credits and information - Modify
src/views/Pronunciation.vuefor your language's pronunciation - Edit acknowledgements in
src/views/Home.vue
This site displays data from Glenn Nelson Jr.'s Owens Valley Paiute Dictionary, made possible through the contributions of native speakers and elders.
Built with Vue 3, Vite, Cloudflare D1/Vectorize/Workers AI, and custom hybrid search. Hosted on Cloudflare Pages.