HTMXとGemini APIを用いて簡単なチャットアプリを作ってみた

# はじめに

57歳で製造業からWeb開発企業に転職して、やっと2年目に突入したピータンと申します。

最近、個人的に[HTMX](https://htmx.org/)が気になっています。そこで、これとGoogleの生成AIである[Gemini](https://gemini.google.com/app)の[API](https://ai.google.dev/tutorials?hl=ja)を使って、簡単なチャットアプリを作ってみたので紹介します。

  ![image](https://github.com/pitang1965/geminikun/assets/47315420/847499c9-3c7e-4f6e-9280-7d9b842f2910)

# HTMXとは？
* [JavaScript ライジングスター 2023](https://risingstars.js.org/2023/ja)のフロントエンドフレームワーク部門で、王者のReactに次ぐ2位となった注目の技術です
* HTMXは、Reactのように非同期通信による動的なサイト更新などを実現する軽量のソリューションです
* `hx-なんちゃら`というカスタム属性を使用することでHTMLを拡張し、JavaScriptコードを書かずにAPIを使い、ページの一部更新ができます
* HTMXは、Reactに比べて学習が圧倒的に簡単で、その日から使えました
* Web制作でのコンタクトフォームの実装に便利です
* シンプルなインタラクティブ機能を備え、特に高度な機能を備えないサイトを構築する場合は、HTMXの方がReactより優れたソリューションとなる可能性があります
  * 状態管理が必要で、複雑な機能を提供し、再利用可能なコンポーネントが必要なWebアプリケーションを作成する場合は、Reactがより適切とは思います

# Geminiとは？

* 2023年12月に発表されたGoogleの生成AIモデルです
* 以前はBardと呼ばれていました

# 実装方法
詳細は、[GitHub](https://github.com/pitang1965/geminikun)をご覧ください。

## フロントエンド
HTML, CSS, 少量のJavaScriptとHTMXを使用しました。少量のJavaScriptは、以下のために使っています。これが不要なら、フロントエンドは完全にJavaScriptなしとなるのですが。

* [送信]ボタンをクリックしたあとのテキストエリアのクリア
* [送信]ボタンをクリックしたあとのページ下部への自動スクロール
* テキストエリアでEnterキーを入力したら自動で高さを増やす

`index.html`は次になります。

```html:index.html
<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ジェミニ君</title>
    <link rel="stylesheet" href="/style.css" />
    <link rel="icon" href="/favicon.ico" type="image/x-icon" />
    <script src="https://unpkg.com/htmx.org@1.9.10"></script>
    <script src="textarea.js"></script>
    <body>
      <div class="container">
        <h1>HTMXとGeminiを用いたシンプルチャット</h1>
        <div id="chat-messages"></div>
        <form
          hx-post="/api/generate"
          hx-target="#chat-messages"
          hx-swap="beforeend "
        >
          <textarea
            id="message-input"
            placeholder="WEFについて教えてください。"
            type="text"
            name="message"
            required
            rows="1"
          ></textarea>
          <button name="submit" type="submit" id="submit-button">送信</button>
          <div class="htmx-indicator loader"></div>
        </form>
        <p class="copyright">
          Powered by
          <a
            href="https://over40web.club"
            target="_blank"
            title="Over 40 Web Club"
            >Over 40 Web Club</a
          >
        </p>
      </div>
    </body>
    <script src="chat-ui-updates.js"></script>
  </head>
</html>
```

* `<form>`タグのカスタム属性（`hx-***`）でAPIと通信してチャットを表示する機能を実現しています
* `<div class="htmx-indicator loader"></div>`のように`htmx-indicator`というクラスを追加するだけで生成AIが考え中のときのローディングアニメーションを実現しています
* `<script>`タグで２つのJavaScriptファイルを読み込んでいます。そちらは[GitHub](https://github.com/pitang1965/geminikun)をご覧ください

## バックエンド

* Node.jsのフレームワークの [express.js](https://expressjs.com/ja/)を使用しています。[Googleのチュートリアル](https://ai.google.dev/tutorials?hl=ja)には、Node.jsの他、PythonやGo, Swiftなどからの利用方法が解説されています
* バックエンドからGeminiのAPIを呼び出しています
  * 「◯◯だよー。」と言わせるようにしています
  *  マルチターンの会話（チャットなど）を構築するために、gemini-pro モデルを使用し、startChat() を呼び出してチャットを初期化しています
  *  次に、sendMessage() を使用して新しいユーザー メッセージを送信するようにしています
* 詳細は、[GitHub](https://github.com/pitang1965/geminikun)をご覧ください

# デプロイ
* こちらはVercelにスタンドアロンのExpress.jsアプリとしてデプロイしました
* これを実現するために、APIのコードは`api`フォルダ以下に配置し、ルートに`vercel.json`を配置します

```json:vercel.json
{
  "rewrites": [
    {
      "source": "/api/(.*)",
      "destination": "/api"
    }
  ]
}
```

# おわりに

これを作る前に、コンタクトフォームも作ってみました。HTMXを使うと、APIとやり取りをして、ページを更新するといったことが、JavaScriptを書かずに非常に簡潔におこなえます。今回の例では多少JavaScriptが必要になりました。APIはHTMLを返却する必要があることから、基本自作にはなってしまいます。

Geminiも最初、model.generateContentというメソッドを使ったときには、次のような応答となりましたが、今回の実装方法では可愛げのある結果が得られました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/345563/96c5739d-1577-0df0-295b-8b5a995a1d9e.png)

今回、自動スクロールの実装がうまくいかず、タイマーを使う苦し紛れの実装となりました。フィードバッグなどありましたら、お気軽にお願いいたします。

# 関連記事

* [HTMXを活用して簡単に実装するHTMLお問い合わせフォーム](https://qiita.com/pitang1965/items/4a5fc049f0b083c0d134)