diff --git a/.env.example b/.env.example index 6c6a4fd03..6817eb98d 100644 --- a/.env.example +++ b/.env.example @@ -60,6 +60,3 @@ GOOGLE_CLIENT_SECRET=your_google_client_secret KEYCLOAK_REALM=quepid KEYCLOAK_SITE=http://keycloak:9080 - -# Whether or not to do analytics for interesting events in Case Scores -QUEPID_PROPHET_ANALYTICS=true diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb index 359adb5f5..4ea372bbe 100644 --- a/app/controllers/home_controller.rb +++ b/app/controllers/home_controller.rb @@ -6,6 +6,39 @@ def show @cases = @current_user.cases_involved_with.not_archived.with_counts @most_recent_cases = @current_user.cases_involved_with.not_archived.recent.limit(4).with_counts.sort_by(&:case_name) + + # Run the prophet! + @prophet_case_data = {} + @most_recent_cases.each do |kase| + data = kase.scores.sampled(kase.id,25).collect{ |score| {ds: score.created_at.to_date.to_fs(:db), y: score.score, datetime: score.created_at.to_date } }.uniq + # warning! blunt filter below! + data = data.uniq { |h| h[:ds] } + data = data.map {|h| h.transform_keys(&:to_s) } + + do_changepoints = data.length >= 3 ? true : false # need at least 3... + + if do_changepoints + df = Rover::DataFrame.new(data) + m = Prophet.new() + m.fit(df) + + last_changepoint = DateTime.parse(m.changepoints.last.to_s) + initial = data.find{ |h| h['datetime'].all_day.overlaps?(last_changepoint.all_day)}["y"] + final = kase.scores.last_one.score + change = 100 * (final - initial) / initial + + vega_data = data.map{ |d| {x: d['ds'], y: d['y']} } + + @prophet_case_data[kase.id] = { + initial: initial, + final: final, + change: change, + last_changepoint: last_changepoint, + vega_data: vega_data + } + end + + end @most_recent_books = [] @lookup_for_books = {} diff --git a/app/views/home/_case_summary.html.erb b/app/views/home/_case_summary.html.erb index cd856dcfa..c71ed29f5 100644 --- a/app/views/home/_case_summary.html.erb +++ b/app/views/home/_case_summary.html.erb @@ -8,70 +8,32 @@
<%= kase.last_score.score unless kase.scores.empty? %> <%= kase.scorer.name %>

<%= kase.created_at.to_date.to_fs(:short) %> - <%= kase.last_score.updated_at.to_date.to_fs(:short) unless kase.scores.empty?%>

- <% - data = kase.scores.sampled(kase.id,100).collect{ |score| {ds: score.created_at.to_date.to_fs(:db), y: score.score, datetime: score.created_at.to_date } }.uniq - # warning! blunt filter below! - data = data.uniq { |h| h[:ds] } - data = data.map {|h| h.transform_keys(&:to_s) } - - do_changepoints = data.length >= 3 ? true : false # need at least 3... - - if Rails.application.config.quepid_prophet_analytics && do_changepoints - df = Rover::DataFrame.new(data) - m = Prophet.new() - m.fit(df) - %> - - <% if change > 0 %> - <% if change.positive? %> -

<%= number_to_percentage(change, precision:0) %> increase since <%=time_ago_in_words(last_changepoint) %> ago

+ prophet_data = @prophet_case_data[kase.id] + if prophet_data + if prophet_data[:change] > 0 %> + <% if prophet_data[:change].positive? %> +

<%= number_to_percentage(prophet_data[:change] , precision:0) %> increase since <%=time_ago_in_words(prophet_data[:last_changepoint]) %> ago

<% else %> -

<%= number_to_percentage(change, precision:0) %> decrease since <%=time_ago_in_words(last_changepoint) %> ago

+

<%= number_to_percentage(prophet_data[:change] , precision:0) %> decrease since <%=time_ago_in_words(prophet_data[:last_changepoint]) %> ago

