😺

テキストからタスクを可視化するツールを作ったった

2024/01/29に公開

こんにちは!ぬこすけです!

昨今では ChatGPT を代表するような大規模言語モデル(LLM)が有名になりました。
皆さんの中にもこの話題の LLM を使ったアプリケーションを作ってる人たちも多いのではないのでしょうか?
私もその中の一人です!

https://dandori-web.com/

私も ChatGPT を使ってアプリケーションを作ってみました。
名前はズバリ Dandori です。

Dandoriのロゴ

この記事では技術構成をメインにお話しますが、 技術選定時に皆さん(特に個人開発者)の参考になればなー という気持ちで書いています。

Dandori とは

技術構成のお話に入る前にどういうサイトかちょっとだけ。

Dandori はその名の通り「段取り」が由来です。
ユーザーが入力したテキストからタスクの依存関係を洗い出し、オンラインホワイトボードツールの Miro などのサードパーティのアプリを使って可視化 します。

一例をあげましょう。
次のようなメモがあったとします。

やることリスト
* 企画書を書く
* 企画書を上司にレビューをもらう
* 顧客A社に企画書を送る
* 顧客B社にも企画書を送る
* 企画書に基づいて発注する

Dandoriのフォーム例

このメモを Miro に連携するとこうなります。

Dandoriを使ってMiroに連携した例

なんとなくタスクの依存関係はあってそうです。

このタスクの依存関係をもとにサードパーティのアプリに連携するロジックは OSS でも公開 しています。

https://github.com/hiroki0525/dandori

Dandori を支える技術構成

あくまで個人開発なので できるだけ安く、できるだけ楽に 開発したいところです。
楽はしたいと言いつつも技術者でもあるので 技術にもこだわりところ です。

そんな考えのもと、 Dandori の技術構成はあげていくとこんな感じです。

  • アプリケーション
    • Next.js (App Router)
    • Valibot
    • TailwindCSS
    • daysiUI
    • Cloud Run
  • データベース
    • Redis
  • デザイン
    • v0.dev
    • GPTs
  • 認証
    • Auth0
  • カスタムドメイン
    • Cloudflare Registrar
  • LLM
    • OpenAI

アプリケーション

アプリケーションは Next.js の App Router で動かしてます。
どうせ新しくアプリケーション作るなら、モダンに作ってみよう、というスタンスです。

フォームの実装

Dandori ではユーザーのテキストや設定をサーバーに送るようなフォームがあります。

Dandoriのフォーム

Server Actions

Next.js ではコンポーネント内でサーバー側のフォーム送信処理を実行できる Server Actionsが使えます。
が、 このフォームでの Server Actions の実装はやめました

理由として大きいのは クライアント側でもバリデーションを実行してサーバーとの通信を減らしたいから です。

Server Actions は React のハイドレーションを待たずに実行できるのでユーザービリティ観点でメリットがあります。
またフォーム用の API を生やさずにシュッと作成できたりで便利です。
が、どうしてもバリデーションするときはサーバーサイドになってしまうので、フォームを送信した時に都度通信が走ってしまいます。
Cloud Run を使っていますが、 個人開発としてはできるだけサーバーとの通信を減らしてサーバー代を節約したい ところです。

また、 Auth0 との兼ね合い という観点もありました。
Auth0 については後述しますが、認証機能を手軽に実装できるサービスです。
Auth0 では Next.js 用の SDK が容易されており、例えば「認証したユーザーのみ API アクセスを許可したい」となると次のコードでシュッと実装できます。

import { withApiAuthRequired } from "@auth0/nextjs-auth0";

export GET = withApiAuthRequired(async (req) => {
  // API の処理
})

だいたいの API がこの関数でラップしていますが、 Server Actions を使うとフォームだけ他の API と違う、一貫性のない実装になります。
また、 Auth0 の SDK を使って Server Actions を良い感じにする API もなさそうでした。

このような理由で 入力フォームでの Server Actions での実装は見送りました
(誤解がないように言っておくと、メインのフォーム以外で Server Actions を使ってるところはあります)

Valibot

フォームのバリデーションには Valibot を採用しました。

https://github.com/fabian-hiller/valibot

Valibot でスキーマを定義して、クライアントとサーバーサイドの両方でバリデーションをしています。

