fix(together): Gemini失敗時もJina成功ならarchive_status='done'にする
Gemini API 503 エラー時に全体を'failed'にしていたため、 Jina で本文取得済みの記事でもReaderボタンが表示されなかった。 Gemini だけ失敗した場合は summary=null/tags=[] で 'done' にし、 Readerは使える状態を保つ。既存の28件は DB で直接修正済み。 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
58ca9d2540
commit
ef7fccb255
32
server.js
32
server.js
|
|
@ -2583,21 +2583,25 @@ ${excerpt}
|
||||||
let summary = null;
|
let summary = null;
|
||||||
let tags = [];
|
let tags = [];
|
||||||
if (genAI && fullContent) {
|
if (genAI && fullContent) {
|
||||||
// 最初の ## 見出し以降を本文とみなし 4000 字を Gemini に渡す
|
|
||||||
const bodyStart = fullContent.search(/^#{1,2}\s/m);
|
|
||||||
const excerpt = (bodyStart >= 0 ? fullContent.slice(bodyStart) : fullContent).slice(0, 4000);
|
|
||||||
const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
|
|
||||||
const prompt = `以下の記事を分析して、JSONのみを返してください(コードブロック不要)。\n\n{"summary":"1〜2文の日本語要約","tags":["タグ1","タグ2","タグ3"]}\n\n- summary: 読者が読む価値があるかを判断できる1〜2文\n- tags: 内容を表す具体的な日本語タグを2〜4個。「その他」は絶対に使わないこと。内容が不明な場合でも最も近いカテゴリを選ぶ(例: AI, テクノロジー, ビジネス, 健康, 旅行, 料理, スポーツ, 政治, 経済, エンタメ, ゲーム, 科学, デザイン, ライフスタイル, 教育, 環境, 医療, 法律, 文化, 歴史)\n\n記事:\n${excerpt}`;
|
|
||||||
const timeoutP = new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 30000));
|
|
||||||
const result = await Promise.race([model.generateContent(prompt), timeoutP]);
|
|
||||||
const raw = result.response.text().trim();
|
|
||||||
try {
|
try {
|
||||||
const parsed = JSON.parse(raw);
|
// 最初の ## 見出し以降を本文とみなし 4000 字を Gemini に渡す
|
||||||
summary = (parsed.summary || '').slice(0, 300);
|
const bodyStart = fullContent.search(/^#{1,2}\s/m);
|
||||||
tags = Array.isArray(parsed.tags) ? parsed.tags.slice(0, 4).map(t => String(t).slice(0, 20)) : [];
|
const excerpt = (bodyStart >= 0 ? fullContent.slice(bodyStart) : fullContent).slice(0, 4000);
|
||||||
} catch {
|
const model = genAI.getGenerativeModel({ model: 'gemini-2.5-flash' });
|
||||||
// JSON パース失敗時は全文を要約として扱う
|
const prompt = `以下の記事を分析して、JSONのみを返してください(コードブロック不要)。\n\n{"summary":"1〜2文の日本語要約","tags":["タグ1","タグ2","タグ3"]}\n\n- summary: 読者が読む価値があるかを判断できる1〜2文\n- tags: 内容を表す具体的な日本語タグを2〜4個。「その他」は絶対に使わないこと。内容が不明な場合でも最も近いカテゴリを選ぶ(例: AI, テクノロジー, ビジネス, 健康, 旅行, 料理, スポーツ, 政治, 経済, エンタメ, ゲーム, 科学, デザイン, ライフスタイル, 教育, 環境, 医療, 法律, 文化, 歴史)\n\n記事:\n${excerpt}`;
|
||||||
summary = raw.slice(0, 300);
|
const timeoutP = new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), 30000));
|
||||||
|
const result = await Promise.race([model.generateContent(prompt), timeoutP]);
|
||||||
|
const raw = result.response.text().trim();
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
summary = (parsed.summary || '').slice(0, 300);
|
||||||
|
tags = Array.isArray(parsed.tags) ? parsed.tags.slice(0, 4).map(t => String(t).slice(0, 20)) : [];
|
||||||
|
} catch {
|
||||||
|
summary = raw.slice(0, 300);
|
||||||
|
}
|
||||||
|
} catch (aiErr) {
|
||||||
|
// Gemini 失敗(503等): Jina 本文は保存済みなので Reader は使える状態で done にする
|
||||||
|
console.error('[together archive AI]', shareId, aiErr.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue