Ravindra BagaleCourses & study guides मराठी Track your progress

AWS SDK AI Examples: Rekognition Image Labels and Bedrock Text Generation (Python, PHP, Node.js)

AWS has ready-made AI you call like any other API. From Python, PHP and Node.js we detect labels and text in photos with Rekognition, moderate uploads, and generate text with Amazon Bedrock using the Converse API, including streaming. The example: a second-hand marketplace with Giulia in Milan and Meera in Kochi.

What you'll learn in this chapter

  • Detect labels in an image
  • Read text and moderate content
  • Call Bedrock Converse
  • Stream model output
  • Control cost and safety

1. The big picture: the shop assistant

Why do we need this?

A seller uploads a photo of a bicycle. One assistant looks at it and says "bicycle, wheel, outdoor". Another writes a friendly listing: "Lightly used city bike, €180". Rekognition is the first assistant, Bedrock the second.

What is it?

Rekognition takes an Image (bytes or S3Object) and returns labels with Confidence. Bedrock Converse takes a modelId and messages and returns the reply plus token usage. Enable model access in the Bedrock console first.

How to do it (step by step)

Photo to listingUpload photo to S3DetectLabels + DetectModerationLabelsReject unsafe photosConverse: write a listing from labelsSave listing
Bedrock runtime calls use the bedrock-runtime client, not bedrock.

2. Detect labels

Why do we need this?

Giulia wants each photo tagged so buyers can search "bicycle" or "sofa".

What is it?

DetectLabels with MaxLabels and MinConfidence. Use S3Object for photos already in S3 (same region).

How to do it (step by step)

  1. Python.
import boto3
rk = boto3.client("rekognition", region_name="eu-west-1")
r = rk.detect_labels(Image={"S3Object": {"Bucket": "market-photos-mi", "Name": "bike-221.jpg"}},
    MaxLabels=5, MinConfidence=80)
for l in r["Labels"]: print(l["Name"], round(l["Confidence"]))

Expected output:

Bicycle 99
Wheel 98
Vehicle 97
Outdoors 88
City 82
  1. Node.js: from local bytes.
import { readFileSync } from "node:fs";
import { RekognitionClient, DetectLabelsCommand } from "@aws-sdk/client-rekognition";
const rk = new RekognitionClient({ region: "ap-south-1" });
const r = await rk.send(new DetectLabelsCommand({ Image: { Bytes: readFileSync("sofa-88.jpg") }, MaxLabels: 3 }));
console.log(r.Labels.map(l => l.Name).join(", "));

Expected output:

Couch, Furniture, Living Room
  1. PHP.
<?php
require "vendor/autoload.php";
$rk = new Aws\Rekognition\RekognitionClient(["region" => "eu-west-1"]);
$r = $rk->detectLabels(["Image" => ["Bytes" => file_get_contents("lamp.jpg")], "MaxLabels" => 2]);
echo implode(", ", array_column($r["Labels"], "Name")), PHP_EOL;

Expected output:

Lamp, Lampshade
  1. Verify with the CLI.
aws rekognition detect-labels --image "S3Object={Bucket=market-photos-mi,Name=bike-221.jpg}" --max-labels 1 --region eu-west-1 --query "Labels[0].Name" --output text

Expected output:

Bicycle

3. Read text and moderate

Why do we need this?

Meera blocks unsafe photos and reads the price tag in a photo of a Kochi spice tin: ₹350.

What is it?

DetectText returns LINE and WORD items. DetectModerationLabels returns categories like "Violence"; an empty list means it looks safe.

How to do it (step by step)

  1. Python: text lines.
r = rk.detect_text(Image={"Bytes": open("tin.jpg", "rb").read()})
print([t["DetectedText"] for t in r["TextDetections"] if t["Type"] == "LINE"])

Expected output:

['KERALA PEPPER', 'MRP ₹350', '200 g']
  1. Node.js: moderation.
