Bedrock KnowledgeBase APIをReactでブラウザ上から利用可能にしてみた

technologies

おはようございます!

株式会社ベンジャミンの木村です!

Bedrock KnowledgeBaseのAPI作成記事でも紹介させていただきましたが、

今回、私はBedrock KnowledgeBaseを使って、以下のような自社のことを回答する簡易チャットアプリを作成しました。

その時の経験をもとに、今回はBedrock KnowledgeBaseのAPIをReactブラウザ表示する手順を記載させていただきます!

※前回、Bedrock KnowledgeBaseのAPIを作るためのバックエンド部分(API Gateway / Lambda)の構築を行いましたので、APIの作成方法がわからない方は、先に下記ブログを実践後に、今回のブログを参考にいただければと思います。

目次

今回作成するもの

下記の通りForm、Button、Text(Bedrockからの返答文)があるだけのシンプルな画面になっております。一旦はこれだけあれば今回の機能を利用できますので、ここからデザインを整えるなどの処理をしていただければと思います。

今回使う技術のバージョン / ファイルの階層

[バージョン]

  • React:18.3
  • chakra-ui/react:2.8.2
  • axios:1.6.8

[ファイルの階層]

~~~~~~~~~~~~~
├── node_modules
├── public
├── src
│   ├── App.tsx
│   ├── components
│   │   └── ChatForm.tsx
│   └── index.tsx
~~~~~~~~~~~~~

1. Reactの準備

Reactをインストールし、準備を行います。普段からReactを使い慣れている方はここは飛ばしていただいても大丈夫です。

1-1.React × TypeScriptをインストール

npx create-react-app <任意のアプリケーション名> --template typescript

※nodeのインストールがされていない場合、上記コマンドはエラーとなります。下記記事が大変わかりやすい内容となっておりますので、ご参照ください。

https://qiita.com/blue_fish/items/7440df68734f3d5ce772

Macにnodejsをインストールする方法

1-2. アプリケーションのディレクトリに移動

cd <任意のアプリケーション名>

1-3. Reactの初期画面を起動

npm start

下記画面がブラウザ表示されれば、Reactがインストールされていることがわかる

1-4. 不要資材の削除

下記ファイルを削除してください

  • src/App.css
  • src/App.test.tsx
  • src/index.css
  • src/logo.svg
  • src/react-app-env.d.ts
  • src/reportWebVitals.ts
  • src/setupTests.ts

1-5. index.tsx / App.tsxの中身を下記の通り変更する

  • index.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

After

import React from 'react';
import ReactDOM from 'react-dom/client';
import { App }  from './App';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

  • App.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before

import React from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

After

export const App = () => {
  return (
    <div>
      test
    </div>
  );
}

ブラウザ上で下記のように表されれば準備完了

2. Chakra UIを用いてCSS / HTMLの準備

Chakra UIというCSSフレームワークを使ってデザインを整えていきます。
アレンジするために、CSSの書き方や、使えるコンポーネントなどを知りたい方は、以下Chakra UI公式よりご参照ください。

https://v2.chakra-ui.com

2-1. Chakra UIをインストール

npm i @chakra-ui/react @emotion/react @emotion/styled framer-motion

2-2. Chakra UIのセットアップ

index.tsxを以下のように変更ください

  • index.tsx

※変更箇所は「黄色」でハイライトしております。

Before

import React from 'react';
import ReactDOM from 'react-dom/client';
import { App }  from './App';


const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>

      <App />

  </React.StrictMode>
);

After

import React from 'react';
import ReactDOM from 'react-dom/client';
import { App }  from './App';
import { ChakraProvider } from '@chakra-ui/react' 

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
  <React.StrictMode>
    <ChakraProvider> 
      <App />
    </ChakraProvider>
  </React.StrictMode>
);

2-3. componentの作成

srcディレクトリ配下に、下記の通りディレクトリ(components)と、その配下にファイル(ChatForm.tsx)を作成してください。

src/components/ChatForm.tsx

※ファイル名はChatForm.tsxとします(変更しても問題ありません)

さらに、App.tsxファイルに<ChatForm />コンポーネントを使えるようにします。

  • App.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before



export const App = () => {
  return (
    <div>
        test
    </div>
  );
}

After

import { ChatForm } from "./components/ChatForm";

export const App = () => {
  return (
    <div>
        <ChatForm />
    </div>
  );
}

2-4. ChatForm.tsxにHTML/CSSの記述を行う

  • ChatForm.tsx

下記をそのまま記述ください。

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"

export const ChatForm = () => {
  return (
    <>
    <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
      <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
        <Textarea 
          placeholder='質問をご記載ください' 
          value=""
          mt={4}
        />
      </Box>
      <Button mt="20px" float="right">
        Submit
      </Button>
    </FormControl>
    <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
      <p>Bedrockからの返答:</p>
    </Box>
    </>
  );
}

下記のようにフォームが出れば完了

3. axiosでAPIを呼び出す

3-1. axiosをインストール

npm install axios

3-2. ChatForm.tsxでAPIを呼び出す

こちらのAPIについては、下記記事で作成したものになります。こちらでAPIを作成の上、お取り組みください。

Amazon Bedrock KnowledgeBase のAPIをLambda と API Gatewayで利用してみた

  • ChatForm.tsx
    ※変更箇所は「黄色」でハイライトしております。
    ※下記コードの<API GatewayのURL><API KEY>は変更して記述ください。
    また、<API GatewayのURL><API KEY>は外部公開してはならない値になります。取り扱いにはご注意ください。