<% end %> <% end %> - <% end # if do_changepoint %> - - <% - # look at https://github.com/ankane/prophet-ruby to remove outliers. - data = kase.scores.sampled(kase.id, 100).collect{ |score| {x: score.created_at.to_date.to_fs(:db), y: score.score } }.uniq - # warning! blunt filter below! - data = data.uniq { |h| h[:x] } - %> - - - - - <%= Vega.lite - .data(data) - .mark(type: "line", tooltip: true, interpolate: "cardinal", point: {size: 60}) - .encoding( - x: {field: "x", type: "temporal", scale: {type: "utc"}, axis: {format: "%b %e"}}, - y: {field: "y", type: "quantitative"} - ) - .height(60) - .config(axis: {title: nil, labelFontSize: 12}) %> + + + + <%= Vega.lite + .data(prophet_data[:vega_data]) + .mark(type: "line", tooltip: true, interpolate: "cardinal", point: {size: 60}) + .encoding( + x: {field: "x", type: "temporal", scale: {type: "utc"}, axis: {format: "%b %e"}}, + y: {field: "y", type: "quantitative"} + ) + .height(60) + .config(axis: {title: nil, labelFontSize: 12}) %> + <% end # if prophet_data %> + diff --git a/app/views/home/show.html.erb b/app/views/home/show.html.erb index 6c1b73c3d..8b2244d36 100644 --- a/app/views/home/show.html.erb +++ b/app/views/home/show.html.erb @@ -12,9 +12,7 @@ https://getbootstrap.com/docs/5.2/examples/navbars-offcanvas/# for example of of
- <% if false %> <%= render partial: "case_summary", collection: @most_recent_cases, as: :kase %> - <% end %>
diff --git a/config/initializers/customize_quepid.rb b/config/initializers/customize_quepid.rb index 8338b9553..ac2c2164e 100644 --- a/config/initializers/customize_quepid.rb +++ b/config/initializers/customize_quepid.rb @@ -94,8 +94,3 @@ # == Disable redirecting to match the TLS setting Rails.application.config.redirect_to_match_search_engine_tls = ENV.fetch('REDIRECT_TO_MATCH_SEARCH_ENGINE_TLS', true) - -# == Prophet Analytics Control -# Prophet tells you interesting things about time series curves and is used on the homepage. -# It may consume too much memory for your environment, and you may need to disable it. -Rails.application.config.quepid_prophet_analytics = bool.deserialize(ENV.fetch('QUEPID_PROPHET_ANALYTICS', true)) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 5ae84eb9e..095a68170 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -46,7 +46,6 @@ services: - EMAIL_PROVIDER= - EMAIL_SENDER= - QUERY_LIST_SORTABLE=true - - QUEPID_PROPHET_ANALYTICS=true command: "foreman s -f Procfile" ports: # - 80:3000 # Map to port 80 for outside users when you are not using Nginx diff --git a/docs/operating_documentation.md b/docs/operating_documentation.md index 8281e85bd..4af05e184 100644 --- a/docs/operating_documentation.md +++ b/docs/operating_documentation.md @@ -177,17 +177,6 @@ the file `Procfile` Want to monitor if Quepid is behaving? Just monitor `/healthcheck`, and you will get 200 status codes from a healthy Quepid, and 503 if not. The JSON output is `{"code":200,"status":{"database":"OK","migrations":"OK"}}`. -## Analytics Settings - -We use the [Prophet.rb](https://github.com/ankane/prophet-ruby) library to decide when interesting things happen in our case scores on the homepage. -This library may use too much memory for your deploy, and can be disabled. - -You can disable this behavior by setting the follow `ENV` var: - -``` -QUEPID_PROPHET_ANALYTICS=false -``` - ## Troubleshoot Your Deploy When errors occur, Quepid logs them and shows a generic page.