【個人開発】生成AIを使って名言を提供するサービスを開発しました【Rails】

## はじめに
こんにちは！[ずっと大地🦦](https://x.com/zuttodaichi)と申します！！
2023年11月より、オンラインスクールのRUNTEQにて、未経験からのWebエンジニア転職を目指して学習をしています。
前職はスポーツ選手として活動しておりました。

今回、生成AIを使った名言提供サービス『MeigenOtter（名言おったー）』を開発したので、記事にしたいと思います。
間違いや不備などありましたら、教えて頂けると幸いです。

## サービス名
[MeigenOtter](https://meigenotter.com/)
ユーザー登録をしなくても、ランダムでの名言取得は可能です。気軽に覗いて頂けると幸いです。

**▼サービスURL**
https://meigenotter.com/

**▼GitHub URL**
https://github.com/daichi3102/wordpass

![MOtop.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3773756/8e32908b-0332-e03e-824a-3bf48dc78708.png)

## サービス概要
生成AIを使った名言提供サービスです。
その日の気分や予定に基づいて、偉人、有名人、書籍、映画、漫画、アニメの中から、名言を提供します。
言葉を通じて、心のエネルギーをサポートします。

## 開発背景
スポーツ選手として活動する中で、モチベーションの管理は非常に重要で、モチベーションによってトレーニングの質が変わることもありました。モチベーション維持のための工夫として、名言や格言を検索し、気持ちを高めていた経験があります。この経験を通して、「言葉」は心に与えるエネルギーは大きいと実感し、その時々に合った「言葉」を「名言」として届けることで、少しでも、誰かにエネルギーを与えられるサービスがあればと思い、生成AIを用いた名言提供サービス「MiegenOtter（名言おったー）」を開発しました。

## 主な機能一覧
|生成AIによる名言取得機能|生成AIによる名言検索機能|
|:-------------|:-------------|
|[![AIによる名言取得機能](https://i.gyazo.com/2c7b29d57e06a0f4071503a8dddd2d5a.gif)](https://gyazo.com/2c7b29d57e06a0f4071503a8dddd2d5a)|[![AIによる名言検索機能](https://i.gyazo.com/1215c95b1d6d30f5fc031a9b3d033934.gif)](https://gyazo.com/https://gyazo.com/1215c95b1d6d30f5fc031a9b3d033934)|
|当アプリのメイン機能になります。全5項目から条件を選択し、条件に合った名言を生成AIが提供します。|他のユーザーを含め、生成AIによって提供されたすべての名言から、条件を選択して検索できます。|

|名言作成機能|協力しての名言作成|
|:-------------|:-------------|
|[![名言作成機能](https://i.gyazo.com/55be691636d7bdf32f053ef2900d6225.gif)](https://gyazo.com/55be691636d7bdf32f053ef2900d6225)|[![協力しての名言作成](https://i.gyazo.com/3ea25ea55ce5e0c3ac95fee78ba42731.gif)](https://gyazo.com/3ea25ea55ce5e0c3ac95fee78ba42731)|
|自分の好きな名言や言葉、座右の銘を投稿（共有）できます。|上の句や下の句のみの名言に対して、残りの句を追加する事で、他ユーザーと協力して名言を作成することができます。|

|作成された名言検索機能|いいね機能|
|:-------------|:-------------|
|[![作成した名言検索機能](https://i.gyazo.com/81338796ca01d2b58bebbcb1ee49ac0e.gif)](https://gyazo.com/81338796ca01d2b58bebbcb1ee49ac0e)|[![いいね機能](https://i.gyazo.com/3e65bce52c3fadfe79c7719303ea2de8.gif)](https://gyazo.com/3e65bce52c3fadfe79c7719303ea2de8)|
|作成された名言に対して、名言の本文か名前からフリーワードで検索ができます。|作成された名言に対して、いいねができます。いいねした名言は、マイページから一覧になっています。|

|アプリ内通知機能|Xシェア機能|
|:-------------|:-------------|
|[![アプリ内通知機能](https://i.gyazo.com/3f77a441985daf50ce1e214b6e7098cd.gif)](https://gyazo.com/3f77a441985daf50ce1e214b6e7098cd)|[![Xシェア機能](https://i.gyazo.com/d884b707b00b1337993f9bb45504d23d.gif)](https://gyazo.com/d884b707b00b1337993f9bb45504d23d)|
|自分の作成した名言に対して、いいねもしくは新しい句が追加された場合、ヘッダーのインジゲーターにバッジが付き、通知一覧が見れます。|気に入った名言があれば、Xにシェアすることができます。生成AIからの名言も、人間が作った名言も、Xシェアすることができます。|

|Googleログイン機能|マイページ機能|
|:-------------|:-------------|
|[![Googleログイン機能](https://i.gyazo.com/889defdf968eec060ede2d6bb9dcce15.gif)](https://gyazo.com/889defdf968eec060ede2d6bb9dcce15)|[![マイページ機能](https://i.gyazo.com/e44ba7d651f39394d0cf578758c1f91c.gif)](https://gyazo.com/e44ba7d651f39394d0cf578758c1f91c)|
|手軽にログインしてもらえるように、Googleログイン機能を実装しました。|マイページからは、プロフィール編集、AIから受け取った名言、作成した名言、いいねした名言を、非同期通信で見れるようにしました。|

## 使用技術
|カテゴリ|技術|
|:-------------|:------------|
|フロントエンド|TailwindCSS / DaisyUI / Hotwire(Turbo/Stimulus)|う
|データベース|PostgreSQL|
|認証|Devise / OmniAuth|
|環境構築|Docker|
|インフラ|Render / Amazon S3|
|API|OpenAI|
|その他|Google Cloud Platform / CarrierWave / Ransack / GitHub Actions |
|テスティング|RSpec / Rubocop|

## 選定理由
### 開発環境
開発環境には、環境ごとの差異を最小限に抑えられるとともに、`docker-compose`を使用することで、各コンテナの起動、停止、再構築をコマンド一つで実行できる点が開発の効率化に繋がると考え、`Docker`を採用しました。

### フロントエンド
見た目が良く、`erb`ファイルに直書きでき、さらにキャッチアップの時間が比較的短く実装が可能な`TailwindCSS`および`DaisyUI`を採用しました。動きをつけた実装に関しては、Rails7系標準装備の`Hotwire(Turbo/Stimulus)`を活用しました。

### バックエンド
今回が初めての1人でのアプリケーション制作だったため、効率的に進める必要があり、既存の知識を活かし、学んだ内容が身についているかを確認したかったので、カリキュラムで学んだ`Ruby on Rails`を採用しました。

### インフラ
チーム開発でも使ったことのある、比較的簡単にデプロイが可能な`Render.com`を採用しました。
本番環境の画像の保存では、`Amazon S3`を採用しています。

### ■画面遷移図
https://www.figma.com/file/S1z6X4vCrSX253LngTahUD/Untitled?type=design&node-id=0-1&mode=design&t=F0ngmkwPdbmGs7d7-0

### ■ER図
```mermaid
erDiagram
  Users ||--o{ Sns_credentials: "has_many"
  Users ||--o{ Fetch_ais: "has_many"
  Users ||--o{ Makes: "has_many"
  Users ||--o{ First_parts: "has_many"
  Users ||--o{ Second_parts: "has_many"
  Users ||--o{ Likes: "has_many"
  Users ||--o{ Informations: "has_many"
  
  Makes ||--o{ First_parts: "has_many"
  Makes ||--o{ Second_parts: "has_many"
  Makes ||--o{ Likes: "has_many"
  Makes ||--o{ Informations: "has_many"

  First_parts ||--o{ Informations: "has_many"
  Second_parts ||--o{ Informations: "has_many"
  
  Users {
    bigint id PK
    string name
    string email
    string avatar
    string encrypted_password
    string reset_password_token
    datetime reset_password_sent_at
    datetime remember_created_at
  }

  Sns_credentials {
    bigint id PK
    string uid
    string provider
  }

  Fetch_ais {
    bigint id PK
    bigint user_id FK "references"
    string mood
    string schedule
    string how
    string popularity
    string quote_type
    text response
  }

  Makes {
    bigint id PK
    bigint user_id FK "references"
    string sentence_type
  }

  First_parts {
    bigint id PK
    bigint user_id FK "references"
    bigint make_id FK "references"
    text content
  }

  Second_parts {
    bigint id PK
    bigint user_id FK "references"
    bigint make_id FK "references"
    text content
  }

  Likes {
    bigint id PK
    bigint user_id FK "references"
    bigint ai_id FK "references"
    bigint make_id FK "references"
  }

  Informations {
    bigint id PK
    bigint make_id FK "references"
    bigint first_part_id FK "references"
    bigint second_part_id FK "references"
    bigint visitor_id FK "references"
    bigint visited_id FK "references"
    datetime created_at
    datetime updated_at
  }
```

## 工夫点
### オリジナリティ
オリジナリティを出すために、世界観を大事にしたアプリにしました。私が普段からプロフィール画像などに使っていて愛着があり、三重県（前職の会社）にゆかりのある「ラッコ」をアプリのメインキャラクターにし、「ラッコが広大な言葉の海から名言を持ってくる」という世界観でアプリを作成しました。生成AIによる名言取得の際には、Stimulusを活用したラッコのアニメーションも実装しています。

### ユーザビリティ
画面遷移が多いと煩わしいのではないかと考え、画面遷移をなるべく少なくし、ユーザーの入力操作（取得、作成、編集、削除）はモーダルで行えるようにしました。また、画面遷移先でも次の動作が直感的にわかるようにボタンを配置し、前のページに戻るボタンなども用意しました。さらに、ヘッダーやフッターには直感的に理解しやすい機能を並べ、説明が少なくてもアプリを操作できるよう意識しました。

### 手軽さ
ユーザー登録をなるべくして全ての機能を使って頂けるように、手軽にログインのできるGoogleログインを実装しました。
そして、メイン機能のユーザー体験は、1回あたり最短10秒ほどで済みます。

### 名言取得機能
他の名言アプリ、サイトを見ると名言の絶対数は限られているように感じたので、OpenAIを活用し、無限に名言が生成されるように実装しました。

### 名言作成機能
ユーザーが楽しめる要素を増やすために、「名言の共有・作成機能」「上の句・下の句に分けて、2人で名言を作成することができる機能」なども実装しております。

### トップページ
生成AIを使った編集サイトで、もともと静止画であった画像の雲や波を動かしています。

### 配色
ラッコと海を意識した青系の配色をメインの色にしました。いいねは星形にし、黄色にしました。
なるべく色が混ざらないように意識しました。

### デザイン
生成AI、もしくはラッコと話しているようなチャットバブルを用いたデザインを多く取り入れました。
フラッシュメッセージや細かい文言も、ラッコが話している風にしています。

## 今後について
**1.パーソナライズ**
生成AIによる名言取得の際に、ユーザーの取得した名言や作成した名言に近い名言が出やすくなるような実装をしたいです。

**2.通知機能**
アプリ内だけではなく、アプリ外でのGmailを使った通知機能、名言の自動提供なども実装したいです。

## 終わりに
1人でアプリケーションを制作するのは、今回が初めてでした。特にテーブル設計など、実装が完了するまで、自分の想像が合っているのか分からず、難しかったですが、とても勉強になりました。『アプリを作ってみないと学習の理解度は確かめられない』という先人たちの言葉を見に染みて感じました。
日々キャッチアップしながらの実装でしたが、自分の思い描くアプリケーションが目に見えて形になっていくのは楽しかったです。
学習を始めてから、一番自分が成長していると感じられる期間でした。

開発するにあたり、ご協力頂いた講師やRUNTEQ生の皆様に感謝いたします。

`JavaScript`や`SQL`、`Docker`など、多方面に勉強が必要なことを痛感しました。今後は、フロントエンドとバックエンドを分ける実装などにも挑戦したいです。

最後まで読んでくださり、ありがとうございました。