架空世界のニュースメディアを作ってみた(Gemini 1.5 Pro)
どうも、ネチコヤン などの面白ペット記事に癒されてる個人開発者です。
でも、現実世界のニュース記事ってネガティブな内容が多いですよね。
もっとコミカルなニュースが増えればいいのに...
...と思ったので、量産体制を構築してみることに
今回は使い慣れた Ruby on Rails
をフルスタックモードで rails new
。
ERBアレルギーなので、 view
は全て gem view_component
の xxx_component.rb
のみで実装する変態構成に。
view_componentの変態構成
class Themes::ArticlesController < ApplicationController
def show
# 一部省略
render_cache_page(Views::Themes::Articles::ShowComponent.new(article:, articles:))
end
end
class Views::Themes::Articles::ShowComponent < Views::BaseComponent
def initialize(article:, articles:)
super
@article = article
@articles = articles
end
def call
content_tag(:section, class: "outer_container") do
concat(content_tag(:section, class: "inner_container") do
concat(breadcrumbs)
concat(content_tag(:section, class: "mt_m") do
concat(render(Application::Articles::ArticleDetailsComponent.new(@article)))
end)
concat(content_tag(:section, class: "mt_m") do
concat(render(Application::Articles::PaginationComponent.new(@article)))
end)
concat(content_tag(:section, class: "mt_m") do
concat(link_to(theme_path(@article.theme)) do
render(Application::Themes::ThemeCardComponent.new(@article.theme))
end)
end)
concat(share)
if @article.topics.present?
concat(content_tag(:section, class: "mt_l_border") do
concat(related_topics)
end)
concat(content_tag(:section, class: "mt_l") do
concat(topics_link)
end)
end
end)
if @articles.present?
concat(content_tag(:section, class: "mt_l_border") do
concat(top_news)
end)
end
concat(content_tag(:section, class: "mt_l") do
concat(themes_link)
end)
end
end
private
def breadcrumbs
render(
Application::Common::BreadcrumbsComponent.new(
items: [
{
name: "TOP",
path: root_path
},
{
name: @article.theme.title,
path: theme_path(@article.theme_id)
},
{
name: @article.title,
path: theme_article_path(@article.theme_id, @article.id)
}
]
)
)
end
def related_topics
capture do
concat(content_tag(:h2, "関連トピック", class: "center_title"))
@article.topics.each_with_index do |topic, index|
concat(content_tag(:div, class: (index.zero? ? "" : "mt_m")) do
concat(link_to(theme_topic_path(topic.theme_id, topic.id)) do
render(Application::Topics::TopicCardComponent.new(topic))
end)
end)
end
end
end
def top_news
capture do
concat(content_tag(:h1, "トップニュース", class: "center_title"))
concat(render(Application::Articles::ArticleCardListComponent.new(@articles)))
end
end
def themes_link
render(
Application::Common::SimpleButtonComponent.new(
text: "「#{@article.theme.title}」の記事一覧へ",
url: theme_path(@article.theme_id)
)
)
end
def topics_link
render(
Application::Common::SimpleButtonComponent.new(
text: "「#{@article.theme.title}」のトピック一覧へ",
url: theme_topics_path(@article.theme_id)
)
)
end
def share
capture do
concat(content_tag(:section, "", class: "mt_m"))
concat(
render(
Application::Common::TwitterShareComponent.new(
url: theme_article_url(@article.theme_id, @article.id),
text: "#{@article.title} | #{@article.theme.title}"
)
)
)
end
end
end
まずは管理画面
実装が面倒なので gem activeadmin
を使って工数削減。
必要な model
を用意して activeadmin
のファイルを rails g
。
はい、完成。
次に記事生成部分
ここはGoogleのGeminiを使うことに。
activeadmin
のカスタムページを用意して 1クリックで記事を生成できるように実装。
Gemini 1.5 Flash
Flashは「小説ではなくメディアの記事のような文体」という命令をガン無視して小説を書き始めた...
→ 不採用!!
Gemini 1.5 Pro
Flashと違ってProは命令を正しく理解できているようで、こちらが期待した結果を返してくれる。
→ 採用!!(しかし、生成1回あたりの費用がお高い...)
デプロイしてみる
- Cloud Run
- RAM: 1GB
- CPU: 1コア
- オートスケール: 0台 ~ 5台
- Cloud SQL(MySQL)
- RAM: 600MB
- CPU: 共有コア
きっと、これで十分だろう。
メモリが少ないかも?
と思ったけど、バズらないから大丈夫と判断。
とはいえ、不安な気持ちもあるので「お手軽で強力なページキャッシュ機能」を用意して対策。
「Phantom News」のできあがり
デザインなども含めて3日くらいで完成。
実際にGeminiで記事を生成してみる
わかりやすく 「魔王と勇者が和解して平和に発展した世界」 というテーマでニュース記事を生成してみた結果がこれ。
とてもいい感じ。
指定してないキャラクターが勝手に生まれてるのも良い。
・勇者が推し活??
・ダイエットに失敗するドラゴン??
・勇者と魔王って意外と仲良しなのでは??
・仲良しかと思ったら売られてるwww
・推し活で狂ってしまう人も...
・ドラゴンの推し活ダイエット?w
生成するたびに世界が広がる
あれ??なんだか記事の出来事が繋がってるような?
そう、実はキャラクターの関係性や過去の出来事を考慮して、そこから新しい記事が生成される仕様にしてるんです。
やってるのはこれだけ
- 簡単な設定を与えて架空世界の記事を生成
- 1の内容と過去の記事を与えて新しい記事を生成
これだけで世界が広がって、キャラクターが増えて、歴史が積み重なる。
ガチャ気分で記事を生成
これは運営側の楽しみ。
毎回「次はどんな記事かな?」とワクワクしながら生成して、気に入った記事のみ採用して公開する。
世界に干渉できて、なんだか架空世界の神になったような気持ち。
とても楽しい。
随時更新のトピック一覧
記事が増えるごとにキャラクター紹介が更新されて、存在しない世界の存在を感じれる不思議なページ。
このページ、個人的にお気に入り。
ランニングコストはGoogleアドセンスで回収
審査に落ちました。助けてください。
記事数は結構あるはずなんだけどなぁ...
それでも運営は続ける
このままでは確実に赤字ですが、しばらくは出力結果を見守りながら毎日投稿する予定です。
「面白い!」と思ってくれた人は、ブックマークやSNSへのシェアよろしくお願いいたします!!
今のところはモチベだけが原動力です。
おしまい。
Discussion