mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2025-04-17 18:18:11 +00: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 changed files with 76 additions and 45 deletions
|
@ -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,
|
||||
|
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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) => {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Add table
Reference in a new issue