@minimalcorp/tsunagi 0.1.26 → 0.1.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/apps/web/.next/BUILD_ID +1 -1
- package/.next/standalone/apps/web/.next/build-manifest.json +3 -3
- package/.next/standalone/apps/web/.next/prerender-manifest.json +3 -3
- package/.next/standalone/apps/web/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.html +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- package/.next/standalone/apps/web/.next/server/middleware-build-manifest.js +3 -3
- package/.next/standalone/apps/web/.next/server/pages/404.html +1 -1
- package/.next/standalone/apps/web/.next/server/pages/500.html +1 -1
- package/.next/standalone/apps/web/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/apps/web/.next/server/server-reference-manifest.json +1 -1
- package/dist/server/lib/llm-process.js +24 -7
- package/dist/server/lib/whisper-process.js +22 -5
- package/npm-shrinkwrap.json +505 -119
- package/package.json +1 -1
- package/whisper-server/server.py +2 -1
- /package/.next/standalone/apps/web/.next/static/{7jfNq7gWy6LmFypqM6QZf → pTO1DUFCsjrTTtmSPyfRJ}/_buildManifest.js +0 -0
- /package/.next/standalone/apps/web/.next/static/{7jfNq7gWy6LmFypqM6QZf → pTO1DUFCsjrTTtmSPyfRJ}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/apps/web/.next/static/{7jfNq7gWy6LmFypqM6QZf → pTO1DUFCsjrTTtmSPyfRJ}/_ssgManifest.js +0 -0
|
@@ -19,6 +19,14 @@ const HF_CACHE_DIR = path.join(TSUNAGI_LLM_DIR, 'cache');
|
|
|
19
19
|
const MODEL_CACHE_DIR = path.join(HF_CACHE_DIR, 'hub', 'models--mlx-community--Qwen3-30B-A3B-Instruct-2507-4bit');
|
|
20
20
|
// 実測値(2026-07時点、4bit量子化された重み一式の合計)。多少の変動はあるがETA計算の目安として使う。
|
|
21
21
|
const EXPECTED_MODEL_BYTES = 17_200_000_000;
|
|
22
|
+
// starting_serverフェーズ(spawn後にhealthyになるまで待つ時間)の上限。
|
|
23
|
+
// mlx_lm.serverは/healthをモデル本体のロード完了を待たずに返す(ロードはバックグラウンド
|
|
24
|
+
// スレッドで進む)ため、この待ち時間の大半はPython起動/import初期化のばらつきに対する
|
|
25
|
+
// マージン。whisperより依存関係が重いぶん長めの90秒を維持する。
|
|
26
|
+
// プロセスが起動途中でクラッシュした場合はこのタイムアウトを待たず即座に検知する。
|
|
27
|
+
const STARTUP_TIMEOUT_MS = 90_000;
|
|
28
|
+
// クラッシュ時にエラーメッセージへ含めるstderrの上限文字数。
|
|
29
|
+
const STDERR_TAIL_MAX_CHARS = 4000;
|
|
22
30
|
// このファイルは apps/server/src/lib (dev) または apps/cli/dist/server/lib
|
|
23
31
|
// (npm配布物) のいずれかにいる。どちらの場合も3階層上に llm-server が
|
|
24
32
|
// 兄弟ディレクトリとして存在するようレイアウトを揃えている
|
|
@@ -150,25 +158,34 @@ async function runSetupAndStart(dir) {
|
|
|
150
158
|
downloadProgress = undefined;
|
|
151
159
|
}
|
|
152
160
|
currentStep = 'starting_server';
|
|
153
|
-
const child = spawn(venvPython(), ['-m', 'mlx_lm.server', '--model', MODEL, '--host', '127.0.0.1', '--port', String(LLM_PORT)], { cwd: dir, stdio: 'ignore', env: hfEnv });
|
|
154
|
-
|
|
161
|
+
const child = spawn(venvPython(), ['-m', 'mlx_lm.server', '--model', MODEL, '--host', '127.0.0.1', '--port', String(LLM_PORT)], { cwd: dir, stdio: ['ignore', 'ignore', 'pipe'], env: hfEnv });
|
|
162
|
+
let stderrTail = '';
|
|
163
|
+
child.stderr?.on('data', (chunk) => {
|
|
164
|
+
stderrTail = (stderrTail + chunk.toString()).slice(-STDERR_TAIL_MAX_CHARS);
|
|
165
|
+
});
|
|
166
|
+
// healthポーリングとは別に、プロセスが起動途中で終了したことをタイムアウトを待たず検知する。
|
|
167
|
+
let exitInfo = null;
|
|
168
|
+
child.on('exit', (code, signal) => {
|
|
169
|
+
exitInfo = `exit code=${code} signal=${signal}`;
|
|
155
170
|
if (managedProcess === child)
|
|
156
171
|
managedProcess = null;
|
|
157
172
|
});
|
|
158
|
-
child.on('error', () => {
|
|
173
|
+
child.on('error', (err) => {
|
|
174
|
+
exitInfo = `spawn error: ${err.message}`;
|
|
159
175
|
if (managedProcess === child)
|
|
160
176
|
managedProcess = null;
|
|
161
177
|
});
|
|
162
178
|
managedProcess = child;
|
|
163
|
-
// MoEで実計算はアクティブパラメータ(~3B)分のみだが、4bit量子化でも~17GBの
|
|
164
|
-
// 重みファイル自体はメモリへ展開する必要があるため、whisperより長めに待つ。
|
|
165
179
|
const start = Date.now();
|
|
166
|
-
while (Date.now() - start <
|
|
180
|
+
while (Date.now() - start < STARTUP_TIMEOUT_MS) {
|
|
181
|
+
if (exitInfo) {
|
|
182
|
+
throw new Error(`llm-server crashed while starting (${exitInfo})${stderrTail ? `\n${stderrTail}` : ''}`);
|
|
183
|
+
}
|
|
167
184
|
if (await checkHealth())
|
|
168
185
|
return;
|
|
169
186
|
await sleep(1000);
|
|
170
187
|
}
|
|
171
|
-
throw new Error(
|
|
188
|
+
throw new Error(`Server did not become healthy within ${STARTUP_TIMEOUT_MS / 1000}s of starting`);
|
|
172
189
|
}
|
|
173
190
|
export function startLlmServer() {
|
|
174
191
|
if (setupPromise || managedProcess) {
|
|
@@ -15,6 +15,12 @@ const HF_CACHE_DIR = path.join(TSUNAGI_WHISPER_DIR, 'cache');
|
|
|
15
15
|
const MODEL_CACHE_DIR = path.join(HF_CACHE_DIR, 'hub', 'models--mlx-community--whisper-large-v3-turbo');
|
|
16
16
|
// 実測値(2026-07時点、encoder+decoder等の合計)。多少の変動はあるがETA計算の目安として使う。
|
|
17
17
|
const EXPECTED_MODEL_BYTES = 1_614_000_000;
|
|
18
|
+
// starting_serverフェーズ(spawn後にhealthyになるまで待つ時間)の上限。
|
|
19
|
+
// 遅いマシンでのPython起動/import/Metal初期化のばらつきを吸収するため60秒に設定。
|
|
20
|
+
// プロセスが起動途中でクラッシュした場合はこのタイムアウトを待たず即座に検知する。
|
|
21
|
+
const STARTUP_TIMEOUT_MS = 60_000;
|
|
22
|
+
// クラッシュ時にエラーメッセージへ含めるstderrの上限文字数。
|
|
23
|
+
const STDERR_TAIL_MAX_CHARS = 4000;
|
|
18
24
|
// このファイルは apps/server/src/lib (dev) または apps/cli/dist/server/lib
|
|
19
25
|
// (npm配布物) のいずれかにいる。どちらの場合も3階層上に whisper-server が
|
|
20
26
|
// 兄弟ディレクトリとして存在するようレイアウトを揃えている
|
|
@@ -146,23 +152,34 @@ async function runSetupAndStart(dir) {
|
|
|
146
152
|
downloadProgress = undefined;
|
|
147
153
|
}
|
|
148
154
|
currentStep = 'starting_server';
|
|
149
|
-
const child = spawn(venvPython(), ['-m', 'uvicorn', 'server:app', '--host', '127.0.0.1', '--port', '8765'], { cwd: dir, stdio: 'ignore', env: hfEnv });
|
|
150
|
-
|
|
155
|
+
const child = spawn(venvPython(), ['-m', 'uvicorn', 'server:app', '--host', '127.0.0.1', '--port', '8765'], { cwd: dir, stdio: ['ignore', 'ignore', 'pipe'], env: hfEnv });
|
|
156
|
+
let stderrTail = '';
|
|
157
|
+
child.stderr?.on('data', (chunk) => {
|
|
158
|
+
stderrTail = (stderrTail + chunk.toString()).slice(-STDERR_TAIL_MAX_CHARS);
|
|
159
|
+
});
|
|
160
|
+
// healthポーリングとは別に、プロセスが起動途中で終了したことをタイムアウトを待たず検知する。
|
|
161
|
+
let exitInfo = null;
|
|
162
|
+
child.on('exit', (code, signal) => {
|
|
163
|
+
exitInfo = `exit code=${code} signal=${signal}`;
|
|
151
164
|
if (managedProcess === child)
|
|
152
165
|
managedProcess = null;
|
|
153
166
|
});
|
|
154
|
-
child.on('error', () => {
|
|
167
|
+
child.on('error', (err) => {
|
|
168
|
+
exitInfo = `spawn error: ${err.message}`;
|
|
155
169
|
if (managedProcess === child)
|
|
156
170
|
managedProcess = null;
|
|
157
171
|
});
|
|
158
172
|
managedProcess = child;
|
|
159
173
|
const start = Date.now();
|
|
160
|
-
while (Date.now() - start <
|
|
174
|
+
while (Date.now() - start < STARTUP_TIMEOUT_MS) {
|
|
175
|
+
if (exitInfo) {
|
|
176
|
+
throw new Error(`whisper-server crashed while starting (${exitInfo})${stderrTail ? `\n${stderrTail}` : ''}`);
|
|
177
|
+
}
|
|
161
178
|
if (await checkHealth())
|
|
162
179
|
return;
|
|
163
180
|
await sleep(1000);
|
|
164
181
|
}
|
|
165
|
-
throw new Error(
|
|
182
|
+
throw new Error(`Server did not become healthy within ${STARTUP_TIMEOUT_MS / 1000}s of starting`);
|
|
166
183
|
}
|
|
167
184
|
export function startWhisperServer() {
|
|
168
185
|
if (setupPromise || managedProcess) {
|