mirror of
https://github.com/danswer-ai/danswer.git
synced 2025-10-10 13:15:18 +02:00
clean up csv prompt + frontend (#3393)
* clean up csv prompt + frontend * nit * nit * detect uploading * upload
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
import copy
|
import copy
|
||||||
import io
|
|
||||||
import json
|
import json
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from collections.abc import Iterator
|
from collections.abc import Iterator
|
||||||
@@ -7,7 +6,6 @@ from typing import Any
|
|||||||
from typing import cast
|
from typing import cast
|
||||||
|
|
||||||
import litellm # type: ignore
|
import litellm # type: ignore
|
||||||
import pandas as pd
|
|
||||||
import tiktoken
|
import tiktoken
|
||||||
from langchain.prompts.base import StringPromptValue
|
from langchain.prompts.base import StringPromptValue
|
||||||
from langchain.prompts.chat import ChatPromptValue
|
from langchain.prompts.chat import ChatPromptValue
|
||||||
@@ -100,53 +98,32 @@ def litellm_exception_to_error_msg(
|
|||||||
return error_msg
|
return error_msg
|
||||||
|
|
||||||
|
|
||||||
# Processes CSV files to show the first 5 rows and max_columns (default 40) columns
|
|
||||||
def _process_csv_file(file: InMemoryChatFile, max_columns: int = 40) -> str:
|
|
||||||
df = pd.read_csv(io.StringIO(file.content.decode("utf-8")))
|
|
||||||
|
|
||||||
csv_preview = df.head().to_string(max_cols=max_columns)
|
|
||||||
|
|
||||||
file_name_section = (
|
|
||||||
f"CSV FILE NAME: {file.filename}\n"
|
|
||||||
if file.filename
|
|
||||||
else "CSV FILE (NO NAME PROVIDED):\n"
|
|
||||||
)
|
|
||||||
return f"{file_name_section}{CODE_BLOCK_PAT.format(csv_preview)}\n\n\n"
|
|
||||||
|
|
||||||
|
|
||||||
def _build_content(
|
def _build_content(
|
||||||
message: str,
|
message: str,
|
||||||
files: list[InMemoryChatFile] | None = None,
|
files: list[InMemoryChatFile] | None = None,
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Applies all non-image files."""
|
"""Applies all non-image files."""
|
||||||
text_files = (
|
if not files:
|
||||||
[file for file in files if file.file_type == ChatFileType.PLAIN_TEXT]
|
return message
|
||||||
if files
|
|
||||||
else None
|
|
||||||
)
|
|
||||||
|
|
||||||
csv_files = (
|
text_files = [
|
||||||
[file for file in files if file.file_type == ChatFileType.CSV]
|
file
|
||||||
if files
|
for file in files
|
||||||
else None
|
if file.file_type in (ChatFileType.PLAIN_TEXT, ChatFileType.CSV)
|
||||||
)
|
]
|
||||||
|
|
||||||
if not text_files and not csv_files:
|
if not text_files:
|
||||||
return message
|
return message
|
||||||
|
|
||||||
final_message_with_files = "FILES:\n\n"
|
final_message_with_files = "FILES:\n\n"
|
||||||
for file in text_files or []:
|
for file in text_files:
|
||||||
file_content = file.content.decode("utf-8")
|
file_content = file.content.decode("utf-8")
|
||||||
file_name_section = f"DOCUMENT: {file.filename}\n" if file.filename else ""
|
file_name_section = f"DOCUMENT: {file.filename}\n" if file.filename else ""
|
||||||
final_message_with_files += (
|
final_message_with_files += (
|
||||||
f"{file_name_section}{CODE_BLOCK_PAT.format(file_content.strip())}\n\n\n"
|
f"{file_name_section}{CODE_BLOCK_PAT.format(file_content.strip())}\n\n\n"
|
||||||
)
|
)
|
||||||
for file in csv_files or []:
|
|
||||||
final_message_with_files += _process_csv_file(file)
|
|
||||||
|
|
||||||
final_message_with_files += message
|
return final_message_with_files + message
|
||||||
|
|
||||||
return final_message_with_files
|
|
||||||
|
|
||||||
|
|
||||||
def build_content_with_imgs(
|
def build_content_with_imgs(
|
||||||
|
@@ -1080,10 +1080,17 @@ export function ChatPage({
|
|||||||
updateCanContinue(false, frozenSessionId);
|
updateCanContinue(false, frozenSessionId);
|
||||||
|
|
||||||
if (currentChatState() != "input") {
|
if (currentChatState() != "input") {
|
||||||
|
if (currentChatState() == "uploading") {
|
||||||
|
setPopup({
|
||||||
|
message: "Please wait for the content to upload",
|
||||||
|
type: "error",
|
||||||
|
});
|
||||||
|
} else {
|
||||||
setPopup({
|
setPopup({
|
||||||
message: "Please wait for the response to complete",
|
message: "Please wait for the response to complete",
|
||||||
type: "error",
|
type: "error",
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1558,7 +1565,7 @@ export function ChatPage({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleImageUpload = (acceptedFiles: File[]) => {
|
const handleImageUpload = async (acceptedFiles: File[]) => {
|
||||||
const [_, llmModel] = getFinalLLM(
|
const [_, llmModel] = getFinalLLM(
|
||||||
llmProviders,
|
llmProviders,
|
||||||
liveAssistant,
|
liveAssistant,
|
||||||
@@ -1598,8 +1605,9 @@ export function ChatPage({
|
|||||||
(file) => !tempFileDescriptors.some((newFile) => newFile.id === file.id)
|
(file) => !tempFileDescriptors.some((newFile) => newFile.id === file.id)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
updateChatState("uploading", currentSessionId());
|
||||||
|
|
||||||
uploadFilesForChat(acceptedFiles).then(([files, error]) => {
|
await uploadFilesForChat(acceptedFiles).then(([files, error]) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
setCurrentMessageFiles((prev) => removeTempFiles(prev));
|
setCurrentMessageFiles((prev) => removeTempFiles(prev));
|
||||||
setPopup({
|
setPopup({
|
||||||
@@ -1610,6 +1618,7 @@ export function ChatPage({
|
|||||||
setCurrentMessageFiles((prev) => [...removeTempFiles(prev), ...files]);
|
setCurrentMessageFiles((prev) => [...removeTempFiles(prev), ...files]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
updateChatState("input", currentSessionId());
|
||||||
};
|
};
|
||||||
const [showHistorySidebar, setShowHistorySidebar] = useState(false); // State to track if sidebar is open
|
const [showHistorySidebar, setShowHistorySidebar] = useState(false); // State to track if sidebar is open
|
||||||
|
|
||||||
|
@@ -1,5 +1,10 @@
|
|||||||
export type FeedbackType = "like" | "dislike";
|
export type FeedbackType = "like" | "dislike";
|
||||||
export type ChatState = "input" | "loading" | "streaming" | "toolBuilding";
|
export type ChatState =
|
||||||
|
| "input"
|
||||||
|
| "loading"
|
||||||
|
| "streaming"
|
||||||
|
| "toolBuilding"
|
||||||
|
| "uploading";
|
||||||
export interface RegenerationState {
|
export interface RegenerationState {
|
||||||
regenerating: boolean;
|
regenerating: boolean;
|
||||||
finalMessageIndex: number;
|
finalMessageIndex: number;
|
||||||
|
@@ -91,9 +91,7 @@ const CsvContent: React.FC<ContentComponentProps> = ({
|
|||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`overflow-y-hidden flex relative ${
|
className={`flex relative ${expanded ? "max-h-2/3" : "max-h-[300px]"}`}
|
||||||
expanded ? "max-h-2/3" : "max-h-[300px]"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<Table>
|
<Table>
|
||||||
<TableHeader className="sticky z-[1000] top-0">
|
<TableHeader className="sticky z-[1000] top-0">
|
||||||
@@ -108,7 +106,7 @@ const CsvContent: React.FC<ContentComponentProps> = ({
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
|
|
||||||
<TableBody className="h-[300px] overflow-y-scroll">
|
<TableBody className="h-[300px] overflow-y-hidden ">
|
||||||
{data.length > 0 ? (
|
{data.length > 0 ? (
|
||||||
data.map((row, rowIndex) => (
|
data.map((row, rowIndex) => (
|
||||||
<TableRow key={rowIndex}>
|
<TableRow key={rowIndex}>
|
||||||
|
@@ -102,9 +102,9 @@ const ExpandableContentWrapper: React.FC<ExpandableContentWrapperProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
<Card
|
<Card
|
||||||
className={`!rounded-none w-full ${
|
className={`!rounded-none p-0 relative mx-auto w-full ${
|
||||||
expanded ? "max-h-[600px]" : "max-h-[300px] h"
|
expanded ? "max-h-[600px]" : "max-h-[300px] h-full"
|
||||||
} p-0 relative overflow-x-scroll overflow-y-scroll mx-auto`}
|
} `}
|
||||||
>
|
>
|
||||||
<CardContent className="p-0">
|
<CardContent className="p-0">
|
||||||
<ContentComponent
|
<ContentComponent
|
||||||
|
Reference in New Issue
Block a user