From 07689928488079ebe57f5fa56309d25ae8cb3105 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Mon, 8 Jul 2024 03:03:46 +0530
Subject: [PATCH 01/13] add route to share and fetch public conversations
---
application/api/user/routes.py | 52 +++++++++++++++++++++++++++++++++-
1 file changed, 51 insertions(+), 1 deletion(-)
diff --git a/application/api/user/routes.py b/application/api/user/routes.py
index 62addc26..b914b61b 100644
--- a/application/api/user/routes.py
+++ b/application/api/user/routes.py
@@ -4,10 +4,12 @@ import shutil
from flask import Blueprint, request, jsonify
from urllib.parse import urlparse
import requests
+import json
from pymongo import MongoClient
from bson.objectid import ObjectId
+from bson.binary import Binary, UuidRepresentation
from werkzeug.utils import secure_filename
-
+from bson.dbref import DBRef
from application.api.user.tasks import ingest, ingest_remote
from application.core.settings import settings
@@ -20,6 +22,8 @@ vectors_collection = db["vectors"]
prompts_collection = db["prompts"]
feedback_collection = db["feedback"]
api_key_collection = db["api_keys"]
+shared_conversations_collections = db["shared_conversations"]
+
user = Blueprint("user", __name__)
current_dir = os.path.dirname(
@@ -491,3 +495,49 @@ def delete_api_key():
}
)
return {"status": "ok"}
+
+
+#route to share conversation
+@user.route("/api/share",methods=["POST"])
+def share_conversation():
+ try:
+ data = request.get_json()
+ conversation_id = data["conversation_id"]
+ isPromptable = request.args.get("isPromptable").lower() == "true"
+ conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
+ current_n_queries = len(conversation["queries"])
+ explicit_binary = Binary.from_uuid(uuid.uuid4(), UuidRepresentation.STANDARD)
+ shared_conversations_collections.insert_one({
+ "uuid":explicit_binary,
+ "conversation_id": {
+ "$ref":"conversations",
+ "$id":ObjectId(conversation_id)
+ } ,
+ "isPromptable":isPromptable,
+ "first_n_queries":current_n_queries
+ })
+ ## Identifier as route parameter in frontend
+ return jsonify({"success":True, "identifier":str(explicit_binary.as_uuid())}),201
+ except Exception as err:
+ return jsonify({"success":False,"error":str(err)}),400
+
+#route to get publicly shared conversations
+@user.route("/api/shared_conversation/",methods=["GET"])
+def get_publicly_shared_conversations(identifier : str):
+ try:
+ query_uuid = Binary.from_uuid(uuid.UUID(identifier), UuidRepresentation.STANDARD)
+ shared = shared_conversations_collections.find_one({"uuid":query_uuid})
+ conversation_queries=[]
+ if shared and 'conversation_id' in shared and isinstance(shared['conversation_id'], DBRef):
+ # Resolve the DBRef
+ conversation_ref = shared['conversation_id']
+ conversation = db.dereference(conversation_ref)
+ conversation_queries = conversation['queries']
+ else:
+ return jsonify({"sucess":False,"error":"might have broken url or the conversation does not exist"}),404
+
+ return jsonify({"success":True,"queries":conversation_queries}),200
+ except Exception as err:
+ print (err)
+ return jsonify({"success":False,"error":str(err)}),400
+
\ No newline at end of file
From edfe5e11566edba2c1b1c80282a81a2aa0e8b7e4 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Mon, 8 Jul 2024 15:59:19 +0530
Subject: [PATCH 02/13] restrict redundant sharing, add user field
---
application/api/user/routes.py | 41 ++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 14 deletions(-)
diff --git a/application/api/user/routes.py b/application/api/user/routes.py
index b914b61b..8db821fa 100644
--- a/application/api/user/routes.py
+++ b/application/api/user/routes.py
@@ -502,22 +502,36 @@ def delete_api_key():
def share_conversation():
try:
data = request.get_json()
+ user = "local"
+ if(hasattr(data,"user")):
+ user = data["user"]
conversation_id = data["conversation_id"]
isPromptable = request.args.get("isPromptable").lower() == "true"
conversation = conversations_collection.find_one({"_id": ObjectId(conversation_id)})
current_n_queries = len(conversation["queries"])
- explicit_binary = Binary.from_uuid(uuid.uuid4(), UuidRepresentation.STANDARD)
- shared_conversations_collections.insert_one({
- "uuid":explicit_binary,
- "conversation_id": {
- "$ref":"conversations",
- "$id":ObjectId(conversation_id)
- } ,
- "isPromptable":isPromptable,
- "first_n_queries":current_n_queries
+ pre_existing = shared_conversations_collections.find_one({
+ "conversation_id":DBRef("conversations",ObjectId(conversation_id)),
+ "isPromptable":isPromptable,
+ "first_n_queries":current_n_queries
})
- ## Identifier as route parameter in frontend
- return jsonify({"success":True, "identifier":str(explicit_binary.as_uuid())}),201
+ print("pre_existing",pre_existing)
+ if(pre_existing is not None):
+ explicit_binary = pre_existing["uuid"]
+ return jsonify({"success":True, "identifier":str(explicit_binary.as_uuid())}),200
+ else:
+ explicit_binary = Binary.from_uuid(uuid.uuid4(), UuidRepresentation.STANDARD)
+ shared_conversations_collections.insert_one({
+ "uuid":explicit_binary,
+ "conversation_id": {
+ "$ref":"conversations",
+ "$id":ObjectId(conversation_id)
+ } ,
+ "isPromptable":isPromptable,
+ "first_n_queries":current_n_queries,
+ "user":user
+ })
+ ## Identifier as route parameter in frontend
+ return jsonify({"success":True, "identifier":str(explicit_binary.as_uuid())}),201
except Exception as err:
return jsonify({"success":False,"error":str(err)}),400
@@ -532,11 +546,10 @@ def get_publicly_shared_conversations(identifier : str):
# Resolve the DBRef
conversation_ref = shared['conversation_id']
conversation = db.dereference(conversation_ref)
- conversation_queries = conversation['queries']
+ conversation_queries = conversation['queries'][:(shared["first_n_queries"])]
else:
return jsonify({"sucess":False,"error":"might have broken url or the conversation does not exist"}),404
-
- return jsonify({"success":True,"queries":conversation_queries}),200
+ return jsonify(conversation_queries),200
except Exception as err:
print (err)
return jsonify({"success":False,"error":str(err)}),400
From d6e59a6a0a1754adccb011c4a08960ae815f3917 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Thu, 11 Jul 2024 21:45:47 +0530
Subject: [PATCH 03/13] conversation tile: add menu, add share modal
---
application/api/user/routes.py | 3 +-
frontend/package-lock.json | 10 ++
frontend/src/assets/red-trash.svg | 3 +
frontend/src/assets/share.svg | 3 +
frontend/src/assets/three-dots.svg | 3 +
.../src/conversation/ConversationTile.tsx | 154 ++++++++++++++----
.../src/modals/ShareConversationModal.tsx | 93 +++++++++++
frontend/tailwind.config.cjs | 1 +
8 files changed, 238 insertions(+), 32 deletions(-)
create mode 100644 frontend/src/assets/red-trash.svg
create mode 100644 frontend/src/assets/share.svg
create mode 100644 frontend/src/assets/three-dots.svg
create mode 100644 frontend/src/modals/ShareConversationModal.tsx
diff --git a/application/api/user/routes.py b/application/api/user/routes.py
index 8db821fa..12744f0f 100644
--- a/application/api/user/routes.py
+++ b/application/api/user/routes.py
@@ -498,6 +498,7 @@ def delete_api_key():
#route to share conversation
+##isPromptable should be passed through queries
@user.route("/api/share",methods=["POST"])
def share_conversation():
try:
@@ -526,7 +527,7 @@ def share_conversation():
"$ref":"conversations",
"$id":ObjectId(conversation_id)
} ,
- "isPromptable":isPromptable,
+ "isPromptable":isPromptable,
"first_n_queries":current_n_queries,
"user":user
})
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 83e0a930..2b868da2 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -11,6 +11,7 @@
"@reduxjs/toolkit": "^1.9.2",
"@vercel/analytics": "^0.1.10",
"i18next": "^23.11.5",
+ "i18next-browser-languagedetector": "^8.0.0",
"prop-types": "^15.8.1",
"react": "^18.2.0",
"react-copy-to-clipboard": "^5.1.0",
@@ -4194,6 +4195,15 @@
"@babel/runtime": "^7.23.2"
}
},
+ "node_modules/i18next-browser-languagedetector": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/i18next-browser-languagedetector/-/i18next-browser-languagedetector-8.0.0.tgz",
+ "integrity": "sha512-zhXdJXTTCoG39QsrOCiOabnWj2jecouOqbchu3EfhtSHxIB5Uugnm9JaizenOy39h7ne3+fLikIjeW88+rgszw==",
+ "license": "MIT",
+ "dependencies": {
+ "@babel/runtime": "^7.23.2"
+ }
+ },
"node_modules/ignore": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
diff --git a/frontend/src/assets/red-trash.svg b/frontend/src/assets/red-trash.svg
new file mode 100644
index 00000000..b3331d95
--- /dev/null
+++ b/frontend/src/assets/red-trash.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/assets/share.svg b/frontend/src/assets/share.svg
new file mode 100644
index 00000000..4699e16b
--- /dev/null
+++ b/frontend/src/assets/share.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/assets/three-dots.svg b/frontend/src/assets/three-dots.svg
new file mode 100644
index 00000000..6462b942
--- /dev/null
+++ b/frontend/src/assets/three-dots.svg
@@ -0,0 +1,3 @@
+
diff --git a/frontend/src/conversation/ConversationTile.tsx b/frontend/src/conversation/ConversationTile.tsx
index b9d2301d..94731b90 100644
--- a/frontend/src/conversation/ConversationTile.tsx
+++ b/frontend/src/conversation/ConversationTile.tsx
@@ -5,11 +5,14 @@ import Exit from '../assets/exit.svg';
import Message from '../assets/message.svg';
import MessageDark from '../assets/message-dark.svg';
import { useDarkTheme } from '../hooks';
+import ConfirmationModal from '../modals/ConfirmationModal';
import CheckMark2 from '../assets/checkMark2.svg';
-import Trash from '../assets/trash.svg';
-
+import Trash from '../assets/red-trash.svg';
+import Share from '../assets/share.svg';
+import threeDots from '../assets/three-dots.svg';
import { selectConversationId } from '../preferences/preferenceSlice';
-
+import { ActiveState } from '../models/misc';
+import { ShareConversationModal } from '../modals/ShareConversationModal';
interface ConversationProps {
name: string;
id: string;
@@ -32,13 +35,18 @@ export default function ConversationTile({
const [isDarkTheme] = useDarkTheme();
const [isEdit, setIsEdit] = useState(false);
const [conversationName, setConversationsName] = useState('');
-
+ const [isOpen, setOpen] = useState(false);
+ const [isShareModalOpen, setShareModalState] = useState(false);
+ const [deleteModalState, setDeleteModalState] =
+ useState('INACTIVE');
+ const menuRef = useRef(null);
useEffect(() => {
setConversationsName(conversation.name);
}, [conversation.name]);
function handleEditConversation() {
setIsEdit(true);
+ setOpen(false);
}
function handleSaveConversation(changedConversation: ConversationProps) {
@@ -50,6 +58,18 @@ export default function ConversationTile({
}
}
+ const handleClickOutside = (event: MouseEvent) => {
+ if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
+ setOpen(false);
+ }
+ };
+
+ useEffect(() => {
+ document.addEventListener('mousedown', handleClickOutside);
+ return () => {
+ document.removeEventListener('mousedown', handleClickOutside);
+ };
+ }, []);
function onClear() {
setConversationsName(conversation.name);
setIsEdit(false);
@@ -79,7 +99,7 @@ export default function ConversationTile({
setConversationsName(e.target.value)}
/>
@@ -90,36 +110,108 @@ export default function ConversationTile({
)}
{conversationId === conversation.id && (
-
-

{
- event.stopPropagation();
- isEdit
- ? handleSaveConversation({
+
+ {isEdit ? (
+
+

{
+ event.stopPropagation();
+ handleSaveConversation({
id: conversationId,
name: conversationName,
- })
- : handleEditConversation();
- }}
- />
-

{
- event.stopPropagation();
- isEdit ? onClear() : onDeleteConversation(conversation.id);
- }}
- />
+ });
+ }}
+ />
+

{
+ event.stopPropagation();
+ onClear();
+ }}
+ />
+
+ ) : (
+
+ )}
+ {isOpen && (
+
+
+
+
+
+ )}
)}
+
onDeleteConversation(conversation.id)}
+ submitLabel="Delete"
+ />
+ {isShareModalOpen && conversationId && (
+ {
+ setShareModalState(false);
+ }}
+ conversationId={conversationId}
+ />
+ )}
);
}
diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx
new file mode 100644
index 00000000..886901b5
--- /dev/null
+++ b/frontend/src/modals/ShareConversationModal.tsx
@@ -0,0 +1,93 @@
+import { useState } from 'react';
+import { useTranslation } from 'react-i18next';
+import Spinner from '../assets/spinner.svg';
+import Exit from '../assets/exit.svg';
+const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
+
+export const ShareConversationModal = ({
+ close,
+ conversationId,
+}: {
+ close: () => void;
+ conversationId: string;
+}) => {
+ const [identifier, setIdentifier] = useState(null);
+ const [isCopied, setIsCopied] = useState(false);
+ type StatusType = 'loading' | 'idle' | 'fetched' | 'failed';
+ const [status, setStatus] = useState('idle');
+ const { t } = useTranslation();
+ const domain = window.location.origin;
+ const handleCopyKey = (url: string) => {
+ navigator.clipboard.writeText(url);
+ setIsCopied(true);
+ };
+ const shareCoversationPublicly: (isPromptable: boolean) => void = (
+ isPromptable = false,
+ ) => {
+ setStatus('loading');
+ fetch(`${apiHost}/api/share?isPromptable=${isPromptable}`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({ conversation_id: conversationId }),
+ })
+ .then((res) => {
+ console.log(res.status);
+ return res.json();
+ })
+ .then((data) => {
+ if (data.success && data.identifier) {
+ setIdentifier(data.identifier);
+ setStatus('fetched');
+ } else setStatus('failed');
+ })
+ .catch((err) => setStatus('failed'));
+ };
+ return (
+
+
+
+
+
Create a public page to share
+
+ Source document, personal information and further conversation will
+ remain private
+
+
+
{`${domain}/shared/${
+ identifier ?? '....'
+ }`}
+ {status === 'fetched' ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
diff --git a/frontend/tailwind.config.cjs b/frontend/tailwind.config.cjs
index 63f99513..938eacee 100644
--- a/frontend/tailwind.config.cjs
+++ b/frontend/tailwind.config.cjs
@@ -48,6 +48,7 @@ module.exports = {
'soap':'#D8CCF1',
'independence':'#54546D',
'philippine-yellow':'#FFC700',
+ 'bright-gray':'#EBEBEB'
},
},
},
From 019bf013ac6990c8a7b2eb9e9ab256c014fbe0e1 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Fri, 12 Jul 2024 02:51:59 +0530
Subject: [PATCH 04/13] add css class: no-scrollbar
---
frontend/src/index.css | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/frontend/src/index.css b/frontend/src/index.css
index c1d80714..7e0b3bda 100644
--- a/frontend/src/index.css
+++ b/frontend/src/index.css
@@ -22,6 +22,18 @@
background: #b1afaf;
}
+@layer utilities {
+ /* Chrome, Safari and Opera */
+ .no-scrollbar::-webkit-scrollbar {
+ display: none;
+ }
+
+ .no-scrollbar {
+ -ms-overflow-style: none; /* IE and Edge */
+ scrollbar-width: none; /* Firefox */
+ }
+}
+
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
/* Document
From 02187fed4e6ecc3156c111e31e39a9d916035c7a Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Sun, 14 Jul 2024 03:27:53 +0530
Subject: [PATCH 05/13] add timetamp in iso, remove sources
---
application/api/user/routes.py | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/application/api/user/routes.py b/application/api/user/routes.py
index 12744f0f..4b6bba8f 100644
--- a/application/api/user/routes.py
+++ b/application/api/user/routes.py
@@ -547,10 +547,15 @@ def get_publicly_shared_conversations(identifier : str):
# Resolve the DBRef
conversation_ref = shared['conversation_id']
conversation = db.dereference(conversation_ref)
- conversation_queries = conversation['queries'][:(shared["first_n_queries"])]
+ if(conversation is None):
+ return jsonify({"sucess":False,"error":"might have broken url or the conversation does not exist"}),404
+ conversation_queries = conversation['queries'][:(shared["first_n_queries"])]
+ for query in conversation_queries:
+ query.pop("sources") ## avoid exposing sources
else:
return jsonify({"sucess":False,"error":"might have broken url or the conversation does not exist"}),404
- return jsonify(conversation_queries),200
+ date = conversation["_id"].generation_time.isoformat()
+ return jsonify({"success":True,"queries":conversation_queries,"title":conversation["name"],"timestamp":date}),200
except Exception as err:
print (err)
return jsonify({"success":False,"error":str(err)}),400
From 81d7fe3fdba409806a3620e51f315bc7fb816cf5 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Sun, 14 Jul 2024 03:29:06 +0530
Subject: [PATCH 06/13] refactor App, add /shared/id page
---
frontend/src/App.tsx | 87 +++++++++--
.../src/conversation/SharedConversation.tsx | 146 ++++++++++++++++++
frontend/src/hooks/index.ts | 14 +-
.../src/modals/ShareConversationModal.tsx | 4 +-
4 files changed, 232 insertions(+), 19 deletions(-)
create mode 100644 frontend/src/conversation/SharedConversation.tsx
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 3083f1f3..2aa8a8fc 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,4 +1,5 @@
import { Routes, Route } from 'react-router-dom';
+import { ReactElement, useEffect } from 'react';
import Navigation from './Navigation';
import Conversation from './conversation/Conversation';
import About from './About';
@@ -8,29 +9,93 @@ import { useMediaQuery } from './hooks';
import { useState } from 'react';
import Setting from './settings';
import './locale/i18n';
-
+import SharedConversation from './conversation/SharedConversation';
+import { useDarkTheme } from './hooks';
inject();
-export default function App() {
+function MainLayout({ children }: { children: ReactElement }) {
const { isMobile } = useMediaQuery();
const [navOpen, setNavOpen] = useState(!isMobile);
return (
-
+ <>
-
- } />
- } />
- } />
- } />
-
+ {children}
-
+ >
+ );
+}
+
+function Layout({ children }: { children: ReactElement }) {
+ return (
+ <>
+ {children}
+ >
+ );
+}
+export default function App() {
+ const [isDarkTheme] = useDarkTheme();
+ useEffect(() => {
+ localStorage.setItem('selectedTheme', isDarkTheme ? 'Dark' : 'Light');
+ if (isDarkTheme) {
+ document
+ .getElementById('root')
+ ?.classList.add('dark', 'dark:bg-raisin-black');
+ } else {
+ document.getElementById('root')?.classList.remove('dark');
+ }
+ }, [isDarkTheme]);
+ return (
+ <>
+
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+
+
+
+ }
+ />
+ {/* default page */}
+
+
+
+ }
+ />
+
+ >
);
}
diff --git a/frontend/src/conversation/SharedConversation.tsx b/frontend/src/conversation/SharedConversation.tsx
new file mode 100644
index 00000000..82e6be62
--- /dev/null
+++ b/frontend/src/conversation/SharedConversation.tsx
@@ -0,0 +1,146 @@
+import { useState, useEffect } from 'react';
+import { useParams } from 'react-router-dom';
+import { useNavigate } from 'react-router-dom';
+import { Query } from './conversationModels';
+import ConversationBubble from './ConversationBubble';
+import { Fragment } from 'react';
+const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
+const SharedConversation = () => {
+ const params = useParams();
+ const navigate = useNavigate();
+ const { identifier } = params; //identifier is a uuid, not conversationId
+ const [queries, setQueries] = useState([]);
+ const [title, setTitle] = useState('');
+ const [date, setDate] = useState('');
+
+ function formatISODate(isoDateStr: string) {
+ const date = new Date(isoDateStr);
+
+ const monthNames = [
+ 'Jan',
+ 'Feb',
+ 'Mar',
+ 'Apr',
+ 'May',
+ 'June',
+ 'July',
+ 'Aug',
+ 'Sept',
+ 'Oct',
+ 'Nov',
+ 'Dec',
+ ];
+
+ const month = monthNames[date.getMonth()];
+ const day = date.getDate();
+ const year = date.getFullYear();
+
+ let hours = date.getHours();
+ const minutes = date.getMinutes();
+ const ampm = hours >= 12 ? 'PM' : 'AM';
+
+ hours = hours % 12;
+ hours = hours ? hours : 12;
+ const minutesStr = minutes < 10 ? '0' + minutes : minutes;
+ const formattedDate = `Published ${month} ${day}, ${year} at ${hours}:${minutesStr} ${ampm}`;
+ return formattedDate;
+ }
+ const fetchQueris = () => {
+ fetch(`${apiHost}/api/shared_conversation/${identifier}`)
+ .then((res) => {
+ if (res.status === 404 || res.status === 400) navigate('/pagenotfound');
+ return res.json();
+ })
+ .then((data) => {
+ if (data.success) {
+ setQueries(data.queries);
+ setTitle(data.title);
+ setDate(formatISODate(data.timestamp));
+ }
+ });
+ };
+
+ const prepResponseView = (query: Query, index: number) => {
+ let responseView;
+ if (query.response) {
+ responseView = (
+
+ );
+ } else if (query.error) {
+ responseView = (
+
+ );
+ }
+ return responseView;
+ };
+ useEffect(() => {
+ fetchQueris();
+ }, []);
+ return (
+
+
+ {queries.length > 0 && (
+
+
+
+
+ {title}
+
+
+ Created with{' '}
+
+ DocsGPT
+
+
+
+ {date}
+
+
+
+ {queries.map((query, index) => {
+ return (
+
+
+
+ {prepResponseView(query, index)}
+
+ );
+ })}
+
+
+
+ )}
+
+
+
+ This is a chatbot that uses the GPT-3, Faiss and LangChain to answer
+ questions.
+
+
+
+
+ );
+};
+
+export default SharedConversation;
diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts
index 6248b3f8..c8258ad2 100644
--- a/frontend/src/hooks/index.ts
+++ b/frontend/src/hooks/index.ts
@@ -77,21 +77,23 @@ export function useDarkTheme() {
// Set dark mode based on local storage preference
if (savedMode === 'Dark') {
setIsDarkTheme(true);
- document.documentElement.classList.add('dark');
- document.documentElement.classList.add('dark:bg-raisin-black');
+ document
+ .getElementById('root')
+ ?.classList.add('dark', 'dark:bg-raisin-black');
} else {
// If no preference found, set to default (light mode)
setIsDarkTheme(false);
- document.documentElement.classList.remove('dark');
+ document.getElementById('root')?.classList.remove('dark');
}
}, []);
useEffect(() => {
localStorage.setItem('selectedTheme', isDarkTheme ? 'Dark' : 'Light');
if (isDarkTheme) {
- document.documentElement.classList.add('dark');
- document.documentElement.classList.add('dark:bg-raisin-black');
+ document
+ .getElementById('root')
+ ?.classList.add('dark', 'dark:bg-raisin-black');
} else {
- document.documentElement.classList.remove('dark');
+ document.getElementById('root')?.classList.remove('dark');
}
}, [isDarkTheme]);
//method to toggle theme
diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx
index 886901b5..d32c5f90 100644
--- a/frontend/src/modals/ShareConversationModal.tsx
+++ b/frontend/src/modals/ShareConversationModal.tsx
@@ -57,13 +57,13 @@ export const ShareConversationModal = ({
remain private
-
{`${domain}/shared/${
+ {`${domain}/share/${
identifier ?? '....'
}`}
{status === 'fetched' ? (
)}
)}
onDeleteConversation(conversation.id)}
- submitLabel="Delete"
+ submitLabel={t('convTile.delete')}
/>
{isShareModalOpen && conversationId && (
{
const [queries, setQueries] = useState([]);
const [title, setTitle] = useState('');
const [date, setDate] = useState('');
-
+ const { t } = useTranslation();
function formatISODate(isoDateStr: string) {
const date = new Date(isoDateStr);
@@ -97,7 +98,7 @@ const SharedConversation = () => {
{title}
- Created with{' '}
+ {t('sharedConv.subtitle')}{' '}
DocsGPT
@@ -131,11 +132,10 @@ const SharedConversation = () => {
onClick={() => navigate('/')}
className="w-fit rounded-full bg-purple-30 p-4 text-white shadow-xl transition-colors duration-200 hover:bg-purple-taupe"
>
- Get Started with DocsGPT
+ {t('sharedConv.button')}
- This is a chatbot that uses the GPT-3, Faiss and LangChain to answer
- questions.
+ {t('sharedConv.meta')}
diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json
index e59fbedc..e914693a 100644
--- a/frontend/src/locale/en.json
+++ b/frontend/src/locale/en.json
@@ -103,6 +103,22 @@
"deleteConv": {
"confirm": "Are you sure you want to delete all the conversations?",
"delete": "Delete"
+ },
+ "shareConv": {
+ "label": "Create a public page to share",
+ "note": "Source document, personal information and further conversation will remain private",
+ "create": "Create"
}
+ },
+ "sharedConv": {
+ "subtitle": "Created with",
+ "button": "Get Started with DocsGPT",
+ "meta": "This is a chatbot that uses the GPT-3, Faiss and LangChain to answer questions."
+ },
+ "convTile": {
+ "share": "Share",
+ "delete": "Delete",
+ "rename": "Rename",
+ "deleteWarning": "Are you sure you want to delete this conversation?"
}
}
diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json
index 70966e4b..78a4aa29 100644
--- a/frontend/src/locale/es.json
+++ b/frontend/src/locale/es.json
@@ -103,6 +103,22 @@
"deleteConv": {
"confirm": "¿Está seguro de que desea eliminar todas las conversaciones?",
"delete": "Eliminar"
+ },
+ "shareConv": {
+ "label": "Crear una página pública para compartir",
+ "note": "El documento original, la información personal y las conversaciones posteriores permanecerán privadas",
+ "create": "Crear"
}
+ },
+ "sharedConv": {
+ "subtitle": "Creado con",
+ "button": "Comienza con DocsGPT",
+ "meta": "Este es un chatbot que utiliza GPT-3, Faiss y LangChain para responder preguntas."
+ },
+ "convTile": {
+ "share": "Compartir",
+ "delete": "Eliminar",
+ "rename": "Renombrar",
+ "deleteWarning": "¿Está seguro de que desea eliminar esta conversación?"
}
}
diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json
index a025a17a..697b137f 100644
--- a/frontend/src/locale/jp.json
+++ b/frontend/src/locale/jp.json
@@ -103,6 +103,22 @@
"deleteConv": {
"confirm": "すべての会話を削除してもよろしいですか?",
"delete": "削除"
+ },
+ "shareConv": {
+ "label": "共有ページを作成して共有する",
+ "note": "ソースドキュメント、個人情報、および以降の会話は非公開のままになります",
+ "create": "作成"
}
+ },
+ "sharedConv": {
+ "subtitle": "作成者",
+ "button": "DocsGPT を始める",
+ "meta": "GPT-3、Faiss、および LangChain を使用して質問に答えるチャットボットです"
+ },
+ "convTile": {
+ "share": "共有",
+ "delete": "削除",
+ "rename": "名前変更",
+ "deleteWarning": "この会話を削除してもよろしいですか?"
}
}
diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json
index f686ea20..8161f740 100644
--- a/frontend/src/locale/zh.json
+++ b/frontend/src/locale/zh.json
@@ -103,6 +103,22 @@
"deleteConv": {
"confirm": "您确定要删除所有对话吗?",
"delete": "删除"
+ },
+ "shareConv": {
+ "label": "创建用于分享的公共页面",
+ "note": "源文档、个人信息和后续对话将保持私密",
+ "create": "创建"
}
+ },
+ "sharedConv": {
+ "subtitle": "使用创建",
+ "button": "开始使用 DocsGPT",
+ "meta": "这是一个使用 GPT-3、Faiss 和 LangChain 来回答问题的聊天机器人。"
+ },
+ "convTile": {
+ "share": "分享",
+ "delete": "删除",
+ "rename": "重命名",
+ "deleteWarning": "您确定要删除此对话吗?"
}
}
diff --git a/frontend/src/modals/ShareConversationModal.tsx b/frontend/src/modals/ShareConversationModal.tsx
index d32c5f90..a6ab1e0f 100644
--- a/frontend/src/modals/ShareConversationModal.tsx
+++ b/frontend/src/modals/ShareConversationModal.tsx
@@ -51,11 +51,8 @@ export const ShareConversationModal = ({
-
Create a public page to share
-
- Source document, personal information and further conversation will
- remain private
-
+
{t('modals.shareConv.label')}
+
{t('modals.shareConv.note')}
{`${domain}/share/${
identifier ?? '....'
@@ -76,7 +73,7 @@ export const ShareConversationModal = ({
shareCoversationPublicly(false);
}}
>
- Create
+ {t('modals.shareConv.create')}
{status === 'loading' && (
Date: Mon, 15 Jul 2024 02:55:38 +0530
Subject: [PATCH 08/13] feedback visible conditioned, update meta info in
shared
---
frontend/src/App.tsx | 6 +-
.../src/conversation/ConversationBubble.tsx | 122 +++++++++---------
.../src/conversation/SharedConversation.tsx | 94 +++++++-------
frontend/src/locale/en.json | 2 +-
frontend/src/locale/es.json | 2 +-
frontend/src/locale/jp.json | 2 +-
frontend/src/locale/zh.json | 2 +-
7 files changed, 114 insertions(+), 116 deletions(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 2aa8a8fc..38694182 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -33,11 +33,7 @@ function MainLayout({ children }: { children: ReactElement }) {
}
function Layout({ children }: { children: ReactElement }) {
- return (
- <>
- {children}
- >
- );
+ return {children}
;
}
export default function App() {
const [isDarkTheme] = useDarkTheme();
diff --git a/frontend/src/conversation/ConversationBubble.tsx b/frontend/src/conversation/ConversationBubble.tsx
index fc5d469e..4adfbf94 100644
--- a/frontend/src/conversation/ConversationBubble.tsx
+++ b/frontend/src/conversation/ConversationBubble.tsx
@@ -1,6 +1,6 @@
import { forwardRef, useState } from 'react';
import Avatar from '../components/Avatar';
-import CoppyButton from '../components/CopyButton';
+import CopyButton from '../components/CopyButton';
import remarkGfm from 'remark-gfm';
import { FEEDBACK, MESSAGE_TYPE } from './conversationModels';
import classes from './ConversationBubble.module.css';
@@ -103,7 +103,7 @@ const ConversationBubble = forwardRef<
className={`absolute right-3 top-3 lg:invisible
${type !== 'ERROR' ? 'group-hover:lg:visible' : ''} `}
>
-
@@ -215,78 +215,82 @@ const ConversationBubble = forwardRef<
${type !== 'ERROR' ? 'group-hover:lg:visible' : ''}`}
>
-
+
-
-
+ {handleFeedback && (
+ <>
-
+
+ {
- handleFeedback?.('LIKE');
- setIsLikeClicked(true);
- setIsDislikeClicked(false);
- }}
- onMouseEnter={() => setIsLikeHovered(true)}
- onMouseLeave={() => setIsLikeHovered(false)}
- >
+ onClick={() => {
+ handleFeedback?.('LIKE');
+ setIsLikeClicked(true);
+ setIsDislikeClicked(false);
+ }}
+ onMouseEnter={() => setIsLikeHovered(true)}
+ onMouseLeave={() => setIsLikeHovered(false)}
+ >
+
+
-
-
-
-
-
{
- handleFeedback?.('DISLIKE');
- setIsDislikeClicked(true);
- setIsLikeClicked(false);
- }}
- onMouseEnter={() => setIsDislikeHovered(true)}
- onMouseLeave={() => setIsDislikeHovered(false)}
- >
+
+
+ {
+ handleFeedback?.('DISLIKE');
+ setIsDislikeClicked(true);
+ setIsLikeClicked(false);
+ }}
+ onMouseEnter={() => setIsDislikeHovered(true)}
+ onMouseLeave={() => setIsDislikeHovered(false)}
+ >
+
+
-
-
+ >
+ )}
{sources && openSource !== null && sources[openSource] && (
diff --git a/frontend/src/conversation/SharedConversation.tsx b/frontend/src/conversation/SharedConversation.tsx
index ff9ab3fb..1b9fb781 100644
--- a/frontend/src/conversation/SharedConversation.tsx
+++ b/frontend/src/conversation/SharedConversation.tsx
@@ -87,58 +87,56 @@ const SharedConversation = () => {
useEffect(() => {
fetchQueris();
}, []);
- return (
-
-
- {queries.length > 0 && (
-
-
-
-
- {title}
-
-
- {t('sharedConv.subtitle')}{' '}
-
- DocsGPT
-
-
-
- {date}
-
-
-
- {queries.map((query, index) => {
- return (
-
-
- {prepResponseView(query, index)}
-
- );
- })}
-
-
+ return (
+
+
+
+
+
+ {title}
+
+
+ {t('sharedConv.subtitle')}{' '}
+
+ DocsGPT
+
+
+
+ {date}
+
+
+
+ {queries?.map((query, index) => {
+ return (
+
+
+
+ {prepResponseView(query, index)}
+
+ );
+ })}
- )}
-
-
-
- {t('sharedConv.meta')}
-
+
+
+
+
+ {t('sharedConv.meta')}
+
+
);
};
diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json
index e914693a..0f5aa708 100644
--- a/frontend/src/locale/en.json
+++ b/frontend/src/locale/en.json
@@ -113,7 +113,7 @@
"sharedConv": {
"subtitle": "Created with",
"button": "Get Started with DocsGPT",
- "meta": "This is a chatbot that uses the GPT-3, Faiss and LangChain to answer questions."
+ "meta": "DocsGPT uses GenAI, please review critical information using sources."
},
"convTile": {
"share": "Share",
diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json
index 78a4aa29..b91b67e9 100644
--- a/frontend/src/locale/es.json
+++ b/frontend/src/locale/es.json
@@ -113,7 +113,7 @@
"sharedConv": {
"subtitle": "Creado con",
"button": "Comienza con DocsGPT",
- "meta": "Este es un chatbot que utiliza GPT-3, Faiss y LangChain para responder preguntas."
+ "meta": "DocsGPT utiliza GenAI, por favor revise la información crítica utilizando fuentes."
},
"convTile": {
"share": "Compartir",
diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json
index 697b137f..75e62589 100644
--- a/frontend/src/locale/jp.json
+++ b/frontend/src/locale/jp.json
@@ -113,7 +113,7 @@
"sharedConv": {
"subtitle": "作成者",
"button": "DocsGPT を始める",
- "meta": "GPT-3、Faiss、および LangChain を使用して質問に答えるチャットボットです"
+ "meta": "DocsGPT は GenAI を使用しています、情報源を使用して重要情報を確認してください。"
},
"convTile": {
"share": "共有",
diff --git a/frontend/src/locale/zh.json b/frontend/src/locale/zh.json
index 8161f740..e46fe254 100644
--- a/frontend/src/locale/zh.json
+++ b/frontend/src/locale/zh.json
@@ -113,7 +113,7 @@
"sharedConv": {
"subtitle": "使用创建",
"button": "开始使用 DocsGPT",
- "meta": "这是一个使用 GPT-3、Faiss 和 LangChain 来回答问题的聊天机器人。"
+ "meta": "DocsGPT 使用 GenAI,请使用资源查看关键信息。"
},
"convTile": {
"share": "分享",
From 7b8458b47de2cf708dac742e84972af0c582e39e Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Mon, 15 Jul 2024 05:00:13 +0530
Subject: [PATCH 09/13] fix layout
---
frontend/src/App.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 38694182..dff27112 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -20,7 +20,7 @@ function MainLayout({ children }: { children: ReactElement }) {
<>
Date: Mon, 15 Jul 2024 05:13:28 +0530
Subject: [PATCH 10/13] minor fix
---
frontend/src/App.tsx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index dff27112..99a63cbc 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -17,10 +17,10 @@ function MainLayout({ children }: { children: ReactElement }) {
const { isMobile } = useMediaQuery();
const [navOpen, setNavOpen] = useState(!isMobile);
return (
- <>
+
);
}
From 1107a2f2bcdb2bff164b42d6cc8a42eb703662c6 Mon Sep 17 00:00:00 2001
From: ManishMadan2882
Date: Mon, 15 Jul 2024 17:56:23 +0530
Subject: [PATCH 11/13] refactor App.tsx: better convention
---
frontend/src/App.tsx | 58 ++++---------------
frontend/src/PageNotFound.tsx | 6 +-
.../src/conversation/SharedConversation.tsx | 2 +-
3 files changed, 15 insertions(+), 51 deletions(-)
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index 99a63cbc..05792187 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,5 +1,5 @@
import { Routes, Route } from 'react-router-dom';
-import { ReactElement, useEffect } from 'react';
+import { useEffect } from 'react';
import Navigation from './Navigation';
import Conversation from './conversation/Conversation';
import About from './About';
@@ -9,11 +9,12 @@ import { useMediaQuery } from './hooks';
import { useState } from 'react';
import Setting from './settings';
import './locale/i18n';
+import { Outlet } from 'react-router-dom';
import SharedConversation from './conversation/SharedConversation';
import { useDarkTheme } from './hooks';
inject();
-function MainLayout({ children }: { children: ReactElement }) {
+function MainLayout() {
const { isMobile } = useMediaQuery();
const [navOpen, setNavOpen] = useState(!isMobile);
return (
@@ -26,15 +27,12 @@ function MainLayout({ children }: { children: ReactElement }) {
: 'ml-0 md:ml-16'
}`}
>
- {children}
+
);
}
-function Layout({ children }: { children: ReactElement }) {
- return
{children}
;
-}
export default function App() {
const [isDarkTheme] = useDarkTheme();
useEffect(() => {
@@ -50,47 +48,13 @@ export default function App() {
return (
<>
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
-
-
-
- }
- />
- {/* default page */}
-
-
-
- }
- />
+ }>
+ } />
+ } />
+ } />
+
+ } />
+ } />
>
);
diff --git a/frontend/src/PageNotFound.tsx b/frontend/src/PageNotFound.tsx
index eaea5cc9..0b86d7c1 100644
--- a/frontend/src/PageNotFound.tsx
+++ b/frontend/src/PageNotFound.tsx
@@ -2,11 +2,11 @@ import { Link } from 'react-router-dom';
export default function PageNotFound() {
return (
-
-
+
+
404
The page you are looking for does not exist.
-