mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-04-11 21:39:31 +02:00
Update search settings + chat/search handling (#2333)
* validate web list * update search settings + chat/search handling * remove accidentally added search manager * minor build fix * push from local
This commit is contained in:
parent
2d7b312e6c
commit
2bd3833c55
@ -280,6 +280,13 @@ def delete_chat_session(
|
||||
db_session: Session,
|
||||
hard_delete: bool = HARD_DELETE_CHATS,
|
||||
) -> None:
|
||||
chat_session = get_chat_session_by_id(
|
||||
chat_session_id=chat_session_id, user_id=user_id, db_session=db_session
|
||||
)
|
||||
|
||||
if chat_session.deleted:
|
||||
raise ValueError("Cannot delete an already deleted chat session")
|
||||
|
||||
if hard_delete:
|
||||
delete_messages_and_files_from_chat_session(chat_session_id, db_session)
|
||||
db_session.execute(delete(ChatSession).where(ChatSession.id == chat_session_id))
|
||||
|
@ -269,7 +269,10 @@ def delete_chat_session_by_id(
|
||||
db_session: Session = Depends(get_session),
|
||||
) -> None:
|
||||
user_id = user.id if user is not None else None
|
||||
delete_chat_session(user_id, session_id, db_session)
|
||||
try:
|
||||
delete_chat_session(user_id, session_id, db_session)
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
|
||||
async def is_disconnected(request: Request) -> Callable[[], bool]:
|
||||
|
@ -84,7 +84,7 @@ class CloudEmbedding:
|
||||
self.client = _initialize_client(api_key, self.provider, model)
|
||||
|
||||
def _embed_openai(self, texts: list[str], model: str | None) -> list[Embedding]:
|
||||
if model is None:
|
||||
if not model:
|
||||
model = DEFAULT_OPENAI_MODEL
|
||||
|
||||
# OpenAI does not seem to provide truncation option, however
|
||||
@ -111,7 +111,7 @@ class CloudEmbedding:
|
||||
def _embed_cohere(
|
||||
self, texts: list[str], model: str | None, embedding_type: str
|
||||
) -> list[Embedding]:
|
||||
if model is None:
|
||||
if not model:
|
||||
model = DEFAULT_COHERE_MODEL
|
||||
|
||||
final_embeddings: list[Embedding] = []
|
||||
@ -130,7 +130,7 @@ class CloudEmbedding:
|
||||
def _embed_voyage(
|
||||
self, texts: list[str], model: str | None, embedding_type: str
|
||||
) -> list[Embedding]:
|
||||
if model is None:
|
||||
if not model:
|
||||
model = DEFAULT_VOYAGE_MODEL
|
||||
|
||||
# Similar to Cohere, the API server will do approximate size chunking
|
||||
@ -146,7 +146,7 @@ class CloudEmbedding:
|
||||
def _embed_vertex(
|
||||
self, texts: list[str], model: str | None, embedding_type: str
|
||||
) -> list[Embedding]:
|
||||
if model is None:
|
||||
if not model:
|
||||
model = DEFAULT_VERTEX_MODEL
|
||||
|
||||
embeddings = self.client.get_embeddings(
|
||||
@ -172,7 +172,6 @@ class CloudEmbedding:
|
||||
try:
|
||||
if self.provider == EmbeddingProvider.OPENAI:
|
||||
return self._embed_openai(texts, model_name)
|
||||
|
||||
embedding_type = EmbeddingModelTextType.get_type(self.provider, text_type)
|
||||
if self.provider == EmbeddingProvider.COHERE:
|
||||
return self._embed_cohere(texts, model_name, embedding_type)
|
||||
|
@ -95,7 +95,7 @@ export default function AddConnector({
|
||||
...configuration.values.reduce(
|
||||
(acc, field) => {
|
||||
if (field.type === "select") {
|
||||
acc[field.name] = field.default || "";
|
||||
acc[field.name] = field.options ? field.options[field.default!]! : "";
|
||||
} else if (field.type === "list") {
|
||||
acc[field.name] = field.default || [];
|
||||
} else if (field.type === "checkbox") {
|
||||
@ -339,11 +339,13 @@ export default function AddConnector({
|
||||
...configuration.values.reduce(
|
||||
(acc, field) => {
|
||||
let schema: any =
|
||||
field.type === "list"
|
||||
? Yup.array().of(Yup.string())
|
||||
: field.type === "checkbox"
|
||||
? Yup.boolean()
|
||||
: Yup.string();
|
||||
field.type === "select"
|
||||
? Yup.string()
|
||||
: field.type === "list"
|
||||
? Yup.array().of(Yup.string())
|
||||
: field.type === "checkbox"
|
||||
? Yup.boolean()
|
||||
: Yup.string();
|
||||
|
||||
if (!field.optional) {
|
||||
schema = schema.required(`${field.label} is required`);
|
||||
|
@ -24,7 +24,10 @@ export function ChangeCredentialsModal({
|
||||
useFileUpload: boolean;
|
||||
isProxy?: boolean;
|
||||
}) {
|
||||
const [apiKeyOrUrl, setApiKeyOrUrl] = useState("");
|
||||
const [apiKey, setApiKey] = useState("");
|
||||
const [apiUrl, setApiUrl] = useState("");
|
||||
const [modelName, setModelName] = useState("");
|
||||
|
||||
const [testError, setTestError] = useState<string>("");
|
||||
const [fileName, setFileName] = useState<string>("");
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
@ -52,7 +55,7 @@ export function ChangeCredentialsModal({
|
||||
let jsonContent;
|
||||
try {
|
||||
jsonContent = JSON.parse(fileContent);
|
||||
setApiKeyOrUrl(JSON.stringify(jsonContent));
|
||||
setApiKey(JSON.stringify(jsonContent));
|
||||
} catch (parseError) {
|
||||
throw new Error(
|
||||
"Failed to parse JSON file. Please ensure it's a valid JSON."
|
||||
@ -64,7 +67,7 @@ export function ChangeCredentialsModal({
|
||||
? error.message
|
||||
: "An unknown error occurred while processing the file."
|
||||
);
|
||||
setApiKeyOrUrl("");
|
||||
setApiKey("");
|
||||
clearFileInput();
|
||||
}
|
||||
}
|
||||
@ -101,16 +104,18 @@ export function ChangeCredentialsModal({
|
||||
|
||||
const handleSubmit = async () => {
|
||||
setTestError("");
|
||||
const normalizedProviderType = provider.provider_type
|
||||
.toLowerCase()
|
||||
.split(" ")[0];
|
||||
try {
|
||||
const testResponse = await fetch("/api/admin/embedding/test-embedding", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
provider_type: provider.provider_type.toLowerCase().split(" ")[0],
|
||||
[isProxy ? "api_url" : "api_key"]: apiKeyOrUrl,
|
||||
[isProxy ? "api_key" : "api_url"]: isProxy
|
||||
? provider.api_key
|
||||
: provider.api_url,
|
||||
provider_type: normalizedProviderType,
|
||||
api_key: apiKey,
|
||||
api_url: apiUrl,
|
||||
model_name: modelName,
|
||||
}),
|
||||
});
|
||||
|
||||
@ -123,8 +128,9 @@ export function ChangeCredentialsModal({
|
||||
method: "PUT",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({
|
||||
provider_type: provider.provider_type.toLowerCase().split(" ")[0],
|
||||
[isProxy ? "api_url" : "api_key"]: apiKeyOrUrl,
|
||||
provider_type: normalizedProviderType,
|
||||
api_key: apiKey,
|
||||
api_url: apiUrl,
|
||||
is_default_provider: false,
|
||||
is_configured: true,
|
||||
}),
|
||||
@ -150,25 +156,31 @@ export function ChangeCredentialsModal({
|
||||
<Modal
|
||||
width="max-w-3xl"
|
||||
icon={provider.icon}
|
||||
title={`Modify your ${provider.provider_type} ${isProxy ? "URL" : "key"}`}
|
||||
title={`Modify your ${provider.provider_type} ${isProxy ? "Configuration" : "key"}`}
|
||||
onOutsideClick={onCancel}
|
||||
>
|
||||
<>
|
||||
{isProxy && (
|
||||
<div className="mb-4">
|
||||
<Subtitle className="font-bold text-lg">
|
||||
Want to swap out your URL?
|
||||
</Subtitle>
|
||||
<a
|
||||
href={provider.apiLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline cursor-pointer mt-2 mb-4"
|
||||
>
|
||||
Visit API
|
||||
</a>
|
||||
<p className="mb-4">
|
||||
You can modify your configuration by providing a new API key
|
||||
{isProxy ? " or API URL." : "."}
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col mt-4 gap-y-2">
|
||||
<div className="mb-4 flex flex-col gap-y-2">
|
||||
<Label className="mt-2">API Key</Label>
|
||||
{useFileUpload ? (
|
||||
<>
|
||||
<Label className="mt-2">Upload JSON File</Label>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".json"
|
||||
onChange={handleFileUpload}
|
||||
className="text-lg w-full p-1"
|
||||
/>
|
||||
{fileName && <p>Uploaded file: {fileName}</p>}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<input
|
||||
className={`
|
||||
border
|
||||
@ -179,67 +191,19 @@ export function ChangeCredentialsModal({
|
||||
px-3
|
||||
bg-background-emphasis
|
||||
`}
|
||||
value={apiKeyOrUrl}
|
||||
onChange={(e: any) => setApiKeyOrUrl(e.target.value)}
|
||||
placeholder="Paste your API URL here"
|
||||
value={apiKey}
|
||||
onChange={(e: any) => setApiKey(e.target.value)}
|
||||
placeholder="Paste your API key here"
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{testError && (
|
||||
<Callout title="Error" color="red" className="mt-4">
|
||||
{testError}
|
||||
</Callout>
|
||||
)}
|
||||
{isProxy && (
|
||||
<>
|
||||
<Label className="mt-2">API URL</Label>
|
||||
|
||||
<div className="flex mt-4 justify-between">
|
||||
<Button
|
||||
color="blue"
|
||||
onClick={() => handleSubmit()}
|
||||
disabled={!apiKeyOrUrl}
|
||||
>
|
||||
Swap URL
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{deletionError && (
|
||||
<Callout title="Error" color="red" className="mt-4">
|
||||
{deletionError}
|
||||
</Callout>
|
||||
)}
|
||||
<Divider />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-4">
|
||||
<Subtitle className="font-bold text-lg">
|
||||
Want to swap out your key?
|
||||
</Subtitle>
|
||||
<a
|
||||
href={provider.apiLink}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline cursor-pointer mt-2 mb-4"
|
||||
>
|
||||
Visit API
|
||||
</a>
|
||||
|
||||
<div className="flex flex-col mt-4 gap-y-2">
|
||||
{useFileUpload ? (
|
||||
<>
|
||||
<Label>Upload JSON File</Label>
|
||||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept=".json"
|
||||
onChange={handleFileUpload}
|
||||
className="text-lg w-full p-1"
|
||||
/>
|
||||
{fileName && <p>Uploaded file: {fileName}</p>}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<input
|
||||
className={`
|
||||
<input
|
||||
className={`
|
||||
border
|
||||
border-border
|
||||
rounded
|
||||
@ -248,29 +212,62 @@ export function ChangeCredentialsModal({
|
||||
px-3
|
||||
bg-background-emphasis
|
||||
`}
|
||||
value={apiKeyOrUrl}
|
||||
onChange={(e: any) => setApiKeyOrUrl(e.target.value)}
|
||||
placeholder="Paste your API key here"
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
value={apiUrl}
|
||||
onChange={(e: any) => setApiUrl(e.target.value)}
|
||||
placeholder="Paste your API URL here"
|
||||
/>
|
||||
|
||||
{deletionError && (
|
||||
<Callout title="Error" color="red" className="mt-4">
|
||||
{deletionError}
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
<div>
|
||||
<Label className="mt-2">Test Model</Label>
|
||||
<p>
|
||||
Since you are using a liteLLM proxy, we'll need a model
|
||||
name to test the connection with.
|
||||
</p>
|
||||
</div>
|
||||
<input
|
||||
className={`
|
||||
border
|
||||
border-border
|
||||
rounded
|
||||
w-full
|
||||
py-2
|
||||
px-3
|
||||
bg-background-emphasis
|
||||
`}
|
||||
value={modelName}
|
||||
onChange={(e: any) => setModelName(e.target.value)}
|
||||
placeholder="Paste your API URL here"
|
||||
/>
|
||||
|
||||
{deletionError && (
|
||||
<Callout title="Error" color="red" className="mt-4">
|
||||
{deletionError}
|
||||
</Callout>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{testError && (
|
||||
<Callout title="Error" color="red" className="mt-4">
|
||||
<Callout title="Error" color="red" className="my-4">
|
||||
{testError}
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
<div className="flex mt-4 justify-between">
|
||||
<Button
|
||||
color="blue"
|
||||
onClick={() => handleSubmit()}
|
||||
disabled={!apiKeyOrUrl}
|
||||
>
|
||||
Swap Key
|
||||
</Button>
|
||||
</div>
|
||||
<Button
|
||||
className="mr-auto mt-4"
|
||||
color="blue"
|
||||
onClick={() => handleSubmit()}
|
||||
disabled={!apiKey}
|
||||
>
|
||||
Update Configuration
|
||||
</Button>
|
||||
|
||||
<Divider />
|
||||
|
||||
<Subtitle className="mt-4 font-bold text-lg mb-2">
|
||||
@ -281,7 +278,7 @@ export function ChangeCredentialsModal({
|
||||
embedding type!
|
||||
</Text>
|
||||
|
||||
<Button onClick={handleDelete} color="red">
|
||||
<Button className="mr-auto" onClick={handleDelete} color="red">
|
||||
Delete Configuration
|
||||
</Button>
|
||||
{deletionError && (
|
||||
|
@ -232,7 +232,7 @@ function ConnectorRow({
|
||||
}}
|
||||
>
|
||||
<TableCell className={`!pr-0 w-[${columnWidths.first}]`}>
|
||||
<p className="w-[200px] inline-block ellipsis truncate">
|
||||
<p className="w-[100px] xl:w-[200px] inline-block ellipsis truncate">
|
||||
{ccPairsIndexingStatus.name}
|
||||
</p>
|
||||
</TableCell>
|
||||
|
@ -1621,10 +1621,14 @@ export function ChatPage({
|
||||
if (response.ok) {
|
||||
setDeletingChatSession(null);
|
||||
// go back to the main page
|
||||
router.push("/chat");
|
||||
if (deletingChatSession.id === chatSessionIdRef.current) {
|
||||
router.push("/chat");
|
||||
}
|
||||
} else {
|
||||
alert("Failed to delete chat session");
|
||||
const responseJson = await response.json();
|
||||
setPopup({ message: responseJson.detail, type: "error" });
|
||||
}
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -607,8 +607,10 @@ export const SearchSection = ({
|
||||
// go back to the main page
|
||||
router.push("/search");
|
||||
} else {
|
||||
alert("Failed to delete chat session");
|
||||
const responseJson = await response.json();
|
||||
setPopup({ message: responseJson.detail, type: "error" });
|
||||
}
|
||||
router.refresh();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
@ -96,7 +96,7 @@ export const connectorConfigs: Record<
|
||||
query: "Select the web connector type:",
|
||||
label: "Scrape Method",
|
||||
name: "web_connector_type",
|
||||
optional: true,
|
||||
default: 0,
|
||||
options: [
|
||||
{ name: "recursive", value: "recursive" },
|
||||
{ name: "single", value: "single" },
|
||||
|
Loading…
x
Reference in New Issue
Block a user