一些检查失败了
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
135 行
3.7 KiB
TypeScript
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);
|
|
});
|
|
});
|