fix: update public URL to posimai.soar-enrich.com in server.js log
This commit is contained in:
parent
ae912344e4
commit
db4674df36
62
server.js
62
server.js
|
|
@ -864,7 +864,7 @@ ${excerpt}
|
||||||
const name = crypto.randomBytes(10).toString('hex') + '.' + ext;
|
const name = crypto.randomBytes(10).toString('hex') + '.' + ext;
|
||||||
fs.writeFileSync(path.join(UPLOADS_DIR, name), buffer);
|
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 });
|
res.json({ ok: true, url });
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error('[Upload Error]:', e);
|
console.error('[Upload Error]:', e);
|
||||||
|
|
@ -1124,6 +1124,7 @@ ${excerpt}
|
||||||
const TTS_CACHE_MAX = 60; // 約60文を最大キャッシュ(メモリ節約)
|
const TTS_CACHE_MAX = 60; // 約60文を最大キャッシュ(メモリ節約)
|
||||||
let ttsBusy = false; // VOICEVOX は同時1リクエストのみ対応(排他ロック)
|
let ttsBusy = false; // VOICEVOX は同時1リクエストのみ対応(排他ロック)
|
||||||
let preWarmBusy = false; // プリウォームが合成中(ユーザーリクエストを優先するために分離)
|
let preWarmBusy = false; // プリウォームが合成中(ユーザーリクエストを優先するために分離)
|
||||||
|
let userWaiting = false; // ユーザーリクエスト待機中 → プリウォームをスキップ
|
||||||
|
|
||||||
// 合成ヘルパー(/tts と /tts/warmup から共用)
|
// 合成ヘルパー(/tts と /tts/warmup から共用)
|
||||||
async function ttsSynthesize(text, speaker) {
|
async function ttsSynthesize(text, speaker) {
|
||||||
|
|
@ -1161,13 +1162,13 @@ ${excerpt}
|
||||||
return res.send(cached);
|
return res.send(cached);
|
||||||
}
|
}
|
||||||
|
|
||||||
// プリウォーム中なら最大6秒待ってユーザーを優先
|
// ユーザー待機フラグを立てる → プリウォームが残り記事をスキップして ttsBusy を解放
|
||||||
if (preWarmBusy) {
|
userWaiting = true;
|
||||||
const deadline = Date.now() + 6000;
|
const deadline = Date.now() + 30000;
|
||||||
while (preWarmBusy && Date.now() < deadline) {
|
while (ttsBusy && Date.now() < deadline) {
|
||||||
await new Promise(r => setTimeout(r, 200));
|
await new Promise(r => setTimeout(r, 200));
|
||||||
}
|
}
|
||||||
}
|
userWaiting = false;
|
||||||
if (ttsBusy) return res.status(503).json({ error: 'TTS_BUSY' });
|
if (ttsBusy) return res.status(503).json({ error: 'TTS_BUSY' });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -1206,27 +1207,7 @@ ${excerpt}
|
||||||
return res.status(400).json({ error: 'texts[] required' });
|
return res.status(400).json({ error: 'texts[] required' });
|
||||||
}
|
}
|
||||||
const valid = texts.filter(t => typeof t === 'string' && t.length > 0 && t.length <= 600);
|
const valid = texts.filter(t => typeof t === 'string' && t.length > 0 && t.length <= 600);
|
||||||
res.status(202).json({ queued: valid.length }); // 即座に返す
|
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(() => {});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// GET /tts/speakers — 利用可能な話者一覧(デバッグ用)
|
// 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 で合成してキャッシュ
|
// 起動時 + 30分ごとに最新フィード記事の音声を VOICEVOX で合成してキャッシュ
|
||||||
// ユーザーが開いたときは既にキャッシュ済み → 即再生
|
// ユーザーが開いたときは既にキャッシュ済み → 即再生
|
||||||
|
|
@ -1254,13 +1245,13 @@ ${excerpt}
|
||||||
const articles = (data.articles || []).slice(0, 5);
|
const articles = (data.articles || []).slice(0, 5);
|
||||||
if (articles.length === 0) return;
|
if (articles.length === 0) return;
|
||||||
|
|
||||||
// ブラウザと同じロジックでテキスト生成(Brief の speechQueue と完全一致させる)
|
// ブラウザと同じロジックでテキスト生成(Brief の speechQueue + preprocessText と完全一致させる)
|
||||||
const texts = [];
|
const texts = [];
|
||||||
articles.forEach((a, i) => {
|
articles.forEach((a, i) => {
|
||||||
const prefix = i === 0 ? '最初のニュースです。' : '続いて。';
|
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; // デフォルト: ずんだもん(明るい)
|
const speaker = 1; // デフォルト: ずんだもん(明るい)
|
||||||
for (const text of texts) {
|
for (const text of texts) {
|
||||||
|
|
@ -1269,12 +1260,11 @@ ${excerpt}
|
||||||
console.log(`[TTS pre-warm] skip (cached): ${text.substring(0, 25)}`);
|
console.log(`[TTS pre-warm] skip (cached): ${text.substring(0, 25)}`);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// ユーザーリクエスト中はスキップ(ユーザー優先)
|
if (ttsBusy || userWaiting) {
|
||||||
if (ttsBusy) {
|
console.log(`[TTS pre-warm] skip (user waiting): ${text.substring(0, 25)}`);
|
||||||
console.log(`[TTS pre-warm] skip (user active): ${text.substring(0, 25)}`);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
preWarmBusy = true;
|
ttsBusy = true;
|
||||||
try {
|
try {
|
||||||
const buf = await ttsSynthesize(text, speaker);
|
const buf = await ttsSynthesize(text, speaker);
|
||||||
if (ttsCache.size >= TTS_CACHE_MAX) ttsCache.delete(ttsCache.keys().next().value);
|
if (ttsCache.size >= TTS_CACHE_MAX) ttsCache.delete(ttsCache.keys().next().value);
|
||||||
|
|
@ -1283,7 +1273,7 @@ ${excerpt}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(`[TTS pre-warm] synth failed: ${e.message}`);
|
console.error(`[TTS pre-warm] synth failed: ${e.message}`);
|
||||||
} finally {
|
} finally {
|
||||||
preWarmBusy = false;
|
ttsBusy = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log('[TTS pre-warm] done');
|
console.log('[TTS pre-warm] done');
|
||||||
|
|
@ -1765,7 +1755,7 @@ initDB()
|
||||||
console.log(` Gemini: ${genAI ? 'enabled' : 'disabled (no key)'}`);
|
console.log(` Gemini: ${genAI ? 'enabled' : 'disabled (no key)'}`);
|
||||||
console.log(` Users: ${Object.values(KEY_MAP).join(', ') || '(none - set API_KEYS)'}`);
|
console.log(` Users: ${Object.values(KEY_MAP).join(', ') || '(none - set API_KEYS)'}`);
|
||||||
console.log(` Local: http://localhost:${PORT}/api/health`);
|
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 => {
|
.catch(err => {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue