├── bash ├── handle_response.py ├── spell_checker.sh └── README.md ├── python ├── README.md └── spell_checker.py ├── nodejs ├── package.json ├── LICENSE ├── README.md ├── test │ └── test.js └── index.js ├── README.md └── LICENSE /bash/handle_response.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | 4 | text = sys.argv[1] 5 | response = json.loads(sys.argv[2]) 6 | 7 | if 'flaggedTokens' in response: 8 | for flaggedToken in response['flaggedTokens']: 9 | text = text.replace(flaggedToken['token'], flaggedToken['suggestions'][0]['suggestion']) 10 | 11 | print(text) 12 | -------------------------------------------------------------------------------- /bash/spell_checker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | LANG='en-US' 4 | MODE='proof' 5 | TEXT=$1 6 | 7 | RESPONSE=$(curl -s "https://api.cognitive.microsoft.com/bing/v7.0/spellcheck?mkt=$LANG&mode=$MODE" \ 8 | -H "Content-Type: application/x-www-form-urlencoded" \ 9 | -H "Ocp-Apim-Subscription-Key: $BING_SPELL_CHECK_API_KEY" \ 10 | -X POST \ 11 | -d "text=$TEXT") 12 | 13 | python handle_response.py "$TEXT" "$RESPONSE" 14 | -------------------------------------------------------------------------------- /python/README.md: -------------------------------------------------------------------------------- 1 | Bing Spell Checker 2 | ================== 3 | Python version of spell checker. 4 | 5 | Requirements 6 | ------------ 7 | BING_SPELL_CHECK_API_KEY value must be set as environment value 8 | ``` 9 | $ export BING_SPELL_CHECK_API_KEY='your_key' 10 | ``` 11 | 12 | Usage 13 | ----- 14 | ``` 15 | $ python spell_checker.py 'It workd!' 16 | ``` 17 | 18 | TODO 19 | ---- 20 | - Read other parameters from command line 21 | - Add tests 22 | - Provide a threshold value -------------------------------------------------------------------------------- /bash/README.md: -------------------------------------------------------------------------------- 1 | Bing Spell Checker 2 | ================== 3 | Bash script version of spell checker. 4 | 5 | Requirements 6 | ------------ 7 | curl and python is required. 8 | 9 | BING_SPELL_CHECK_API_KEY value must be set as environment value 10 | ``` 11 | $ export BING_SPELL_CHECK_API_KEY='your_key' 12 | ``` 13 | 14 | Usage 15 | ----- 16 | ``` 17 | $ ./spell_checker.sh 'It workd!' 18 | ``` 19 | 20 | TODO 21 | ---- 22 | - Read other parameters from command line 23 | - Add tests 24 | - Provide a threshold value -------------------------------------------------------------------------------- /nodejs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bing-spell-checker", 3 | "version": "0.1.1", 4 | "description": "Bing Spell Check API connector", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "node test/test.js" 8 | }, 9 | "keywords": [ 10 | "bing", 11 | "spell", 12 | "check", 13 | "api" 14 | ], 15 | "author": "mustafa ilhan ", 16 | "license": "MIT", 17 | "repository": { 18 | "type" : "git", 19 | "url" : "https://github.com/EmakinaTR/bing-spell-checker.git" 20 | }, 21 | "homepage": "https://github.com/EmakinaTR/bing-spell-checker" 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bing Spell Checker 2 | ================== 3 | 4 | This repo provides several implementation of Bing Spell Check Api in different programming languages. Currently, node.js and python version is available, however, different implementations will be available in the future. 5 | 6 | Details of the API is here: [Bing Spell Check](https://azure.microsoft.com/en-us/services/cognitive-services/spell-check/) 7 | 8 | How to use? 9 | ----------- 10 | You need an API access key. You can get it from here: [Bing Spell Check API Access](https://azure.microsoft.com/en-us/try/cognitive-services/#lang) 11 | 12 | TODO 13 | ---- 14 | - ~~Bash~~ 15 | - Java 16 | - Kotlin 17 | - ~~Python~~ -------------------------------------------------------------------------------- /python/spell_checker.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import json 3 | import os 4 | from urllib.request import urlopen, Request 5 | 6 | lang = 'en-US' 7 | mode = 'proof' 8 | text = sys.argv[1] 9 | 10 | settingUrl = 'https://api.cognitive.microsoft.com/bing/v7.0/spellcheck?mkt={}&mode={}'.format(lang, mode) 11 | data = 'text={}'.format(text) 12 | method = 'POST' 13 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Ocp-Apim-Subscription-Key': os.environ['BING_SPELL_CHECK_API_KEY']} 14 | 15 | response = urlopen(Request(settingUrl, data=data.encode('utf-8'), method=method, headers=headers)) 16 | response = json.load(response) 17 | 18 | if 'flaggedTokens' in response: 19 | for flaggedToken in response['flaggedTokens']: 20 | text = text.replace(flaggedToken['token'], flaggedToken['suggestions'][0]['suggestion']) 21 | 22 | print(text) 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Emakina.TR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /nodejs/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2018 Emakina.TR 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /nodejs/README.md: -------------------------------------------------------------------------------- 1 | Bing Spell Checker 2 | ================== 3 | 4 | This node.js module calls Bing's Spell Check API with the provided text. It returns corrected text if API suggests correction. 5 | 6 | Details are here: [Bing Spell Check](https://azure.microsoft.com/en-us/services/cognitive-services/spell-check/) 7 | 8 | Install 9 | ------- 10 | ``` 11 | npm install bing-spell-checker 12 | ``` 13 | 14 | How to use? 15 | ----------- 16 | You need an API access key. You can get it from here: [Bing Spell Check API Access](https://azure.microsoft.com/en-us/try/cognitive-services/#lang) 17 | 18 | > Reading access key through environment variables are a secure way of accessing secret information. Therefore, you should consider setting access key to environment variables. 19 | 20 | ```javascript 21 | 'use strict' 22 | 23 | const BingSpellChecker = require('bing-spell-checker') 24 | 25 | BingSpellChecker.init({ 26 | 'key': process.env.BING_SPELL_CHECK_API_KEY 27 | }) 28 | 29 | let promise = BingSpellChecker.check('It workd!') 30 | promise.then(function (result) { 31 | console.log(result) // "Stuff worked!" 32 | }, function (err) { 33 | console.log(err) // Error: "It broke" 34 | }) 35 | ``` 36 | 37 | TODO 38 | ---- 39 | - Provide a threshold value -------------------------------------------------------------------------------- /nodejs/test/test.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * License: MIT 3 | * Author: Mustafa İlhan 4 | */ 5 | 6 | 'use strict' 7 | 8 | const BingSpellChecker = require('../index.js') 9 | 10 | let scenarios = [ 11 | { 12 | 'testCase': 'empty_key', 13 | 'text': 'Hello', 14 | 'expected': 'Key can not be empty. Please provide a key.', 15 | 'key': '' 16 | }, 17 | { 18 | 'testCase': 'empty_text', 19 | 'text': '', 20 | 'expected': 'Text can not be empty. Please provide a text.', 21 | 'key': process.env.BING_SPELL_CHECK_API_KEY 22 | }, 23 | { 24 | 'testCase': 'wrong_key', 25 | 'text': 'It workd!', 26 | 'expected': 'Access denied due to invalid subscription key. Make sure to provide a valid key for an active subscription.', 27 | 'key': 'asd' 28 | }, 29 | { 30 | 'testCase': 'correct_text', 31 | 'text': 'It workd!', 32 | 'expected': 'It works!', 33 | 'key': process.env.BING_SPELL_CHECK_API_KEY 34 | } 35 | ] 36 | 37 | let passed = [] 38 | let failed = [] 39 | 40 | function sleep (ms) { 41 | return new Promise(resolve => setTimeout(resolve, ms)) 42 | } 43 | 44 | function check (testCase, expected, result) { 45 | if (expected === result) { 46 | passed.push(testCase) 47 | } else { 48 | failed.push(testCase) 49 | console.log('Test case: ' + testCase + ' failed. Expecting: "' + expected + '", returned: "' + result + '"') 50 | } 51 | } 52 | 53 | async function test (testCase, text, expected, key) { 54 | BingSpellChecker.init({ 55 | 'key': key 56 | }) 57 | 58 | let promise = BingSpellChecker.check(text) 59 | await promise.then(function (result) { 60 | check(testCase, expected, result) 61 | }, function (err) { 62 | check(testCase, expected, err.message) 63 | }) 64 | } 65 | 66 | async function runTests () { 67 | for (let i = 0, ii = scenarios.length; i !== ii; i++) { 68 | await test(scenarios[i].testCase, scenarios[i].text, scenarios[i].expected, scenarios[i].key) 69 | // Bing API has a rate limit, therefore we need wait at least 1 second. 70 | await sleep(1000) 71 | } 72 | 73 | if (failed.length === 0) { 74 | console.log('Passed all.') 75 | process.exit() 76 | } else { 77 | console.log('Failed (' + (failed.length) + ') Passed (' + (passed.length) + ').') 78 | process.exit(1) 79 | } 80 | } 81 | 82 | runTests() 83 | -------------------------------------------------------------------------------- /nodejs/index.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * License: MIT 3 | * Author: Mustafa İlhan 4 | */ 5 | 6 | 'use strict' 7 | 8 | const https = require('https') 9 | 10 | let properties = { 11 | 'host': 'api.cognitive.microsoft.com', 12 | 'path': '/bing/v7.0/spellcheck' 13 | } 14 | 15 | function isEmpty (str) { 16 | return !str || str.length === 0 17 | } 18 | 19 | function correctSpellingErrors (text, response) { 20 | if (!isEmpty(response.flaggedTokens)) { 21 | for (let i = 0, ii = response.flaggedTokens.length; i !== ii; i++) { 22 | let flaggedToken = response.flaggedTokens[i] 23 | text = text.replace(flaggedToken['token'], flaggedToken['suggestions'][0]['suggestion']) 24 | } 25 | } 26 | return text 27 | } 28 | 29 | module.exports.init = function (props) { 30 | properties['host'] = props['host'] || properties['host'] 31 | properties['path'] = props['path'] || properties['path'] 32 | properties['key'] = props['key'] || properties['key'] 33 | properties['clientLocation'] = props['clientLocation'] || properties['clientLocation'] 34 | properties['clientId'] = props['clientId'] || properties['clientId'] 35 | properties['clientIp'] = props['clientIp'] || properties['clientIp'] 36 | } 37 | 38 | module.exports.check = function (text, lang = 'en-US', mode = 'proof') { 39 | if (isEmpty(text)) { 40 | return new Promise((resolve, reject) => { 41 | reject(new Error('Text can not be empty. Please provide a text.')) 42 | }) 43 | } 44 | if (isEmpty(properties.key)) { 45 | return new Promise((resolve, reject) => { 46 | reject(new Error('Key can not be empty. Please provide a key.')) 47 | }) 48 | } 49 | 50 | let queryString = '?mkt=' + lang + '&mode=' + mode 51 | let requestParams = { 52 | 'method': 'POST', 53 | 'hostname': properties.host, 54 | 'path': properties.path + queryString, 55 | 'headers': { 56 | 'Content-Type': 'application/x-www-form-urlencoded', 57 | 'Content-Length': text.length + 5, 58 | 'Ocp-Apim-Subscription-Key': properties.key 59 | } 60 | } 61 | 62 | if (!isEmpty(properties['clientLocation'])) { 63 | requestParams['headers']['X-Search-Location'] = properties['clientLocation'] 64 | } 65 | if (!isEmpty(properties['clientId'])) { 66 | requestParams['headers']['X-MSEdge-ClientID'] = properties['clientId'] 67 | } 68 | if (!isEmpty(properties['clientIp'])) { 69 | requestParams['headers']['X-MSEdge-ClientIP'] = properties['clientIp'] 70 | } 71 | 72 | return new Promise((resolve, reject) => { 73 | let req = https.request(requestParams, (response) => { 74 | let body = '' 75 | response.on('data', function (d) { 76 | body += d 77 | }) 78 | response.on('end', function () { 79 | body = JSON.parse(body) 80 | // console.log(body) 81 | if (body['statusCode']) { 82 | reject(new Error(body['message'])) 83 | } else { 84 | resolve(correctSpellingErrors(text, body)) 85 | } 86 | }) 87 | response.on('error', function (e) { 88 | reject(new Error(e.message)) 89 | }) 90 | }) 91 | req.write('text=' + text) 92 | req.end() 93 | }) 94 | } 95 | --------------------------------------------------------------------------------