This commit is contained in:
GH Action - Upstream Sync
2024-11-15 01:25:08 +00:00
8 changed files with 115 additions and 24 deletions

View File

@@ -316,7 +316,7 @@ class UploadFile(Resource):
for file in files:
filename = secure_filename(file.filename)
file.save(os.path.join(temp_dir, filename))
print(f"Saved file: {filename}")
zip_path = shutil.make_archive(
base_name=os.path.join(save_dir, job_name),
format="zip",
@@ -324,6 +324,26 @@ class UploadFile(Resource):
)
final_filename = os.path.basename(zip_path)
shutil.rmtree(temp_dir)
task = ingest.delay(
settings.UPLOAD_FOLDER,
[
".rst",
".md",
".pdf",
".txt",
".docx",
".csv",
".epub",
".html",
".mdx",
".json",
".xlsx",
".pptx",
],
job_name,
final_filename,
user,
)
else:
file = files[0]
final_filename = secure_filename(file.filename)
@@ -350,9 +370,10 @@ class UploadFile(Resource):
final_filename,
user,
)
except Exception as err:
return make_response(jsonify({"success": False, "error": str(err)}), 400)
except Exception as err:
print(f"Error: {err}")
return make_response(jsonify({"success": False, "error": str(err)}), 400)
return make_response(jsonify({"success": True, "task_id": task.id}), 200)
@@ -423,6 +444,11 @@ class TaskStatus(Resource):
task = celery.AsyncResult(task_id)
task_meta = task.info
print(f"Task status: {task.status}")
if not isinstance(
task_meta, (dict, list, str, int, float, bool, type(None))
):
task_meta = str(task_meta) # Convert to a string representation
except Exception as err:
return make_response(jsonify({"success": False, "error": str(err)}), 400)

View File

