mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-10-04 01:40:12 +02:00
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:
parent
1d39b8a2ce
commit
4e2c0f04b4
@ -6,7 +6,9 @@ import Directory from "./Directory";
|
|||||||
import showToast from "../../../../utils/toast";
|
import showToast from "../../../../utils/toast";
|
||||||
import WorkspaceDirectory from "./WorkspaceDirectory";
|
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({
|
export default function DocumentSettings({
|
||||||
workspace,
|
workspace,
|
||||||
|
@ -26,24 +26,11 @@ function castToType(key, value) {
|
|||||||
return definitions[key].cast(value);
|
return definitions[key].cast(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function WorkspaceSettings({ workspace }) {
|
export default function WorkspaceSettings({ active, workspace }) {
|
||||||
const { slug } = useParams();
|
const { slug } = useParams();
|
||||||
const formEl = useRef(null);
|
const formEl = useRef(null);
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [hasChanges, setHasChanges] = 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) => {
|
const handleUpdate = async (e) => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
@ -89,6 +76,9 @@ export default function WorkspaceSettings({ workspace }) {
|
|||||||
<h3 className="text-white text-sm font-semibold">
|
<h3 className="text-white text-sm font-semibold">
|
||||||
Vector database identifier
|
Vector database identifier
|
||||||
</h3>
|
</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">
|
<p className="text-white text-opacity-60 text-sm font-medium">
|
||||||
{workspace?.slug}
|
{workspace?.slug}
|
||||||
</p>
|
</p>
|
||||||
@ -101,13 +91,7 @@ export default function WorkspaceSettings({ workspace }) {
|
|||||||
<p className="text-white text-opacity-60 text-xs font-medium my-[2px]">
|
<p className="text-white text-opacity-60 text-xs font-medium my-[2px]">
|
||||||
Total number of vectors in your vector database.
|
Total number of vectors in your vector database.
|
||||||
</p>
|
</p>
|
||||||
{totalVectors !== null ? (
|
<VectorCount reload={active} workspace={workspace} />
|
||||||
<p className="text-white text-opacity-60 text-sm font-medium">
|
|
||||||
{totalVectors}
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
<PreLoader size="4" />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -275,15 +259,7 @@ export default function WorkspaceSettings({ workspace }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-between p-2 md:p-6 space-x-2 border-t rounded-b border-gray-600">
|
<div className="flex items-center justify-between p-2 md:p-6 space-x-2 border-t rounded-b border-gray-600">
|
||||||
{canDelete && (
|
<DeleteWorkspace workspace={workspace} onClick={deleteWorkspace} />
|
||||||
<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>
|
|
||||||
)}
|
|
||||||
{hasChanges && (
|
{hasChanges && (
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
@ -296,3 +272,43 @@ export default function WorkspaceSettings({ workspace }) {
|
|||||||
</form>
|
</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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -114,7 +114,10 @@ const ManageWorkspace = ({ hideModal = noop, providedSlug = null }) => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={selectedTab === "settings" ? "" : "hidden"}>
|
<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>
|
</div>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,8 +9,10 @@ const System = {
|
|||||||
.then((res) => res?.online || false)
|
.then((res) => res?.online || false)
|
||||||
.catch(() => false);
|
.catch(() => false);
|
||||||
},
|
},
|
||||||
totalIndexes: async function () {
|
totalIndexes: async function (slug = null) {
|
||||||
return await fetch(`${API_BASE}/system/system-vectors`, {
|
const url = new URL(`${API_BASE}/system/system-vectors`);
|
||||||
|
if (!!slug) url.searchParams.append("slug", encodeURIComponent(slug));
|
||||||
|
return await fetch(url.toString(), {
|
||||||
headers: baseHeaders(),
|
headers: baseHeaders(),
|
||||||
})
|
})
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
|
@ -42,11 +42,11 @@ function inviteEndpoints(app) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { user, error } = await User.create(({
|
const { user, error } = await User.create({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
role: "default",
|
role: "default",
|
||||||
}));
|
});
|
||||||
if (!user) {
|
if (!user) {
|
||||||
console.error("Accepting invite:", error);
|
console.error("Accepting invite:", error);
|
||||||
response
|
response
|
||||||
|
@ -15,6 +15,7 @@ const {
|
|||||||
makeJWT,
|
makeJWT,
|
||||||
userFromSession,
|
userFromSession,
|
||||||
multiUserMode,
|
multiUserMode,
|
||||||
|
queryParams,
|
||||||
} = require("../utils/http");
|
} = require("../utils/http");
|
||||||
const {
|
const {
|
||||||
setupDataImports,
|
setupDataImports,
|
||||||
@ -180,16 +181,23 @@ function systemEndpoints(app) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get("/system/system-vectors", [validatedRequest], async (_, response) => {
|
app.get(
|
||||||
|
"/system/system-vectors",
|
||||||
|
[validatedRequest],
|
||||||
|
async (request, response) => {
|
||||||
try {
|
try {
|
||||||
|
const query = queryParams(request);
|
||||||
const VectorDb = getVectorDbClass();
|
const VectorDb = getVectorDbClass();
|
||||||
const vectorCount = await VectorDb.totalVectors();
|
const vectorCount = !!query.slug
|
||||||
|
? await VectorDb.namespaceCount(query.slug)
|
||||||
|
: await VectorDb.totalVectors();
|
||||||
response.status(200).json({ vectorCount });
|
response.status(200).json({ vectorCount });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e.message, e);
|
console.log(e.message, e);
|
||||||
response.sendStatus(500).end();
|
response.sendStatus(500).end();
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
|
|
||||||
app.delete(
|
app.delete(
|
||||||
"/system/remove-document",
|
"/system/remove-document",
|
||||||
|
Loading…
Reference in New Issue
Block a user