From 0b09c00b50edc437b4011d5c058418a97394eef8 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 14:47:29 +0100 Subject: [PATCH 01/13] chore: modified handleQuestion to favor "Retry" action after a failed response generation --- frontend/src/conversation/Conversation.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index cf4949e9..1bddf2e3 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -80,11 +80,11 @@ export default function Conversation() { }); }; - const handleQuestion = (question: string) => { + const handleQuestion = (question: string, isRetry = false) => { question = question.trim(); if (question === '') return; setEventInterrupt(false); - dispatch(addQuery({ prompt: question })); + !isRetry && dispatch(addQuery({ prompt: question })); //dispatch only new queries fetchStream.current = dispatch(fetchAnswer({ question })); }; const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => { From ae846dac4d5682b7334aae0d5212a405126bd3bd Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 15:33:24 +0100 Subject: [PATCH 02/13] chore: received changes from upstream --- frontend/src/conversation/conversationApi.ts | 1 - frontend/src/locale/en.json | 16 ++++++++-------- frontend/src/locale/es.json | 14 +++++++------- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/frontend/src/conversation/conversationApi.ts b/frontend/src/conversation/conversationApi.ts index 2fe6eb7f..e107abc8 100644 --- a/frontend/src/conversation/conversationApi.ts +++ b/frontend/src/conversation/conversationApi.ts @@ -1,6 +1,5 @@ import { Answer, FEEDBACK } from './conversationModels'; import { Doc } from '../preferences/preferenceApi'; -import { selectTokenLimit } from '../preferences/preferenceSlice'; const apiHost = import.meta.env.VITE_API_HOST || 'https://docsapi.arc53.com'; diff --git a/frontend/src/locale/en.json b/frontend/src/locale/en.json index 94df2e75..7e39420b 100644 --- a/frontend/src/locale/en.json +++ b/frontend/src/locale/en.json @@ -9,7 +9,7 @@ "tagline": "DocsGPT uses GenAI, please review critial information using sources.", "sourceDocs": "Source Docs", "none": "None", - "cancel":"Cancel", + "cancel": "Cancel", "demo": [ { "header": "Learn about DocsGPT", @@ -41,13 +41,13 @@ "deleteAllLabel": "Delete all Conversation", "deleteAllBtn": "Delete all", "addNew": "Add New", - "convHistory":"Conversational history", - "none":"None", - "low":"Low", - "medium":"Medium", - "high":"High", - "unlimited":"Unlimited", - "default":"default" + "convHistory": "Conversational history", + "none": "None", + "low": "Low", + "medium": "Medium", + "high": "High", + "unlimited": "Unlimited", + "default": "default" }, "documents": { "label": "Documents", diff --git a/frontend/src/locale/es.json b/frontend/src/locale/es.json index 9ab6f8c4..70966e4b 100644 --- a/frontend/src/locale/es.json +++ b/frontend/src/locale/es.json @@ -41,13 +41,13 @@ "deleteAllLabel": "Eliminar toda la Conversación", "deleteAllBtn": "Eliminar todo", "addNew": "Agregar Nuevo", - "convHistory":"Historia conversacional", - "none":"ninguno", - "low":"Bajo", - "medium":"Medio", - "high":"Alto", - "unlimited":"Ilimitado", - "default":"predeterminada" + "convHistory": "Historia conversacional", + "none": "ninguno", + "low": "Bajo", + "medium": "Medio", + "high": "Alto", + "unlimited": "Ilimitado", + "default": "predeterminada" }, "documents": { "label": "Documentos", From 8d2ebe97187c42074df4782018af77f968497ba7 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 15:59:56 +0100 Subject: [PATCH 03/13] feat: "Retry" btn conditionally renders in place of query input when a generation fails. Uses prev query to fetch answer when clicked. --- frontend/src/conversation/Conversation.tsx | 93 ++++++++++++++-------- 1 file changed, 58 insertions(+), 35 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index 1bddf2e3..bda6b5f9 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -29,6 +29,7 @@ export default function Conversation() { const [hasScrolledToLast, setHasScrolledToLast] = useState(true); const fetchStream = useRef(null); const [eventInterrupt, setEventInterrupt] = useState(false); + const [lastQueryReturnedErr, setLastQueryReturnedErr] = useState(false); const { t } = useTranslation(); const handleUserInterruption = () => { @@ -73,6 +74,13 @@ export default function Conversation() { }; }, [endMessageRef.current]); + useEffect(() => { + if (queries.length) { + queries[queries.length - 1].error && setLastQueryReturnedErr(true); + queries[queries.length - 1].response && setLastQueryReturnedErr(false); //considering a query that initially returned error can later include a response property on retry + } + }, [queries]); + const scrollIntoView = () => { endMessageRef?.current?.scrollIntoView({ behavior: 'smooth', @@ -174,45 +182,60 @@ export default function Conversation() { {queries.length === 0 && }
-
-
{ - if (e.key === 'Enter' && !e.shiftKey) { - e.preventDefault(); - if (inputRef.current?.textContent && status !== 'loading') { - handleQuestion(inputRef.current.textContent); - inputRef.current.textContent = ''; - } - } - }} - >
- {status === 'loading' ? ( - - ) : ( -
- { - if (inputRef.current?.textContent) { + {!lastQueryReturnedErr ? ( +
+
{ + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + if (inputRef.current?.textContent && status !== 'loading') { handleQuestion(inputRef.current.textContent); inputRef.current.textContent = ''; } - }} - src={isDarkTheme ? SendDark : Send} + } + }} + >
+ {status === 'loading' ? ( + -
- )} -
+ ) : ( +
+ { + if (inputRef.current?.textContent) { + handleQuestion(inputRef.current.textContent); + inputRef.current.textContent = ''; + } + }} + src={isDarkTheme ? SendDark : Send} + > +
+ )} +
+ ) : ( +
+

There was an error during generation

+ +
+ )} +

