Skip to content

Commit

Permalink
[FEAT] Implement model provider UI updates (#996)
Browse files Browse the repository at this point in the history
* implement new LLM preference UI

* implement new vector db preferences UI to match LLM preferences

* implement new embedding preferences UI to match LLM preferences

* normalize placeholder text for search input

* implement new transcription preferences UI to match LLM preferences

* remove uneeded css

* implement new UI for llm preference onboarding

* implement new UI for embedder preference onboarding

* implement new UI for vector db preference onboarding

* fix placeholder text

* unset onboarding

* move autocomplete field

---------

Co-authored-by: timothycarambat <[email protected]>
  • Loading branch information
shatfield4 and timothycarambat authored Apr 2, 2024
1 parent b643639 commit 1cd9e13
Show file tree
Hide file tree
Showing 10 changed files with 508 additions and 252 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default function EmbedderItem({
return (
<div
onClick={() => onClick(value)}
className={`w-full hover:bg-white/10 p-2 rounded-md hover:cursor-pointer ${
checked && "bg-white/10"
className={`w-full p-2 rounded-md hover:cursor-pointer hover:bg-white/10 ${
checked ? "bg-white/10" : ""
}`}
>
<input
Expand All @@ -28,8 +28,8 @@ export default function EmbedderItem({
className="w-10 h-10 rounded-md"
/>
<div className="flex flex-col">
<div className="text-sm font-semibold">{name}</div>
<div className="mt-1 text-xs text-white/60">{description}</div>
<div className="text-sm font-semibold text-white">{name}</div>
<div className="mt-1 text-xs text-[#D2D5DB]">{description}</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function NativeEmbeddingOptions() {
return (
<div className="w-full h-20 items-center justify-center flex">
<div className="w-full h-10 items-center flex">
<p className="text-sm font-base text-white text-opacity-60">
There is no set up required when using AnythingLLM's native embedding
engine.
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/LLMSelection/LLMItem/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ export default function LLMItem({
return (
<div
onClick={() => onClick(value)}
className={`w-full hover:bg-white/10 p-2 rounded-md hover:cursor-pointer ${
checked && "bg-white/10"
className={`w-full p-2 rounded-md hover:cursor-pointer hover:bg-white/10 ${
checked ? "bg-white/10" : ""
}`}
>
<input
Expand All @@ -28,8 +28,8 @@ export default function LLMItem({
className="w-10 h-10 rounded-md"
/>
<div className="flex flex-col">
<div className="text-sm font-semibold">{name}</div>
<div className="mt-1 text-xs text-white/60">{description}</div>
<div className="text-sm font-semibold text-white">{name}</div>
<div className="mt-1 text-xs text-[#D2D5DB]">{description}</div>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
export default function LanceDBOptions() {
return (
<div className="w-full h-10 items-center justify-center flex">
<div className="w-full h-10 items-center flex">
<p className="text-sm font-base text-white text-opacity-60">
There is no configuration needed for LanceDB.
</p>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export default function VectorDBItem({
return (
<div
onClick={() => onClick(value)}
className={`w-full hover:bg-white/10 p-2 rounded-md hover:cursor-pointer ${
className={`w-full p-2 rounded-md hover:cursor-pointer hover:bg-white/10 ${
checked ? "bg-white/10" : ""
}`}
>
Expand All @@ -28,8 +28,8 @@ export default function VectorDBItem({
className="w-10 h-10 rounded-md"
/>
<div className="flex flex-col">
<div className="text-sm font-semibold">{name}</div>
<div className="mt-1 text-xs text-white/60">{description}</div>
<div className="text-sm font-semibold text-white">{name}</div>
<div className="mt-1 text-xs text-[#D2D5DB]">{description}</div>
</div>
</div>
</div>
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -633,3 +633,32 @@ does not extend the close button beyond the viewport. */
.upload-modal-arrow {
margin-top: 25%;
}

/* Scrollbar container */
.white-scrollbar {
overflow-y: scroll;
scrollbar-width: thin;
scrollbar-color: #ffffff #18181b;
margin-right: 8px;
}

/* Webkit browsers (Chrome, Safari) */
.white-scrollbar::-webkit-scrollbar {
width: 3px;
background-color: #18181b;
}

.white-scrollbar::-webkit-scrollbar-track {
background-color: #18181b;
margin-right: 8px;
}

.white-scrollbar::-webkit-scrollbar-thumb {
background-color: #ffffff;
border-radius: 4px;
border: 2px solid #18181b;
}

.white-scrollbar::-webkit-scrollbar-thumb:hover {
background-color: #cccccc;
}
154 changes: 106 additions & 48 deletions frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useRef } from "react";
import Sidebar from "@/components/SettingsSidebar";
import { isMobile } from "react-device-detect";
import System from "@/models/system";
Expand All @@ -16,7 +16,7 @@ import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions";
import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbeddingOptions";
import OllamaEmbeddingOptions from "@/components/EmbeddingSelection/OllamaOptions";
import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem";
import { MagnifyingGlass } from "@phosphor-icons/react";
import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react";
import { useModal } from "@/hooks/useModal";
import ModalWrapper from "@/components/ModalWrapper";

Expand All @@ -29,6 +29,8 @@ export default function GeneralEmbeddingPreference() {
const [searchQuery, setSearchQuery] = useState("");
const [filteredEmbedders, setFilteredEmbedders] = useState([]);
const [selectedEmbedder, setSelectedEmbedder] = useState(null);
const [searchMenuOpen, setSearchMenuOpen] = useState(false);
const searchInputRef = useRef(null);
const { isOpen, openModal, closeModal } = useModal();

const handleSubmit = async (e) => {
Expand Down Expand Up @@ -65,10 +67,21 @@ export default function GeneralEmbeddingPreference() {
};

const updateChoice = (selection) => {
setSearchQuery("");
setSelectedEmbedder(selection);
setSearchMenuOpen(false);
setHasChanges(true);
};

const handleXButton = () => {
if (searchQuery.length > 0) {
setSearchQuery("");
if (searchInputRef.current) searchInputRef.current.value = "";
} else {
setSearchMenuOpen(!searchMenuOpen);
}
};

useEffect(() => {
async function fetchKeys() {
const _settings = await System.keys();
Expand Down Expand Up @@ -126,6 +139,10 @@ export default function GeneralEmbeddingPreference() {
setFilteredEmbedders(filtered);
}, [searchQuery, selectedEmbedder]);

const selectedEmbedderObject = EMBEDDERS.find(
(embedder) => embedder.value === selectedEmbedder
);

return (
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
<Sidebar />
Expand Down Expand Up @@ -174,55 +191,96 @@ export default function GeneralEmbeddingPreference() {
format which AnythingLLM can use to process.
</p>
</div>
<div className="text-sm font-medium text-white mt-6 mb-4">
Embedding Providers
<div className="text-base font-bold text-white mt-6 mb-4">
Embedding Provider
</div>
<div className="w-full">
<div className="w-full relative border-slate-300/20 shadow border-4 rounded-xl text-white">
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
<div className="w-full flex items-center sticky top-0">
<MagnifyingGlass
size={16}
weight="bold"
className="absolute left-4 z-30 text-white"
/>
<input
type="text"
placeholder="Search Embedding providers"
className="bg-zinc-600 z-20 pl-10 h-[38px] rounded-full w-full px-4 py-1 text-sm border-2 border-slate-300/40 outline-none focus:border-white text-white"
onChange={(e) => setSearchQuery(e.target.value)}
autoComplete="off"
onKeyDown={(e) => {
if (e.key === "Enter") e.preventDefault();
}}
/>
</div>
</div>
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll pb-4">
{filteredEmbedders.map((embedder) => {
return (
<EmbedderItem
key={embedder.name}
name={embedder.name}
value={embedder.value}
image={embedder.logo}
description={embedder.description}
checked={selectedEmbedder === embedder.value}
onClick={() => updateChoice(embedder.value)}
<div className="relative">
{searchMenuOpen && (
<div
className="fixed top-0 left-0 w-full h-full bg-black bg-opacity-70 backdrop-blur-sm z-10"
onClick={() => setSearchMenuOpen(false)}
/>
)}
{searchMenuOpen ? (
<div className="absolute top-0 left-0 w-full max-w-[640px] max-h-[310px] overflow-auto white-scrollbar min-h-[64px] bg-[#18181B] rounded-lg flex flex-col justify-between cursor-pointer border-2 border-[#46C8FF] z-20">
<div className="w-full flex flex-col gap-y-1">
<div className="flex items-center sticky top-0 border-b border-[#9CA3AF] mx-4 bg-[#18181B]">
<MagnifyingGlass
size={20}
weight="bold"
className="absolute left-4 z-30 text-white -ml-4 my-2"
/>
<input
type="text"
name="embedder-search"
autoComplete="off"
placeholder="Search all embedding providers"
className="-ml-4 my-2 bg-transparent z-20 pl-12 h-[38px] w-full px-4 py-1 text-sm outline-none focus:border-white text-white placeholder:text-white placeholder:font-medium"
onChange={(e) => setSearchQuery(e.target.value)}
ref={searchInputRef}
onKeyDown={(e) => {
if (e.key === "Enter") e.preventDefault();
}}
/>
<X
size={20}
weight="bold"
className="cursor-pointer text-white hover:text-[#9CA3AF]"
onClick={handleXButton}
/>
);
})}
</div>
<div className="flex-1 pl-4 pr-2 flex flex-col gap-y-1 overflow-y-auto white-scrollbar pb-4">
{filteredEmbedders.map((embedder) => (
<EmbedderItem
key={embedder.name}
name={embedder.name}
value={embedder.value}
image={embedder.logo}
description={embedder.description}
checked={selectedEmbedder === embedder.value}
onClick={() => updateChoice(embedder.value)}
/>
))}
</div>
</div>
</div>
</div>
<div
onChange={() => setHasChanges(true)}
className="mt-4 flex flex-col gap-y-1"
>
{selectedEmbedder &&
EMBEDDERS.find(
(embedder) => embedder.value === selectedEmbedder
)?.options}
</div>
) : (
<button
className="w-full max-w-[640px] h-[64px] bg-[#18181B] rounded-lg flex items-center p-[14px] justify-between cursor-pointer border-2 border-transparent hover:border-[#46C8FF] transition-all duration-300"
type="button"
onClick={() => setSearchMenuOpen(true)}
>
<div className="flex gap-x-4 items-center">
<img
src={selectedEmbedderObject.logo}
alt={`${selectedEmbedderObject.name} logo`}
className="w-10 h-10 rounded-md"
/>
<div className="flex flex-col text-left">
<div className="text-sm font-semibold text-white">
{selectedEmbedderObject.name}
</div>
<div className="mt-1 text-xs text-[#D2D5DB]">
{selectedEmbedderObject.description}
</div>
</div>
</div>
<CaretUpDown
size={24}
weight="bold"
className="text-white"
/>
</button>
)}
</div>
<div
onChange={() => setHasChanges(true)}
className="mt-4 flex flex-col gap-y-1"
>
{selectedEmbedder &&
EMBEDDERS.find(
(embedder) => embedder.value === selectedEmbedder
)?.options}
</div>
</div>
</form>
Expand Down
Loading

0 comments on commit 1cd9e13

Please sign in to comment.