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 "annotator/types.h"
18
19 #include <vector>
20
21 #include "utils/optional.h"
22
23 namespace libtextclassifier3 {
24
operator <<(logging::LoggingStringStream & stream,const Token & token)25 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
26 const Token& token) {
27 if (!token.is_padding) {
28 return stream << "Token(\"" << token.value << "\", " << token.start << ", "
29 << token.end << ")";
30 } else {
31 return stream << "Token()";
32 }
33 }
34
ShouldRoundToGranularity() const35 bool DatetimeComponent::ShouldRoundToGranularity() const {
36 // Don't round to the granularity for relative expressions that specify the
37 // distance. So that, e.g. "in 2 hours" when it's 8:35:03 will result in
38 // 10:35:03.
39 if (relative_qualifier == RelativeQualifier::UNSPECIFIED) {
40 return false;
41 }
42 if (relative_qualifier == RelativeQualifier::NEXT ||
43 relative_qualifier == RelativeQualifier::TOMORROW ||
44 relative_qualifier == RelativeQualifier::YESTERDAY ||
45 relative_qualifier == RelativeQualifier::LAST ||
46 relative_qualifier == RelativeQualifier::THIS ||
47 relative_qualifier == RelativeQualifier::NOW) {
48 return true;
49 }
50 return false;
51 }
52
53 namespace {
FormatMillis(int64 time_ms_utc)54 std::string FormatMillis(int64 time_ms_utc) {
55 long time_seconds = time_ms_utc / 1000; // NOLINT
56 char buffer[512];
57 strftime(buffer, sizeof(buffer), "%a %Y-%m-%d %H:%M:%S %Z",
58 localtime(&time_seconds));
59 return std::string(buffer);
60 }
61 } // namespace
62
ComponentTypeToString(const DatetimeComponent::ComponentType & component_type)63 std::string ComponentTypeToString(
64 const DatetimeComponent::ComponentType& component_type) {
65 switch (component_type) {
66 case DatetimeComponent::ComponentType::UNSPECIFIED:
67 return "UNSPECIFIED";
68 case DatetimeComponent::ComponentType::YEAR:
69 return "YEAR";
70 case DatetimeComponent::ComponentType::MONTH:
71 return "MONTH";
72 case DatetimeComponent::ComponentType::WEEK:
73 return "WEEK";
74 case DatetimeComponent::ComponentType::DAY_OF_WEEK:
75 return "DAY_OF_WEEK";
76 case DatetimeComponent::ComponentType::DAY_OF_MONTH:
77 return "DAY_OF_MONTH";
78 case DatetimeComponent::ComponentType::HOUR:
79 return "HOUR";
80 case DatetimeComponent::ComponentType::MINUTE:
81 return "MINUTE";
82 case DatetimeComponent::ComponentType::SECOND:
83 return "SECOND";
84 case DatetimeComponent::ComponentType::MERIDIEM:
85 return "MERIDIEM";
86 case DatetimeComponent::ComponentType::ZONE_OFFSET:
87 return "ZONE_OFFSET";
88 case DatetimeComponent::ComponentType::DST_OFFSET:
89 return "DST_OFFSET";
90 default:
91 return "";
92 }
93 }
94
RelativeQualifierToString(const DatetimeComponent::RelativeQualifier & relative_qualifier)95 std::string RelativeQualifierToString(
96 const DatetimeComponent::RelativeQualifier& relative_qualifier) {
97 switch (relative_qualifier) {
98 case DatetimeComponent::RelativeQualifier::UNSPECIFIED:
99 return "UNSPECIFIED";
100 case DatetimeComponent::RelativeQualifier::NEXT:
101 return "NEXT";
102 case DatetimeComponent::RelativeQualifier::THIS:
103 return "THIS";
104 case DatetimeComponent::RelativeQualifier::LAST:
105 return "LAST";
106 case DatetimeComponent::RelativeQualifier::NOW:
107 return "NOW";
108 case DatetimeComponent::RelativeQualifier::TOMORROW:
109 return "TOMORROW";
110 case DatetimeComponent::RelativeQualifier::YESTERDAY:
111 return "YESTERDAY";
112 case DatetimeComponent::RelativeQualifier::PAST:
113 return "PAST";
114 case DatetimeComponent::RelativeQualifier::FUTURE:
115 return "FUTURE";
116 default:
117 return "";
118 }
119 }
120
operator <<(logging::LoggingStringStream & stream,const DatetimeParseResultSpan & value)121 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
122 const DatetimeParseResultSpan& value) {
123 stream << "DatetimeParseResultSpan({" << value.span.first << ", "
124 << value.span.second << "}, "
125 << "/*target_classification_score=*/ "
126 << value.target_classification_score << "/*priority_score=*/"
127 << value.priority_score << " {";
128 for (const DatetimeParseResult& data : value.data) {
129 stream << "{/*time_ms_utc=*/ " << data.time_ms_utc << " /* "
130 << FormatMillis(data.time_ms_utc) << " */, /*granularity=*/ "
131 << data.granularity << ", /*datetime_components=*/ ";
132 for (const DatetimeComponent& datetime_comp : data.datetime_components) {
133 stream << "{/*component_type=*/ "
134 << ComponentTypeToString(datetime_comp.component_type)
135 << " /*relative_qualifier=*/ "
136 << RelativeQualifierToString(datetime_comp.relative_qualifier)
137 << " /*value=*/ " << datetime_comp.value << " /*relative_count=*/ "
138 << datetime_comp.relative_count << "}, ";
139 }
140 stream << "}, ";
141 }
142 stream << "})";
143 return stream;
144 }
145
operator ==(const ClassificationResult & other) const146 bool ClassificationResult::operator==(const ClassificationResult& other) const {
147 return ClassificationResultsEqualIgnoringScoresAndSerializedEntityData(
148 *this, other) &&
149 fabs(score - other.score) < 0.001 &&
150 fabs(priority_score - other.priority_score) < 0.001 &&
151 serialized_entity_data == other.serialized_entity_data;
152 }
153
ClassificationResultsEqualIgnoringScoresAndSerializedEntityData(const ClassificationResult & a,const ClassificationResult & b)154 bool ClassificationResultsEqualIgnoringScoresAndSerializedEntityData(
155 const ClassificationResult& a, const ClassificationResult& b) {
156 return a.collection == b.collection &&
157 a.datetime_parse_result == b.datetime_parse_result &&
158 a.serialized_knowledge_result == b.serialized_knowledge_result &&
159 a.contact_pointer == b.contact_pointer &&
160 a.contact_name == b.contact_name &&
161 a.contact_given_name == b.contact_given_name &&
162 a.contact_family_name == b.contact_family_name &&
163 a.contact_nickname == b.contact_nickname &&
164 a.contact_email_address == b.contact_email_address &&
165 a.contact_phone_number == b.contact_phone_number &&
166 a.contact_id == b.contact_id &&
167 a.app_package_name == b.app_package_name &&
168 a.numeric_value == b.numeric_value &&
169 fabs(a.numeric_double_value - b.numeric_double_value) < 0.001 &&
170 a.duration_ms == b.duration_ms;
171 }
172
operator <<(logging::LoggingStringStream & stream,const ClassificationResult & result)173 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
174 const ClassificationResult& result) {
175 return stream << "ClassificationResult(" << result.collection
176 << ", /*score=*/ " << result.score << ", /*priority_score=*/ "
177 << result.priority_score << ")";
178 }
179
operator <<(logging::LoggingStringStream & stream,const std::vector<ClassificationResult> & results)180 logging::LoggingStringStream& operator<<(
181 logging::LoggingStringStream& stream,
182 const std::vector<ClassificationResult>& results) {
183 stream = stream << "{\n";
184 for (const ClassificationResult& result : results) {
185 stream = stream << " " << result << "\n";
186 }
187 stream = stream << "}";
188 return stream;
189 }
190
operator <<(logging::LoggingStringStream & stream,const AnnotatedSpan & span)191 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
192 const AnnotatedSpan& span) {
193 std::string best_class;
194 float best_score = -1;
195 if (!span.classification.empty()) {
196 best_class = span.classification[0].collection;
197 best_score = span.classification[0].score;
198 }
199 return stream << "Span(" << span.span.first << ", " << span.span.second
200 << ", " << best_class << ", " << best_score << ")";
201 }
202
operator <<(logging::LoggingStringStream & stream,const DatetimeParsedData & data)203 logging::LoggingStringStream& operator<<(logging::LoggingStringStream& stream,
204 const DatetimeParsedData& data) {
205 std::vector<DatetimeComponent> date_time_components;
206 data.GetDatetimeComponents(&date_time_components);
207 stream = stream << "DatetimeParsedData { \n";
208 for (const DatetimeComponent& c : date_time_components) {
209 stream = stream << " DatetimeComponent { \n";
210 stream = stream << " Component Type:" << static_cast<int>(c.component_type)
211 << "\n";
212 stream = stream << " Value:" << c.value << "\n";
213 stream = stream << " Relative Qualifier:"
214 << static_cast<int>(c.relative_qualifier) << "\n";
215 stream = stream << " Relative Count:" << c.relative_count << "\n";
216 stream = stream << " } \n";
217 }
218 stream = stream << "}";
219 return stream;
220 }
221
SetAbsoluteValue(const DatetimeComponent::ComponentType & field_type,int value)222 void DatetimeParsedData::SetAbsoluteValue(
223 const DatetimeComponent::ComponentType& field_type, int value) {
224 GetOrCreateDatetimeComponent(field_type).value = value;
225 }
226
SetRelativeValue(const DatetimeComponent::ComponentType & field_type,const DatetimeComponent::RelativeQualifier & relative_value)227 void DatetimeParsedData::SetRelativeValue(
228 const DatetimeComponent::ComponentType& field_type,
229 const DatetimeComponent::RelativeQualifier& relative_value) {
230 GetOrCreateDatetimeComponent(field_type).relative_qualifier = relative_value;
231 }
232
SetRelativeCount(const DatetimeComponent::ComponentType & field_type,int relative_count)233 void DatetimeParsedData::SetRelativeCount(
234 const DatetimeComponent::ComponentType& field_type, int relative_count) {
235 GetOrCreateDatetimeComponent(field_type).relative_count = relative_count;
236 }
237
AddDatetimeComponents(const std::vector<DatetimeComponent> & datetime_components)238 void DatetimeParsedData::AddDatetimeComponents(
239 const std::vector<DatetimeComponent>& datetime_components) {
240 for (const DatetimeComponent& datetime_component : datetime_components) {
241 date_time_components_.insert(
242 {datetime_component.component_type, datetime_component});
243 }
244 }
245
HasFieldType(const DatetimeComponent::ComponentType & field_type) const246 bool DatetimeParsedData::HasFieldType(
247 const DatetimeComponent::ComponentType& field_type) const {
248 if (date_time_components_.find(field_type) == date_time_components_.end()) {
249 return false;
250 }
251 return true;
252 }
253
GetFieldValue(const DatetimeComponent::ComponentType & field_type,int * field_value) const254 bool DatetimeParsedData::GetFieldValue(
255 const DatetimeComponent::ComponentType& field_type,
256 int* field_value) const {
257 if (HasFieldType(field_type)) {
258 *field_value = date_time_components_.at(field_type).value;
259 return true;
260 }
261 return false;
262 }
263
GetRelativeValue(const DatetimeComponent::ComponentType & field_type,DatetimeComponent::RelativeQualifier * relative_value) const264 bool DatetimeParsedData::GetRelativeValue(
265 const DatetimeComponent::ComponentType& field_type,
266 DatetimeComponent::RelativeQualifier* relative_value) const {
267 if (HasFieldType(field_type)) {
268 *relative_value = date_time_components_.at(field_type).relative_qualifier;
269 return true;
270 }
271 return false;
272 }
273
HasRelativeValue(const DatetimeComponent::ComponentType & field_type) const274 bool DatetimeParsedData::HasRelativeValue(
275 const DatetimeComponent::ComponentType& field_type) const {
276 if (HasFieldType(field_type)) {
277 return date_time_components_.at(field_type).relative_qualifier !=
278 DatetimeComponent::RelativeQualifier::UNSPECIFIED;
279 }
280 return false;
281 }
282
HasAbsoluteValue(const DatetimeComponent::ComponentType & field_type) const283 bool DatetimeParsedData::HasAbsoluteValue(
284 const DatetimeComponent::ComponentType& field_type) const {
285 return HasFieldType(field_type) && !HasRelativeValue(field_type);
286 }
287
IsEmpty() const288 bool DatetimeParsedData::IsEmpty() const {
289 return date_time_components_.empty();
290 }
291
GetRelativeDatetimeComponents(std::vector<DatetimeComponent> * date_time_components) const292 void DatetimeParsedData::GetRelativeDatetimeComponents(
293 std::vector<DatetimeComponent>* date_time_components) const {
294 for (auto it = date_time_components_.begin();
295 it != date_time_components_.end(); it++) {
296 if (it->second.relative_qualifier !=
297 DatetimeComponent::RelativeQualifier::UNSPECIFIED) {
298 date_time_components->push_back(it->second);
299 }
300 }
301 }
302
GetDatetimeComponents(std::vector<DatetimeComponent> * date_time_components) const303 void DatetimeParsedData::GetDatetimeComponents(
304 std::vector<DatetimeComponent>* date_time_components) const {
305 for (auto it = date_time_components_.begin();
306 it != date_time_components_.end(); it++) {
307 date_time_components->push_back(it->second);
308 }
309 }
310
GetOrCreateDatetimeComponent(const DatetimeComponent::ComponentType & component_type)311 DatetimeComponent& DatetimeParsedData::GetOrCreateDatetimeComponent(
312 const DatetimeComponent::ComponentType& component_type) {
313 auto result =
314 date_time_components_
315 .insert(
316 {component_type,
317 DatetimeComponent(
318 component_type,
319 DatetimeComponent::RelativeQualifier::UNSPECIFIED, 0, 0)})
320 .first;
321 return result->second;
322 }
323
324 namespace {
GetFinestGranularityFromComponentTypes(const std::vector<DatetimeComponent::ComponentType> & datetime_component_types)325 DatetimeGranularity GetFinestGranularityFromComponentTypes(
326 const std::vector<DatetimeComponent::ComponentType>&
327 datetime_component_types) {
328 DatetimeGranularity granularity = DatetimeGranularity::GRANULARITY_UNKNOWN;
329 for (const auto& component_type : datetime_component_types) {
330 switch (component_type) {
331 case DatetimeComponent::ComponentType::YEAR:
332 if (granularity < DatetimeGranularity::GRANULARITY_YEAR) {
333 granularity = DatetimeGranularity::GRANULARITY_YEAR;
334 }
335 break;
336
337 case DatetimeComponent::ComponentType::MONTH:
338 if (granularity < DatetimeGranularity::GRANULARITY_MONTH) {
339 granularity = DatetimeGranularity::GRANULARITY_MONTH;
340 }
341 break;
342
343 case DatetimeComponent::ComponentType::WEEK:
344 if (granularity < DatetimeGranularity::GRANULARITY_WEEK) {
345 granularity = DatetimeGranularity::GRANULARITY_WEEK;
346 }
347 break;
348
349 case DatetimeComponent::ComponentType::DAY_OF_WEEK:
350 case DatetimeComponent::ComponentType::DAY_OF_MONTH:
351 if (granularity < DatetimeGranularity::GRANULARITY_DAY) {
352 granularity = DatetimeGranularity::GRANULARITY_DAY;
353 }
354 break;
355
356 case DatetimeComponent::ComponentType::HOUR:
357 if (granularity < DatetimeGranularity::GRANULARITY_HOUR) {
358 granularity = DatetimeGranularity::GRANULARITY_HOUR;
359 }
360 break;
361
362 case DatetimeComponent::ComponentType::MINUTE:
363 if (granularity < DatetimeGranularity::GRANULARITY_MINUTE) {
364 granularity = DatetimeGranularity::GRANULARITY_MINUTE;
365 }
366 break;
367
368 case DatetimeComponent::ComponentType::SECOND:
369 if (granularity < DatetimeGranularity::GRANULARITY_SECOND) {
370 granularity = DatetimeGranularity::GRANULARITY_SECOND;
371 }
372 break;
373
374 case DatetimeComponent::ComponentType::MERIDIEM:
375 case DatetimeComponent::ComponentType::ZONE_OFFSET:
376 case DatetimeComponent::ComponentType::DST_OFFSET:
377 default:
378 break;
379 }
380 }
381 return granularity;
382 }
383 } // namespace
384
GetFinestGranularity() const385 DatetimeGranularity DatetimeParsedData::GetFinestGranularity() const {
386 std::vector<DatetimeComponent::ComponentType> component_types;
387 std::transform(date_time_components_.begin(), date_time_components_.end(),
388 std::back_inserter(component_types),
389 [](const std::map<DatetimeComponent::ComponentType,
390 DatetimeComponent>::value_type& pair) {
391 return pair.first;
392 });
393 return GetFinestGranularityFromComponentTypes(component_types);
394 }
395
GetDatetimeComponent(const std::vector<DatetimeComponent> & datetime_components,const DatetimeComponent::ComponentType & component_type)396 Optional<DatetimeComponent> GetDatetimeComponent(
397 const std::vector<DatetimeComponent>& datetime_components,
398 const DatetimeComponent::ComponentType& component_type) {
399 for (auto datetime_component : datetime_components) {
400 if (datetime_component.component_type == component_type) {
401 return Optional<DatetimeComponent>(datetime_component);
402 }
403 }
404 return Optional<DatetimeComponent>();
405 }
406
407 // Returns the granularity of the DatetimeComponents.
GetFinestGranularity(const std::vector<DatetimeComponent> & datetime_component)408 DatetimeGranularity GetFinestGranularity(
409 const std::vector<DatetimeComponent>& datetime_component) {
410 std::vector<DatetimeComponent::ComponentType> component_types;
411 std::transform(datetime_component.begin(), datetime_component.end(),
412 std::back_inserter(component_types),
413 [](const DatetimeComponent& component) {
414 return component.component_type;
415 });
416 return GetFinestGranularityFromComponentTypes(component_types);
417 }
418
419 } // namespace libtextclassifier3
420