From 89d5e7bee5bcb4c84b53ab60e6f63b20b8b33611 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Wed, 7 May 2025 19:15:36 +0530 Subject: [PATCH 1/5] (feat:attachment) store file in endpoint layer --- application/api/user/routes.py | 10 ++-- application/worker.py | 95 ++++++++++++++-------------------- 2 files changed, 46 insertions(+), 59 deletions(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index e10082d3..606f6cd3 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -28,6 +28,8 @@ from application.extensions import api from application.tts.google_tts import GoogleTTS from application.utils import check_required_fields, validate_function_name from application.vectorstore.vector_creator import VectorCreator +from application.storage.storage_creator import StorageCreator +storage = StorageCreator.get_storage() mongo = MongoDB.get_client() db = mongo[settings.MONGO_DB_NAME] @@ -2978,14 +2980,14 @@ class StoreAttachment(Resource): attachment_id = ObjectId() original_filename = secure_filename(file.filename) relative_path = f"{settings.UPLOAD_FOLDER}/{user}/attachments/{str(attachment_id)}/{original_filename}" - - file_content = file.read() - + + metadata = storage.save_file(file, relative_path) + file_info = { "filename": original_filename, "attachment_id": str(attachment_id), "path": relative_path, - "file_content": file_content, + "metadata": metadata } task = store_attachment.delay(file_info, user) diff --git a/application/worker.py b/application/worker.py index 619993c9..2f9e97f3 100755 --- a/application/worker.py +++ b/application/worker.py @@ -445,76 +445,61 @@ def attachment_worker(self, file_info, user): filename = file_info["filename"] attachment_id = file_info["attachment_id"] relative_path = file_info["path"] - file_content = file_info["file_content"] + metadata = file_info.get("metadata", {}) try: self.update_state(state="PROGRESS", meta={"current": 10}) - storage_type = getattr(settings, "STORAGE_TYPE", "local") - storage = StorageCreator.create_storage(storage_type) + storage = StorageCreator.get_storage() + self.update_state( state="PROGRESS", meta={"current": 30, "status": "Processing content"} ) - with tempfile.NamedTemporaryFile( - suffix=os.path.splitext(filename)[1] - ) as temp_file: - temp_file.write(file_content) - temp_file.flush() - reader = SimpleDirectoryReader( - input_files=[temp_file.name], exclude_hidden=True, errors="ignore" - ) - documents = reader.load_data() + content = storage.process_file( + relative_path, + lambda local_path, **kwargs: SimpleDirectoryReader( + input_files=[local_path], exclude_hidden=True, errors="ignore" + ).load_data()[0].text + ) + + token_count = num_tokens_from_string(content) - if not documents: - logging.warning(f"No content extracted from file: {filename}") - raise ValueError(f"Failed to extract content from file: {filename}") + self.update_state( + state="PROGRESS", meta={"current": 80, "status": "Storing in database"} + ) - content = documents[0].text - token_count = num_tokens_from_string(content) + mime_type = mimetypes.guess_type(filename)[0] or "application/octet-stream" - self.update_state( - state="PROGRESS", meta={"current": 60, "status": "Saving file"} - ) - file_obj = io.BytesIO(file_content) - - metadata = storage.save_file(file_obj, relative_path) - - mime_type = mimetypes.guess_type(filename)[0] or "application/octet-stream" - - self.update_state( - state="PROGRESS", meta={"current": 80, "status": "Storing in database"} - ) - - doc_id = ObjectId(attachment_id) - attachments_collection.insert_one( - { - "_id": doc_id, - "user": user, - "path": relative_path, - "content": content, - "token_count": token_count, - "mime_type": mime_type, - "date": datetime.datetime.now(), - "metadata": metadata, - } - ) - - logging.info( - f"Stored attachment with ID: {attachment_id}", extra={"user": user} - ) - - self.update_state( - state="PROGRESS", meta={"current": 100, "status": "Complete"} - ) - - return { - "filename": filename, + doc_id = ObjectId(attachment_id) + attachments_collection.insert_one( + { + "_id": doc_id, + "user": user, "path": relative_path, + "content": content, "token_count": token_count, - "attachment_id": attachment_id, "mime_type": mime_type, + "date": datetime.datetime.now(), "metadata": metadata, } + ) + + logging.info( + f"Stored attachment with ID: {attachment_id}", extra={"user": user} + ) + + self.update_state( + state="PROGRESS", meta={"current": 100, "status": "Complete"} + ) + + return { + "filename": filename, + "path": relative_path, + "token_count": token_count, + "attachment_id": attachment_id, + "mime_type": mime_type, + "metadata": metadata, + } except Exception as e: logging.error( From ea6533db4e56ab516beb4e80e3274a41b8c9db2a Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 8 May 2025 00:11:02 +0530 Subject: [PATCH 2/5] (fix:attachment) strictly use filename --- application/api/user/routes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 606f6cd3..1ca8fc32 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -2978,7 +2978,7 @@ class StoreAttachment(Resource): try: attachment_id = ObjectId() - original_filename = secure_filename(file.filename) + original_filename = secure_filename(os.path.basename(file.filename)) relative_path = f"{settings.UPLOAD_FOLDER}/{user}/attachments/{str(attachment_id)}/{original_filename}" metadata = storage.save_file(file, relative_path) From d0a04d98014d41bdabc7348af47c24289809fd68 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Thu, 8 May 2025 00:14:42 +0530 Subject: [PATCH 3/5] (fix/lint) empty methods --- frontend/src/agents/NewAgent.tsx | 9 ++++++--- frontend/src/modals/JWTModal.tsx | 9 ++++++--- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/frontend/src/agents/NewAgent.tsx b/frontend/src/agents/NewAgent.tsx index 0a601699..475571cf 100644 --- a/frontend/src/agents/NewAgent.tsx +++ b/frontend/src/agents/NewAgent.tsx @@ -11,7 +11,10 @@ import AgentDetailsModal from '../modals/AgentDetailsModal'; import ConfirmationModal from '../modals/ConfirmationModal'; import { ActiveState, Doc, Prompt } from '../models/misc'; import { - selectSelectedAgent, selectSourceDocs, selectToken, setSelectedAgent + selectSelectedAgent, + selectSourceDocs, + selectToken, + setSelectedAgent, } from '../preferences/preferenceSlice'; import PromptsModal from '../preferences/PromptsModal'; import { UserToolType } from '../settings/types'; @@ -603,9 +606,9 @@ function AddPromptModal({ newPromptContent={newPromptContent} setNewPromptContent={setNewPromptContent} editPromptName={''} - setEditPromptName={() => {}} + setEditPromptName={() => undefined} editPromptContent={''} - setEditPromptContent={() => {}} + setEditPromptContent={() => undefined} currentPromptEdit={{ id: '', name: '', type: '' }} handleAddPrompt={handleAddPrompt} /> diff --git a/frontend/src/modals/JWTModal.tsx b/frontend/src/modals/JWTModal.tsx index 5f25b217..79f012dc 100644 --- a/frontend/src/modals/JWTModal.tsx +++ b/frontend/src/modals/JWTModal.tsx @@ -1,5 +1,4 @@ import React, { useState } from 'react'; -import { useDispatch } from 'react-redux'; import Input from '../components/Input'; import { ActiveState } from '../models/misc'; @@ -19,13 +18,17 @@ export default function JWTModal({ if (modalState !== 'ACTIVE') return null; return ( - {}}> + undefined} + >
Add JWT Token
-
+
Date: Thu, 8 May 2025 00:15:28 +0530 Subject: [PATCH 4/5] lint --- frontend/src/About.tsx | 12 +- frontend/src/Hero.tsx | 19 +-- frontend/src/PageNotFound.tsx | 2 +- frontend/src/agents/index.tsx | 1 - frontend/src/components/Accordion.tsx | 4 +- .../src/components/DocumentPagination.tsx | 30 ++-- frontend/src/components/DropdownMenu.tsx | 2 +- frontend/src/components/Help.tsx | 10 +- frontend/src/components/MermaidRenderer.tsx | 131 ++++++++-------- frontend/src/components/ShareButton.tsx | 2 +- frontend/src/components/Sidebar.tsx | 2 +- frontend/src/components/SkeletonLoader.tsx | 108 +++++++------- frontend/src/components/SourcesPopup.tsx | 104 +++++++------ frontend/src/components/ToggleSwitch.tsx | 6 +- frontend/src/components/ToolsPopup.tsx | 65 ++++---- .../src/conversation/ConversationBubble.tsx | 140 ++++++++++-------- .../src/conversation/ConversationMessages.tsx | 17 ++- .../src/conversation/ConversationTile.tsx | 2 +- .../src/conversation/SharedConversation.tsx | 10 +- .../src/conversation/conversationHandlers.ts | 4 +- .../src/conversation/conversationModels.ts | 1 - frontend/src/index.css | 6 +- frontend/src/modals/AddActionModal.tsx | 8 +- frontend/src/modals/AddToolModal.tsx | 18 +-- frontend/src/modals/ChunkModal.tsx | 42 +++--- frontend/src/modals/ConfigToolModal.tsx | 4 +- frontend/src/modals/CreateAPIKeyModal.tsx | 2 +- .../src/modals/ShareConversationModal.tsx | 2 +- frontend/src/modals/WrapperModal.tsx | 6 +- frontend/src/preferences/PromptsModal.tsx | 8 +- frontend/src/settings/APIKeys.tsx | 32 ++-- frontend/src/settings/Analytics.tsx | 9 +- frontend/src/settings/Documents.tsx | 80 +++++----- frontend/src/settings/General.tsx | 12 +- frontend/src/settings/Prompts.tsx | 4 +- frontend/src/settings/ToolConfig.tsx | 70 ++++----- frontend/src/settings/Tools.tsx | 30 ++-- frontend/src/upload/Upload.tsx | 40 ++--- 38 files changed, 550 insertions(+), 495 deletions(-) diff --git a/frontend/src/About.tsx b/frontend/src/About.tsx index 90842c59..d2bbaac4 100644 --- a/frontend/src/About.tsx +++ b/frontend/src/About.tsx @@ -29,7 +29,7 @@ export default function About() { If you want to add your own documentation, please follow the instruction below:

-

+

1. Navigate to{' '} {' '} @@ -37,13 +37,13 @@ export default function About() { {' '} folder

-

+

2. Install dependencies from{' '} pip install -r requirements.txt

-

+

3. Prepare a{' '} .env{' '} file. Copy{' '} @@ -54,7 +54,7 @@ export default function About() { .env{' '} with your OpenAI API token

-

+

4. Run the app with{' '} python app.py @@ -64,9 +64,9 @@ export default function About() {

Currently It uses{' '} - DocsGPT{' '} + DocsGPT{' '} documentation, so it will respond to information relevant to{' '} - DocsGPT. If you + DocsGPT. If you want to train it on different documentation - please follow ; return ( -

+
{/* Header Section */} -
-
+
+
DocsGPT docsgpt
{/* Demo Buttons Section */} -
-
+
+
{demos?.map( (demo: { header: string; query: string }, key: number) => demo.header && @@ -38,17 +38,12 @@ export default function Hero({ diff --git a/frontend/src/PageNotFound.tsx b/frontend/src/PageNotFound.tsx index 0b86d7c1..4ee3a476 100644 --- a/frontend/src/PageNotFound.tsx +++ b/frontend/src/PageNotFound.tsx @@ -6,7 +6,7 @@ export default function PageNotFound() {

404

The page you are looking for does not exist.

-

diff --git a/frontend/src/agents/index.tsx b/frontend/src/agents/index.tsx index c2edb34a..d0052111 100644 --- a/frontend/src/agents/index.tsx +++ b/frontend/src/agents/index.tsx @@ -3,7 +3,6 @@ import { useSelector, useDispatch } from 'react-redux'; import { Route, Routes, useNavigate } from 'react-router-dom'; import userService from '../api/services/userService'; -import Copy from '../assets/copy-linear.svg'; import Edit from '../assets/edit.svg'; import Monitoring from '../assets/monitoring.svg'; import Trash from '../assets/red-trash.svg'; diff --git a/frontend/src/components/Accordion.tsx b/frontend/src/components/Accordion.tsx index ec0a81d7..45c3170d 100644 --- a/frontend/src/components/Accordion.tsx +++ b/frontend/src/components/Accordion.tsx @@ -32,9 +32,9 @@ export default function Accordion({ setIsOpen(!isOpen); }; return ( -
+
{rowsPerPageOptions.map((option) => (
handleSelectRowsPerPage(option)} - className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ + className={`cursor-pointer px-4 py-2 text-xs hover:bg-gray-100 dark:hover:bg-neutral-700 ${ rowsPerPage === option ? 'bg-gray-100 dark:bg-neutral-700 dark:text-light-gray' : 'bg-white dark:bg-dark-charcoal dark:text-light-gray' @@ -97,45 +97,45 @@ const Pagination: React.FC = ({
diff --git a/frontend/src/components/DropdownMenu.tsx b/frontend/src/components/DropdownMenu.tsx index 56242d7a..3fe85508 100644 --- a/frontend/src/components/DropdownMenu.tsx +++ b/frontend/src/components/DropdownMenu.tsx @@ -88,7 +88,7 @@ export default function DropdownMenu({ onClick={(e) => e.stopPropagation()} >
{ {isOpen && (
{ Email Us {t('emailUs')} diff --git a/frontend/src/components/MermaidRenderer.tsx b/frontend/src/components/MermaidRenderer.tsx index 06d5628b..bc56f023 100644 --- a/frontend/src/components/MermaidRenderer.tsx +++ b/frontend/src/components/MermaidRenderer.tsx @@ -2,7 +2,10 @@ import React, { useEffect, useRef, useState } from 'react'; import mermaid from 'mermaid'; import CopyButton from './CopyButton'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; -import { oneLight, vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism'; +import { + oneLight, + vscDarkPlus, +} from 'react-syntax-highlighter/dist/cjs/styles/prism'; import { MermaidRendererProps } from './types'; import { useSelector } from 'react-redux'; import { selectStatus } from '../conversation/conversationSlice'; @@ -20,9 +23,12 @@ const MermaidRenderer: React.FC = ({ const [showDownloadMenu, setShowDownloadMenu] = useState(false); const downloadMenuRef = useRef(null); const containerRef = useRef(null); - const [hoverPosition, setHoverPosition] = useState<{ x: number, y: number } | null>(null); + const [hoverPosition, setHoverPosition] = useState<{ + x: number; + y: number; + } | null>(null); const [isHovering, setIsHovering] = useState(false); - const [zoomFactor, setZoomFactor] = useState(2); + const [zoomFactor, setZoomFactor] = useState(2); const handleMouseMove = (event: React.MouseEvent) => { if (!containerRef.current) return; @@ -40,16 +46,14 @@ const MermaidRenderer: React.FC = ({ setHoverPosition(null); }; - const handleKeyDown = (event: React.KeyboardEvent) => { if (!isHovering) return; if (event.key === '+' || event.key === '=') { - setZoomFactor(prev => Math.min(6, prev + 0.5)); // Cap at 6x + setZoomFactor((prev) => Math.min(6, prev + 0.5)); // Cap at 6x event.preventDefault(); - } - else if (event.key === '-') { - setZoomFactor(prev => Math.max(1, prev - 0.5)); // Minimum 1x + } else if (event.key === '-') { + setZoomFactor((prev) => Math.max(1, prev - 0.5)); // Minimum 1x event.preventDefault(); } }; @@ -57,13 +61,13 @@ const MermaidRenderer: React.FC = ({ const handleWheel = (event: React.WheelEvent) => { if (!isHovering) return; - if ( event.ctrlKey || event.metaKey) { + if (event.ctrlKey || event.metaKey) { event.preventDefault(); if (event.deltaY < 0) { - setZoomFactor(prev => Math.min(6, prev + 0.25)); + setZoomFactor((prev) => Math.min(6, prev + 0.25)); } else { - setZoomFactor(prev => Math.max(1, prev - 0.25)); + setZoomFactor((prev) => Math.max(1, prev - 0.25)); } } }; @@ -81,8 +85,9 @@ const MermaidRenderer: React.FC = ({ securityLevel: 'loose', suppressErrorRendering: true, }); - - const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + + const isCurrentlyLoading = + isLoading !== undefined ? isLoading : status === 'loading'; if (!isCurrentlyLoading && code) { try { const element = document.getElementById(diagramId.current); @@ -93,7 +98,9 @@ const MermaidRenderer: React.FC = ({ } } catch (err) { console.error('Error rendering mermaid diagram:', err); - setError(`Failed to render diagram: ${err instanceof Error ? err.message : String(err)}`); + setError( + `Failed to render diagram: ${err instanceof Error ? err.message : String(err)}`, + ); } } }; @@ -101,9 +108,6 @@ const MermaidRenderer: React.FC = ({ renderDiagram(); }, [code, isDarkTheme, isLoading]); - - - useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if ( @@ -120,7 +124,6 @@ const MermaidRenderer: React.FC = ({ }; }, [showDownloadMenu]); - const downloadSvg = (): void => { const element = document.getElementById(diagramId.current); if (!element) return; @@ -146,7 +149,7 @@ const MermaidRenderer: React.FC = ({ const svgBlob = new Blob( [`\n${svgString}`], - { type: 'image/svg+xml' } + { type: 'image/svg+xml' }, ); const url = URL.createObjectURL(svgBlob); @@ -198,7 +201,7 @@ const MermaidRenderer: React.FC = ({ const img = new Image(); img.crossOrigin = 'anonymous'; - img.onload = function(): void { + img.onload = function (): void { const canvas = document.createElement('canvas'); canvas.width = width; canvas.height = height; @@ -243,20 +246,20 @@ const MermaidRenderer: React.FC = ({ URL.revokeObjectURL(url); }; - const downloadOptions = [ { label: 'Download as SVG', action: downloadSvg }, { label: 'Download as PNG', action: downloadPng }, { label: 'Download as MMD', action: downloadMmd }, ]; - const isCurrentlyLoading = isLoading !== undefined ? isLoading : status === 'loading'; + const isCurrentlyLoading = + isLoading !== undefined ? isLoading : status === 'loading'; const showDiagramOptions = !isCurrentlyLoading && !error; const errorRender = !isCurrentlyLoading && error; return ( -
-
+
+
mermaid @@ -267,13 +270,13 @@ const MermaidRenderer: React.FC = ({
{showDownloadMenu && ( -
+
    {downloadOptions.map((option, index) => (
  • @@ -282,7 +285,7 @@ const MermaidRenderer: React.FC = ({ option.action(); setShowDownloadMenu(false); }} - className="text-xs px-4 py-2 w-full text-left hover:bg-gray-100 dark:hover:bg-gray-700" + className="w-full px-4 py-2 text-left text-xs hover:bg-gray-100 dark:hover:bg-gray-700" > {option.label} @@ -297,7 +300,7 @@ const MermaidRenderer: React.FC = ({ {showDiagramOptions && (
{isCurrentlyLoading ? ( -
+
Loading diagram...
) : errorRender ? ( -
-
+
+
{error}
@@ -326,13 +329,12 @@ const MermaidRenderer: React.FC = ({ <>
= ({ onKeyDown={handleKeyDown} onWheel={handleWheel} tabIndex={0} - > {isHovering && ( <> -
- - { - setZoomFactor(2); - }} - title="Reset zoom" - > - {zoomFactor.toFixed(1)}x - - -
+
+ + { + setZoomFactor(2); + }} + title="Reset zoom" + > + {zoomFactor.toFixed(1)}x + + +
)}
 = ({
                 cursor: 'default',
                 width: '100%',
                 display: 'flex',
-                justifyContent: 'center'
+                justifyContent: 'center',
               }}
             >
               {code}
@@ -391,7 +396,7 @@ const MermaidRenderer: React.FC = ({
 
           {showCode && (
             
-
+
Mermaid Code @@ -403,7 +408,7 @@ const MermaidRenderer: React.FC = ({ margin: 0, borderRadius: 0, scrollbarWidth: 'thin', - maxHeight: '300px' + maxHeight: '300px', }} > {code} diff --git a/frontend/src/components/ShareButton.tsx b/frontend/src/components/ShareButton.tsx index 8d4a93de..e912ea22 100644 --- a/frontend/src/components/ShareButton.tsx +++ b/frontend/src/components/ShareButton.tsx @@ -15,7 +15,7 @@ export default function ShareButton({ conversationId }: ShareButtonProps) { onClick={() => { setShareModalState(true); }} - className="absolute top-4 right-20 z-20 rounded-full hover:bg-bright-gray dark:hover:bg-[#28292E]" + className="absolute right-20 top-4 z-20 rounded-full hover:bg-bright-gray dark:hover:bg-[#28292E]" >
-
+
{children}
diff --git a/frontend/src/components/SkeletonLoader.tsx b/frontend/src/components/SkeletonLoader.tsx index 2433110a..71b796d8 100644 --- a/frontend/src/components/SkeletonLoader.tsx +++ b/frontend/src/components/SkeletonLoader.tsx @@ -42,17 +42,17 @@ const SkeletonLoader: React.FC = ({ <> {[...Array(4)].map((_, idx) => ( - -
+ +
- -
+ +
- -
+ +
- -
+ +
))} @@ -64,16 +64,16 @@ const SkeletonLoader: React.FC = ({ {[...Array(4)].map((_, idx) => ( -
+
-
+
-
+
-
+
))} @@ -82,10 +82,10 @@ const SkeletonLoader: React.FC = ({ const renderDropdown = () => (
-
-
-
-
+
+
+
+
); @@ -95,14 +95,14 @@ const SkeletonLoader: React.FC = ({ {[...Array(8)].map((_, idx) => (
-
-
-
-
-
-
+
+
+
+
+
+
@@ -117,32 +117,32 @@ const SkeletonLoader: React.FC = ({ key={idx} className={`p-6 ${ skeletonCount === 1 ? 'w-full' : 'w-60' - } dark:bg-raisin-black rounded-3xl animate-pulse`} + } animate-pulse rounded-3xl dark:bg-raisin-black`} >
-
-
-
-
-
+
+
+
+
+
-
+
-
-
-
+
+
+
-
+
-
-
-
-
+
+
+
+
-
-
-
+
+
+
))} @@ -154,27 +154,27 @@ const SkeletonLoader: React.FC = ({ {[...Array(skeletonCount)].map((_, idx) => (
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
diff --git a/frontend/src/components/SourcesPopup.tsx b/frontend/src/components/SourcesPopup.tsx index 088b3eb1..6846cf84 100644 --- a/frontend/src/components/SourcesPopup.tsx +++ b/frontend/src/components/SourcesPopup.tsx @@ -32,8 +32,13 @@ export default function SourcesPopup({ const { t } = useTranslation(); const popupRef = useRef(null); const [searchTerm, setSearchTerm] = useState(''); - const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0, maxHeight: 0, showAbove: false }); - + const [popupPosition, setPopupPosition] = useState({ + top: 0, + left: 0, + maxHeight: 0, + showAbove: false, + }); + const embeddingsName = import.meta.env.VITE_EMBEDDINGS_NAME || 'huggingface_sentence-transformers/all-mpnet-base-v2'; @@ -41,16 +46,16 @@ export default function SourcesPopup({ const options = useSelector(selectSourceDocs); const selectedDocs = useSelector(selectSelectedDocs); - const filteredOptions = options?.filter(option => - option.name.toLowerCase().includes(searchTerm.toLowerCase()) + const filteredOptions = options?.filter((option) => + option.name.toLowerCase().includes(searchTerm.toLowerCase()), ); useLayoutEffect(() => { if (!isOpen || !anchorRef.current) return; - + const updatePosition = () => { if (!anchorRef.current) return; - + const rect = anchorRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; const viewportWidth = window.innerWidth; @@ -60,17 +65,17 @@ export default function SourcesPopup({ const maxHeight = showAbove ? spaceAbove - 16 : spaceBelow - 16; const left = Math.min( rect.left, - viewportWidth - Math.min(480, viewportWidth * 0.95) - 10 + viewportWidth - Math.min(480, viewportWidth * 0.95) - 10, ); - + setPopupPosition({ top: showAbove ? rect.top - 8 : rect.bottom + 8, left, maxHeight: Math.min(600, maxHeight), - showAbove + showAbove, }); }; - + updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); @@ -111,10 +116,12 @@ export default function SourcesPopup({ return (
-
-
-

+
+
+

{t('conversation.sources.text')}

- +
-
+
{options ? ( <> {filteredOptions?.map((option: any, index: number) => { @@ -149,7 +156,7 @@ export default function SourcesPopup({ return (
{ dispatch(setSelectedDocs(option)); handlePostDocumentSelect(option); @@ -159,23 +166,26 @@ export default function SourcesPopup({ Source - + {option.name} -
- {selectedDocs && - (option.id ? - selectedDocs.id === option.id : // For documents with MongoDB IDs - selectedDocs.date === option.date) && // For preloaded sources - Selected - } +
+ {selectedDocs && + (option.id + ? selectedDocs.id === option.id // For documents with MongoDB IDs + : selectedDocs.date === option.date) && ( // For preloaded sources + Selected + )}
); @@ -183,14 +193,22 @@ export default function SourcesPopup({ return null; })}
- Source - + Source + {t('none')} -
+
{selectedDocs === null && ( Selected )} @@ -198,27 +216,27 @@ export default function SourcesPopup({
) : ( -
+
{t('noSourcesAvailable')}
)}
- -
+
diff --git a/frontend/src/components/ToggleSwitch.tsx b/frontend/src/components/ToggleSwitch.tsx index 3a4ed7db..69530e79 100644 --- a/frontend/src/components/ToggleSwitch.tsx +++ b/frontend/src/components/ToggleSwitch.tsx @@ -46,9 +46,9 @@ const ToggleSwitch: React.FC = ({ return (
diff --git a/frontend/src/components/ToolsPopup.tsx b/frontend/src/components/ToolsPopup.tsx index f0466e95..5fdd6c23 100644 --- a/frontend/src/components/ToolsPopup.tsx +++ b/frontend/src/components/ToolsPopup.tsx @@ -29,18 +29,23 @@ export default function ToolsPopup({ const [searchTerm, setSearchTerm] = useState(''); const [isDarkTheme] = useDarkTheme(); const popupRef = useRef(null); - const [popupPosition, setPopupPosition] = useState({ top: 0, left: 0, maxHeight: 0, showAbove: false }); + const [popupPosition, setPopupPosition] = useState({ + top: 0, + left: 0, + maxHeight: 0, + showAbove: false, + }); useLayoutEffect(() => { if (!isOpen || !anchorRef.current) return; - + const updatePosition = () => { if (!anchorRef.current) return; - + const rect = anchorRef.current.getBoundingClientRect(); const viewportHeight = window.innerHeight; const viewportWidth = window.innerWidth; - + const spaceAbove = rect.top; const spaceBelow = viewportHeight - rect.bottom; const showAbove = spaceAbove > spaceBelow && spaceAbove >= 300; @@ -48,17 +53,17 @@ export default function ToolsPopup({ const left = Math.min( rect.left, - viewportWidth - Math.min(462, viewportWidth * 0.95) - 10 + viewportWidth - Math.min(462, viewportWidth * 0.95) - 10, ); - + setPopupPosition({ top: showAbove ? rect.top - 8 : rect.bottom + 8, left, maxHeight: Math.min(600, maxHeight), - showAbove + showAbove, }); }; - + updatePosition(); window.addEventListener('resize', updatePosition); return () => window.removeEventListener('resize', updatePosition); @@ -125,16 +130,18 @@ export default function ToolsPopup({ if (!isOpen) return null; const filteredTools = userTools.filter((tool) => - tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()) + tool.displayName.toLowerCase().includes(searchTerm.toLowerCase()), ); return (
-
-
-

+
+
+

{t('settings.tools.label')}

@@ -162,20 +169,20 @@ export default function ToolsPopup({
{loading ? ( -
-
+
+
) : ( -
+
{filteredTools.length === 0 ? ( -
+
No tools found -

+

{t('settings.tools.noToolsFound')}

@@ -184,22 +191,24 @@ export default function ToolsPopup({
updateToolStatus(tool.id, !tool.status)} - className="flex items-center justify-between p-3 border-b border-[#D9D9D9] dark:border-dim-gray hover:bg-gray-100 dark:hover:bg-charleston-green-3" + className="flex items-center justify-between border-b border-[#D9D9D9] p-3 hover:bg-gray-100 dark:border-dim-gray dark:hover:bg-charleston-green-3" > -
+
{`${tool.displayName}
-

+

{tool.displayName}

-
-
+
+
{tool.status && ( )} -
+
{t('settings.tools.manageTools')} + } /> {!isEditClicked && ( <> -
+
{message}
@@ -128,7 +134,7 @@ const ConversationBubble = forwardRef< setIsEditClicked(true); setEditInputBox(message ?? ''); }} - className={`flex-shrink-0 h-fit mt-3 p-2 cursor-pointer rounded-full hover:bg-light-silver dark:hover:bg-[#35363B] flex items-center ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} + className={`mt-3 flex h-fit flex-shrink-0 cursor-pointer items-center rounded-full p-2 hover:bg-light-silver dark:hover:bg-[#35363B] ${isQuestionHovered || isEditClicked ? 'visible' : 'invisible'}`} > Edit @@ -137,7 +143,7 @@ const ConversationBubble = forwardRef< {isEditClicked && (
-
+
-
-
+
+
- - - - @@ -151,7 +151,7 @@ export default function APIKeys() { @@ -163,22 +163,22 @@ export default function APIKeys() { key={element.id} className="group transition-colors hover:bg-gray-50 dark:hover:bg-gray-800/50" > - - - -
+ {t('settings.apiKeys.name')} + {t('settings.apiKeys.sourceDoc')} + {t('settings.apiKeys.key')} @@ -139,7 +139,7 @@ export default function APIKeys() { {t('settings.apiKeys.key')} + Actions
{t('settings.apiKeys.noData')} +
{element.name}
+
{element.source}
+
{element.key}
+
-
-
+
+
- - - - @@ -370,7 +370,7 @@ export default function Documents({ @@ -382,26 +382,26 @@ export default function Documents({ return ( - - @@ -824,20 +824,20 @@ function APIActionTable({ } }} placeholder="New property key" - className="min-w-[130.5px] w-full flex items-start bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm" + className="flex w-full min-w-[130.5px] items-start rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40" />
+ {t('settings.documents.name')} -
+
+
{t('settings.documents.date')} refreshDocs('date')} src={caretSort} alt="sort" />
-
+
+
{t('settings.documents.tokenUsage')} @@ -351,14 +351,14 @@ export default function Documents({ {t('settings.documents.tokenUsage')} refreshDocs('tokens')} src={caretSort} alt="sort" />
+ {t('settings.documents.actions')}
{t('settings.documents.noData')}
{document.name} + {document.date ? formatDate(document.date) : ''} + {document.tokens ? formatTokens(+document.tokens) : ''} e.stopPropagation()} >
{document.syncFrequency && ( handleMenuClick(e, docId)} - className="inline-flex items-center justify-center w-8 h-8 rounded-full hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors flex-shrink-0" + className="inline-flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-colors hover:bg-gray-100 dark:hover:bg-gray-700" aria-label="Open menu" data-testid={`menu-button-${docId}`} > @@ -633,19 +633,19 @@ function DocumentChunks({ fetchChunks(); }, [page, perPage]); return ( -
-
+
+

Back to all documents

-
-
-

{`${totalChunks} Chunks`}

+
+
+

{`${totalChunks} Chunks`}

@@ -663,7 +663,7 @@ function DocumentChunks({ />
{loading ? ( -
-
+
+
) : ( -
+
{paginatedChunks.filter((chunk) => { if (!chunk.metadata?.title) return true; return chunk.metadata.title .toLowerCase() .includes(searchTerm.toLowerCase()); }).length === 0 ? ( -
+
No tools found No chunks found
@@ -703,10 +703,10 @@ function DocumentChunks({ .map((chunk, index) => (
-
+
-

+

{chunk.metadata?.title ?? 'Untitled'}

-

+

{chunk.text}

@@ -745,7 +745,7 @@ function DocumentChunks({ .toLowerCase() .includes(searchTerm.toLowerCase()); }).length !== 0 && ( -
+
{' '} -
-
-
-
-
+

Back to all tools

@@ -128,7 +128,7 @@ export default function ToolConfig({

Type

-

+

{tool.name}

@@ -138,7 +138,7 @@ export default function ToolConfig({ Authentication

)} -
+
{Object.keys(tool?.config).length !== 0 && tool.name !== 'api_tool' && (
@@ -153,13 +153,13 @@ export default function ToolConfig({ )}
-
-
+
+

Actions

@@ -177,7 +177,7 @@ export default function ToolConfig({ onClick={() => { setActionModalState('ACTIVE'); }} - className="border border-solid border-violets-are-blue text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white rounded-full text-sm px-5 py-1" + className="rounded-full border border-solid border-violets-are-blue px-5 py-1 text-sm text-violets-are-blue transition-colors hover:bg-violets-are-blue hover:text-white" > Add action @@ -191,9 +191,9 @@ export default function ToolConfig({ return (
-
+

{action.name}

@@ -214,10 +214,10 @@ export default function ToolConfig({ id={`actionToggle-${actionIndex}`} />
-
+
{ @@ -285,7 +285,7 @@ export default function ToolConfig({ { setTool({ ...tool, @@ -321,7 +321,7 @@ export default function ToolConfig({ value={param[1].value} key={uniqueKey} disabled={param[1].filled_by_llm} - className={`bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm ${param[1].filled_by_llm ? 'opacity-50' : ''}`} + className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param[1].filled_by_llm ? 'opacity-50' : ''}`} onChange={(e) => { setTool({ ...tool, @@ -424,9 +424,9 @@ function APIToolConfig({ return (
-
+

{action.name}

@@ -439,7 +439,7 @@ function APIToolConfig({
- + URL
- + Method
- + Description setNewPropertyKey(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { @@ -724,26 +724,26 @@ function APIActionTable({
) : ( handleRenamePropertyStart(section, key)} readOnly /> @@ -772,7 +772,7 @@ function APIActionTable({
handlePropertyChange( section, @@ -790,7 +790,7 @@ function APIActionTable({ onChange={(e) => handlePropertyChange(section, key, 'value', e.target.value) } - className={`bg-transparent border border-silver dark:border-silver/40 outline-none px-2 py-1 rounded-lg text-sm ${param.filled_by_llm ? 'opacity-50' : ''}`} + className={`rounded-lg border border-silver bg-transparent px-2 py-1 text-sm outline-none dark:border-silver/40 ${param.filled_by_llm ? 'opacity-50' : ''}`} >
diff --git a/frontend/src/settings/Tools.tsx b/frontend/src/settings/Tools.tsx index 3a91d30f..9c7b6906 100644 --- a/frontend/src/settings/Tools.tsx +++ b/frontend/src/settings/Tools.tsx @@ -101,8 +101,8 @@ export default function Tools() { /> ) : (
-
-
+
+
-
+
{loading ? ( -
-
+
+
) : ( -
+
{userTools.length === 0 ? ( -
+
No tools found -

+

{t('settings.tools.noToolsFound')}

@@ -157,14 +157,14 @@ export default function Tools() { .map((tool, index) => (
-
+
{`${tool.displayName}

{tool.displayName}

-

+

{tool.description}

diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 8c016b29..61a7bc47 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -69,8 +69,8 @@ function Upload({ : 'grid-rows-[0fr] opacity-0' }`} > -
-
+
+
{advancedFields.map((field: FormField) => renderField(field))}
@@ -212,11 +212,11 @@ function Upload({ function ProgressBar({ progressPercent }: { progressPercent: number }) { return ( -
-
+
+
{t('modals.uploadDoc.start')} ) : ( @@ -617,7 +617,7 @@ function Upload({ required={true} />
- + {t('modals.uploadDoc.choose')} @@ -633,7 +633,7 @@ function Upload({ {files.map((file) => (

{file.name} @@ -681,7 +681,7 @@ function Upload({ ) && ( @@ -709,7 +709,7 @@ function Upload({ } }} disabled={isUploadDisabled()} - className={`rounded-3xl px-4 py-2 font-medium text-[14px] ${ + className={`rounded-3xl px-4 py-2 text-[14px] font-medium ${ isUploadDisabled() ? 'cursor-not-allowed bg-gray-300 text-gray-500' : 'cursor-pointer bg-purple-30 text-white hover:bg-violets-are-blue' From 183251487c0cd19cbc60a07ba6fc648ac2ef6320 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 7 May 2025 23:37:35 +0100 Subject: [PATCH 5/5] lint: remove unused import of 'io' in worker.py --- application/worker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/application/worker.py b/application/worker.py index 2f9e97f3..9829fde9 100755 --- a/application/worker.py +++ b/application/worker.py @@ -1,5 +1,4 @@ import datetime -import io import json import logging import mimetypes