{t('tagline')}

From 414ec08deee416ae166f290eb56e3a988a27904b Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 17:26:19 +0100 Subject: [PATCH 04/13] refactor: modified prepResponseView to prioritize query.response and trigger re-render after a failed generation is retried --- frontend/src/conversation/Conversation.tsx | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index bda6b5f9..3cd3176d 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -79,7 +79,7 @@ export default function Conversation() { queries[queries.length - 1].error && setLastQueryReturnedErr(true); queries[queries.length - 1].response && setLastQueryReturnedErr(false); //considering a query that initially returned error can later include a response property on retry } - }, [queries]); + }, [queries[queries.length - 1]]); const scrollIntoView = () => { endMessageRef?.current?.scrollIntoView({ @@ -105,17 +105,7 @@ export default function Conversation() { const prepResponseView = (query: Query, index: number) => { let responseView; - if (query.error) { - responseView = ( - - ); - } else if (query.response) { + if (query.response) { responseView = ( ); + } else if (query.error) { + responseView = ( + + ); } return responseView; }; From c26573482e03bd0673e00d988173a5de796308e4 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 17:28:13 +0100 Subject: [PATCH 05/13] style: retry query generation btn --- frontend/src/conversation/Conversation.tsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index 3cd3176d..03eb240f 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -173,6 +173,7 @@ export default function Conversation() { type="QUESTION" sources={query.sources} > + {prepResponseView(query, index)} ); @@ -223,10 +224,13 @@ export default function Conversation() { )}
) : ( -
-

There was an error during generation

+
+

+ There was an error during generation +

)} -

+

{t('tagline')}