import { DetectModerationLabelsCommand } from "@aws-sdk/client-rekognition";
const r = await rk.send(new DetectModerationLabelsCommand({ Image: { Bytes: readFileSync("sofa-88.jpg") }, MinConfidence: 60 }));
console.log(r.ModerationLabels.length === 0 ? "safe" : r.ModerationLabels.map(m => m.Name));

Expected output:

safe
  1. PHP: reject in an upload handler.
<?php
$m = $rk->detectModerationLabels(["Image" => ["Bytes" => file_get_contents($_FILES["p"]["tmp_name"])], "MinConfidence" => 70]);
if (count($m["ModerationLabels"])) { http_response_code(422); exit("Photo not allowed"); }
echo "accepted", PHP_EOL;

Expected output:

accepted
  1. Verify: a test image.
aws rekognition detect-text --image-bytes fileb://tin.jpg --region ap-south-1 --query "TextDetections[?Type=='LINE'] | [1].DetectedText" --output text

Expected output:

MRP ₹350

4. Generate text with Bedrock

Why do we need this?

From labels and a price, write a short, honest listing in English or Italian.

What is it?

Converse uses the same request shape for every model: messages, system, inferenceConfig. Use a model ID or inference profile enabled in your account.

How to do it (step by step)

  1. Python.
br = boto3.client("bedrock-runtime", region_name="eu-west-1")
r = br.converse(modelId="amazon.nova-lite-v1:0",
    system=[{"text": "You write short marketplace listings. Max 25 words. No made-up facts."}],
    messages=[{"role": "user", "content": [{"text": "Labels: Bicycle, City. Price €180. Condition: lightly used. Italian."}]}],
    inferenceConfig={"maxTokens": 120, "temperature": 0.4})
print(r["output"]["message"]["content"][0]["text"]); print(r["usage"])

Expected output:

Bici da città poco usata, pronta per Milano. €180.
{'inputTokens': 41, 'outputTokens': 17, 'totalTokens': 58}
  1. Node.js.
import { BedrockRuntimeClient, ConverseCommand } from "@aws-sdk/client-bedrock-runtime";
const br = new BedrockRuntimeClient({ region: "ap-south-1" });
const r = await br.send(new ConverseCommand({ modelId: "apac.amazon.nova-lite-v1:0",
  messages: [{ role: "user", content: [{ text: "Write a 20-word listing: Couch, 3-seater, ₹9,500, Kochi pickup." }] }],
  inferenceConfig: { maxTokens: 100 } }));
console.log(r.output.message.content[0].text);

Expected output:

Comfortable 3-seater couch in great shape. ₹9,500. Pickup in Kochi.
  1. PHP.
<?php
$br = new Aws\BedrockRuntime\BedrockRuntimeClient(["region" => "eu-west-1"]);
$r = $br->converse(["modelId" => "amazon.nova-lite-v1:0",
  "messages" => [["role" => "user", "content" => [["text" => "One-line listing: Lamp, brass, £25, London."]]]],
  "inferenceConfig" => ["maxTokens" => 60]]);
echo $r["output"]["message"]["content"][0]["text"], PHP_EOL;

Expected output:

Vintage brass lamp, warm light, £25 — collect in London.
  1. Verify: model access is enabled.
aws bedrock list-foundation-models --region eu-west-1 --by-provider amazon --query "modelSummaries[?modelId=='amazon.nova-lite-v1:0'].modelId" --output text

Expected output:

amazon.nova-lite-v1:0

5. Stream the answer

Why do we need this?

In the chat helper, buyers in Dubai should see words appear at once, not wait 5 seconds.

What is it?

ConverseStream returns an event stream: contentBlockDelta events carry text pieces; metadata carries usage.

How to do it (step by step)

  1. Python.
r = br.converse_stream(modelId="amazon.nova-lite-v1:0",
    messages=[{"role": "user", "content": [{"text": "Is a used bike for AED 700 a fair price? 2 lines."}]}])
for ev in r["stream"]:
    if "contentBlockDelta" in ev: print(ev["contentBlockDelta"]["delta"]["text"], end="", flush=True)
