In this segment, you’ll implement image moderation for your sample app, Fooder.
Open the Jupyter Lab in your browser. Then, open 03-image-moderation-with-azure-content-safety/Starter/starter.ipynb.
Start by importing the required packages for this demo. Replace # TODO: install the packages with the following:
# install the packages
%pip install azure-ai-contentsafety
%pip install python-dotenv
You may remember importing these packages in the last demo! To quickly summarize once again:
- azure-ai-contentsafety: This will install the Azure AI Content Safety library that you’ll use to create moderation requests
- python-dotenv: You’ll use this library to load your sensitive endpoint and api-key variable from the .env file.
Run the cell by pressing the Enter + Shift keys and wait for the installation to finish.
Next, import the packages that you’ll use in this notebook. Replace # TODO import packages with the following:
# 1
import os
# 2
from dotenv import load_dotenv
# 3
from azure.ai.contentsafety import ContentSafetyClient
from azure.ai.contentsafety.models import ImageCategory
from azure.core.credentials import AzureKeyCredential
from azure.core.exceptions import HttpResponseError
from azure.ai.contentsafety.models import AnalyzeImageOptions, ImageData
Here’s the explanation of the above code:
- You imported the os module. You’ll use this module to read the environment variables to fetch the content safety key and endpoint.
-
You then imported the
load_dotenvfunction from dotenv module. This function will load the key-value pairs from the .env file into environment variables. - Finally, you also imported various classes from the Azure AI contents safety package. You’ll use them to create image analysis requests, send requests, etc.
Run the cell to successfully import everything, and wait for the cell execution to finish.
Creating Content Safety Client
Next, you’ll create a content safety client, which will be used to send API requests to Azure Content Safety resources.Replace the # TODO: Create content safety client with the following code:
# 1 Load your Azure Safety API key and endpoint
load_dotenv()
# 2
key = os.environ["CONTENT_SAFETY_KEY"]
endpoint = os.environ["CONTENT_SAFETY_ENDPOINT"]
# 3 Create a Content Safety client
client = ContentSafetyClient(endpoint, AzureKeyCredential(key))
In the above code:
-
You’re using the
load_dotenvfunction to load the content from your .env file into the environment variables of your application. -
Next, you’re accessing the values of
CONTENT_SAFETY_KEYandCONTENT_SAFETY_ENDPOINTfrom the environment variables usingos.environ. These are assigned to the variables key and endpoint, which will be used to authenticate the API requests. -
Finally, you’re creating
ContentSafetyClientusing endpoint and key, and assigning it to client variable.
Make sure to copy the .env file that you created in lesson 2 in the present directory. Then, run the cell to create the content safety client.
Creating Moderate Image Function
Next, create the moderate_image function. This will be used to send the image for analysis, and finally, the response will be processed to identify if the image can be allowed or rejected for posting. Replace # TODO: Implement moderate image function with the following code:
# 1
def moderate_image(image_data):
# 2 Construct a request
request = AnalyzeImageOptions(image=ImageData(content=image_data))
# 3 Analyze image
try:
response = client.analyze_image(request)
except HttpResponseError as e:
print("Analyze image failed.")
if e.error:
print(f"Error code: {e.error.code}")
print(f"Error message: {e.error.message}")
raise
print(e)
raise
## TODO: Process moderation response to determine if the image
# is approved or rejected
# 4 If content is appropriate
return "Post successful"
Here’s what the following code does:
-
It creates the function
moderate_image, which takesimage_dataas an argument and returns whether the shared input is approved or rejected for posting. -
Then, it constructs the request using
AnalyzeImageOptions. You’ve provided the base64-encoded image toImageData, and is passed toAnalyzeImageOptionsusing animageargument. Also, by default,output_typeis set toFourSeverityLevels, where you only get 0,2,4,6 as the severity level output. -
You’re calling the
client.analyze_imageand passing the above-generated request inside it. You’ve also used thetry-exceptblock on the analyze image function to catch any exception and let the user know about it. -
Finally, if the content is appropriate, you return status as
"Post successful".
Next, it’s time to implement the logic to determine if the image is safe, and whether the request can be approved or rejected if it’s harmful/violates the platform rules. Replace ## TODO: Process moderation response to determine if the image is approved or rejected with the following code:
# 1 Extract results
categories = {
ImageCategory.HATE: None,
ImageCategory.SELF_HARM: None,
ImageCategory.SEXUAL: None,
ImageCategory.VIOLENCE: None
}
# 2
for item in response.categories_analysis:
if item.category in categories:
categories[item.category] = item
# 3
hate_result = categories[ImageCategory.HATE]
self_harm_result = categories[ImageCategory.SELF_HARM]
sexual_result = categories[ImageCategory.SEXUAL]
violence_result = categories[ImageCategory.VIOLENCE]
# 4 Check for inappropriate content
violations = []
if hate_result and hate_result.severity > 2:
violations.append("hate speech")
if self_harm_result and self_harm_result.severity > 3:
violations.append("self-harm references")
if sexual_result and sexual_result.severity > 0:
violations.append("sexual references")
if violence_result and violence_result.severity > 2:
violations.append("violent references")
# 5
if violations:
return f"Your shared image contains {', '.join(violations)} that violate
our community guidelines. Please modify your image to adhere to
community guidelines."
Make sure to fix the indentation of the code by selecting the above code and pressing the tab key if it is not indented adequately with respect to the remaining function.
Here’s the explanation for the code:
-
You created a dictionary of
ImageCategoryvalues, which will be utilized to extract the moderation results from the respective categories. -
You’re then iterating through
response.categories_analysislist to extract the output category responses and storing them in the appropriate category dictionary key defined above. - You then extract each category’s results in a separate variable from the category dictionary.
- This is the central part of the processing logic. Here, you’re determining if the image that was requested for moderation is found inappropriate for any of the different categories - hate, self-harm, violence, and sexual, based on the severity threshold defined. If the output severity level is found to be more than its respective category’s threshold value, then you append the category name to the violation list.
- Finally, if any violation exists on the violation list, you inform the user by returning details regarding the categories that are found to be violated from the image and asking them to change the image so that it adheres to the community guidelines. If no violation is found, the user is notified that the post is successful.
Now, run the cell to ensure the defined function is error-free.
Exploring Image Moderation Function
Here comes the fun part! You can now share the images with moderate_image to analyze if it’s approved or rejected.
Copy the code in the newly created cell:
with open(’../../sample-data/test-images/pexels-ash-craig-122861-376464.jpg’,
'rb') as file:
image_data = file.read()
moderation_response = moderate_image(image_data)
print(moderation_response)
In the above code, you open the image stored in the sample data shared in the repo in read binary format. Then, it’s passed to moderate_image for analysis. Finally, you print the output received from the moderate_image function.
Run the cell to see it in action:
Post successful
Congratulations! You’ve successfully implemented the Image Moderation workflow. Feel free to test the moderation function with other sample images stored in the data to see how the response varies.
That’s it for this segment. Continue towards the next segment to conclude the lesson.