diff --git a/server.js b/server.js index 0b6b4bbc..6fdcdf38 100644 --- a/server.js +++ b/server.js @@ -191,8 +191,6 @@ pool.on('error', (err) => { const genAI = process.env.GEMINI_API_KEY ? new GoogleGenerativeAI(process.env.GEMINI_API_KEY) : null; -// Together 専用インスタンス(メインキーを共用) -const genAITogether = genAI; // ── API Key 認証 ────────────────────────── // API_KEYS="pk_maita_abc:maita,pk_partner_def:partner" @@ -1389,14 +1387,20 @@ function buildRouter() { sql += ' ORDER BY saved_at DESC LIMIT 300'; try { - const { rows } = await pool.query(sql, params); + const [{ rows }, { rows: countRows }] = await Promise.all([ + pool.query(sql, params), + pool.query( + `SELECT status, COUNT(*)::int AS cnt FROM articles WHERE user_id=$1 GROUP BY status`, + [req.userId] + ) + ]); - // カウント計算 + const countMap = Object.fromEntries(countRows.map(r => [r.status, r.cnt])); const counts = { - all: rows.length, - unread: rows.filter(a => a.status === 'inbox').length, - favorite: rows.filter(a => a.status === 'favorite').length, - shared: rows.filter(a => a.status === 'shared').length + all: countRows.reduce((s, r) => s + r.cnt, 0), + unread: countMap['inbox'] || 0, + favorite: countMap['favorite'] || 0, + shared: countMap['shared'] || 0, }; res.json({ articles: rows, counts }); @@ -1465,7 +1469,14 @@ function buildRouter() { if (checkRateLimit('gemini_analyze', savedUserId, 50, 60 * 60 * 1000)) { analyzeWithGemini(finalTitle, fullText || meta.desc, url).then(async (ai) => { - if (!ai) { console.warn(`[Brain API] AI analysis skipped (null) for ${url}`); return; } + if (!ai) { + console.warn(`[Brain API] AI analysis failed for ${url}, clearing placeholder`); + await pool.query( + `UPDATE articles SET summary=NULL WHERE user_id=$1 AND url=$2 AND summary LIKE '⏳%'`, + [savedUserId, url] + ); + return; + } await pool.query(` UPDATE articles SET summary=$1, topics=$2, reading_time=$3 WHERE user_id=$4 AND url=$5 @@ -1474,7 +1485,7 @@ function buildRouter() { }).catch(e => console.error('[Background AI Error]:', e)); } } catch (e) { - console.error('[Background Meta Error]:', e.message); + console.error('[Background Meta Error]:', e.message || e); } }); @@ -1566,7 +1577,13 @@ function buildRouter() { if (checkRateLimit('gemini_analyze', savedUserId, 50, 60 * 60 * 1000)) { analyzeWithGemini(meta.title, fullText, url).then(async (ai) => { - if (!ai) { console.warn(`[Brain API] AI analysis skipped (null) for ${url}`); return; } + if (!ai) { + await pool.query( + `UPDATE articles SET summary=NULL WHERE user_id=$1 AND url=$2 AND summary LIKE '⏳%'`, + [savedUserId, url] + ); + return; + } await pool.query(` UPDATE articles SET summary=$1, topics=$2, reading_time=$3 WHERE user_id=$4 AND url=$5 @@ -1579,7 +1596,7 @@ function buildRouter() { }); } catch (e) { - if (!res.headersSent) res.status(500).send(`