Martechsol commited on
Commit Β·
e441398
1
Parent(s): afb4b4d
feat: pre-create named session on widget load via /api/session/init
Browse files- app/api/schemas.py +5 -0
- app/main.py +25 -1
- static/addon.html +22 -17
app/api/schemas.py
CHANGED
|
@@ -25,3 +25,8 @@ class HealthResponse(BaseModel):
|
|
| 25 |
class SessionUpdateNameRequest(BaseModel):
|
| 26 |
session_id: str
|
| 27 |
user_name: str
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
class SessionUpdateNameRequest(BaseModel):
|
| 26 |
session_id: str
|
| 27 |
user_name: str
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
class SessionInitRequest(BaseModel):
|
| 31 |
+
session_id: str
|
| 32 |
+
user_name: str | None = Field(default=None, description="User name to associate with the session at creation time")
|
app/main.py
CHANGED
|
@@ -6,7 +6,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
| 6 |
from fastapi.staticfiles import StaticFiles
|
| 7 |
import os
|
| 8 |
|
| 9 |
-
from app.api.schemas import ChatRequest, ChatResponse, HealthResponse, SessionUpdateNameRequest
|
| 10 |
from app.core.config import get_settings
|
| 11 |
from app.services.embeddings import EmbeddingService
|
| 12 |
from app.services.llm import LLMService
|
|
@@ -193,6 +193,30 @@ async def update_session_user_name(payload: SessionUpdateNameRequest):
|
|
| 193 |
return {"status": "ok", "new_session_id": new_id}
|
| 194 |
|
| 195 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 196 |
@fastapi_app.get("/api/session/history/{session_id}")
|
| 197 |
async def get_session_history(session_id: str):
|
| 198 |
"""Returns the chat history for a session formatted for the frontend."""
|
|
|
|
| 6 |
from fastapi.staticfiles import StaticFiles
|
| 7 |
import os
|
| 8 |
|
| 9 |
+
from app.api.schemas import ChatRequest, ChatResponse, HealthResponse, SessionUpdateNameRequest, SessionInitRequest
|
| 10 |
from app.core.config import get_settings
|
| 11 |
from app.services.embeddings import EmbeddingService
|
| 12 |
from app.services.llm import LLMService
|
|
|
|
| 193 |
return {"status": "ok", "new_session_id": new_id}
|
| 194 |
|
| 195 |
|
| 196 |
+
@fastapi_app.post("/api/session/init")
|
| 197 |
+
async def init_session(payload: SessionInitRequest):
|
| 198 |
+
"""
|
| 199 |
+
Pre-creates a session on widget load β before the user opens the chat.
|
| 200 |
+
If user_name is provided the session is immediately renamed to the canonical
|
| 201 |
+
named session (merging any existing temp session). The caller should store
|
| 202 |
+
the returned session_id in localStorage so subsequent requests use the same ID.
|
| 203 |
+
"""
|
| 204 |
+
import re
|
| 205 |
+
|
| 206 |
+
# Ensure the temp session file exists first
|
| 207 |
+
await _ss.ensure_session(payload.session_id)
|
| 208 |
+
|
| 209 |
+
if payload.user_name and payload.user_name.strip():
|
| 210 |
+
# Immediately promote to named session
|
| 211 |
+
clean_name = re.sub(r'[^\w\s-]', '', payload.user_name).strip().replace(' ', '_')
|
| 212 |
+
new_id = await _ss.rename_session(payload.session_id, payload.user_name)
|
| 213 |
+
logger.info("session/init: pre-created named session '%s' for user '%s'", new_id, payload.user_name)
|
| 214 |
+
return {"status": "ok", "session_id": new_id}
|
| 215 |
+
else:
|
| 216 |
+
logger.info("session/init: pre-created temp session '%s' (name unknown yet)", payload.session_id)
|
| 217 |
+
return {"status": "ok", "session_id": payload.session_id}
|
| 218 |
+
|
| 219 |
+
|
| 220 |
@fastapi_app.get("/api/session/history/{session_id}")
|
| 221 |
async def get_session_history(session_id: str):
|
| 222 |
"""Returns the chat history for a session formatted for the frontend."""
|
static/addon.html
CHANGED
|
@@ -425,20 +425,23 @@
|
|
| 425 |
localStorage.setItem('martech_last_user_name', userName);
|
| 426 |
}
|
| 427 |
|
| 428 |
-
//
|
| 429 |
-
//
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
}
|
|
|
|
|
|
|
|
|
|
| 442 |
}
|
| 443 |
|
| 444 |
// Now fetch history using the finalized session ID
|
|
@@ -457,6 +460,7 @@
|
|
| 457 |
} catch (e) {}
|
| 458 |
|
| 459 |
// If name still not found, set up continuous lightweight background resolution
|
|
|
|
| 460 |
if (!userName) {
|
| 461 |
let _isResolving = false;
|
| 462 |
|
|
@@ -469,13 +473,14 @@
|
|
| 469 |
if (resolved) {
|
| 470 |
localStorage.setItem('martech_last_user_name', resolved);
|
| 471 |
try {
|
| 472 |
-
|
|
|
|
| 473 |
method: 'POST',
|
| 474 |
headers: { 'Content-Type': 'application/json' },
|
| 475 |
body: JSON.stringify({ session_id: sessionId, user_name: resolved })
|
| 476 |
}).then(r => r.json());
|
| 477 |
-
if (rData.
|
| 478 |
-
sessionId = rData.
|
| 479 |
localStorage.setItem('martech_session_id', sessionId);
|
| 480 |
}
|
| 481 |
} catch (e) {}
|
|
|
|
| 425 |
localStorage.setItem('martech_last_user_name', userName);
|
| 426 |
}
|
| 427 |
|
| 428 |
+
// ββ PRE-CREATE SESSION AT BACKEND ON WIDGET LOAD ββββββββββββββββββββ
|
| 429 |
+
// This creates the session with the user's name BEFORE the user even
|
| 430 |
+
// opens the chat window, so it is immediately visible in the admin panel.
|
| 431 |
+
try {
|
| 432 |
+
const initData = await fetch(BASE_URL + "/api/session/init", {
|
| 433 |
+
method: 'POST',
|
| 434 |
+
headers: { 'Content-Type': 'application/json' },
|
| 435 |
+
body: JSON.stringify({ session_id: sessionId, user_name: userName || null })
|
| 436 |
+
}).then(r => r.json());
|
| 437 |
+
// Backend may return a canonical named session_id (e.g. "Ali_Hassan")
|
| 438 |
+
if (initData.session_id && initData.session_id !== sessionId) {
|
| 439 |
+
sessionId = initData.session_id;
|
| 440 |
+
localStorage.setItem('martech_session_id', sessionId);
|
| 441 |
+
}
|
| 442 |
+
} catch (e) {
|
| 443 |
+
// Non-fatal: session will still be created on first message if this fails
|
| 444 |
+
console.warn('Martech: background session pre-creation failed', e);
|
| 445 |
}
|
| 446 |
|
| 447 |
// Now fetch history using the finalized session ID
|
|
|
|
| 460 |
} catch (e) {}
|
| 461 |
|
| 462 |
// If name still not found, set up continuous lightweight background resolution
|
| 463 |
+
// so the session gets named as soon as auth is available
|
| 464 |
if (!userName) {
|
| 465 |
let _isResolving = false;
|
| 466 |
|
|
|
|
| 473 |
if (resolved) {
|
| 474 |
localStorage.setItem('martech_last_user_name', resolved);
|
| 475 |
try {
|
| 476 |
+
// Re-init with the now-known name to promote temp β named session
|
| 477 |
+
const rData = await fetch(BASE_URL + "/api/session/init", {
|
| 478 |
method: 'POST',
|
| 479 |
headers: { 'Content-Type': 'application/json' },
|
| 480 |
body: JSON.stringify({ session_id: sessionId, user_name: resolved })
|
| 481 |
}).then(r => r.json());
|
| 482 |
+
if (rData.session_id && rData.session_id !== sessionId) {
|
| 483 |
+
sessionId = rData.session_id;
|
| 484 |
localStorage.setItem('martech_session_id', sessionId);
|
| 485 |
}
|
| 486 |
} catch (e) {}
|