Merge branch 'feature/t28-laya-download-unavailable-runtime' into develop (#28)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
blomios
2026-10-06 20:31:29 +02:00
3 changed files with 33 additions and 3 deletions

View File

@ -1212,7 +1212,7 @@
<script src="/js/components/VideoPlayer.js?v=5"></script>
<script src="/js/services/channelLanguageDetection.js?v=1"></script>
<script src="/js/services/channelLanguageFusion.js?v=1"></script>
<script src="/js/services/layaStatusPresentation.js?v=5"></script>
<script src="/js/services/layaStatusPresentation.js?v=6"></script>
<script src="/js/services/liveAnalysisPresentation.js?v=1"></script>
<script src="/js/services/liveChannelProjection.js?v=5"></script>
<script src="/js/services/channelVariantGrouping.js?v=7"></script>

View File

@ -3,6 +3,7 @@
if (typeof module === 'object' && module.exports) module.exports = service;
if (root) root.LayaStatusPresentation = service;
})(typeof globalThis !== 'undefined' ? globalThis : this, function () {
const START_COMMAND = 'docker compose --profile laya up -d';
const PHASE_LABELS = {
idle: 'Model not downloaded',
checking: 'Checking local AI model…',
@ -39,6 +40,10 @@
const failed = phase === 'failed';
const modelPresent = status.modelPresent === true;
const runtimeAvailable = status.runtimeAvailable === true;
const runtimeUnavailable = status.runtimeAvailable === false;
const runtimeHelp = runtimeUnavailable
? `Nodecast cannot reach the optional Laya runtime. Standard matching remains available.\nStart the Laya service, then try again:\n${START_COMMAND}`
: '';
const ready = modelPresent && runtimeAvailable && !busy && !failed;
const statusLabel = ready
? 'Ready'
@ -64,13 +69,13 @@
totalBytes: status.totalBytes !== null && status.totalBytes !== undefined && Number.isFinite(Number(status.totalBytes))
? Number(status.totalBytes) : null,
errorMessage: failed ? (error.message || 'The local AI model could not be downloaded.') : '',
errorDetail: failed ? error.detail : '',
errorDetail: failed ? [error.detail, runtimeHelp].filter(Boolean).join('\n\n') : '',
downloadLabel: failed ? 'Retry download' : 'Download model',
showDownload: !busy && !modelPresent && (phase === 'idle' || failed),
showRemove: !busy && modelPresent,
showUseStandard: failed && mode !== 'algo',
showCheckAgain: !busy && modelPresent && !runtimeAvailable,
showStartCommand: !busy && modelPresent && !runtimeAvailable,
showStartCommand: !busy && runtimeUnavailable,
availabilityMessage: modelPresent && !runtimeAvailable
? 'The model is installed, but the Local AI service is not running. Standard channel matching is being used.'
: ''

View File

@ -36,6 +36,31 @@ test('failed downloads expose retry, safe details and Standard fallback', () =>
assert.equal(view.errorDetail, 'The optional Laya runtime is unavailable.');
});
test('failed Laya downloads explain how to start the unavailable runtime', () => {
const view = presentLayaStatus({
phase: 'failed',
modelPresent: false,
runtimeAvailable: false,
error: { message: 'Model download failed', detail: 'The optional Laya runtime is unavailable.' }
}, 'hybrid');
assert.match(view.errorDetail, /Nodecast cannot reach the optional Laya runtime/);
assert.match(view.errorDetail, /Standard matching remains available/);
assert.match(view.errorDetail, /Start the Laya service, then try again:/);
assert.match(view.errorDetail, /docker compose --profile laya up -d/);
assert.equal(view.showStartCommand, true);
});
test('generic Laya failures do not suggest Docker Compose', () => {
const view = presentLayaStatus({
phase: 'failed',
modelPresent: false,
runtimeAvailable: true,
error: { message: 'Model download failed', detail: 'Laya model operation failed (HTTP 500).' }
}, 'hybrid');
assert.doesNotMatch(view.errorDetail, /docker compose/);
assert.equal(view.showStartCommand, false);
});
test('ready models expose removal without download actions', () => {
const view = presentLayaStatus({ phase: 'idle', modelPresent: true, runtimeAvailable: true, sizeBytes: 678323814 });
assert.equal(view.statusLabel, 'Ready');