print()

Expected output:

For a lightly used city bike, AED 700 is fair.
Check brakes and gears before paying.
  1. Node.js.
import { ConverseStreamCommand } from "@aws-sdk/client-bedrock-runtime";
const r = await br.send(new ConverseStreamCommand({ modelId: "apac.amazon.nova-lite-v1:0",
  messages: [{ role: "user", content: [{ text: "Give 3 tips to sell a sofa fast." }] }] }));
for await (const ev of r.stream) if (ev.contentBlockDelta) process.stdout.write(ev.contentBlockDelta.delta.text);

Expected output:

1. Clear photos in daylight. 2. Fair price. 3. Offer pickup times.
  1. PHP.
<?php
$r = $br->converseStream(["modelId" => "amazon.nova-lite-v1:0",
  "messages" => [["role" => "user", "content" => [["text" => "Say hello in Italian and Malayalam."]]]]]);
foreach ($r["stream"] as $ev) if (isset($ev["contentBlockDelta"])) echo $ev["contentBlockDelta"]["delta"]["text"];
echo PHP_EOL;

Expected output:

Ciao! നമസ്കാരം!
  1. Verify: token usage metric.
aws cloudwatch get-metric-statistics --namespace AWS/Bedrock --metric-name OutputTokenCount --dimensions Name=ModelId,Value=amazon.nova-lite-v1:0 --statistics Sum --period 3600 --start-time $(date -u -d "-1 hour" +%FT%TZ) --end-time $(date -u +%FT%TZ) --region eu-west-1 --query "Datapoints[0].Sum"

Expected output:

112.0

6. The same call in Java, Go, .NET and the CLI

Why do we need this?

Teams often mix languages. Once you know the call in Python, PHP and Node.js, the other SDKs are the same API with different syntax.

What is it?

All of them call the Converse API. Use the CLI line to test it quickly from a terminal.

How to do it (step by step)

StackCode
AWS CLIaws bedrock-runtime converse --model-id amazon.nova-lite-v1:0 --messages '[{"role":"user","content":[{"text":"Hi"}]}]'
Java v2var r = br.converse(b -> b.modelId("amazon.nova-lite-v1:0").messages(Message.builder().role(ConversationRole.USER).content(ContentBlock.fromText("Hi")).build()));
Go v2out, _ := client.Converse(ctx, &bedrockruntime.ConverseInput{ModelId: aws.String("amazon.nova-lite-v1:0"), Messages: msgs})
.NETvar r = await br.ConverseAsync(new ConverseRequest { ModelId = "amazon.nova-lite-v1:0", Messages = msgs });

7. Clean up so nothing keeps costing

Why do we need this?

Lab resources left running cost money and can be a security risk.

What is it?

Delete in reverse order: children first, then parents.

How to do it (step by step)

  1. Nothing to delete for on-demand calls; remove test photos.
aws s3 rm s3://market-photos-mi/bike-221.jpg

Expected output:

(no output means success)

Ravindra Bagale's Tip

Always set maxTokens and log usage; an unbounded prompt in a loop can cost real money fast.

8. Interview questions and answers

Q. Rekognition input options?

Image bytes (up to 5 MB) or an S3Object in the same region.

Q. Which client calls models?

bedrock-runtime (Converse, InvokeModel); bedrock is for management.

Q. Why Converse over InvokeModel?

One request format for all models, plus tools and streaming.

Q. How do you stream?

ConverseStream and read contentBlockDelta events.

Q. What does an empty ModerationLabels mean?

No unsafe content above MinConfidence.

Try at home

  1. Chain it: Python reads labels for an S3 photo and asks Bedrock for a listing in Marathi.
  2. Add a 1-cent budget guard in Node.js that stops when totalTokens > 2,000.

In short

  1. DetectLabels with confidence.
  2. DetectText / Moderation.
  3. Converse = one format.
  4. ConverseStream for chat.
  5. Limit tokens, log usage.

Practice Tasks

About this scenario