@@ -140,7 +140,7 @@ function Dropdown({
: option.description
}`}
</span>
{showEdit && onEdit && (
{showEdit && onEdit && option.type !== 'public' && (
<img
src={Edit}
alt="Edit"

View File

@@ -1,29 +1,30 @@
import { Fragment, useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useDispatch, useSelector } from 'react-redux';
import newChatIcon from '../assets/openNewChat.svg';
import { useNavigate } from 'react-router-dom';
import Hero from '../Hero';
import ArrowDown from '../assets/arrow-down.svg';
import newChatIcon from '../assets/openNewChat.svg';
import Send from '../assets/send.svg';
import SendDark from '../assets/send_dark.svg';
import ShareIcon from '../assets/share.svg';
import SpinnerDark from '../assets/spinner-dark.svg';
import Spinner from '../assets/spinner.svg';
import RetryIcon from '../components/RetryIcon';
import { useNavigate } from 'react-router-dom';
import Hero from '../Hero';
import { useDarkTheme, useMediaQuery } from '../hooks';
import { ShareConversationModal } from '../modals/ShareConversationModal';
import { setConversation, updateConversationId } from './conversationSlice';
import { selectConversationId } from '../preferences/preferenceSlice';
import { AppDispatch } from '../store';
import ConversationBubble from './ConversationBubble';
import { handleSendFeedback } from './conversationHandlers';
import { FEEDBACK, Query } from './conversationModels';
import ShareIcon from '../assets/share.svg';
import {
addQuery,
fetchAnswer,
selectQueries,
selectStatus,
setConversation,
updateConversationId,
updateQuery,
} from './conversationSlice';
@@ -302,14 +303,14 @@ export default function Conversation() {
)}
</div>
<div className="flex w-11/12 flex-col items-end self-center rounded-2xl bg-opacity-0 pb-1 sm:w-[62%] h-auto">
<div className="flex w-11/12 flex-col items-end self-center rounded-2xl bg-opacity-0 z-3 sm:w-[62%] h-auto">
<div className="flex w-full items-center rounded-[40px] border border-silver bg-white py-1 dark:bg-raisin-black">
<textarea
id="inputbox"
ref={inputRef}
tabIndex={1}
placeholder={t('inputPlaceholder')}
className={`inputbox-style h-16 w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-full bg-white pt-5 pb-[22px] text-base leading-tight opacity-100 focus:outline-none dark:bg-raisin-black dark:text-bright-gray`}
className={`inputbox-style w-full overflow-y-auto overflow-x-hidden whitespace-pre-wrap rounded-full bg-transparent py-5 text-base leading-tight opacity-100 focus:outline-none dark:bg-transparent dark:text-bright-gray`}
onInput={handleInput}
onKeyDown={(e) => {
if (e.key === 'Enter' && !e.shiftKey) {

View File

@@ -1,12 +1,14 @@
import 'katex/dist/katex.min.css';
import { forwardRef, useState } from 'react';
import ReactMarkdown from 'react-markdown';
import { useSelector } from 'react-redux';
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import rehypeKatex from 'rehype-katex';
import remarkGfm from 'remark-gfm';
import remarkMath from 'remark-math';
import rehypeKatex from 'rehype-katex';
import 'katex/dist/katex.min.css';
import DocsGPT3 from '../assets/cute_docsgpt3.svg';
import Dislike from '../assets/dislike.svg?react';
import Document from '../assets/document.svg';
@@ -16,13 +18,13 @@ import Sources from '../assets/sources.svg';
import Avatar from '../components/Avatar';
import CopyButton from '../components/CopyButton';
import Sidebar from '../components/Sidebar';
import SpeakButton from '../components/TextToSpeechButton';
import {
selectChunks,
selectSelectedDocs,
} from '../preferences/preferenceSlice';
import classes from './ConversationBubble.module.css';
import { FEEDBACK, MESSAGE_TYPE } from './conversationModels';
import SpeakButton from '../components/TextToSpeechButton';
const DisableSourceFE = import.meta.env.VITE_DISABLE_SOURCE_FE || false;
@@ -41,6 +43,7 @@ const ConversationBubble = forwardRef<
{ message, type, className, feedback, handleFeedback, sources, retryBtn },
ref,
) {
// const bubbleRef = useRef<HTMLDivElement | null>(null);
const chunks = useSelector(selectChunks);
const selectedDocs = useSelector(selectSelectedDocs);
const [isLikeHovered, setIsLikeHovered] = useState(false);
@@ -141,7 +144,7 @@ const ConversationBubble = forwardRef<
/>
<p className="text-base font-semibold">Sources</p>
</div>
<div className="ml-3 mr-5 max-w-[90vw] md:max-w-[70vw] lg:max-w-[50vw]">
<div className="fade-in ml-3 mr-5 max-w-[90vw] md:max-w-[70vw] lg:max-w-[50vw]">
<div className="grid grid-cols-2 gap-2 lg:grid-cols-4">
{sources?.slice(0, 3)?.map((source, index) => (
<div key={index} className="relative">
@@ -190,7 +193,7 @@ const ConversationBubble = forwardRef<
</div>
{activeTooltip === index && (
<div
className={`absolute left-1/2 z-30 max-h-48 w-40 translate-x-[-50%] translate-y-[3px] rounded-xl bg-[#FBFBFB] p-4 text-black shadow-xl dark:bg-chinese-black dark:text-chinese-silver sm:w-56`}
className={`absolute left-1/2 z-50 max-h-48 w-40 translate-x-[-50%] translate-y-[3px] rounded-xl bg-[#FBFBFB] p-4 text-black shadow-xl dark:bg-chinese-black dark:text-chinese-silver sm:w-56`}
onMouseOver={() => setActiveTooltip(index)}
onMouseOut={() => setActiveTooltip(null)}
>
@@ -231,14 +234,14 @@ const ConversationBubble = forwardRef<
<p className="text-base font-semibold">Answer</p>
</div>
<div
className={`ml-2 mr-5 flex max-w-[90vw] rounded-[28px] bg-gray-1000 py-[14px] px-7 dark:bg-gun-metal md:max-w-[70vw] lg:max-w-[50vw] ${
className={`fade-in-bubble ml-2 mr-5 flex max-w-[90vw] rounded-[28px] bg-gray-1000 py-[14px] px-7 dark:bg-gun-metal md:max-w-[70vw] lg:max-w-[50vw] ${
type === 'ERROR'
? 'relative flex-row items-center rounded-full border border-transparent bg-[#FFE7E7] p-2 py-5 text-sm font-normal text-red-3000 dark:border-red-2000 dark:text-white'
: 'flex-col rounded-3xl'
}`}
>
<ReactMarkdown
className="whitespace-pre-wrap break-normal leading-normal"
className="fade-in whitespace-pre-wrap break-normal leading-normal"
remarkPlugins={[remarkGfm, remarkMath]}
rehypePlugins={[rehypeKatex]}
components={{

View File

@@ -514,3 +514,29 @@ input:-webkit-autofill:focus {
.logs-table {
font-family: 'IBMPlexMono-Medium', system-ui;
}
.fade-in {
animation: fadeIn 0.5s ease-in-out;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
.fade-in-bubble {
opacity: 0;
transform: translateY(10px);
animation: fadeInUp 0.5s forwards;
}
@keyframes fadeInUp {
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@@ -1,6 +1,7 @@
import { ActiveState } from '../models/misc';
import Exit from '../assets/exit.svg';
import Input from '../components/Input';
import React from 'react';
function AddPrompt({
setModalState,
@@ -9,6 +10,7 @@ function AddPrompt({
setNewPromptName,
newPromptContent,
setNewPromptContent,
disableSave,
}: {
setModalState: (state: ActiveState) => void;
handleAddPrompt?: () => void;
@@ -16,6 +18,7 @@ function AddPrompt({
setNewPromptName: (name: string) => void;
newPromptContent: string;
setNewPromptContent: (content: string) => void;
disableSave: boolean;
}) {
return (
<div className="relative">
@@ -23,6 +26,8 @@ function AddPrompt({
className="absolute top-3 right-4 m-2 w-3"
onClick={() => {
setModalState('INACTIVE');
setNewPromptName('');
setNewPromptContent('');
}}
>
<img className="filter dark:invert" src={Exit} />
@@ -41,7 +46,7 @@ function AddPrompt({
className="h-10 rounded-lg"
value={newPromptName}
onChange={(e) => setNewPromptName(e.target.value)}
></Input>
/>
<div className="relative bottom-12 left-3 mt-[-3.00px]">
<span className="bg-white px-1 text-xs text-silver dark:bg-outer-space dark:text-silver">
Prompt Name
@@ -62,6 +67,8 @@ function AddPrompt({
<button
onClick={handleAddPrompt}
className="rounded-3xl bg-purple-30 px-5 py-2 text-sm text-white transition-all hover:opacity-90"
disabled={disableSave}
title={disableSave && newPromptName ? 'Name already exists' : ''}
>
Save
</button>
@@ -79,6 +86,7 @@ function EditPrompt({
editPromptContent,
setEditPromptContent,
currentPromptEdit,
disableSave,
}: {
setModalState: (state: ActiveState) => void;
handleEditPrompt?: (id: string, type: string) => void;
@@ -87,6 +95,7 @@ function EditPrompt({
editPromptContent: string;
setEditPromptContent: (content: string) => void;
currentPromptEdit: { name: string; id: string; type: string };
disableSave: boolean;
}) {
return (
<div className="relative">
@@ -140,7 +149,8 @@ function EditPrompt({
handleEditPrompt &&
handleEditPrompt(currentPromptEdit.id, currentPromptEdit.type);
}}
disabled={currentPromptEdit.type === 'public'}
disabled={currentPromptEdit.type === 'public' || disableSave}
title={disableSave && editPromptName ? 'Name already exists' : ''}
>
Save
</button>
@@ -151,6 +161,7 @@ function EditPrompt({
}
export default function PromptsModal({
existingPrompts,
modalState,
setModalState,
type,
@@ -166,6 +177,7 @@ export default function PromptsModal({
handleAddPrompt,
handleEditPrompt,
}: {
existingPrompts: { name: string; id: string; type: string }[];
modalState: ActiveState;
setModalState: (state: ActiveState) => void;
type: 'ADD' | 'EDIT';
@@ -181,6 +193,25 @@ export default function PromptsModal({
handleAddPrompt?: () => void;
handleEditPrompt?: (id: string, type: string) => void;
}) {
const [disableSave, setDisableSave] = React.useState(true);
const handlePrompNameChange = (edit: boolean, newName: string) => {
const nameExists = existingPrompts.find(
(prompt) => newName === prompt.name,
);
if (newName && !nameExists) {
setDisableSave(false);
} else {
setDisableSave(true);
}
if (edit) {
setEditPromptName(newName);
} else {
setNewPromptName(newName);
}
};
let view;
if (type === 'ADD') {
@@ -189,9 +220,10 @@ export default function PromptsModal({
setModalState={setModalState}
handleAddPrompt={handleAddPrompt}
newPromptName={newPromptName}
setNewPromptName={setNewPromptName}
setNewPromptName={handlePrompNameChange.bind(null, false)}
newPromptContent={newPromptContent}
setNewPromptContent={setNewPromptContent}
disableSave={disableSave}
/>
);
} else if (type === 'EDIT') {
@@ -200,10 +232,11 @@ export default function PromptsModal({
setModalState={setModalState}
handleEditPrompt={handleEditPrompt}
editPromptName={editPromptName}
setEditPromptName={setEditPromptName}
setEditPromptName={handlePrompNameChange.bind(null, true)}
editPromptContent={editPromptContent}
setEditPromptContent={setEditPromptContent}
currentPromptEdit={currentPromptEdit}
disableSave={disableSave}
/>
);
} else {

View File

@@ -58,7 +58,8 @@ export default function Prompts({
}
setModalState('INACTIVE');
onSelectPrompt(newPromptName, newPrompt.id, newPromptContent);
setNewPromptName(newPromptName);
setNewPromptName('');
setNewPromptContent('');
} catch (error) {
console.error(error);
}
@@ -178,6 +179,7 @@ export default function Prompts({
</div>
</div>
<PromptsModal
existingPrompts={prompts}
type={modalType}
modalState={modalState}
setModalState={setModalState}

View File

@@ -76,7 +76,7 @@ function Upload({
<div className="relative w-32 h-32 rounded-full">
<div className="absolute inset-0 rounded-full shadow-[0_0_10px_2px_rgba(0,0,0,0.3)_inset] dark:shadow-[0_0_10px_2px_rgba(0,0,0,0.3)_inset]"></div>
<div
className={`absolute inset-0 rounded-full ${progressPercent === 100 ? 'shadow-xl shadow-lime-300/50 dark:shadow-lime-300/50 bg-gradient-to-r from-white to-gray-400 dark:bg-gradient-to-br dark:from-gray-500 dark:to-gray-300' : 'shadow-[0_2px_0_#FF3D00_inset] dark:shadow-[0_2px_0_#FF3D00_inset]'}`}
className={`absolute inset-0 rounded-full ${progressPercent === 100 ? 'shadow-xl shadow-lime-300/50 dark:shadow-lime-300/50 bg-gradient-to-r from-white to-gray-400 dark:bg-gradient-to-br dark:from-gray-500 dark:to-gray-300' : 'shadow-[0_4px_0_#7D54D1] dark:shadow-[0_4px_0_#7D54D1]'}`}
style={{
animation: `${progressPercent === 100 ? 'none' : 'rotate 2s linear infinite'}`,
}}