# Multiple references
score = metric.score(
    output="Hello world!",
    reference=["Hello planet", "Hello world"]
)
print(score.value, score.reason)

```

Use `CorpusBLEU` to compute corpus-level BLEU for multiple candidates vs. multiple references. Each candidate and its references align by index in the list:

```python
from opik.evaluation.metrics import CorpusBLEU

metric = CorpusBLEU()

outputs = ["Hello there", "This is a test."]
references = [
    # For the first candidate, two references
    ["Hello world", "Hello there"],
    # For the second candidate, one reference
    "This is a test."
]

score = metric.score(output=outputs, reference=references)
print(score.value, score.reason)
```

You can also customize n-grams, smoothing methods, or weights:

```python
from opik.evaluation.metrics import SentenceBLEU

metric = SentenceBLEU(
    n_grams=4,
    smoothing_method="method2",
    weights=[0.25, 0.25, 0.25, 0.25]
)

score = metric.score(
    output="The cat sat on the mat",
    reference=["The cat is on the mat", "A cat sat here on the mat"]
)
print(score.value, score.reason)
```

**Note:** If any candidate or reference is empty, SentenceBLEU or CorpusBLEU will raise a MetricComputationError. Handle or validate inputs accordingly.

### ROUGE

`ROUGE` supports multiple variants out of the box: `rouge1`, `rouge2`, `rougeL`, and `rougeLsum`. You can switch variants via the `rouge_type` argument and optionally enable stemming or sentence splitting.

```python
from opik.evaluation.metrics import ROUGE

metric = ROUGE(rouge_type="rougeLsum", use_stemmer=True)
score = metric.score(
    output="The quick brown fox jumps over the lazy dog.",
    reference="A quick brown fox leapt over a very lazy dog."
)
print(score.value, score.reason)
```

Install `rouge-score` when using this metric:

```bash
pip install rouge-score
```

### GLEU

`GLEU` estimates grammatical fluency using n-gram overlap. It is useful when you care about fluency rather than exact lexical matches.

```python
from opik.evaluation.metrics import GLEU

metric = GLEU(min_len=1, max_len=4)
score = metric.score(
    output="I has a pen",
    reference=["I have a pen"]
)
print(score.value, score.reason)
```

Requires `nltk`:

```bash
pip install nltk
```

### BERTScore

`BERTScore` compares texts using contextual embeddings, offering a robust alternative to token-level similarity metrics. It produces precision, recall, and F1 scores (Opik reports the F1 by default).

```python
from opik.evaluation.metrics import BERTScore

metric = BERTScore(model_type="microsoft/deberta-xlarge-mnli")
score = metric.score(
    output="The cat sits on the mat.",
    reference="A cat is sitting on a mat."
)
print(score.value, score.reason)
```

Install the optional dependency before use:

```bash
pip install bert-score
```

### ChrF

`ChrF` computes the character n-gram F-score (`chrF` / `chrF++`). Adjust `beta`, `char_order`, and `word_order` to switch between the two variants.

```python
from opik.evaluation.metrics import ChrF

metric = ChrF(beta=2.0, char_order=6, word_order=2)
score = metric.score(
    output="The cat sat on the mat",
    reference="A cat sits upon the mat"
)
print(score.value, score.reason)
```

This metric relies on NLTK:

```bash
pip install nltk
```

### Distribution metrics

Histogram-based metrics compare token distributions between candidate and reference texts. They are helpful when you want to match style, vocabulary, or topical coverage.

#### JSDivergence

Returns `1 - Jensen–Shannon divergence`, giving a similarity score between 0.0 and 1.0.

```python
from opik.evaluation.metrics import JSDivergence

metric = JSDivergence()
score = metric.score(
    output="Dogs chase balls",
    reference="Cats chase toys"
)
print(score.value, score.reason)
```

#### JSDistance

Wraps the same computation but returns the raw divergence (0.0 means identical distributions).

```python
from opik.evaluation.metrics import JSDistance

metric = JSDistance()
score = metric.score(output="hello world", reference="hello there")
print(score.value, score.reason)
```

#### KLDivergence

Computes the KL divergence with optional smoothing and direction control.

```python
from opik.evaluation.metrics import KLDivergence

metric = KLDivergence(direction="avg")
score = metric.score(output="a b b", reference="a a b")
print(score.value, score.reason)
```

### Language Adherence

`LanguageAdherenceMetric` checks whether text matches an expected ISO language code. It can use a fastText language identification model or a custom detector callable.

```python
from opik.evaluation.metrics import LanguageAdherenceMetric

metric = LanguageAdherenceMetric(
    expected_language="en",
    model_path="/path/to/lid.176.ftz",
)
score = metric.score(output="Hello, how are you?")
print(score.value, score.reason, score.metadata)
```

Install `fasttext` and download a language ID model when using the default detector:

```bash
pip install fasttext
```

### Readability

`Readability` computes Flesch Reading Ease (0–100) and the Flesch–Kincaid grade using the `textstat` package. The metric returns the reading-ease score normalised to `[0, 1]`.

```python
from opik.evaluation.metrics import Readability

metric = Readability()
score = metric.score(output="This is a simple explanation of the payment process.")
print(score.value, score.reason)
print(score.metadata["flesch_kincaid_grade"])
```

Install the optional dependency when using this metric:

```bash
pip install textstat
```

Pass `enforce_bounds=True` alongside `min_grade` and/or `max_grade` to turn the metric into a strict guardrail that only reports 1.0 when the text meets your grade limits.

### Spearman Ranking

`SpearmanRanking` measures how well two rankings agree. It returns a normalised correlation score in `[0, 1]`.

```python
from opik.evaluation.metrics import SpearmanRanking

metric = SpearmanRanking()
score = metric.score(
    output=["doc3", "doc1", "doc2"],
    reference=["doc1", "doc2", "doc3"],
)
print(score.value, score.metadata["rho"])
```

### Tone

`Tone` flags outputs that sound aggressive, negative, or violate a list of forbidden phrases. You can tweak sentiment thresholds, uppercase ratios, and exclamation limits.

```python
from opik.evaluation.metrics import Tone

metric = Tone(max_exclamations=1)
score = metric.score(output="THIS IS TERRIBLE!!!")
print(score.value, score.reason)
print(score.metadata)
```

### Sentiment

The Sentiment metric analyzes the sentiment of text using NLTK's VADER (Valence Aware Dictionary and sEntiment Reasoner) sentiment analyzer. It returns scores for positive, neutral, negative, and compound sentiment.

You will need the nltk library and the vader\_lexicon:

```bash
pip install nltk
python -m nltk.downloader vader_lexicon
```

Use `Sentiment` to analyze the sentiment of text:

```python
from opik.evaluation.metrics import Sentiment

metric = Sentiment()