💭

【GPT3.5turbo】NextJsで動くGPT3.5turbo【#7Scroll Into View】

2023/04/24に公開

【#7Scroll Into View】

YouTube:https://youtu.be/uFI5J7xOiCw

https://youtu.be/uFI5J7xOiCw

今回は「scrollIntoView」を使用して最新のやり取りを表示できるように
実装を進めていきます。

毎回チャット欄の一番下をターゲットにするために「useRef」を使用して、
空の「div」要素に設定します。
そして、「setLogs」のメソッドで「logs」の内容に変化があったときに
「useEffect」を使用して発火させるようにします。

今回はチャット欄にスクロールを出すために、
「logs」の初期値にダミーデータを設定しています。
ダミーデータはテスト後に削除してしまって大丈夫です!

pages/index.tsx
import { ChangeEvent, SyntheticEvent, useEffect, useRef, useState } from 'react'

interface Log {
  prompt: string
  role: string
  content: string
}

const dummyLogs: Log[] = [
  {
    prompt: 'hello',
    role: 'assitant',
    content: 'hello',
  },
  {
    prompt: 'hello test',
    role: 'assitant',
    content: 'thank you test',
  },
  {
    prompt: 'Are you ai?',
    role: 'assitant',
    content: 'Yes i am ai',
  },
]

export default function Home() {
  const [prompt, setPropmt] = useState('')
  const [isLoading, setIsLoading] = useState(false)
  const [logs, setLogs] = useState<Log[]>(dummyLogs)

  const logScrollRef = useRef<HTMLDivElement>(null)

  const handleChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
    setPropmt(e.target.value)
  }

  const handleSubmit = async (e: SyntheticEvent) => {
    e.preventDefault()
    setIsLoading(true)

    const res = await fetch('/api/chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ prompt: prompt }),
    })
    const data = await res.json()
    if (res.status === 200) {
      console.log(data)
      const logData = {
        prompt: prompt,
        ...data.message,
      }
      setLogs([...logs, logData])
      setPropmt('')
      setIsLoading(false)
    } else {
      console.log(data)
      setIsLoading(false)
    }
  }

  useEffect(() => {
    logScrollRef?.current?.scrollIntoView({ behavior: 'smooth', block: 'end' })
  }, [logs])

  return (
    <main className="flex min-h-screen flex-col items-center px-2">
      <h1 className="my-6 text-3xl font-bold tracking-tight text-white sm:text-4xl">
        Hello Chat-GPT
      </h1>
      <div className="max-w-xl overflow-hidden bg-gray-900 py-4 sm:py-6 lg:py-8">
        <div className="mx-auto max-w-3xl px-6 lg:px-8">
          <div>
            <div className="max-w-xl lg:max-w-lg mb-3">
              <h2 className="text-3xl mb-3 font-bold tracking-tight text-white sm:text-4xl">
                Please Enter Your Message.
              </h2>
            </div>
          </div>
          <div>
            <form
              onSubmit={handleSubmit}
              className="flex flex-col items-center justify-center"
            >
              <textarea
                name="prompt"
                value={prompt}
                onChange={handleChange}
                cols={20}
                rows={4}
                className="w-full flex-auto rounded-md border-0 bg-white/5 px-3.5 py-2 text-white shadow-sm ring-1 ring-inset ring-white/10 focus:ring-2 focus:ring-inset focus:ring-indigo-500 sm:text-sm sm:leading-6"
              ></textarea>
              <button
                disabled={isLoading || !prompt}
                type="submit"
                className="flex-none rounded-md bg-indigo-500 mt-3 px-3.5 py-2.5 text-sm font-semibold text-white shadow-sm hover:bg-indigo-400 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-indigo-500"
              >
                Send Message
              </button>
            </form>
          </div>
          <div className="max-w-xl mt-3 p-5 bg-white/5 min-h-[300px] max-h-[300px] text-white overflow-y-scroll break-words">
            <div className="w-full">
              <div className=" flex flex-row-reverse my-6">
                <h3 className=" flex flex-col justify-center items-center">
                  <div className=" w-12 h-12 flex justify-center items-center rounded-full bg-white text-pink-700 font-bold text-[28px]">
                    <p>AI</p>
                  </div>
                  Assistant
                </h3>
                <p className=" mr-3 px-3 py-2 bg-[#000c22] rounded-md">
                  何か御用があれば、入力欄にメッセージをお願いします。
                </p>
              </div>
            </div>
            {logs?.map((log, idx) => (
              <div className="w-full" key={idx}>
                <div className="flex">
                  <h3 className="flex flex-col justify-center items-center">
                    <div className="w-12 h-12 flex justify-center items-center rounded-full bg-white text-blue-700 font-bold text-[28px]">
                      <p>U</p>
                    </div>
                    User
                  </h3>
                  <p className="ml-3 px-3 py-2 bg-[#000c22] rounded-md">
                    {log.prompt}
                  </p>
                </div>
                <div className="flex flex-row-reverse my-6">
                  <h3 className="flex flex-col justify-center items-center">
                    <div className="w-12 h-12 flex justify-center items-center rounded-full bg-white text-pink-700 font-bold text-[28px]">
                      <p>AI</p>
                    </div>
                    Assistant
                  </h3>
                  <p className="mr-3 px-3 py-2 bg-[#000c22] rounded-md">
                    {log.content}
                  </p>
                </div>
              </div>
            ))}
            <div ref={logScrollRef} />
          </div>
        </div>
      </div>
    </main>
  )
}

Discussion