Dynamic vector count on workspace settings (#567)

* Dynamic vector count on workspace settings
Add count to be workspace specific, fallback to system count
Update layout of data in settings
Update OpenAI per-token embedding price

* linting
This commit is contained in:
Timothy Carambat 2024-01-10 13:18:48 -08:00 committed by GitHub
parent 1d39b8a2ce
commit 4e2c0f04b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 45 deletions

View File

@ -6,7 +6,9 @@ import Directory from "./Directory";
import showToast from "../../../../utils/toast";
import WorkspaceDirectory from "./WorkspaceDirectory";
const COST_PER_TOKEN = 0.0004;
// OpenAI Cost per token for text-ada-embedding
// ref: https://openai.com/pricing#:~:text=%C2%A0/%201K%20tokens-,Embedding%20models,-Build%20advanced%20search
const COST_PER_TOKEN = 0.0000001; // $0.0001 / 1K tokens
export default function DocumentSettings({
workspace,

View File

@ -26,24 +26,11 @@ function castToType(key, value) {
return definitions[key].cast(value);
}
export default function WorkspaceSettings({ workspace }) {
export default function WorkspaceSettings({ active, workspace }) {
const { slug } = useParams();
const formEl = useRef(null);
const [saving, setSaving] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
const [totalVectors, setTotalVectors] = useState(null);
const [canDelete, setCanDelete] = useState(false);
useEffect(() => {
async function fetchKeys() {
const canDelete = await System.getCanDeleteWorkspaces();
setCanDelete(canDelete);
const totalVectors = await System.totalIndexes();
setTotalVectors(totalVectors);
}
fetchKeys();
}, []);
const handleUpdate = async (e) => {
setSaving(true);
@ -89,6 +76,9 @@ export default function WorkspaceSettings({ workspace }) {
<h3 className="text-white text-sm font-semibold">
Vector database identifier
</h3>
<p className="text-white text-opacity-60 text-xs font-medium py-1.5">
{" "}
</p>
<p className="text-white text-opacity-60 text-sm font-medium">
{workspace?.slug}
</p>
@ -101,13 +91,7 @@ export default function WorkspaceSettings({ workspace }) {
<p className="text-white text-opacity-60 text-xs font-medium my-[2px]">
Total number of vectors in your vector database.
</p>
{totalVectors !== null ? (
<p className="text-white text-opacity-60 text-sm font-medium">
{totalVectors}
</p>
) : (
<PreLoader size="4" />
)}
<VectorCount reload={active} workspace={workspace} />
</div>
</div>
</div>
@ -275,15 +259,7 @@ export default function WorkspaceSettings({ workspace }) {
</div>
</div>
<div className="flex items-center justify-between p-2 md:p-6 space-x-2 border-t rounded-b border-gray-600">
{canDelete && (
<button
onClick={deleteWorkspace}
type="button"
className="transition-all duration-300 border border-transparent rounded-lg whitespace-nowrap text-sm px-5 py-2.5 focus:z-10 bg-transparent text-white hover:text-white hover:bg-red-600"
>
Delete Workspace
</button>
)}
<DeleteWorkspace workspace={workspace} onClick={deleteWorkspace} />
{hasChanges && (
<button
type="submit"
@ -296,3 +272,43 @@ export default function WorkspaceSettings({ workspace }) {
</form>
);
}
function DeleteWorkspace({ workspace, onClick }) {
const [canDelete, setCanDelete] = useState(false);
useEffect(() => {
async function fetchKeys() {
const canDelete = await System.getCanDeleteWorkspaces();
setCanDelete(canDelete);
}
fetchKeys();
}, [workspace?.slug]);
if (!canDelete) return null;
return (
<button
onClick={onClick}
type="button"
className="transition-all duration-300 border border-transparent rounded-lg whitespace-nowrap text-sm px-5 py-2.5 focus:z-10 bg-transparent text-white hover:text-white hover:bg-red-600"
>
Delete Workspace
</button>
);
}
function VectorCount({ reload, workspace }) {
const [totalVectors, setTotalVectors] = useState(null);
useEffect(() => {
async function fetchVectorCount() {
const totalVectors = await System.totalIndexes(workspace.slug);
setTotalVectors(totalVectors);
}
fetchVectorCount();
}, [workspace?.slug, reload]);
if (totalVectors === null) return <PreLoader size="4" />;
return (
<p className="text-white text-opacity-60 text-sm font-medium">
{totalVectors}
</p>
);
}

View File

@ -114,7 +114,10 @@ const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => {
/>
</div>
<div className={selectedTab === "settings" ? "" : "hidden"}>
<WorkspaceSettings workspace={workspace} fileTypes={fileTypes} />
<WorkspaceSettings
active={selectedTab === "settings"} // To force reload live sub-components like VectorCount
workspace={workspace}
/>
</div>
</Suspense>
</div>

View File

@ -9,8 +9,10 @@ const System = {
.then((res) => res?.online || false)
.catch(() => false);
},
totalIndexes: async function () {
return await fetch(`${API_BASE}/system/system-vectors`, {
totalIndexes: async function (slug = null) {
const url = new URL(`${API_BASE}/system/system-vectors`);
if (!!slug) url.searchParams.append("slug", encodeURIComponent(slug));
return await fetch(url.toString(), {
headers: baseHeaders(),
})
.then((res) => {

View File

@ -42,11 +42,11 @@ function inviteEndpoints(app) {
return;
}
const { user, error } = await User.create(({
const { user, error } = await User.create({
username,
password,
role: "default",
}));
});
if (!user) {
console.error("Accepting invite:", error);
response

View File

@ -15,6 +15,7 @@ const {
makeJWT,
userFromSession,
multiUserMode,
queryParams,
} = require("../utils/http");
const {
setupDataImports,
@ -180,16 +181,23 @@ function systemEndpoints(app) {
}
});
app.get("/system/system-vectors", [validatedRequest], async (_, response) => {
try {
const VectorDb = getVectorDbClass();
const vectorCount = await VectorDb.totalVectors();
response.status(200).json({ vectorCount });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
app.get(
"/system/system-vectors",
[validatedRequest],
async (request, response) => {
try {
const query = queryParams(request);
const VectorDb = getVectorDbClass();
const vectorCount = !!query.slug
? await VectorDb.namespaceCount(query.slug)
: await VectorDb.totalVectors();
response.status(200).json({ vectorCount });
} catch (e) {
console.log(e.message, e);
response.sendStatus(500).end();
}
}
});
);
app.delete(
"/system/remove-document",