Spree Menu Chat

Gem Version GitHub Release License: MIT

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_doordash already uses for DoorDash's Drive API.

Installation

  1. Add this extension to your Gemfile with this line:

    bundle add spree_menu_chat
    
  2. Run the install generator

    bundle exec rails g spree_menu_chat:install
    
  3. 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:

  1. 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).
  2. Create a free API key at Voyage AI — the first 200 million tokens are free per account on the voyage-4/voyage-4-lite family, 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::EmbeddingClient self-throttles to that limit so a full-catalog reembed_all run 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.
  3. 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_doordash use for their own credentials, sharing the same ACTIVE_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.