feat(subtitles): use loaded subtitles to guide generation timing (#249)

This commit is contained in:
2026-09-18 00:24:42 -07:00
committed by GitHub
parent 186d4a0640
commit a8c16147ad
24 changed files with 965 additions and 75 deletions
@@ -3,10 +3,25 @@ import test from 'node:test';
import {
describeGenerationModel,
describeGenerationProgress,
describeGenerationRecommendation,
describeGenerationTools,
describeGenerationVad,
} from './subtitle-generation-view';
test('only confirmed NVIDIA CUDA support recommends turbo', () => {
assert.deepEqual(describeGenerationRecommendation({ kind: 'unavailable' }), {
model: 'small',
text: 'NVIDIA CUDA acceleration was not confirmed. small is recommended.',
});
assert.deepEqual(
describeGenerationRecommendation({ kind: 'nvidia-cuda', gpuName: 'NVIDIA RTX 5070 Ti' }),
{
model: 'large-v3-turbo',
text: 'NVIDIA CUDA is available with NVIDIA RTX 5070 Ti. large-v3-turbo is recommended.',
},
);
});
test('missing tools block generation and list every install instruction', () => {
const found = { kind: 'found', path: '/usr/bin/tool' } as const;
assert.deepEqual(
@@ -1,11 +1,23 @@
import {
missingSubtitleGenerationTools,
recommendedSubtitleGenerationModel,
type SubtitleGenerationAcceleration,
type SubtitleGenerationModelStatus,
type SubtitleGenerationProgress,
type SubtitleGenerationTools,
} from '../../shared/subtitle-generation';
import type { SubtitleGenerationStatus } from '../../shared/subtitle-generation-ipc';
export function describeGenerationRecommendation(acceleration: SubtitleGenerationAcceleration) {
return {
model: recommendedSubtitleGenerationModel(acceleration),
text:
acceleration.kind === 'nvidia-cuda'
? `NVIDIA CUDA is available with ${acceleration.gpuName}. large-v3-turbo is recommended.`
: 'NVIDIA CUDA acceleration was not confirmed. small is recommended.',
};
}
export function describeGenerationTools(tools: SubtitleGenerationTools) {
const missing = missingSubtitleGenerationTools(tools);
if (missing.length > 0) return { ready: false, text: missing.join(' ') };
+10 -6
View File
@@ -1,7 +1,6 @@
import type { SubtitleGenerationProgress } from '../../shared/subtitle-generation';
import {
SUBTITLE_GENERATION_MODELS,
RECOMMENDED_SUBTITLE_GENERATION_MODEL,
formatSubtitleGenerationModelSize,
getSubtitleGenerationModel,
isSubtitleGenerationModelId,
@@ -16,6 +15,7 @@ import { createModalFocusGuard } from './modal-focus-guard';
import {
describeGenerationModel,
describeGenerationProgress,
describeGenerationRecommendation,
describeGenerationTools,
describeGenerationVad,
} from './subtitle-generation-view';
@@ -70,8 +70,7 @@ export function createSubtitleGenerationModal(
for (const model of SUBTITLE_GENERATION_MODELS) {
const option = document.createElement('option');
option.value = model.id;
const recommended = model.id === RECOMMENDED_SUBTITLE_GENERATION_MODEL ? ' (recommended)' : '';
option.textContent = `${model.id}${recommended} · ${formatSubtitleGenerationModelSize(model.size)}`;
option.textContent = `${model.id} · ${formatSubtitleGenerationModelSize(model.size)}`;
dom.modelSelect.append(option);
}
@@ -103,10 +102,15 @@ export function createSubtitleGenerationModal(
dom.modelPicker.classList.toggle('hidden', !snapshot || Boolean(snapshot.externalModelPath));
dom.modelSelect.disabled = busy || checking || !snapshot || Boolean(snapshot.externalModelPath);
if (snapshot) {
const recommendation = describeGenerationRecommendation(snapshot.acceleration);
for (const option of dom.modelSelect.options) {
if (!isSubtitleGenerationModelId(option.value)) continue;
const model = getSubtitleGenerationModel(option.value);
const recommended = model.id === recommendation.model ? ' (recommended)' : '';
option.textContent = `${model.id}${recommended} · ${formatSubtitleGenerationModelSize(model.size)}`;
}
dom.modelSelect.value = snapshot.managedModel;
dom.modelDescription.textContent = getSubtitleGenerationModel(
snapshot.managedModel,
).description;
dom.modelDescription.textContent = `${getSubtitleGenerationModel(snapshot.managedModel).description} ${recommendation.text}`;
}
dom.download.classList.toggle('hidden', !model?.download);
dom.download.textContent = snapshot