diff --git a/README.md b/README.md index ab1f7110e4..d8edbb4019 100644 --- a/README.md +++ b/README.md @@ -338,10 +338,12 @@ TODO - [x] Change `context` to `contexts`. - [x] Change `contexts` to `context`.... - - [] Figure out what a `Context` will be + - [x] Figure out what a `Context` will be - [x] Implement hack to make `global` inherit from `self` - [x] Define on `self.registerModel(factory: (c) => Model)` protocol - [x] Describe `contexts` + - [x] Implement loading a model from a file. + - [ ] Document `suggestions` - [ ] make simple `index.html` that demos a dummy model - [ ] make an `error` initialization message. - [ ] TypeScript! diff --git a/index.js b/index.js index d82af000c3..174b7208e5 100644 --- a/index.js +++ b/index.js @@ -21,7 +21,7 @@ class LMLayer { /** * [async] Waits for the model's initialization. */ - initialize(_acceptConfiguration) { + initialize({model, configuration }) { if (this._configuration) { return Promise.resolve(this._configuration); } @@ -30,9 +30,11 @@ class LMLayer { // _onMessage() will resolve this Promise. return new Promise((resolve, _reject) => { this._cast('initialize', { + model, configuration: { maxLeftContextCodeUnits: 32, supportsRightContexts: false, + ...configuration } }); this._resolveInitialized = resolve; diff --git a/lmlayer.js b/lmlayer.js index aa327dc169..04bd2f2307 100644 --- a/lmlayer.js +++ b/lmlayer.js @@ -52,7 +52,7 @@ function onMessageWhenUninitialized(event) { } // Import the model. - let model = loadModel(configuration.path, configuration); + let model = loadModel(event.data.model, configuration); transitionToReadyState(model); // Ready! Send desired configuration. @@ -69,7 +69,7 @@ function transitionToReadyState(model) { * Responds to `predict` messages with a `suggestions` message. */ onMessage = function onMessageWhenReady(event) { - const {message, token} = event.data; + const {message, token, transform, context} = event.data; if (message !== 'predict') { throw new Error('invalid message'); @@ -82,10 +82,9 @@ function transitionToReadyState(model) { return; } - // TODO: rip contexts out of message. - let rawSuggestions = model.predict(); + let rawSuggestions = model.predict(context, transform); - // Sort in-place according to weight. + // Sort in-place according to weight, ascending. rawSuggestions.sort((a, b) => a.weight - b.weight); // Convert the internal suggestion format to the one required by the keyboard. @@ -114,8 +113,8 @@ function cast(message, parameters) { /** * Loads the model from a separate file. */ -function loadModel(_path /* : string */, configuration /* : Configuration */) { - importScripts('./models/en-x-test-derek.js'); +function loadModel(path /* : string */, configuration /* : Configuration */) { + importScripts(path); /** * The model MUST call registerModel() which ultimately defines * createModel() to a function. diff --git a/models/en-x-test-teapot.js b/models/en-x-test-teapot.js new file mode 100644 index 0000000000..a8f9bfac4e --- /dev/null +++ b/models/en-x-test-teapot.js @@ -0,0 +1,33 @@ +/** + * This is a test model that simply returns "teapot" when given the context of + * «I'm a little ». + */ +registerModel(function () { + return { + predict(context, transform) { + return [ + { + transform: { + insert: 'teapot', + deleteLeft: transform.insert.length, + deleteRight: 0, + }, + displayAs: '🍵', + weight: 0.00, + } + ]; + + /* TODO: + if (context.wordsLeft === ["I'm", "a", "little"] && + transform.insert === 't') { + } + + return []; + */ + }, + + configuration: { + } + }; +}); +/*global registerModel*/ diff --git a/test.js b/test.js index c5ad72026f..8a8a18d6fe 100644 --- a/test.js +++ b/test.js @@ -11,7 +11,7 @@ test('It provide context to LMLayer', async t => { const lm = new LMLayer; // Wait for the language model to initialize and declare its configuration. - let configuration = await lm.initialize({ model: 'en-x-derek' }); + let configuration = await lm.initialize({ model: './models/en-x-test-derek.js' }); // The model should as for 32 code units of context to the left of the // cursor. t.is(configuration.leftContextCodeUnits, 32); @@ -46,7 +46,7 @@ test('It should reject when predictions crash', async t => { t.plan(1); const lm = new LMLayer; - await lm.initialize({ model: 'en-x-derek' }); + await lm.initialize({ model: './models/en-x-test-derek.js' }); try { await lm.predict({