Bengaluru HealthTech is a health technology business in Bengaluru. Arjun Rao looks after its IT and cloud work. They count money in INR and run their AWS resources in the ap-south-1 Region. In the tasks below you do real jobs for them using what this lesson teaches. All names, account IDs, IP addresses and numbers are made up for practice.

0 / 10

Easy List Bedrock models

Why: See which foundation models are offered in your Region.

What to do: List the foundation models available in Amazon Bedrock.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy List SageMaker endpoints

Why: Endpoints cost money every hour; list them to find forgotten ones.

What to do: List SageMaker endpoints.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Easy How many addresses in a /16?

Why: Picking a VPC size needs this count.

What to do: Bengaluru HealthTech plans the VPC 10.130.0.0/16. How many IP addresses does it hold in total?

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Port for SSH

Why: Security group rules need the right port.

What to do: Which TCP port must the security group open for SSH?

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Easy Show where you are

Why: Before you copy or delete anything, you must know which folder you are in.

What to do: Arjun Rao logged in to the Bengaluru HealthTech server and is not sure which folder the terminal is in. Print the current folder path.

How:
  1. Find the Linux command that does this job.
  2. Add the options (like -r or -h) the task needs.
  3. Add the file names, folders or users in the right order.
  4. Use sudo if the job changes system files or users. Click Check answer.

Easy Read-only access to one bucket

Why: Least privilege: give only the actions and the bucket the job needs.

What to do: Write an identity policy that lets the user read objects (s3:GetObject) only in bucket blrhealthtech-data.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium Detect labels in an image

Why: Rekognition names objects in a photo, e.g. to tag product images.

What to do: Detect labels in s3://blrhealthtech-media/shop/p1.jpg (Bucket=blrhealthtech-media, Name=shop/p1.jpg), max 10 labels.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Medium Allow one Bedrock model

Why: Limit apps to the approved model so costs stay predictable.

What to do: Allow bedrock:InvokeModel on arn:aws:bedrock:ap-south-1::foundation-model/amazon.nova-lite-v1:0 only.

How:
  1. Start with { "Version": "2012-10-17", "Statement": [ ... ] }.
  2. In each statement write Effect, Action and Resource.
  3. Give only what the task needs (least privilege).
  4. Use double quotes and commas correctly. Click Check answer.

Medium Usable IPs in an AWS /24 subnet

Why: AWS keeps 5 addresses in every subnet.

What to do: How many addresses can Bengaluru HealthTech use for servers in subnet 10.130.1.0/24 on AWS?

How:
  1. Write down the numbers the task gives you.
  2. Work it out step by step on paper.
  3. Type only the final answer in the box.
  4. Click Check answer.

Hard Ask a model a question

Why: Converse is one API shape for many models.

What to do: Call converse on model amazon.nova-lite-v1:0 with the messages in msgs.json.

How:
  1. Read the task and decide which AWS service it is about.
  2. Write aws, then the service name, then the operation (the action word).
  3. Add each needed flag (--name) followed by its value from the task.
  4. Flags can be in any order. Click Check answer.

Revision, comparison and interview cards

Revise this lesson in a few minutes. Save the cards on your phone or download them as PNG files. The QR code on each card opens this lesson.

Rekognition labels. DetectLabels with MinConfidence. Bytes up to 5 MB, or S3Object. DetectText: LINE and WORD. Empty moderation = safe.
Revision card: Rekognition labels · Download PNG · Open card page
Bedrock Converse. Client: bedrock-runtime. Enable model access first. Set maxTokens, log usage. ConverseStream for chat.
Revision card: Bedrock Converse · Download PNG · Open card page
Rekognition vs Bedrock. Ready-made vision API. / Foundation models API.
Comparison: Rekognition vs Bedrock · Download PNG · Open card page
Bedrock AccessDeniedException?. Model access not enabled. Wrong region for the model. IAM needs bedrock:InvokeModel.
Interview card: Bedrock AccessDeniedException? · Download PNG · Open card page

More cards: Ravi Sir's Cards.