Skip to content

Instantly share code, notes, and snippets.

@marcmartino
Created November 27, 2019 16:07
Show Gist options
  • Save marcmartino/3040c96bcf1f16cf33865b34365ededd to your computer and use it in GitHub Desktop.
Save marcmartino/3040c96bcf1f16cf33865b34365ededd to your computer and use it in GitHub Desktop.
first attempt at fleshing out cogeneration of regex and grammars based on the same adts for use in speech recognition
enum QtyOperators {
Optional,
OnePlus,
ZeroPlus
}
type SpeechExpectation = {
captureName?: string;
qty?: QtyOperators;
inputs: (SpeechExpectation | string)[];
union?: true;
};
// interface CaptureAugmentedRegexp<T extends string> extends RegExpMatchArray {
// // thinking that T can be a string literal and then it can be explicity
// // noted in the groups?: {} record
// }
const genRegex = (expectation: SpeechExpectation): RegExp => {
return RegExp(genRegexSubstring(expectation), "mi");
};
const genRegexUnionStr = ({ inputs, union }: SpeechExpectation): string =>
inputs
.map(input =>
typeof input === "string" ? input : genRegexSubstring(input)
)
.join(union ? "|" : " ");
const genRegexSubstring = (expec: SpeechExpectation): string =>
"(" +
genCaptureGroupName(expec.captureName) +
genRegexUnionStr(expec) +
")" +
genRegexQtyStr(expec.qty);
const genCaptureGroupName = (groupName: string | undefined) =>
groupName ? `?<${groupName}>` : "?:";
const genRegexQtyStr = (qty: QtyOperators | undefined) => {
if (typeof qty === "undefined") return "";
switch (qty) {
case QtyOperators.Optional:
return "?";
case QtyOperators.OnePlus:
return "+";
case QtyOperators.ZeroPlus:
return "*";
default:
return "";
// return assertNever(qty);
}
};
interface JSGFConfig {
packageName?: string[];
// ruleName?: string;
charEncoding?: string;
locale?: string;
}
type JSGFText = string;
const genJSGFQtyStr = (qty: QtyOperators | undefined) => {
if (typeof qty === "undefined") return "";
switch (qty) {
case QtyOperators.Optional:
return "";
case QtyOperators.OnePlus:
return "+";
case QtyOperators.ZeroPlus:
return "*";
default:
return "";
//return assertNever(qty)
}
};
const genJSGFSubCommand = ({ inputs, qty, union }: SpeechExpectation) => {
const subcommandString = inputs
.map((input: SpeechExpectation | string): string =>
typeof input === "string" ? input : genJSGFSubCommand(input)
)
.join(union ? "|" : " ");
return (
(qty === QtyOperators.Optional ? ["[", "]"] : ["(", ")"]).join(
subcommandString
) + genJSGFQtyStr(qty)
);
};
const genJSGFCommand = (ex: SpeechExpectation) =>
`public <autoGeneratedCommand> = ${genJSGFSubCommand(ex)}`;
const genJSGF = (ex: SpeechExpectation, config: JSGFConfig = {}) => {
return `#JSGF V1.0; ${config.charEncoding ? config.charEncoding : ""} ${
config.locale ? config : ""
};
grammar speechStreams.commands.autogen;
${genJSGFCommand(ex)}
`;
};
const greeting: SpeechExpectation = {
inputs: ["hello", "hey", "howdy", "hi"],
union: true
};
const names: SpeechExpectation = {
inputs: ["german", "germi", "germanchu"],
captureName: "name",
union: true
};
const endingPhrase: SpeechExpectation = {
inputs: ["my friend", "bro"],
qty: QtyOperators.Optional,
union: true
};
const germanGreeting: SpeechExpectation = {
inputs: [greeting, names, endingPhrase]
};
const compileExpectation = (ex: SpeechExpectation) => {
const grammar = new SpeechGrammar();
grammar.src = genJSGF(ex);
return {
regex: genRegex(ex),
grammar
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment