| const { v4: uuidv4 } = require("uuid"); |
| const { reqBody, userFromSession, multiUserMode } = require("../utils/http"); |
| const { validatedRequest } = require("../utils/middleware/validatedRequest"); |
| const { Telemetry } = require("../models/telemetry"); |
| const { streamChatWithWorkspace } = require("../utils/chats/stream"); |
| const { |
| ROLES, |
| flexUserRoleValid, |
| } = require("../utils/middleware/multiUserProtected"); |
| const { EventLogs } = require("../models/eventLogs"); |
| const { |
| validWorkspaceAndThreadSlug, |
| validWorkspaceSlug, |
| } = require("../utils/middleware/validWorkspace"); |
| const { writeResponseChunk } = require("../utils/helpers/chat/responses"); |
| const { WorkspaceThread } = require("../models/workspaceThread"); |
| const { User } = require("../models/user"); |
| const truncate = require("truncate"); |
| const { getModelTag } = require("./utils"); |
|
|
| function chatEndpoints(app) { |
| if (!app) return; |
|
|
| app.post( |
| "/workspace/:slug/stream-chat", |
| [validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug], |
| async (request, response) => { |
| try { |
| const user = await userFromSession(request, response); |
| const { message, attachments = [] } = reqBody(request); |
| const workspace = response.locals.workspace; |
|
|
| if (!message?.length) { |
| response.status(400).json({ |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: !message?.length ? "Message is empty." : null, |
| }); |
| return; |
| } |
|
|
| response.setHeader("Cache-Control", "no-cache"); |
| response.setHeader("Content-Type", "text/event-stream"); |
| response.setHeader("Access-Control-Allow-Origin", "*"); |
| response.setHeader("Connection", "keep-alive"); |
| response.flushHeaders(); |
|
|
| if (multiUserMode(response) && !(await User.canSendChat(user))) { |
| writeResponseChunk(response, { |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: `You have met your maximum 24 hour chat quota of ${user.dailyMessageLimit} chats. Try again later.`, |
| }); |
| return; |
| } |
|
|
| await streamChatWithWorkspace( |
| response, |
| workspace, |
| message, |
| workspace?.chatMode, |
| user, |
| null, |
| attachments |
| ); |
| await Telemetry.sendTelemetry("sent_chat", { |
| multiUserMode: multiUserMode(response), |
| LLMSelection: process.env.LLM_PROVIDER || "openai", |
| Embedder: process.env.EMBEDDING_ENGINE || "inherit", |
| VectorDbSelection: process.env.VECTOR_DB || "lancedb", |
| multiModal: Array.isArray(attachments) && attachments?.length !== 0, |
| TTSSelection: process.env.TTS_PROVIDER || "native", |
| LLMModel: getModelTag(), |
| }); |
|
|
| await EventLogs.logEvent( |
| "sent_chat", |
| { |
| workspaceName: workspace?.name, |
| chatModel: workspace?.chatModel || "System Default", |
| }, |
| user?.id |
| ); |
| response.end(); |
| } catch (e) { |
| console.error(e); |
| writeResponseChunk(response, { |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: e.message, |
| }); |
| response.end(); |
| } |
| } |
| ); |
|
|
| app.post( |
| "/workspace/:slug/thread/:threadSlug/stream-chat", |
| [ |
| validatedRequest, |
| flexUserRoleValid([ROLES.all]), |
| validWorkspaceAndThreadSlug, |
| ], |
| async (request, response) => { |
| try { |
| const user = await userFromSession(request, response); |
| const { message, attachments = [] } = reqBody(request); |
| const workspace = response.locals.workspace; |
| const thread = response.locals.thread; |
|
|
| if (!message?.length) { |
| response.status(400).json({ |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: !message?.length ? "Message is empty." : null, |
| }); |
| return; |
| } |
|
|
| response.setHeader("Cache-Control", "no-cache"); |
| response.setHeader("Content-Type", "text/event-stream"); |
| response.setHeader("Access-Control-Allow-Origin", "*"); |
| response.setHeader("Connection", "keep-alive"); |
| response.flushHeaders(); |
|
|
| if (multiUserMode(response) && !(await User.canSendChat(user))) { |
| writeResponseChunk(response, { |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: `You have met your maximum 24 hour chat quota of ${user.dailyMessageLimit} chats. Try again later.`, |
| }); |
| return; |
| } |
|
|
| await streamChatWithWorkspace( |
| response, |
| workspace, |
| message, |
| workspace?.chatMode, |
| user, |
| thread, |
| attachments |
| ); |
|
|
| |
| await WorkspaceThread.autoRenameThread({ |
| thread, |
| workspace, |
| user, |
| newName: truncate(message, 22), |
| onRename: (thread) => { |
| writeResponseChunk(response, { |
| action: "rename_thread", |
| thread: { |
| slug: thread.slug, |
| name: thread.name, |
| }, |
| }); |
| }, |
| }); |
|
|
| await Telemetry.sendTelemetry("sent_chat", { |
| multiUserMode: multiUserMode(response), |
| LLMSelection: process.env.LLM_PROVIDER || "openai", |
| Embedder: process.env.EMBEDDING_ENGINE || "inherit", |
| VectorDbSelection: process.env.VECTOR_DB || "lancedb", |
| multiModal: Array.isArray(attachments) && attachments?.length !== 0, |
| TTSSelection: process.env.TTS_PROVIDER || "native", |
| LLMModel: getModelTag(), |
| }); |
|
|
| await EventLogs.logEvent( |
| "sent_chat", |
| { |
| workspaceName: workspace.name, |
| thread: thread.name, |
| chatModel: workspace?.chatModel || "System Default", |
| }, |
| user?.id |
| ); |
| response.end(); |
| } catch (e) { |
| console.error(e); |
| writeResponseChunk(response, { |
| id: uuidv4(), |
| type: "abort", |
| textResponse: null, |
| sources: [], |
| close: true, |
| error: e.message, |
| }); |
| response.end(); |
| } |
| } |
| ); |
| } |
|
|
| module.exports = { chatEndpoints }; |
|
|