- added metaResponse:Bool and metaResponseSettings:String columns to workspaces table via prisma.

- added workspacMetaResponse routes and models
This commit is contained in:
sherifButt 2024-03-18 08:37:36 +00:00
parent 23fa3297cf
commit afc52c643e
9 changed files with 390 additions and 21 deletions

View File

@ -1,6 +1,6 @@
import React, { useEffect, useState } from "react";
// import TextInput from './TextInput';
import OptionSelect from "@/components/WorkspaceChat/ChatContainer/DynamicInput/OptionSelect";
import OptionSelect from "@/components/WorkspaceChat/ChatContainer/MetaInputs/OptionSelect";
import { Cursor, Keyboard } from "@phosphor-icons/react";
import PromptInput from "../PromptInput";
// import RangeSlider from './RangeSlider';
@ -9,7 +9,6 @@ import PromptInput from "../PromptInput";
// import DateTimePicker from './DateTimePicker';
// import FileUpload from './FileUpload';
// import Rating from './Rating';
// import Checkbox from './Checkbox';
const inputComponents = {
text: PromptInput,
@ -20,12 +19,11 @@ const inputComponents = {
// datetime: DateTimePicker,
// file: FileUpload,
// rating: Rating,
// checkbox: Checkbox
};
const DynamicInput = ({
const MetaInputs = ({
inputs,
isDynamicInput,
isMetaInputs,
submit,
setMessage,
workspace,
@ -48,13 +46,13 @@ const DynamicInput = ({
: inputComponents[inputs?.type] || null;
// Condition to show the dynamic input or the forced text input
const shouldShowDynamicInput =
isDynamicInput && inputs !== undefined && !isForcedTextInput;
const shouldShowMetaInputs =
isMetaInputs && inputs !== undefined && !isForcedTextInput;
return (
<div className="w-full md:px-4 fixed md:absolute bottom-10 left-0 z-10 md:z-0 flex justify-center items-center">
<div className="w-[600px]">
{shouldShowDynamicInput ? (
{shouldShowMetaInputs ? (
<InputComponent
submit={submit}
setMessage={setMessage}
@ -80,7 +78,7 @@ const DynamicInput = ({
sendCommand={sendCommand}
/>
)}
{isDynamicInput && inputs != undefined && (
{isMetaInputs && inputs != undefined && (
<div className="w-full absolute -bottom-8 left-0 z-10 md:z-0 flex justify-center items-center">
<button
type="button"
@ -104,4 +102,4 @@ const DynamicInput = ({
);
};
export default DynamicInput;
export default MetaInputs;

View File

@ -6,13 +6,14 @@ import { isMobile } from "react-device-detect";
import { useParams } from "react-router-dom";
import { SidebarMobileHeader } from "../../Sidebar";
import ChatHistory from "./ChatHistory";
import DynamicInput from "./DynamicInput";
import PromptInput from "./PromptInput";
import MetaInputs from "./MetaInputs";
export default function ChatContainer({
workspace,
knownHistory = [],
isDynamicInput,
isMetaInputs,
currentInputMeta,
setCurrentInputMeta,
}) {
@ -108,7 +109,7 @@ export default function ChatContainer({
);
}
if (isDynamicInput) {
if (isMetaInputs) {
const { remainingText, metaData } = extractMetaData(
_chatHistory[_chatHistory.length - 1].content
);
@ -130,14 +131,14 @@ export default function ChatContainer({
{isMobile && <SidebarMobileHeader />}
<div className="flex flex-col h-full w-full md:mt-0 mt-[40px]">
<ChatHistory
history={isDynamicInput ? finalizedChatHistory : chatHistory}
history={isMetaInputs ? finalizedChatHistory : chatHistory}
workspace={workspace}
sendCommand={sendCommand}
/>
{isDynamicInput && currentInputMeta?.inputs?.type !== undefined ? (
<DynamicInput
{isMetaInputs && currentInputMeta?.inputs?.type !== undefined ? (
<MetaInputs
inputs={currentInputMeta?.inputs}
isDynamicInput={isDynamicInput}
isMetaInputs={isMetaInputs}
submit={handleSubmit}
setMessage={setMessage}
workspace={workspace}

View File

@ -13,7 +13,7 @@ export default function WorkspaceChat({ loading, workspace }) {
const [loadingHistory, setLoadingHistory] = useState(true);
const [currentInputMeta, setCurrentInputMeta] = useState(null);
const isDynamicInput = true;
const isMetaInputs = true;
useEffect(() => {
async function getHistory() {
@ -29,7 +29,7 @@ export default function WorkspaceChat({ loading, workspace }) {
// TODO: add conditional if dynamic input is enabled in the workspace by default is false
// Append metadata to the chat history
if (isDynamicInput) {
if (isMetaInputs) {
chatHistory = chatHistory.map((message) => {
if (message.role === "assistant") {
const { remainingText, metaData } = extractMetaData(
@ -85,7 +85,7 @@ export default function WorkspaceChat({ loading, workspace }) {
<ChatContainer
workspace={workspace}
knownHistory={history}
isDynamicInput={isDynamicInput}
isMetaInputs={isMetaInputs}
currentInputMeta={currentInputMeta}
setCurrentInputMeta={setCurrentInputMeta}
/>

View File

@ -0,0 +1,294 @@
const { multiUserMode, userFromSession } = require("../utils/http");
const { validatedRequest } = require("../utils/middleware/validatedRequest");
const { Telemetry } = require("../models/telemetry");
const {
flexUserRoleValid,
ROLES,
} = require("../utils/middleware/multiUserProtected");
const { EventLogs } = require("../models/eventLogs");
const { WorkspaceMetaResponse } = require("../models/workspaceMetaResponse");
const { validWorkspaceSlug } = require("../utils/middleware/validWorkspace");
function workspaceMetaResponse(app) {
if (!app) return;
app.patch(
"/workspace/:slug/metaResponse/toggle",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const user = await userFromSession(request, response);
const workspace = response.locals.workspace;
const metaResponse = workspace.metaResponse;
// If metaResponse settings are not found, create them
if (!workspace.metaResponse && !workspace.metaResponseSettings) {
metaResponseDefaultSettings.inputs.config.systemPrompt.openAiPrompt =
workspace.openAiPrompt || "";
await WorkspaceMetaResponse.update(
workspace.id,
JSON.stringify(metaResponseDefaultSettings)
);
await Telemetry.sendTelemetry(
"workspace_meta_response_enabled",
{
multiUserMode: multiUserMode(response),
LLMSelection: process.env.LLM_PROVIDER || "openai",
Embedder: process.env.EMBEDDING_ENGINE || "inherit",
VectorDbSelection: process.env.VECTOR_DB || "pinecone",
},
user?.id
);
await EventLogs.logEvent(
"workspace_meta_response_enabled",
{
workspaceName: workspace?.name || "Unknown Workspace",
},
user?.id
);
}
await WorkspaceMetaResponse.toggleMetaResponse(workspace.id, !metaResponse);
response.sendStatus(200).end();
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.get(
"/workspace/:slug/metaResponse/status",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
response.status(200).json({ status: workspace.metaResponse });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.get(
"/workspace/:slug/metaResponse/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const settings = JSON.parse(workspace.metaResponseSettings);
if (!settings) {
response.status(200).json(metaResponseDefaultSettings);
return;
}
response.status(200).json(settings);
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.patch(
"/workspace/:slug/metaResponse/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const data = request.body;
const result = await WorkspaceMetaResponse.update(workspace.id, JSON.stringify(data));
response.status(200).json(JSON.parse(result.metaResponseSettings));
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.get(
"/workspace/:slug/metaResponse/inputs/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const settings = JSON.parse(workspace.metaResponseSettings);
response.status(200).json(settings.inputs);
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.patch(
"/workspace/:slug/metaResponse/inputs/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const data = request.body;
const settings = JSON.parse(workspace.metaResponseSettings);
settings.inputs = data;
const result = await WorkspaceMetaResponse.update(
workspace.id,
JSON.stringify(settings)
);
response.status(200).json(JSON.parse(result.metaResponseSettings).inputs);
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.patch(
"/workspace/:slug/metaResponse/inputs/toggle",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const settings = JSON.parse(workspace.metaResponseSettings);
settings.inputs.isEnabled = !settings.inputs.isEnabled;
const result = await WorkspaceMetaResponse.update(
workspace.id,
JSON.stringify(settings)
);
response.sendStatus(200).end();
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.get(
"/workspace/:slug/metaResponse/sentiments/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const settings = JSON.parse(workspace.metaResponseSettings);
response.status(200).json(settings.sentiments);
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.patch(
"/workspace/:slug/metaResponse/sentiments/settings",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const data = request.body;
const settings = JSON.parse(workspace.metaResponseSettings);
settings.sentiments = data;
const result = await WorkspaceMetaResponse.update(
workspace.id,
JSON.stringify(settings)
);
response.status(200).json(JSON.parse(result.metaResponseSettings).sentiments);
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
app.patch(
"/workspace/:slug/metaResponse/sentiments/toggle",
[validatedRequest, flexUserRoleValid([ROLES.all]), validWorkspaceSlug],
async (request, response) => {
try {
const workspace = response.locals.workspace;
const settings = JSON.parse(workspace.metaResponseSettings);
settings.sentiments.isEnabled = !settings.sentiments.isEnabled;
const result = await WorkspaceMetaResponse.update(
workspace.id,
JSON.stringify(settings)
);
response.sendStatus(200).end();
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
);
}
const metaResponseDefaultSettings = {
inputs: {
isEnabled: false,
config: {
systemPrompt: {
isEnabled: false,
content: "",
openAiPrompt: "",
overrideSystemPrompt: false,
suggestionsList: [
{
title: "",
content: "",
},
],
canEdit: ["admin", "manager"],
},
promptSchema: {
content: "",
suggestionsList: [
{
title: "",
content: "",
},
],
overrideWorkspacePrompt: false,
canEdit: ["admin", "manager"],
},
components: {
dropDownMenu: {
isEnabled: false,
options: [],
},
optionsList: {
isEnabled: false,
options: [],
},
optionsButtons: {
isEnabled: false,
options: [],
},
multiSelectCheckboxes: {
isEnabled: false,
options: [],
},
},
},
permissions: ["user"],
},
sentiments: {
isEnabled: false,
config: {
sentimentAnalysis: {
isEnabled: false,
scoreThreshold: 0.5,
},
},
permissions: ["user"],
},
avatars: {
isEnabled: false,
config: {
avatarType: "circle",
avatarSize: "medium",
avatarName: "user",
},
permissions: ["user"],
},
};
module.exports = { workspaceMetaResponse };

View File

@ -20,6 +20,7 @@ const { developerEndpoints } = require("./endpoints/api");
const { extensionEndpoints } = require("./endpoints/extensions");
const { bootHTTP, bootSSL } = require("./utils/boot");
const { workspaceThreadEndpoints } = require("./endpoints/workspaceThreads");
const { workspaceMetaResponse } = require("./endpoints/workspaceMetaResponse");
const app = express();
const apiRouter = express.Router();
const FILE_LIMIT = "3GB";
@ -39,6 +40,7 @@ systemEndpoints(apiRouter);
extensionEndpoints(apiRouter);
workspaceEndpoints(apiRouter);
workspaceThreadEndpoints(apiRouter);
workspaceMetaResponse(apiRouter);
chatEndpoints(apiRouter);
adminEndpoints(apiRouter);
inviteEndpoints(apiRouter);

View File

@ -0,0 +1,69 @@
const prisma = require("../utils/prisma");
const WorkspaceMetaResponse = {
writable: ["name"],
update: async function (workspaceId, data) {
try {
const result = await prisma.workspaces.update({
where: {
id: workspaceId,
},
data: {
metaResponseSettings: data,
},
});
return {
metaResponseSettings: result.metaResponseSettings,
message: null
};
} catch (error) {
console.error(error.message);
return { workspace: null, message: error.message };
}
},
get: async function (clause = {}) {
try {
const thread = await prisma.workspaces.findFirst({
where: clause,
});
return thread || null;
} catch (error) {
console.error(error.message);
return null;
}
},
where: async function (clause = {}, limit = null, orderBy = null) {
try {
const results = await prisma.workspaces.findMany({
where: clause,
...(limit !== null ? { take: limit } : {}),
...(orderBy !== null ? { orderBy } : {}),
});
return results;
} catch (error) {
console.error(error.message);
return [];
}
},
toggleMetaResponse: async function (workspaceId, status) {
try {
const result = await prisma.workspaces.update({
where: { id: workspaceId },
data: {
metaResponse: status,
},
});
return { result, message: null };
} catch (error) {
console.error(error.message);
return { workspace: null, message: error.message };
}
}
};
module.exports = { WorkspaceMetaResponse };

View File

@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "workspaces" ADD COLUMN "metaResponse" BOOLEAN DEFAULT false;
ALTER TABLE "workspaces" ADD COLUMN "metaResponseSettings" TEXT;

View File

@ -100,7 +100,9 @@ model workspaces {
chatModel String?
topN Int? @default(4)
chatMode String? @default("chat")
pfpFilename String?
pfpFilename String?
metaResponse Boolean? @default(false)
metaResponseSettings String?
workspace_users workspace_users[]
documents workspace_documents[]
workspace_suggested_messages workspace_suggested_messages[]