Gauge.ai is a high-performance Terminal User Interface (TUI) built in Rust. It serves as a local knowledge aggregator for model railway enthusiasts, combining multi-source web scraping, AI-driven data reconciliation via Ollama, and local semantic search using a vector-enabled SQLite database.
- Local-First: All data, high-res images, and metadata are stored locally in the user's home directory.
- Intelligent Normalization: Leverage Ollama to transform "noisy" web HTML into structured technical datasets.
- Semantic Search: Natural language querying (RAG) powered by
sqlite-vec. - Data Synthesis: Use LLMs to merge conflicting data from multiple sources into a single "Golden Record."
| Component | Technology |
|---|---|
| Language | Rust (Edition 2024) |
| Async Runtime | tokio |
| TUI Framework | ratatui with crossterm |
| Database | SQLite + sqlite-vec (Single-file storage) |
| AI Inference | Ollama (Local API) |
| Hashing | sha2 (SHA-256) for CAS and cache keys |
| Image Rendering | ratatui-image (Sixel/Kitty support) |
pub struct ModelData {
pub manufacturer: String,
pub product_code: String, // SKU
pub name: String,
pub description: String,
pub details: String,
pub scale: String,
pub epoch: String,
pub railway_company: String,
pub local_image_paths: Vec<String>,
pub image_urls: Vec<String>,
pub specifications: HashMap<String, String>,
}- Config:
~/.config/gauge-ai/config.toml - Database:
~/.local/share/gauge-ai/trains.db - Cache:
~/.local/share/gauge-ai/cache/<scraper-name>/<url-hash>.json - Images:
~/.local/share/gauge-ai/cache/<scraper-name>/<url-hash>/<img-hash>.jpg
Scrapers use a two-stage process to allow for TUI progress tracking.
#[async_trait]
pub trait ModelScraper: Send + Sync {
fn name(&self) -> &str;
fn supports_manufacturer(&self, mfr: &str) -> bool;
fn supports_latest(&self) -> bool { false }
async fn discover_product_pages(&self, criteria: ScrapeCriteria) -> Result<Vec<Url>, ScraperError>;
async fn discover_latest(&self) -> Result<Vec<Url>, ScraperError>;
async fn extract_model_info(&self, url: Url) -> Result<ModelData, ScraperError>;
}A wrapper that intercepts scraper calls to manage the local filesystem.
- URL Hashing: Uses SHA-256 of the URL as the primary cache key.
- Asset Management: Downloads images to a subdirectory named after the URL hash.
- Persistence: Saves the
ModelDataas JSON to allow for offline TUI browsing.
When a duplicate SKU is found across different sources (e.g., Roco.cc vs. an E-shop), the system does not simply overwrite data.
- Retrieval: Pulls the existing "Golden Record" from SQLite.
- Synthesis: Ollama is prompted to merge the two records, prioritizing technical accuracy and preserving unique specs from both sources.
- Versioning: The previous state is archived in a
model_versionstable before the new merge is committed.
- Knowledge Injection: Local
knowledge_base.tomlcontaining NEM standards and Epoch definitions is used to ground the LLM's normalization. - Semantic Search: User queries are embedded via Ollama and matched in the
sqlite-vecvirtual table.
| Command | Usage | Logic |
|---|---|---|
/help |
/help |
Displays command overview. |
/list-scraper |
/list-scraper |
Iterates and prints names of available scraper modules. |
/scrape |
/scrape <mfr> <query> |
Triggers background task; sends MPSC message upon completion. |
/latest |
/latest [mfr] |
Scans "New Arrivals" on supported sites. |
/query |
/query <text> |
Semantic search via embeddings + vector database. |
/export |
/export <query> |
Bundles JSON and image assets for matching records. |
/clear |
/clear |
Clears in-memory chat history from the TUI console. |
- Async Loader: A throbber widget that alternates between bold and normal text with a "..." cycle to indicate background Ollama/Scrape activity.
- Protocol Fallback: Auto-detects terminal capabilities. Uses high-res rendering for Sixel/Kitty; falls back to Unicode Half-blocks for basic terminals.
- Database Corruption: Automatic backup and re-initialization of
trains.dbon startup. - Scraper Brittleness: Graceful error handling for HTML structure changes; reports "Update Required" instead of crashing.
- Incompatible Embeddings: Detects if the embedding model version has changed in
config.tomland prompts for a vector re-index. - Disk Pressure: Aborts image caching if disk space is low, preserving the lightweight text metadata.