@@ -212,6 +186,8 @@ const General: React.FC = () => {
setSelectedTheme(option);
option !== selectedTheme && toggleTheme();
}}
+ size="w-56"
+ rounded="3xl"
/>
@@ -223,9 +199,11 @@ const General: React.FC = () => {
options={languages}
selectedValue={selectedLanguage}
onSelect={setSelectedLanguage}
+ size="w-56"
+ rounded="3xl"
/>
-
+
Chunks processed per query
@@ -234,6 +212,19 @@ const General: React.FC = () => {
options={chunks}
selectedValue={selectedChunks}
onSelect={(value: string) => dispatch(setChunks(value))}
+ size="w-56"
+ rounded="3xl"
+ />
+
+
+
+ dispatch(setPrompt({ name: name, id: id, type: type }))
+ }
+ setPrompts={setPrompts}
+ apiHost={apiHost}
/>
@@ -241,12 +232,6 @@ const General: React.FC = () => {
};
export default Setting;
-type PromptProps = {
- prompts: { name: string; id: string; type: string }[];
- selectedPrompt: { name: string; id: string; type: string };
- onSelectPrompt: (name: string, id: string, type: string) => void;
- setPrompts: (prompts: { name: string; id: string; type: string }[]) => void;
-};
const Prompts: React.FC
= ({
prompts,
@@ -263,11 +248,20 @@ const Prompts: React.FC = ({
id: string;
type: string;
}) => {
- setNewPromptName(name);
+ setEditPromptName(name);
onSelectPrompt(name, id, type);
};
- const [newPromptName, setNewPromptName] = useState(selectedPrompt.name);
+ const [newPromptName, setNewPromptName] = useState('');
const [newPromptContent, setNewPromptContent] = useState('');
+ const [editPromptName, setEditPromptName] = useState('');
+ const [editPromptContent, setEditPromptContent] = useState('');
+ const [currentPromptEdit, setCurrentPromptEdit] = useState({
+ id: '',
+ name: '',
+ type: '',
+ });
+ const [modalType, setModalType] = useState<'ADD' | 'EDIT'>('ADD');
+ const [modalState, setModalState] = useState('INACTIVE');
const handleAddPrompt = async () => {
try {
@@ -291,6 +285,7 @@ const Prompts: React.FC = ({
{ name: newPromptName, id: newPrompt.id, type: 'private' },
]);
}
+ setModalState('INACTIVE');
onSelectPrompt(newPromptName, newPrompt.id, newPromptContent);
setNewPromptName(newPromptName);
} catch (error) {
@@ -298,16 +293,14 @@ const Prompts: React.FC = ({
}
};
- const handleDeletePrompt = () => {
- setPrompts(prompts.filter((prompt) => prompt.id !== selectedPrompt.id));
- console.log('selectedPrompt.id', selectedPrompt.id);
-
+ const handleDeletePrompt = (id: string) => {
+ setPrompts(prompts.filter((prompt) => prompt.id !== id));
fetch(`${apiHost}/api/delete_prompt`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
- body: JSON.stringify({ id: selectedPrompt.id }),
+ body: JSON.stringify({ id: id }),
})
.then((response) => {
if (!response.ok) {
@@ -316,7 +309,6 @@ const Prompts: React.FC = ({
// get 1st prompt and set it as selected
if (prompts.length > 0) {
onSelectPrompt(prompts[0].name, prompts[0].id, prompts[0].type);
- setNewPromptName(prompts[0].name);
}
})
.catch((error) => {
@@ -324,50 +316,65 @@ const Prompts: React.FC = ({
});
};
- useEffect(() => {
- const fetchPromptContent = async () => {
- console.log('fetching prompt content');
- try {
- const response = await fetch(
- `${apiHost}/api/get_single_prompt?id=${selectedPrompt.id}`,
- {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- },
+ const fetchPromptContent = async (id: string) => {
+ console.log('fetching prompt content');
+ try {
+ const response = await fetch(
+ `${apiHost}/api/get_single_prompt?id=${id}`,
+ {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
},
- );
- if (!response.ok) {
- throw new Error('Failed to fetch prompt content');
- }
- const promptContent = await response.json();
- setNewPromptContent(promptContent.content);
- } catch (error) {
- console.error(error);
+ },
+ );
+ if (!response.ok) {
+ throw new Error('Failed to fetch prompt content');
}
- };
+ const promptContent = await response.json();
+ setEditPromptContent(promptContent.content);
+ } catch (error) {
+ console.error(error);
+ }
+ };
- fetchPromptContent();
- }, [selectedPrompt]);
-
- const handleSaveChanges = () => {
+ const handleSaveChanges = (id: string, type: string) => {
fetch(`${apiHost}/api/update_prompt`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
- id: selectedPrompt.id,
- name: newPromptName,
- content: newPromptContent,
+ id: id,
+ name: editPromptName,
+ content: editPromptContent,
}),
})
.then((response) => {
if (!response.ok) {
throw new Error('Failed to update prompt');
}
- onSelectPrompt(newPromptName, selectedPrompt.id, selectedPrompt.type);
- setNewPromptName(newPromptName);
+ if (setPrompts) {
+ const existingPromptIndex = prompts.findIndex(
+ (prompt) => prompt.id === id,
+ );
+ if (existingPromptIndex === -1) {
+ setPrompts([
+ ...prompts,
+ { name: editPromptName, id: id, type: type },
+ ]);
+ } else {
+ const updatedPrompts = [...prompts];
+ updatedPrompts[existingPromptIndex] = {
+ name: editPromptName,
+ id: id,
+ type: type,
+ };
+ setPrompts(updatedPrompts);
+ }
+ }
+ setModalState('INACTIVE');
+ onSelectPrompt(editPromptName, id, type);
})
.catch((error) => {
console.error(error);
@@ -375,76 +382,65 @@ const Prompts: React.FC = ({
};
return (
-
-
-
Active Prompt
-
+ <>
+
+
+
+
Active Prompt
+
{
+ setModalType('EDIT');
+ setEditPromptName(name);
+ fetchPromptContent(id);
+ setCurrentPromptEdit({ id: id, name: name, type: type });
+ setModalState('ACTIVE');
+ }}
+ onDelete={handleDeletePrompt}
+ />
+
+
+
-
-
-
Prompt name
{' '}
-
- start by editing name
-
-
setNewPromptName(e.target.value)}
- />
-
-
-
-
-
-
-
-
-
-
+
+ >
);
};
@@ -499,10 +495,8 @@ const Documents: React.FC
= ({
}) => {
return (
-
- {/*
Documents
*/}
-
-
+
+
diff --git a/frontend/src/components/Dropdown.tsx b/frontend/src/components/Dropdown.tsx
index 0892c269..f88e93ac 100644
--- a/frontend/src/components/Dropdown.tsx
+++ b/frontend/src/components/Dropdown.tsx
@@ -1,10 +1,16 @@
import { useState } from 'react';
import Arrow2 from '../assets/dropdown-arrow.svg';
+import Edit from '../assets/edit.svg';
+import Trash from '../assets/trash.svg';
function Dropdown({
options,
selectedValue,
onSelect,
+ size = 'w-32',
+ rounded = 'xl',
+ showEdit,
+ onEdit,
showDelete,
onDelete,
placeholder,
@@ -20,6 +26,10 @@ function Dropdown({
| ((value: string) => void)
| ((value: { name: string; id: string; type: string }) => void)
| ((value: { label: string; value: string }) => void);
+ size?: string;
+ rounded?: 'xl' | '3xl';
+ showEdit?: boolean;
+ onEdit?: (value: { name: string; id: string; type: string }) => void;
showDelete?: boolean;
onDelete?: (value: string) => void;
placeholder?: string;
@@ -28,19 +38,22 @@ function Dropdown({
}) {
const [isOpen, setIsOpen] = useState(false);
return (
-
+
{isOpen && (
-
+
{options.map((option: any, index) => (
+ {showEdit && onEdit && (
+

{
+ onEdit({
+ id: option.id,
+ name: option.name,
+ type: option.type,
+ });
+ setIsOpen(false);
+ }}
+ />
+ )}
{showDelete && onDelete && (
-
diff --git a/frontend/src/components/SourceDropdown.tsx b/frontend/src/components/SourceDropdown.tsx
index 04b95d7c..353d49db 100644
--- a/frontend/src/components/SourceDropdown.tsx
+++ b/frontend/src/components/SourceDropdown.tsx
@@ -24,6 +24,12 @@ function SourceDropdown({
const embeddingsName =
import.meta.env.VITE_EMBEDDINGS_NAME ||
'huggingface_sentence-transformers/all-mpnet-base-v2';
+
+ const handleEmptyDocumentSelect = () => {
+ dispatch(setSelectedDocs(null));
+ setIsDocsListOpen(false);
+ };
+
return (
- {selectedDocs?.name}
+ {selectedDocs?.name || ''}
{selectedDocs?.version}
@@ -93,6 +99,14 @@ function SourceDropdown({
No default documentation.
)}
+
+
+ Empty
+
+
)}
diff --git a/frontend/src/conversation/conversationApi.ts b/frontend/src/conversation/conversationApi.ts
index e586366b..e3a82191 100644
--- a/frontend/src/conversation/conversationApi.ts
+++ b/frontend/src/conversation/conversationApi.ts
@@ -6,7 +6,7 @@ const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com';
export function fetchAnswerApi(
question: string,
signal: AbortSignal,
- selectedDocs: Doc,
+ selectedDocs: Doc | null,
history: Array
= [],
conversationId: string | null,
promptId: string | null,
@@ -28,24 +28,26 @@ export function fetchAnswerApi(
title: any;
}
> {
- let namePath = selectedDocs.name;
- if (selectedDocs.language === namePath) {
- namePath = '.project';
- }
-
let docPath = 'default';
- if (selectedDocs.location === 'local') {
- docPath = 'local' + '/' + selectedDocs.name + '/';
- } else if (selectedDocs.location === 'remote') {
- docPath =
- selectedDocs.language +
- '/' +
- namePath +
- '/' +
- selectedDocs.version +
- '/' +
- selectedDocs.model +
- '/';
+
+ if (selectedDocs) {
+ let namePath = selectedDocs.name;
+ if (selectedDocs.language === namePath) {
+ namePath = '.project';
+ }
+ if (selectedDocs.location === 'local') {
+ docPath = 'local' + '/' + selectedDocs.name + '/';
+ } else if (selectedDocs.location === 'remote') {
+ docPath =
+ selectedDocs.language +
+ '/' +
+ namePath +
+ '/' +
+ selectedDocs.version +
+ '/' +
+ selectedDocs.model +
+ '/';
+ }
}
//in history array remove all keys except prompt and response
history = history.map((item) => {
@@ -89,31 +91,33 @@ export function fetchAnswerApi(
export function fetchAnswerSteaming(
question: string,
signal: AbortSignal,
- selectedDocs: Doc,
+ selectedDocs: Doc | null,
history: Array = [],
conversationId: string | null,
promptId: string | null,
chunks: string,
onEvent: (event: MessageEvent) => void,
): Promise {
- let namePath = selectedDocs.name;
- if (selectedDocs.language === namePath) {
- namePath = '.project';
- }
-
let docPath = 'default';
- if (selectedDocs.location === 'local') {
- docPath = 'local' + '/' + selectedDocs.name + '/';
- } else if (selectedDocs.location === 'remote') {
- docPath =
- selectedDocs.language +
- '/' +
- namePath +
- '/' +
- selectedDocs.version +
- '/' +
- selectedDocs.model +
- '/';
+
+ if (selectedDocs) {
+ let namePath = selectedDocs.name;
+ if (selectedDocs.language === namePath) {
+ namePath = '.project';
+ }
+ if (selectedDocs.location === 'local') {
+ docPath = 'local' + '/' + selectedDocs.name + '/';
+ } else if (selectedDocs.location === 'remote') {
+ docPath =
+ selectedDocs.language +
+ '/' +
+ namePath +
+ '/' +
+ selectedDocs.version +
+ '/' +
+ selectedDocs.model +
+ '/';
+ }
}
history = history.map((item) => {
@@ -186,7 +190,7 @@ export function fetchAnswerSteaming(
}
export function searchEndpoint(
question: string,
- selectedDocs: Doc,
+ selectedDocs: Doc | null,
conversation_id: string | null,
history: Array = [],
chunks: string,
@@ -196,24 +200,25 @@ export function searchEndpoint(
"question": "Summarise",
"conversation_id": null,
"history": "[]" */
- let namePath = selectedDocs.name;
- if (selectedDocs.language === namePath) {
- namePath = '.project';
- }
-
let docPath = 'default';
- if (selectedDocs.location === 'local') {
- docPath = 'local' + '/' + selectedDocs.name + '/';
- } else if (selectedDocs.location === 'remote') {
- docPath =
- selectedDocs.language +
- '/' +
- namePath +
- '/' +
- selectedDocs.version +
- '/' +
- selectedDocs.model +
- '/';
+ if (selectedDocs) {
+ let namePath = selectedDocs.name;
+ if (selectedDocs.language === namePath) {
+ namePath = '.project';
+ }
+ if (selectedDocs.location === 'local') {
+ docPath = 'local' + '/' + selectedDocs.name + '/';
+ } else if (selectedDocs.location === 'remote') {
+ docPath =
+ selectedDocs.language +
+ '/' +
+ namePath +
+ '/' +
+ selectedDocs.version +
+ '/' +
+ selectedDocs.model +
+ '/';
+ }
}
const body = {
diff --git a/frontend/src/preferences/PromptsModal.tsx b/frontend/src/preferences/PromptsModal.tsx
new file mode 100644
index 00000000..596c9f59
--- /dev/null
+++ b/frontend/src/preferences/PromptsModal.tsx
@@ -0,0 +1,213 @@
+import { ActiveState } from '../models/misc';
+
+function AddPrompt({
+ setModalState,
+ handleAddPrompt,
+ newPromptName,
+ setNewPromptName,
+ newPromptContent,
+ setNewPromptContent,
+}: {
+ setModalState: (state: ActiveState) => void;
+ handleAddPrompt?: () => void;
+ newPromptName: string;
+ setNewPromptName: (name: string) => void;
+ newPromptContent: string;
+ setNewPromptContent: (content: string) => void;
+}) {
+ return (
+
+
Add Prompt
+
+ Add your custom prompt and save it to DocsGPT
+
+
+
setNewPromptName(e.target.value)}
+ >
+
+
+ Prompt Name
+
+
+
+
+ Prompt Text
+
+
+
+
+
+
+ Save
+
+ {
+ setModalState('INACTIVE');
+ }}
+ className="cursor-pointer font-medium dark:text-light-gray"
+ >
+ Cancel
+
+
+
+ );
+}
+
+function EditPrompt({
+ setModalState,
+ handleEditPrompt,
+ editPromptName,
+ setEditPromptName,
+ editPromptContent,
+ setEditPromptContent,
+ currentPromptEdit,
+}: {
+ setModalState: (state: ActiveState) => void;
+ handleEditPrompt?: (id: string, type: string) => void;
+ editPromptName: string;
+ setEditPromptName: (name: string) => void;
+ editPromptContent: string;
+ setEditPromptContent: (content: string) => void;
+ currentPromptEdit: { name: string; id: string; type: string };
+}) {
+ return (
+
+
Edit Prompt
+
+ Edit your custom prompt and save it to DocsGPT
+
+
+
setEditPromptName(e.target.value)}
+ >
+
+
+ Prompt Name
+
+
+
+
+ Prompt Text
+
+
+
+
+
+ {
+ handleEditPrompt &&
+ handleEditPrompt(currentPromptEdit.id, currentPromptEdit.type);
+ }}
+ disabled={currentPromptEdit.type === 'public'}
+ >
+ Save
+
+ {
+ setModalState('INACTIVE');
+ }}
+ className="cursor-pointer font-medium dark:text-light-gray"
+ >
+ Cancel
+
+
+
+ );
+}
+
+export default function PromptsModal({
+ modalState,
+ setModalState,
+ type,
+ newPromptName,
+ setNewPromptName,
+ newPromptContent,
+ setNewPromptContent,
+ editPromptName,
+ setEditPromptName,
+ editPromptContent,
+ setEditPromptContent,
+ currentPromptEdit,
+ handleAddPrompt,
+ handleEditPrompt,
+}: {
+ modalState: ActiveState;
+ setModalState: (state: ActiveState) => void;
+ type: 'ADD' | 'EDIT';
+ newPromptName: string;
+ setNewPromptName: (name: string) => void;
+ newPromptContent: string;
+ setNewPromptContent: (content: string) => void;
+ editPromptName: string;
+ setEditPromptName: (name: string) => void;
+ editPromptContent: string;
+ setEditPromptContent: (content: string) => void;
+ currentPromptEdit: { name: string; id: string; type: string };
+ handleAddPrompt?: () => void;
+ handleEditPrompt?: (id: string, type: string) => void;
+}) {
+ let view;
+
+ if (type === 'ADD') {
+ view = (
+
+ );
+ } else if (type === 'EDIT') {
+ view = (
+
+ );
+ } else {
+ view = <>>;
+ }
+ return (
+
+
+ {view}
+
+
+ );
+}
diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx
index b2144427..39c2a093 100644
--- a/frontend/src/upload/Upload.tsx
+++ b/frontend/src/upload/Upload.tsx
@@ -308,6 +308,8 @@ export default function Upload({
onSelect={(value: { label: string; value: string }) =>
setUrlType(value)
}
+ size="w-full"
+ rounded="3xl"
/>
{urlType.label !== 'Reddit' ? (
<>