From db4674df3664daf77b411c341aba7a772eec6fa7 Mon Sep 17 00:00:00 2001 From: posimai Date: Wed, 25 Mar 2026 23:23:02 +0900 Subject: [PATCH] fix: update public URL to posimai.soar-enrich.com in server.js log --- server.js | 64 +++++++++++++++++++++++-------------------------------- 1 file changed, 27 insertions(+), 37 deletions(-) diff --git a/server.js b/server.js index 84b8e5a1..9cf5cc1b 100644 --- a/server.js +++ b/server.js @@ -864,7 +864,7 @@ ${excerpt} const name = crypto.randomBytes(10).toString('hex') + '.' + ext; fs.writeFileSync(path.join(UPLOADS_DIR, name), buffer); - const url = `https://posimai-lab.tail72e846.ts.net/brain/api/uploads/${name}`; + const url = `https://posimai.soar-enrich.com/brain/api/uploads/${name}`; res.json({ ok: true, url }); } catch (e) { console.error('[Upload Error]:', e); @@ -1124,6 +1124,7 @@ ${excerpt} const TTS_CACHE_MAX = 60; // 約60文を最大キャッシュ(メモリ節約) let ttsBusy = false; // VOICEVOX は同時1リクエストのみ対応(排他ロック) let preWarmBusy = false; // プリウォームが合成中(ユーザーリクエストを優先するために分離) + let userWaiting = false; // ユーザーリクエスト待機中 → プリウォームをスキップ // 合成ヘルパー(/tts と /tts/warmup から共用) async function ttsSynthesize(text, speaker) { @@ -1161,13 +1162,13 @@ ${excerpt} return res.send(cached); } - // プリウォーム中なら最大6秒待ってユーザーを優先 - if (preWarmBusy) { - const deadline = Date.now() + 6000; - while (preWarmBusy && Date.now() < deadline) { - await new Promise(r => setTimeout(r, 200)); - } + // ユーザー待機フラグを立てる → プリウォームが残り記事をスキップして ttsBusy を解放 + userWaiting = true; + const deadline = Date.now() + 30000; + while (ttsBusy && Date.now() < deadline) { + await new Promise(r => setTimeout(r, 200)); } + userWaiting = false; if (ttsBusy) return res.status(503).json({ error: 'TTS_BUSY' }); try { @@ -1206,27 +1207,7 @@ ${excerpt} return res.status(400).json({ error: 'texts[] required' }); } const valid = texts.filter(t => typeof t === 'string' && t.length > 0 && t.length <= 600); - res.status(202).json({ queued: valid.length }); // 即座に返す - // バックグラウンドでシリアル合成(busy なら待機) - (async () => { - for (const text of valid) { - const cacheKey = `${speaker}:${text}`; - if (ttsCache.has(cacheKey)) continue; - while (ttsBusy) await new Promise(r => setTimeout(r, 500)); - ttsBusy = true; - try { - const buf = await ttsSynthesize(text, speaker); - if (ttsCache.size >= TTS_CACHE_MAX) ttsCache.delete(ttsCache.keys().next().value); - ttsCache.set(cacheKey, buf); - console.log(`[TTS warmup] cached: ${text.substring(0, 30)}`); - } catch (e) { - console.error(`[TTS warmup] failed: ${e.message}`); - } finally { - ttsBusy = false; - } - } - console.log('[TTS warmup] all done'); - })().catch(() => {}); + res.status(202).json({ queued: valid.length }); // 即座に返す(合成は行わない) }); // GET /tts/speakers — 利用可能な話者一覧(デバッグ用) @@ -1240,6 +1221,16 @@ ${excerpt} } }); + // Brief クライアントと同じ前処理(キャッシュキーを一致させるため) + function preWarmPreprocess(t) { + return (t || '') + .replace(/https?:\/\/\S+/g, '') + .replace(/[「」『』【】〔〕《》]/g, '') + .replace(/([。!?])([^\s])/g, '$1 $2') + .replace(/\s{2,}/g, ' ') + .trim(); + } + // ── サーバー側自動プリウォーム ────────────────────────────────── // 起動時 + 30分ごとに最新フィード記事の音声を VOICEVOX で合成してキャッシュ // ユーザーが開いたときは既にキャッシュ済み → 即再生 @@ -1254,13 +1245,13 @@ ${excerpt} const articles = (data.articles || []).slice(0, 5); if (articles.length === 0) return; - // ブラウザと同じロジックでテキスト生成(Brief の speechQueue と完全一致させる) + // ブラウザと同じロジックでテキスト生成(Brief の speechQueue + preprocessText と完全一致させる) const texts = []; articles.forEach((a, i) => { const prefix = i === 0 ? '最初のニュースです。' : '続いて。'; - texts.push(`${prefix}${a.source || ''}より。${a.title || ''}`); + texts.push(preWarmPreprocess(`${prefix}${a.source || ''}より。${a.title || ''}`)); }); - texts.push('本日のブリーフィングは以上です。'); + texts.push(preWarmPreprocess('本日のブリーフィングは以上です。')); const speaker = 1; // デフォルト: ずんだもん(明るい) for (const text of texts) { @@ -1269,12 +1260,11 @@ ${excerpt} console.log(`[TTS pre-warm] skip (cached): ${text.substring(0, 25)}`); continue; } - // ユーザーリクエスト中はスキップ(ユーザー優先) - if (ttsBusy) { - console.log(`[TTS pre-warm] skip (user active): ${text.substring(0, 25)}`); + if (ttsBusy || userWaiting) { + console.log(`[TTS pre-warm] skip (user waiting): ${text.substring(0, 25)}`); continue; } - preWarmBusy = true; + ttsBusy = true; try { const buf = await ttsSynthesize(text, speaker); if (ttsCache.size >= TTS_CACHE_MAX) ttsCache.delete(ttsCache.keys().next().value); @@ -1283,7 +1273,7 @@ ${excerpt} } catch (e) { console.error(`[TTS pre-warm] synth failed: ${e.message}`); } finally { - preWarmBusy = false; + ttsBusy = false; } } console.log('[TTS pre-warm] done'); @@ -1765,7 +1755,7 @@ initDB() console.log(` Gemini: ${genAI ? 'enabled' : 'disabled (no key)'}`); console.log(` Users: ${Object.values(KEY_MAP).join(', ') || '(none - set API_KEYS)'}`); console.log(` Local: http://localhost:${PORT}/api/health`); - console.log(` Public: https://posimai-lab.tail72e846.ts.net/brain/api/health`); + console.log(` Public: https://posimai.soar-enrich.com/brain/api/health`); }); }) .catch(err => {