Before

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"


























  return (
    <>
    <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
      <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
        <Textarea 
          placeholder='質問をご記載ください' 
          value=""
          mt={4}
        />
      </Box>
      <Button mt="20px" float="right">
        Submit
      </Button>
    </FormControl>
    <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
      <p>Bedrockからの返答:</p>
    </Box>
    </>
  );
}

After

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"

export const ChatForm = () => {
  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": "株式会社ベンジャミンって?"
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }

  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value=""
            mt={4}
          />
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答:</p>
      </Box>
    </>
  );
}

3-3. Submitボタンをクリックし、呼び出されるか確認

検証モードでデータが取得されているか確認する
※ちなみに検証モードは「⌘ + ⌥ + i」、もしくは右クリックで「検証」を選択することで表示できます

4. useStateでbedrockからの回答値をstate管理する

4-1. Formの値をstate管理する

  • ChatForm.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"


export const ChatForm = () => {


  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": "株式会社ベンジャミンって?"
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }

  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value=""
            mt={4}

          />

        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答:</p>
      </Box>
    </>
  );
}

After

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"
import { useState } from "react"

export const ChatForm = () => {
  const [inputText, setInputText] = useState("")

  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": "株式会社ベンジャミンって?"
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }
  console.log(inputText)
  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value={inputText}
            mt={4}
            onChange={(e) => setInputText(e.target.value)}
          />
        
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答:</p>
      </Box>
    </>
  );
}

検証画面で下記にように表示されればOK
※Submitボタンの押下は不要です

4-2. Formの値をBedrockにPOSTする

  • ChatForm.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"
import { useState } from "react"

export const ChatForm = () => {
  const [inputText, setInputText] = useState("")

  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText":"株式会社ベンジャミンって?"
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }
   console.log(inputText) //不要なので消しておきます
  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value={inputText}
            mt={4}
            onChange={(e) => setInputText(e.target.value)}
          />
        
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答:</p>
      </Box>
    </>
  );
}

After

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"
import { useState } from "react"

export const ChatForm = () => {
  const [inputText, setInputText] = useState("")

  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": inputText
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }

  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value={inputText}
            mt={4}
            onChange={(e) => setInputText(e.target.value)}
          />
        
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答:</p>
      </Box>
    </>
  );
}

検証モードで返答があればOK!

4-3. Bedrockから返ってきた値を表示させる

  • ChatForm.tsx
    ※変更箇所は「黄色」でハイライトしております。

Before

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"
import { useState } from "react"

export const ChatForm = () => {
  const [inputText, setInputText] = useState("")


  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": inputText
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      console.log(res) //不要なので消しておきます
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }

  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value={inputText}
            mt={4}
            onChange={(e) => setInputText(e.target.value)}
          />
        
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答: </p>
      </Box>
    </>
  );
}

After

import { Box, FormControl, Textarea, Button } from "@chakra-ui/react"
import axios from "axios"
import { useState } from "react"

export const ChatForm = () => {
  const [inputText, setInputText] = useState("")
  const [bedrockValue, setBedrockValue] = useState("")

  const bedrockApi = async () => {
    await axios
    .post(
      "<API GatewayのURL>", 
      {
      "inputText": inputText
      },
      {
        headers: {
          "Content-Type": "application/json",
          "X-API-KEY": "<API KEY>",
        },
      }
    )
    .then((res) => {
      setBedrockValue(res.data.body)
    })
    .catch((error) => {
      console.error("Error fetching data:", error);
      alert("エラーが発生しました");
    })
  }

  return (
    <>
      <FormControl w={{ base: "80%", md: "60%" }} margin="0 auto" mt="32px">
        <Box as="div" display="flex" justifyContent="center" alignItems="center" flexDirection="column">
          <Textarea 
            placeholder='質問をご記載ください' 
            value={inputText}
            mt={4}
            onChange={(e) => setInputText(e.target.value)}
          />
        
        </Box>
        <Button mt="20px" float="right" onClick={bedrockApi}>
          Submit
        </Button>
      </FormControl>
      <Box as="div" width={{base: "80%", md: "60%"}} mx="auto" mt="100px" display="flex" flexDirection="column">
        <p>Bedrockからの返答: {bedrockValue}</p>
      </Box>
    </>
  );
}

あとはフォームに入力し、Submitボタンをクリックして数秒待ち、下記の通りブラウザ上に表示されれば完了となります!

まとめ

いかがでしょうか? 今回は、ブラウザ上でBedrock knowledgeBaseを呼び出し、取得した値を使う方法を紹介させていただきました。

ここまでできれば、Bedrockでアプリ開発ができるのではないでしょうか?

ちなみに今回紹介しなかった、デプロイ方法ですが、Amplifyにて簡単にデプロイできます。下記記事が大変わかりやすいので、ご参照下さい。

https://qiita.com/itoshin1341/items/20a4fcd2630618870b38

※AWSにデプロイする際はAPI KEY、API GatewayのURLを直接埋め込まずに、SecretsManagerなどをご利用ください。

AWS Amplifyを利用して、Reactで作成したアプリケーションをデプロイしてみた

また、Bedrockで他の機能も使っていこうと思いますので、引き続きよろしくお願いいたします!

Related posts