🐱

ChatGPTプロンプト共有サービス 個人開発

2023/03/01に公開

こんにちはtapecojapanという会社でエンジニアをしているstdと申します。

個人開発でChatGPTのプロンプト、返答を共有できるサービスを作りましたのでそのアーキテクチャを書いていきたいと思います。

開発の参考になりましたら幸いです。

作ったサービス

AI Sensei

https://ai-sensei.net
https://ai-sensei.net/threads

サービスの特徴

  • スレッド形式でChatGPTの内容をコピペして投稿できる。
  • スレッドをTwitterにシェアできる。
  • スレッドをお気に入りに保存できる。
  • 無料

解決したいこと

ChatGPTが話題ですが使い方が上手い人と便利な使い方がいまいちわからない人との差が生まれてるように感じます。
そこでプロンプトのtipを簡単に保存、共有できるサービスがあれば差が縮まりみんながChatGPTを使えるのではないかと思い作ってみました。

開発体制

std 1人
(メンバー募集中)

開発期間

2週間くらい

使用技術

  • Next.js
  • Vercel
  • Supabase
  • Tailwind CSS
  • Mantine
  • jotai
  • vercel/og

Supabase

https://supabase.com/
ログインとデータベースに使用しています。
ドキュメントも充実していて実装に迷うことが少ないです。
今回supabase/auth-helpers-react、supabase/auth-helpers-nextjsを採用してみました。
.envにNEXT_PUBLIC_SUPABASE_URLとNEXT_PUBLIC_SUPABASE_ANON_KEYを入れるだけで導入でき快適でした。

Supabase CLIで

supabase gen types typescript --linked > ./src/types/schema.ts

することでデータベースの型を保存できますのでTypescriptでも安心です。

Mantine

https://mantine.dev/
職場ではTailwind CSSを使用することが多いですが、コンポーネントを作るのにClassをたくさん書かなくてはならなく実装に時間がかかりますので、今回は実装時間を短縮するために採用しました。
Mantineで実装しにくい箇所はTailwind CSSを採用しています。

どちらも採用するとMantineのButton等が透明になってしまう不具合が発生しました。
回避策としてこのようにprependをfalseにして実装しています。

//_app.tsx抜粋
import type { AppProps } from "next/app";
import { MantineProvider, createEmotionCache } from "@mantine/core";

const appendCache = createEmotionCache({ key: "mantine", prepend: false });

export default function App({ Component, pageProps }: AppProps) {
  return (
    <MantineProvider
      withGlobalStyles
      withNormalizeCSS
      emotionCache={appendCache}
      theme={{
        colorScheme: "light",
      }}
    >
      <Component {...pageProps} />
    </MantineProvider>
  );
}

vercel/og

HTML&CSS で画像を生成できるライブラリです。
https://vercel.com/docs/concepts/functions/edge-functions/og-image-generation
こちらを使用してOGPイメージを動的に生成するようにしました。
使い方はまず、apiディレクトリにOGP生成用のファイルを作ります。

//pages/api/og.tsx 抜粋
import { ImageResponse } from "@vercel/og";
import { NextRequest } from "next/server";
import { siteName } from "@/lib/constants";

export const config = {
  runtime: "edge",
};

export default function handler(req: NextRequest) {
  try {
    const { searchParams } = new URL(req.url);
    const hasTitle = searchParams.has("title");
    const title = hasTitle
      ? searchParams.get("title")?.slice(0, 100)
      : "AI Sensei";

    const url = process.env.NEXT_PUBLIC_VERCEL_URL
      ? "https://" + process.env.NEXT_PUBLIC_VERCEL_URL
      : "http://localhost:3000";
    return new ImageResponse(
      (
        <div
          style={{
            fontSize: 128,
            background: 'white',
            width: '100%',
            height: '100%',
            display: 'flex',
            textAlign: 'center',
            alignItems: 'center',
            justifyContent: 'center',
          }}
        >
          { title }
        </div>
      ),
      {
        width: 1200,
        height: 600,
      },
    );
  } catch (e: any) {
    console.log(`${e.message}`);
    return new Response(`Failed to generate the image`, {
      status: 500,
    });
  }
}

OGPイメージのPathをこのように取得してHeadに設置します。

const ogImage = useMemo(() => {
   return `${url}/api/og?title=${"OGPのタイトル"}`;
}, []);

これだけで動的にOGPイメージが作れます。
OGPがあるとTwitterにシェアする時に目立っていいですね!(凝ったデザインではないですが。)

OGPサンプル

https://ai-sensei.net/ja/threads/0edbcf03-9a4d-43de-8cc9-d5925f869ecf

今後

  • 投稿のcodeコピーをよりよく改善したい。
  • 時間あるときに機能追加していければと思っています。

こうすればよかった

  • デザインは実装しながら考えましたが行ったり来たりが多かったので、次回からはちゃんとFigma等でデザインしてから進めようと思います。

一緒に開発してくれる方募集!

もし参加したい方いらっしゃいましたららDiscordにコミュニティを作ろうと思います。
このサービスの機能追加や新規サービスのアイデア出しからしていきましょう。

宣伝

AI Senseiぜひ使ってみてください!!
不具合、こうした方が良い等の意見ありましたら、改善していきますのでお声がけいただけますと助かります。

Discussion