提交 255ffd46 authored 作者: Chris Rienzo's avatar Chris Rienzo

mod_rayo: add some hacky support for SISR in DTMF recognizer

上级 6476adc4
......@@ -397,9 +397,10 @@ static int isdtmf(const char digit)
/**
* Construct an NLSML result for digit match
* @param digits the matching digits
* @param interpretation the optional digit interpretation
* @return the NLSML <result>
*/
iks *nlsml_create_dtmf_match(const char *digits)
iks *nlsml_create_dtmf_match(const char *digits, const char *interpretation)
{
iks *result = iks_new("result");
iks_insert_attrib(result, "xmlns", NLSML_NS);
......@@ -410,10 +411,11 @@ iks *nlsml_create_dtmf_match(const char *digits)
int num_digits = strlen(digits);
switch_stream_handle_t stream = { 0 };
iks *interpretation = iks_insert(result, "interpretation");
iks *input = iks_insert(interpretation, "input");
iks_insert_attrib(input, "mode", "dtmf");
iks_insert_attrib(input, "confidence", "100");
iks *interpretation_node = iks_insert(result, "interpretation");
iks *input_node = iks_insert(interpretation_node, "input");
iks *instance_node = iks_insert(interpretation_node, "instance");
iks_insert_attrib(input_node, "mode", "dtmf");
iks_insert_attrib(input_node, "confidence", "100");
SWITCH_STANDARD_STREAM(stream);
for (i = 0; i < num_digits; i++) {
......@@ -426,7 +428,13 @@ iks *nlsml_create_dtmf_match(const char *digits)
}
}
}
iks_insert_cdata(input, stream.data, strlen(stream.data));
iks_insert_cdata(input_node, stream.data, strlen(stream.data));
if (zstr(interpretation)) {
iks_insert_cdata(instance_node, stream.data, strlen(stream.data));
} else {
iks_insert_cdata(instance_node, interpretation, strlen(interpretation));
}
switch_safe_free(stream.data);
}
return result;
......
......@@ -42,7 +42,7 @@ enum nlsml_match_type {
extern int nlsml_init(void);
enum nlsml_match_type nlsml_parse(const char *result, const char *uuid);
iks *nlsml_normalize(const char *result);
extern iks *nlsml_create_dtmf_match(const char *digits);
extern iks *nlsml_create_dtmf_match(const char *digits, const char *interpretation);
#endif
......
......@@ -157,6 +157,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
int is_term_digit = 0;
struct input_component *component;
enum srgs_match_type match;
const char *interpretation = NULL;
switch_mutex_lock(handler->mutex);
......@@ -179,7 +180,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Collected term digit = \"%c\"\n", dtmf->digit);
}
match = srgs_grammar_match(component->grammar, component->digits);
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
/* adjust result if terminating digit was pressed */
if (is_term_digit) {
......@@ -208,7 +209,7 @@ static switch_status_t input_component_on_dtmf(switch_core_session_t *session, c
break;
}
case SMT_MATCH_END: {
iks *result = nlsml_create_dtmf_match(component->digits);
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
/* notify of match and remove input component */
handler->dtmf_component = NULL;
switch_core_media_bug_remove(session, &handler->bug);
......@@ -248,13 +249,14 @@ static switch_bool_t input_component_bug_callback(switch_media_bug_t *bug, void
int elapsed_ms = (switch_micro_time_now() - component->last_digit_time) / 1000;
if (component->num_digits && component->inter_digit_timeout > 0 && elapsed_ms > component->inter_digit_timeout) {
enum srgs_match_type match;
const char *interpretation = NULL;
handler->dtmf_component = NULL;
switch_core_media_bug_set_flag(bug, SMBF_PRUNE);
/* we got some input, check for match */
match = srgs_grammar_match(component->grammar, component->digits);
match = srgs_grammar_match(component->grammar, component->digits, &interpretation);
if (match == SMT_MATCH || match == SMT_MATCH_END) {
iks *result = nlsml_create_dtmf_match(component->digits);
iks *result = nlsml_create_dtmf_match(component->digits, interpretation);
/* notify of match */
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "MATCH = %s\n", component->digits);
send_match_event(RAYO_COMPONENT(component), result);
......
......@@ -33,6 +33,7 @@
#include "srgs.h"
#define MAX_RECURSION 100
#define MAX_TAGS 30
/** function to handle tag attributes */
typedef int (* tag_attribs_fn)(struct srgs_grammar *, char **);
......@@ -111,6 +112,7 @@ struct item_value {
int repeat_min;
int repeat_max;
const char *weight;
char *tag;
};
/**
......@@ -161,6 +163,10 @@ struct srgs_grammar {
struct srgs_node *cur;
/** rule names mapped to node */
switch_hash_t *rules;
/** possible matching tags */
const char *tags[MAX_TAGS];
/** number of tags */
int tag_count;
/** grammar encoding */
char *encoding;
/** grammar language */
......@@ -708,6 +714,30 @@ static int tag_hook(void *user_data, char *name, char **atts, int type)
return result;
}
/**
* Process <tag> CDATA
* @param grammar the grammar
* @param data the CDATA
* @param len the CDATA length
* @return IKS_OK
*/
static int process_cdata_tag(struct srgs_grammar *grammar, char *data, size_t len)
{
struct srgs_node *item = grammar->cur->parent;
if (item && item->type == SNT_ITEM) {
item->value.item.tag = switch_core_alloc(grammar->pool, sizeof(char) * (len + 1));
item->value.item.tag[len] = '\0';
strncpy(item->value.item.tag, data, len);
if (grammar->tag_count < MAX_TAGS) {
grammar->tags[grammar->tag_count++] = item->value.item.tag;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "too many <tag>s\n");
return IKS_BADXML;
}
}
return IKS_OK;
}
/**
* Process CDATA grammar tokens
* @param grammar the grammar
......@@ -956,8 +986,12 @@ static int create_regexes(struct srgs_grammar *grammar, struct srgs_node *node,
case SNT_ITEM:
if (node->child) {
struct srgs_node *item = node->child;
if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1) {
stream->write_function(stream, "%s", "(?:");
if (node->value.item.repeat_min != 1 || node->value.item.repeat_max != 1 || !zstr(node->value.item.tag)) {
if (zstr(node->value.item.tag)) {
stream->write_function(stream, "%s", "(?:");
} else {
stream->write_function(stream, "(?P<%s>", node->value.item.tag);
}
}
for(; item; item = item->next) {
if (!create_regexes(grammar, item, stream)) {
......@@ -980,6 +1014,8 @@ static int create_regexes(struct srgs_grammar *grammar, struct srgs_node *node,
} else {
stream->write_function(stream, "){%i}", node->value.item.repeat_min);
}
} else if (!zstr(node->value.item.tag)) {
stream->write_function(stream, "%s", ")");
}
}
break;
......@@ -1171,7 +1207,7 @@ struct srgs_grammar *srgs_parse(struct srgs_parser *parser, const char *document
}
#define MAX_INPUT_SIZE 128
#define OVECTOR_SIZE 30
#define OVECTOR_SIZE MAX_TAGS
#define WORKSPACE_SIZE 1024
/**
......@@ -1214,15 +1250,17 @@ static int is_match_end(pcre *compiled_regex, const char *input)
* Find a match
* @param grammar the grammar to match
* @param input the input to compare
* @param interpretation the (optional) interpretation of the input result
* @return the match result
*/
enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input)
enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input, const char **interpretation)
{
int result = 0;
int ovector[OVECTOR_SIZE];
int workspace[WORKSPACE_SIZE];
pcre *compiled_regex;
*interpretation = NULL;
if (zstr(input)) {
return SMT_NO_MATCH;
}
......@@ -1234,12 +1272,24 @@ enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char
if (!(compiled_regex = get_compiled_regex(grammar))) {
return SMT_NO_MATCH;
}
result = pcre_dfa_exec(compiled_regex, NULL, input, strlen(input), 0, PCRE_PARTIAL,
ovector, sizeof(ovector) / sizeof(ovector[0]),
workspace, sizeof(workspace) / sizeof(workspace[0]));
result = pcre_exec(compiled_regex, NULL, input, strlen(input), 0, PCRE_PARTIAL,
ovector, OVECTOR_SIZE);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "match = %i\n", result);
if (result > 0) {
int i;
char buffer[MAX_INPUT_SIZE + 1];
buffer[MAX_INPUT_SIZE] = '\0';
/* find matching instance... */
for (i = 0; i < grammar->tag_count; i++) {
buffer[0] = '\0';
if (pcre_copy_named_substring(compiled_regex, input, ovector, result, grammar->tags[i], buffer, MAX_INPUT_SIZE) != PCRE_ERROR_NOSUBSTRING && !zstr_buf(buffer)) {
*interpretation = grammar->tags[i];
break;
}
}
if (is_match_end(compiled_regex, input)) {
return SMT_MATCH_END;
}
......@@ -1562,7 +1612,7 @@ int srgs_init(void)
add_root_tag_def("grammar", process_grammar, process_cdata_bad, "meta,metadata,lexicon,tag,rule");
add_tag_def("ruleref", process_ruleref, process_cdata_bad, "");
add_tag_def("token", process_attribs_ignore, process_cdata_ignore, "");
add_tag_def("tag", process_attribs_ignore, process_cdata_ignore, "");
add_tag_def("tag", process_attribs_ignore, process_cdata_tag, "");
add_tag_def("one-of", process_attribs_ignore, process_cdata_tokens, "item");
add_tag_def("item", process_item, process_cdata_tokens, "token,ruleref,item,one-of,tag");
add_tag_def("rule", process_rule, process_cdata_tokens, "token,ruleref,item,one-of,tag,example");
......
......@@ -51,7 +51,7 @@ extern struct srgs_grammar *srgs_parse(struct srgs_parser *parser, const char *d
extern const char *srgs_grammar_to_regex(struct srgs_grammar *grammar);
extern const char *srgs_grammar_to_jsgf(struct srgs_grammar *grammar);
extern const char *srgs_grammar_to_jsgf_file(struct srgs_grammar *grammar, const char *basedir, const char *ext);
extern enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input);
extern enum srgs_match_type srgs_grammar_match(struct srgs_grammar *grammar, const char *input, const char **interpretation);
extern void srgs_parser_destroy(struct srgs_parser *parser);
#endif
......
......@@ -245,14 +245,15 @@ static const char *nlsml_dtmf_result =
"<result xmlns='http://www.ietf.org/xml/ns/mrcpv2' "
"xmlns:xf='http://www.w3.org/2000/xforms'><interpretation>"
"<input mode='dtmf' confidence='100'>1 2 3 4</input>"
"<instance>1 2 3 4</instance>"
"</interpretation></result>";
/**
* Test parsing NLSML example results
* Test creating DTMF match result
*/
static void test_create_dtmf_match(void)
{
iks *result = nlsml_create_dtmf_match("1234");
iks *result = nlsml_create_dtmf_match("1234", NULL);
char *result_str;
ASSERT_NOT_NULL(result);
result_str = iks_string(NULL, result);
......@@ -260,6 +261,26 @@ static void test_create_dtmf_match(void)
iks_free(result_str);
}
static const char *nlsml_dtmf_instance_result =
"<result xmlns='http://www.ietf.org/xml/ns/mrcpv2' "
"xmlns:xf='http://www.w3.org/2000/xforms'><interpretation>"
"<input mode='dtmf' confidence='100'>1</input>"
"<instance>foo</instance>"
"</interpretation></result>";
/**
* Test creating DTMF match result with instance interpretation
*/
static void test_create_dtmf_instance(void)
{
iks *result = nlsml_create_dtmf_match("1", "foo");
char *result_str;
ASSERT_NOT_NULL(result);
result_str = iks_string(NULL, result);
ASSERT_STRING_EQUALS(nlsml_dtmf_instance_result, result_str);
iks_free(result_str);
}
static const char *nlsml_good_normalized =
"<result x-model='http://theYesNoModel'"
" xmlns:xf='http://www.w3.org/2000/xforms'"
......@@ -295,6 +316,7 @@ int main(int argc, char **argv)
nlsml_init();
TEST(test_parse_nlsml_examples);
TEST(test_create_dtmf_match);
TEST(test_create_dtmf_instance);
TEST(test_normalize);
return 0;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论