他の選択肢として代表的なのは Zod がありますが、 Valibot の方が バンドルサイズが削減 できます。

For example, this allows a bundler to use the import statements to remove code that is not needed. This way, only the code that is actually used gets into your production build. This can reduce the bundle size by up to 98 % compared to Zod.
https://github.com/fabian-hiller/valibot?tab=readme-ov-file#comparison

このようなメリットはあるものの、一方で ドキュメントが少ない デメリットもあります。

記事の執筆時点で Valibot の公式ドキュメントで API リファレンスを調べると、だいたいこんな感じです。

ValibotのAPIリファレンス

Zod と比べると新しいライブラリということもあり、「こういうことがしたい!」と思ってググっても情報が出てこない時があります。
ChatGPT に聞いてもまだ Valibot の情報は持っていないようでした。

Valibot はドキュメントが少ないという欠点はあるものの、バンドルサイズ削減のメリットも大きい のかなーと思います。

スタイリング

スタイリングには TailwindCSS を使っています。
私自身が TailwindCSS に慣れちゃっているというのもありますが、採用した理由を挙げるとするのならば次のような感じでしょうか。

  1. 生の CSS を書くよりも少ない記述で書けるので 実装が早い
  2. emotion などランタイムで JavaScript として評価される CSS in JS よりかは パフォーマンスが良い
  3. v0.dev で出力されるデザインのコード例が TailwindCSS なのでそのまま使える

3 の v0.dev については後述 しますが、プロンプトを投げるとデザイン案を出力してくれるサービスです。
今回デザインを考えるにあたってこのv0.dev も使いました。

出力してくれるデザイン案は次のように TailwindCSS でもコード例で表示してくれます。

v0.devのコード例

まあ v0.dev に限らずですが、最近はコード例をあげる際には TailwindCSS の例も多くなってきているなーという印象です。

デザインシステム

Dadndori は一から全て自前でスタイリングしているわけではありません。
開発スピードを上げるために、すでに整ったデザインシステムに乗っかっています。

Dandori では daisyUI を採用しました。

https://daisyui.com/

daisyUI は TailwindCSS ベースのデザインシステムです。
例えばボタンを作る時は次のコードでイケます。

<button className="btn">Button</button>

daisyUIのボタン

採用理由としては TailwindCSS ベースというのもありますが、 消去法的に採用した ところが大きいです。

Dandori では Next.js の App Router を使っていますが、 React Server Component(RSC) での実装が前提になります。

Material UIChakra UI のような React におけるデザインシステムが実装された 代表的なライブラリが RSC に対応していない のが選定時に直面しました。
(対応していない、と言い切ると若干語弊があるのですがこの後説明します。)

「 RSC に対応しました!!」と謳ったライブラリはたくさんあるのですが、私が調べて限りでは「ライブラリ側で全てのコンポーネントに use client ディレクティブをつけるよ!」という感じでした。
(あくまで選定当初なので現在はどうなってるかはわかりません)

つまり全てのコンポーネントはクライアントコンポーネントということになりますが、これでは App Router を使う旨みが少なくなってしまいます...

このような事情があり、 実質的に RSC に対応できる TailwindCSS ベースの daysiUI を採用 しました。

daysiUI は TailwindCSS ベースということもあり class 名をつけるだけでデザインを組めるので便利 です。
一方で dialog タグや css の has など新しめなブラウザ API を使っているので古いブラウザに対応する場合は注意です。

サーバーインフラ

Next.js アプリケーションは Cloud Run を使っています。
Cloud Run を使ってるのも 消去法的な理由 です。

Next.js アプリケーションのデプロイ先として候補に上がるのは Vercel ですが、商用利用は禁止されていているのがネックです。
いずれ「広告貼りたいなー」と思ってもできません。

Netlify も無料プランがあって魅力的なのですが、昔作ったアプリケーションをすでにデプロイしていて、できれば他のホスティングサービスを使いたいなーと。

https://chaisear.com/

firebase も代表的なデプロイ先としてあります。
認証やデータベースなどその他の機能も合わせて firebase で使うなら有効かもしれませんが、そこらへんは firebase 以外のサービスを使うので、特に firebase を使うメリットも薄かったのでやめました。

