ZainabEman's picture
Update README.md
e366adf verified
|
Raw History Blame Contribute Delete
5.73 kB

A newer version of the Streamlit SDK is available: 1.67.0

Upgrade
metadata
title: Machine Part Finder
emoji: πŸ”
colorFrom: red
colorTo: gray
sdk: streamlit
sdk_version: 1.63.0
python_version: '3.11'
app_file: app.py
app_port: 7860
pinned: false

Machine Part Finder β€” BQ188 spare-parts catalogue

Type a spare-part number, get the catalogue diagram with the actual machine component outlined in red β€” not just the printed number.

30642  ->  page 34, section 07 "Motor-drive", Schnecke,kpl. / worm,cpl.
           red box drawn around the worm gear itself

The source document is 1.pdf, a 55-page catalogue for the BQ188 warp tying machine. Its exploded-view diagrams label parts with the part number itself, joined to the component by a thin leader line. Finding the text 30642 is easy; finding the worm gear it points at is the actual problem this solves.

How it works

Two stages. All the expensive work happens once, offline.

OFFLINE (once, ~10 min)                    RUNTIME (per search, instant)

1.pdf                                      part number
  |  parse catalogue tables (real text)      |  SQLite lookup
  |  extract diagrams at native resolution   |  load cached PNG
  |  OCR the diagrams (RapidOCR)             |  draw red box in memory
  |  snap callouts to the known part set     |  display
  |  trace leader lines -> component boxes
  v
data/catalog.db + data/pages/*.png

The search path never runs OCR, computer vision or PDF parsing β€” it reads the database and draws rectangles. No network, no LLM, no cloud service is involved at any point, before or after the build.

Piece What it does
spareparts/pdf_loader.py Finds the 30 catalogue pages, extracts each diagram
spareparts/table_parser.py Reads the parts tables (real vector text, never OCR)
spareparts/ocr.py OCRs the 30 diagrams, cached to JSON
spareparts/matcher.py Snaps OCR output to the 705 known part numbers
spareparts/localizer.py Traces leader lines to the component (the hard part)
spareparts/index_db.py SQLite schema and queries
spareparts/lookup.py, overlay.py Runtime query and red-box rendering
app.py Streamlit UI

PSD.md is the project's specification and records what was found in the PDF.

Install

Python 3.11.

pip install -r requirements.txt

Everything runs on CPU and offline. The OCR models ship inside the rapidocr-onnxruntime wheel; nothing is downloaded at run time.

Build the index

Needed once, before first use, and only again if 1.pdf changes.

python -m spareparts.build_index

Takes about ten minutes and writes data/catalog.db plus data/pages/*.png. It is safe to re-run: the database is rebuilt from scratch rather than appended to. OCR results are cached in data/ocr_cache/, so re-running after a change to the localizer only costs a couple of minutes:

python -m spareparts.build_index --stage annotate       # skip re-indexing
python -m spareparts.build_index --stage annotate --debug-images   # + overlays

Expected output: 30 catalogue pages, 705 distinct parts, 861 table occurrences, 987 located callouts.

Run the app

streamlit run app.py

Then open http://localhost:8501, type a part number and press Enter.

Example searches

Search What you get
30642 One page. Red box on the worm gear, page 34, section 07.
74506 One page, but the part is drawn four times β€” all four boxed and numbered #1–#4.
73290 Ten pages. An occurrence selector appears; pick which to view.
99999 "Part number not found in the catalogue."

Input is forgiving: part no. 30642 finds the same part. It is not fuzzy, though β€” the digits you type either name a real part or they do not.

Tests

python -m pytest tests -q

Accuracy of the offline stages can be re-measured at any time:

python tools/ocr_report.py     # OCR recall, per page
python tools/evaluate.py       # localization vs. the hand-checked ground truth

Limitation worth knowing

Localization is deterministic OCR and classical computer vision β€” binarize, find connected components, trace the leader line from the callout to what it touches. There is no model and nothing is learned from data, so every result can be explained by the geometry that produced it.

That approach has one real limit: where two parts are drawn physically touching, they are a single connected shape and cannot be separated. On the hand-checked set of 87 callouts the tool puts the box on the correct component 90.8% of the time; the misses are almost all parts merged into a larger housing or arm.

Rather than hide this, the app labels every result with how it was obtained:

  • Located β€” the leader line was traced cleanly to the component.
  • Assembly β€” the callout is boxed in the catalogue, so it names a whole group.
  • Approximate β€” the component could not be isolated; the highlight is a conservative area around the leader line's end. Shown with a low confidence.
  • Not located β€” a callout was found but no component could be resolved.

Page 51 is the clearest example: it is a single assembled view where everything touches, so every callout there falls back to "Approximate". The box still lands on the right area, and the app says so instead of implying precision it does not have.

Two other honest caveats:

  • The catalogue does not draw every part it lists. When a part is listed on a page but not drawn there, the page is shown without a highlight and the app explains why.
  • Occasionally a part is drawn on a page whose own table omits it. Those callouts are still matched against the full catalogue, and flagged.