-
Notifications
You must be signed in to change notification settings - Fork 15.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
community: Add configurable
VisualFeatures
to the `AzureAiServicesI…
…mageAnalysisTool` (#27444) Thank you for contributing to LangChain! - [ ] **PR title**: community: Add configurable `VisualFeatures` to the `AzureAiServicesImageAnalysisTool` - [ ] **PR message**: - **Description:** The `AzureAiServicesImageAnalysisTool` is a good service and utilises the Azure AI Vision package under the hood. However, since the creation of this tool, new `VisualFeatures` have been added to allow the user to request other image specific information to be returned. Currently, the tool offers neither configuration of which features should be return nor does it offer any newer feature types. The aim of this PR is to address this and expose more of the Azure Service in this integration. - **Dependencies:** no new dependencies in the main class file, azure.ai.vision.imageanalysis added to extra test dependencies file. - [ ] **Add tests and docs**: If you're adding a new integration, please include 1. Although no tests exist for already implemented Azure Service tools, I've created 3 unit tests for this class that test initialisation and credentials, local file analysis and a test for the new changes/ features option. - [ ] **Lint and test**: All linting has passed. --------- Co-authored-by: Erick Friis <erick@langchain.dev> Co-authored-by: Chester Curme <chester.curme@gmail.com>
- Loading branch information
1 parent
1c120e9
commit 580a8d5
Showing
4 changed files
with
182 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
127 changes: 127 additions & 0 deletions
127
libs/community/tests/unit_tests/tools/azure_ai_services/test_image_analysis.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
"""Tests for the Azure AI Services Image Analysis Tool.""" | ||
|
||
from pathlib import Path | ||
from typing import Any | ||
|
||
import pytest | ||
|
||
from langchain_community.tools.azure_ai_services.image_analysis import ( | ||
AzureAiServicesImageAnalysisTool, | ||
) | ||
|
||
this_dir = Path(__file__).parents[3] | ||
|
||
examples_dir = this_dir / "examples" | ||
building_path = examples_dir / "building.jpg" | ||
|
||
|
||
@pytest.mark.requires("azure.ai.vision.imageanalysis") | ||
def test_content_safety(mocker: Any) -> None: | ||
mocker.patch("azure.ai.vision.imageanalysis.ImageAnalysisClient", autospec=True) | ||
mocker.patch("azure.core.credentials.AzureKeyCredential", autospec=True) | ||
|
||
key = "key" | ||
endpoint = "endpoint" | ||
|
||
tool = AzureAiServicesImageAnalysisTool( | ||
azure_ai_services_key=key, azure_ai_services_endpoint=endpoint | ||
) | ||
assert tool.azure_ai_services_key == key | ||
assert tool.azure_ai_services_endpoint == endpoint | ||
|
||
|
||
@pytest.mark.requires("azure.ai.vision.imageanalysis") | ||
def test_local_image_analysis(mocker: Any) -> None: | ||
key = "key" | ||
endpoint = "endpoint" | ||
|
||
mocker.patch("azure.ai.vision.imageanalysis.ImageAnalysisClient", autospec=True) | ||
mocker.patch("azure.core.credentials.AzureKeyCredential", autospec=True) | ||
mocker.patch( | ||
"langchain_community.tools.azure_ai_services.utils.detect_file_src_type", | ||
return_value="local", | ||
) | ||
|
||
tool = AzureAiServicesImageAnalysisTool( | ||
azure_ai_services_key=key, | ||
azure_ai_services_endpoint=endpoint, | ||
visual_features=["CAPTION"], | ||
) | ||
|
||
mock_content_client = mocker.Mock() | ||
mock_content_client.analyze.return_value = mocker.Mock() | ||
mock_content_client.analyze.return_value.caption.text = "A building corner." | ||
|
||
mock_content_client.analyze.return_value.objects = None | ||
mock_content_client.analyze.return_value.tags = None | ||
mock_content_client.analyze.return_value.read = None | ||
mock_content_client.analyze.return_value.dense_captions = None | ||
mock_content_client.analyze.return_value.smart_crops = None | ||
mock_content_client.analyze.return_value.people = None | ||
|
||
tool.image_analysis_client = mock_content_client | ||
|
||
input = str(building_path) | ||
output = "Caption: A building corner." | ||
|
||
result = tool._run(input) | ||
assert result == output | ||
|
||
|
||
@pytest.mark.requires("azure.ai.vision.imageanalysis") | ||
def test_local_image_different_features(mocker: Any) -> None: | ||
key = "key" | ||
endpoint = "endpoint" | ||
|
||
mocker.patch("azure.ai.vision.imageanalysis.ImageAnalysisClient", autospec=True) | ||
mocker.patch("azure.core.credentials.AzureKeyCredential", autospec=True) | ||
mocker.patch( | ||
"langchain_community.tools.azure_ai_services.utils.detect_file_src_type", | ||
return_value="local", | ||
) | ||
|
||
tool = AzureAiServicesImageAnalysisTool( | ||
azure_ai_services_key=key, | ||
azure_ai_services_endpoint=endpoint, | ||
visual_features=["PEOPLE", "CAPTION", "SMARTCROPS"], | ||
) | ||
|
||
mock_content_client = mocker.Mock() | ||
mock_content_client.analyze.return_value = mocker.Mock() | ||
mock_content_client.analyze.return_value.caption.text = "A building corner." | ||
|
||
mock_content_client.analyze.return_value.objects = None | ||
mock_content_client.analyze.return_value.tags = None | ||
mock_content_client.analyze.return_value.read = None | ||
mock_content_client.analyze.return_value.dense_captions = None | ||
|
||
mock_smart_crops = mocker.MagicMock() | ||
mock_smart_crops.list = [ | ||
{"aspectRatio": 1.97, "boundingBox": {"x": 43, "y": 24, "w": 853, "h": 432}} | ||
] | ||
mock_smart_crops.__len__.return_value = 1 | ||
mock_content_client.analyze.return_value.smart_crops = mock_smart_crops | ||
|
||
mock_people = mocker.MagicMock() | ||
mock_people.list = [ | ||
{ | ||
"boundingBox": {"x": 454, "y": 44, "w": 408, "h": 531}, | ||
"confidence": 0.9601945281028748, | ||
}, | ||
] | ||
mock_people.__len__.return_value = 1 | ||
mock_content_client.analyze.return_value.people = mock_people | ||
|
||
tool.image_analysis_client = mock_content_client | ||
|
||
input = str(building_path) | ||
output = ( | ||
"Caption: A building corner.\n" | ||
"Smart Crops: {'aspectRatio': 1.97," | ||
" 'boundingBox': {'x': 43, 'y': 24, 'w': 853, 'h': 432}}\n" | ||
"People: {'boundingBox': {'x': 454, 'y': 44, 'w': 408, 'h': 531}," | ||
" 'confidence': 0.9601945281028748}" | ||
) | ||
|
||
result = tool._run(input) | ||
assert result == output |