Lalabase
Tickets, Doku, Zeiterfassung und Kundengespräche an einem Ort, durchsuchbar per KI. Für Softwarefirmen mit Kundenprojekten. Open Source: auf deinem eigenen Server oder in unserer Cloud in Deutschland.
翻譯準備中
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Embeddable AI chat widget for restaurant websites — menu Q&A, reservations, and to-go ordering. Vanilla JS + one serverless proxy.
翻譯準備中
取自儲存庫 README
正在載入完整 README。 以下為已儲存的摘錄。
An embeddable chat widget for restaurant websites. Guests can ask about the
menu, get hours and directions, request a reservation, or build a to-go order —
all in a floating chat bubble, grounded in one config file per restaurant.
Built as a sales demo: it ships with a believable fictional restaurant
(The Copper Thistle) and a mock website behind it so it looks real on a
projector or a phone, and it repoints at a real client by editing one file.
The widget is restaurant-data.js + widget.css + widget.js + api/chat.js.
The rest is stage dressing for the pitch.檢視完整 README ↗An embeddable chat widget for restaurant websites. Guests can ask about the menu, get hours and directions, request a reservation, or build a to-go order — all in a floating chat bubble, grounded in one config file per restaurant.
Built as a sales demo: it ships with a believable fictional restaurant (The Copper Thistle) and a mock website behind it so it looks real on a projector or a phone, and it repoints at a real client by editing one file.
| File | What it is | Edit it? |
|---|---|---|
restaurant-data.js | All restaurant content — name, hours, address, full menu, policies | Yes — this is the file you change per client |
widget.css | Widget styling. Brand colors are CSS variables at the top | Yes — change the colors |
widget.js | The widget itself: chat, tools, order cart, API calls | Rarely |
api/chat.js | Serverless function that holds the API key and forwards to Claude | Rarely |
index.html | The mock restaurant site used as a demo backdrop | Demo only |
site.css | Styling for that mock site | Demo only |
The widget is restaurant-data.js + widget.css + widget.js + api/chat.js.
The rest is stage dressing for the pitch.
The key lives in an environment variable on the server, never in the front-end code. You set it once and never touch it again.
On Vercel (production):
ANTHROPIC_API_KEY = your key from https://console.anthropic.comLocally:
cp .env.example .env.local # then paste your key into .env.local
npm i -g vercel # once
vercel dev # serves the site AND /api/chat on localhost:3000
.env.local is gitignored. Do not commit it.
Why not just put the key in the JavaScript? Because anything in the browser is public. A key in
widget.jsis visible to every visitor via View Source or the Network tab, and GitHub's secret scanning will flag it the moment you push — Anthropic auto-revokes keys that leak, so you'd be rotating keys constantly.api/chat.jsexists so that never happens: the browser calls/api/chat, and only the server sees the key.There is a
directApiKeyfield at the top ofwidget.jsfor the rare case where you need to run the demo by double-clickingindex.htmlwith no server at all. It carries the same exposure problem. Leave it empty unless you're offline, and clear it before you commit or deploy.
Open restaurant-data.js. Everything the bot knows is in the RESTAURANT
object at the top, in plain English:
brand — name, tagline, cuisine, greeting, and the quick-reply buttonshours — one line per day, written however the restaurant writes itcontact — address, phone, email, and a free-text parking/directions notemenu — categories, each with items: name, description, price, tagspolicies — reservations, allergies, to-go timingorder — tax rate, currency symbol, pickup estimateNotes:
22, not "$22"). The widget adds the symbol.tags are free text and shown to guests as written. Keep them consistent:
vegetarian, vegan, gluten-free, gluten-free available,
contains nuts, dairy-free, spicy, shellfish.index.html) reads from the same file, so swapping data
reskins the mock site and the widget together.You do not need to touch widget.js to change restaurants.
Open widget.css. The first block is the entire theme:
:root {
--rct-brand: #1f4d3d; /* header, launcher, guest bubbles */
--rct-brand-hover: #17392d; /* a darker shade of the above */
--rct-brand-contrast: #ffffff; /* text on top of the brand color */
--rct-accent: #c2703d; /* prices, cart badge, highlights */
...
}
Change those four and the widget is reskinned. --rct-radius controls how
rounded everything is; --rct-font sets the typeface.
For a logo: set brand.logoUrl in restaurant-data.js to an image path and it
replaces the two-letter placeholder in the chat header. Leave it empty to keep
the initials from brand.logoInitials.
Three files and three lines:
<link rel="stylesheet" href="/widget.css">
<script src="/restaurant-data.js"></script>
<script src="/widget.js"></script>
The widget mounts itself into <body>; there's no container div to place and
no initialization call. Every CSS class is prefixed .rct- so it won't collide
with the client's existing styles.
To open the chat from the client's own buttons:
<button onclick="RestaurantChat.open()">Chat with us</button>
<button onclick="RestaurantChat.send('I would like to make a reservation')">Book a table</button>
The client's site needs /api/chat available on the same domain, or you point
CONFIG.apiEndpoint in widget.js at wherever you deployed it.
git init
git add .
git commit -m "Restaurant chat widget"
git remote add origin https://github.com/YOUR-USERNAME/YOUR-REPO.git
git push -u origin main
Then on Vercel: Add New → Project → import the repo. No framework preset, no
build command, no output directory — it's static files plus one function.
Add ANTHROPIC_API_KEY under Environment Variables and deploy.
Or from the terminal:
vercel --prod
The model doesn't just talk — it calls four tools that the widget executes in the browser:
| Tool | Effect |
|---|---|
add_to_order | Adds items to the cart. Matches loosely on names, rejects anything not on the menu |
remove_from_order | Removes an item or reduces its quantity |
show_order_summary | Renders the final order card with subtotal, tax, and total |
confirm_reservation | Renders the reservation request card |
That's why the order drawer stays in sync with the conversation — the cart is real state the model manipulates, not text it wrote.
The tool definitions plus the system prompt (which carries the whole menu) come
to roughly 2,200 tokens that are identical on every request. Rather than paying
full price to resend them each time, widget.js marks that prefix with
cache_control, so the API stores it after the first request and bills later
requests at about 10% of the input price for that chunk.
This only holds while the text is byte-identical. If you interpolate anything
per-request into systemPrompt() — a timestamp, the guest's name, "today is
Tuesday" — the cache silently stops matching and you quietly pay full price
again. Put dynamic content in a message instead.
To confirm it's working, watch the server log (vercel dev, or Vercel →
Logs). Every request prints a line like:
tokens — cache write: 2214, cache read: 0, uncached in: 31, out: 88
tokens — cache write: 0, cache read: 2214, uncached in: 47, out: 112
First request writes, everything after reads. If cache read stays at 0
forever, something in the prefix is changing between requests.
Nothing here books or submits anything for real. There is no backend, no
POS, no reservation system. confirm_reservation draws a card that says
"not booked yet — we'll text you to confirm," and show_order_summary says
"not sent to the kitchen yet." The system prompt instructs the model to say the
same. If a client wants real bookings, those two tool handlers in widget.js
are where you'd POST to OpenTable, Resy, Toast, or the client's own system.
There is no payment handling, and the bot is told to refuse card details.
Conversations live in memory only — nothing is written to localStorage,
sessionStorage, or any database. Closing the tab clears everything.
This is a pitch demo. It's fine on a URL you control. Before it's a product:
/api/chat. Right now anyone who finds the endpoint can spend
your tokens. Add per-IP limiting (Vercel KV, Upstash) and set a monthly
spend cap in the Anthropic console.ALLOWED_ORIGINS in api/chat.js with the
client's domain.| What you see | What it means |
|---|---|
| "The assistant is not configured yet" | ANTHROPIC_API_KEY isn't set on the server |
"could not be reached... start it with vercel dev" | You're on a plain static server, so /api/chat doesn't exist. Use vercel dev |
| "We're getting a lot of messages right now" | Rate limited by the API — wait a few seconds |
| Bot says it doesn't know something obvious | It's missing from restaurant-data.js. Add it there |
| Bot invents a dish | Shouldn't happen. If it does, check the item is really absent from the data, then tighten the grounding rules in systemPrompt() in widget.js |
The model is set in widget.js (CONFIG.model, currently claude-opus-5) and
allowlisted in api/chat.js. To use a cheaper model, change it in both places.