Compare commits

..

1 Commits

Author SHA1 Message Date
pablodanswer
856c2debd9 add danswer api key header 2024-10-29 13:29:03 -07:00
20 changed files with 64 additions and 115 deletions

View File

@@ -34,7 +34,6 @@ from danswer.db.engine import get_session_with_tenant
from danswer.db.enums import ConnectorCredentialPairStatus
from danswer.db.models import ConnectorCredentialPair
from danswer.redis.redis_pool import get_redis_client
from danswer.utils.logger import pruning_ctx
from danswer.utils.logger import setup_logger
logger = setup_logger()
@@ -230,15 +229,10 @@ def connector_pruning_generator_task(
and compares those IDs to locally stored documents and deletes all locally stored IDs missing
from the most recently pulled document ID list"""
pruning_ctx_dict = pruning_ctx.get()
pruning_ctx_dict["cc_pair_id"] = cc_pair_id
pruning_ctx_dict["request_id"] = self.request.id
pruning_ctx.set(pruning_ctx_dict)
r = get_redis_client(tenant_id=tenant_id)
rcp = RedisConnectorPruning(cc_pair_id)
r = get_redis_client(tenant_id=tenant_id)
lock = r.lock(
DanswerRedisLocks.PRUNING_LOCK_PREFIX + f"_{rcp._id}",
timeout=CELERY_PRUNING_LOCK_TIMEOUT,

View File

@@ -81,6 +81,18 @@ def get_cc_source_full_info(
]
@router.get("/credential/{id}")
def list_credentials_by_id(
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
) -> list[CredentialSnapshot]:
credentials = fetch_credentials(db_session=db_session, user=user)
return [
CredentialSnapshot.from_credential_db_model(credential)
for credential in credentials
]
@router.delete("/admin/credential/{credential_id}")
def delete_credential_by_id_admin(
credential_id: int,

View File

@@ -1,4 +1,3 @@
import contextvars
import logging
import os
from collections.abc import MutableMapping
@@ -17,10 +16,6 @@ from shared_configs.configs import TENANT_ID_PREFIX
logging.addLevelName(logging.INFO + 5, "NOTICE")
pruning_ctx: contextvars.ContextVar[dict[str, Any]] = contextvars.ContextVar(
"pruning_ctx", default=dict()
)
class IndexAttemptSingleton:
"""Used to tell if this process is an indexing job, and if so what is the
@@ -69,19 +64,11 @@ class DanswerLoggingAdapter(logging.LoggerAdapter):
index_attempt_id = IndexAttemptSingleton.get_index_attempt_id()
cc_pair_id = IndexAttemptSingleton.get_connector_credential_pair_id()
pruning_ctx_dict = pruning_ctx.get()
if len(pruning_ctx_dict) > 0:
if "request_id" in pruning_ctx_dict:
msg = f"[Prune: {pruning_ctx_dict['request_id']}] {msg}"
if index_attempt_id is not None:
msg = f"[Index Attempt: {index_attempt_id}] {msg}"
if "cc_pair_id" in pruning_ctx_dict:
msg = f"[CC Pair: {pruning_ctx_dict['cc_pair_id']}] {msg}"
else:
if index_attempt_id is not None:
msg = f"[Index Attempt: {index_attempt_id}] {msg}"
if cc_pair_id is not None:
msg = f"[CC Pair: {cc_pair_id}] {msg}"
if cc_pair_id is not None:
msg = f"[CC Pair: {cc_pair_id}] {msg}"
# Add tenant information if it differs from default
# This will always be the case for authenticated API requests

View File

@@ -8,13 +8,8 @@ from pydantic import BaseModel
from danswer.auth.schemas import UserRole
from ee.danswer.configs.app_configs import API_KEY_HASH_ROUNDS
_DANSWER_API_KEY_HEADER_NAME = "Danswer-Authorization"
_API_KEY_HEADER_NAME = "Authorization"
# NOTE for others who are curious: In the context of a header, "X-" often refers
# to non-standard, experimental, or custom headers in HTTP or other protocols. It
# indicates that the header is not part of the official standards defined by
# organizations like the Internet Engineering Task Force (IETF).
_API_KEY_HEADER_ALTERNATIVE_NAME = "X-Danswer-Authorization"
_BEARER_PREFIX = "Bearer "
_API_KEY_PREFIX = "dn_"
_API_KEY_LEN = 192
@@ -48,9 +43,10 @@ def build_displayable_api_key(api_key: str) -> str:
def get_hashed_api_key_from_request(request: Request) -> str | None:
# Try both Authorization and Danswer-Authorization headers
raw_api_key_header = request.headers.get(
_API_KEY_HEADER_ALTERNATIVE_NAME
) or request.headers.get(_API_KEY_HEADER_NAME)
_API_KEY_HEADER_NAME
) or request.headers.get(_DANSWER_API_KEY_HEADER_NAME)
if raw_api_key_header is None:
return None