その他、無料枠のある flyio も候補としてありますが、ちょっと 無料枠で使えるインスタンスのスペックが心許ないかもなーと思い、採用を見送りました。

という具合でなかなかこれは、と思うホスティング先というものが見つかりませんでした。

Cloud Run は過去に作ったサイトでデプロイ実績があるので、そのまま Cloud Run を使うことにしました。

https://nuko-programming.com/

データベース

Dandori では PostgreSQL のようなリレーショナルデータベースを使わず、 KVS(Key-Value Store) のデータベースとして Redis を使っています。

Dandori ではユーザーが入力したテキストから抽出したタスクの依存関係を、 Miro や Notion などのサードパーティアプリケーションに連携します。
OAuth 経由でサードパーティアプリケーションから発行されたアクセストークンを Redis で有効期限付き & 暗号化して保存しています。

Upstash を使えば Redis を無料で運用できる ので、個人開発にはおすすめです。

https://upstash.com/

デザイン

トップ画面

Dandoriのトップ画面
https://dandori-web.com/

Dandori のトップ画面のデザインは Vercel 社が公開している v0.dev を使いました。
v0.dev はプロンプトを投げるだけでサイトのデザイン案を出力 してくれます。

https://v0.dev/t/rNuTroeDt6J

これは「 Sass LP 」というプロンプトを投げた結果のサイトのデザイン案です。
なかなか良い感じですね。

スタイリングのところでもお話しましたが、コードも出力してくれて便利です。

この v0.dev で出力してくれたコードをコピペして、自分のサイトにアレンジしていくことで Dandori のトップページを作成 しました。

サイトロゴ

Dandoriのロゴ

サイトのロゴは GPTs の DALL·E を使って作りました。
プロンプトを投げるだけで画像を作ってくれます。

段取りの「段」という漢字を書道風に出力して、みたいなプロンプト投げた結果をそのままサイトのロゴとして使っています。

認証

Dandori のログイン機能は Auth0 の無料プランを使っています。
無料プランでも 7500 人のアクティブユーザーや 2 つの SNS 認証によるログイン機能も使えるので個人開発では十分 です。
加えて パスキーによるログインも使えました

無料プランもさることながら、 アプリに実装しやすい ということもありました。
具体的には次の通りです。

  • アプリケーションに実装するにあたってのドキュメントが充実している
  • Next.js の App Router にも対応している
  • Next.js の SDK が用意されており、サクッと実装できる

実は firebase を使った認証機能も実装しようとしたのですが、 Auth0 と比べるとだいぶ実装が複雑かなーという印象を受けたり、 Next.js の App Router を使った実装のドキュメントもわかりづらい、と個人的には思った次第です。

デメリットをあげるとするのなら、無料枠を超えた時の価格が高いかなーという印象はありますが、個人開発レベルであればそこまで気にする必要もないかなとも思います。

https://auth0.com/pricing

カスタムドメイン

カスタムドメインは Cloudflare Registrar で買いました。

https://www.cloudflare.com/ja-jp/products/registrar/

為替による影響はあるものの、 卸売価格で提供されているので安い かなと。

昔からお名前.comでカスタムドメインは買っていたのですが、まあ広告メールが鬱陶しかったり管理画面が見づらいと思っていたので、いつかは乗り換えたいなーと思っていました。

Cloudflare Registrar は安いですし、将来的にも Cloudflare の機能を使うかもなーと思ったので Cloudflare Registrar に乗り換えました。

LLM

Dandori のテキストからタスクの依存関係を抽出する機能は OpenAI の API を使っています。
どういう感じで API を使っているかは OSS として公開しているので興味があればぜひ!

https://github.com/hiroki0525/dandori

OpenAI の APIは無料では使えなかったので、一旦 5 ドルの課金をしています。

また、 GPT-4 の方がより正確な結果が出るのですが、費用を抑えるために Dandori では GPT-3.5 を使うようにしています。

さいごに

https://dandori-web.com/

Dandori の技術構成についてお話しました。
もしこれから技術選定する方、特に個人開発をする方の参考になればと思います!

さいごに、個人的に Zenn の作者の catnose さんの「しずかなインターネットの技術構成」という記事も参考になるなー、と思ったのでぜひ!

https://zenn.dev/catnose99/articles/f8a90a1616dfb3

Discussion