diff --git a/tuts/114-amazon-transcribe-gs/README.md b/tuts/114-amazon-transcribe-gs/README.md new file mode 100644 index 00000000..98b6ffa1 --- /dev/null +++ b/tuts/114-amazon-transcribe-gs/README.md @@ -0,0 +1,42 @@ +# Transcribe: Transcribe audio to text + +## Source + +https://docs.aws.amazon.com/transcribe/latest/dg/getting-started.html + +## Use case + +- **ID**: transcribe/getting-started +- **Level**: beginner +- **Core actions**: `transcribe:StartTranscriptionJob` + +## Steps + +1. Create a sample audio file (WAV with silence) +2. Upload to S3 +3. Start a transcription job +4. Wait for completion +5. Get results +6. List transcription jobs + +## Resources created + +| Resource | Type | +|----------|------| +| `transcribe-tut-` | S3 bucket | +| `tut-job-` | Transcription job | + +## Cost + +Transcribe pricing is per second of audio transcribed. This tutorial transcribes 1 second, costing a fraction of a cent. + +## Duration + +~16 seconds + +## Related docs + +- [Getting started with Amazon Transcribe](https://docs.aws.amazon.com/transcribe/latest/dg/getting-started.html) +- [Amazon Transcribe API reference](https://docs.aws.amazon.com/transcribe/latest/APIReference/Welcome.html) +- [Supported languages](https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html) +- [Amazon Transcribe pricing](https://aws.amazon.com/transcribe/pricing/) diff --git a/tuts/114-amazon-transcribe-gs/REVISION-HISTORY.md b/tuts/114-amazon-transcribe-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..8930e744 --- /dev/null +++ b/tuts/114-amazon-transcribe-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 114-amazon-transcribe-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.md b/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.md new file mode 100644 index 00000000..6272b96d --- /dev/null +++ b/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.md @@ -0,0 +1,123 @@ +# Transcribe audio to text with Amazon Transcribe + +This tutorial shows you how to create a sample audio file, upload it to Amazon S3, start a transcription job with Amazon Transcribe, wait for the job to complete, retrieve the results, and list recent transcription jobs. + +## Prerequisites + +- AWS CLI configured with credentials and a default region +- Python 3 installed (used to generate a WAV file) +- Permissions for `transcribe:StartTranscriptionJob`, `transcribe:GetTranscriptionJob`, `transcribe:ListTranscriptionJobs`, `transcribe:DeleteTranscriptionJob`, `s3:CreateBucket`, `s3:PutObject`, `s3:DeleteObject`, `s3:DeleteBucket` + +## Step 1: Create a sample audio file + +Generate a 1-second WAV file containing silence using Python. This gives Transcribe a valid audio file to process without needing an external recording. + +```bash +python3 -c " +import struct, wave +with wave.open('/tmp/sample.wav', 'w') as w: + w.setnchannels(1) + w.setsampwidth(2) + w.setframerate(16000) + w.writeframes(struct.pack('<' + 'h' * 16000, *([0] * 16000))) +" +``` + +The file is 16 kHz mono PCM, which is the recommended format for Amazon Transcribe. One second of silence produces a ~32 KB file. + +## Step 2: Upload to S3 + +Create an S3 bucket and upload the audio file. Transcribe reads input from S3. + +```bash +BUCKET_NAME="transcribe-tut-$(openssl rand -hex 4)-$(aws sts get-caller-identity --query 'Account' --output text)" + +aws s3api create-bucket --bucket "$BUCKET_NAME" +aws s3 cp /tmp/sample.wav "s3://$BUCKET_NAME/sample.wav" --quiet +``` + +For regions other than `us-east-1`, the script adds `--create-bucket-configuration LocationConstraint=$REGION`. + +## Step 3: Start a transcription job + +Start an asynchronous transcription job pointing to the uploaded audio. + +```bash +JOB_NAME="tut-job-$(openssl rand -hex 4)" + +aws transcribe start-transcription-job \ + --transcription-job-name "$JOB_NAME" \ + --language-code en-US \ + --media "MediaFileUri=s3://$BUCKET_NAME/sample.wav" \ + --output-bucket-name "$BUCKET_NAME" \ + --query 'TranscriptionJob.{Name:TranscriptionJobName,Status:TranscriptionJobStatus}' \ + --output table +``` + +`--language-code` specifies the language of the audio. `--output-bucket-name` tells Transcribe where to write the JSON result file. Without it, Transcribe uses a service-managed bucket. + +## Step 4: Wait for completion + +Poll the job status until it reaches `COMPLETED` or `FAILED`. + +```bash +for i in $(seq 1 30); do + STATUS=$(aws transcribe get-transcription-job \ + --transcription-job-name "$JOB_NAME" \ + --query 'TranscriptionJob.TranscriptionJobStatus' --output text) + echo " Status: $STATUS" + [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ] && break + sleep 5 +done +``` + +Most short audio files complete within 15–30 seconds. The script polls every 5 seconds with a 150-second timeout. + +## Step 5: Get results + +Retrieve the transcript URI from the completed job. + +```bash +aws transcribe get-transcription-job \ + --transcription-job-name "$JOB_NAME" \ + --query 'TranscriptionJob.Transcript.TranscriptFileUri' --output text +``` + +The result is a JSON file in your S3 bucket containing the transcript text, confidence scores, and word-level timestamps. Since the input was silence, the transcript will be empty or minimal. + +## Step 6: List transcription jobs + +List recent completed transcription jobs. + +```bash +aws transcribe list-transcription-jobs --status COMPLETED \ + --query 'TranscriptionJobSummaries[:3].{Name:TranscriptionJobName,Status:TranscriptionJobStatus,Created:CreationTime}' \ + --output table +``` + +You can filter by `--status` (`QUEUED`, `IN_PROGRESS`, `COMPLETED`, `FAILED`) and by `--job-name-contains` to find specific jobs. + +## Cleanup + +Delete the transcription job and the S3 bucket: + +```bash +aws transcribe delete-transcription-job --transcription-job-name "$JOB_NAME" +aws s3 rm "s3://$BUCKET_NAME" --recursive +aws s3 rb "s3://$BUCKET_NAME" +``` + +Amazon Transcribe charges per second of audio transcribed. This tutorial transcribes 1 second of audio, costing a fraction of a cent. The S3 bucket is also deleted during cleanup. + +The script automates all steps including cleanup: + +```bash +bash amazon-transcribe-gs.sh +``` + +## Related resources + +- [Getting started with Amazon Transcribe](https://docs.aws.amazon.com/transcribe/latest/dg/getting-started.html) +- [Amazon Transcribe API reference](https://docs.aws.amazon.com/transcribe/latest/APIReference/Welcome.html) +- [Supported languages](https://docs.aws.amazon.com/transcribe/latest/dg/supported-languages.html) +- [Amazon Transcribe pricing](https://aws.amazon.com/transcribe/pricing/) diff --git a/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.sh b/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.sh new file mode 100644 index 00000000..f578c92a --- /dev/null +++ b/tuts/114-amazon-transcribe-gs/amazon-transcribe-gs.sh @@ -0,0 +1,106 @@ +#!/bin/bash +# Tutorial: Transcribe audio to text with Amazon Transcribe +# Source: https://docs.aws.amazon.com/transcribe/latest/dg/getting-started.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/transcribe-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +ACCOUNT_ID=$(aws sts get-caller-identity --query 'Account' --output text) +echo "Region: $REGION" + +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) +BUCKET_NAME="transcribe-tut-${RANDOM_ID}-${ACCOUNT_ID}" +JOB_NAME="tut-job-${RANDOM_ID}" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + aws transcribe delete-transcription-job --transcription-job-name "$JOB_NAME" 2>/dev/null && echo " Deleted job $JOB_NAME" + if aws s3 ls "s3://$BUCKET_NAME" > /dev/null 2>&1; then + aws s3 rm "s3://$BUCKET_NAME" --recursive --quiet 2>/dev/null + aws s3 rb "s3://$BUCKET_NAME" 2>/dev/null && echo " Deleted bucket $BUCKET_NAME" + fi + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Create a sample audio file (WAV with silence) +echo "Step 1: Creating sample audio file" +python3 -c " +import struct, wave +with wave.open('$WORK_DIR/sample.wav', 'w') as w: + w.setnchannels(1) + w.setsampwidth(2) + w.setframerate(16000) + w.writeframes(struct.pack('<' + 'h' * 16000, *([0] * 16000))) +" +echo " Created sample.wav (1 second, 16kHz mono)" + +# Step 2: Upload to S3 +echo "Step 2: Uploading to S3" +if [ "$REGION" = "us-east-1" ]; then + aws s3api create-bucket --bucket "$BUCKET_NAME" > /dev/null +else + aws s3api create-bucket --bucket "$BUCKET_NAME" \ + --create-bucket-configuration LocationConstraint="$REGION" > /dev/null +fi +aws s3 cp "$WORK_DIR/sample.wav" "s3://$BUCKET_NAME/sample.wav" --quiet +echo " Uploaded to s3://$BUCKET_NAME/sample.wav" + +# Step 3: Start transcription job +echo "Step 3: Starting transcription job: $JOB_NAME" +aws transcribe start-transcription-job \ + --transcription-job-name "$JOB_NAME" \ + --language-code en-US \ + --media "MediaFileUri=s3://$BUCKET_NAME/sample.wav" \ + --output-bucket-name "$BUCKET_NAME" \ + --query 'TranscriptionJob.{Name:TranscriptionJobName,Status:TranscriptionJobStatus}' --output table + +# Step 4: Wait for completion +echo "Step 4: Waiting for transcription to complete..." +for i in $(seq 1 30); do + STATUS=$(aws transcribe get-transcription-job --transcription-job-name "$JOB_NAME" \ + --query 'TranscriptionJob.TranscriptionJobStatus' --output text) + echo " Status: $STATUS" + [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ] && break + sleep 5 +done + +# Step 5: Get results +echo "Step 5: Transcription results" +if [ "$STATUS" = "COMPLETED" ]; then + RESULT_URI=$(aws transcribe get-transcription-job --transcription-job-name "$JOB_NAME" \ + --query 'TranscriptionJob.Transcript.TranscriptFileUri' --output text) + echo " Result URI: $RESULT_URI" + echo " (Audio was silence, so transcript will be empty or minimal)" +else + echo " Job status: $STATUS" +fi + +# Step 6: List jobs +echo "Step 6: Listing transcription jobs" +aws transcribe list-transcription-jobs --status COMPLETED \ + --query 'TranscriptionJobSummaries[:3].{Name:TranscriptionJobName,Status:TranscriptionJobStatus,Created:CreationTime}' --output table 2>/dev/null || \ + echo " No completed jobs" + +echo "" +echo "Tutorial complete." +echo "Do you want to clean up all resources? (y/n): " +read -r CHOICE +if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup +else + echo "Manual cleanup:" + echo " aws transcribe delete-transcription-job --transcription-job-name $JOB_NAME" + echo " aws s3 rm s3://$BUCKET_NAME --recursive && aws s3 rb s3://$BUCKET_NAME" +fi diff --git a/tuts/118-amazon-lex-gs/README.md b/tuts/118-amazon-lex-gs/README.md new file mode 100644 index 00000000..1e32a8bc --- /dev/null +++ b/tuts/118-amazon-lex-gs/README.md @@ -0,0 +1,58 @@ +# Lex: Create a chatbot + +Create an Amazon Lex V2 chatbot with an IAM role, English locale, and a sample intent, then build the bot locale. + +## Source + +https://docs.aws.amazon.com/lexv2/latest/dg/getting-started.html + +## Use case + +- **ID**: lex/getting-started +- **Level**: intermediate +- **Core actions**: `lexv2-models:CreateBot`, `lexv2-models:CreateIntent`, `lexv2-models:CreateBotLocale`, `lexv2-models:BuildBotLocale` + +## Steps + +1. Create an IAM role for the bot +2. Create a bot +3. Create an English locale +4. Create an OrderPizza intent with sample utterances +5. Build the bot locale +6. Describe the bot + +## Resources created + +| Resource | Type | +|----------|------| +| `tut-bot-` | Lex V2 bot | +| `lex-tut-role-` | IAM role (with Polly policy) | + +## Duration + +~40 seconds + +## Cost + +No charge for bot creation. Lex charges per text or speech request when the bot processes conversations. This tutorial does not send conversation requests. + +## Related docs + +- [Getting started with Amazon Lex V2](https://docs.aws.amazon.com/lexv2/latest/dg/getting-started.html) +- [Creating a bot](https://docs.aws.amazon.com/lexv2/latest/dg/build-create.html) +- [Adding intents](https://docs.aws.amazon.com/lexv2/latest/dg/build-intents.html) +- [Amazon Lex pricing](https://aws.amazon.com/lex/pricing/) + +--- + +## Appendix + +| Field | Value | +|-------|-------| +| Date | 2026-04-14 | +| Script lines | 106 | +| Exit code | 0 | +| Runtime | 40s | +| Steps | 6 | +| Issues | Fixed bot/locale wait timing | +| Version | v1 | diff --git a/tuts/118-amazon-lex-gs/REVISION-HISTORY.md b/tuts/118-amazon-lex-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..12f645d3 --- /dev/null +++ b/tuts/118-amazon-lex-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 118-amazon-lex-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/118-amazon-lex-gs/amazon-lex-gs.md b/tuts/118-amazon-lex-gs/amazon-lex-gs.md new file mode 100644 index 00000000..dec7cf10 --- /dev/null +++ b/tuts/118-amazon-lex-gs/amazon-lex-gs.md @@ -0,0 +1,145 @@ +# Create a chatbot with Amazon Lex + +## Overview + +In this tutorial, you use the AWS CLI to create an Amazon Lex V2 chatbot. You create an IAM role, configure an English locale, add an intent with sample utterances, and build the bot locale. You then delete the bot and role during cleanup. + +## Prerequisites + +- AWS CLI installed and configured with appropriate permissions. +- An IAM principal with permissions for `lexv2-models:CreateBot`, `lexv2-models:CreateBotLocale`, `lexv2-models:CreateIntent`, `lexv2-models:BuildBotLocale`, `lexv2-models:DescribeBot`, `lexv2-models:DescribeBotLocale`, `lexv2-models:DeleteBot`, `iam:CreateRole`, `iam:PutRolePolicy`, `iam:DeleteRolePolicy`, and `iam:DeleteRole`. + +## Step 1: Create an IAM role + +Create a role that allows Lex to call Amazon Polly for speech synthesis. + +```bash +RANDOM_ID=$(openssl rand -hex 4) +ROLE_NAME="lex-tut-role-${RANDOM_ID}" + +ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" \ + --assume-role-policy-document '{ + "Version":"2012-10-17", + "Statement":[{"Effect":"Allow","Principal":{"Service":"lexv2.amazonaws.com"},"Action":"sts:AssumeRole"}] + }' --query 'Role.Arn' --output text) + +aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name lex-policy \ + --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["polly:SynthesizeSpeech"],"Resource":"*"}]}' +echo "Role ARN: $ROLE_ARN" +sleep 10 +``` + +The sleep gives IAM time to propagate the role. Lex requires a service role even for text-only bots. + +## Step 2: Create a bot + +Create the bot with a 5-minute idle session timeout. + +```bash +BOT_NAME="tut-bot-${RANDOM_ID}" + +BOT_ID=$(aws lexv2-models create-bot --bot-name "$BOT_NAME" \ + --role-arn "$ROLE_ARN" \ + --data-privacy '{"childDirected":false}' \ + --idle-session-ttl-in-seconds 300 \ + --query 'botId' --output text) +echo "Bot ID: $BOT_ID" +``` + +`childDirected` is required by COPPA compliance. Set to `true` if the bot is directed at children under 13. + +## Step 3: Create an English locale + +Wait for the bot to become available, then add an English (US) locale. + +```bash +# Wait for bot +for i in $(seq 1 15); do + BOT_STATUS=$(aws lexv2-models describe-bot --bot-id "$BOT_ID" \ + --query 'botStatus' --output text) + [ "$BOT_STATUS" = "Available" ] && break + sleep 3 +done + +aws lexv2-models create-bot-locale --bot-id "$BOT_ID" --bot-version DRAFT \ + --locale-id en_US --nlu-intent-confidence-threshold 0.40 +``` + +The NLU confidence threshold (0.40) controls how confident Lex must be before matching an utterance to an intent. Lower values match more broadly. + +## Step 4: Create an OrderPizza intent + +Wait for the locale to be ready, then create an intent with sample utterances. + +```bash +# Wait for locale +for i in $(seq 1 15); do + LOC_STATUS=$(aws lexv2-models describe-bot-locale --bot-id "$BOT_ID" \ + --bot-version DRAFT --locale-id en_US \ + --query 'botLocaleStatus' --output text 2>/dev/null || echo "Creating") + [ "$LOC_STATUS" = "NotBuilt" ] || [ "$LOC_STATUS" = "Built" ] && break + sleep 3 +done + +INTENT_ID=$(aws lexv2-models create-intent --bot-id "$BOT_ID" --bot-version DRAFT \ + --locale-id en_US --intent-name OrderPizza \ + --sample-utterances '[{"utterance":"I want to order a pizza"},{"utterance":"Order a pizza"},{"utterance":"I would like a pizza please"}]' \ + --query 'intentId' --output text) +echo "Intent ID: $INTENT_ID" +``` + +Sample utterances train the NLU model to recognize when a user wants to trigger this intent. Add more utterances for better accuracy. + +## Step 5: Build the bot locale + +Build the locale to compile the NLU model. + +```bash +aws lexv2-models build-bot-locale --bot-id "$BOT_ID" \ + --bot-version DRAFT --locale-id en_US + +for i in $(seq 1 20); do + STATUS=$(aws lexv2-models describe-bot-locale --bot-id "$BOT_ID" \ + --bot-version DRAFT --locale-id en_US \ + --query 'botLocaleStatus' --output text) + echo "Status: $STATUS" + [ "$STATUS" = "Built" ] || [ "$STATUS" = "ReadyExpressTesting" ] && break + sleep 5 +done +``` + +Building compiles the intents and utterances into a model. The bot must be built before it can handle conversations. + +## Step 6: Describe the bot + +View the bot configuration. + +```bash +aws lexv2-models describe-bot --bot-id "$BOT_ID" \ + --query '{Name:botName,Id:botId,Status:botStatus}' --output table +``` + +## Cleanup + +Delete the bot and its IAM role. + +```bash +aws lexv2-models delete-bot --bot-id "$BOT_ID" --skip-resource-in-use-check +aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name lex-policy +aws iam delete-role --role-name "$ROLE_NAME" +``` + +`--skip-resource-in-use-check` deletes the bot even if it has aliases or versions. Without this flag, you must delete aliases and versions first. + +The script automates all steps including cleanup: + +```bash +bash amazon-lex-gs.sh +``` + +## Related resources + +- [Getting started with Amazon Lex V2](https://docs.aws.amazon.com/lexv2/latest/dg/getting-started.html) +- [Creating a bot](https://docs.aws.amazon.com/lexv2/latest/dg/build-create.html) +- [Adding intents](https://docs.aws.amazon.com/lexv2/latest/dg/build-intents.html) +- [Amazon Lex pricing](https://aws.amazon.com/lex/pricing/) diff --git a/tuts/118-amazon-lex-gs/amazon-lex-gs.sh b/tuts/118-amazon-lex-gs/amazon-lex-gs.sh new file mode 100644 index 00000000..c8e5810d --- /dev/null +++ b/tuts/118-amazon-lex-gs/amazon-lex-gs.sh @@ -0,0 +1,113 @@ +#!/bin/bash +# Tutorial: Create a chatbot with Amazon Lex V2 +# Source: https://docs.aws.amazon.com/lexv2/latest/dg/getting-started.html + +WORK_DIR=$(mktemp -d) +LOG_FILE="$WORK_DIR/lex-$(date +%Y%m%d-%H%M%S).log" +exec > >(tee -a "$LOG_FILE") 2>&1 + +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null)}} +if [ -z "$REGION" ]; then + echo "ERROR: No AWS region configured. Set one with: export AWS_DEFAULT_REGION=us-east-1" + exit 1 +fi +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" + +RANDOM_ID=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 8 | head -n 1) +BOT_NAME="tut-bot-${RANDOM_ID}" +ROLE_NAME="lex-tut-role-${RANDOM_ID}" + +handle_error() { echo "ERROR on line $1"; trap - ERR; cleanup; exit 1; } +trap 'handle_error $LINENO' ERR + +cleanup() { + echo "" + echo "Cleaning up resources..." + [ -n "$BOT_ID" ] && aws lexv2-models delete-bot --bot-id "$BOT_ID" --skip-resource-in-use-check > /dev/null 2>&1 && \ + echo " Deleted bot $BOT_NAME" + aws iam delete-role-policy --role-name "$ROLE_NAME" --policy-name lex-policy 2>/dev/null + aws iam delete-role --role-name "$ROLE_NAME" 2>/dev/null && echo " Deleted role $ROLE_NAME" + rm -rf "$WORK_DIR" + echo "Cleanup complete." +} + +# Step 1: Create IAM role +echo "Step 1: Creating IAM role: $ROLE_NAME" +ROLE_ARN=$(aws iam create-role --role-name "$ROLE_NAME" \ + --assume-role-policy-document '{ + "Version":"2012-10-17", + "Statement":[{"Effect":"Allow","Principal":{"Service":"lexv2.amazonaws.com"},"Action":"sts:AssumeRole"}] + }' --query 'Role.Arn' --output text) +aws iam put-role-policy --role-name "$ROLE_NAME" --policy-name lex-policy \ + --policy-document '{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":["polly:SynthesizeSpeech"],"Resource":"*"}]}' +echo " Role ARN: $ROLE_ARN" +sleep 10 + +# Step 2: Create a bot +echo "Step 2: Creating bot: $BOT_NAME" +BOT_ID=$(aws lexv2-models create-bot --bot-name "$BOT_NAME" \ + --role-arn "$ROLE_ARN" \ + --data-privacy '{"childDirected":false}' \ + --idle-session-ttl-in-seconds 300 \ + --query 'botId' --output text) +echo " Bot ID: $BOT_ID" + +# Step 3: Create a locale +echo "Step 3: Creating English locale" +echo " Waiting for bot to be available..." +for i in $(seq 1 15); do + BOT_STATUS=$(aws lexv2-models describe-bot --bot-id "$BOT_ID" --query 'botStatus' --output text) + [ "$BOT_STATUS" = "Available" ] && break + sleep 3 +done +aws lexv2-models create-bot-locale --bot-id "$BOT_ID" --bot-version DRAFT \ + --locale-id en_US --nlu-intent-confidence-threshold 0.40 \ + --query 'localeId' --output text > /dev/null +echo " Locale: en_US" + +# Wait for locale to be ready +for i in $(seq 1 15); do + LOC_STATUS=$(aws lexv2-models describe-bot-locale --bot-id "$BOT_ID" --bot-version DRAFT --locale-id en_US \ + --query 'botLocaleStatus' --output text 2>/dev/null || echo "Creating") + [ "$LOC_STATUS" = "NotBuilt" ] || [ "$LOC_STATUS" = "Built" ] && break + sleep 3 +done + +# Step 4: Create an intent +echo "Step 4: Creating OrderPizza intent" +INTENT_ID=$(aws lexv2-models create-intent --bot-id "$BOT_ID" --bot-version DRAFT \ + --locale-id en_US --intent-name OrderPizza \ + --sample-utterances '[{"utterance":"I want to order a pizza"},{"utterance":"Order a pizza"},{"utterance":"I would like a pizza please"}]' \ + --query 'intentId' --output text) +echo " Intent ID: $INTENT_ID" + +# Step 5: Build the bot locale +echo "Step 5: Building bot locale" +aws lexv2-models build-bot-locale --bot-id "$BOT_ID" --bot-version DRAFT --locale-id en_US > /dev/null +echo " Build started..." +for i in $(seq 1 20); do + STATUS=$(aws lexv2-models describe-bot-locale --bot-id "$BOT_ID" --bot-version DRAFT --locale-id en_US \ + --query 'botLocaleStatus' --output text) + echo " Status: $STATUS" + [ "$STATUS" = "Built" ] || [ "$STATUS" = "ReadyExpressTesting" ] || [ "$STATUS" = "Failed" ] && break + sleep 5 +done + +# Step 6: Describe the bot +echo "Step 6: Bot details" +aws lexv2-models describe-bot --bot-id "$BOT_ID" \ + --query '{Name:botName,Id:botId,Status:botStatus}' --output table + +echo "" +echo "Tutorial complete." +echo "Do you want to clean up all resources? (y/n): " +read -r CHOICE +if [[ "$CHOICE" =~ ^[Yy]$ ]]; then + cleanup +else + echo "Manual cleanup:" + echo " aws lexv2-models delete-bot --bot-id $BOT_ID --skip-resource-in-use-check" + echo " aws iam delete-role-policy --role-name $ROLE_NAME --policy-name lex-policy" + echo " aws iam delete-role --role-name $ROLE_NAME" +fi diff --git a/tuts/123-amazon-bedrock-gs/README.md b/tuts/123-amazon-bedrock-gs/README.md new file mode 100644 index 00000000..dc9153bd --- /dev/null +++ b/tuts/123-amazon-bedrock-gs/README.md @@ -0,0 +1,31 @@ +# Amazon Bedrock Gs + +A read-only script that queries Bedrock resources and displays information. + +## Running + +```bash +bash amazon-bedrock-gs.sh +``` + +## What it does + +1. Listing foundation models +2. Listing inference profiles +3. Invoking a model +4. Listing custom models +5. Listing model invocation logs + +## Resources created + +None — this script is read-only. + +## Cost + +No cost. This script only reads existing resources. + +## Related docs + +- [AWS CLI bedrock reference](https://docs.aws.amazon.com/cli/latest/reference/bedrock/index.html) +- [AWS CLI bedrock-runtime reference](https://docs.aws.amazon.com/cli/latest/reference/bedrock-runtime/index.html) + diff --git a/tuts/123-amazon-bedrock-gs/REVISION-HISTORY.md b/tuts/123-amazon-bedrock-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..07955553 --- /dev/null +++ b/tuts/123-amazon-bedrock-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 123-amazon-bedrock-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.md b/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.md new file mode 100644 index 00000000..99040fa4 --- /dev/null +++ b/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.md @@ -0,0 +1,27 @@ +# Amazon Bedrock Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Listing foundation models + +The script handles this step automatically. See `amazon-bedrock-gs.sh` for the exact CLI commands. + +## Step 2: Listing inference profiles + +The script handles this step automatically. See `amazon-bedrock-gs.sh` for the exact CLI commands. + +## Step 3: Invoking a model + +The script handles this step automatically. See `amazon-bedrock-gs.sh` for the exact CLI commands. + +## Step 4: Listing custom models + +The script handles this step automatically. See `amazon-bedrock-gs.sh` for the exact CLI commands. + +## Step 5: Listing model invocation logs + +The script handles this step automatically. See `amazon-bedrock-gs.sh` for the exact CLI commands. + diff --git a/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.sh b/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.sh new file mode 100644 index 00000000..708551e7 --- /dev/null +++ b/tuts/123-amazon-bedrock-gs/amazon-bedrock-gs.sh @@ -0,0 +1,21 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d) +exec > >(tee -a "$WORK_DIR/bedrock-$(date +%Y%m%d-%H%M%S).log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))} +[ -z "$REGION" ] && echo "ERROR: No region" && exit 1 +export AWS_DEFAULT_REGION="$REGION" +echo "Region: $REGION" +echo "Step 1: Listing foundation models" +aws bedrock list-foundation-models --query 'modelSummaries[:10].{Id:modelId,Name:modelName,Provider:providerName}' --output table +echo "Step 2: Listing inference profiles" +aws bedrock list-inference-profiles --query 'inferenceProfileSummaries[:5].{Name:inferenceProfileName,Id:inferenceProfileId}' --output table +echo "Step 3: Invoking a model" +RESPONSE=$(aws bedrock-runtime invoke-model --model-id us.anthropic.claude-haiku-4-5-20251001-v1:0 --content-type application/json --accept application/json --body "$(echo '{"anthropic_version":"bedrock-2023-05-31","max_tokens":100,"messages":[{"role":"user","content":"What is Amazon Bedrock in one sentence?"}]}' | base64 -w0 | python3 -c 'import sys,base64;sys.stdout.buffer.write(base64.b64decode(sys.stdin.read()))')" "$WORK_DIR/response.json" 2>&1) +python3 -c "import json;r=json.load(open('$WORK_DIR/response.json'));print(f\" Model: {r.get('model','?')}\\n Response: {r['content'][0]['text']}\")" 2>/dev/null || echo " Model invocation failed (check model access)" +echo "Step 4: Listing custom models" +aws bedrock list-custom-models --query 'modelSummaries[:3].{Name:modelName,Base:baseModelId}' --output table 2>/dev/null || echo " No custom models" +echo "Step 5: Listing model invocation logs" +aws bedrock get-model-invocation-logging-configuration --query 'loggingConfig' --output table 2>/dev/null || echo " No logging configured" +echo "" +echo "Tutorial complete. No resources were created." +rm -rf "$WORK_DIR" diff --git a/tuts/149-aws-lakeformation-gs/README.md b/tuts/149-aws-lakeformation-gs/README.md new file mode 100644 index 00000000..41fe6105 --- /dev/null +++ b/tuts/149-aws-lakeformation-gs/README.md @@ -0,0 +1,28 @@ +# Aws Lakeformation Gs + +A read-only script that queries Lakeformation resources and displays information. + +## Running + +```bash +bash aws-lakeformation-gs.sh +``` + +## What it does + +1. Getting data lake settings +2. Listing resources +3. Listing permissions + +## Resources created + +None — this script is read-only. + +## Cost + +No cost. This script only reads existing resources. + +## Related docs + +- [AWS CLI lakeformation reference](https://docs.aws.amazon.com/cli/latest/reference/lakeformation/index.html) + diff --git a/tuts/149-aws-lakeformation-gs/REVISION-HISTORY.md b/tuts/149-aws-lakeformation-gs/REVISION-HISTORY.md new file mode 100644 index 00000000..72556b91 --- /dev/null +++ b/tuts/149-aws-lakeformation-gs/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 149-aws-lakeformation-gs + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.md b/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.md new file mode 100644 index 00000000..2937278a --- /dev/null +++ b/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.md @@ -0,0 +1,19 @@ +# Aws Lakeformation Gs + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Getting data lake settings + +The script handles this step automatically. See `aws-lakeformation-gs.sh` for the exact CLI commands. + +## Step 2: Listing resources + +The script handles this step automatically. See `aws-lakeformation-gs.sh` for the exact CLI commands. + +## Step 3: Listing permissions + +The script handles this step automatically. See `aws-lakeformation-gs.sh` for the exact CLI commands. + diff --git a/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.sh b/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.sh new file mode 100644 index 00000000..870193d6 --- /dev/null +++ b/tuts/149-aws-lakeformation-gs/aws-lakeformation-gs.sh @@ -0,0 +1,11 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/lf.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +echo "Step 1: Getting data lake settings" +aws lakeformation get-data-lake-settings --query 'DataLakeSettings.{Admins:DataLakeAdmins|length(@),CreateDBDefault:CreateDatabaseDefaultPermissions|length(@)}' --output table +echo "Step 2: Listing resources" +aws lakeformation list-resources --query 'ResourceInfoList[:5].{Arn:ResourceArn}' --output table 2>/dev/null || echo " No registered resources" +echo "Step 3: Listing permissions" +aws lakeformation list-permissions --query 'PrincipalResourcePermissions[:5].{Principal:Principal.DataLakePrincipalIdentifier,Resource:Resource}' --output json 2>/dev/null | python3 -c "import sys,json;d=json.load(sys.stdin);print(f' {len(d)} permissions found')" 2>/dev/null || echo " No permissions" +echo ""; echo "Tutorial complete. No resources created — Lake Formation is read-only in this tutorial." +rm -rf "$WORK_DIR" diff --git a/tuts/212-cloudwatch-list-alarms/README.md b/tuts/212-cloudwatch-list-alarms/README.md new file mode 100644 index 00000000..989a0426 --- /dev/null +++ b/tuts/212-cloudwatch-list-alarms/README.md @@ -0,0 +1,27 @@ +# Cloudwatch List Alarms + +A read-only script that queries Cloudwatch resources and displays information. + +## Running + +```bash +bash cloudwatch-list-alarms.sh +``` + +## What it does + +1. Listing alarms +2. Alarm summary by state + +## Resources created + +None — this script is read-only. + +## Cost + +No cost. This script only reads existing resources. + +## Related docs + +- [AWS CLI cloudwatch reference](https://docs.aws.amazon.com/cli/latest/reference/cloudwatch/index.html) + diff --git a/tuts/212-cloudwatch-list-alarms/REVISION-HISTORY.md b/tuts/212-cloudwatch-list-alarms/REVISION-HISTORY.md new file mode 100644 index 00000000..13dbafeb --- /dev/null +++ b/tuts/212-cloudwatch-list-alarms/REVISION-HISTORY.md @@ -0,0 +1,8 @@ +# Revision History: 212-cloudwatch-list-alarms + +## Shell (CLI script) + +### 2026-04-14 v1 published +- Type: functional +- Initial version + diff --git a/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.md b/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.md new file mode 100644 index 00000000..09ae7b1a --- /dev/null +++ b/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.md @@ -0,0 +1,15 @@ +# Cloudwatch List Alarms + +## Prerequisites + +1. AWS CLI installed and configured (`aws configure`) +2. Appropriate IAM permissions for the AWS services used + +## Step 1: Listing alarms + +The script handles this step automatically. See `cloudwatch-list-alarms.sh` for the exact CLI commands. + +## Step 2: Alarm summary by state + +The script handles this step automatically. See `cloudwatch-list-alarms.sh` for the exact CLI commands. + diff --git a/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.sh b/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.sh new file mode 100644 index 00000000..887982b2 --- /dev/null +++ b/tuts/212-cloudwatch-list-alarms/cloudwatch-list-alarms.sh @@ -0,0 +1,9 @@ +#!/bin/bash +WORK_DIR=$(mktemp -d); exec > >(tee -a "$WORK_DIR/tut.log") 2>&1 +REGION=${AWS_DEFAULT_REGION:-${AWS_REGION:-$(aws configure get region 2>/dev/null))}; [ -z "$REGION" ] && echo "ERROR: No region" && exit 1; export AWS_DEFAULT_REGION="$REGION"; echo "Region: $REGION" +echo "Step 1: Listing alarms"; aws cloudwatch describe-alarms --query 'MetricAlarms[:10].{Name:AlarmName,State:StateValue,Metric:MetricName,Threshold:Threshold}' --output table +echo "Step 2: Alarm summary by state" +echo " OK: $(aws cloudwatch describe-alarms --state-value OK --query 'MetricAlarms | length(@)' --output text)" +echo " ALARM: $(aws cloudwatch describe-alarms --state-value ALARM --query 'MetricAlarms | length(@)' --output text)" +echo " INSUFFICIENT_DATA: $(aws cloudwatch describe-alarms --state-value INSUFFICIENT_DATA --query 'MetricAlarms | length(@)' --output text)" +echo ""; echo "Tutorial complete. Read-only."; rm -rf "$WORK_DIR"