class EmbeddingModelTextClassifier<E extends Enum<E>> implements TextClassifier<E> {

    private final EmbeddingModel embeddingModel;
    private final Map<E, List<Embedding>> exampleEmbeddingsByLabel;
    private final int maxResults;
    private final double minScore;
    private final double meanToMaxScoreRatio;

    /**
     * Creates a classifier with the default values for {@link #maxResults} (1), {@link #minScore} (0)
     * and {@link #meanToMaxScoreRatio} (0.5).
     *
     * @param embeddingModel  The embedding model used for embedding both the examples and the text to be classified.
     * @param examplesByLabel A map containing examples of texts for each label.
     *                        The more examples, the better. Examples can be easily generated by the LLM.
     */
    public EmbeddingModelTextClassifier(EmbeddingModel embeddingModel,
                                        Map<E, ? extends Collection<String>> examplesByLabel) {
        this(embeddingModel, examplesByLabel, 1, 0, 0.5);
    }

    /**
     * Creates a classifier.
     *
     * @param embeddingModel      The embedding model used for embedding both the examples and the text to be classified.
     * @param examplesByLabel     A map containing examples of texts for each label.
     *                            The more examples, the better. Examples can be easily generated by the LLM.
     * @param maxResults          The maximum number of labels to return for each classification.
     * @param minScore            The minimum similarity score required for classification, in the range [0..1].
     *                            Labels scoring lower than this value will be discarded.
     * @param meanToMaxScoreRatio A ratio, in the range [0..1], between the mean and max scores used for calculating
     *                            the final score.
     *                            During classification, the embeddings of examples for each label are compared to
     *                            the embedding of the text being classified.
     *                            This results in two metrics: the mean and max scores.
     *                            The mean score is the average similarity score for all examples associated with a given label.
     *                            The max score is the highest similarity score, corresponding to the example most
     *                            similar to the text being classified.
     *                            A value of 0 means that only the mean score will be used for ranking labels.
     *                            A value of 0.5 means that both scores will contribute equally to the final score.
     *                            A value of 1 means that only the max score will be used for ranking labels.
     */
    public EmbeddingModelTextClassifier(EmbeddingModel embeddingModel,
                                        Map<E, ? extends Collection<String>> examplesByLabel,
                                        int maxResults,
                                        double minScore,
                                        double meanToMaxScoreRatio) {
        this.embeddingModel = ensureNotNull(embeddingModel, "embeddingModel");
        ensureNotNull(examplesByLabel, "examplesByLabel");

        this.exampleEmbeddingsByLabel = new HashMap<>();
        examplesByLabel.forEach((label, examples) ->
                exampleEmbeddingsByLabel.put(label, examples.stream()
                        .map(example -> embeddingModel.embed(example).content())
                        .collect(toList()))
        );

        this.maxResults = ensureGreaterThanZero(maxResults, "maxResults");
        this.minScore = ensureBetween(minScore, 0.0, 1.0, "minScore");
        this.meanToMaxScoreRatio = ensureBetween(meanToMaxScoreRatio, 0.0, 1.0, "meanToMaxScoreRatio");
    }

    @Override
    public List<E> classify(String text) {

        Embedding textEmbedding = embeddingModel.embed(text).content();

        List<LabelWithScore> labelsWithScores = new ArrayList<>();
        exampleEmbeddingsByLabel.forEach((label, exampleEmbeddings) -> {

            double meanScore = 0;
            double maxScore = 0;
            for (Embedding exampleEmbedding : exampleEmbeddings) {
                double cosineSimilarity = CosineSimilarity.between(textEmbedding, exampleEmbedding);
                double score = RelevanceScore.fromCosineSimilarity(cosineSimilarity);
                meanScore += score;
                maxScore = Math.max(score, maxScore);
            }
            meanScore /= exampleEmbeddings.size();

            labelsWithScores.add(new LabelWithScore(label, aggregatedScore(meanScore, maxScore)));
        });

        return labelsWithScores.stream()
                .filter(it -> it.score >= minScore)
                // sorting in descending order to return highest score first
                .sorted(comparingDouble(labelWithScore -> 1 - labelWithScore.score))
                .limit(maxResults)
                .map(it -> it.label)
                .collect(toList());
    }

    private double aggregatedScore(double meanScore, double maxScore) {<FILL_FUNCTION_BODY>}

    private class LabelWithScore {

        private final E label;
        private final double score;

        private LabelWithScore(E label, double score) {
            this.label = label;
            this.score = score;
        }
    }
}

        return (meanToMaxScoreRatio * meanScore) + ((1 - meanToMaxScoreRatio) * maxScore);
    
<no_super_class>