Skip to content

Commit

Permalink
Merge pull request #823 from stanford-oval/wip/misc-fixes
Browse files Browse the repository at this point in the history
Miscellaneous fixes
  • Loading branch information
gcampax committed Oct 26, 2021
2 parents db9e235 + ea91d8b commit 9d9e0dd
Show file tree
Hide file tree
Showing 13 changed files with 99 additions and 113 deletions.
9 changes: 6 additions & 3 deletions lib/dialogue-agent/dialogue-loop.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ export class DialogueLoop {
}));

return pickHandler(this._currentHandler, handlerCandidates, command);
} catch(e) {
} catch(e : any) {
if (e.code === 'EHOSTUNREACH' || e.code === 'ETIMEDOUT') {
await this.reply(this._("Sorry, I cannot contact the Genie service. Please check your Internet connection and try again later."), null);
throw new CancellationError();
Expand Down Expand Up @@ -385,7 +385,7 @@ export class DialogueLoop {
await this._handleUserInput(item.command);
else
await this._handleAPICall(item);
} catch(e) {
} catch(e : any) {
if (e.code === 'ECANCELLED') {
for (const handler of this._iterateDialogueHandlers())
handler.reset();
Expand All @@ -396,6 +396,8 @@ export class DialogueLoop {
// in a new turn with an empty utterance from the user
await this.conversation.dialogueFinished();
} else {
console.error(`Error processing queue item`, item);
console.error(e);
if (item instanceof QueueItem.UserInput) {
await this.replyInterp(this._("Sorry, I had an error processing your command: ${error}."), { //"
error: this._formatError(e)
Expand All @@ -405,7 +407,6 @@ export class DialogueLoop {
error: this._formatError(e)
});
}
console.error(e);
}
}
}
Expand Down Expand Up @@ -566,6 +567,8 @@ export class DialogueLoop {
async replyGeneric(message : string|Tp.FormatObjects.FormattedObject, icon ?: string|null) {
if (typeof message === 'string')
await this.reply(message, icon);
else if (message.type === 'text')
await this.reply(message.text, icon);
else if (message.type === 'picture' || message.type === 'audio' || message.type === 'video')
await this.conversation.sendMedia(message.type, message.url, message.alt, icon || this.icon);
else if (message.type === 'rdl')
Expand Down
6 changes: 3 additions & 3 deletions lib/dialogue-agent/handlers/thingtalk.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ export default class ThingTalkDialogueHandler implements DialogueHandler<ThingTa
schemaRetriever: this._engine.schemas,
loadMetadata: true,
}, true);
} catch(e) {
} catch(e : any) {
// Likely, a type error in the ThingTalk code; not a big deal, but we still log it
console.log(`Failed to parse beam ${beamposition}: ${e.message}`);
parsed = new Ast.ControlCommand(null, new Ast.SpecialControlIntent(null, 'failed'));
Expand Down Expand Up @@ -560,7 +560,7 @@ export default class ThingTalkDialogueHandler implements DialogueHandler<ThingTa
this.icon = getProgramIcon(this._dialogueState);
return null;
}
} catch(e) {
} catch(e : any) {
if (e.code === 'ECANCELLED')
return null;
console.error(`Failed to restore conversation state: ${e.message}`);
Expand All @@ -572,7 +572,7 @@ export default class ThingTalkDialogueHandler implements DialogueHandler<ThingTa
// if we want to show the welcome message, we run the policy on the `null` state, which will return the sys_greet intent
// note: we need "return await" here or try/catch won't work
return await this._showWelcome();
} catch(e) {
} catch(e : any) {
if (e.code === 'ECANCELLED')
return null;
console.error(`Failed to show welcome message: ${e.message}`);
Expand Down
71 changes: 35 additions & 36 deletions lib/i18n/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ import BaseTokenizer from './tokenizer/base';
import {
Phrase,
Concatenation,
Replaceable
Replaceable,
Choice
} from '../utils/template-string';
import {
EntityMap,
Expand All @@ -56,13 +57,13 @@ export interface NormalizedParameterCanonical {
default : string;
projection_pronoun ?: string[];

base : Phrase[];
base_projection : Phrase[];
argmin : Phrase[];
argmax : Phrase[];
filter : Concatenation[];
enum_filter : Record<string, Phrase[]>;
projection : Phrase[];
base : Array<Phrase|Concatenation>;
base_projection : Array<Phrase|Concatenation>;
argmin : Array<Phrase|Concatenation>;
argmax : Array<Phrase|Concatenation>;
filter : Array<Phrase|Concatenation>;
enum_filter : Record<string, Array<Phrase|Concatenation>>;
projection : Array<Phrase|Concatenation>;
}

const POS_RENAME : Record<string, string> = {
Expand Down Expand Up @@ -262,10 +263,7 @@ export default class LanguagePack {
return this._tokenizer = new BaseTokenizer();
}

private _toTemplatePhrase(canonical : unknown, forSide : 'user'|'agent', isFilter : true) : Concatenation;
private _toTemplatePhrase(canonical : unknown, forSide : 'user'|'agent', isFilter ?: false) : Phrase;
private _toTemplatePhrase(canonical : unknown, forSide : 'user'|'agent', isFilter : boolean) : Phrase|Concatenation;
private _toTemplatePhrase(canonical : unknown, forSide : 'user'|'agent', isFilter = false) : Replaceable {
private _toTemplatePhrases(canonical : unknown, forSide : 'user'|'agent', isFilter = false) : Array<Phrase|Concatenation> {
let tmpl = String(canonical);
if (forSide === 'agent')
tmpl = this.toAgentSideUtterance(tmpl);
Expand All @@ -279,29 +277,32 @@ export default class LanguagePack {
tmpl = tmpl.replace('|', '//');
}
const parsed = Replaceable.parse(tmpl).preprocess(this, isFilter ? ['value'] : []);
if (isFilter) {
if (parsed instanceof Concatenation)
return parsed;
// this can happen if the original template was empty
return new Concatenation([parsed], {}, {});
} else {
assert(parsed instanceof Phrase);
if (parsed instanceof Phrase || parsed instanceof Concatenation)
return [parsed];

if (parsed instanceof Choice) {
return parsed.variants.map((v) => {
if (v instanceof Phrase || v instanceof Concatenation)
return v;

return new Concatenation([v], {}, {});
});
}
return parsed;
return [new Concatenation([parsed], {}, {})];
}

/**
* Apply load-time transformations to the canonical annotation of a function. This normalizes
* the form to the expected sets of POS, and adds any automatically generated
* plural/gender/case forms as necessary.
*/
preprocessFunctionCanonical(canonical : unknown, forItem : 'query'|'action'|'stream', forSide : 'user'|'agent', isList : boolean) : Phrase[] {
preprocessFunctionCanonical(canonical : unknown, forItem : 'query'|'action'|'stream', forSide : 'user'|'agent', isList : boolean) : Replaceable[] {
if (canonical === undefined || canonical === null)
return [];
if (Array.isArray(canonical))
return canonical.map((c) => this._toTemplatePhrase(c, forSide));
return canonical.flatMap((c) => this._toTemplatePhrases(c, forSide));
else
return [this._toTemplatePhrase(canonical, forSide)];
return this._toTemplatePhrases(canonical, forSide);
}

/**
Expand Down Expand Up @@ -337,17 +338,17 @@ export default class LanguagePack {
if (canonical === undefined || canonical === null)
return normalized;
if (typeof canonical === 'string') {
normalized.base = [this._toTemplatePhrase(canonical, forSide)];
normalized.filter = [this._toTemplatePhrase(canonical, forSide, true)];
normalized.base = this._toTemplatePhrases(canonical, forSide);
normalized.filter = this._toTemplatePhrases(canonical, forSide, true);
for (const phrase of normalized.filter) {
if (!phrase.flags.pos)
phrase.flags.pos = 'property';
}
return normalized;
}
if (Array.isArray(canonical)) {
normalized.base = canonical.map((c) => this._toTemplatePhrase(c, forSide));
normalized.filter = canonical.map((c) => this._toTemplatePhrase(c, forSide, true));
normalized.base = canonical.flatMap((c) => this._toTemplatePhrases(c, forSide));
normalized.filter = canonical.flatMap((c) => this._toTemplatePhrases(c, forSide, true));
for (const phrase of normalized.filter) {
if (!phrase.flags.pos)
phrase.flags.pos = 'property';
Expand Down Expand Up @@ -395,9 +396,9 @@ export default class LanguagePack {
}
let phrases;
if (Array.isArray(value))
phrases = value.map((c) => this._toTemplatePhrase(c, forSide));
phrases = value.flatMap((c) => this._toTemplatePhrases(c, forSide));
else
phrases = [this._toTemplatePhrase(value, forSide)];
phrases = this._toTemplatePhrases(value, forSide);

pos = POS_RENAME[pos]||pos;
for (const phrase of phrases)
Expand All @@ -415,9 +416,9 @@ export default class LanguagePack {
continue;
let enumNormalized;
if (Array.isArray(enumCanonical))
enumNormalized = enumCanonical.map((c) => this._toTemplatePhrase(c, forSide));
enumNormalized = enumCanonical.flatMap((c) => this._toTemplatePhrases(c, forSide));
else
enumNormalized = [this._toTemplatePhrase(enumCanonical, forSide)];
enumNormalized = this._toTemplatePhrases(enumCanonical, forSide);

if (key !== 'enumerands') {
let pos = key.substring(0, key.length - '_enum'.length);
Expand Down Expand Up @@ -465,18 +466,16 @@ export default class LanguagePack {

let phrases;
if (Array.isArray(value))
phrases = value.map((c) => this._toTemplatePhrase(c, forSide, isFilter));
phrases = value.flatMap((c) => this._toTemplatePhrases(c, forSide, isFilter));
else
phrases = [this._toTemplatePhrase(value, forSide, isFilter)];
phrases = this._toTemplatePhrases(value, forSide, isFilter);

if (pos !== undefined) {
pos = POS_RENAME[pos]||pos;
for (const phrase of phrases)
phrase.flags.pos = pos;
}
// HACK: this is not the right type signature, but it works in practice
// due to the logic around isFilter
normalized[into].push(...(phrases as Array<Concatenation & Phrase>));
normalized[into].push(...phrases);
}
}

Expand Down
13 changes: 6 additions & 7 deletions lib/i18n/english.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import { Tag } from 'en-pos';
import * as lexicon from 'en-lexicon';

import { coin } from '../utils/random';
import { Phrase } from '../utils/template-string';
import { Phrase, Replaceable } from '../utils/template-string';
import {
EntityMap,
} from '../utils/entity-utils';
Expand Down Expand Up @@ -251,16 +251,15 @@ export default class EnglishLanguagePack extends DefaultLanguagePack {
return sentence.trim();
}

preprocessFunctionCanonical(canonical : unknown, forItem : 'query'|'action'|'stream', forSide : 'user'|'agent', isList : boolean) : Phrase[] {
preprocessFunctionCanonical(canonical : unknown, forItem : 'query'|'action'|'stream', forSide : 'user'|'agent', isList : boolean) : Replaceable[] {
const normalized = super.preprocessFunctionCanonical(canonical, forItem, forSide, isList);

// if we have any form that already has the [plural] flag, we do nothing
// and assume the developer already did the work
if (normalized.some((form) => !!form.flags.plural))
return normalized;

if (forItem === 'query' && isList) {
return normalized.flatMap((form) => {
// if this form already has the [plural] flag, or if it is not a simple Phrase, we do nothing
if (!(form instanceof Phrase) || form.flags.plural)
return [form];

const clone = form.clone();
clone.text = this.pluralize(form.text);
if (clone.text !== form.text) {
Expand Down
13 changes: 11 additions & 2 deletions lib/templates/ast_manip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1079,7 +1079,7 @@ function addFilter(loader : ThingpediaLoader,
return addFilterInternal(table, filter.ast, options);
}

function tableToStream(table : Ast.Expression) : Ast.Expression|null {
function tableToStream(table : Ast.Expression, options : { monitorItemID : boolean }) : Ast.Expression|null {
if (!table.schema!.is_monitorable)
return null;

Expand All @@ -1095,6 +1095,8 @@ function tableToStream(table : Ast.Expression) : Ast.Expression|null {

if (projArg[0] === '$event')
return null;
} else if (options.monitorItemID && table.schema!.is_list && table.schema!.hasArgument('id')) {
projArg = ['id'];
}

let stream;
Expand Down Expand Up @@ -1538,7 +1540,7 @@ function makeComputeExpression(table : Ast.Expression,
return new Ast.ProjectionExpression(null, table, [], [expression], [null], resolveProjection(table.schema!, [], [expression]));
}

function makeComputeFilterExpression(loader : ThingpediaLoader,
function makeComputeFilterExpression(loader : ThingpediaLoader,
table : Ast.Expression,
operation : 'distance',
operands : Ast.Value[],
Expand Down Expand Up @@ -2045,6 +2047,13 @@ function makeGenericJoin(tpLoader : ThingpediaLoader,
return makeJoinExpressionHelper(join, condition, ['first.id', `second.${rhsParam.name}`]);
}

export function whenDoRule(table : Ast.Expression, action : ExpressionWithCoreference, options : { monitorItemID : boolean }) {
const stream = tableToStream(table, { monitorItemID: false });
if (!stream)
return null;
return addParameterPassing(stream, action);
}

export {
// helpers
typeToStringSafe,
Expand Down
Loading

0 comments on commit 9d9e0dd

Please sign in to comment.