🌙 LUAR: Local Utility for Automated Reviews
Drop a spreadsheet, say what you want to know about each row, and get back a copy with the answers plus a Markdown summary. Everything runs on your own computer: no cloud, no data sent anywhere.
Who it's for: anyone with a spreadsheet of text (reviews, survey answers, messages, notes) who
wants it labeled without writing code, SQL or Docker files. One pip install, one file, your own
questions.
LUAR has two local engines:
| Engine | What it is | Speed* | When to use |
|---|---|---|---|
| Laya (default) | Laya, an open decision model in the style of Jev: it answers structured questions with a probability, instead of generating text | ~0.6 s per row | large files, quick passes |
| LM Studio | any chat model you run in LM Studio (tested with Qwen 3.5 4B) | ~5 s per row per question | smaller files, when accuracy matters most |
*On a laptop CPU without a dedicated GPU. Both engines give a real probability as confidence.
What it does
| You give it | You get back |
|---|---|
A .csv or .xlsx file |
<name>_luar.csv/.xlsx: a copy with new columns (your original is never touched) |
| The column(s) to read | For each question: <id> (the answer) and <id>_confidence (0–1) |
| Your questions | needs_review = yes when any answer is below the confidence threshold, and review_reasons |
<name>_luar_summary.md: counts per answer, rows to review, accuracy (see below) |
Question types
| Type | Answers | Example |
|---|---|---|
choice |
one of your options (2–20) | What is this review about? delivery / product / support / price |
noul |
yes or no |
Does the customer ask for their money back? |
score ⚠️ |
a level on an ordered scale | How severe is it? low / medium / high |
⚠️
scoreis experimental. It was the least reliable type in our tests: 71% (Laya) and 79% (LM Studio) agreement with hand labels on the bundled severity example. Preferchoiceornoul, or checkscoreresults by hand.
Install
Requires Python 3.10+. The first run downloads the Laya model (a few hundred MB) from Hugging Face.
pip install "luar[ui]"
Leave out [ui] if you only need the command line. To get the bundled examples (and the example
picker in the web interface), install from the repository instead:
git clone https://github.com/HayateV30/luar.git
cd luar
pip install -e ".[ui]"
Use it
Web interface
luar ui
This opens http://127.0.0.1:7860 in your browser (local only). Then:
- Drop your file and tick the column(s) the model should read.
- Fill in the questions table (or load a questions
.json, or pick a bundled example). - Pick the engine (Laya or LM Studio), click Run and download the result copy and the summary.
Command line
luar columns examples/reviews.csv
luar run examples/reviews.csv -q examples/reviews_questions.json -c review
Options: -t/--threshold (default 0.7), -o/--out-dir, --sheet (Excel), -e/--engine
(laya or lmstudio). Laya: --checkpoint (auto, multilingual, english), --device
(cpu/cuda). LM Studio: --model, --lmstudio-url.
Using LM Studio
- Install LM Studio and download a chat model (e.g.
qwen3.5-4b). - Start the server and load the model, in the app (Developer → Start Server) or with its CLI:
lms server start lms load qwen3.5-4b
- Run with
--engine lmstudio(or choose LM Studio in the web interface).
The server URL defaults to http://localhost:1234/v1 (change it with LUAR_LMSTUDIO_URL). If you turned
on Require API key in LM Studio, put the key in the LMSTUDIO_API_KEY environment variable, never in
a file you commit. LUAR turns the model's "thinking" off (reasoning_effort: none): each answer is a
single token.
Python
from luar import load_questions, run_file
from luar.backends import make_backend
backend = make_backend("laya") # or make_backend("lmstudio", model="qwen3.5-4b")
result = run_file("data.csv", load_questions("questions.json"), ["text"], backend)
print(result.table_path, result.summary_path)
Questions file
[
{
"id": "topic",
"type": "choice",
"question": "What is this review mainly about?",
"options": {
"delivery": "shipping, delays, courier, package condition",
"product": "quality, defects, how the item works"
}
},
{"id": "sentiment", "type": "choice", "question": "Overall sentiment?", "options": ["positive", "neutral", "negative"]},
{"id": "wants_refund", "type": "noul", "question": "Does the customer explicitly ask for their money back?"}
]
id: letters, digits and_; becomes the column name.options: a list of labels, or{label: description}. Descriptions help the model a lot.- Laya's native format (
{"id": {"type", "instructions", "criteria"}}) is accepted too.
Check before you trust it
A model can be confidently wrong, so measure it on your own data before using the results:
- Label 20–50 rows by hand in columns named
expected_<id>(e.g.expected_topic). Fornoul,yes/no,sim/não,true/falseand1/0all work. - Run LUAR. The summary shows accuracy against
expected_<id>for each question. - Adjust the questions (wording, option descriptions) or the threshold until you are happy.
expected_* columns are never offered to the model as input.
Tips from testing
- Accuracy on the bundled examples: Laya got 86–100% on
choice/noul; LM Studio with Qwen 3.5 4B got 100% on all of them, but took over 20x longer (3 questions: ~14 s vs ~0.6 s per row). - Language (Laya):
autopicks theenglishmodel when the file is in English andmultilingualotherwise. On English text, the English model was clearly better; on Portuguese, the multilingual one. - Describe options.
"price": "cost, value for money, charges"beats a bare"price". - Option order can change answers. Put the most specific options first and test with
expected_*. - Keep to about 20 options per question. Split larger lists into two questions.
- Confidence is a hint, not a guarantee. Use
needs_reviewto decide where a human should look.
Related projects
Other open tools around Laya, in case one fits you better:
- laya-studio: a full web platform (Docker + PostgreSQL) with batch evaluation, calibration monitoring, a review queue and automations. Pick it if you are building a decision system for a team; pick LUAR if you just want a labeled spreadsheet.
- vgi-laya: Laya as SQL functions inside DuckDB. Pick it if your data already lives in a database and you are comfortable with SQL.
- More in the laya.tools directory.
Architecture
src/luar/
questions.py question model + validation (choice / score / noul)
tables.py CSV/XLSX reading (separator & encoding sniffing) and never-overwrite writing
engine.py runs the questions over rows, confidence threshold, accuracy
report.py Markdown summary
backends/ the "socket" for decision engines: Laya and LM Studio
cli.py, app.py command line and Gradio interface
A new engine only needs to implement
Backend.decide(texts, questions) -> [{question_id: Answer(value, confidence)}].
How the LM Studio engine gets a confidence: each option is shown with a letter (A, B, C…), the model
answers with one token, and LUAR reads the probability the model gave each letter (logprobs),
renormalized over the valid letters. That is the model's actual probability, not a number it writes
about itself.
Development
pip install -e ".[ui,dev]"
pytest # fast tests, no model needed
pytest -m slow -s # runs the real models on the examples (LM Studio tests skip if the server is off)
License
MIT for LUAR's code. Laya (the package and the model weights) is a separate project with its own license; check its model card before redistributing it.
Metadata
Release files for luar 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| luar-0.2.0.tar.gz | 30.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| luar-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 56.8 kB
Release files / luar-0.2.0.tar.gz
| Download URL | luar-0.2.0.tar.gz |
|---|---|
| Size | 30.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a993721544d7afa214223a0c6a34757cb798d4183a6047c111851a40abb184cf
|
|
BLAKE2b-256 checksum How to use checksums |
6f98ed871754e73f9cc56aa3e3099ecfe31cb8eb746f4b7ab575e1fda8c2ade3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency logRelease files / luar-0.2.0-py3-none-any.whl
| Download URL | luar-0.2.0-py3-none-any.whl |
|---|---|
| Size | 26.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a8c2f45d3f446eb44ac9a8624100570aa1580b3bb2a030e757371b567e1437cc
|
|
BLAKE2b-256 checksum How to use checksums |
0ccec4bc713de3c93f9ebc47c81254501feba8f2d3742f7dd7744e2d56789bec
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.
Transparency log