Skip to content

Commit 641e2ed

Browse files
vertex-sdk-botcopybara-github
authored andcommitted
feat: GenAI Client(evals) - add rich HTML visualization for loss pattern analysis
PiperOrigin-RevId: 894799725
1 parent 7142c62 commit 641e2ed

3 files changed

Lines changed: 449 additions & 87 deletions

File tree

tests/unit/vertexai/genai/test_evals.py

Lines changed: 87 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,79 @@ def test_response_structure(self):
520520
assert result.clusters[0].item_count == 3
521521
assert result.clusters[1].cluster_id == "cluster-2"
522522

523-
def test_response_show_with_results(self, capsys):
523+
def test_get_loss_analysis_html(self):
524+
"""Tests that _get_loss_analysis_html generates valid HTML with data."""
525+
from vertexai._genai import _evals_visualization
526+
import json
527+
528+
data = {
529+
"results": [
530+
{
531+
"config": {
532+
"metric": "test_metric",
533+
"candidate": "test-candidate",
534+
},
535+
"clusters": [
536+
{
537+
"cluster_id": "c1",
538+
"taxonomy_entry": {
539+
"l1_category": "Tool Calling",
540+
"l2_category": "Missing Invocation",
541+
"description": "Agent failed to call the tool.",
542+
},
543+
"item_count": 5,
544+
"examples": [
545+
{
546+
"evaluation_result": {
547+
"request": {
548+
"prompt": {
549+
"agent_data": {
550+
"turns": [
551+
{
552+
"turn_index": 0,
553+
"events": [
554+
{
555+
"author": "user",
556+
"content": {
557+
"parts": [
558+
{
559+
"text": "Find flights to Paris"
560+
}
561+
],
562+
},
563+
}
564+
],
565+
}
566+
],
567+
},
568+
},
569+
},
570+
},
571+
"failed_rubrics": [
572+
{
573+
"rubric_id": "tool_use",
574+
"classification_rationale": "Did not invoke find_flights.",
575+
}
576+
],
577+
}
578+
],
579+
},
580+
],
581+
}
582+
]
583+
}
584+
html = _evals_visualization._get_loss_analysis_html(json.dumps(data))
585+
assert "Loss Pattern Analysis" in html
586+
assert "test_metric" not in html # data is Base64-encoded in the HTML
587+
assert "<!DOCTYPE html>" in html
588+
assert "extractScenarioPreview" in html
589+
assert "example-scenario" in html
590+
591+
def test_display_loss_clusters_response_no_ipython(self):
592+
"""Tests graceful fallback when not in IPython."""
593+
from vertexai._genai import _evals_visualization
594+
from unittest import mock
595+
524596
response = common_types.GenerateLossClustersResponse(
525597
results=[
526598
common_types.LossAnalysisResult(
@@ -541,12 +613,17 @@ def test_response_show_with_results(self, capsys):
541613
)
542614
],
543615
)
544-
response.show()
545-
captured = capsys.readouterr()
546-
assert "test_metric" in captured.out
547-
assert "c1" in captured.out
616+
with mock.patch.object(
617+
_evals_visualization, "_is_ipython_env", return_value=False
618+
):
619+
# Should not raise, just log a warning
620+
response.show()
621+
622+
def test_display_loss_analysis_result_no_ipython(self):
623+
"""Tests graceful fallback for individual result when not in IPython."""
624+
from vertexai._genai import _evals_visualization
625+
from unittest import mock
548626

549-
def test_loss_analysis_result_show(self, capsys):
550627
result = common_types.LossAnalysisResult(
551628
config=common_types.LossAnalysisConfig(
552629
metric="test_metric",
@@ -563,10 +640,10 @@ def test_loss_analysis_result_show(self, capsys):
563640
),
564641
],
565642
)
566-
result.show()
567-
captured = capsys.readouterr()
568-
assert "test_metric" in captured.out
569-
assert "c1" in captured.out
643+
with mock.patch.object(
644+
_evals_visualization, "_is_ipython_env", return_value=False
645+
):
646+
result.show()
570647

571648

572649
def _make_eval_result(

0 commit comments

Comments
 (0)