Add experimental machine learning

This commit is contained in:
Machine Learning
2021-06-18 12:27:29 +07:00
committed by Javi Martín
parent c8d8fae98d
commit 4d27bbebad
84 changed files with 2845 additions and 30 deletions

View File

@@ -0,0 +1,25 @@
<div class="tabs-panel machine-learning-help" id="help">
<h3><%= t("admin.machine_learning.help.title_1") %></h3>
<p><%= t("admin.machine_learning.help.description_1") %></p>
<h3><%= t("admin.machine_learning.help.title_2") %></h3>
<p><%= t("admin.machine_learning.help.description_2") %></p>
<h3><%= t("admin.machine_learning.help.title_3") %></h3>
<p><%= t("admin.machine_learning.help.description_3") %></p>
<h3><%= t("admin.machine_learning.help.title_4") %></h3>
<ul>
<li><%= t("admin.machine_learning.help.description_4") %></li>
<li><%= sanitize(t("admin.machine_learning.help.description_4b")) %></li>
<li><%= sanitize(t("admin.machine_learning.help.description_4c")) %></li>
<li><%= sanitize(t("admin.machine_learning.help.description_4d")) %></li>
<li><%= sanitize(t("admin.machine_learning.help.description_4e")) %></li>
<li><%= t("admin.machine_learning.help.description_4f") %></li>
<li><%= sanitize(t("admin.machine_learning.help.description_4g")) %></li>
</ul>
<h3><%= t("admin.machine_learning.help.title_5") %></h3>
<p><%= t("admin.machine_learning.help.description_5") %></p>
<code><%= instructions %></code>
</div>

View File

@@ -0,0 +1,17 @@
class Admin::MachineLearning::HelpComponent < ApplicationComponent
private
def instructions
<<~INSTRUCTIONS
sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt install python3.7
sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.7 1
curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py
python get-pip.py
sudo update-alternatives --install /usr/bin/pip pip /home/deploy/.local/bin/pip3.7 1
pip install pandas
INSTRUCTIONS
end
end

View File

@@ -0,0 +1,63 @@
<div class="tabs-panel is-active machine-learning-scripts" id="scripts">
<% if machine_learning_job.errored? %>
<div class="callout alert">
<p>
<strong><%= t("admin.machine_learning.notice.error") %></strong>
</p>
<dl>
<dt><%= t("admin.machine_learning.executed_by") %></dt>
<dd><%= machine_learning_job.user.name %></dd>
<dt><%= t("admin.machine_learning.script_name") %></dt>
<dd><%= machine_learning_job.script %></dd>
<dt><%= t("admin.machine_learning.error") %></dt>
<dd><%= sanitize(machine_learning_job.error) %></dd>
</dl>
</div>
<% elsif machine_learning_job.finished? %>
<div class="callout success">
<strong><%= t("admin.machine_learning.notice.success") %></strong>
</div>
<% elsif machine_learning_job.started? %>
<div class="callout warning">
<p>
<strong><%= t("admin.machine_learning.notice.working") %></strong>
</p>
<dl>
<dt><%= t("admin.machine_learning.executed_by") %></dt>
<dd><%= machine_learning_job.user.name %></dd>
<dt><%= t("admin.machine_learning.script_name") %></dt>
<dd><%= machine_learning_job.script %></dd>
<dt><%= t("admin.machine_learning.started_at") %></dt>
<dd><%= machine_learning_job.started_at %></dd>
</dl>
</div>
<% end %>
<% if machine_learning_job.running_for_too_long? %>
<%= button_to t("admin.machine_learning.cancel"),
cancel_admin_machine_learning_path,
method: :delete, class: "cancel",
data: { confirm: t("admin.machine_learning.cancel_alert") } %>
<% elsif machine_learning_job.errored? || !machine_learning_job.started? || machine_learning_job.finished? %>
<%= form_tag execute_admin_machine_learning_path, method: :post do %>
<label for="script"><%= t("admin.machine_learning.select_script") %></label>
<%= select_tag "script", options_for_select(script_select_options) %>
<div id="script_descriptions">
<% scripts_info.each_with_index do |script_info, index| %>
<div id="<%= script_info[:name] %>" class="help-text">
<%= sanitize(script_info[:description]) %>
</div>
<% end %>
</div>
<%= submit_tag t("admin.machine_learning.execute_script") %>
<% end %>
<% end %>
</div>

View File

@@ -0,0 +1,17 @@
class Admin::MachineLearning::ScriptsComponent < ApplicationComponent
attr_reader :machine_learning_job
def initialize(machine_learning_job)
@machine_learning_job = machine_learning_job
end
private
def script_select_options
scripts_info.map { |info| [info[:name], { "aria-describedby": info[:name] }] }
end
def scripts_info
@scripts_info ||= ::MachineLearning.scripts_info
end
end

