expertiza/expertiza

View on GitHub
app/helpers/summary_helper.rb

Summary

Maintainability
A
1 hr
Test Coverage
F
19%
# require for webservice calls
require 'json'
require 'rest_client'
require 'logger'

# required by autosummary
module SummaryHelper
  class Summary
    attr_accessor :summary, :reviewers, :avg_scores_by_reviewee, :avg_scores_by_round, :avg_scores_by_criterion, :summary_ws_url

    def summarize_reviews_by_reviewee(questions, assignment, reviewee_id, summary_ws_url, _session = nil)
      self.summary = ({})
      self.avg_scores_by_round = ({})
      self.avg_scores_by_criterion = ({})
      self.summary_ws_url = summary_ws_url
      
      # get all answers for each question and send them to summarization WS
      questions.each_with_index do |question, index|
        round = index + 1
        summary[round.to_s] = {}
        avg_scores_by_criterion[round.to_s] = {}
        avg_scores_by_round[round.to_s] = 0.0
        
        question_iterator = nil
        if question[1] == nil
          question_iterator = [*question]
        else
          question_iterator = question[1]
        end

        question_iterator.each do |question| 
          next if question.type.eql?('SectionHeader')

          summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)
          avg_scores_by_round[round.to_s] = calculate_avg_score_by_round(avg_scores_by_criterion[round.to_s], questions[round])
        end
      end
      self
    end

    # get average scores and summary for each question in a review by a reviewer
    def summarize_reviews_by_reviewee_question(assignment, reviewee_id, question, round)
      question_answers = Answer.answers_by_question_for_reviewee(assignment.id, reviewee_id, question.id)

      avg_scores_by_criterion[round.to_s][question.txt] = calculate_avg_score_by_criterion(question_answers, get_max_score_for_question(question))

      summary[round.to_s][question.txt] = summarize_sentences(break_up_comments_to_sentences(question_answers), summary_ws_url)
    end

    def get_max_score_for_question(question)
      question.type.eql?('Checkbox') ? 1 : Questionnaire.where(id: question.questionnaire_id).first.max_question_score
    end

    def summarize_sentences(comments, summary_ws_url)
      logger = Logger.new(STDOUT)
      logger.level = Logger::WARN
      param = { sentences: comments }
      # call web service
      begin
        sum_json = RestClient.post summary_ws_url, param.to_json, content_type: :json, accept: :json
        # store each summary in a hashmap and use the question as the key
        summary = JSON.parse(sum_json)['summary']
        ps = PragmaticSegmenter::Segmenter.new(text: summary)
        return ps.segment
      rescue StandardError => e
        logger.warn "Standard Error: #{e.inspect}"
        return ['Problem with WebServices', 'Please contact the Expertiza Development team']
      end
    end

    # convert answers to each question to sentences
    def get_sentences(answer)
      sentences = answer.comments.gsub!(/[.?!]/, '\1|').try(:split, '|') || nil unless answer.nil? || answer.comments.nil?
      sentences.map!(&:strip) unless sentences.nil?
      sentences
    end

    def break_up_comments_to_sentences(question_answers)
      # store answers of each question in an array to be converted into json
      comments = []
      question_answers.each do |answer|
        sentences = get_sentences(answer)
        # add the comment to an array to be converted as a json request
        comments.concat(sentences) unless sentences.nil?
      end
      comments
    end

    def calculate_avg_score_by_criterion(question_answers, q_max_score)
      # get score and summary of answers for each question
      # only include divide the valid_answer_sum with the number of valid answers

      valid_answer_counter = 0
      question_score = 0.0
      question_answers.each do |question_answer|
        # calculate score per question
        unless question_answer.answer.nil?
          question_score += question_answer.answer
          valid_answer_counter += 1
        end
      end

      if (valid_answer_counter > 0) && (q_max_score > 0)
        # convert the score in percentage
        question_score /= (valid_answer_counter * q_max_score)
        question_score = question_score.round(2) * 100
      end

      question_score
    end

    def calculate_round_score(avg_scores_by_criterion, criterions)
      round_score = sum_weight = 0.0
      # include this score in the average round score if the weight is valid & q is criterion
      criterions = [*criterions]
      criterions.each do |criteria|
        if !criteria.weight.nil? && (criteria.weight > 0) && criteria.type.eql?('Criterion')
          round_score += avg_scores_by_criterion.values.first * criteria.weight
          sum_weight += criteria.weight
        end
      end
      round_score /= sum_weight if (sum_weight > 0) && (round_score > 0)
      round_score
    end

    def calculate_avg_score_by_round(avg_scores_by_criterion, criterions)
      round_score = calculate_round_score(avg_scores_by_criterion, criterions)
      round_score.round(2)
    end
  end
end

# end required by autosummary