Spree Menu Chat
A read-only, retrieval-grounded chat assistant for Spree Commerce storefronts. Answers customer questions about the menu, ingredients, dietary info, hours, and store policies — grounded entirely in the store's own synced catalog and Spree::Policy content, nothing from the model's general knowledge. It's the companion to spree_square (reused, softly, for modifier-list grounding when present) and spree_doordash.
⚠️ This extension is explicitly read-only. It has no cart or order mutation capability at all — no
tools/function-calling definitions are ever passed to the generation call, so there is no code path by which a response can add an item, place an order, or change any Spree state. That's a deliberately separate, higher-risk feature this extension does not attempt.
What this does
- Grounded Q&A over the real menu — embeds every published product (name, description, category, modifier lists) and every store
Spree::Policy(hours, delivery area, allergen info, etc.) into pgvector, and answers only from what's actually retrieved for a given question. - Live-synced, not a snapshot — re-embeds automatically whenever a product changes, whether from a Square sync or a manual admin edit.
- Graceful "I don't know" — if nothing retrieved clears a similarity floor, it skips the generation call entirely and returns a real contact-us fallback rather than guessing.
- No official SDK dependency — neither the Gemini API (generation) nor Voyage AI (embeddings) has an official Ruby SDK, so both are called directly over their REST APIs — the same pattern
spree_doordashalready uses for DoorDash's Drive API.
Installation
-
Add this extension to your Gemfile with this line:
bundle add -
Run the install generator
bundle exec rails g spree_menu_chat:install -
Restart your server
If your server was running, restart it so that it can find the assets properly.
Connecting Gemini and Voyage AI
Neither service uses OAuth — both are plain static API keys, entered directly:
- Create a free API key at Google AI Studio — no billing account
required. The free tier (as of writing: 1,000 requests/day on
gemini-flash-lite-latest, no card on file) comfortably covers a single restaurant's real traffic. One trade-off worth knowing: Google's free-tier terms allow using your prompts/responses to improve their models (the paid tier does not). - Create a free API key at Voyage AI — the first 200 million tokens
are free per account on the
voyage-4/voyage-4-litefamily, which is enormous headroom for embedding a restaurant menu (a few thousand tokens, typically). Separately, and easy to miss: without a payment method on file, Voyage also caps request rate at just 3 requests/minute, 10K tokens/minute (confirmed live — the free 200M-token allowance is real and unaffected, but this rate cap is much tighter than that headroom suggests).SpreeMenuChat::EmbeddingClientself-throttles to that limit so a full-catalogreembed_allrun doesn't 429, but it does mean that run takes real wall-clock time (roughly one record every ~20s once past the first 3) — add a payment method in the Voyage dashboard once you're past initial development to raise the cap; the free token grant still applies afterward. - In your Spree admin, go to Menu Chat Connection in the sidebar and paste both keys in.
They're encrypted at rest (ActiveRecord::Encryption)
— same mechanism
spree_square/spree_doordashuse for their own credentials, sharing the sameACTIVE_RECORD_ENCRYPTION_*keys.
Development
bundle install
bundle exec rake test_app # generates spec/dummy
bundle exec rspec
To manually verify a real Gemini key end to end (outside the spec suite):
cp .env.local.example .env.local # fill in GEMINI_API_KEY
bin/rails spree_menu_chat:verify_connection
When testing your application's integration with this extension you may use its factories. Simply add this require statement to your spec_helper:
require 'spree_menu_chat/factories'
Releasing a new version
bundle exec gem bump -p -t
bundle exec gem release
For more options please see gem-release README
Contributing
If you'd like to contribute, please take a look at the instructions for installing dependencies and crafting a good pull request.