Skip to content

Commit

Permalink
Add delete all chats option (#2515)
Browse files Browse the repository at this point in the history
* Add delete all chats option

* post rebase fixes

* final validation

* minor cleanup

* move up
  • Loading branch information
pablonyx authored Dec 17, 2024
1 parent b5d0df9 commit 2859869
Show file tree
Hide file tree
Showing 12 changed files with 301 additions and 93 deletions.
121 changes: 121 additions & 0 deletions backend/alembic/versions/35e518e0ddf4_properly_cascade.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
"""properly_cascade
Revision ID: 35e518e0ddf4
Revises: 91a0a4d62b14
Create Date: 2024-09-20 21:24:04.891018
"""
from alembic import op


# revision identifiers, used by Alembic.
revision = "35e518e0ddf4"
down_revision = "91a0a4d62b14"
branch_labels = None
depends_on = None


def upgrade() -> None:
# Update chat_message foreign key constraint
op.drop_constraint(
"chat_message_chat_session_id_fkey", "chat_message", type_="foreignkey"
)
op.create_foreign_key(
"chat_message_chat_session_id_fkey",
"chat_message",
"chat_session",
["chat_session_id"],
["id"],
ondelete="CASCADE",
)

# Update chat_message__search_doc foreign key constraints
op.drop_constraint(
"chat_message__search_doc_chat_message_id_fkey",
"chat_message__search_doc",
type_="foreignkey",
)
op.drop_constraint(
"chat_message__search_doc_search_doc_id_fkey",
"chat_message__search_doc",
type_="foreignkey",
)

op.create_foreign_key(
"chat_message__search_doc_chat_message_id_fkey",
"chat_message__search_doc",
"chat_message",
["chat_message_id"],
["id"],
ondelete="CASCADE",
)
op.create_foreign_key(
"chat_message__search_doc_search_doc_id_fkey",
"chat_message__search_doc",
"search_doc",
["search_doc_id"],
["id"],
ondelete="CASCADE",
)

# Add CASCADE delete for tool_call foreign key
op.drop_constraint("tool_call_message_id_fkey", "tool_call", type_="foreignkey")
op.create_foreign_key(
"tool_call_message_id_fkey",
"tool_call",
"chat_message",
["message_id"],
["id"],
ondelete="CASCADE",
)


def downgrade() -> None:
# Revert chat_message foreign key constraint
op.drop_constraint(
"chat_message_chat_session_id_fkey", "chat_message", type_="foreignkey"
)
op.create_foreign_key(
"chat_message_chat_session_id_fkey",
"chat_message",
"chat_session",
["chat_session_id"],
["id"],
)

# Revert chat_message__search_doc foreign key constraints
op.drop_constraint(
"chat_message__search_doc_chat_message_id_fkey",
"chat_message__search_doc",
type_="foreignkey",
)
op.drop_constraint(
"chat_message__search_doc_search_doc_id_fkey",
"chat_message__search_doc",
type_="foreignkey",
)

op.create_foreign_key(
"chat_message__search_doc_chat_message_id_fkey",
"chat_message__search_doc",
"chat_message",
["chat_message_id"],
["id"],
)
op.create_foreign_key(
"chat_message__search_doc_search_doc_id_fkey",
"chat_message__search_doc",
"search_doc",
["search_doc_id"],
["id"],
)

# Revert tool_call foreign key constraint
op.drop_constraint("tool_call_message_id_fkey", "tool_call", type_="foreignkey")
op.create_foreign_key(
"tool_call_message_id_fkey",
"tool_call",
"chat_message",
["message_id"],
["id"],
)
17 changes: 17 additions & 0 deletions backend/onyx/db/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,23 @@ def update_chat_session(
return chat_session


def delete_all_chat_sessions_for_user(
user: User | None, db_session: Session, hard_delete: bool = HARD_DELETE_CHATS
) -> None:
user_id = user.id if user is not None else None

query = db_session.query(ChatSession).filter(
ChatSession.user_id == user_id, ChatSession.onyxbot_flow.is_(False)
)

if hard_delete:
query.delete(synchronize_session=False)
else:
query.update({ChatSession.deleted: True}, synchronize_session=False)

db_session.commit()


def delete_chat_session(
user_id: UUID | None,
chat_session_id: UUID,
Expand Down
4 changes: 3 additions & 1 deletion backend/onyx/db/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1010,7 +1010,7 @@ class ChatSession(Base):
"ChatFolder", back_populates="chat_sessions"
)
messages: Mapped[list["ChatMessage"]] = relationship(
"ChatMessage", back_populates="chat_session"
"ChatMessage", back_populates="chat_session", cascade="all, delete-orphan"
)
persona: Mapped["Persona"] = relationship("Persona")

Expand Down Expand Up @@ -1078,6 +1078,8 @@ class ChatMessage(Base):
"SearchDoc",
secondary=ChatMessage__SearchDoc.__table__,
back_populates="chat_messages",
cascade="all, delete-orphan",
single_parent=True,
)

tool_call: Mapped["ToolCall"] = relationship(
Expand Down
12 changes: 12 additions & 0 deletions backend/onyx/server/query_and_chat/chat_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from onyx.db.chat import add_chats_to_session_from_slack_thread
from onyx.db.chat import create_chat_session
from onyx.db.chat import create_new_chat_message
from onyx.db.chat import delete_all_chat_sessions_for_user
from onyx.db.chat import delete_chat_session
from onyx.db.chat import duplicate_chat_session_for_user_from_slack
from onyx.db.chat import get_chat_message
Expand Down Expand Up @@ -280,6 +281,17 @@ def patch_chat_session(
return None


@router.delete("/delete-all-chat-sessions")
def delete_all_chat_sessions(
user: User | None = Depends(current_user),
db_session: Session = Depends(get_session),
) -> None:
try:
delete_all_chat_sessions_for_user(user=user, db_session=db_session)
except ValueError as e:
raise HTTPException(status_code=400, detail=str(e))


@router.delete("/delete-chat-session/{session_id}")
def delete_chat_session_by_id(
session_id: UUID,
Expand Down
5 changes: 5 additions & 0 deletions backend/onyx/server/query_and_chat/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from onyx.configs.constants import DocumentSource
from onyx.configs.constants import MessageType
from onyx.configs.constants import SearchFeedbackType
from onyx.configs.constants import SessionType
from onyx.context.search.models import BaseFilters
from onyx.context.search.models import ChunkContext
from onyx.context.search.models import RerankingDetails
Expand Down Expand Up @@ -151,6 +152,10 @@ class ChatSessionUpdateRequest(BaseModel):
sharing_status: ChatSessionSharedStatus


class DeleteAllSessionsRequest(BaseModel):
session_type: SessionType


class RenameChatSessionResponse(BaseModel):
new_name: str # This is only really useful if the name is generated

Expand Down
39 changes: 33 additions & 6 deletions web/src/app/chat/ChatPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
buildLatestMessageChain,
checkAnyAssistantHasSearch,
createChatSession,
deleteAllChatSessions,
deleteChatSession,
getCitedDocumentsFromMessage,
getHumanAndAIMessageFromMessageNumber,
Expand Down Expand Up @@ -1837,6 +1838,7 @@ export function ChatPage({

const innerSidebarElementRef = useRef<HTMLDivElement>(null);
const [settingsToggled, setSettingsToggled] = useState(false);
const [showDeleteAllModal, setShowDeleteAllModal] = useState(false);

const currentPersona = alternativeAssistant || liveAssistant;
useEffect(() => {
Expand Down Expand Up @@ -1903,11 +1905,6 @@ export function ChatPage({
const showShareModal = (chatSession: ChatSession) => {
setSharedChatSession(chatSession);
};
const [documentSelection, setDocumentSelection] = useState(false);
// const toggleDocumentSelectionAspects = () => {
// setDocumentSelection((documentSelection) => !documentSelection);
// setShowDocSidebar(false);
// };

const toggleDocumentSidebar = () => {
if (!documentSidebarToggled) {
Expand Down Expand Up @@ -1972,6 +1969,32 @@ export function ChatPage({

<ChatPopup />

{showDeleteAllModal && (
<DeleteEntityModal
entityType="All Chats"
entityName="all your chat sessions"
onClose={() => setShowDeleteAllModal(false)}
additionalDetails="This action cannot be undone. All your chat sessions will be deleted."
onSubmit={async () => {
const response = await deleteAllChatSessions("Chat");
if (response.ok) {
setShowDeleteAllModal(false);
setPopup({
message: "All your chat sessions have been deleted.",
type: "success",
});
refreshChatSessions();
router.push("/chat");
} else {
setPopup({
message: "Failed to delete all chat sessions.",
type: "error",
});
}
}}
/>
)}

{currentFeedback && (
<FeedbackModal
feedbackType={currentFeedback[0]}
Expand Down Expand Up @@ -2132,6 +2155,7 @@ export function ChatPage({
removeToggle={removeToggle}
showShareModal={showShareModal}
showDeleteModal={showDeleteModal}
showDeleteAllModal={() => setShowDeleteAllModal(true)}
/>
</div>
</div>
Expand Down Expand Up @@ -2739,6 +2763,10 @@ export function ChatPage({
removeDocs={() => {
clearSelectedDocuments();
}}
showDocs={() => {
setFiltersToggled(false);
setDocumentSidebarToggled(true);
}}
removeFilters={() => {
filterManager.setSelectedSources([]);
filterManager.setSelectedTags([]);
Expand All @@ -2751,7 +2779,6 @@ export function ChatPage({
chatState={currentSessionChatState}
stopGenerating={stopGenerating}
openModelSettings={() => setSettingsToggled(true)}
showDocs={() => setDocumentSelection(true)}
selectedDocuments={selectedDocuments}
// assistant stuff
selectedAssistant={liveAssistant}
Expand Down
15 changes: 2 additions & 13 deletions web/src/app/chat/input/ChatInputBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,7 @@ import { SettingsContext } from "@/components/settings/SettingsProvider";
import { ChatState } from "../types";
import UnconfiguredProviderText from "@/components/chat_search/UnconfiguredProviderText";
import { useAssistants } from "@/components/context/AssistantsContext";
import AnimatedToggle from "@/components/search/SearchBar";
import { Popup } from "@/components/admin/connectors/Popup";
import { AssistantsTab } from "../modal/configuration/AssistantsTab";
import { IconType } from "react-icons";
import { LlmTab } from "../modal/configuration/LlmTab";
import { XIcon } from "lucide-react";
import { FilterPills } from "./FilterPills";
import { Tag } from "@/lib/types";
import FiltersDisplay from "./FilterDisplay";

const MAX_INPUT_HEIGHT = 200;
Expand All @@ -47,7 +40,6 @@ interface ChatInputBarProps {
removeFilters: () => void;
removeDocs: () => void;
openModelSettings: () => void;
showDocs: () => void;
showConfigureAPIKey: () => void;
selectedDocuments: OnyxDocument[];
message: string;
Expand All @@ -57,6 +49,7 @@ interface ChatInputBarProps {
filterManager: FilterManager;
llmOverrideManager: LlmOverrideManager;
chatState: ChatState;
showDocs: () => void;
alternativeAssistant: Persona | null;
// assistants
selectedAssistant: Persona;
Expand All @@ -75,8 +68,8 @@ export function ChatInputBar({
removeFilters,
removeDocs,
openModelSettings,
showDocs,
showConfigureAPIKey,
showDocs,
selectedDocuments,
message,
setMessage,
Expand Down Expand Up @@ -284,10 +277,6 @@ export function ChatInputBar({
</div>
)}

{/* <div>
<SelectedFilterDisplay filterManager={filterManager} />
</div> */}

<UnconfiguredProviderText showConfigureAPIKey={showConfigureAPIKey} />

<div
Expand Down
10 changes: 10 additions & 0 deletions web/src/app/chat/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,16 @@ export async function deleteChatSession(chatSessionId: string) {
return response;
}

export async function deleteAllChatSessions(sessionType: "Chat" | "Search") {
const response = await fetch(`/api/chat/delete-all-chat-sessions`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
},
});
return response;
}

export async function* simulateLLMResponse(input: string, delay: number = 30) {
// Split the input string into tokens. This is a simple example, and in real use case, tokenization can be more complex.
// Iterate over tokens and yield them one by one
Expand Down
3 changes: 3 additions & 0 deletions web/src/app/chat/sessionSidebar/HistorySidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ interface HistorySidebarProps {
showDeleteModal?: (chatSession: ChatSession) => void;
stopGenerating?: () => void;
explicitlyUntoggle: () => void;
showDeleteAllModal?: () => void;
backgroundToggled?: boolean;
}

Expand All @@ -49,6 +50,7 @@ export const HistorySidebar = forwardRef<HTMLDivElement, HistorySidebarProps>(
stopGenerating = () => null,
showShareModal,
showDeleteModal,
showDeleteAllModal,
backgroundToggled,
},
ref: ForwardedRef<HTMLDivElement>
Expand Down Expand Up @@ -176,6 +178,7 @@ export const HistorySidebar = forwardRef<HTMLDivElement, HistorySidebarProps>(
currentChatId={currentChatId}
folders={folders}
openedFolders={openedFolders}
showDeleteAllModal={showDeleteAllModal}
/>
</div>
</>
Expand Down
Loading

0 comments on commit 2859869

Please sign in to comment.