feat: add Wit Speech API and tryEnglishSpeechModel option

pull/73/head
dessant 6 years ago
parent f13d1eaace
commit c32a6549eb

@ -39,12 +39,12 @@
"@material/theme": "^0.30.0",
"@material/typography": "^0.28.0",
"audiobuffer-to-wav": "^1.0.0",
"ext-components": "dessant/ext-components#^0.1.5",
"ext-contribute": "dessant/ext-contribute#^0.1.5",
"storage-versions": "dessant/storage-versions#^0.2.3",
"ext-components": "dessant/ext-components#^0.1.6",
"ext-contribute": "dessant/ext-contribute#^0.1.6",
"storage-versions": "dessant/storage-versions#^0.2.4",
"typeface-roboto": "^0.0.54",
"vue": "^2.5.17",
"webextension-polyfill": "^0.3.0"
"webextension-polyfill": "^0.3.1"
},
"devDependencies": {
"@babel/core": "^7.0.0-rc.1",

@ -39,6 +39,16 @@
"description": "Value of the option."
},
"optionValue_speechService_witSpeechApiDemo": {
"message": "Wit Speech API (demo)",
"description": "Value of the option."
},
"optionValue_speechService_witSpeechApi": {
"message": "Wit Speech API",
"description": "Value of the option."
},
"optionTitle_ibmSpeechApiLoc": {
"message": "API location",
"description": "Title of the option."
@ -114,9 +124,300 @@
"description": "Value of the option."
},
"optionSectionTitle_misc": {
"message": "Miscellaneous",
"description": "Title of the options section."
},
"optionTitle_tryEnglishSpeechModel": {
"message": "Retry speech recognition with English model",
"description": "Title of the option."
},
"optionTitle_witSpeechApiLang": {
"message": "API language",
"description": "Title of the option."
},
"optionValue_witSpeechApiLang_afrikaans": {
"message": "Afrikaans",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_arabic": {
"message": "Arabic",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_azerbaijani": {
"message": "Azerbaijani",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_bengali": {
"message": "Bengali",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_bulgarian": {
"message": "Bulgarian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_catalan": {
"message": "Catalan",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_chinese": {
"message": "Chinese",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_croatian": {
"message": "Croatian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_czech": {
"message": "Czech",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_danish": {
"message": "Danish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_dutch": {
"message": "Dutch",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_english": {
"message": "English",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_estonian": {
"message": "Estonian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_finnish": {
"message": "Finnish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_french": {
"message": "French",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_georgian": {
"message": "Georgian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_german": {
"message": "German",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_greek": {
"message": "Greek",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_hebrew": {
"message": "Hebrew",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_hindi": {
"message": "Hindi",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_hungarian": {
"message": "Hungarian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_icelandic": {
"message": "Icelandic",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_indonesian": {
"message": "Indonesian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_italian": {
"message": "Italian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_japanese": {
"message": "Japanese",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_kannada": {
"message": "Kannada",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_korean": {
"message": "Korean",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_laothian": {
"message": "Laothian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_latvian": {
"message": "Latvian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_lithuanian": {
"message": "Lithuanian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_malay": {
"message": "Malay",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_mongolian": {
"message": "Mongolian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_norwegian": {
"message": "Norwegian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_persian": {
"message": "Persian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_polish": {
"message": "Polish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_portuguese": {
"message": "Portuguese",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_romanian": {
"message": "Romanian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_russian": {
"message": "Russian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_serbian": {
"message": "Serbian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_slovak": {
"message": "Slovak",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_slovenian": {
"message": "Slovenian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_spanish": {
"message": "Spanish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_swahili": {
"message": "Swahili",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_swedish": {
"message": "Swedish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_tamil": {
"message": "Tamil",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_telugu": {
"message": "Telugu",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_thai": {
"message": "Thai",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_turkish": {
"message": "Turkish",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_ukrainian": {
"message": "Ukrainian",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_urdu": {
"message": "Urdu",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_vietnamese": {
"message": "Vietnamese",
"description": "Value of the option."
},
"optionValue_witSpeechApiLang_zulu": {
"message": "Zulu",
"description": "Value of the option."
},
"inputLabel_apiKey": {
"message": "API key",
"description": "Placeholder of the input."
"description": "Label of the input."
},
"inputLabel_apiKeyType": {
"message": "API key: $TYPE$",
"description": "Label of the input.",
"placeholders": {
"type": {
"content": "$1",
"example": "English"
}
}
},
"buttonText_addApi": {
"message": "Add API",
"description": "Text of the button."
},
"buttonText_solve": {

@ -11,12 +11,14 @@
:options="selectOptions.speechService">
</v-select>
</div>
<div class="option text-field"
v-if="options.speechService === 'googleSpeechApi'">
<v-textfield v-model="options.googleSpeechApiKey"
<v-textfield v-model.trim="options.googleSpeechApiKey"
:label="getText('inputLabel_apiKey')">
</v-textfield>
</div>
<div class="option select"
v-if="options.speechService === 'ibmSpeechApi'">
<v-select :label="getText('optionTitle_ibmSpeechApiLoc')"
@ -26,10 +28,11 @@
</div>
<div class="option text-field"
v-if="options.speechService === 'ibmSpeechApi'">
<v-textfield v-model="options.ibmSpeechApiKey"
<v-textfield v-model.trim="options.ibmSpeechApiKey"
:label="getText('inputLabel_apiKey')">
</v-textfield>
</div>
<div class="option select"
v-if="options.speechService === 'microsoftSpeechApi'">
<v-select :label="getText('optionTitle_microsoftSpeechApiLoc')"
@ -39,10 +42,48 @@
</div>
<div class="option text-field"
v-if="options.speechService === 'microsoftSpeechApi'">
<v-textfield v-model="options.microsoftSpeechApiKey"
<v-textfield v-model.trim="options.microsoftSpeechApiKey"
:label="getText('inputLabel_apiKey')">
</v-textfield>
</div>
<v-textfield
v-if="options.speechService === 'witSpeechApi'"
v-for="item in witSpeechApis"
:key="item.id"
:value="options.witSpeechApiKeys[item] || ''"
:label="getText('inputLabel_apiKeyType',
[getText(`optionValue_witSpeechApiLang_${item}`)])"
@input="saveWitSpeechApiKey($event.trim(), item)">
</v-textfield>
<div class="wit-add-api"
v-if="options.speechService === 'witSpeechApi'">
<v-select
v-model="witSpeechApiLang"
:options="selectOptions.witSpeechApiLang"
:label="getText('optionTitle_witSpeechApiLang')">
</v-select>
<v-button
:stroked="true"
:disabled="!witSpeechApiLang"
@click="addWitSpeechApi">
{{ getText('buttonText_addApi') }}
</v-button>
</div>
</div>
</div>
<div class="section">
<div class="section-title" v-once>
{{ getText('optionSectionTitle_misc') }}
</div>
<div class="option-wrap">
<div class="option">
<v-form-field input-id="esm"
:label="getText('optionTitle_tryEnglishSpeechModel')">
<v-switch id="esm" v-model="options.tryEnglishSpeechModel"></v-switch>
</v-form-field>
</div>
</div>
</div>
</div>
@ -50,16 +91,19 @@
<script>
import browser from 'webextension-polyfill';
import {Select, TextField} from 'ext-components';
import {Button, Select, Switch, FormField, TextField} from 'ext-components';
import storage from 'storage/storage';
import {getOptionLabels} from 'utils/app';
import {getText} from 'utils/common';
import {optionKeys} from 'utils/data';
import {optionKeys, captchaWitSpeechApiLangCodes} from 'utils/data';
export default {
components: {
[Button.name]: Button,
[Select.name]: Select,
[Switch.name]: Switch,
[FormField.name]: FormField,
[TextField.name]: TextField
},
@ -70,7 +114,9 @@ export default {
selectOptions: getOptionLabels({
speechService: [
'googleSpeechApiDemo',
'witSpeechApiDemo',
'googleSpeechApi',
'witSpeechApi',
'ibmSpeechApi',
'microsoftSpeechApi'
],
@ -90,22 +136,56 @@ export default {
'southeastAsia',
'westEu',
'northEu'
]
],
witSpeechApiLang: [
...new Set(
Object.values(captchaWitSpeechApiLangCodes).filter(Boolean)
)
].sort()
}),
witSpeechApiLang: '',
witSpeechApis: [],
options: {
speechService: '',
googleSpeechApiKey: '',
ibmSpeechApiLoc: '',
ibmSpeechApiKey: '',
microsoftSpeechApiLoc: '',
microsoftSpeechApiKey: ''
microsoftSpeechApiKey: '',
witSpeechApiKeys: {},
tryEnglishSpeechModel: false
}
};
},
methods: {
getText
getText,
setWitSpeechApiLangOptions: function() {
this.selectOptions.witSpeechApiLang = this.selectOptions.witSpeechApiLang.filter(
item => !this.witSpeechApis.includes(item.id)
);
},
addWitSpeechApi: function() {
this.witSpeechApis.push(this.witSpeechApiLang);
this.witSpeechApiLang = '';
this.setWitSpeechApiLangOptions();
},
saveWitSpeechApiKey: function(value, lang) {
const apiKeys = this.options.witSpeechApiKeys;
if (value) {
this.options.witSpeechApiKeys = Object.assign({}, apiKeys, {
[lang]: value
});
} else if (apiKeys[lang]) {
delete apiKeys[lang];
this.options.witSpeechApiKeys = Object.assign({}, apiKeys);
}
}
},
created: async function() {
@ -114,13 +194,13 @@ export default {
for (const option of Object.keys(this.options)) {
this.options[option] = options[option];
this.$watch(`options.${option}`, async function(value) {
if (['googleSpeechApiKey', 'ibmSpeechApiKey'].includes(option)) {
value = value.trim();
}
await storage.set({[option]: value}, 'sync');
});
}
this.witSpeechApis = Object.keys(options.witSpeechApiKeys);
this.setWitSpeechApiLangOptions();
document.title = getText('pageTitle', [
getText('pageTitle_options'),
getText('extensionName')
@ -145,7 +225,7 @@ body {
}
.mdc-select__menu {
top: inherit !important;
top: 0 !important;
left: inherit !important;
}
@ -190,4 +270,15 @@ body {
.option.text-field {
height: 56px;
}
.wit-add-api {
display: flex;
align-items: center;
height: 56px;
}
.wit-add-api > button {
align-self: end;
margin-left: 36px;
}
</style>

@ -7,9 +7,11 @@ import {
captchaGoogleSpeechApiLangCodes,
captchaIbmSpeechApiLangCodes,
captchaMicrosoftSpeechApiLangCodes,
captchaWitSpeechApiLangCodes,
ibmSpeechApiUrls,
microsoftSpeechApiUrls
} from 'utils/data';
import {witApiKeys} from 'utils/config';
let solverWorking = false;
@ -79,8 +81,8 @@ async function prepareAudio(audio) {
const source = offlineCtx.createBufferSource();
source.buffer = data;
source.connect(offlineCtx.destination);
// discard 1 second noise from beginning/end
source.start(0, 1, data.duration - 2);
// discard 1.5 second noise from beginning/end
source.start(0, 1.5, data.duration - 3);
return audioBufferToWav(await offlineCtx.startRendering());
}
@ -103,6 +105,91 @@ function dispatchEnter(node) {
node.click();
}
async function getWitSpeechApiKey(speechService, language) {
if (speechService === 'witSpeechApiDemo') {
return witApiKeys[language];
} else {
const {witSpeechApiKeys: apiKeys} = await storage.get(
'witSpeechApiKeys',
'sync'
);
return apiKeys[language];
}
}
async function getWitSpeechApiResult(apiKey, audioContent) {
const rsp = await fetch('https://api.wit.ai/speech', {
referrer: '',
mode: 'cors',
method: 'POST',
headers: {
Authorization: 'Bearer ' + apiKey
},
body: new Blob([audioContent], {type: 'audio/wav'})
});
if (rsp.status !== 200) {
throw new Error(`API response: ${rsp.status}, ${await rsp.text()}`);
}
return (await rsp.json())._text.trim();
}
async function getIbmSpeechApiResult(apiUrl, apiKey, audioContent, language) {
const rsp = await fetch(
`${apiUrl}?model=${language}&profanity_filter=false`,
{
referrer: '',
mode: 'cors',
method: 'POST',
headers: {
Authorization: 'Basic ' + window.btoa('apiKey:' + apiKey),
'X-Watson-Learning-Opt-Out': 'true'
},
body: new Blob([audioContent], {type: 'audio/wav'})
}
);
if (rsp.status !== 200) {
throw new Error(`API response: ${rsp.status}, ${await rsp.text()}`);
}
const results = (await rsp.json()).results;
if (results && results.length) {
return results[0].alternatives[0].transcript.trim();
}
}
async function getMicrosoftSpeechApiResult(
apiUrl,
apiKey,
audioContent,
language
) {
const rsp = await fetch(
`${apiUrl}?language=${language}&format=detailed&profanity=raw`,
{
referrer: '',
mode: 'cors',
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': apiKey,
'Content-type': 'audio/wav; codec=audio/pcm; samplerate=16000'
},
body: new Blob([audioContent], {type: 'audio/wav'})
}
);
if (rsp.status !== 200) {
throw new Error(`API response: ${rsp.status}, ${await rsp.text()}`);
}
const results = (await rsp.json()).NBest;
if (results) {
return results[0].Lexical.trim();
}
}
async function solve() {
let audioUrl;
let solution;
@ -139,9 +226,38 @@ async function solve() {
const audioRsp = await fetch(audioUrl, {referrer: ''});
const audioContent = await prepareAudio(await audioRsp.arrayBuffer());
const {speechService} = await storage.get('speechService', 'sync');
const {speechService, tryEnglishSpeechModel} = await storage.get(
['speechService', 'tryEnglishSpeechModel'],
'sync'
);
if (['witSpeechApiDemo', 'witSpeechApi'].includes(speechService)) {
const language = captchaWitSpeechApiLangCodes[lang] || 'english';
if (['googleSpeechApiDemo', 'googleSpeechApi'].includes(speechService)) {
const apiKey = await getWitSpeechApiKey(speechService, language);
if (!apiKey) {
browser.runtime.sendMessage({
id: 'notification',
messageId: 'error_missingApiKey'
});
return;
}
solution = await getWitSpeechApiResult(apiKey, audioContent);
if (!solution && language !== 'english' && tryEnglishSpeechModel) {
const apiKey = await getWitSpeechApiKey(speechService, 'english');
if (!apiKey) {
browser.runtime.sendMessage({
id: 'notification',
messageId: 'error_missingApiKey'
});
return;
}
solution = await getWitSpeechApiResult(apiKey, audioContent);
}
} else if (
['googleSpeechApiDemo', 'googleSpeechApi'].includes(speechService)
) {
let apiUrl;
if (speechService === 'googleSpeechApiDemo') {
apiUrl =
@ -173,7 +289,7 @@ async function solve() {
sampleRateHertz: 16000
}
};
if (!['en-US', 'en-GB'].includes(language)) {
if (!['en-US', 'en-GB'].includes(language) && tryEnglishSpeechModel) {
data.config.alternativeLanguageCodes = ['en-US'];
}
@ -205,25 +321,26 @@ async function solve() {
return;
}
const apiUrl = ibmSpeechApiUrls[apiLoc];
const model = captchaIbmSpeechApiLangCodes[lang] || 'en-US_BroadbandModel';
const rsp = await fetch(`${apiUrl}?model=${model}&profanity_filter=false`, {
referrer: '',
mode: 'cors',
method: 'POST',
headers: {
Authorization: 'Basic ' + window.btoa('apiKey:' + apiKey)
},
body: new Blob([audioContent], {type: 'audio/wav'})
});
if (rsp.status !== 200) {
throw new Error(`API response: ${rsp.status}, ${await rsp.text()}`);
}
const results = (await rsp.json()).results;
if (results && results.length) {
solution = results[0].alternatives[0].transcript.trim();
const language =
captchaIbmSpeechApiLangCodes[lang] || 'en-US_BroadbandModel';
solution = await getIbmSpeechApiResult(
apiUrl,
apiKey,
audioContent,
language
);
if (
!solution &&
!['en-US_BroadbandModel', 'en-GB_BroadbandModel'].includes(language) &&
tryEnglishSpeechModel
) {
solution = await getIbmSpeechApiResult(
apiUrl,
apiKey,
audioContent,
'en-US_BroadbandModel'
);
}
} else if (speechService === 'microsoftSpeechApi') {
const {
@ -243,27 +360,23 @@ async function solve() {
const apiUrl = microsoftSpeechApiUrls[apiLoc];
const language = captchaMicrosoftSpeechApiLangCodes[lang] || 'en-US';
const rsp = await fetch(
`${apiUrl}?language=${language}&format=detailed&profanity=raw`,
{
referrer: '',
mode: 'cors',
method: 'POST',
headers: {
'Ocp-Apim-Subscription-Key': apiKey,
'Content-type': 'audio/wav; codec=audio/pcm; samplerate=16000'
},
body: new Blob([audioContent], {type: 'audio/wav'})
}
solution = await getMicrosoftSpeechApiResult(
apiUrl,
apiKey,
audioContent,
language
);
if (rsp.status !== 200) {
throw new Error(`API response: ${rsp.status}, ${await rsp.text()}`);
}
const results = (await rsp.json()).NBest;
if (results) {
solution = results[0].Lexical.trim();
if (
!solution &&
!['en-US', 'en-GB'].includes(language) &&
tryEnglishSpeechModel
) {
solution = await getMicrosoftSpeechApiResult(
apiUrl,
apiKey,
audioContent,
'en-US'
);
}
}

@ -9,7 +9,7 @@ const storage = browser.storage.local;
async function upgrade() {
const changes = {
speechService: 'googleSpeechApiDemo', // 'googleSpeechApiDemo', 'googleSpeechApi', 'ibmSpeechApi', 'microsoftSpeechApi'
speechService: 'googleSpeechApiDemo', // 'googleSpeechApiDemo', 'witSpeechApiDemo', 'googleSpeechApi', 'witSpeechApi', 'ibmSpeechApi', 'microsoftSpeechApi'
googleSpeechApiKey: '',
installTime: new Date().getTime(),
useCount: 0

@ -0,0 +1,28 @@
import browser from 'webextension-polyfill';
const message = 'Add Wit Speech API and tryEnglishSpeechModel option';
const revision = 'nOedd0Txqd';
const downRevision = 'UidMDYaYA';
const storage = browser.storage.local;
async function upgrade() {
const changes = {
witSpeechApiKeys: {},
tryEnglishSpeechModel: true
};
changes.storageVersion = revision;
return storage.set(changes);
}
async function downgrade() {
const changes = {};
await storage.remove(['witSpeechApiKeys', 'tryEnglishSpeechModel']);
changes.storageVersion = downRevision;
return storage.set(changes);
}
export {message, revision, upgrade, downgrade};

@ -1 +1 @@
{"versions": ["UoT3kGyBH", "ONiJBs00o", "UidMDYaYA"]}
{"versions": ["UoT3kGyBH", "ONiJBs00o", "UidMDYaYA", "nOedd0Txqd"]}

@ -9,7 +9,7 @@ const storage = browser.storage.sync;
async function upgrade() {
const changes = {
speechService: 'googleSpeechApiDemo', // 'googleSpeechApiDemo', 'googleSpeechApi', 'ibmSpeechApi', 'microsoftSpeechApi'
speechService: 'googleSpeechApiDemo', // 'googleSpeechApiDemo', 'witSpeechApiDemo', 'googleSpeechApi', 'witSpeechApi', 'ibmSpeechApi', 'microsoftSpeechApi'
googleSpeechApiKey: '',
installTime: new Date().getTime(),
useCount: 0

@ -0,0 +1,28 @@
import browser from 'webextension-polyfill';
const message = 'Add Wit Speech API and tryEnglishSpeechModel option';
const revision = 'nOedd0Txqd';
const downRevision = 'UidMDYaYA';
const storage = browser.storage.sync;
async function upgrade() {
const changes = {
witSpeechApiKeys: {},
tryEnglishSpeechModel: true
};
changes.storageVersion = revision;
return storage.set(changes);
}
async function downgrade() {
const changes = {};
await storage.remove(['witSpeechApiKeys', 'tryEnglishSpeechModel']);
changes.storageVersion = downRevision;
return storage.set(changes);
}
export {message, revision, upgrade, downgrade};

@ -1 +1 @@
{"versions": ["UoT3kGyBH", "ONiJBs00o", "UidMDYaYA"]}
{"versions": ["UoT3kGyBH", "ONiJBs00o", "UidMDYaYA", "nOedd0Txqd"]}

@ -1,3 +1,58 @@
const targetEnv = process.env.TARGET_ENV;
export {targetEnv};
const witApiKeys = {
afrikaans: 'T3T7A2WS3TQJVBB4L4CTK2EEUI6N7YGZ',
arabic: 'AD6RLFYBWRGGJD76SWKALZMUFVGMVCTB',
azerbaijani: 'RMSJ2FEOW4KJDYRF5LNZBIWBRZDW4ZB7',
bengali: 'ACETQ4IVS5ITSUTSWBETY2QZKBJVIQAI',
bulgarian: 'PILJVNIC5Y2EBHB5LFBCFCVRMJB6YAHT',
catalan: 'YBAZZV6ITGFD3C2QX7CANYQPMGUOI7RK',
chinese: 'KBBALJMRKYDJJDMC4NJ32VWCBKFJFIIU',
croatian: 'WNMTNHQVRCIO7LWM3KJ7KSMELXJ7LVHI',
czech: 'LRLFTX2Q66Y6YQX2RA6SN2ULGJJ4ABHY',
danish: 'XNXWQBMCXS4CPGD5XS6J6CSIPG2NLMIO',
dutch: 'T43TEUNW4HDQFNUTIA3EYTTD4A22AS4H',
english: 'NVYD6ZUJMC26US5XS2ZJJ32EDZZ654TD',
estonian: 'BFR5DZRBITRYUPEUAEC5NBAYH32TZWFW',
finnish: '3GOWLMYD7DUY72XTPJW6QTVZSK2QEAPT',
french: 'JLNITTO2D4KMEOGQ6MTSN634ADK62VZ7',
georgian: 'MN4WRTLFDM2AESM6HXUF2KXQACTNC2CJ',
german: 'LPVVXWRBFTVBOOHZAEJC3QRM6E3UMD7I',
greek: 'VRQCDIURC3D22ZTYPEJAHGZW2PG5MY5T',
hebrew: 'IFNGQOZ63NDYAXHMJTOFGDWUFXTU3XZH',
hindi: 'GZY4V5WN75QHO4Q5PMCU5AIDKQZLKP4L',
hungarian: 'U22W2AWXWQHWUUGTJRJZYAMYSSPX44TR',
icelandic: 'KD3DQ2XPQJM4VBYUJPPOPHZYOUQZ55JL',
indonesian: 'NBKNPYO6ZTVSSTH2AT3H5DM7OUOIAN3F',
italian: 'JNSYW453QWIXNR3TOCE2K7NO5GGU3KYL',
japanese: 'S3IDY5JTJVJ6XBISPGZBZQHQXO23BXEB',
kannada: 'MZ7NKAQGQI3T4JH6YRIEL6K4AWDCDE3A',
korean: '5UWNE4YDBZTSNWWBYC4XZEWJGBUI24YL',
laothian: 'GEM2VG7WS7NIWWYCVUKKW6T2BZDND4J2',
latvian: 'FZ7HMEZDHUTGCA77BGYHRGJ3ENK3H6HD',
lithuanian: 'ZDSKNPEMQJMVPX3AFIKGGT2CGZG3SLDW',
malay: 'YW73R7QWXQT23GE5CTM4R2IVNCH2KMS3',
mongolian: '73LDBOC5T55YLADCESZUHS2CI447UMWE',
norwegian: 'TOXJSFSKC7EQAJRMYXOQMMZ5FEYT5ZCF',
persian: 'OQS2XU2VPTCHUNNOGLWAGGVNP4LIFXZI',
polish: 'G73FWND7N5O3ZCSBCHF6NDOV2QIXW2MF',
portuguese: 'N7D57ZCGWLRSMQNHQYKWC3OHVNTZI5UT',
romanian: '4Q4AMYQP43UCUV2RJOT4TRAONA6JYSMD',
russian: 'V2IMQUEC5M7TSYAY3VCKSGQ7HOCWFPFY',
serbian: 'ZQEVSPDJ7TV4GJSTO3EV4JOFQGF2AJYI',
slovak: 'SCXIEULQSWCFQNBCOF7ERG6EHRKYV4SL',
slovenian: 'UKZACHY2BVGVHWZGCWDDB5LQ2WBKZ5XL',
spanish: 'JU6JOEJBHRH7IILGSSUVEYO552JUNMG4',
swahili: 'JDXM4LB6AXQNCURNTZ5RT2U5I2CBXLBT',
swedish: '33RMFTS5OKLEWV2KGX2HMTP7M3VCKXC4',
tamil: 'MNIEHY7BQVMEU6BBJBL57E4QYNHOUIDB',
telugu: 'MXE6BFOLRMR72GLUFEK3Y7NOUBPV5W4G',
thai: 'MA3JUGAZNCCTBBTO2K7HR3RWJ3LILU6E',
turkish: 'HZJRJNL3C3KLBXZQ4BPIODYRKXXRKYCL',
ukrainian: 'OW43DTZJ432PEORIXR72R35V4H6SUUU3',
urdu: 'T5FSZMLJ55LNPBIILM2A2SVEA3YIIYL3',
vietnamese: 'ULJN5SUWA3HJKLPKHOSTOH5AJSSWN5H3',
zulu: 'B6OMGRZUYIJ5WLDQZODKCFCXCTH7PHB3'
};
export {targetEnv, witApiKeys};

@ -1,141 +1,308 @@
import browser from 'webextension-polyfill';
const optionKeys = [
'speechService',
'googleSpeechApiKey',
'ibmSpeechApiLoc',
'ibmSpeechApiKey',
'microsoftSpeechApiLoc',
'microsoftSpeechApiKey'
'microsoftSpeechApiKey',
'witSpeechApiKeys',
'tryEnglishSpeechModel'
];
// https://developers.google.com/recaptcha/docs/language
// https://cloud.google.com/speech-to-text/docs/languages
const captchaGoogleSpeechApiLangCodes = {
ar: 'ar-SA',
af: 'af-ZA',
am: 'am-ET',
hy: 'hy-AM',
az: 'az-AZ',
eu: 'eu-ES',
bn: 'bn-BD',
bg: 'bg-BG',
ca: 'ca-ES',
'zh-HK': 'cmn-Hans-HK',
'zh-CN': 'cmn-Hans-CN',
'zh-TW': 'cmn-Hant-TW',
hr: 'hr-HR',
cs: 'cs-CZ',
da: 'da-DK',
nl: 'nl-NL',
'en-GB': 'en-GB',
en: 'en-US',
et: '',
fil: 'fil-PH',
fi: 'fi-FI',
fr: 'fr-FR',
'fr-CA': 'fr-CA',
gl: 'gl-ES',
ka: 'ka-GE',
de: 'de-DE',
'de-AT': 'de-DE',
'de-CH': 'de-DE',
el: 'el-GR',
gu: 'gu-IN',
iw: 'he-IL',
hi: 'hi-IN',
hu: 'hu-HU',
is: 'is-IS',
id: 'id-ID',
it: 'it-IT',
ja: 'ja-JP',
kn: 'kn-IN',
ko: 'ko-KR',
lo: 'lo-LA',
lv: 'lv-LV',
lt: 'lt-LT',
ms: 'ms-MY',
ml: 'ml-IN',
mr: 'mr-IN',
mn: '',
no: 'nb-NO',
fa: 'fa-IR',
pl: 'pl-PL',
pt: 'pt-PT',
'pt-BR': 'pt-BR',
'pt-PT': 'pt-PT',
ro: 'ro-RO',
ru: 'ru-RU',
sr: 'sr-RS',
si: 'si-LK',
sk: 'sk-SK',
sl: 'sl-SI',
es: 'es-ES',
'es-419': 'es-MX',
sw: 'sw-TZ',
sv: 'sv-SE',
ta: 'ta-IN',
te: 'te-IN',
th: 'th-TH',
tr: 'tr-TR',
uk: 'uk-UA',
ur: 'ur-IN',
vi: 'vi-VN',
zu: 'zu-ZA'
ar: 'ar-SA', // Arabic
af: 'af-ZA', // Afrikaans
am: 'am-ET', // Amharic
hy: 'hy-AM', // Armenian
az: 'az-AZ', // Azerbaijani
eu: 'eu-ES', // Basque
bn: 'bn-BD', // Bengali
bg: 'bg-BG', // Bulgarian
ca: 'ca-ES', // Catalan
'zh-HK': 'cmn-Hans-HK', // Chinese (Hong Kong)
'zh-CN': 'cmn-Hans-CN', // Chinese (Simplified)
'zh-TW': 'cmn-Hant-TW', // Chinese (Traditional)
hr: 'hr-HR', // Croatian
cs: 'cs-CZ', // Czech
da: 'da-DK', // Danish
nl: 'nl-NL', // Dutch
'en-GB': 'en-GB', // English (UK)
en: 'en-US', // English (US)
et: '', // Estonian
fil: 'fil-PH', // Filipino
fi: 'fi-FI', // Finnish
fr: 'fr-FR', // French
'fr-CA': 'fr-CA', // French (Canadian)
gl: 'gl-ES', // Galician
ka: 'ka-GE', // Georgian
de: 'de-DE', // German
'de-AT': 'de-DE', // German (Austria)
'de-CH': 'de-DE', // German (Switzerland)
el: 'el-GR', // Greek
gu: 'gu-IN', // Gujarati
iw: 'he-IL', // Hebrew
hi: 'hi-IN', // Hindi
hu: 'hu-HU', // Hungarian
is: 'is-IS', // Icelandic
id: 'id-ID', // Indonesian
it: 'it-IT', // Italian
ja: 'ja-JP', // Japanese
kn: 'kn-IN', // Kannada
ko: 'ko-KR', // Korean
lo: 'lo-LA', // Laothian
lv: 'lv-LV', // Latvian
lt: 'lt-LT', // Lithuanian
ms: 'ms-MY', // Malay
ml: 'ml-IN', // Malayalam
mr: 'mr-IN', // Marathi
mn: '', // Mongolian
no: 'nb-NO', // Norwegian
fa: 'fa-IR', // Persian
pl: 'pl-PL', // Polish
pt: 'pt-PT', // Portuguese
'pt-BR': 'pt-BR', // Portuguese (Brazil)
'pt-PT': 'pt-PT', // Portuguese (Portugal)
ro: 'ro-RO', // Romanian
ru: 'ru-RU', // Russian
sr: 'sr-RS', // Serbian
si: 'si-LK', // Sinhalese
sk: 'sk-SK', // Slovak
sl: 'sl-SI', // Slovenian
es: 'es-ES', // Spanish
'es-419': 'es-MX', // Spanish (Latin America)
sw: 'sw-TZ', // Swahili
sv: 'sv-SE', // Swedish
ta: 'ta-IN', // Tamil
te: 'te-IN', // Telugu
th: 'th-TH', // Thai
tr: 'tr-TR', // Turkish
uk: 'uk-UA', // Ukrainian
ur: 'ur-IN', // Urdu
vi: 'vi-VN', // Vietnamese
zu: 'zu-ZA' // Zulu
};
// https://cloud.ibm.com/apidocs/speech-to-text#recognize-audio
const captchaIbmSpeechApiLangCodes = {
ar: 'ar-AR_BroadbandModel',
'zh-CN': 'zh-CN_BroadbandModel',
'zh-TW': 'zh-CN_BroadbandModel',
'en-GB': 'en-GB_BroadbandModel',
en: 'en-US_BroadbandModel',
fr: 'fr-FR_BroadbandModel',
'fr-CA': 'fr-FR_BroadbandModel',
de: 'de-DE_BroadbandModel',
'de-AT': 'de-DE_BroadbandModel',
'de-CH': 'de-DE_BroadbandModel',
ja: 'ja-JP_BroadbandModel',
ko: 'ko-KR_BroadbandModel',
pt: 'pt-BR_BroadbandModel',
'pt-BR': 'pt-BR_BroadbandModel',
'pt-PT': 'pt-BR_BroadbandModel',
es: 'es-ES_BroadbandModel',
'es-419': 'es-ES_BroadbandModel'
ar: 'ar-AR_BroadbandModel', // Arabic
af: '', // Afrikaans
am: '', // Amharic
hy: '', // Armenian
az: '', // Azerbaijani
eu: '', // Basque
bn: '', // Bengali
bg: '', // Bulgarian
ca: '', // Catalan
'zh-HK': '', // Chinese (Hong Kong)
'zh-CN': 'zh-CN_BroadbandModel', // Chinese (Simplified)
'zh-TW': 'zh-CN_BroadbandModel', // Chinese (Traditional)
hr: '', // Croatian
cs: '', // Czech
da: '', // Danish
nl: '', // Dutch
'en-GB': 'en-GB_BroadbandModel', // English (UK)
en: 'en-US_BroadbandModel', // English (US)
et: '', // Estonian
fil: '', // Filipino
fi: '', // Finnish
fr: 'fr-FR_BroadbandModel', // French
'fr-CA': 'fr-FR_BroadbandModel', // French (Canadian)
gl: '', // Galician
ka: '', // Georgian
de: 'de-DE_BroadbandModel', // German
'de-AT': 'de-DE_BroadbandModel', // German (Austria)
'de-CH': 'de-DE_BroadbandModel', // German (Switzerland)
el: '', // Greek
gu: '', // Gujarati
iw: '', // Hebrew
hi: '', // Hindi
hu: '', // Hungarian
is: '', // Icelandic
id: '', // Indonesian
it: '', // Italian
ja: 'ja-JP_BroadbandModel', // Japanese
kn: '', // Kannada
ko: 'ko-KR_BroadbandModel', // Korean
lo: '', // Laothian
lv: '', // Latvian
lt: '', // Lithuanian
ms: '', // Malay
ml: '', // Malayalam
mr: '', // Marathi
mn: '', // Mongolian
no: '', // Norwegian
fa: '', // Persian
pl: '', // Polish
pt: 'pt-BR_BroadbandModel', // Portuguese
'pt-BR': 'pt-BR_BroadbandModel', // Portuguese (Brazil)
'pt-PT': 'pt-BR_BroadbandModel', // Portuguese (Portugal)
ro: '', // Romanian
ru: '', // Russian
sr: '', // Serbian
si: '', // Sinhalese
sk: '', // Slovak
sl: '', // Slovenian
es: 'es-ES_BroadbandModel', // Spanish
'es-419': 'es-ES_BroadbandModel', // Spanish (Latin America)
sw: '', // Swahili
sv: '', // Swedish
ta: '', // Tamil
te: '', // Telugu
th: '', // Thai
tr: '', // Turkish
uk: '', // Ukrainian
ur: '', // Urdu
vi: '', // Vietnamese
zu: '' // Zulu
};
// https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/language-support#speech-to-text
const captchaMicrosoftSpeechApiLangCodes = {
ar: 'ar-EG',
ca: 'ca-ES',
'zh-HK': 'zh-HK',
'zh-CN': 'zh-CN',
'zh-TW': 'zh-TW',
da: 'da-DK',
nl: 'nl-NL',
'en-GB': 'en-GB',
en: 'en-US',
fi: 'fi-FI',
fr: 'fr-FR',
'fr-CA': 'fr-CA',
de: 'de-DE',
'de-AT': 'de-DE',
'de-CH': 'de-DE',
hi: 'hi-IN',
it: 'it-IT',
ja: 'ja-JP',
ko: 'ko-KR',
no: 'nb-NO',
pl: 'pl-PL',
pt: 'pt-PT',
'pt-BR': 'pt-BR',
'pt-PT': 'pt-PT',
ru: 'ru-RU',
es: 'es-ES',
'es-419': 'es-MX',
sv: 'sv-SE',
th: 'th-TH'
ar: 'ar-EG', // Arabic
af: '', // Afrikaans
am: '', // Amharic
hy: '', // Armenian
az: '', // Azerbaijani
eu: '', // Basque
bn: '', // Bengali
bg: '', // Bulgarian
ca: 'ca-ES', // Catalan
'zh-HK': 'zh-HK', // Chinese (Hong Kong)
'zh-CN': 'zh-CN', // Chinese (Simplified)
'zh-TW': 'zh-TW', // Chinese (Traditional)
hr: '', // Croatian
cs: '', // Czech
da: 'da-DK', // Danish
nl: 'nl-NL', // Dutch
'en-GB': 'en-GB', // English (UK)
en: 'en-US', // English (US)
et: '', // Estonian
fil: '', // Filipino
fi: 'fi-FI', // Finnish
fr: 'fr-FR', // French
'fr-CA': 'fr-CA', // French (Canadian)
gl: '', // Galician
ka: '', // Georgian
de: 'de-DE', // German
'de-AT': 'de-DE', // German (Austria)
'de-CH': 'de-DE', // German (Switzerland)
el: '', // Greek
gu: '', // Gujarati
iw: '', // Hebrew
hi: 'hi-IN', // Hindi
hu: '', // Hungarian
is: '', // Icelandic
id: '', // Indonesian
it: 'it-IT', // Italian
ja: 'ja-JP', // Japanese
kn: '', // Kannada
ko: 'ko-KR', // Korean
lo: '', // Laothian
lv: '', // Latvian
lt: '', // Lithuanian
ms: '', // Malay
ml: '', // Malayalam
mr: '', // Marathi
mn: '', // Mongolian
no: 'nb-NO', // Norwegian
fa: '', // Persian
pl: 'pl-PL', // Polish
pt: 'pt-PT', // Portuguese
'pt-BR': 'pt-BR', // Portuguese (Brazil)
'pt-PT': 'pt-PT', // Portuguese (Portugal)
ro: '', // Romanian
ru: 'ru-RU', // Russian
sr: '', // Serbian
si: '', // Sinhalese
sk: '', // Slovak
sl: '', // Slovenian
es: 'es-ES', // Spanish
'es-419': 'es-MX', // Spanish (Latin America)
sw: '', // Swahili
sv: 'sv-SE', // Swedish
ta: '', // Tamil
te: '', // Telugu
th: 'th-TH', // Thai
tr: '', // Turkish
uk: '', // Ukrainian
ur: '', // Urdu
vi: '', // Vietnamese
zu: '' // Zulu
};
const captchaWitSpeechApiLangCodes = {
ar: 'arabic', // Arabic
af: 'afrikaans', // Afrikaans
am: '', // Amharic
hy: '', // Armenian
az: 'azerbaijani', // Azerbaijani
eu: '', // Basque
bn: 'bengali', // Bengali
bg: 'bulgarian', // Bulgarian
ca: 'catalan', // Catalan
'zh-HK': '', // Chinese (Hong Kong)
'zh-CN': 'chinese', // Chinese (Simplified)
'zh-TW': 'chinese', // Chinese (Traditional)
hr: 'croatian', // Croatian
cs: 'czech', // Czech
da: 'danish', // Danish
nl: 'dutch', // Dutch
'en-GB': 'english', // English (UK)
en: 'english', // English (US)
et: 'estonian', // Estonian
fil: '', // Filipino
fi: 'finnish', // Finnish
fr: 'french', // French
'fr-CA': 'french', // French (Canadian)
gl: '', // Galician
ka: 'georgian', // Georgian
de: 'german', // German
'de-AT': 'german', // German (Austria)
'de-CH': 'german', // German (Switzerland)
el: 'greek', // Greek
gu: '', // Gujarati
iw: 'hebrew', // Hebrew
hi: 'hindi', // Hindi
hu: 'hungarian', // Hungarian
is: 'icelandic', // Icelandic
id: 'indonesian', // Indonesian
it: 'italian', // Italian
ja: 'japanese', // Japanese
kn: 'kannada', // Kannada
ko: 'korean', // Korean
lo: 'laothian', // Laothian
lv: 'latvian', // Latvian
lt: 'lithuanian', // Lithuanian
ms: 'malay', // Malay
ml: '', // Malayalam
mr: '', // Marathi
mn: 'mongolian', // Mongolian
no: 'norwegian', // Norwegian
fa: 'persian', // Persian
pl: 'polish', // Polish
pt: 'portuguese', // Portuguese
'pt-BR': 'portuguese', // Portuguese (Brazil)
'pt-PT': 'portuguese', // Portuguese (Portugal)
ro: 'romanian', // Romanian
ru: 'russian', // Russian
sr: 'serbian', // Serbian
si: '', // Sinhalese
sk: 'slovak', // Slovak
sl: 'slovenian', // Slovenian
es: 'spanish', // Spanish
'es-419': 'spanish', // Spanish (Latin America)
sw: 'swahili', // Swahili
sv: 'swedish', // Swedish
ta: 'tamil', // Tamil
te: 'telugu', // Telugu
th: 'thai', // Thai
tr: 'turkish', // Turkish
uk: 'ukrainian', // Ukrainian
ur: 'urdu', // Urdu
vi: 'vietnamese', // Vietnamese
zu: 'zulu' // Zulu
};
// https://cloud.ibm.com/apidocs/speech-to-text#service-endpoint
@ -176,6 +343,7 @@ export {
captchaGoogleSpeechApiLangCodes,
captchaIbmSpeechApiLangCodes,
captchaMicrosoftSpeechApiLangCodes,
captchaWitSpeechApiLangCodes,
ibmSpeechApiUrls,
microsoftSpeechApiUrls
};

@ -4876,9 +4876,9 @@ express@^4.16.2:
utils-merge "1.0.1"
vary "~1.1.2"
ext-components@dessant/ext-components#^0.1.5:
version "0.1.5"
resolved "https://codeload.github.com/dessant/ext-components/tar.gz/a6f4128f032248efbc183fc8af822456f9f91898"
ext-components@dessant/ext-components#^0.1.6:
version "0.1.6"
resolved "https://codeload.github.com/dessant/ext-components/tar.gz/b16ebbd8928abe5bf10df8a6fb9b196e64c3ffbe"
dependencies:
"@material/button" "^0.31.0"
"@material/checkbox" "^0.31.0"
@ -4894,16 +4894,16 @@ ext-components@dessant/ext-components#^0.1.5:
typeface-roboto "^0.0.54"
vue "^2.5.17"
ext-contribute@dessant/ext-contribute#^0.1.5:
version "0.1.5"
resolved "https://codeload.github.com/dessant/ext-contribute/tar.gz/2957d7e7227554838a9015ee4c5f8382679db1af"
ext-contribute@dessant/ext-contribute#^0.1.6:
version "0.1.6"
resolved "https://codeload.github.com/dessant/ext-contribute/tar.gz/5cb22ee3d403eb371d4b30fc9b557441310cc6a9"
dependencies:
"@material/theme" "^0.30.0"
"@material/typography" "^0.28.0"
ext-components dessant/ext-components#^0.1.5
ext-components dessant/ext-components#^0.1.6
typeface-roboto "^0.0.54"
vue "^2.5.17"
webextension-polyfill "^0.3.0"
webextension-polyfill "^0.3.1"
extend-shallow@^1.1.2:
version "1.1.4"
@ -12029,15 +12029,15 @@ stdout-stream@^1.4.0:
dependencies:
readable-stream "^2.0.1"
storage-versions@dessant/storage-versions#^0.2.3:
version "0.2.3"
resolved "https://codeload.github.com/dessant/storage-versions/tar.gz/6925601efbca042da51601853e412a651e8a2176"
storage-versions@dessant/storage-versions#^0.2.4:
version "0.2.4"
resolved "https://codeload.github.com/dessant/storage-versions/tar.gz/72df3876592344b8f32e31bdbd88422cfc7ecaca"
dependencies:
commander "^2.17.1"
fs-extra "^7.0.0"
lodash-es "^4.17.10"
shortid "^2.2.12"
webextension-polyfill "^0.3.0"
webextension-polyfill "^0.3.1"
stream-browserify@^2.0.1:
version "2.0.1"
@ -13340,7 +13340,7 @@ web-ext@^2.8.0:
yargs "6.6.0"
zip-dir "1.0.2"
webextension-polyfill@^0.3.0:
webextension-polyfill@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/webextension-polyfill/-/webextension-polyfill-0.3.1.tgz#fab2aed917a713a5d8221e41febad81c5d0b080f"
integrity sha512-ISB42vlgMyM7xE1u6pREeCqmmXjLsYu/nqAR8Dl/gIAnylb+KpRpvKbVkUYNFePhhXn0Obkkc3jasOII9ztUtg==

Loading…
Cancel
Save