# Restaurant QR Voice Assistant — Static Demo

A **client-side-only** demo: speak a phrase, see it transcribed, see it translated, and hear it
spoken back — all in the browser, no server, no build step, no API keys.

Deployable as-is to Cloudflare Pages (or any static host): just point it at this folder.

## Files

- `index.html` — page structure and controls
- `style.css` — plain CSS, no framework
- `app.js` — vanilla JS wiring up the three browser APIs below
- `README.md` — this file

## What it uses

| Step | API | Notes |
|---|---|---|
| Speech → text | **Web Speech API** (`SpeechRecognition` / `webkitSpeechRecognition`) | Browser-native, free, no key. |
| Text → text | **LibreTranslate**-compatible public HTTP API (`fetch` to `libretranslate.com` and fallback mirrors) | Free public instances, no key required for this demo. |
| Text → speech | **Web Speech API** (`SpeechSynthesis`) | Browser-native, free, no key. |

Nothing is sent anywhere except the plain-text phrase to the translation endpoint. There is no
backend, no database, and no analytics in this demo.

## Known limitations

- **`SpeechRecognition` browser support is Chrome/Edge only** (desktop and Android). Firefox and
  Safari do not implement it, and the app will show a clear on-screen message instead of failing
  silently.
- **Maltese (`mt-MT`) speech recognition is unreliable.** Support depends on the browser's speech
  backend and the OS's installed language packs, not just the browser itself. Expect a
  `language-not-supported` error on many devices — the app surfaces this as a plain message rather
  than crashing.
- **The public LibreTranslate endpoints are rate-limited and not guaranteed to be online.** This
  demo tries a small ordered list of known public instances and falls back through them, but all
  of them can be slow, unavailable, or temporarily blocking requests. **Do not use these endpoints
  in production** — self-host LibreTranslate or use a paid translation API with a real quota
  instead.
- **`SpeechSynthesis` voice availability is device-dependent.** If the device has no installed
  voice for the target language, the app falls back to the default system voice and shows a
  "no native voice for this language" notice rather than failing.
- This is a **demo, not a production app**: no error retry/backoff beyond the endpoint fallback
  list, no offline support, no persistence.

## Running locally

No build step needed. Either:

```bash
# Open directly
open index.html

# Or serve it (recommended, since some browsers restrict microphone
# access on file:// origins)
npx serve .
```

## Deploying to Cloudflare Pages

1. Push this repo (or just the `web-demo/` folder) to GitHub.
2. In Cloudflare Pages, create a new project pointing at the repo.
3. Build command: none. Build output directory: `web-demo` (or `/` if deploying this folder alone).
4. Deploy — that's it, there's no backend to configure.
