はじめに
「Obsidianでメモを書いたら、勝手にブログが更新されてほしい」
「しかも、勝手に英語翻訳と要約もしてほしい」
「でも、お金はかけたくない(API無料枠を使いたい)」
そんな夢のようなシステムを構築しようとしたら、数々のエラー(404, 403, DB文字数制限...) に見舞われました。
この記事では、それらをどうやって乗り越え、「Gemini 3 Flash Preview」 を搭載した最強の自動化スクリプトを完成させたのかを記録します。
🛑 直面した3つの壁
1. データベースの「文字数オーバー」エラー
最初にぶつかったのがこれです。
Value too long for type character varying(255)
PostgreSQL(Neon)の sns_x_ja など一部のカラムが String (通常191~255文字) で定義されていたため、AIが少し長めの文章を生成すると、保存時にクラッシュしていました。
✅ 解決策:
データをDBに入れる直前に、強制的に文字数をカットする(Truncate)関数 を実装しました。
これにより、AIがどんなに長文を返しても、システムは落ちなくなりました。
const safePayload = {
// 140文字で強制カット!
sns_x_ja: truncate(blogData.sns_x_ja, 140),
// ...
};
2. Gemini API の「モデル名ガチャ」
ここが一番の沼でした。
最初は gemini-1.5-flash を使おうとしましたが、なぜか 404 Not Found や 403 Forbidden が多発。
APIキーは合っているはずなのに動きません。
調査の結果、APIキーを発行したプロジェクトやタイミングによって、「使えるモデル」と「使えないモデル」がある ことが判明しました。
curl コマンドでモデル一覧を引っこ抜いて確認した結果、以下の変遷をたどりました。
-
gemini-1.5-flash→ ❌ (404/403) -
gemini-2.0-flash-exp→ ❌ (404) -
gemini-3-flash-preview→ ⭕️ 大成功!
なんと、最新のプレビュー版である Gemini 3 が一番安定して動作し、しかも英語翻訳の精度も抜群でした。
3. AIが死んだらブログも死ぬ問題
AIは水物です。APIがダウンしたり、タイムアウトすることもあります。
初期の実装では、AIがエラーを吐くと 「No AI Title」 というダミー記事が作られたり、最悪の場合は同期が止まっていました。
✅ 解決策:
「フォールバック(Fallback)」 戦略を強化しました。
AI生成 (generateContent) が失敗した場合、即座に 「Markdownの原文」 をそのまま利用するルートに切り替えます。
try {
// AIに要約・翻訳を依頼
const result = await geminiModel.generateContent(prompt);
// ...
} catch (error) {
// 失敗したら、原文をそのままつっこむ!
console.warn("⚠️ Using Original Markdown Content as Fallback.");
rawJson = JSON.stringify({
title_ja: originalTitle, // 元のファイル名
content_ja: originalContent, // 元のMarkdown
// ...
});
}
これにより、「AIが不調でも、ブログ記事自体は絶対に公開される」 という堅牢なシステムになりました。
🛠️ 完成したアーキテクチャ
最終的な構成は以下の通りです。
- Obsidian: 記事を書く(ローカル)
-
Sync Script:
scripts/manual-sync-final.tsを実行- ファイルのハッシュ値を計算(変更がなければスキップ)
- Google Gemini 3 Flash Preview を呼び出し
- JSON形式で「タイトル」「要約」「英語翻訳」「SNS文案」を取得
- 万が一のときは、安全なデータにフォールバック
- Prisma & Vercel Postgres: データを保存
- Next.js (App Router): ISR で高速表示
🎉 まとめ
あきらめずにデバッグした結果、以下の状態を達成しました。
- 完全無料: Gemini API の無料枠を利用。
- 完全自動翻訳: 日本語で書くだけで、英語記事も同時生成。
- 堅牢性: APIエラーでもシステムは止まらない。
これからブログを書くのが楽しみになりました!