From a6a9a0008909afa649a11e9c1be78998553f0bc9 Mon Sep 17 00:00:00 2001 From: Taichiro Suzuki Date: Wed, 4 Dec 2024 15:07:18 +0900 Subject: [PATCH] fix --- .../useCaseBuilder/UseCaseBuilderHelp.tsx | 91 +++++++++++++++--- .../useCaseBuilder/UseCaseBuilderView.tsx | 92 +++++++++++++++++-- .../useCaseBuilder/UseCaseBuilderEditPage.tsx | 2 +- packages/web/src/utils/UseCaseBuilderUtils.ts | 10 +- .../web/tests/use-case-builder/items.test.ts | 58 ++++++++++++ 5 files changed, 226 insertions(+), 27 deletions(-) diff --git a/packages/web/src/components/useCaseBuilder/UseCaseBuilderHelp.tsx b/packages/web/src/components/useCaseBuilder/UseCaseBuilderHelp.tsx index 16d282d3..545b5d15 100644 --- a/packages/web/src/components/useCaseBuilder/UseCaseBuilderHelp.tsx +++ b/packages/web/src/components/useCaseBuilder/UseCaseBuilderHelp.tsx @@ -21,12 +21,11 @@ const PromptSample: React.FC = (props) => { {isOpen && ( -
+        
           {props.prompt}
-          
+          
+ +
)} @@ -51,28 +50,76 @@ const UseCaseBuilderHelp: React.FC = (props) => {
-
- プロンプトテンプレートについて -
+
プロンプトテンプレートとは?
- ユースケースごとに、プロンプトテンプレートを定義することができます。ユースケースを実行すると、ここで定義したプロンプトテンプレートをもとに、生成 - AI が推論を行います。 + 生成AIに指示を出すための「ひな形」のようなものです。目的に応じて、あらかじめ指示文の型を用意しておくことができます。
-
可変項目の設定
+
可変項目
- プロンプトテンプレートの中には、可変項目を設定することができます。この可変項目を設定すると、自動的に画面上に入力欄が配置されます。ユースケースを実行すると、プロンプトテンプレート内の可変項目が対応する画面の入力値で置換されます。 + プロンプトテンプレートの中に「後から内容を入れられる場所」(可変項目)を作れます。例えるなら、穴埋め問題の空欄のようなものです。 + 可変項目を定義すると、自動的に入力用の欄が画面に表示されます。 + また、入力された内容が実行時にテンプレート内の該当箇所に自動で入ります。
可変項目の設定方法
- プロンプトテンプレート内に、 - + プロンプトテンプレート内に以下の形式で記述します。 +
+ + {'{{入力タイプ:見出し}}'} + +
+ ※「見出し」は入力欄のラベルとなります(省略可) +
+
+
+
可変項目一覧
+
+
{'{{text:見出し}}'} +
+ 自由入力を受け付けます。入力された内容をそのまま可変項目が定義された場所に埋め込みます。 +
+
+
+ {'{{retrieveKendra:見出し}}'} +
+ Amazon Kendra から Retrieve + した結果を可変項目が定義された場所に埋め込みます。Retrieve + した結果は Amazon Kendra の Retrieve API の + + ResultItems を JSON にした文字列 + + です。 + + この機能を利用するためには、GenU で RAG チャット (Amazon Kendra) + が有効になっている必要があります。 + +
+
+
+ {'{{retrieveKnowledgeBase:見出し}}'} +
+ Knowledge Base から Retrieve + した結果を可変項目が定義された場所に埋め込みます。Retrieve + した結果は Knowledge Base の Retrieve API の + + retrievalResults を JSON にした文字列 + + です。 + + この機能を利用するためには、GenU で RAG チャット (Knowledge Base) + が有効になっている必要があります。 - の形式で入力してください。「見出し」は画面上に表示される入力項目のラベルとなります。
@@ -113,6 +160,20 @@ const UseCaseBuilderHelp: React.FC = (props) => { {{text:CDK で生成したい構成の概要}} `} /> + +{{text:質問}} + + +<情報> +{{retrieveKnowledgeBase:検索クエリ}} +`} + />
diff --git a/packages/web/src/components/useCaseBuilder/UseCaseBuilderView.tsx b/packages/web/src/components/useCaseBuilder/UseCaseBuilderView.tsx index 50ed3760..2a20d790 100644 --- a/packages/web/src/components/useCaseBuilder/UseCaseBuilderView.tsx +++ b/packages/web/src/components/useCaseBuilder/UseCaseBuilderView.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useEffect, useMemo } from 'react'; +import React, { useCallback, useEffect, useMemo, useState } from 'react'; import Select from '../Select'; import Button from '../Button'; import useChat from '../../hooks/useChat'; @@ -21,6 +21,12 @@ import { extractPlaceholdersFromPromptTemplate, getItemsFromPlaceholders, } from '../../utils/UseCaseBuilderUtils'; +import useRagKnowledgeBaseApi from '../../hooks/useRagKnowledgeBaseApi'; +import useRagApi from '../../hooks/useRagApi'; + +const ragEnabled: boolean = import.meta.env.VITE_APP_RAG_ENABLED === 'true'; +const ragKnowledgeBaseEnabled: boolean = + import.meta.env.VITE_APP_RAG_KNOWLEDGE_BASE_ENABLED === 'true'; type Props = { modelId?: string; @@ -90,6 +96,7 @@ const UseCaseBuilderView: React.FC = (props) => { getModelId, setModelId, loading, + setLoading, messages, postChat, clear: clearChat, @@ -104,6 +111,9 @@ const UseCaseBuilderView: React.FC = (props) => { const { modelIds: availableModels } = MODELS; const { setTypingTextInput, typingTextOutput } = useTyping(loading); const { updateRecentUseUseCase } = useMyUseCases(); + const { retrieve: retrieveKendra } = useRagApi(); + const { retrieve: retrieveKnowledgeBase } = useRagKnowledgeBaseApi(); + const [warnMessages, setWarnMessages] = useState([]); const placeholders = useMemo(() => { return extractPlaceholdersFromPromptTemplate(props.promptTemplate); @@ -141,12 +151,37 @@ const UseCaseBuilderView: React.FC = (props) => { // eslint-disable-next-line react-hooks/exhaustive-deps }, [messages]); - const onClickExec = useCallback(() => { + useEffect(() => { + const hasKendra = + items.filter((i) => i.inputType === 'retrieveKendra').length > 0; + const hasKnowledgeBase = + items.filter((i) => i.inputType === 'retrieveKnowledgeBase').length > 0; + const tmpWarnMessages = []; + + if (hasKendra && !ragEnabled) { + tmpWarnMessages.push( + 'プロンプトテンプレート内で {{retrieveKendra}} が指定されていますが GenU で RAG チャット (Amazon Kendra) が有効になっていません。' + ); + } + + if (hasKnowledgeBase && !ragKnowledgeBaseEnabled) { + tmpWarnMessages.push( + 'プロンプトテンプレート内で {{retrieveKnowledgeBase}} が指定されていますが GenU で RAG チャット (Knowledge Base) が有効になっていません。' + ); + } + + setWarnMessages(tmpWarnMessages); + }, [setWarnMessages, items]); + + const onClickExec = useCallback(async () => { if (loading) return; + setLoading(true); + setText(''); + let prompt = props.promptTemplate; - items.forEach((item, idx) => { + for (const [idx, item] of items.entries()) { let placeholder; if (item.label !== NOLABEL) { @@ -154,13 +189,40 @@ const UseCaseBuilderView: React.FC = (props) => { } else { placeholder = `{{${item.inputType}}}`; } - prompt = prompt.replace(new RegExp(placeholder, 'g'), values[idx]); - }); + + if (item.inputType === 'text') { + prompt = prompt.replace(new RegExp(placeholder, 'g'), values[idx]); + } else if (item.inputType === 'retrieveKendra') { + if (ragEnabled) { + const res = await retrieveKendra(values[idx]); + const resJson = JSON.stringify(res.data.ResultItems); + prompt = prompt.replace(new RegExp(placeholder, 'g'), resJson); + } + } else if (item.inputType === 'retrieveKnowledgeBase') { + if (ragKnowledgeBaseEnabled) { + const res = await retrieveKnowledgeBase(values[idx]); + const resJson = JSON.stringify(res.data.retrievalResults); + prompt = prompt.replace(new RegExp(placeholder, 'g'), resJson); + } + } + } + postChat(prompt, true); if (!props.previewMode) { updateRecentUseUseCase(props.useCaseId); } - }, [loading, items, postChat, props, updateRecentUseUseCase, values]); + }, [ + loading, + items, + postChat, + props, + updateRecentUseUseCase, + values, + setLoading, + retrieveKendra, + retrieveKnowledgeBase, + setText, + ]); // リセット const onClickClear = useCallback(() => { @@ -217,6 +279,15 @@ const UseCaseBuilderView: React.FC = (props) => { )} + {warnMessages.length > 0 && + warnMessages.map((m, idx) => ( +
+ {m} +
+ ))} + {props.description && (
{props.description}
)} @@ -247,7 +318,7 @@ const UseCaseBuilderView: React.FC = (props) => {