From 83f2fb1e62c215828b2ecd95498e886900e83571 Mon Sep 17 00:00:00 2001 From: kom-senapati Date: Fri, 18 Oct 2024 09:18:15 +0530 Subject: [PATCH 01/38] refactor: Use MongoDB singleton for connection management --- application/api/answer/routes.py | 4 ++-- application/api/internal/routes.py | 4 ++-- application/api/user/routes.py | 4 ++-- application/core/mongo_db.py | 25 +++++++++++++++++++++++++ application/usage.py | 4 ++-- application/worker.py | 4 ++-- 6 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 application/core/mongo_db.py diff --git a/application/api/answer/routes.py b/application/api/answer/routes.py index 17eb5cc3..40c4d8cb 100644 --- a/application/api/answer/routes.py +++ b/application/api/answer/routes.py @@ -11,7 +11,7 @@ from bson.objectid import ObjectId from flask import Blueprint, current_app, make_response, request, Response from flask_restx import fields, Namespace, Resource -from pymongo import MongoClient +from core.mongo_db import MongoDB from application.core.settings import settings from application.error import bad_request @@ -22,7 +22,7 @@ from application.utils import check_required_fields logger = logging.getLogger(__name__) -mongo = MongoClient(settings.MONGO_URI) +mongo = MongoDB.get_client() db = mongo["docsgpt"] conversations_collection = db["conversations"] sources_collection = db["sources"] diff --git a/application/api/internal/routes.py b/application/api/internal/routes.py index 6ecb4346..f004cf97 100755 --- a/application/api/internal/routes.py +++ b/application/api/internal/routes.py @@ -1,13 +1,13 @@ import os import datetime from flask import Blueprint, request, send_from_directory -from pymongo import MongoClient +from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from bson.objectid import ObjectId from application.core.settings import settings -mongo = MongoClient(settings.MONGO_URI) +mongo = MongoDB.get_client() db = mongo["docsgpt"] conversations_collection = db["conversations"] sources_collection = db["sources"] diff --git a/application/api/user/routes.py b/application/api/user/routes.py index feee91cc..3469c800 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -8,7 +8,7 @@ from bson.dbref import DBRef from bson.objectid import ObjectId from flask import Blueprint, jsonify, make_response, request from flask_restx import inputs, fields, Namespace, Resource -from pymongo import MongoClient +from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from application.api.user.tasks import ingest, ingest_remote @@ -18,7 +18,7 @@ from application.extensions import api from application.utils import check_required_fields from application.vectorstore.vector_creator import VectorCreator -mongo = MongoClient(settings.MONGO_URI) +mongo = MongoDB.get_client() db = mongo["docsgpt"] conversations_collection = db["conversations"] sources_collection = db["sources"] diff --git a/application/core/mongo_db.py b/application/core/mongo_db.py new file mode 100644 index 00000000..ffb55d7f --- /dev/null +++ b/application/core/mongo_db.py @@ -0,0 +1,25 @@ +from application.core import settings +from pymongo import MongoClient +from flask import current_app, g + + +class MongoDB: + _client = None + + @classmethod + def get_client(cls): + """ + Get the MongoDB client instance, creating it if necessary. + """ + if cls._client is None: + cls._client = MongoClient(settings.MONGO_URI) + return cls._client + + @classmethod + def close_client(cls): + """ + Close the MongoDB client connection. + """ + if cls._client is not None: + cls._client.close() + cls._client = None diff --git a/application/usage.py b/application/usage.py index aba0ec77..21797817 100644 --- a/application/usage.py +++ b/application/usage.py @@ -1,10 +1,10 @@ import sys -from pymongo import MongoClient +from core.mongo_db import MongoDB from datetime import datetime from application.core.settings import settings from application.utils import num_tokens_from_string -mongo = MongoClient(settings.MONGO_URI) +mongo = MongoDB.get_client() db = mongo["docsgpt"] usage_collection = db["token_usage"] diff --git a/application/worker.py b/application/worker.py index f8f38afa..fc780d61 100755 --- a/application/worker.py +++ b/application/worker.py @@ -8,7 +8,7 @@ from urllib.parse import urljoin import requests from bson.objectid import ObjectId -from pymongo import MongoClient +from core.mongo_db import MongoDB from application.core.settings import settings from application.parser.file.bulk import SimpleDirectoryReader @@ -18,7 +18,7 @@ from application.parser.schema.base import Document from application.parser.token_func import group_split from application.utils import count_tokens_docs -mongo = MongoClient(settings.MONGO_URI) +mongo = MongoDB.get_client() db = mongo["docsgpt"] sources_collection = db["sources"] From 5ba917c5e42c29e286c74d0443d88454ff6b7f46 Mon Sep 17 00:00:00 2001 From: kom-senapati Date: Fri, 18 Oct 2024 09:22:27 +0530 Subject: [PATCH 02/38] chore: remove unused imports --- application/core/mongo_db.py | 1 - application/usage.py | 1 - 2 files changed, 2 deletions(-) diff --git a/application/core/mongo_db.py b/application/core/mongo_db.py index ffb55d7f..fdb728a2 100644 --- a/application/core/mongo_db.py +++ b/application/core/mongo_db.py @@ -1,6 +1,5 @@ from application.core import settings from pymongo import MongoClient -from flask import current_app, g class MongoDB: diff --git a/application/usage.py b/application/usage.py index 21797817..31feb5f1 100644 --- a/application/usage.py +++ b/application/usage.py @@ -1,7 +1,6 @@ import sys from core.mongo_db import MongoDB from datetime import datetime -from application.core.settings import settings from application.utils import num_tokens_from_string mongo = MongoDB.get_client() From 2366c2cd94a0ff2d0cf450c6825cf63c08b0f937 Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Sat, 19 Oct 2024 04:24:14 +0000 Subject: [PATCH 03/38] enhancement: added loading state for conversation --- frontend/src/Navigation.tsx | 23 ++++++++++++++++----- frontend/src/preferences/preferenceApi.ts | 11 +++++----- frontend/src/preferences/preferenceSlice.ts | 10 +++++++-- 3 files changed, 32 insertions(+), 12 deletions(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index ac7063be..c8252e37 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -37,11 +37,12 @@ import { setSelectedDocs, setSourceDocs, } from './preferences/preferenceSlice'; +import Spinner from './assets/spinner.svg'; +import SpinnerDark from './assets/spinner-dark.svg'; import Upload from './upload/Upload'; import ShareButton from './components/ShareButton'; import Help from './components/Help'; - interface NavigationProps { navOpen: boolean; setNavOpen: React.Dispatch>; @@ -89,18 +90,20 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { const navigate = useNavigate(); useEffect(() => { - if (!conversations) { + if (!conversations?.data) { fetchConversations(); } - }, [conversations, dispatch]); + }, [conversations?.data, dispatch]); async function fetchConversations() { + dispatch(setConversations({ data: null, loading: true })); return await getConversations() .then((fetchedConversations) => { dispatch(setConversations(fetchedConversations)); }) .catch((error) => { console.error('Failed to fetch conversations: ', error); + dispatch(setConversations({ data: null, loading: false })); }); } @@ -196,6 +199,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { setNavOpen(!isMobile); }, [isMobile]); useDefaultDocument(); + return ( <> {!navOpen && ( @@ -278,13 +282,22 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { id="conversationsMainDiv" className="mb-auto h-[78vh] overflow-y-auto overflow-x-hidden dark:text-white" > - {conversations && conversations.length > 0 ? ( + {conversations?.loading && ( +
+ +
+ )} + + {conversations?.data && conversations.data.length > 0 ? (

{t('chats')}

- {conversations?.map((conversation) => ( + {conversations.data?.map((conversation) => ( { } } -export async function getConversations(): Promise< - { name: string; id: string }[] | null -> { +export async function getConversations(): Promise<{ + data: { name: string; id: string }[] | null; + loading: boolean; +}> { try { const response = await conversationService.getConversations(); const data = await response.json(); @@ -34,10 +35,10 @@ export async function getConversations(): Promise< conversations.push(conversation as { name: string; id: string }); }); - return conversations; + return { data: conversations, loading: false }; } catch (error) { console.log(error); - return null; + return { data: null, loading: false }; } } diff --git a/frontend/src/preferences/preferenceSlice.ts b/frontend/src/preferences/preferenceSlice.ts index 6fb2480b..c566ba70 100644 --- a/frontend/src/preferences/preferenceSlice.ts +++ b/frontend/src/preferences/preferenceSlice.ts @@ -15,7 +15,10 @@ export interface Preference { token_limit: number; selectedDocs: Doc | null; sourceDocs: Doc[] | null; - conversations: { name: string; id: string }[] | null; + conversations: { + data: { name: string; id: string }[] | null; + loading: boolean; + }; modalState: ActiveState; } @@ -34,7 +37,10 @@ const initialState: Preference = { retriever: 'classic', } as Doc, sourceDocs: null, - conversations: null, + conversations: { + data: null, + loading: false, + }, modalState: 'INACTIVE', }; From a185b2a12a526e843b0a0723c02d255c02dc953c Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Sat, 19 Oct 2024 04:45:00 +0000 Subject: [PATCH 04/38] retaining original state --- frontend/src/Navigation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index c8252e37..d858bc02 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -96,14 +96,14 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { }, [conversations?.data, dispatch]); async function fetchConversations() { - dispatch(setConversations({ data: null, loading: true })); + dispatch(setConversations({ ...conversations, loading: true })); return await getConversations() .then((fetchedConversations) => { dispatch(setConversations(fetchedConversations)); }) .catch((error) => { console.error('Failed to fetch conversations: ', error); - dispatch(setConversations({ data: null, loading: false })); + dispatch(setConversations({ ...conversations, loading: false })); }); } From 6a024b0ced42d89a32d4ba868dbcecaded4c5b37 Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Sat, 19 Oct 2024 04:46:46 +0000 Subject: [PATCH 05/38] update catch block --- frontend/src/Navigation.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index d858bc02..5aa694f8 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -103,7 +103,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { }) .catch((error) => { console.error('Failed to fetch conversations: ', error); - dispatch(setConversations({ ...conversations, loading: false })); + dispatch(setConversations({ data: null, loading: false })); }); } From cbea17b4d509243851bac2e726e1ccf2bdb7d5a1 Mon Sep 17 00:00:00 2001 From: Christine Date: Mon, 21 Oct 2024 20:52:44 +0000 Subject: [PATCH 06/38] feat: add edit buttons Signed-off-by: Christine --- docs/theme.config.jsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/theme.config.jsx b/docs/theme.config.jsx index 2b868db7..777a0ed5 100644 --- a/docs/theme.config.jsx +++ b/docs/theme.config.jsx @@ -51,6 +51,9 @@ const config = { footer: { text: `MIT ${new Date().getFullYear()} © DocsGPT`, }, + editLink: { + content: 'Edit this page on GitHub', + }, logo() { return (
From e4a1730a5b9959326ef1e544dc5eb7f0215336cf Mon Sep 17 00:00:00 2001 From: kom-senapati Date: Tue, 22 Oct 2024 17:58:41 +0530 Subject: [PATCH 07/38] fix: MongoDB imports --- application/api/answer/routes.py | 2 +- application/api/internal/routes.py | 2 +- application/api/user/routes.py | 2 +- application/usage.py | 2 +- application/worker.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/application/api/answer/routes.py b/application/api/answer/routes.py index 40c4d8cb..ad434157 100644 --- a/application/api/answer/routes.py +++ b/application/api/answer/routes.py @@ -11,8 +11,8 @@ from bson.objectid import ObjectId from flask import Blueprint, current_app, make_response, request, Response from flask_restx import fields, Namespace, Resource -from core.mongo_db import MongoDB +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.error import bad_request from application.extensions import api diff --git a/application/api/internal/routes.py b/application/api/internal/routes.py index f004cf97..c8e32d11 100755 --- a/application/api/internal/routes.py +++ b/application/api/internal/routes.py @@ -1,10 +1,10 @@ import os import datetime from flask import Blueprint, request, send_from_directory -from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from bson.objectid import ObjectId +from application.core.mongo_db import MongoDB from application.core.settings import settings mongo = MongoDB.get_client() diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 3469c800..ca4a051b 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -8,11 +8,11 @@ from bson.dbref import DBRef from bson.objectid import ObjectId from flask import Blueprint, jsonify, make_response, request from flask_restx import inputs, fields, Namespace, Resource -from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from application.api.user.tasks import ingest, ingest_remote +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.extensions import api from application.utils import check_required_fields diff --git a/application/usage.py b/application/usage.py index 31feb5f1..e87ebe38 100644 --- a/application/usage.py +++ b/application/usage.py @@ -1,6 +1,6 @@ import sys -from core.mongo_db import MongoDB from datetime import datetime +from application.core.mongo_db import MongoDB from application.utils import num_tokens_from_string mongo = MongoDB.get_client() diff --git a/application/worker.py b/application/worker.py index fc780d61..33cd90e5 100755 --- a/application/worker.py +++ b/application/worker.py @@ -8,8 +8,8 @@ from urllib.parse import urljoin import requests from bson.objectid import ObjectId -from core.mongo_db import MongoDB +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.parser.file.bulk import SimpleDirectoryReader from application.parser.open_ai_func import call_openai_api From 3b76b3ddceadcdc8cc7742d9624017ad43896924 Mon Sep 17 00:00:00 2001 From: kom-senapati Date: Tue, 22 Oct 2024 17:58:41 +0530 Subject: [PATCH 08/38] fix: Settings import --- application/api/answer/routes.py | 2 +- application/api/internal/routes.py | 2 +- application/api/user/routes.py | 2 +- application/core/mongo_db.py | 4 ++-- application/usage.py | 2 +- application/worker.py | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/application/api/answer/routes.py b/application/api/answer/routes.py index 40c4d8cb..ad434157 100644 --- a/application/api/answer/routes.py +++ b/application/api/answer/routes.py @@ -11,8 +11,8 @@ from bson.objectid import ObjectId from flask import Blueprint, current_app, make_response, request, Response from flask_restx import fields, Namespace, Resource -from core.mongo_db import MongoDB +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.error import bad_request from application.extensions import api diff --git a/application/api/internal/routes.py b/application/api/internal/routes.py index f004cf97..c8e32d11 100755 --- a/application/api/internal/routes.py +++ b/application/api/internal/routes.py @@ -1,10 +1,10 @@ import os import datetime from flask import Blueprint, request, send_from_directory -from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from bson.objectid import ObjectId +from application.core.mongo_db import MongoDB from application.core.settings import settings mongo = MongoDB.get_client() diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 3469c800..ca4a051b 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -8,11 +8,11 @@ from bson.dbref import DBRef from bson.objectid import ObjectId from flask import Blueprint, jsonify, make_response, request from flask_restx import inputs, fields, Namespace, Resource -from core.mongo_db import MongoDB from werkzeug.utils import secure_filename from application.api.user.tasks import ingest, ingest_remote +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.extensions import api from application.utils import check_required_fields diff --git a/application/core/mongo_db.py b/application/core/mongo_db.py index fdb728a2..a29ca5d6 100644 --- a/application/core/mongo_db.py +++ b/application/core/mongo_db.py @@ -1,4 +1,4 @@ -from application.core import settings +from application.core.settings import Settings from pymongo import MongoClient @@ -11,7 +11,7 @@ class MongoDB: Get the MongoDB client instance, creating it if necessary. """ if cls._client is None: - cls._client = MongoClient(settings.MONGO_URI) + cls._client = MongoClient(Settings.MONGO_URI) return cls._client @classmethod diff --git a/application/usage.py b/application/usage.py index 31feb5f1..e87ebe38 100644 --- a/application/usage.py +++ b/application/usage.py @@ -1,6 +1,6 @@ import sys -from core.mongo_db import MongoDB from datetime import datetime +from application.core.mongo_db import MongoDB from application.utils import num_tokens_from_string mongo = MongoDB.get_client() diff --git a/application/worker.py b/application/worker.py index fc780d61..33cd90e5 100755 --- a/application/worker.py +++ b/application/worker.py @@ -8,8 +8,8 @@ from urllib.parse import urljoin import requests from bson.objectid import ObjectId -from core.mongo_db import MongoDB +from application.core.mongo_db import MongoDB from application.core.settings import settings from application.parser.file.bulk import SimpleDirectoryReader from application.parser.open_ai_func import call_openai_api From fcb5f946dd676d3583587350a4db5e5c8403760a Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Tue, 22 Oct 2024 22:37:56 +0000 Subject: [PATCH 09/38] fixed according to suggestion Signed-off-by: JeevaRamanathan M --- frontend/src/Navigation.tsx | 10 ++++------ frontend/src/store.ts | 5 ++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index aa0b1a58..6050108e 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -11,7 +11,6 @@ import DocsGPT3 from './assets/cute_docsgpt3.svg'; import Discord from './assets/discord.svg'; import Expand from './assets/expand.svg'; import Github from './assets/github.svg'; -import Info from './assets/info.svg'; import SettingGear from './assets/settingGear.svg'; import Twitter from './assets/TwitterX.svg'; import UploadIcon from './assets/upload.svg'; @@ -44,7 +43,6 @@ import Spinner from './assets/spinner.svg'; import SpinnerDark from './assets/spinner-dark.svg'; import { selectQueries } from './conversation/conversationSlice'; import Upload from './upload/Upload'; -import ShareButton from './components/ShareButton'; import Help from './components/Help'; interface NavigationProps { @@ -314,14 +312,14 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { className="mb-auto h-[78vh] overflow-y-auto overflow-x-hidden dark:text-white" > {conversations?.loading && ( -
+
+ className="animate-spin cursor-pointer bg-transparent" + alt="Loading..." + />
)} - {conversations?.data && conversations.data.length > 0 ? (
diff --git a/frontend/src/store.ts b/frontend/src/store.ts index 565ea8cc..5843d493 100644 --- a/frontend/src/store.ts +++ b/frontend/src/store.ts @@ -23,7 +23,10 @@ const preloadedState: { preference: Preference } = { chunks: JSON.parse(chunks ?? '2').toString(), token_limit: token_limit ? parseInt(token_limit) : 2000, selectedDocs: doc !== null ? JSON.parse(doc) : null, - conversations: null, + conversations: { + data: null, + loading: false, + }, sourceDocs: [ { name: 'default', From 1e88c8637824ecdfee7210c2e5dd6333fdd796bf Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Tue, 22 Oct 2024 23:34:32 +0000 Subject: [PATCH 10/38] updated loader state Signed-off-by: JeevaRamanathan M --- frontend/src/Navigation.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/Navigation.tsx b/frontend/src/Navigation.tsx index 6050108e..cf9da2d1 100644 --- a/frontend/src/Navigation.tsx +++ b/frontend/src/Navigation.tsx @@ -72,6 +72,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { const conversations = useSelector(selectConversations); const modalStateDeleteConv = useSelector(selectModalStateDeleteConv); const conversationId = useSelector(selectConversationId); + const [isDeletingConversation, setIsDeletingConversation] = useState(false); const { isMobile } = useMediaQuery(); const [isDarkTheme] = useDarkTheme(); @@ -114,6 +115,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { } const handleDeleteAllConversations = () => { + setIsDeletingConversation(true); conversationService .deleteAll() .then(() => { @@ -123,6 +125,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { }; const handleDeleteConversation = (id: string) => { + setIsDeletingConversation(true); conversationService .delete(id, {}) .then(() => { @@ -311,7 +314,7 @@ export default function Navigation({ navOpen, setNavOpen }: NavigationProps) { id="conversationsMainDiv" className="mb-auto h-[78vh] overflow-y-auto overflow-x-hidden dark:text-white" > - {conversations?.loading && ( + {conversations?.loading && !isDeletingConversation && (
Date: Sat, 26 Oct 2024 03:29:54 +0530 Subject: [PATCH 11/38] Feature: Added Text-To-Speech Functionality --- frontend/src/assets/speaker.svg | 4 ++ frontend/src/assets/stopspeech.svg | 5 ++ .../src/components/TextToSpeechButton.tsx | 64 +++++++++++++++++++ .../src/conversation/ConversationBubble.tsx | 10 ++- 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 frontend/src/assets/speaker.svg create mode 100644 frontend/src/assets/stopspeech.svg create mode 100644 frontend/src/components/TextToSpeechButton.tsx diff --git a/frontend/src/assets/speaker.svg b/frontend/src/assets/speaker.svg new file mode 100644 index 00000000..ea947330 --- /dev/null +++ b/frontend/src/assets/speaker.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/stopspeech.svg b/frontend/src/assets/stopspeech.svg new file mode 100644 index 00000000..f77a235b --- /dev/null +++ b/frontend/src/assets/stopspeech.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/components/TextToSpeechButton.tsx b/frontend/src/components/TextToSpeechButton.tsx new file mode 100644 index 00000000..2ab7d1c2 --- /dev/null +++ b/frontend/src/components/TextToSpeechButton.tsx @@ -0,0 +1,64 @@ +import { useState } from 'react'; +import Speaker from '../assets/speaker.svg?react'; +import Stopspeech from '../assets/stopspeech.svg?react'; + +export default function SpeakButton({ + text, + colorLight, + colorDark, +}: { + text: string; + colorLight?: string; + colorDark?: string; +}) { + const [isSpeaking, setIsSpeaking] = useState(false); + const [isSpeakHovered, setIsSpeakHovered] = useState(false); + + const handleSpeakClick = (text: string) => { + if (isSpeaking) { + window.speechSynthesis.cancel(); + setIsSpeaking(false); + return; + } // Stop ongoing speech if already speaking + + const utterance = new SpeechSynthesisUtterance(text); + setIsSpeaking(true); + + utterance.onend = () => { + setIsSpeaking(false); // Reset when speech ends + }; + + utterance.onerror = () => { + console.error('Speech synthesis failed.'); + setIsSpeaking(false); + }; + + window.speechSynthesis.speak(utterance); + }; + + return ( +
+ {isSpeaking ? ( + handleSpeakClick(text)} + onMouseEnter={() => setIsSpeakHovered(true)} + onMouseLeave={() => setIsSpeakHovered(false)} + /> + ) : ( + handleSpeakClick(text)} + onMouseEnter={() => setIsSpeakHovered(true)} + onMouseLeave={() => setIsSpeakHovered(false)} + /> + )} +
+ ); +} diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx index 2ccf1ca3..a9a05168 100644 --- a/frontend/src/conversation/ConversationBubble.tsx +++ b/frontend/src/conversation/ConversationBubble.tsx @@ -7,7 +7,6 @@ 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'; @@ -23,6 +22,7 @@ import { } 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; @@ -336,6 +336,14 @@ const ConversationBubble = forwardRef<
+
+
+ {/* Add SpeakButton here */} +
+
{type === 'ERROR' && (
{retryBtn}
From 8564c2ba72b9f9b0c5cba6fc0902756021c40046 Mon Sep 17 00:00:00 2001 From: shatanikmahanty Date: Sat, 26 Oct 2024 22:00:22 +0530 Subject: [PATCH 12/38] Fix: Fonts on Safari browser --- frontend/src/index.css | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/index.css b/frontend/src/index.css index 1eca983c..fe9bec3f 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -4,6 +4,7 @@ :root { --viewport-height: 100vh; + font-synthesis: none !important; } @supports (height: 100dvh) { From 0aa9da39a9292d9f01bd438ea9ae3b1a397f6a17 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Sun, 27 Oct 2024 01:27:59 +0530 Subject: [PATCH 13/38] fix(isNoneDoc): empty doc assumed as default --- application/api/answer/routes.py | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/application/api/answer/routes.py b/application/api/answer/routes.py index 17eb5cc3..e05de123 100644 --- a/application/api/answer/routes.py +++ b/application/api/answer/routes.py @@ -269,9 +269,6 @@ class Stream(Resource): "prompt_id": fields.String( required=False, default="default", description="Prompt ID" ), - "selectedDocs": fields.String( - required=False, description="Selected documents" - ), "chunks": fields.Integer( required=False, default=2, description="Number of chunks" ), @@ -303,10 +300,9 @@ class Stream(Resource): history = json.loads(history) conversation_id = data.get("conversation_id") prompt_id = data.get("prompt_id", "default") - if "selectedDocs" in data and data["selectedDocs"] is None: - chunks = 0 - else: - chunks = int(data.get("chunks", 2)) + + + chunks = int(data.get("chunks", 2)) token_limit = data.get("token_limit", settings.DEFAULT_MAX_HISTORY) retriever_name = data.get("retriever", "classic") @@ -333,7 +329,8 @@ class Stream(Resource): ) prompt = get_prompt(prompt_id) - + if "isNoneDoc" in data and data["isNoneDoc"] is True: + chunks = 0 retriever = RetrieverCreator.create_retriever( retriever_name, question=question, From 45f930a9e2c2337aa23690b50a77357baad76869 Mon Sep 17 00:00:00 2001 From: Arnav Mahalpure <100768252+AranavMahalpure@users.noreply.github.com> Date: Sun, 27 Oct 2024 14:53:47 +0530 Subject: [PATCH 14/38] Update run-with-docker-compose.sh Source Environment Variables: source .env loads environment variables from the .env file, making them available within the script. Conditional Check for Azure Configuration: The if condition checks if all required Azure variables are set (non-empty). If they are, it runs Docker Compose with docker-compose-azure.yaml. Otherwise, it defaults to the standard configuration with docker-compose.yaml. Build and Run Services: Depending on the condition, the script either builds and runs services with Azure settings (docker-compose-azure.yaml) or the standard configuration (docker-compose.yaml). --- run-with-docker-compose.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/run-with-docker-compose.sh b/run-with-docker-compose.sh index 61aab467..145b1e23 100755 --- a/run-with-docker-compose.sh +++ b/run-with-docker-compose.sh @@ -4,8 +4,8 @@ source .env if [[ -n "$OPENAI_API_BASE" ]] && [[ -n "$OPENAI_API_VERSION" ]] && [[ -n "$AZURE_DEPLOYMENT_NAME" ]] && [[ -n "$AZURE_EMBEDDINGS_DEPLOYMENT_NAME" ]]; then echo "Running Azure Configuration" - docker compose -f docker-compose-azure.yaml build && docker compose -f docker-compose-azure.yaml up + docker compose -f docker-compose-azure.yaml up --build else echo "Running Plain Configuration" - docker compose build && docker compose up + docker compose up --build fi From 91690ff99affef6260628ee7f7b1d97ddea18abf Mon Sep 17 00:00:00 2001 From: Srayash <146334722+Srayash@users.noreply.github.com> Date: Sun, 27 Oct 2024 23:02:52 +0530 Subject: [PATCH 15/38] Resize speaker icon. --- frontend/src/assets/speaker.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/assets/speaker.svg b/frontend/src/assets/speaker.svg index ea947330..6c379177 100644 --- a/frontend/src/assets/speaker.svg +++ b/frontend/src/assets/speaker.svg @@ -1,4 +1,4 @@ - + From fcb6bec4746314244d9abca42e97cf7949ec2a3e Mon Sep 17 00:00:00 2001 From: Srayash <146334722+Srayash@users.noreply.github.com> Date: Mon, 28 Oct 2024 02:52:13 +0530 Subject: [PATCH 16/38] Update TextToSpeechButton.tsx --- .../src/components/TextToSpeechButton.tsx | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/frontend/src/components/TextToSpeechButton.tsx b/frontend/src/components/TextToSpeechButton.tsx index 2ab7d1c2..cc062c87 100644 --- a/frontend/src/components/TextToSpeechButton.tsx +++ b/frontend/src/components/TextToSpeechButton.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import Speaker from '../assets/speaker.svg?react'; import Stopspeech from '../assets/stopspeech.svg?react'; +import EasySpeech from 'easy-speech'; export default function SpeakButton({ text, @@ -14,26 +15,28 @@ export default function SpeakButton({ const [isSpeaking, setIsSpeaking] = useState(false); const [isSpeakHovered, setIsSpeakHovered] = useState(false); - const handleSpeakClick = (text: string) => { + const handleSpeakClick = async (text: string) => { if (isSpeaking) { - window.speechSynthesis.cancel(); + EasySpeech.cancel(); setIsSpeaking(false); return; } // Stop ongoing speech if already speaking - const utterance = new SpeechSynthesisUtterance(text); - setIsSpeaking(true); - - utterance.onend = () => { - setIsSpeaking(false); // Reset when speech ends - }; - - utterance.onerror = () => { - console.error('Speech synthesis failed.'); - setIsSpeaking(false); - }; - - window.speechSynthesis.speak(utterance); + try { + await EasySpeech.init(); // Initialize EasySpeech + setIsSpeaking(true); + + EasySpeech.speak({ + text, + onend: () => setIsSpeaking(false), // Reset when speech ends + onerror: () => { + console.error('Speech synthesis failed.'); + setIsSpeaking(false); + }, + }); + } catch (error) { + console.error('Failed to initialize speech synthesis', error); + } }; return ( From 6978e7439f9039b8c8cfe1f201b6d40e131db089 Mon Sep 17 00:00:00 2001 From: Srayash <146334722+Srayash@users.noreply.github.com> Date: Mon, 28 Oct 2024 02:53:07 +0530 Subject: [PATCH 17/38] Update package-lock.json --- frontend/package-lock.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 4087e4f5..37bf0c07 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", + "easy-speech": "^2.4.0", "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "prop-types": "^15.8.1", @@ -3075,6 +3076,24 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/easy-speech": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/easy-speech/-/easy-speech-2.4.0.tgz", + "integrity": "sha512-wpMv29DEoeP/eyXr4aXpDqd9DvlXl7aQs7BgfKbjGVxqkmQPgNmpbF5YULaTH5bc/5qrteg5MDfCD2Zd0qr4rQ==", + "funding": [ + { + "type": "GitHub", + "url": "https://github.com/sponsors/jankapunkt" + }, + { + "type": "PayPal", + "url": "https://paypal.me/kuesterjan" + } + ], + "engines": { + "node": ">= 14.x" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.11", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.11.tgz", From 0b1a3029959384df00fff0b5e0bce78c0fc52b94 Mon Sep 17 00:00:00 2001 From: Srayash <146334722+Srayash@users.noreply.github.com> Date: Mon, 28 Oct 2024 02:53:51 +0530 Subject: [PATCH 18/38] Update package.json --- frontend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/package.json b/frontend/package.json index 83d531d6..9148831f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,6 +21,7 @@ "dependencies": { "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", + "easy-speech": "^2.4.0", "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "prop-types": "^15.8.1", From 18ed255f5a8488a0dcba441dceea0767d563dcb0 Mon Sep 17 00:00:00 2001 From: kom-senapati Date: Mon, 28 Oct 2024 19:30:38 +0530 Subject: [PATCH 19/38] fix: import settings object of Settings class in mongo_db.py --- application/core/mongo_db.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/core/mongo_db.py b/application/core/mongo_db.py index a29ca5d6..52006aa7 100644 --- a/application/core/mongo_db.py +++ b/application/core/mongo_db.py @@ -1,4 +1,4 @@ -from application.core.settings import Settings +from application.core.settings import settings from pymongo import MongoClient @@ -11,7 +11,7 @@ class MongoDB: Get the MongoDB client instance, creating it if necessary. """ if cls._client is None: - cls._client = MongoClient(Settings.MONGO_URI) + cls._client = MongoClient(settings.MONGO_URI) return cls._client @classmethod From 997243552527cfa14abd34df53912b581b390c65 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:07:25 +0000 Subject: [PATCH 20/38] build(deps): bump docker/build-push-action from 4 to 6 Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 4 to 6. - [Release notes](https://github.com/docker/build-push-action/releases) - [Commits](https://github.com/docker/build-push-action/compare/v4...v6) --- updated-dependencies: - dependency-name: docker/build-push-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- .github/workflows/cife.yml | 2 +- .github/workflows/docker-develop-build.yml | 2 +- .github/workflows/docker-develop-fe-build.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be0263ff..0eeae15f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images to docker.io and ghcr.io - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: file: './application/Dockerfile' platforms: linux/amd64 diff --git a/.github/workflows/cife.yml b/.github/workflows/cife.yml index 4b1cbf3b..67b02fc1 100644 --- a/.github/workflows/cife.yml +++ b/.github/workflows/cife.yml @@ -35,7 +35,7 @@ jobs: # Runs a single command using the runners shell - name: Build and push Docker images to docker.io and ghcr.io - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: file: './frontend/Dockerfile' platforms: linux/amd64, linux/arm64 diff --git a/.github/workflows/docker-develop-build.yml b/.github/workflows/docker-develop-build.yml index 0bfc7e70..dd183a58 100644 --- a/.github/workflows/docker-develop-build.yml +++ b/.github/workflows/docker-develop-build.yml @@ -36,7 +36,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images to docker.io and ghcr.io - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: file: './application/Dockerfile' platforms: linux/amd64 diff --git a/.github/workflows/docker-develop-fe-build.yml b/.github/workflows/docker-develop-fe-build.yml index 14dbccc5..7088c5b6 100644 --- a/.github/workflows/docker-develop-fe-build.yml +++ b/.github/workflows/docker-develop-fe-build.yml @@ -36,7 +36,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push Docker images to docker.io and ghcr.io - uses: docker/build-push-action@v4 + uses: docker/build-push-action@v6 with: file: './frontend/Dockerfile' platforms: linux/amd64 From c83ff2237cfeb9b4edad10576c907c738f3161cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:07:26 +0000 Subject: [PATCH 21/38] build(deps): bump docker/setup-qemu-action from 1 to 3 Bumps [docker/setup-qemu-action](https://github.com/docker/setup-qemu-action) from 1 to 3. - [Release notes](https://github.com/docker/setup-qemu-action/releases) - [Commits](https://github.com/docker/setup-qemu-action/compare/v1...v3) --- updated-dependencies: - dependency-name: docker/setup-qemu-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/ci.yml | 2 +- .github/workflows/cife.yml | 2 +- .github/workflows/docker-develop-build.yml | 2 +- .github/workflows/docker-develop-fe-build.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index be0263ff..402a6ddb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/cife.yml b/.github/workflows/cife.yml index 4b1cbf3b..9034be9d 100644 --- a/.github/workflows/cife.yml +++ b/.github/workflows/cife.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/docker-develop-build.yml b/.github/workflows/docker-develop-build.yml index 0bfc7e70..067dfaf5 100644 --- a/.github/workflows/docker-develop-build.yml +++ b/.github/workflows/docker-develop-build.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 diff --git a/.github/workflows/docker-develop-fe-build.yml b/.github/workflows/docker-develop-fe-build.yml index 14dbccc5..99a2252c 100644 --- a/.github/workflows/docker-develop-fe-build.yml +++ b/.github/workflows/docker-develop-fe-build.yml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@v4 - name: Set up QEMU - uses: docker/setup-qemu-action@v1 + uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 From 331dfdbab4e7e47ef6957b13aaa2be60f2250212 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Oct 2024 21:07:28 +0000 Subject: [PATCH 22/38] build(deps): bump actions/labeler from 4 to 5 Bumps [actions/labeler](https://github.com/actions/labeler) from 4 to 5. - [Release notes](https://github.com/actions/labeler/releases) - [Commits](https://github.com/actions/labeler/compare/v4...v5) --- updated-dependencies: - dependency-name: actions/labeler dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 7bdbab64..74b9d7d5 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -10,7 +10,7 @@ jobs: pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v4 + - uses: actions/labeler@v5 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" sync-labels: true From 7ff3a31e72258f7207e8afdef84e777d54aa3a54 Mon Sep 17 00:00:00 2001 From: ManishMadan2882 Date: Tue, 29 Oct 2024 03:11:51 +0530 Subject: [PATCH 23/38] (feat:TTS) create gtts over abstraction --- application/api/user/routes.py | 25 +++++++++++++++++++++++++ application/requirements.txt | 1 + application/tts/base.py | 10 ++++++++++ application/tts/google_tts.py | 19 +++++++++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 application/tts/base.py create mode 100644 application/tts/google_tts.py diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 3f1a7218..794c69d4 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -17,6 +17,7 @@ from application.core.settings import settings from application.extensions import api from application.utils import check_required_fields from application.vectorstore.vector_creator import VectorCreator +from application.tts.google_tts import GoogleTTS mongo = MongoClient(settings.MONGO_URI) db = mongo["docsgpt"] @@ -1663,3 +1664,27 @@ class ManageSync(Resource): return make_response(jsonify({"success": False, "error": str(err)}), 400) return make_response(jsonify({"success": True}), 200) + + +@user_ns.route("/api/tts") +class TextToSpeech(Resource): + tts_model = api.model( + "TextToSpeechModel", + { + "text": fields.String(required=True, description="Text to be synthesized as audio"), + }, + ) + + @api.expect(tts_model) + @api.doc(description="Synthesize audio speech from text") + def post(self): + data = request.get_json() + text = data["text"] + try: + tts_instance = GoogleTTS(text) + audio_base64, detected_language = tts_instance.text_to_speech() + return make_response(jsonify({"success": True,'audio_base64': audio_base64,'lang':detected_language}), 200) + except Exception as err: + return make_response(jsonify({"success": False, "error": str(err)}), 400) + + diff --git a/application/requirements.txt b/application/requirements.txt index 6ea1d1ba..aad629f1 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -85,3 +85,4 @@ vine==5.1.0 wcwidth==0.2.13 werkzeug==3.0.4 yarl==1.11.1 +gTTS==2.3.2 \ No newline at end of file diff --git a/application/tts/base.py b/application/tts/base.py new file mode 100644 index 00000000..143bed73 --- /dev/null +++ b/application/tts/base.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod + + +class BaseTTS(ABC): + def __init__(self): + pass + + @abstractmethod + def text_to_speech(self, *args, **kwargs): + pass \ No newline at end of file diff --git a/application/tts/google_tts.py b/application/tts/google_tts.py new file mode 100644 index 00000000..310309dc --- /dev/null +++ b/application/tts/google_tts.py @@ -0,0 +1,19 @@ +import io +import base64 +from gtts import gTTS +from application.tts.base import BaseTTS + + +class GoogleTTS(BaseTTS): + def __init__(self, text): + self.text = text + + + def text_to_speech(self): + lang = "en" + audio_fp = io.BytesIO() + tts = gTTS(text=self.text, lang=lang, slow=False) + tts.write_to_fp(audio_fp) + audio_fp.seek(0) + audio_base64 = base64.b64encode(audio_fp.read()).decode("utf-8") + return audio_base64, lang From b223cf05d93be450b15c0a6dfc6c233d47717a13 Mon Sep 17 00:00:00 2001 From: Srayash Date: Tue, 29 Oct 2024 23:36:09 +0530 Subject: [PATCH 24/38] use /api/tts endpoint for TTS feature --- .../src/components/TextToSpeechButton.tsx | 52 +++++++++++++------ 1 file changed, 35 insertions(+), 17 deletions(-) diff --git a/frontend/src/components/TextToSpeechButton.tsx b/frontend/src/components/TextToSpeechButton.tsx index cc062c87..b5402469 100644 --- a/frontend/src/components/TextToSpeechButton.tsx +++ b/frontend/src/components/TextToSpeechButton.tsx @@ -1,7 +1,7 @@ -import { useState } from 'react'; +import { useState, useRef } from 'react'; import Speaker from '../assets/speaker.svg?react'; import Stopspeech from '../assets/stopspeech.svg?react'; -import EasySpeech from 'easy-speech'; +const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; export default function SpeakButton({ text, @@ -14,28 +14,46 @@ export default function SpeakButton({ }) { const [isSpeaking, setIsSpeaking] = useState(false); const [isSpeakHovered, setIsSpeakHovered] = useState(false); + const audioRef = useRef(null); // Reference to the audio object - const handleSpeakClick = async (text: string) => { + const handleSpeakClick = async () => { if (isSpeaking) { - EasySpeech.cancel(); + // Stop audio if currently playing and reset the state + audioRef.current?.pause(); + audioRef.current = null; setIsSpeaking(false); return; - } // Stop ongoing speech if already speaking + } try { - await EasySpeech.init(); // Initialize EasySpeech setIsSpeaking(true); - - EasySpeech.speak({ - text, - onend: () => setIsSpeaking(false), // Reset when speech ends - onerror: () => { - console.error('Speech synthesis failed.'); - setIsSpeaking(false); - }, + + // Make a POST request to the /api/tts endpoint + const response = await fetch(apiHost + '/api/tts', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ text }), }); + + const data = await response.json(); + + if (data.success && data.audio_base64) { + const audio = new Audio(`data:audio/mp3;base64,${data.audio_base64}`); + audioRef.current = audio; // Store the audio object in ref for later control + audio.play(); + + // Reset state when audio ends + audio.onended = () => { + setIsSpeaking(false); + audioRef.current = null; + }; + } else { + console.error('Failed to retrieve audio.'); + setIsSpeaking(false); + } } catch (error) { - console.error('Failed to initialize speech synthesis', error); + console.error('Error fetching audio from TTS endpoint', error); + setIsSpeaking(false); } }; @@ -50,14 +68,14 @@ export default function SpeakButton({ {isSpeaking ? ( handleSpeakClick(text)} + onClick={handleSpeakClick} onMouseEnter={() => setIsSpeakHovered(true)} onMouseLeave={() => setIsSpeakHovered(false)} /> ) : ( handleSpeakClick(text)} + onClick={handleSpeakClick} onMouseEnter={() => setIsSpeakHovered(true)} onMouseLeave={() => setIsSpeakHovered(false)} /> From 605f168c7ef834f733bdeb461e9ad56c28404d4f Mon Sep 17 00:00:00 2001 From: Srayash Date: Tue, 29 Oct 2024 23:51:25 +0530 Subject: [PATCH 25/38] remove unused modules (easy-speech) --- frontend/package-lock.json | 1 - frontend/package.json | 1 - 2 files changed, 2 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 37bf0c07..9973bb9e 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10,7 +10,6 @@ "dependencies": { "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", - "easy-speech": "^2.4.0", "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "prop-types": "^15.8.1", diff --git a/frontend/package.json b/frontend/package.json index 9148831f..83d531d6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -21,7 +21,6 @@ "dependencies": { "@reduxjs/toolkit": "^2.2.7", "chart.js": "^4.4.4", - "easy-speech": "^2.4.0", "i18next": "^23.15.1", "i18next-browser-languagedetector": "^8.0.0", "prop-types": "^15.8.1", From 5c99615edf373bef3b50c1c188064ca7979864fc Mon Sep 17 00:00:00 2001 From: Srayash Date: Wed, 30 Oct 2024 00:03:08 +0530 Subject: [PATCH 26/38] UI changes: add loading animation while audio response is being fetched --- frontend/src/assets/Loading.svg | 3 ++ .../src/components/TextToSpeechButton.tsx | 37 ++++++++++++------- 2 files changed, 26 insertions(+), 14 deletions(-) create mode 100644 frontend/src/assets/Loading.svg diff --git a/frontend/src/assets/Loading.svg b/frontend/src/assets/Loading.svg new file mode 100644 index 00000000..84a604f9 --- /dev/null +++ b/frontend/src/assets/Loading.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/components/TextToSpeechButton.tsx b/frontend/src/components/TextToSpeechButton.tsx index b5402469..2cb9e8f8 100644 --- a/frontend/src/components/TextToSpeechButton.tsx +++ b/frontend/src/components/TextToSpeechButton.tsx @@ -1,6 +1,7 @@ import { useState, useRef } from 'react'; import Speaker from '../assets/speaker.svg?react'; import Stopspeech from '../assets/stopspeech.svg?react'; +import LoadingIcon from '../assets/Loading.svg?react'; // Add a loading icon SVG here const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; export default function SpeakButton({ @@ -13,12 +14,13 @@ export default function SpeakButton({ colorDark?: string; }) { const [isSpeaking, setIsSpeaking] = useState(false); + const [isLoading, setIsLoading] = useState(false); const [isSpeakHovered, setIsSpeakHovered] = useState(false); - const audioRef = useRef(null); // Reference to the audio object + const audioRef = useRef(null); const handleSpeakClick = async () => { if (isSpeaking) { - // Stop audio if currently playing and reset the state + // Stop audio if it's currently playing audioRef.current?.pause(); audioRef.current = null; setIsSpeaking(false); @@ -26,9 +28,9 @@ export default function SpeakButton({ } try { - setIsSpeaking(true); + // Set loading state and initiate TTS request + setIsLoading(true); - // Make a POST request to the /api/tts endpoint const response = await fetch(apiHost + '/api/tts', { method: 'POST', headers: { 'Content-Type': 'application/json' }, @@ -38,22 +40,27 @@ export default function SpeakButton({ const data = await response.json(); if (data.success && data.audio_base64) { + // Create and play the audio const audio = new Audio(`data:audio/mp3;base64,${data.audio_base64}`); - audioRef.current = audio; // Store the audio object in ref for later control - audio.play(); + audioRef.current = audio; - // Reset state when audio ends - audio.onended = () => { - setIsSpeaking(false); - audioRef.current = null; - }; + audio.play().then(() => { + setIsSpeaking(true); + setIsLoading(false); + + // Reset when audio ends + audio.onended = () => { + setIsSpeaking(false); + audioRef.current = null; + }; + }); } else { console.error('Failed to retrieve audio.'); - setIsSpeaking(false); + setIsLoading(false); } } catch (error) { console.error('Error fetching audio from TTS endpoint', error); - setIsSpeaking(false); + setIsLoading(false); } }; @@ -65,7 +72,9 @@ export default function SpeakButton({ : `bg-[${colorLight ? colorLight : '#FFFFFF'}] dark:bg-[${colorDark ? colorDark : 'transparent'}]` }`} > - {isSpeaking ? ( + {isLoading ? ( + + ) : isSpeaking ? ( Date: Wed, 30 Oct 2024 12:59:28 +0000 Subject: [PATCH 27/38] fix: discord bot --- extensions/discord/bot.py | 128 +++++++++++++++++++++++++++++--------- 1 file changed, 99 insertions(+), 29 deletions(-) diff --git a/extensions/discord/bot.py b/extensions/discord/bot.py index 3cb1d1e2..9e2eee67 100644 --- a/extensions/discord/bot.py +++ b/extensions/discord/bot.py @@ -1,25 +1,39 @@ import os import re - +import logging +import aiohttp import discord -import requests from discord.ext import commands import dotenv dotenv.load_dotenv() -# Replace 'YOUR_BOT_TOKEN' with your bot's token +# Enable logging +logging.basicConfig(level=logging.INFO) +logger = logging.getLogger(__name__) + +# Bot configuration TOKEN = os.getenv("DISCORD_TOKEN") -PREFIX = '@DocsGPT' -BASE_API_URL = 'http://localhost:7091' +PREFIX = '!' # Command prefix +BASE_API_URL = os.getenv("API_BASE", "https://gptcloud.arc53.com") +API_URL = BASE_API_URL + "/api/answer" +API_KEY = os.getenv("API_KEY") intents = discord.Intents.default() intents.message_content = True bot = commands.Bot(command_prefix=PREFIX, intents=intents) +# Store conversation history per user +conversation_histories = {} + +def escape_markdown(text): + """Escapes Discord markdown characters.""" + escape_chars = r'\*_$$$$()~>#+-=|{}.!' + return re.sub(f'([{re.escape(escape_chars)}])', r'\\\1', text) def split_string(input_str): + """Splits the input string to detect bot mentions.""" pattern = r'^<@!?{0}>\s*'.format(bot.user.id) match = re.match(pattern, input_str) if match: @@ -27,42 +41,98 @@ def split_string(input_str): return str(bot.user.id), content return None, input_str - @bot.event async def on_ready(): print(f'{bot.user.name} has connected to Discord!') - -async def fetch_answer(question): - data = { - 'sender': 'discord', - 'question': question, - 'history': '' +async def generate_answer(question, messages, conversation_id): + """Generates an answer using the external API.""" + payload = { + "question": question, + "api_key": API_KEY, + "history": messages, + "conversation_id": conversation_id } - headers = {"Content-Type": "application/json", - "Accept": "application/json"} - response = requests.post(BASE_API_URL + '/api/answer', json=data, headers=headers) - if response.status_code == 200: - return response.json()['answer'] - return 'Sorry, I could not fetch the answer.' + headers = { + "Content-Type": "application/json; charset=utf-8" + } + timeout = aiohttp.ClientTimeout(total=60) + async with aiohttp.ClientSession(timeout=timeout) as session: + async with session.post(API_URL, json=payload, headers=headers) as resp: + if resp.status == 200: + data = await resp.json() + conversation_id = data.get("conversation_id") + answer = data.get("answer", "Sorry, I couldn't find an answer.") + return {"answer": answer, "conversation_id": conversation_id} + else: + return {"answer": "Sorry, I couldn't find an answer.", "conversation_id": None} +@bot.command(name="start") +async def start(ctx): + """Handles the /start command.""" + await ctx.send(f"Hi {ctx.author.mention}! How can I assist you today?") + +@bot.command(name="custom_help") +async def custom_help_command(ctx): + """Handles the /custom_help command.""" + help_text = ( + "Here are the available commands:\n" + "`!start` - Begin a new conversation with the bot\n" + "`!help` - Display this help message\n\n" + "You can also mention me or send a direct message to ask a question!" + ) + await ctx.send(help_text) @bot.event async def on_message(message): if message.author == bot.user: return - content = message.content.strip() - prefix, content = split_string(content) - if prefix is None: - return - - part_prefix = str(bot.user.id) - if part_prefix == prefix: - answer = await fetch_answer(content) - await message.channel.send(answer) - + # Process commands first await bot.process_commands(message) + # Check if the message is in a DM channel + if isinstance(message.channel, discord.DMChannel): + content = message.content.strip() + else: + # In guild channels, check if the message mentions the bot at the start + content = message.content.strip() + prefix, content = split_string(content) + if prefix is None: + return + part_prefix = str(bot.user.id) + if part_prefix != prefix: + return # Bot not mentioned at the start, so do not process -bot.run(TOKEN) + # Now process the message + user_id = message.author.id + if user_id not in conversation_histories: + conversation_histories[user_id] = { + "history": [], + "conversation_id": None + } + + conversation = conversation_histories[user_id] + conversation["history"].append({"prompt": content}) + + # Generate the answer + response_doc = await generate_answer( + content, + conversation["history"], + conversation["conversation_id"] + ) + answer = response_doc["answer"] + conversation_id = response_doc["conversation_id"] + + # Escape markdown characters + answer = escape_markdown(answer) + + await message.channel.send(answer) + + conversation["history"][-1]["response"] = answer + conversation["conversation_id"] = conversation_id + + # Keep conversation history to last 10 exchanges + conversation["history"] = conversation["history"][-10:] + +bot.run(TOKEN) \ No newline at end of file From 06e4a05e419bab9d5e8cb1169f6006ba035af0ed Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 30 Oct 2024 15:17:37 +0000 Subject: [PATCH 28/38] fix: slightly better discord bot formatting --- extensions/discord/bot.py | 1 - 1 file changed, 1 deletion(-) diff --git a/extensions/discord/bot.py b/extensions/discord/bot.py index 9e2eee67..7ebef2ea 100644 --- a/extensions/discord/bot.py +++ b/extensions/discord/bot.py @@ -125,7 +125,6 @@ async def on_message(message): conversation_id = response_doc["conversation_id"] # Escape markdown characters - answer = escape_markdown(answer) await message.channel.send(answer) From 2cc3372b86820e9c30ef51813ddac1d22083de86 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 30 Oct 2024 15:27:14 +0000 Subject: [PATCH 29/38] fix: bot chunking --- extensions/discord/bot.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/extensions/discord/bot.py b/extensions/discord/bot.py index 7ebef2ea..94daf7e2 100644 --- a/extensions/discord/bot.py +++ b/extensions/discord/bot.py @@ -27,6 +27,27 @@ bot = commands.Bot(command_prefix=PREFIX, intents=intents) # Store conversation history per user conversation_histories = {} +def chunk_string(text, max_length=2000): + """Splits a string into chunks of a specified maximum length.""" + # Create list to store the split strings + chunks = [] + # Loop through the text, create substrings with max_length + while len(text) > max_length: + # Find last space within the limit + idx = text.rfind(' ', 0, max_length) + # Ensure we don't have an empty part + if idx == -1: + # If no spaces, just take chunk + chunks.append(text[:max_length]) + text = text[max_length:] + else: + # Push whatever we've got up to the last space + chunks.append(text[:idx]) + text = text[idx+1:] + # Catches the remaining part + chunks.append(text) + return chunks + def escape_markdown(text): """Escapes Discord markdown characters.""" escape_chars = r'\*_$$$$()~>#+-=|{}.!' @@ -124,9 +145,9 @@ async def on_message(message): answer = response_doc["answer"] conversation_id = response_doc["conversation_id"] - # Escape markdown characters - - await message.channel.send(answer) + answer_chunks = chunk_string(answer) + for chunk in answer_chunks: + await message.channel.send(chunk) conversation["history"][-1]["response"] = answer conversation["conversation_id"] = conversation_id From 23889f7f16cec76cc0407ba959d5d24c9093d584 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 11:32:17 +0000 Subject: [PATCH 30/38] Minor word change --- frontend/src/locale/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index cefb99b7..4e1da2d2 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -12,7 +12,7 @@ "cancel": "Cancel", "help": "Help", "emailUs": "Email us", - "documentation": "documentation", + "documentation": "Documentation", "demo": [ { "header": "Learn about DocsGPT", From 82189b0a3c54851692a8c4dd2d665f90539094a2 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 11:32:39 +0000 Subject: [PATCH 31/38] capitalisation --- frontend/src/locale/es.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 66b457e8..8cb0ff1d 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -12,7 +12,7 @@ "cancel": "Cancelar", "help": "Asistencia", "emailUs": "Envíanos un correo", - "documentation": "documentación", + "documentation": "Documentación", "demo": [ { "header": "Aprende sobre DocsGPT", From 5c756348a545167bbe5b46a28acafa4bcc541d7e Mon Sep 17 00:00:00 2001 From: JeevaRamanathan M Date: Thu, 31 Oct 2024 11:47:12 +0000 Subject: [PATCH 32/38] feat: Presentation parser implementation Signed-off-by: JeevaRamanathan M --- application/api/user/routes.py | 1 + application/parser/file/bulk.py | 2 + application/parser/file/pptx_parser.py | 75 ++++++++++++++++++++++++++ application/requirements.txt | 5 +- frontend/src/locale/en.json | 2 +- frontend/src/locale/es.json | 2 +- frontend/src/locale/jp.json | 2 +- frontend/src/locale/zh-TW.json | 2 +- frontend/src/locale/zh.json | 2 +- frontend/src/upload/Upload.tsx | 2 + 10 files changed, 88 insertions(+), 7 deletions(-) create mode 100644 application/parser/file/pptx_parser.py diff --git a/application/api/user/routes.py b/application/api/user/routes.py index 794c69d4..84a67863 100644 --- a/application/api/user/routes.py +++ b/application/api/user/routes.py @@ -343,6 +343,7 @@ class UploadFile(Resource): ".mdx", ".json", ".xlsx", + ".pptx", ], job_name, final_filename, diff --git a/application/parser/file/bulk.py b/application/parser/file/bulk.py index bb63aa61..3b8fbca8 100644 --- a/application/parser/file/bulk.py +++ b/application/parser/file/bulk.py @@ -12,6 +12,7 @@ from application.parser.file.markdown_parser import MarkdownParser from application.parser.file.rst_parser import RstParser from application.parser.file.tabular_parser import PandasCSVParser,ExcelParser from application.parser.file.json_parser import JSONParser +from application.parser.file.pptx_parser import PPTXParser from application.parser.schema.base import Document DEFAULT_FILE_EXTRACTOR: Dict[str, BaseParser] = { @@ -25,6 +26,7 @@ DEFAULT_FILE_EXTRACTOR: Dict[str, BaseParser] = { ".html": HTMLParser(), ".mdx": MarkdownParser(), ".json":JSONParser(), + ".pptx":PPTXParser(), } diff --git a/application/parser/file/pptx_parser.py b/application/parser/file/pptx_parser.py new file mode 100644 index 00000000..00cb3698 --- /dev/null +++ b/application/parser/file/pptx_parser.py @@ -0,0 +1,75 @@ +"""PPT parser. +Contains parsers for presentation (.pptx) files to extract slide text. +""" +from pathlib import Path +from typing import Any, Dict, List, Union + +from application.parser.file.base_parser import BaseParser + +class PPTXParser(BaseParser): + r"""PPTX (.pptx) parser for extracting text from PowerPoint slides. + Args: + concat_slides (bool): Specifies whether to concatenate all slide text into one document. + - If True, slide texts will be joined together as a single string. + - If False, each slide's text will be stored as a separate entry in a list. + Set to True by default. + slide_separator (str): Separator used to join slides' text content. + Only used when `concat_slides=True`. Default is "\n". + Refer to https://python-pptx.readthedocs.io/en/latest/ for more information. + """ + + def __init__( + self, + *args: Any, + concat_slides: bool = True, + slide_separator: str = "\n", + **kwargs: Any + ) -> None: + """Init params.""" + super().__init__(*args, **kwargs) + self._concat_slides = concat_slides + self._slide_separator = slide_separator + + def _init_parser(self) -> Dict: + """Init parser.""" + return {} + + def parse_file(self, file: Path, errors: str = "ignore") -> Union[str, List[str]]: + r""" + Parse a .pptx file and extract text from each slide. + Args: + file (Path): Path to the .pptx file. + errors (str): Error handling policy ('ignore' by default). + Returns: + Union[str, List[str]]: Concatenated text if concat_slides is True, + otherwise a list of slide texts. + """ + + try: + from pptx import Presentation + except ImportError: + raise ImportError("pptx module is required to read .PPTX files.") + + try: + presentation = Presentation(file) + slide_texts=[] + + # Iterate over each slide in the presentation + for slide in presentation.slides: + slide_text="" + + # Iterate over each shape in the slide + for shape in slide.shapes: + # Check if the shape has a 'text' attribute and append that to the slide_text + if hasattr(shape,"text"): + slide_text+=shape.text + + slide_texts.append(slide_text.strip()) + + if self._concat_slides: + return self._slide_separator.join(slide_texts) + else: + return slide_texts + + except Exception as e: + raise e \ No newline at end of file diff --git a/application/requirements.txt b/application/requirements.txt index aad629f1..5325a849 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -14,6 +14,7 @@ esutils==1.0.1 Flask==3.0.3 faiss-cpu==1.8.0.post1 flask-restx==1.3.0 +gTTS==2.3.2 gunicorn==23.0.0 html2text==2024.2.26 javalang==0.13.0 @@ -65,6 +66,7 @@ pymongo==4.8.0 pypdf2==3.0.1 python-dateutil==2.9.0.post0 python-dotenv==1.0.1 +python-pptx==0.4.1 qdrant-client==1.11.0 redis==5.0.1 referencing==0.30.2 @@ -84,5 +86,4 @@ urllib3==2.2.3 vine==5.1.0 wcwidth==0.2.13 werkzeug==3.0.4 -yarl==1.11.1 -gTTS==2.3.2 \ No newline at end of file +yarl==1.11.1 \ No newline at end of file diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index a1f254ac..52d3b50e 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -86,7 +86,7 @@ "start": "Start Chatting", "name": "Name", "choose": "Choose Files", - "info": "Please upload .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .zip limited to 25mb", + "info": "Please upload .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip limited to 25mb", "uploadedFiles": "Uploaded Files", "cancel": "Cancel", "train": "Train", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 6a096ffd..44fafed7 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -86,7 +86,7 @@ "start": "Empezar a chatear", "name": "Nombre", "choose": "Seleccionar Archivos", - "info": "Por favor, suba archivos .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .zip limitados a 25 MB", + "info": "Por favor, suba archivos .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip limitados a 25 MB", "uploadedFiles": "Archivos Subidos", "cancel": "Cancelar", "train": "Entrenar", diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index 841a477b..a69ae31f 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -86,7 +86,7 @@ "start": "チャットを開始する", "name": "名前", "choose": "ファイルを選択", - "info": ".pdf, .txt, .rst, .docx, .md, .json, .zipファイルを25MBまでアップロードしてください", + "info": ".pdf, .txt, .rst, .docx, .md, .json, .pptx, .zipファイルを25MBまでアップロードしてください", "uploadedFiles": "アップロードされたファイル", "cancel": "キャンセル", "train": "トレーニング", diff --git a/frontend/src/locale/zh-TW.json b/frontend/src/locale/zh-TW.json index 35df818b..fa0638f4 100644 --- a/frontend/src/locale/zh-TW.json +++ b/frontend/src/locale/zh-TW.json @@ -80,7 +80,7 @@ "remote": "遠端", "name": "名稱", "choose": "選擇檔案", - "info": "請上傳 .pdf, .txt, .rst, .docx, .md, .json, .zip 檔案,大小限制為 25MB", + "info": "請上傳 .pdf, .txt, .rst, .docx, .md, .json, .pptx, .zip 檔案,大小限制為 25MB", "uploadedFiles": "已上傳的檔案", "cancel": "取消", "train": "訓練", diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json index 710c5e3e..51f8bfe9 100644 --- a/frontend/src/locale/zh.json +++ b/frontend/src/locale/zh.json @@ -86,7 +86,7 @@ "start": "开始聊天", "name": "名称", "choose": "选择文件", - "info": "请上传 .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .zip 文件,限 25MB", + "info": "请上传 .pdf, .txt, .rst, .csv, .xlsx, .docx, .md, .html, .epub, .json, .pptx, .zip 文件,限 25MB", "uploadedFiles": "已上传文件", "cancel": "取消", "train": "训练", diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index 2da284c3..81ce9f2b 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -321,6 +321,8 @@ function Upload({ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': [ '.xlsx', ], + 'application/vnd.openxmlformats-officedocument.presentationml.presentation': + ['.pptx'], }, }); From 78c819f976fc534224b4aaee88d4a6f7dac3b1e4 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 17:33:09 +0000 Subject: [PATCH 33/38] fix: history bug --- application/retriever/brave_search.py | 1 - application/retriever/classic_rag.py | 2 -- application/retriever/duckduck_search.py | 1 - 3 files changed, 4 deletions(-) diff --git a/application/retriever/brave_search.py b/application/retriever/brave_search.py index 29666a57..1fd844b2 100644 --- a/application/retriever/brave_search.py +++ b/application/retriever/brave_search.py @@ -75,7 +75,6 @@ class BraveRetSearch(BaseRetriever): if len(self.chat_history) > 1: tokens_current_history = 0 # count tokens in history - self.chat_history.reverse() for i in self.chat_history: if "prompt" in i and "response" in i: tokens_batch = num_tokens_from_string(i["prompt"]) + num_tokens_from_string( diff --git a/application/retriever/classic_rag.py b/application/retriever/classic_rag.py index b87b5852..6a67cb38 100644 --- a/application/retriever/classic_rag.py +++ b/application/retriever/classic_rag.py @@ -78,7 +78,6 @@ class ClassicRAG(BaseRetriever): if len(self.chat_history) > 1: tokens_current_history = 0 # count tokens in history - self.chat_history.reverse() for i in self.chat_history: if "prompt" in i and "response" in i: tokens_batch = num_tokens_from_string(i["prompt"]) + num_tokens_from_string( @@ -97,7 +96,6 @@ class ClassicRAG(BaseRetriever): llm = LLMCreator.create_llm( settings.LLM_NAME, api_key=settings.API_KEY, user_api_key=self.user_api_key ) - completion = llm.gen_stream(model=self.gpt_model, messages=messages_combine) for line in completion: yield {"answer": str(line)} diff --git a/application/retriever/duckduck_search.py b/application/retriever/duckduck_search.py index d746ecaa..6ae56226 100644 --- a/application/retriever/duckduck_search.py +++ b/application/retriever/duckduck_search.py @@ -92,7 +92,6 @@ class DuckDuckSearch(BaseRetriever): if len(self.chat_history) > 1: tokens_current_history = 0 # count tokens in history - self.chat_history.reverse() for i in self.chat_history: if "prompt" in i and "response" in i: tokens_batch = num_tokens_from_string(i["prompt"]) + num_tokens_from_string( From 0b7be94d1359ca0ff578ac9abec8db321478e761 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 17:56:32 +0000 Subject: [PATCH 34/38] fix: dependecy version --- application/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/requirements.txt b/application/requirements.txt index 5325a849..2f28c2ea 100644 --- a/application/requirements.txt +++ b/application/requirements.txt @@ -66,7 +66,7 @@ pymongo==4.8.0 pypdf2==3.0.1 python-dateutil==2.9.0.post0 python-dotenv==1.0.1 -python-pptx==0.4.1 +python-pptx==1.0.2 qdrant-client==1.11.0 redis==5.0.1 referencing==0.30.2 From 0684449c2a00ea655024f59946861dca68cf8ec7 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 22:24:19 +0000 Subject: [PATCH 35/38] Update lexeu-competition.md --- lexeu-competition.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lexeu-competition.md b/lexeu-competition.md index 1077de29..e8824438 100644 --- a/lexeu-competition.md +++ b/lexeu-competition.md @@ -12,8 +12,8 @@ Welcome to the LLM Document Analysis by [LexEU](https://www.lexeu.ai/) competiti ### 📆 Timeline: - **Competition Announcement:** 1st October -- **Deadline for Submissions:** 27th October -- **Results Announcement:** Early November/ Late October +- **Deadline for Submissions:** 8th November +- **Results Announcement:** Early November ## 📜 How to Participate: From 0bb014c965e60a607be84952521d3e36b800bfb5 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 31 Oct 2024 22:24:42 +0000 Subject: [PATCH 36/38] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 8f5897fa..eeecb598 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,6 @@ Say goodbye to time-consuming manual searches, and let Date: Sun, 3 Nov 2024 21:22:34 +0000 Subject: [PATCH 38/38] Update labeler.yml --- .github/labeler.yml | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/.github/labeler.yml b/.github/labeler.yml index 0c9b1838..057772a5 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,23 +1,31 @@ repo: - - '*' +- changed-files: + - any-glob-to-any-file: '*' github: - - .github/**/* +- changed-files: + - any-glob-to-any-file: '.github/**/*' application: - - application/**/* +- changed-files: + - any-glob-to-any-file: 'application/**/*' docs: - - docs/**/* +- changed-files: + - any-glob-to-any-file: 'docs/**/*' extensions: - - extensions/**/* +- changed-files: + - any-glob-to-any-file: 'extensions/**/*' frontend: - - frontend/**/* +- changed-files: + - any-glob-to-any-file: 'frontend/**/*' scripts: - - scripts/**/* +- changed-files: + - any-glob-to-any-file: 'scripts/**/*' tests: - - tests/**/* +- changed-files: + - any-glob-to-any-file: 'tests/**/*'