Date: 2026-08-21
Browser/operator-facing endpoints are separate from Flowise tool endpoints and admin endpoints:
GET /chatwoot-ai-tools.js
POST /agent-tools/translate-message
POST /agent-tools/translate-draft
Auth:
Authorization: Bearer <AGENT_UI_TOKEN>
AGENT_UI_TOKEN is intentionally separate from ADMIN_TOKEN; do not use the full admin/ops token in daily operator UI.
CORS allows CHATWOOT_BASE_URL automatically and optional extra origins from:
AGENT_UI_ALLOWED_ORIGINS
A separate Flowise chatflow was created:
name: EK Agent UI Translation
id: 47ea6bda-1be4-4c11-96f6-ea0187ea8a75
predict URL: https://botek.easyklima.com/api/v1/prediction/47ea6bda-1be4-4c11-96f6-ea0187ea8a75
Smoke test returned:
Hello, when will my order #123 arrive?
→ Witam, kiedy dotrze moje zamówienie nr 123?
Production EKSRelay should set:
FLOWISE_TRANSLATION_PREDICT_URL=https://botek.easyklima.com/api/v1/prediction/47ea6bda-1be4-4c11-96f6-ea0187ea8a75
AGENT_UI_TOKEN=<separate operator token>
EKSRelay serves:
<script src="https://eks-relay.easyklima.com/chatwoot-ai-tools.js" defer></script>
The script:
AI tłumacz panel in Chatwoot,localStorage,AI→PL buttons to detected message bubbles,Message translation:
{
"conversationId": 1604,
"messageId": "12345",
"targetLanguage": "pl",
"sourceLanguage": "auto",
"sourceText": "Hello, when will my order arrive?"
}
Draft translation:
{
"conversationId": 1604,
"targetLanguage": "de",
"draftText": "Dzień dobry, proszę podać numer zamówienia."
}
Translations are cached in EKSRelay SQLite table TranslationCache, keyed by:
sha256(sourceText.trim()) + targetLanguage
The raw source text is not stored as a lookup key. The translated text is stored so repeated operator requests do not call Flowise/OpenAI again.
The JS is ready and served by EKSRelay. To make it appear automatically in Chatwoot, use one of:
For production, prefer reverse-proxy injection or a documented minimal override instead of editing files inside the running Chatwoot container.