Synaplan
開源 AI 平台,供企業使用:自行託管的 AI 代理、符合 GDPR 的聊天機器人小工具、RAG 知識庫、WhatsApp 與 Outlook AI、MCP、多模型路由。Docker、Kubernetes 或託管於 Germ
AI 翻譯
尚未偵測到更新。GitHub 發布版本後會顯示在這裡。
個人 GitHub 帳號下公開儲存庫的擁有者可以登入並驗證所有權,自行管理介紹,無需管理員核准。
登入並產生驗證檔案,在 30 分鐘內將其提交至此儲存庫的預設分支。其他分支或分叉儲存庫中的檔案無效。然後在下方檢查檔案,即可無需管理員核准直接管理專案。請保留檔案以維持管理權限。
如需登入,將前往登入頁面。登入後請回到此處,再次點擊所選的驗證按鈕。
在專案資料夾中執行 /nomorevibe verify,即可驗證所有權並自行管理介紹。
一分鐘完成驗證Pre-Flight Shipment Checker — catch shipment booking mistakes before they ship (Ops Hackathon Case 2)
翻譯準備中
取自儲存庫 README
正在載入完整 README。
檢視完整 README ↗Catch it before it ships. Upload a workbook of UK → EU shipment bookings, or just describe a shipment by chat or voice. Every booking is checked against the 10-rule rulebook (plus UK export-invoice tips). Each mistake is explained with its numbers and a fix, a carrier is picked for the seller's priority, and you get a plain-English confirmation.
Ship Eazy is a shipment checker built for Ops Hackathon – Case 2: Conversational Shipment Booking & "Pre-Flight" Error Checker.
/samples/stress-test.xlsx, then in Checker click Choose file (or drop it on the card). It has 16 bookings: one booking breaks each rule R-01…R-10, plus combinations, a missing field, an overweight-for-every-carrier case, a 5-digit numeric HS code, an orphan item and a "Bluetooth speaker".
Or drop your own .xlsx / .xls in the template format. Excel template download in the hero gives a blank workbook: just the Bookings and Items sheets with their column headings./results/<id>#BK-xxx for anyone.The 76-booking edge-case workbook is at /samples/edge-cases.xlsx: 21 can't ship yet, 15 details missing, 7 check first, 33 ready to ship, plus the orphan item EC-99 (V-11).
/api/voice/token; the ElevenLabs key never leaves the server.update_booking, get_booking_summary, confirm_booking, undo_last_change, start_over, download_purchase_order, download_corrected_excel). So the rules, guardrails, maths, summary panel and booking card are the same.Uploading the original template gives BK-001 GREEN, Carrier A Road economy, £540.00. That file contains only the grey example row, so it is checked as a demo. In any file that also has real rows, the grey example row is skipped.
Browser Server (Vercel, Next.js route handlers)
─────── ───────────────────────────────────────
Excel ─► lib/parseExcel.ts (SheetJS, raw cells)
│ Booking[] + Item[]
▼
lib/calculations.ts runFile() ◄── the ONLY source of pass/fail and numbers
│ "possible" restricted items ─────────────► POST /api/r06 Gemini yes/no (8 s, Zod) → else A-09 tip
▼ runFile() again with the verdicts
Results UI (cards, highlights, purchase order, corrected Excel)
│ BookingResult facts ─────────────────────► POST /api/explain Gemini wording (8 s, Zod, numbers-grounded check)
│ └ fallback: deterministic text from lib/explain.ts
├─ save ────────────────────────────────────► POST /api/uploads → Neon (uploads, bookings, items)
└─ confirm ─────────────────────────────────► POST /api/confirm → re-checks status rules → Neon (confirmations)
/results/[uploadId] ◄── server-rendered from Neon (public share link)
Chat / Voice ─► POST /api/chat { message, state, mode }
lib/conversation/engine.ts runTurn():
1 Gemini extracts raw values (JSON schema, Zod) └ fallback: keyword/pending-field parser
2 code normalises + applies them (provenance: stated / calculated / default), cascades totals
3 lib/calculations.ts runs the same checks as File Upload
4 code picks the next question (fixed priority order — never Gemini)
5 Gemini words the reply from FACTS; every £, date, carrier and rule ID must be in FACTS
└ else a fixed template reply
state saved → Neon conversations (version-checked; 409 on a stale tab)
lib/calculations.ts. Gemini only (a) gives a restricted yes/no on items keyword detection marks as "possible", and (b) rephrases facts the engine already produced. Gemini output is schema-validated, and any £ amount or date not found in the input facts is rejected.CARRIERS / RULES constants.| Rule | Check | Severity |
|---|---|---|
| R-01 | Every item has an HS code of at least 6 digits | Red |
| R-02 | Declared value = Σ(quantity × unit price), within 1% | Red |
| R-03 | Units per carton × cartons = quantity (per item) | Red |
| R-04 | Booking cartons = Σ item cartons | Red |
| R-05 | Gross weight ÷ pallets ≤ chosen carrier's max per pallet | Red |
| R-06 | No lithium batteries, aerosols or flammable liquids | Red |
| R-07 | Gross weight ≥ Σ(unit weight × quantity) | Amber |
| R-08 | Warehouse deliveries have an appointment booked | Amber |
| R-09 | Every item has a country of origin | Amber |
| R-10 | Ready-to-ship date is not in the past | Amber |
Plus input checks V-01…V-11, which make a booking Incomplete, and tips A-01…A-09 from the UK government export-invoice guide. Tips never change a booking's status. The full spec is in docs/RULEBOOK.md, docs/RECOMMENDATION_RULES.md and docs/CALCULATIONS_FORMULAS.pdf.
| Run | What | Result |
|---|---|---|
| Unit, scripted & parity | npm test — 302 Vitest cases: every rule and boundary, V-01…V-11, tips, carriers, parser warnings, the 76-booking edge-case workbook against its Expected sheet; conversation state, next-question order, normalisers, read-backs, reply validator; scripted chats (§7.1 vague seller, §7.2 add a pallet, contradictions, restricted goods, voice, prompt injection, Gemini down); chat ↔ Excel parity | 302 / 302 pass |
| Local build | npm run build && npm run e2e — 73 Playwright cases. The local server runs with GEMINI_MOCK=1, so chat runs are repeatable. Covers V1 plus chat booking to purchase order and corrected Excel, add-a-pallet toast and highlight, Undo, refresh starting fresh, voice token / mic-denied / not-configured / no-mic handling, guardrails on the rules page, HTML-as-text and axe | 71 pass, 2 skipped by design |
| Production | E2E_BASE_URL=https://preflight-shipment-checker-omega.vercel.app npm run e2e (the mocked-chat tests skip; the full chat was also run by hand with real Gemini, about 2–4 s per turn) | 63 pass, 7 skipped |
| No database, no AI (V1 run) | same suite with E2E_NO_DB=1 E2E_NO_AI=1 against a server with Neon unreachable and no Gemini key | 48 pass, 3 skipped by design |
npx tsx scripts/collect-metrics.ts measures speed and AI success on the live site; npx tsx scripts/build-report-data.ts turns all of it into reports/data/*.json, the datasets behind the test report dashboard (reports/dashboard/index.html).
npm install
cp .env.example .env.local # then fill in the values
npm run db:migrate && npm run db:seed # optional: Neon tables + carriers/rules
npm run dev
| Name | Required | Purpose |
|---|---|---|
GEMINI_API_KEY | No (fallback text without it) | Google AI Studio key. Used server-side only. |
GEMINI_CHAT_MODEL | No | Model for chat extraction and replies (default gemini-3.5-flash, minimal thinking, for about 2–5 s per turn) |
ELEVENLABS_API_KEY | For voice | ElevenLabs API key. Server only — used by /api/voice/token to mint a conversation token |
ELEVENLABS_AGENT_ID | For voice | The ElevenLabs agent to talk to |
GEMINI_MOCK | No | 1 = no Gemini calls in chat; the demo messages map to fixed extractions (used by Playwright) |
CHAT_RATE_LIMIT | No | Chat messages per minute per IP (default 30) |
GEMINI_MODEL | No | Overrides the model (production uses gemini-3.8-flash, the newest stable Flash on the key, with thinking set to low so calls fit the 8 s time-box). If empty, the newest stable gemini-X.Y-flash from the key's model list is used. |
DATABASE_URL | No (no share links without it) | Neon Postgres connection string |
| Script | What it does |
|---|---|
npm run dev / build / start | Next.js |
npm test | Vitest: engine, Excel parser, edge cases and the conversation (302 tests) |
npm run e2e | Playwright, V1 and V2 (run npm run build first). Add E2E_BASE_URL=https://… to test a deployment. |
npx tsx scripts/elevenlabs-setup.ts | Registers (or updates) the 7 client tools on the ElevenLabs agent; --check only reports. Reads the key from .env.local |
npm run make:stress | Regenerates public/samples/stress-test.xlsx from the real template |
npm run db:generate / db:migrate / db:seed | Drizzle migrations and the idempotent seed |
npm run lint / typecheck | ESLint / tsc |
lib/calculations.ts rule engine (spec, used as-is; see "Changes to the engine")
lib/parseExcel.ts header detection, grey example row, raw HS codes, Excel date serials
lib/checkFile.ts browser pipeline: parse → check → AI R-06 → re-check
lib/explain.ts confirmation, next steps, invoice checklist, fallback explanations
lib/gemini.ts server-only Gemini client (8 s time-box, JSON mode, model discovery)
lib/pdf.ts purchase order PDF per booking (jsPDF + autotable, embedded Unicode font)
lib/workbook.ts blank Excel template and the corrected workbook (exceljs)
lib/conversation/guard.ts guardrails that run before the AI
lib/conversation/ V2: state, normalisers, next-question picker, read-backs, FACTS + validator, turn engine
lib/gemini/ extraction, reply writer, R-06, mock
app/api/* r06, explain, uploads, confirm, chat, conversation
components/conversation/ Chat, Voice, summary panel, diff toast, review card
db/ Drizzle schema, migrations, seed
components/ page sections, booking card, carrier card, data tables
scripts/ stress-workbook generator and its expectations
tests/, e2e/ Vitest and Playwright
The page sits on a full-screen photo backdrop: a ship at sea, a container port and a lorry and plane at dusk. It cross-fades between them as you scroll from section to section, drifts slowly, and a plane crosses the sky now and then. The photos are small, so the backdrop uses blurred copies, and the hero shows them sharp in a tall window (full-screen on phones). Sections are translucent so the backdrop shows through. All the motion stops when the device asks for reduced motion.
The page borrows the feel of a product page: a big, tight hero headline; calm grey subheads; alternating light and dark full-width sections; a translucent sticky nav with a product sub-nav; pill buttons; large rounded cards; and scroll-reveal motion. It uses no third-party brand assets. Colour is used only for status (Red #ff3b30, Amber #ff9f0a, Green #34c759, Incomplete #8e8e93, Tips blue), with darker text variants for WCAG AA contrast.
It works from 360 px phones up, in light and dark mode, follows prefers-reduced-motion, and supports the keyboard (visible focus rings, tooltips that open on focus). The hero illustration is an original SVG.
lib/calculations.ts is the provided spec, with one fix. runFile() passed one geminiR06Verdicts map, keyed by item index, to every booking. A file-level AI verdict for item #0 of one booking would therefore also mark item #0 of every other booking as restricted. The new geminiR06VerdictsByBooking option scopes verdicts to their booking. A test covers it in tests/calculations.test.ts.
Edge-case fixes since then, each with a test: line values rounded to the pence; dates with a trailing time and decimal commas read correctly; Booking IDs matched ignoring case and extra spaces; "-free" and "no lithium" wording no longer flags R-06; unreadable cells explained instead of treated as blank; scientific-notation HS codes explained; parser warnings for merged cells and formulas with no saved value; CSV exports guarded against formula injection.
Estimates only — costs and delivery dates come from the fixed hackathon rate card.