From 2f580f780020cf1cc49d91c7fd1631eaec685b64 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Fri, 7 Jun 2024 17:40:33 +0100 Subject: [PATCH 06/13] feat: japan locale config --- frontend/src/locale/jp.json | 207 ++++++++++++++++++------------------ 1 file changed, 103 insertions(+), 104 deletions(-) diff --git a/frontend/src/locale/jp.json b/frontend/src/locale/jp.json index bb97554c..a025a17a 100644 --- a/frontend/src/locale/jp.json +++ b/frontend/src/locale/jp.json @@ -1,109 +1,108 @@ { - "language": "日本語", - "chat": "チャット", - "chats": "チャット", - "newChat": "新しいチャット", - "myPlan": "私のプラン", - "about": "について", - "inputPlaceholder": "ここにメッセージを入力してください...", - "tagline": "DocsGPTはGenAIを使用しています。重要な情報はソースで確認してください。", - "sourceDocs": "ソースドキュメント", - "none": "なし", - "cancel":"キャンセル", - "demo": [ - { - "header": "DocsGPTについて学ぶ", - "query": "DocsGPTとは何ですか?" - }, - { - "header": "ドキュメントを要約する", - "query": "現在のコンテキストを要約してください" - }, - { - "header": "コードを書く", - "query": "APIリクエストのコードを/api/answerに書いてください。" - }, - { - "header": "学習支援", - "query": "コンテキストに対する潜在的な質問を書いてください" - } - ], - "settings": { - "label": "設定", - "general": { - "label": "一般", - "selectTheme": "テーマを選択", - "light": "ライト", - "dark": "ダーク", - "selectLanguage": "言語を選択", - "chunks": "クエリごとに処理されるチャンク", - "prompt": "アクティブプロンプト", - "deleteAllLabel": "すべての会話を削除", - "deleteAllBtn": "すべて削除", - "addNew": "新規追加", - "convHistory":"会話履歴", - "none":"なし", - "low":"低", - "medium":"中", - "high":"高", - "unlimited":"無制限", - "default":"デフォルト" - }, - "documents": { - "label": "ドキュメント", - "name": "ドキュメント名", - "date": "ベクトル日付", - "type": "タイプ", - "tokenUsage": "トークン使用量" - }, - "apiKeys": { - "label": "APIキー", - "name": "名前", - "key": "APIキー", - "sourceDoc": "ソースドキュメント", - "createNew": "新規作成" + "language": "日本語", + "chat": "チャット", + "chats": "チャット", + "newChat": "新しいチャット", + "myPlan": "私のプラン", + "about": "について", + "inputPlaceholder": "ここにメッセージを入力してください...", + "tagline": "DocsGPTはGenAIを使用しています。重要な情報はソースで確認してください。", + "sourceDocs": "ソースドキュメント", + "none": "なし", + "cancel": "キャンセル", + "demo": [ + { + "header": "DocsGPTについて学ぶ", + "query": "DocsGPTとは何ですか?" + }, + { + "header": "ドキュメントを要約する", + "query": "現在のコンテキストを要約してください" + }, + { + "header": "コードを書く", + "query": "APIリクエストのコードを/api/answerに書いてください。" + }, + { + "header": "学習支援", + "query": "コンテキストに対する潜在的な質問を書いてください" + } + ], + "settings": { + "label": "設定", + "general": { + "label": "一般", + "selectTheme": "テーマを選択", + "light": "ライト", + "dark": "ダーク", + "selectLanguage": "言語を選択", + "chunks": "クエリごとに処理されるチャンク", + "prompt": "アクティブプロンプト", + "deleteAllLabel": "すべての会話を削除", + "deleteAllBtn": "すべて削除", + "addNew": "新規追加", + "convHistory": "会話履歴", + "none": "なし", + "low": "低", + "medium": "中", + "high": "高", + "unlimited": "無制限", + "default": "デフォルト" + }, + "documents": { + "label": "ドキュメント", + "name": "ドキュメント名", + "date": "ベクトル日付", + "type": "タイプ", + "tokenUsage": "トークン使用量" + }, + "apiKeys": { + "label": "APIキー", + "name": "名前", + "key": "APIキー", + "sourceDoc": "ソースドキュメント", + "createNew": "新規作成" + } + }, + "modals": { + "uploadDoc": { + "label": "新規書類のアップロード", + "file": "ファイルから", + "remote": "リモート", + "name": "名前", + "choose": "ファイルを選択", + "info": ".pdf, .txt, .rst, .docx, .md, .zipファイルを25MBまでアップロードしてください", + "uploadedFiles": "アップロードされたファイル", + "cancel": "キャンセル", + "train": "トレーニング", + "link": "リンク", + "urlLink": "URLリンク", + "reddit": { + "id": "クライアントID", + "secret": "クライアントシークレット", + "agent": "ユーザーエージェント", + "searchQueries": "検索クエリ", + "numberOfPosts": "投稿数" } }, - "modals": { - "uploadDoc": { - "label": "新規書類のアップロード", - "file": "ファイルから", - "remote": "リモート", - "name": "名前", - "choose": "ファイルを選択", - "info": ".pdf, .txt, .rst, .docx, .md, .zipファイルを25MBまでアップロードしてください", - "uploadedFiles": "アップロードされたファイル", - "cancel": "キャンセル", - "train": "トレーニング", - "link": "リンク", - "urlLink": "URLリンク", - "reddit": { - "id": "クライアントID", - "secret": "クライアントシークレット", - "agent": "ユーザーエージェント", - "searchQueries": "検索クエリ", - "numberOfPosts": "投稿数" - } - }, - "createAPIKey": { - "label": "新しいAPIキーを作成", - "apiKeyName": "APIキー名", - "chunks": "クエリごとに処理されるチャンク", - "prompt": "アクティブプロンプトを選択", - "sourceDoc": "ソースドキュメント", - "create": "作成" - }, - "saveKey": { - "note": "キーを保存してください", - "disclaimer": "キーが表示されるのはこのときだけです。", - "copy": "コピー", - "copied": "コピーしました", - "confirm": "キーを保存しました" - }, - "deleteConv": { - "confirm": "すべての会話を削除してもよろしいですか?", - "delete": "削除" - } + "createAPIKey": { + "label": "新しいAPIキーを作成", + "apiKeyName": "APIキー名", + "chunks": "クエリごとに処理されるチャンク", + "prompt": "アクティブプロンプトを選択", + "sourceDoc": "ソースドキュメント", + "create": "作成" + }, + "saveKey": { + "note": "キーを保存してください", + "disclaimer": "キーが表示されるのはこのときだけです。", + "copy": "コピー", + "copied": "コピーしました", + "confirm": "キーを保存しました" + }, + "deleteConv": { + "confirm": "すべての会話を削除してもよろしいですか?", + "delete": "削除" } } - \ No newline at end of file +} From 32c06414c530023e9f5d4e58d907dac9d649fbf2 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sat, 8 Jun 2024 03:29:18 +0100 Subject: [PATCH 07/13] style: added theme adaptable RetryIcon component to Retry btn --- frontend/src/components/RetryIcon.tsx | 17 +++++++++++++++++ frontend/src/conversation/Conversation.tsx | 12 +++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 frontend/src/components/RetryIcon.tsx diff --git a/frontend/src/components/RetryIcon.tsx b/frontend/src/components/RetryIcon.tsx new file mode 100644 index 00000000..27ed6028 --- /dev/null +++ b/frontend/src/components/RetryIcon.tsx @@ -0,0 +1,17 @@ +import * as React from 'react'; +import { SVGProps } from 'react'; +const RetryIcon = (props: SVGProps) => ( + + + +); +export default RetryIcon; diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index 03eb240f..2bb9d101 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -19,6 +19,7 @@ import { FEEDBACK, Query } from './conversationModels'; import { sendFeedback } from './conversationApi'; import { useTranslation } from 'react-i18next'; import ArrowDown from './../assets/arrow-down.svg'; +import RetryIcon from '../components/RetryIcon'; export default function Conversation() { const queries = useSelector(selectQueries); const status = useSelector(selectStatus); @@ -229,12 +230,21 @@ export default function Conversation() { There was an error during generation

From ee762c3c68dab4531b99df66f78af76dbb12b42f Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Sun, 9 Jun 2024 13:47:51 +0100 Subject: [PATCH 08/13] chore: modified handleQuestion params for more clarity --- frontend/src/Hero.tsx | 10 ++++++++-- frontend/src/conversation/Conversation.tsx | 19 +++++++++++++++---- 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/frontend/src/Hero.tsx b/frontend/src/Hero.tsx index 69bf23ac..f138ec4f 100644 --- a/frontend/src/Hero.tsx +++ b/frontend/src/Hero.tsx @@ -4,7 +4,13 @@ import { useTranslation } from 'react-i18next'; export default function Hero({ handleQuestion, }: { - handleQuestion: (question: string) => void; + handleQuestion: ({ + question, + isRetry, + }: { + question: string; + isRetry?: boolean; + }) => void; }) { const { t } = useTranslation(); const demos = t('demo', { returnObjects: true }) as Array<{ @@ -30,7 +36,7 @@ export default function Hero({ demo.query && ( + )} + +
+
{ + if (e.key === 'Enter' && !e.shiftKey) { + e.preventDefault(); + if (inputRef.current?.textContent && status !== 'loading') { + handleQuestion({ question: inputRef.current.textContent }); + inputRef.current.textContent = ''; + } + } + }} + >
+ {status === 'loading' ? ( + + ) : ( +
+ { + if (inputRef.current?.textContent) { + handleQuestion({ + question: inputRef.current.textContent, + }); inputRef.current.textContent = ''; } - } - }} - >
- {status === 'loading' ? ( - - ) : ( -
- { - if (inputRef.current?.textContent) { - handleQuestion({ - question: inputRef.current.textContent, - }); - inputRef.current.textContent = ''; - } - }} - src={isDarkTheme ? SendDark : Send} - > -
- )} -
- ) : ( -
-

- There was an error during generation -

- -
- )} + + )} +

{t('tagline')} From 2f9cbe2bf112d2b357eaea7779e65d82b61e9234 Mon Sep 17 00:00:00 2001 From: utin-francis-peter Date: Tue, 11 Jun 2024 20:30:12 +0100 Subject: [PATCH 11/13] chore: if user types in a new prompt after failed generation (instead of hitting retry btn), the failed query is updated with the new prompt before response is fetched. Ensuring every query object remains useful & relevant --- frontend/src/conversation/Conversation.tsx | 46 +++++++++++++++------- 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/frontend/src/conversation/Conversation.tsx b/frontend/src/conversation/Conversation.tsx index 1695f714..8d221570 100644 --- a/frontend/src/conversation/Conversation.tsx +++ b/frontend/src/conversation/Conversation.tsx @@ -33,6 +33,8 @@ export default function Conversation() { const [lastQueryReturnedErr, setLastQueryReturnedErr] = useState(false); const { t } = useTranslation(); + console.log('QUERIES: ', queries); + const handleUserInterruption = () => { if (!eventInterrupt && status === 'loading') setEventInterrupt(true); }; @@ -102,6 +104,7 @@ export default function Conversation() { !isRetry && dispatch(addQuery({ prompt: question })); //dispatch only new queries fetchStream.current = dispatch(fetchAnswer({ question })); }; + const handleFeedback = (query: Query, feedback: FEEDBACK, index: number) => { const prevFeedback = query.feedback; dispatch(updateQuery({ index, query: { feedback } })); @@ -110,6 +113,29 @@ export default function Conversation() { ); }; + const handleQuestionSubmission = () => { + if (inputRef.current?.textContent && status !== 'loading') { + if (lastQueryReturnedErr) { + // update last failed query with new prompt + dispatch( + updateQuery({ + index: queries.length - 1, + query: { + prompt: inputRef.current.textContent, + }, + }), + ); + handleQuestion({ + question: queries[queries.length - 1].prompt, + isRetry: true, + }); + } else { + handleQuestion({ question: inputRef.current.textContent }); + } + inputRef.current.textContent = ''; + } + }; + const prepResponseView = (query: Query, index: number) => { let responseView; if (query.response) { @@ -196,12 +222,12 @@ export default function Conversation() { + ); responseView = ( ); } @@ -213,6 +233,7 @@ export default function Conversation() { {queries.length === 0 && } +

void; sources?: { title: string; text: string; source: string }[]; + retryBtn?: React.ReactElement; } >(function ConversationBubble( - { message, type, className, feedback, handleFeedback, sources }, + { message, type, className, feedback, handleFeedback, sources, retryBtn }, ref, ) { const [openSource, setOpenSource] = useState(null); @@ -69,12 +70,17 @@ const ConversationBubble = forwardRef<
{type === 'ERROR' && ( - alert + <> + alert +
+ {retryBtn} +
+ )}