View File

@@ -0,0 +1,40 @@
<div class="card machine-learning-setting" id="<%= dom_id(setting) %>">
<div class="card-divider">
<h3 id="machine_learning_<%= kind %>"><%= t("admin.machine_learning.#{kind}") %></h3>
</div>
<div class="card-section">
<p id="machine_learning_<%= kind %>_description"><%= t("admin.machine_learning.#{kind}_description") %></p>
<% if ml_info.present? %>
<%= form_for(setting, url: admin_setting_path(setting), method: :put) do |f| %>
<%= f.hidden_field :tab, value: "#settings", id: "setting_tab_#{kind}" %>
<%= f.hidden_field :value, value: (setting.enabled? ? "" : "active"), id: "setting_value_#{kind}" %>
<%= f.button(t("shared.#{setting.enabled? ? "yes" : "no"}"),
"aria-labelledby": "machine_learning_#{kind}",
"aria-describedby": "machine_learning_#{kind}_description",
"aria-pressed": setting.enabled?) %>
<% end %>
<dl class="callout success">
<dt><strong><%= t("admin.machine_learning.last_execution") %></strong></dt>
<dd>
<strong><%= render Admin::DateRangeComponent.new(ml_info.generated_at, ml_info.updated_at) %></strong>
</dd>
<dt><%= t("admin.machine_learning.executed_script") %></dt>
<dd><%= ml_info.script %></dd>
<dt><%= t("admin.machine_learning.output_files") %></dt>
<dd>
<% filenames.each do |filename| %>
<a href="<%= data_path(filename) %>" target="_blank"><%= filename %></a><br>
<% end %>
</dd>
</dl>
<% else %>
<div class="callout secondary">
<%= t("admin.machine_learning.no_content") %>
</div>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,25 @@
class Admin::MachineLearning::SettingComponent < ApplicationComponent
attr_reader :kind
def initialize(kind)
@kind = kind
end
private
def setting
@setting ||= Setting.find_by(key: "machine_learning.#{kind}")
end
def ml_info
@ml_info ||= MachineLearningInfo.for(kind)
end
def filenames
::MachineLearning.data_output_files[ml_info.kind.to_sym].sort
end
def data_path(filename)
::MachineLearning.data_path(filename)
end
end

View File

@@ -0,0 +1,15 @@
<div class="tabs-panel machine-learning-settings" id="settings">
<div class="settings-management">
<% script_kinds.each do |kind| %>
<%= render Admin::MachineLearning::SettingComponent.new(kind) %>
<% end %>
</div>
<div class="callout secondary">
<p><strong><%= t("admin.machine_learning.data_folder_content") %></strong></p>
<% filenames.each do |filename| %>
<a href="<%= data_path(filename) %>" target="_blank"><%= filename %></a><br>
<% end %>
</div>
</div>

View File

@@ -0,0 +1,15 @@
class Admin::MachineLearning::SettingsComponent < ApplicationComponent
private
def script_kinds
@script_kinds ||= ::MachineLearning.script_kinds
end
def filenames
::MachineLearning.data_intermediate_files
end
def data_path(filename)
::MachineLearning.data_path(filename)
end
end

View File

@@ -0,0 +1,39 @@
<%= header %>
<% if enabled? %>
<div class="callout primary experimental-feature">
<strong><%= sanitize(t("admin.machine_learning.help_text")) %></strong>
</div>
<ul class="tabs" data-tabs id="machine_learning_tabs" data-deep-link="true">
<li class="tabs-title is-active">
<a href="#scripts">
<%= t("admin.machine_learning.tab_scripts") %>
</a>
</li>
<li class="tabs-title">
<a href="#settings">
<%= t("admin.machine_learning.tab_settings") %>
</a>
</li>
<li class="tabs-title">
<a href="#help">
<%= t("admin.machine_learning.tab_help") %>
</a>
</li>
</ul>
<div class="tabs-content" data-tabs-content="machine_learning_tabs">
<%= render Admin::MachineLearning::ScriptsComponent.new(machine_learning_job) %>
<%= render Admin::MachineLearning::SettingsComponent.new %>
<%= render Admin::MachineLearning::HelpComponent.new %>
</div>
<% else %>
<div class="callout primary">
<p>
<%= sanitize(t("admin.machine_learning.feature_disabled",
link: link_to(t("admin.machine_learning.feature_disabled_link"),
admin_settings_path(anchor: "tab-feature-flags")))) %>
</p>
</div>
<% end %>

View File

@@ -0,0 +1,18 @@
class Admin::MachineLearning::ShowComponent < ApplicationComponent
include Header
attr_reader :machine_learning_job
def initialize(machine_learning_job)
@machine_learning_job = machine_learning_job
end
def title
t("admin.machine_learning.title")
end
private
def enabled?
::MachineLearning.enabled?
end
end