Skip to content

Commit 94971fc

Browse files
committed
Cambios actualizados para los ultimos cambios
1 parent 98dfc02 commit 94971fc

4 files changed

Lines changed: 92 additions & 15 deletions

File tree

chatbot/public/app.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ function appendErrorCard(type) {
128128
icon = '⚠️';
129129
title = 'AI Token Quota Reached';
130130
desc = 'The OpenAI token quota for this account has been exhausted. Please contact your Zters IT administrator to top up the API credits.';
131+
} else if (type === 'auth_error') {
132+
variant = 'auth';
133+
icon = '🔑';
134+
title = 'BookStack API Token Expired';
135+
desc = 'The API token used to authenticate with the Zters knowledge base has expired or is no longer valid. Please contact your Zters IT administrator to generate a new token.';
131136
} else if (type === 'bookstack_error') {
132137
variant = 'connection';
133138
icon = '🔌';
@@ -319,9 +324,9 @@ async function handleChatRequest(message, isSystemCommand = false) {
319324
botMsgDiv.innerHTML = marked.parse(fullResponse);
320325
scrollToBottom();
321326
}
322-
else if (data.type === 'quota_error' || data.type === 'bookstack_error') {
327+
else if (data.type === 'quota_error' || data.type === 'bookstack_error' || data.type === 'auth_error') {
323328
removeStatus();
324-
botMsgDiv.remove(); // remove empty bot placeholder
329+
botMsgDiv.remove();
325330
appendErrorCard(data.type);
326331
}
327332
else if (data.type === 'error') {

chatbot/public/styles.css

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -869,6 +869,16 @@ a:hover { text-decoration: underline; }
869869
.error-card.generic .error-title { color: #f87171; }
870870
.error-card.generic .error-desc { color: #fca5a5; }
871871

872+
/* — BookStack API token expired — blue/indigo */
873+
.error-card.auth {
874+
background: rgba(99, 102, 241, 0.12);
875+
border-color: rgba(99, 102, 241, 0.35);
876+
border-left: 4px solid #6366f1;
877+
color: #a5b4fc;
878+
}
879+
.error-card.auth .error-title { color: #a5b4fc; }
880+
.error-card.auth .error-desc { color: #c7d2fe; }
881+
872882
/* Light-mode overrides for error cards */
873883
body.light-theme .error-card.quota {
874884
background: #fffbeb;
@@ -878,6 +888,14 @@ body.light-theme .error-card.quota {
878888
body.light-theme .error-card.quota .error-title { color: #92400e; }
879889
body.light-theme .error-card.quota .error-desc { color: #b45309; }
880890

891+
body.light-theme .error-card.auth {
892+
background: #eef2ff;
893+
border-color: #a5b4fc;
894+
color: #3730a3;
895+
}
896+
body.light-theme .error-card.auth .error-title { color: #3730a3; }
897+
body.light-theme .error-card.auth .error-desc { color: #4338ca; }
898+
881899
body.light-theme .error-card.connection,
882900
body.light-theme .error-card.generic {
883901
background: #fef2f2;

chatbot/server.js

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -34,31 +34,39 @@ const bookstackApi = axios.create({
3434
timeout: 7000 // 7 s — fast-fail when VPN is off
3535
});
3636

37-
// Pre-flight connectivity check — run before every chat request
38-
// Returns true if BookStack is reachable, false otherwise.
37+
// Pre-flight connectivity check — run before every chat request.
38+
// Returns { ok: true } if reachable, or { ok: false, reason: 'auth' | 'connection' }.
3939
async function checkBookStackConnectivity() {
4040
try {
4141
await bookstackApi.get('/books', { params: { count: 1 } });
42-
return true;
42+
return { ok: true };
4343
} catch (err) {
4444
const status = err.response?.status;
45-
// 403 = server is up but VPN / access is blocked
46-
// 401 = bad token (treat as unreachable — user can't get docs either)
47-
// 5xx, network codes = server down / VPN not connected
45+
46+
// 401 = API token expired or invalid (different from VPN/connection issue)
47+
if (status === 401) {
48+
console.warn('BookStack connectivity check failed — 401 Unauthorized (token expired or invalid)');
49+
return { ok: false, reason: 'auth' };
50+
}
51+
52+
// 403 = server reachable but access blocked (VPN not connected)
53+
// Network codes = server unreachable (VPN down, server offline)
54+
// 5xx = server error
4855
if (
4956
err.code === 'ECONNREFUSED' ||
5057
err.code === 'ENOTFOUND' ||
5158
err.code === 'ETIMEDOUT' ||
5259
err.code === 'ECONNRESET' ||
5360
err.code === 'ECONNABORTED' ||
54-
status === 401 || status === 403 ||
61+
status === 403 ||
5562
(status && status >= 500)
5663
) {
5764
console.warn(`BookStack connectivity check failed — code: ${err.code || status}`);
58-
return false;
65+
return { ok: false, reason: 'connection' };
5966
}
60-
// Unknown error — assume reachable so we don't block on transient issues
61-
return true;
67+
68+
// Unknown error — assume reachable to avoid blocking on transient issues
69+
return { ok: true };
6270
}
6371
}
6472

@@ -205,9 +213,10 @@ app.post('/api/chat', async (req, res) => {
205213

206214
try {
207215
// ── Pre-flight: verify BookStack is reachable before doing anything ──
208-
const bookStackOnline = await checkBookStackConnectivity();
209-
if (!bookStackOnline) {
210-
res.write(`data: ${JSON.stringify({ type: 'bookstack_error', content: 'Cannot reach BookStack' })}\n\n`);
216+
const connectivity = await checkBookStackConnectivity();
217+
if (!connectivity.ok) {
218+
const errType = connectivity.reason === 'auth' ? 'auth_error' : 'bookstack_error';
219+
res.write(`data: ${JSON.stringify({ type: errType, content: connectivity.reason })}\n\n`);
211220
res.end();
212221
return;
213222
}

faq_document.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# 🤖 Zters BookStack AI Chatbot - FAQ & Strategy Document
2+
3+
This document answers key questions regarding the deployment, security, maintenance, and future integrations of the newly developed BookStack AI Chatbot for the Zters organization.
4+
5+
---
6+
7+
### 1. Can this chat be integrated into another app (e.g., CUBE)? How do we manage its deployment?
8+
9+
**Yes, the chatbot is highly modular and built with integration in mind.** You have two primary approaches for integrating this into CUBE (or any other internal portal):
10+
11+
* **Approach A: UI Widget (Iframe/Embedded):** You can host the current Docker container centrally on an internal server. Within CUBE, you can simply embed the `localhost:3000` (or its production equivalent) using an `<iframe>` or a sliding side-panel widget that floats over the CUBE interface.
12+
* **Approach B: Headless Backend (API Integration):** CUBE's developers can build their own native chat UI inside CUBE and simply send HTTP `POST` requests directly to the Chatbot's backend (`/api/chat`). The backend will handle the RAG pipeline (retrieving BookStack context and calling OpenAI) and return the response.
13+
14+
**Deployment Management:**
15+
You should deploy the Docker container on a centralized server (e.g., AWS EC2, ECS, or an internal Linux host) alongside a Reverse Proxy like Nginx. The Docker Compose setup provided makes it easy to orchestrate. If using Approach B, you will need to configure **CORS** in `server.js` to allow the CUBE domain to interact with your API.
16+
17+
---
18+
19+
### 2. What are the security measures for this given that it uses the OpenAI API?
20+
21+
> [!IMPORTANT]
22+
> The most critical rule of AI architecture is maintaining a secure boundary between the client UI and the LLM provider.
23+
24+
* **Zero Frontend Exposure**: Your OpenAI API key and your BookStack credentials are **never** shipped to the user's browser. They exist strictly as environmental variables (`.env`) locked inside the Docker backend.
25+
* **Data Privacy**: By default, OpenAI **does not** use data submitted via their enterprise API (unlike consumer ChatGPT) to train their models. Your internal documentation remains your intellectual property.
26+
* **Current Security Gap (Action Required)**: Currently, anyone who accesses `http://your-server-ip:3000` has access to query BookStack through the bot. Before full production deployment into existing apps like CUBE, you should protect the `/api/chat` route. This is typically done by passing a Zters JWT (JSON Web Token) or SSO cookie from CUBE to verify the user is logged into the Zters network before the backend processes the request.
27+
28+
---
29+
30+
### 3. ⏰ Maintenance Reminder: The BookStack API Key
31+
32+
> [!WARNING]
33+
> Your BookStack API Key (`BOOKSTACK_TOKEN_ID` and `BOOKSTACK_TOKEN_SECRET`) has been configured to expire in exactly **1 Month**.
34+
35+
When this expires, the AI will lose the ability to fetch context and will start failing to answer queries about Zters systems.
36+
**Action item:** Open BookStack Admin configuration, generate a permanent service-account API key (or one with a longer lifespan), and update the `.env` file containing the credentials. Remember to run `docker compose restart` after changing `.env` variables!
37+
38+
---
39+
40+
### 4. What else should Developers and Managers know about this tool?
41+
42+
* **Hallucination Handling & Fallbacks**: The system has a specific "multi-query fallback" algorithm explicitly built into `server.js`. If the AI suspects the initial BookStack keyword search failed, it automatically extracts clearer noun-keywords and tries a secondary search. However, if BookStack lacks documentation on a subject, the AI is instructed to honestly say "I don't know" rather than guess.
43+
* **Stateless Architecture**: The backend remembers the last 10 messages of *the active session* passing from the browser. However, if a user refreshes their browser, the history resets. There is no database storing user chat logs.
44+
* **Operating Costs**: Generative AI via API incurs costs per token. Using GPT-4o with extensive RAG (Retrieval-Augmented Generation) uses thousands of tokens per query securely fed from your BookStack pages. Managers should monitor the OpenAI billing dashboard to ensure usage scales appropriately with internal adoption.
45+
* **Documentation formatting**: The AI extracts markdown directly from BookStack. The better your BookStack pages are formatted (with clear `H1/H2` tags, bullet points, and clean tables), the more accurate the AI's answers will be!

0 commit comments

Comments
 (0)