| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "peridot/bin/suggestion_engine/ranking_features/mod_pair_ranking_feature.h" |
| |
| #include <lib/context/cpp/context_helper.h> |
| #include <lib/fxl/logging.h> |
| |
| #include "rapidjson/document.h" |
| #include "rapidjson/schema.h" |
| |
| namespace modular { |
| |
| namespace { |
| // Sample map using data collected between Feb 6-20, 2018 |
| constexpr char kDataFilePath[] = "/pkg/data/ranking_data/mod_pairs.json"; |
| } // namespace |
| |
| ModPairRankingFeature::ModPairRankingFeature(const bool init_data) { |
| if (init_data) { |
| LoadDataFromFile(kDataFilePath); |
| } |
| } |
| |
| ModPairRankingFeature::~ModPairRankingFeature() = default; |
| |
| void ModPairRankingFeature::LoadDataFromFile(const std::string& filepath) { |
| auto maybe_result = FetchJsonObject(filepath); |
| if (!maybe_result.has_value()) { |
| FXL_LOG(WARNING) << "Failed to fetch mod pairs ranking feature data."; |
| return; |
| } |
| auto& result = maybe_result.value(); |
| module_pairs_.clear(); |
| for (rapidjson::Value::ConstMemberIterator iter = result.MemberBegin(); |
| iter != result.MemberEnd(); ++iter) { |
| const std::string existing_mod_url = iter->name.GetString(); |
| rapidjson::Value& other_mods = result[existing_mod_url.c_str()]; |
| for (rapidjson::Value::ConstMemberIterator iter2 = other_mods.MemberBegin(); |
| iter2 != other_mods.MemberEnd(); ++iter2) { |
| const std::string added_mod_url = iter2->name.GetString(); |
| module_pairs_[existing_mod_url][added_mod_url] = iter2->value.GetDouble(); |
| } |
| } |
| } |
| |
| double ModPairRankingFeature::ComputeFeatureInternal( |
| const fuchsia::modular::UserInput& query, |
| const RankedSuggestion& suggestion) { |
| double prob = 0.0; |
| |
| for (auto& command : *suggestion.prototype->proposal.on_selected) { |
| fidl::StringPtr module_url; |
| switch (command.Which()) { |
| case fuchsia::modular::StoryCommand::Tag::kAddMod: { |
| module_url = command.add_mod().intent.handler; |
| break; |
| } |
| case fuchsia::modular::StoryCommand::Tag::kSetKindOfProtoStoryOption: |
| case fuchsia::modular::StoryCommand::Tag::kSetFocusState: |
| case fuchsia::modular::StoryCommand::Tag::kFocusMod: |
| case fuchsia::modular::StoryCommand::Tag::kSetLinkValue: |
| case fuchsia::modular::StoryCommand::Tag::kUpdateMod: |
| case fuchsia::modular::StoryCommand::Tag::kRemoveMod: |
| case fuchsia::modular::StoryCommand::Tag::Invalid: |
| continue; |
| } |
| if (module_url.is_null() || module_url->empty()) { |
| continue; |
| } |
| // Currently computing: max{P(m|mi) for mi in modules_in_source_story} |
| // TODO(miguelfrde): compute P(module_url | modules in source story) |
| for (auto& context_value : *ContextValues()) { |
| const std::string existing_mod_url = context_value.meta.mod->url; |
| if (module_pairs_.count(existing_mod_url) && |
| module_pairs_[existing_mod_url].count(module_url)) { |
| prob = std::max(prob, module_pairs_[existing_mod_url][module_url]); |
| } |
| } |
| } |
| return prob; |
| } |
| |
| fuchsia::modular::ContextSelectorPtr |
| ModPairRankingFeature::CreateContextSelectorInternal() { |
| // Get modules in the currently focused story. |
| auto selector = fuchsia::modular::ContextSelector::New(); |
| selector->type = fuchsia::modular::ContextValueType::MODULE; |
| selector->meta = fuchsia::modular::ContextMetadata::New(); |
| selector->meta->story = fuchsia::modular::StoryMetadata::New(); |
| selector->meta->story->focused = fuchsia::modular::FocusedState::New(); |
| selector->meta->story->focused->state = |
| fuchsia::modular::FocusedStateState::FOCUSED; |
| return selector; |
| } |
| |
| } // namespace modular |