code: def rouge_n(eval_sentences, ref_sentences, n=2):
    
    f1_scores = []
    for eval_sentence, ref_sentence in zip(eval_sentences, ref_sentences):
      eval_ngrams = _get_ngrams(n, eval_sentence)
      ref_ngrams = _get_ngrams(n, ref_sentence)
      ref_count = len(ref_ngrams)
      eval_count = len(eval_ngrams)
  
      # Count the overlapping ngrams between evaluated and reference
      overlapping_ngrams = eval_ngrams.intersection(ref_ngrams)
      overlapping_count = len(overlapping_ngrams)
  
      # Handle edge case. This isn't mathematically correct, but it's good enough
      if eval_count == 0:
        precision = 0.0
      else:
        precision = float(overlapping_count) / eval_count
      if ref_count == 0:
        recall = 0.0
      else:
        recall = float(overlapping_count) / ref_count
      f1_scores.append(2.0 * ((precision * recall) / (precision + recall + 1e-8)))
  
    # return overlapping_count / reference_count
    return np.mean(f1_scores, dtype=np.float32)
docs: Computes ROUGE-N f1 score of two text collections of sentences.
  
    Source: https://www.microsoft.com/en-us/research/publication/
    rouge-a-package-for-automatic-evaluation-of-summaries/
  
    Args:
      eval_sentences: Predicted sentences.
      ref_sentences: Sentences from the reference set
      n: Size of ngram.  Defaults to 2.
  
    Returns:
      f1 score for ROUGE-N