From ba15e7a4bf9dc4ab6b312f40c2e0199d4e5a8255 Mon Sep 17 00:00:00 2001 From: Agando Date: Mon, 9 Nov 2026 15:02:17 +0100 Subject: feat(chat-widget): shippable widget package replacing the demo as the paid download MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The store sold a €149 package whose download_url was the sales demo page. This is the widget alone: 601 lines, no CDN, no operator host, no model name, config extracted to config.example.js, wx- prefixed ids so embeds cannot collide. Verified in headless Chromium against a mock gateway (streaming, chips, link detection, unconfigured state). --- docs/USAGE.md | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 233 insertions(+) create mode 100644 docs/USAGE.md (limited to 'docs/USAGE.md') diff --git a/docs/USAGE.md b/docs/USAGE.md new file mode 100644 index 0000000..b71c3cd --- /dev/null +++ b/docs/USAGE.md @@ -0,0 +1,233 @@ +# Using the WebX11 Chat Widget + +## 1. Files + +``` +widget.html the widget (HTML + CSS + JS, self-contained) +config.example.js copy to config.js and edit +``` + +Both files must sit in the same directory, because `widget.html` loads +`config.js` with a relative ` +``` + +Order matters: `config.js` must be loaded before the widget script runs, and +the widget script must run after the DOM nodes exist (place it at the end of +``, or wrap your own init in `DOMContentLoaded`). + +Minimal page: + +```html + + + + + + My site + + + +

My site

+ + + + + + + +``` + +The widget uses `wx-` prefixed ids and classes and all CSS is scoped to +`#wx-chat-widget`, so it will not collide with your site's styles. It sets +`z-index: 2147483000`; lower it in your CSS if you have a cookie banner that +must sit above the bubble. + +## 4. The endpoint contract + +The widget sends: + +``` +POST +Content-Type: application/json + +{"model":"","prompt":"\n\nUser Question: ","stream":true} +``` + +and expects newline-delimited JSON (Ollama `/api/generate` format), where each +line has a `response` string: + +``` +{"model":"llama3.2:latest","response":"Hello","done":false} +{"model":"llama3.2:latest","response":" there","done":false} +{"model":"llama3.2:latest","response":"","done":true} +``` + +Server-sent events (`data: {...}`) and a non-streaming JSON reply with a +`response` field are also accepted, so most OpenAI-style shims work if they +emit one of those shapes. + +## 5. Gateway examples + +nginx reverse proxy in front of a local Ollama: + +```nginx +location /ollama/ { + proxy_pass http://127.0.0.1:11434/; + proxy_http_version 1.1; + proxy_set_header Host $host; + proxy_buffering off; # streaming + proxy_read_timeout 300s; + # your key is added here, server side, e.g. + # proxy_set_header Authorization "..." ; (kept out of this doc on purpose) +} +``` + +Ollama itself refuses cross-origin browser calls unless the origin is allowed: + +```bash +# systemd drop-in or shell environment for the ollama service +OLLAMA_ORIGINS="https://www.example.com,https://example.com" +``` + +Caddy: + +```caddy +handle_path /ollama/* { + reverse_proxy 127.0.0.1:11434 +} +``` + +## 6. Troubleshooting + +**Nothing happens when I open the page.** +Check the browser console. A 404 on `config.js` means the file is not next to +`widget.html` or the path in the `