文件
chen 301194963b
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
feat: Initial clean release of CHM
2026-11-04 11:29:39 +08:00

135 行
3.7 KiB
TypeScript

import { setupDatabase } from '@joplin/lib/testing/test-utils';
import whisper from './whisper';
import { dirname, join } from 'path';
import { exists, mkdir, remove, writeFile } from 'fs-extra';
import Setting from '@joplin/lib/models/Setting';
const { testing__lastPrompt } = require('@joplin/whisper-voice-typing');
jest.mock('@joplin/whisper-voice-typing', () => {
let lastPrompt: string|null = null;
return {
runTests: ()=> {},
openSession: jest.fn((options) => {
lastPrompt = options.prompt;
return {
open: jest.fn(),
close: jest.fn(),
convertNext: jest.fn(() => 'Test. This is test output. Test!'),
convertAvailable: jest.fn(() => ''),
};
}),
test: ()=>{},
testing__lastPrompt: () => {
return lastPrompt;
},
};
});
interface ModelConfig {
output: {
stringReplacements: string[][];
regexReplacements: string[][];
};
}
const defaultModelConfig: ModelConfig = {
output: { stringReplacements: [], regexReplacements: [] },
};
const createMockModel = async (config: ModelConfig = defaultModelConfig) => {
const whisperBaseDirectory = dirname(whisper.modelLocalFilepath('en'));
await mkdir(whisperBaseDirectory);
const modelDirectory = join(whisperBaseDirectory, 'model');
await mkdir(modelDirectory);
await writeFile(join(modelDirectory, 'model.bin'), 'mock model', 'utf-8');
await writeFile(join(modelDirectory, 'config.json'), JSON.stringify(config), 'utf-8');
return modelDirectory;
};
describe('whisper', () => {
beforeEach(async () => {
await setupDatabase(0);
});
afterEach(async () => {
const whisperDirectory = dirname(whisper.modelLocalFilepath('en'));
await remove(whisperDirectory);
});
test('should remove legacy models when deleting cached models', async () => {
const whisperDirectory = dirname(whisper.modelLocalFilepath('en'));
const legacyModelPath = join(whisperDirectory, 'whisper_tiny.onnx');
await mkdir(whisperDirectory);
await writeFile(legacyModelPath, 'test', 'utf-8');
await whisper.deleteCachedModels('en');
expect(await exists(legacyModelPath)).toBe(false);
});
test('should apply post-processing replacements specified in the model config', async () => {
const modelDirectory = await createMockModel({
output: {
stringReplacements: [
['Test', 'replaced'],
],
regexReplacements: [
['replace[d]', 'replaced again!'],
],
},
});
let lastFinalizedText = '';
const onFinalize = jest.fn((text: string) => {
lastFinalizedText = text;
// Stop the session after the first data is fetched.
return session.stop();
});
const onPreview = jest.fn();
const session = await whisper.build({
modelPath: modelDirectory,
callbacks: {
onFinalize, onPreview,
},
locale: 'en',
});
await session.start();
// Should have applied string, then regex replacements.
expect(
lastFinalizedText,
).toBe('\n\nreplaced again!. This is test output. replaced again!!');
});
it.each([
{ glossary: '', expectedPrompt: '' },
{ glossary: 'test', expectedPrompt: 'Glossary: test' },
{ glossary: 'Joplin, app', expectedPrompt: 'Glossary: Joplin, app' },
// Should not include the "Glossary:" prefix if there's no translation for it
{ glossary: 'Joplin, app', expectedPrompt: 'Joplin, app', locale: 'testLocale-test' },
])('should construct a prompt from the user-specified glossary (%j)', async ({ glossary, expectedPrompt, locale }) => {
Setting.setValue('voiceTyping.glossary', glossary);
const modelDirectory = await createMockModel();
const session = await whisper.build({
modelPath: modelDirectory,
callbacks: {
onFinalize: () => {
return session.stop();
},
onPreview: jest.fn(),
},
locale: locale ?? 'en',
});
await session.start();
expect(testing__lastPrompt()).toBe(expectedPrompt);
});
});