View File

@@ -7,10 +7,6 @@ from pywikibot.family import Family # type: ignore[import-untyped]
from danswer.connectors.mediawiki import family
# Disabling these tests as they are flaky and rely on external wikis that are maintained by just fan communities
NON_BUILTIN_WIKIS: Final[list[tuple[str, str]]] = [
("https://fallout.fandom.com", "falloutwiki"),
("https://harrypotter.fandom.com/wiki/", "harrypotterwiki"),
@@ -23,7 +19,6 @@ NON_BUILTIN_WIKIS: Final[list[tuple[str, str]]] = [
# TODO: Add support for more builtin family types from `pywikibot.families`.
@pytest.mark.skip(reason="Temporarily skipped")
@pytest.mark.parametrize(
"url, name, expected",
[
@@ -53,7 +48,6 @@ def test_family_class_dispatch_builtins(
assert family.family_class_dispatch(url, name) == expected
@pytest.mark.skip(reason="Temporarily skipped")
@pytest.mark.parametrize("url, name", NON_BUILTIN_WIKIS)
def test_family_class_dispatch_on_non_builtins_generates_new_class_fast(
url: str, name: str, mocker: MockFixture
@@ -64,7 +58,6 @@ def test_family_class_dispatch_on_non_builtins_generates_new_class_fast(
mock_generate_family_class.assert_called_once_with(url, name)
@pytest.mark.skip(reason="Temporarily skipped")
@pytest.mark.slow
@pytest.mark.parametrize("url, name", NON_BUILTIN_WIKIS)
def test_family_class_dispatch_on_non_builtins_generates_new_class_slow(

View File

@@ -253,9 +253,9 @@ export default function AddConnector({
// Apply advanced configuration-specific transforms.
const advancedConfiguration: any = {
pruneFreq: (pruneFreq ?? defaultPruneFreqDays) * 60 * 60 * 24,
pruneFreq: (pruneFreq || defaultPruneFreqDays) * 60 * 60 * 24,
indexingStart: convertStringToDateTime(indexingStart),
refreshFreq: (refreshFreq ?? defaultRefreshFreqMinutes) * 60,
refreshFreq: (refreshFreq || defaultRefreshFreqMinutes) * 60,
};
// Google sites-specific handling

View File

@@ -153,15 +153,13 @@ export default function SidebarWrapper<T extends object>({
/>
<div
className={`mt-4 w-full ${
size == "lg" ? "max-w-4xl" : "max-w-3xl"
} mx-auto`}
className={`mt-4 w-full ${size == "lg" ? "max-w-4xl" : "max-w-3xl"} mx-auto`}
>
{children}
</div>
</div>
</div>
<FixedLogo backgroundToggled={toggledSidebar || showDocSidebar} />
<FixedLogo />
</div>
);
}

View File

@@ -2512,7 +2512,7 @@ export function ChatPage({
)}
</div>
</div>
<FixedLogo backgroundToggled={toggledSidebar || showDocSidebar} />
<FixedLogo chat />
</div>
</div>
<DocumentSidebar

View File

@@ -16,7 +16,6 @@ import { Hoverable } from "@/components/Hoverable";
import { Popover } from "@/components/popover/Popover";
import { StarFeedback } from "@/components/icons/icons";
import { IconType } from "react-icons";
import { FiRefreshCw } from "react-icons/fi";
export function RegenerateDropdown({
options,
@@ -69,7 +68,7 @@ export function RegenerateDropdown({
py-1.5
"
>
Regenerate with
Pick a model
</p>
{options.map((option, ind) => {
const isSelected = option.value === selected;
@@ -93,7 +92,7 @@ export function RegenerateDropdown({
content={
<div onClick={() => toggleDropdownVisible(!isOpen)}>
{!alternate ? (
<Hoverable size={16} icon={FiRefreshCw as IconType} />
<Hoverable size={16} icon={StarFeedback as IconType} />
) : (
<Hoverable
size={16}

View File

@@ -299,9 +299,7 @@ export const AIMessage = ({
className={"py-5 ml-4 px-5 relative flex "}
>
<div
className={`mx-auto ${
shared ? "w-full" : "w-[90%]"
} max-w-message-max`}
className={`mx-auto ${shared ? "w-full" : "w-[90%]"} max-w-message-max`}
>
<div className={`desktop:mr-12 ${!shared && "mobile:ml-0 md:ml-8"}`}>
<div className="flex">
@@ -547,21 +545,9 @@ export const AIMessage = ({
className={`
absolute -bottom-5
z-10
invisible ${
(isHovering ||
isRegenerateHovered ||
settings?.isMobile) &&
"!visible"
}
opacity-0 ${
(isHovering ||
isRegenerateHovered ||
settings?.isMobile) &&
"!opacity-100"
}
translate-y-2 ${
(isHovering || settings?.isMobile) && "!translate-y-0"
}
invisible ${(isHovering || isRegenerateHovered || settings?.isMobile) && "!visible"}
opacity-0 ${(isHovering || isRegenerateHovered || settings?.isMobile) && "!opacity-100"}
translate-y-2 ${(isHovering || settings?.isMobile) && "!translate-y-0"}
transition-transform duration-300 ease-in-out
flex md:flex-row gap-x-0.5 bg-background-125/40 -mx-1.5 p-1.5 rounded-lg
`}
@@ -717,7 +703,9 @@ export const HumanMessage = ({
}, [isEditing]);
const handleEditSubmit = () => {
onEdit?.(editedContent);
if (editedContent.trim() !== content.trim()) {
onEdit?.(editedContent);
}
setIsEditing(false);
};
@@ -733,9 +721,7 @@ export const HumanMessage = ({
onMouseLeave={() => setIsHovered(false)}
>
<div
className={`text-user-text mx-auto ${
shared ? "w-full" : "w-[90%]"
} max-w-[790px]`}
className={`text-user-text mx-auto ${shared ? "w-full" : "w-[90%]"} max-w-[790px]`}
>
<div className="xl:ml-8">
<div className="flex flex-col mr-4">

View File

@@ -122,7 +122,7 @@ export function ChatSessionDisplay({
);
}}
>
<BasicSelectable padding="extra" fullWidth selected={isSelected}>
<BasicSelectable chat padding="extra" fullWidth selected={isSelected}>
<>
<div className="flex relative">
{isRenamingChat ? (
@@ -144,8 +144,8 @@ export function ChatSessionDisplay({
className={`absolute right-0 top-0 h-full w-8 bg-gradient-to-r from-transparent
${
isSelected
? "to-background-chat-selected"
: "group-hover:to-background-chat-hover"
? "to-background-chat-hover"
: " to-background-chat-selected group-hover:to-background-chat-hover"
} `}
/>
</p>

View File

@@ -27,6 +27,7 @@ function BackToDanswerButton() {
Back to {enterpriseSettings?.application_name || "Danswer Chat"}
</Button>
</div>
pr
</div>
);
}

View File

@@ -8,12 +8,7 @@ import Link from "next/link";
import { useContext } from "react";
import { FiSidebar } from "react-icons/fi";
export default function FixedLogo({
// Whether the sidebar is toggled or not
backgroundToggled,
}: {
backgroundToggled?: boolean;
}) {
export default function FixedLogo({ chat }: { chat?: boolean }) {
const combinedSettings = useContext(SettingsContext);
const settings = combinedSettings?.settings;
const enterpriseSettings = combinedSettings?.enterpriseSettings;
@@ -33,7 +28,7 @@ export default function FixedLogo({
<div className="w-full">
{enterpriseSettings && enterpriseSettings.application_name ? (
<div>
<HeaderTitle backgroundToggled={backgroundToggled}>
<HeaderTitle chat={chat}>
{enterpriseSettings.application_name}
</HeaderTitle>
{!NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED && (
@@ -41,9 +36,7 @@ export default function FixedLogo({
)}
</div>
) : (
<HeaderTitle backgroundToggled={backgroundToggled}>
Danswer
</HeaderTitle>
<HeaderTitle chat={chat}>Danswer</HeaderTitle>
)}
</div>
</div>

View File

@@ -81,12 +81,14 @@ export function BasicSelectable({
children,
selected,
hasBorder,
chat,
fullWidth = false,
padding = "normal",
}: {
children: string | JSX.Element;
selected: boolean;
hasBorder?: boolean;
chat?: boolean;
fullWidth?: boolean;
padding?: "none" | "normal" | "extra";
}) {
@@ -102,8 +104,12 @@ export function BasicSelectable({
${hasBorder ? "border border-border" : ""}
${
selected
? "bg-background-chat-selected"
: "hover:bg-background-chat-hover"
? chat
? "bg-background-chat-selected"
: "bg-hover"
: chat
? "bg-background-chat-hover"
: "hover:bg-hover"
}
${fullWidth ? "w-full" : ""}`}
>

View File

@@ -58,7 +58,7 @@ export function ClientLayout({
return (
<div className="h-screen overflow-y-hidden">
<div className="flex h-full">
<div className="flex-none text-text-settings-sidebar bg-background-sidebar w-[250px] z-20 pt-4 pb-8 h-full border-r border-border miniscroll overflow-auto">
<div className="flex-none text-text-settings-sidebar bg-background-settings-sidebar w-[250px] z-20 pt-4 pb-8 h-full border-r border-border miniscroll overflow-auto">
<AdminSidebar
collections={[
{

View File

@@ -55,7 +55,7 @@ export function AdminSidebar({ collections }: { collections: Collection[] }) {
<div className="flex-grow min-w-0 my-auto">
{enterpriseSettings && enterpriseSettings.application_name ? (
<div className="w-full">
<HeaderTitle backgroundToggled={true}>
<HeaderTitle>
{enterpriseSettings.application_name}
</HeaderTitle>
{!NEXT_PUBLIC_DO_NOT_USE_TOGGLE_OFF_DANSWER_POWERED && (
@@ -65,7 +65,7 @@ export function AdminSidebar({ collections }: { collections: Collection[] }) {
)}
</div>
) : (
<HeaderTitle backgroundToggled={true}>Danswer</HeaderTitle>
<HeaderTitle>Danswer</HeaderTitle>
)}
</div>
</div>
@@ -74,7 +74,7 @@ export function AdminSidebar({ collections }: { collections: Collection[] }) {
</div>
<div className="flex w-full justify-center">
<Link href={"/chat"}>
<button className="text-sm flex items-center block w-52 py-2.5 flex px-2 text-left text-text-back-button bg-background-back-button hover:bg-opacity-80 cursor-pointer rounded">
<button className="text-sm flex items-center block w-52 py-2.5 flex px-2 text-left bg-background-200 hover:bg-background-200/80 cursor-pointer rounded">
<BackIcon className="my-auto" size={18} />
<p className="ml-1 break-words line-clamp-2 ellipsis leading-none">
Back to{" "}

View File

@@ -4,10 +4,10 @@ import React from "react";
export function HeaderTitle({
children,
backgroundToggled,
chat,
}: {
children: JSX.Element | string;
backgroundToggled?: boolean;
chat?: boolean;
}) {
const isString = typeof children === "string";
const textSize = isString && children.length > 10 ? "text-xl" : "text-2xl";
@@ -15,9 +15,7 @@ export function HeaderTitle({
return (
<h1
className={`${textSize} ${
backgroundToggled
? "text-text-sidebar-toggled-header"
: "text-text-sidebar-header"
chat ? "text-text-sidebar-header" : "text-text-header"
} break-words line-clamp-2 ellipsis text-strong leading-none font-bold`}
>
{children}

View File

@@ -37,9 +37,7 @@ export default function LogoType({
return (
<div
className={`${
hideOnMobile && "mobile:hidden"
} z-[100] mb-auto shrink-0 flex items-center text-xl font-bold`}
className={`${hideOnMobile && "mobile:hidden"} z-[100] mb-auto shrink-0 flex items-center text-xl font-bold`}
>
{toggleSidebar && page == "chat" ? (
<button
@@ -57,9 +55,7 @@ export default function LogoType({
</div>
)}
<div
className={`cursor-pointer ${
showArrow ? "desktop:invisible" : "invisible"
} break-words inline-block w-fit ml-2 text-text-700 text-xl`}
className={`cursor-pointer ${showArrow ? "desktop:invisible" : "invisible"} break-words inline-block w-fit ml-2 text-text-700 text-xl`}
>
<div className="max-w-[175px]">
{enterpriseSettings && enterpriseSettings.application_name ? (
@@ -115,9 +111,9 @@ export default function LogoType({
}}
>
{!toggled && !combinedSettings?.isMobile ? (
<RightToLineIcon className="text-sidebar-toggle" />
<RightToLineIcon />
) : (
<LeftToLineIcon className="text-sidebar-toggle" />
<LeftToLineIcon />
)}
</button>
</Tooltip>

View File

@@ -851,7 +851,7 @@ export const SearchSection = ({
</div>
</div>
</div>
<FixedLogo backgroundToggled={toggledSidebar || showDocSidebar} />
<FixedLogo chat />
</>
);
};

View File

@@ -103,15 +103,10 @@ module.exports = {
// colors for sidebar in chat, search, and manage settings
"background-sidebar": "var(--background-100)",
"background-settings-sidebar": "var(--background-100)",
"background-chatbar": "var(--background-100)",
"text-sidebar": "var(--text-500)",
"toggled-background": "var(--background-400)",
"untoggled-background": "var(--background-200)",
"background-back-button": "var(--background-200)",
"text-back-button": "var(--text-800)",
// Settings
"text-sidebar-subtle": "var(--text-500)",
"icon-settings-sidebar": "var(--text-600)",
@@ -119,14 +114,9 @@ module.exports = {
"text-settings-sidebar-strong": "var(--text-900)",
"background-settings-hover": "var(--background-200)",
"background-chat-hover": "var(--background-200)",
"background-chat-selected": "var(--background-200)",
// Background for chat messages (user bubbles)
user: "var(--user-bubble)",
"background-toggle": "var(--background-100)",
// Colors for the search toggle buttons
"background-agentic-toggled": "var(--light-success)",
"background-agentic-untoggled": "var(--undo)",