1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "actions/utils.h"
18
19 #include "annotator/collections.h"
20 #include "utils/base/logging.h"
21 #include "utils/normalization.h"
22 #include "utils/strings/stringpiece.h"
23
24 namespace libtextclassifier3 {
25
26 // Name for a datetime annotation that only includes time but no date.
27 const std::string& kTimeAnnotation =
__anon323323a30102() 28 *[]() { return new std::string("time"); }();
29
FillSuggestionFromSpec(const ActionSuggestionSpec * action,MutableFlatbuffer * entity_data,ActionSuggestion * suggestion)30 void FillSuggestionFromSpec(const ActionSuggestionSpec* action,
31 MutableFlatbuffer* entity_data,
32 ActionSuggestion* suggestion) {
33 if (action != nullptr) {
34 suggestion->score = action->score();
35 suggestion->priority_score = action->priority_score();
36 if (action->type() != nullptr) {
37 suggestion->type = action->type()->str();
38 }
39 if (action->response_text() != nullptr) {
40 suggestion->response_text = action->response_text()->str();
41 }
42 if (action->serialized_entity_data() != nullptr) {
43 TC3_CHECK_NE(entity_data, nullptr);
44 entity_data->MergeFromSerializedFlatbuffer(
45 StringPiece(action->serialized_entity_data()->data(),
46 action->serialized_entity_data()->size()));
47 }
48 if (action->entity_data() != nullptr) {
49 TC3_CHECK_NE(entity_data, nullptr);
50 entity_data->MergeFrom(
51 reinterpret_cast<const flatbuffers::Table*>(action->entity_data()));
52 }
53 }
54 if (entity_data != nullptr && entity_data->HasExplicitlySetFields()) {
55 suggestion->serialized_entity_data = entity_data->Serialize();
56 }
57 }
58
SuggestTextRepliesFromCapturingMatch(const MutableFlatbufferBuilder * entity_data_builder,const RulesModel_::RuleActionSpec_::RuleCapturingGroup * group,const UnicodeText & match_text,const std::string & smart_reply_action_type,std::vector<ActionSuggestion> * actions)59 void SuggestTextRepliesFromCapturingMatch(
60 const MutableFlatbufferBuilder* entity_data_builder,
61 const RulesModel_::RuleActionSpec_::RuleCapturingGroup* group,
62 const UnicodeText& match_text, const std::string& smart_reply_action_type,
63 std::vector<ActionSuggestion>* actions) {
64 if (group->text_reply() != nullptr) {
65 ActionSuggestion suggestion;
66 suggestion.response_text = match_text.ToUTF8String();
67 suggestion.type = smart_reply_action_type;
68 std::unique_ptr<MutableFlatbuffer> entity_data =
69 entity_data_builder != nullptr ? entity_data_builder->NewRoot()
70 : nullptr;
71 FillSuggestionFromSpec(group->text_reply(), entity_data.get(), &suggestion);
72 actions->push_back(suggestion);
73 }
74 }
75
NormalizeMatchText(const UniLib & unilib,const RulesModel_::RuleActionSpec_::RuleCapturingGroup * group,StringPiece match_text)76 UnicodeText NormalizeMatchText(
77 const UniLib& unilib,
78 const RulesModel_::RuleActionSpec_::RuleCapturingGroup* group,
79 StringPiece match_text) {
80 return NormalizeMatchText(unilib, group,
81 UTF8ToUnicodeText(match_text, /*do_copy=*/false));
82 }
83
NormalizeMatchText(const UniLib & unilib,const RulesModel_::RuleActionSpec_::RuleCapturingGroup * group,const UnicodeText match_text)84 UnicodeText NormalizeMatchText(
85 const UniLib& unilib,
86 const RulesModel_::RuleActionSpec_::RuleCapturingGroup* group,
87 const UnicodeText match_text) {
88 if (group->normalization_options() == nullptr) {
89 return match_text;
90 }
91 return NormalizeText(unilib, group->normalization_options(), match_text);
92 }
93
FillAnnotationFromCapturingMatch(const CodepointSpan & span,const RulesModel_::RuleActionSpec_::RuleCapturingGroup * group,const int message_index,StringPiece match_text,ActionSuggestionAnnotation * annotation)94 bool FillAnnotationFromCapturingMatch(
95 const CodepointSpan& span,
96 const RulesModel_::RuleActionSpec_::RuleCapturingGroup* group,
97 const int message_index, StringPiece match_text,
98 ActionSuggestionAnnotation* annotation) {
99 if (group->annotation_name() == nullptr &&
100 group->annotation_type() == nullptr) {
101 return false;
102 }
103 annotation->span.span = span;
104 annotation->span.message_index = message_index;
105 annotation->span.text = match_text.ToString();
106 if (group->annotation_name() != nullptr) {
107 annotation->name = group->annotation_name()->str();
108 }
109 if (group->annotation_type() != nullptr) {
110 annotation->entity.collection = group->annotation_type()->str();
111 }
112 return true;
113 }
114
MergeEntityDataFromCapturingMatch(const RulesModel_::RuleActionSpec_::RuleCapturingGroup * group,StringPiece match_text,MutableFlatbuffer * buffer)115 bool MergeEntityDataFromCapturingMatch(
116 const RulesModel_::RuleActionSpec_::RuleCapturingGroup* group,
117 StringPiece match_text, MutableFlatbuffer* buffer) {
118 if (group->entity_field() != nullptr) {
119 if (!buffer->ParseAndSet(group->entity_field(), match_text.ToString())) {
120 TC3_LOG(ERROR) << "Could not set entity data from rule capturing group.";
121 return false;
122 }
123 }
124 if (group->entity_data() != nullptr) {
125 if (!buffer->MergeFrom(reinterpret_cast<const flatbuffers::Table*>(
126 group->entity_data()))) {
127 TC3_LOG(ERROR) << "Could not set entity data for capturing match.";
128 return false;
129 }
130 }
131 return true;
132 }
133
ConvertDatetimeToTime(std::vector<AnnotatedSpan> * annotations)134 void ConvertDatetimeToTime(std::vector<AnnotatedSpan>* annotations) {
135 for (int i = 0; i < annotations->size(); i++) {
136 ClassificationResult* classification =
137 &(*annotations)[i].classification.front();
138 // Specialize datetime annotation to time annotation if no date
139 // component is present.
140 if (classification->collection == Collections::DateTime() &&
141 classification->datetime_parse_result.IsSet()) {
142 bool has_only_time = true;
143 for (const DatetimeComponent& component :
144 classification->datetime_parse_result.datetime_components) {
145 if (component.component_type !=
146 DatetimeComponent::ComponentType::UNSPECIFIED &&
147 component.component_type < DatetimeComponent::ComponentType::HOUR) {
148 has_only_time = false;
149 break;
150 }
151 }
152 if (has_only_time) {
153 classification->collection = kTimeAnnotation;
154 }
155 }
156 }
157 }
158
159 } // namespace libtextclassifier3
160