Skip to content
Snippets Groups Projects
Commit fc0431fc authored by timothycarambat's avatar timothycarambat
Browse files

add endpoint saftey to prevent server dying in production

parent abdaf4e6
No related branches found
No related tags found
No related merge requests found
......@@ -16,8 +16,9 @@ export default function DefaultChatContainer() {
const MESSAGES = [
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -33,8 +34,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -49,8 +51,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -76,8 +79,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-end ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-end ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-slate-200 dark:bg-amber-800 rounded-b-2xl rounded-tl-2xl rounded-tr-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -89,8 +93,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -117,8 +122,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-end ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-end ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-slate-200 dark:bg-amber-800 rounded-b-2xl rounded-tl-2xl rounded-tr-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -131,8 +137,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -161,8 +168,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-end ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-end ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-slate-200 dark:bg-amber-800 rounded-b-2xl rounded-tl-2xl rounded-tr-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......@@ -174,8 +182,9 @@ export default function DefaultChatContainer() {
<React.Fragment>
<div
className={`flex w-full mt-2 justify-start ${popMsg ? "chat__message" : ""
}`}
className={`flex w-full mt-2 justify-start ${
popMsg ? "chat__message" : ""
}`}
>
<div className="p-4 max-w-[75%] bg-orange-100 dark:bg-stone-700 rounded-b-2xl rounded-tr-2xl rounded-tl-sm">
<p className="text-slate-800 dark:text-slate-200 font-semibold">
......
......@@ -6,16 +6,21 @@ function chatEndpoints(app) {
if (!app) return;
app.post("/workspace/:slug/chat", async (request, response) => {
const { slug } = request.params;
const { message, mode = "query" } = reqBody(request);
const workspace = await Workspace.get(`slug = '${slug}'`);
if (!workspace) {
response.sendStatus(400).end();
return;
}
try {
const { slug } = request.params;
const { message, mode = "query" } = reqBody(request);
const workspace = await Workspace.get(`slug = '${slug}'`);
if (!workspace) {
response.sendStatus(400).end();
return;
}
const result = await chatWithWorkspace(workspace, message, mode);
response.status(200).json({ ...result });
const result = await chatWithWorkspace(workspace, message, mode);
response.status(200).json({ ...result });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
}
......
if (process.env.NODE_ENV === 'development') require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` });
process.env.NODE_ENV === "development"
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
: require("dotenv").config();
const { viewLocalFiles } = require("../utils/files");
const { getVectorDbClass } = require("../utils/helpers");
......@@ -10,37 +12,52 @@ function systemEndpoints(app) {
});
app.get("/setup-complete", (_, response) => {
const vectorDB = process.env.VECTOR_DB || "pinecone";
const results = {
VectorDB: vectorDB,
OpenAiKey: !!process.env.OPEN_AI_KEY,
OpenAiModelPref: process.env.OPEN_MODEL_PREF || "gpt-3.5-turbo",
...(vectorDB === "pinecone"
? {
PineConeEnvironment: process.env.PINECONE_ENVIRONMENT,
PineConeKey: !!process.env.PINECONE_API_KEY,
PineConeIndex: process.env.PINECONE_INDEX,
}
: {}),
...(vectorDB === "chroma"
? {
ChromaEndpoint: process.env.CHROMA_ENDPOINT,
}
: {}),
};
response.status(200).json({ results });
try {
const vectorDB = process.env.VECTOR_DB || "pinecone";
const results = {
VectorDB: vectorDB,
OpenAiKey: !!process.env.OPEN_AI_KEY,
OpenAiModelPref: process.env.OPEN_MODEL_PREF || "gpt-3.5-turbo",
...(vectorDB === "pinecone"
? {
PineConeEnvironment: process.env.PINECONE_ENVIRONMENT,
PineConeKey: !!process.env.PINECONE_API_KEY,
PineConeIndex: process.env.PINECONE_INDEX,
}
: {}),
...(vectorDB === "chroma"
? {
ChromaEndpoint: process.env.CHROMA_ENDPOINT,
}
: {}),
};
response.status(200).json({ results });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.get("/system-vectors", async (_, response) => {
const VectorDb = getVectorDbClass();
const vectorCount = await VectorDb.totalIndicies();
response.status(200).json({ vectorCount });
try {
const VectorDb = getVectorDbClass();
const vectorCount = await VectorDb.totalIndicies();
response.status(200).json({ vectorCount });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.get("/local-files", async (_, response) => {
const localFiles = await viewLocalFiles();
response.status(200).json({ localFiles });
try {
const localFiles = await viewLocalFiles();
response.status(200).json({ localFiles });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
}
module.exports = { systemEndpoints };
\ No newline at end of file
module.exports = { systemEndpoints };
......@@ -10,70 +10,100 @@ function workspaceEndpoints(app) {
if (!app) return;
app.post("/workspace/new", async (request, response) => {
const { name = null } = reqBody(request);
const { workspace, message } = await Workspace.new(name);
response.status(200).json({ workspace, message });
try {
const { name = null } = reqBody(request);
const { workspace, message } = await Workspace.new(name);
response.status(200).json({ workspace, message });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.post("/workspace/:slug/update-embeddings", async (request, response) => {
const { slug = null } = request.params;
const { adds = [], deletes = [] } = reqBody(request);
const currWorkspace = await Workspace.get(`slug = '${slug}'`);
try {
const { slug = null } = request.params;
const { adds = [], deletes = [] } = reqBody(request);
const currWorkspace = await Workspace.get(`slug = '${slug}'`);
if (!currWorkspace) {
response.sendStatus(400).end();
return;
}
if (!currWorkspace) {
response.sendStatus(400).end();
return;
}
await Document.removeDocuments(currWorkspace, deletes);
await Document.addDocuments(currWorkspace, adds);
const updatedWorkspace = await Workspace.get(`slug = '${slug}'`);
response.status(200).json({ workspace: updatedWorkspace });
await Document.removeDocuments(currWorkspace, deletes);
await Document.addDocuments(currWorkspace, adds);
const updatedWorkspace = await Workspace.get(`slug = '${slug}'`);
response.status(200).json({ workspace: updatedWorkspace });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.delete("/workspace/:slug", async (request, response) => {
const VectorDb = getVectorDbClass();
const { slug = "" } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
try {
const VectorDb = getVectorDbClass();
const { slug = "" } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
if (!workspace) {
response.sendStatus(400).end();
return;
}
if (!workspace) {
response.sendStatus(400).end();
return;
}
await Workspace.delete(`slug = '${slug.toLowerCase()}'`);
await DocumentVectors.deleteForWorkspace(workspace.id);
await Document.delete(`workspaceId = ${Number(workspace.id)}`);
await WorkspaceChats.delete(`workspaceId = ${Number(workspace.id)}`);
try {
await VectorDb["delete-namespace"]({ namespace: slug });
await Workspace.delete(`slug = '${slug.toLowerCase()}'`);
await DocumentVectors.deleteForWorkspace(workspace.id);
await Document.delete(`workspaceId = ${Number(workspace.id)}`);
await WorkspaceChats.delete(`workspaceId = ${Number(workspace.id)}`);
try {
await VectorDb["delete-namespace"]({ namespace: slug });
} catch (e) {
console.error(e.message);
}
response.sendStatus(200).end();
} catch (e) {
console.error(e.message);
console.log(e.message, e);
response.sendStatus(500).end();
}
response.sendStatus(200).end();
});
app.get("/workspaces", async (_, response) => {
const workspaces = await Workspace.where();
response.status(200).json({ workspaces });
try {
const workspaces = await Workspace.where();
response.status(200).json({ workspaces });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.get("/workspace/:slug", async (request, response) => {
const { slug } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
response.status(200).json({ workspace });
try {
const { slug } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
response.status(200).json({ workspace });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
app.get("/workspace/:slug/chats", async (request, response) => {
const { slug } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
if (!workspace) {
response.sendStatus(400).end();
return;
}
try {
const { slug } = request.params;
const workspace = await Workspace.get(`slug = '${slug}'`);
if (!workspace) {
response.sendStatus(400).end();
return;
}
const history = await WorkspaceChats.forWorkspace(workspace.id);
response.status(200).json({ history: convertToChatHistory(history) });
const history = await WorkspaceChats.forWorkspace(workspace.id);
response.status(200).json({ history: convertToChatHistory(history) });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
});
}
......
if (process.env.NODE_ENV === 'development') require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` });
process.env.NODE_ENV === "development"
? require("dotenv").config({ path: `.env.${process.env.NODE_ENV}` })
: require("dotenv").config();
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
......@@ -25,26 +28,31 @@ workspaceEndpoints(app);
chatEndpoints(app);
app.post("/v/:command", async (request, response) => {
const VectorDb = getVectorDbClass();
const { command } = request.params;
if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
response.status(500).json({
message: "invalid interface command",
commands: Object.getOwnPropertyNames(VectorDb),
});
return;
}
try {
const body = reqBody(request);
const resBody = await VectorDb[command](body);
response.status(200).json({ ...resBody });
const VectorDb = getVectorDbClass();
const { command } = request.params;
if (!Object.getOwnPropertyNames(VectorDb).includes(command)) {
response.status(500).json({
message: "invalid interface command",
commands: Object.getOwnPropertyNames(VectorDb),
});
return;
}
try {
const body = reqBody(request);
const resBody = await VectorDb[command](body);
response.status(200).json({ ...resBody });
} catch (e) {
// console.error(e)
console.error(JSON.stringify(e));
response.status(500).json({ error: e.message });
}
return;
} catch (e) {
// console.error(e)
console.error(JSON.stringify(e));
response.status(500).json({ error: e.message });
console.log(e.message, e);
response.sendStatus(500).end();
}
return;
});
app.all("*", function (_, response) {
......
......@@ -2,46 +2,20 @@ const { ChromaClient, OpenAIEmbeddingFunction } = require("chromadb");
const { Chroma: ChromaStore } = require("langchain/vectorstores/chroma");
const { OpenAI } = require("langchain/llms/openai");
const { ChatOpenAI } = require("langchain/chat_models/openai");
const {
VectorDBQAChain,
LLMChain,
RetrievalQAChain,
ConversationalRetrievalQAChain,
} = require("langchain/chains");
const { VectorDBQAChain } = require("langchain/chains");
const { OpenAIEmbeddings } = require("langchain/embeddings/openai");
// const { VectorStoreRetrieverMemory, BufferMemory } = require("langchain/memory");
// const { PromptTemplate } = require("langchain/prompts");
const { RecursiveCharacterTextSplitter } = require("langchain/text_splitter");
const { storeVectorResult, cachedVectorInformation } = require("../files");
const { Configuration, OpenAIApi } = require("openai");
const { v4: uuidv4 } = require("uuid");
const toChunks = (arr, size) => {
return Array.from({ length: Math.ceil(arr.length / size) }, (_v, i) =>
arr.slice(i * size, i * size + size)
);
};
function curateSources(sources = []) {
const knownDocs = [];
const documents = [];
for (const source of sources) {
const { metadata = {} } = source;
if (
Object.keys(metadata).length > 0 &&
!knownDocs.includes(metadata.title)
) {
documents.push({ ...metadata });
knownDocs.push(metadata.title);
}
}
return documents;
}
const { toChunks, curateSources } = require("../helpers");
const Chroma = {
name: 'Chroma',
name: "Chroma",
connect: async function () {
if (process.env.VECTOR_DB !== "chroma")
throw new Error("Chroma::Invalid ENV settings");
const client = new ChromaClient({
path: process.env.CHROMA_ENDPOINT, // if not set will fallback to localhost:8000
});
......@@ -356,6 +330,4 @@ const Chroma = {
},
};
module.exports = {
Chroma,
};
module.exports.Chroma = Chroma;
const { Pinecone } = require("../pinecone");
const { Chroma } = require("../chroma");
function getVectorDbClass() {
const { Pinecone } = require("../pinecone");
const { Chroma } = require("../chroma");
const vectorSelection = process.env.VECTOR_DB || "pinecone";
switch (vectorSelection) {
case "pinecone":
......@@ -9,10 +9,35 @@ function getVectorDbClass() {
case "chroma":
return Chroma;
default:
return Pinecone;
throw new Error("ENV: No VECTOR_DB value found in environment!");
}
}
function toChunks(arr, size) {
return Array.from({ length: Math.ceil(arr.length / size) }, (_v, i) =>
arr.slice(i * size, i * size + size)
);
}
function curateSources(sources = []) {
const knownDocs = [];
const documents = [];
for (const source of sources) {
const { metadata = {} } = source;
if (
Object.keys(metadata).length > 0 &&
!knownDocs.includes(metadata.title)
) {
documents.push({ ...metadata });
knownDocs.push(metadata.title);
}
}
return documents;
}
module.exports = {
getVectorDbClass,
toChunks,
curateSources,
};
......@@ -2,49 +2,22 @@ const { PineconeClient } = require("@pinecone-database/pinecone");
const { PineconeStore } = require("langchain/vectorstores/pinecone");
const { OpenAI } = require("langchain/llms/openai");
const { ChatOpenAI } = require("langchain/chat_models/openai");
const {
VectorDBQAChain,
LLMChain,
RetrievalQAChain,
ConversationalRetrievalQAChain,
} = require("langchain/chains");
const { VectorDBQAChain, LLMChain } = require("langchain/chains");
const { OpenAIEmbeddings } = require("langchain/embeddings/openai");
const {
VectorStoreRetrieverMemory,
BufferMemory,
} = require("langchain/memory");
const { VectorStoreRetrieverMemory } = require("langchain/memory");
const { PromptTemplate } = require("langchain/prompts");
const { RecursiveCharacterTextSplitter } = require("langchain/text_splitter");
const { storeVectorResult, cachedVectorInformation } = require("../files");
const { Configuration, OpenAIApi } = require("openai");
const { v4: uuidv4 } = require("uuid");
const toChunks = (arr, size) => {
return Array.from({ length: Math.ceil(arr.length / size) }, (_v, i) =>
arr.slice(i * size, i * size + size)
);
};
function curateSources(sources = []) {
const knownDocs = [];
const documents = [];
for (const source of sources) {
const { metadata = {} } = source;
if (
Object.keys(metadata).length > 0 &&
!knownDocs.includes(metadata.title)
) {
documents.push({ ...metadata });
knownDocs.push(metadata.title);
}
}
return documents;
}
const { toChunks, curateSources } = require("../helpers");
const Pinecone = {
name: 'Pinecone',
name: "Pinecone",
connect: async function () {
if (process.env.VECTOR_DB !== "pinecone")
throw new Error("Pinecone::Invalid ENV settings");
const client = new PineconeClient();
await client.init({
apiKey: process.env.PINECONE_API_KEY,
......@@ -327,6 +300,4 @@ const Pinecone = {
},
};
module.exports = {
Pinecone,
};
module.exports.Pinecone = Pinecone;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment