diff --git a/.doc_gen/metadata/comprehend_metadata.yaml b/.doc_gen/metadata/comprehend_metadata.yaml index b2590b3d34f..9e2a675eaa9 100644 --- a/.doc_gen/metadata/comprehend_metadata.yaml +++ b/.doc_gen/metadata/comprehend_metadata.yaml @@ -172,6 +172,15 @@ comprehend_DetectDominantLanguage: snippet_tags: - python.example_code.comprehend.ComprehendDetect - python.example_code.comprehend.DetectDominantLanguage + Rust: + versions: + - sdk_version: 1 + github: rustv1/examples/comprehend + sdkguide: + excerpts: + - description: + snippet_tags: + - comprehend.rust.detect-language services: comprehend: {DetectDominantLanguage} comprehend_DetectEntities: @@ -204,6 +213,15 @@ comprehend_DetectEntities: snippet_tags: - python.example_code.comprehend.ComprehendDetect - python.example_code.comprehend.DetectEntities + Rust: + versions: + - sdk_version: 1 + github: rustv1/examples/comprehend + sdkguide: + excerpts: + - description: + snippet_tags: + - comprehend.rust.detect-entities services: comprehend: {DetectEntities} comprehend_DetectKeyPhrases: @@ -291,6 +309,15 @@ comprehend_DetectSentiment: snippet_tags: - python.example_code.comprehend.ComprehendDetect - python.example_code.comprehend.DetectSentiment + Rust: + versions: + - sdk_version: 1 + github: rustv1/examples/comprehend + sdkguide: + excerpts: + - description: + snippet_tags: + - comprehend.rust.detect-sentiment services: comprehend: {DetectSentiment} comprehend_DetectSyntax: @@ -325,6 +352,23 @@ comprehend_DetectSyntax: - python.example_code.comprehend.DetectSyntax services: comprehend: {DetectSyntax} +comprehend_Hello: + title: Hello &CMP; + title_abbrev: Hello &CMP; + synopsis: Get started using &CMP; by detecting the dominant language in text. + category: Hello + languages: + Rust: + versions: + - sdk_version: 1 + github: rustv1/examples/comprehend + sdkguide: + excerpts: + - description: + snippet_tags: + - comprehend.rust.hello + services: + comprehend: {DetectDominantLanguage} comprehend_Usage_DetectApis: title: Detect document elements with &CMP; and an &AWS; SDK title_abbrev: Detect document elements @@ -354,6 +398,15 @@ comprehend_Usage_DetectApis: - description: Call functions on the wrapper class to detect entities, phrases, and more in a document. snippet_tags: - python.example_code.comprehend.Usage_DetectApis + Rust: + versions: + - sdk_version: 1 + github: rustv1/examples/comprehend + sdkguide: + excerpts: + - description: Run a comprehensive scenario demonstrating various Amazon Comprehend text analysis capabilities. + snippet_tags: + - comprehend.rust.getting-started services: comprehend: {DetectDominantLanguage, DetectEntities, DetectKeyPhrases, DetectPiiEntities, DetectSentiment, DetectSyntax} comprehend_StartTopicsDetectionJob: diff --git a/rustv1/examples/comprehend/Cargo.toml b/rustv1/examples/comprehend/Cargo.toml new file mode 100644 index 00000000000..4fbf191513e --- /dev/null +++ b/rustv1/examples/comprehend/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "comprehend-code-examples" +version = "0.1.0" +authors = [ + "AWS SDK for Rust Team ", +] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +aws-config = { version = "1.0.1", features = ["behavior-version-latest"] } +aws-sdk-comprehend = { version = "1.3.0" } +aws-types = { version = "1.0.1" } +tokio = { version = "1.20.1", features = ["full"] } +clap = { version = "4.4", features = ["derive"] } +tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } +tracing = "0.1.40" \ No newline at end of file diff --git a/rustv1/examples/comprehend/README.md b/rustv1/examples/comprehend/README.md new file mode 100644 index 00000000000..00f244aa137 --- /dev/null +++ b/rustv1/examples/comprehend/README.md @@ -0,0 +1,140 @@ +# Amazon Comprehend code examples for the SDK for Rust + +## Overview + +Shows how to use the AWS SDK for Rust to work with Amazon Comprehend. + + + + +_Amazon Comprehend is a natural language processing (NLP) service that uses machine learning to find insights and relationships in text._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `rustv1` folder. + +### Get started + +- [Hello Amazon Comprehend](src/bin/hello.rs#L25) (`DetectDominantLanguage`) + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [DetectDominantLanguage](src/bin/detect-language.rs#L18) (`DetectDominantLanguage`) +- [DetectEntities](src/bin/detect-entities.rs#L18) (`DetectEntities`) +- [DetectSentiment](src/bin/detect-sentiment.rs#L18) (`DetectSentiment`) + +### Scenarios + +Code examples that show you how to accomplish a specific task by calling multiple functions within the same service. + +- [Get started with Amazon Comprehend](src/bin/getting-started.rs) (`DetectDominantLanguage`, `DetectEntities`, `DetectKeyPhrases`, `DetectSentiment`, `DetectPiiEntities`, `DetectSyntax`) + +## Run the examples + +### Instructions + + + + +#### Hello Amazon Comprehend + +This example shows you how to get started using Amazon Comprehend. + +``` +cargo run --bin hello +``` + +#### Get started with Amazon Comprehend + +This example shows you how to do the following: + +- Detect the dominant language in text. +- Extract entities from text. +- Detect key phrases in text. +- Analyze sentiment in text. +- Detect personally identifiable information (PII) in text. +- Analyze syntax in text. + +``` +cargo run --bin getting-started +``` + +#### Detect dominant language + +This example shows you how to detect the dominant language in text. + +``` +cargo run --bin detect-language +``` + +You can also specify custom text: + +``` +cargo run --bin detect-language -- --text "Bonjour, comment allez-vous?" +``` + +#### Detect entities + +This example shows you how to detect entities in text. + +``` +cargo run --bin detect-entities +``` + +You can also specify custom text and language: + +``` +cargo run --bin detect-entities -- --text "John works at Amazon in Seattle" --language-code "en" +``` + +#### Detect sentiment + +This example shows you how to detect sentiment in text. + +``` +cargo run --bin detect-sentiment +``` + +You can also specify custom text and language: + +``` +cargo run --bin detect-sentiment -- --text "I love this product!" --language-code "en" +``` + +### Tests + +⚠ Running tests might result in charges to your AWS account. + +To find instructions for running these tests, see the [README](../../README.md#Tests) in the `rustv1` folder. + + + + +## Additional resources + +- [Amazon Comprehend Developer Guide](https://docs.aws.amazon.com/comprehend/latest/dg/what-is.html) +- [Amazon Comprehend API Reference](https://docs.aws.amazon.com/comprehend/latest/APIReference/Welcome.html) +- [SDK for Rust Amazon Comprehend reference](https://docs.rs/aws-sdk-comprehend/latest/aws_sdk_comprehend/) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/bin/detect-entities.rs b/rustv1/examples/comprehend/src/bin/detect-entities.rs new file mode 100644 index 00000000000..252aa5c4216 --- /dev/null +++ b/rustv1/examples/comprehend/src/bin/detect-entities.rs @@ -0,0 +1,104 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_sdk_comprehend::{config::Region, Client, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The text to analyze for entities. + #[structopt(short, long)] + text: Option, + + /// The language code (e.g., "en" for English). + #[structopt(short, long)] + language_code: Option, + + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +// snippet-start:[comprehend.rust.detect-entities] +/// Detects entities in the provided text using Amazon Comprehend. +async fn detect_entities(client: &aws_sdk_comprehend::Client, text: &str, language_code: &str) -> Result<(), Error> { + let response = client + .detect_entities() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + println!("Detected entities:"); + if let Some(entities) = response.entities { + if entities.is_empty() { + println!(" No entities detected."); + } else { + for entity in entities { + println!( + " {}: {} (confidence: {:.2}%)", + entity.r#type().unwrap().as_str(), + entity.text().unwrap_or("unknown"), + entity.score().unwrap_or(0.0) * 100.0 + ); + } + } + } else { + println!(" No entities detected."); + } + + Ok(()) +} +// snippet-end:[comprehend.rust.detect-entities] + +/// Detects entities in text using Amazon Comprehend. +/// +/// # Arguments +/// +/// * `[-t TEXT]` - The text to analyze. If not provided, uses a default sample. +/// * `[-l LANGUAGE_CODE]` - The language code (e.g., "en"). If not provided, defaults to "en". +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + let Opt { text, language_code, region, verbose } = Opt::parse(); + + let region_provider = RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")); + + if verbose { + println!("Comprehend client version: {}", aws_sdk_comprehend::meta::PKG_VERSION); + println!( + "Region: {}", + region_provider.region().await.unwrap().as_ref() + ); + println!(); + } + + let shared_config = aws_config::from_env().region(region_provider).load().await; + let client = Client::new(&shared_config); + + let text_to_analyze = text.as_deref().unwrap_or( + "John Doe works at Amazon Web Services in Seattle, Washington. He can be reached at john.doe@example.com." + ); + let lang_code = language_code.as_deref().unwrap_or("en"); + + println!("Analyzing text: \"{}\"", text_to_analyze); + println!("Language code: {}", lang_code); + println!(); + + detect_entities(&client, text_to_analyze, lang_code).await?; + + Ok(()) +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/bin/detect-language.rs b/rustv1/examples/comprehend/src/bin/detect-language.rs new file mode 100644 index 00000000000..889d0a6c928 --- /dev/null +++ b/rustv1/examples/comprehend/src/bin/detect-language.rs @@ -0,0 +1,91 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_sdk_comprehend::{config::Region, Client, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The text to analyze for language detection. + #[structopt(short, long)] + text: Option, + + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +// snippet-start:[comprehend.rust.detect-language] +/// Detects the dominant language in the provided text using Amazon Comprehend. +async fn detect_dominant_language(client: &aws_sdk_comprehend::Client, text: &str) -> Result<(), Error> { + let response = client + .detect_dominant_language() + .text(text) + .send() + .await?; + + println!("Detected languages:"); + if let Some(languages) = response.languages { + for language in languages { + println!( + " Language: {} (confidence: {:.2}%)", + language.language_code().unwrap_or("unknown"), + language.score().unwrap_or(0.0) * 100.0 + ); + } + } else { + println!(" No languages detected."); + } + + Ok(()) +} +// snippet-end:[comprehend.rust.detect-language] + +/// Detects the dominant language in text using Amazon Comprehend. +/// +/// # Arguments +/// +/// * `[-t TEXT]` - The text to analyze. If not provided, uses a default sample. +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + let Opt { text, region, verbose } = Opt::parse(); + + let region_provider = RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")); + + if verbose { + println!("Comprehend client version: {}", aws_sdk_comprehend::meta::PKG_VERSION); + println!( + "Region: {}", + region_provider.region().await.unwrap().as_ref() + ); + println!(); + } + + let shared_config = aws_config::from_env().region(region_provider).load().await; + let client = Client::new(&shared_config); + + let text_to_analyze = text.as_deref().unwrap_or( + "Hello, how are you today? I hope you're having a wonderful day!" + ); + + println!("Analyzing text: \"{}\"", text_to_analyze); + println!(); + + detect_dominant_language(&client, text_to_analyze).await?; + + Ok(()) +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/bin/detect-sentiment.rs b/rustv1/examples/comprehend/src/bin/detect-sentiment.rs new file mode 100644 index 00000000000..417f6bd2ce5 --- /dev/null +++ b/rustv1/examples/comprehend/src/bin/detect-sentiment.rs @@ -0,0 +1,97 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_sdk_comprehend::{config::Region, Client, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The text to analyze for sentiment. + #[structopt(short, long)] + text: Option, + + /// The language code (e.g., "en" for English). + #[structopt(short, long)] + language_code: Option, + + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +// snippet-start:[comprehend.rust.detect-sentiment] +/// Detects sentiment in the provided text using Amazon Comprehend. +async fn detect_sentiment(client: &aws_sdk_comprehend::Client, text: &str, language_code: &str) -> Result<(), Error> { + let response = client + .detect_sentiment() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + println!("Sentiment analysis results:"); + println!(" Overall sentiment: {}", response.sentiment().unwrap().as_str()); + + if let Some(sentiment_score) = response.sentiment_score { + println!(" Sentiment scores:"); + println!(" Positive: {:.2}%", sentiment_score.positive().unwrap_or(0.0) * 100.0); + println!(" Negative: {:.2}%", sentiment_score.negative().unwrap_or(0.0) * 100.0); + println!(" Neutral: {:.2}%", sentiment_score.neutral().unwrap_or(0.0) * 100.0); + println!(" Mixed: {:.2}%", sentiment_score.mixed().unwrap_or(0.0) * 100.0); + } + + Ok(()) +} +// snippet-end:[comprehend.rust.detect-sentiment] + +/// Detects sentiment in text using Amazon Comprehend. +/// +/// # Arguments +/// +/// * `[-t TEXT]` - The text to analyze. If not provided, uses a default sample. +/// * `[-l LANGUAGE_CODE]` - The language code (e.g., "en"). If not provided, defaults to "en". +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + let Opt { text, language_code, region, verbose } = Opt::parse(); + + let region_provider = RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")); + + if verbose { + println!("Comprehend client version: {}", aws_sdk_comprehend::meta::PKG_VERSION); + println!( + "Region: {}", + region_provider.region().await.unwrap().as_ref() + ); + println!(); + } + + let shared_config = aws_config::from_env().region(region_provider).load().await; + let client = Client::new(&shared_config); + + let text_to_analyze = text.as_deref().unwrap_or( + "I absolutely love using Amazon Web Services! The cloud services are fantastic and make development so much easier." + ); + let lang_code = language_code.as_deref().unwrap_or("en"); + + println!("Analyzing text: \"{}\"", text_to_analyze); + println!("Language code: {}", lang_code); + println!(); + + detect_sentiment(&client, text_to_analyze, lang_code).await?; + + Ok(()) +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/bin/getting-started.rs b/rustv1/examples/comprehend/src/bin/getting-started.rs new file mode 100644 index 00000000000..49f223d54c9 --- /dev/null +++ b/rustv1/examples/comprehend/src/bin/getting-started.rs @@ -0,0 +1,74 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_sdk_comprehend::{config::Region, Client, Error}; +use clap::Parser; +use comprehend_code_examples::getting_started::scenario::ComprehendScenario; + +#[derive(Debug, Parser)] +struct Opt { + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +// snippet-start:[comprehend.rust.getting-started] +/// Amazon Comprehend Getting Started - demonstrates comprehensive text analysis capabilities. +/// +/// This example shows how to use Amazon Comprehend to: +/// - Detect the dominant language in text +/// - Extract entities (people, places, organizations, etc.) +/// - Identify key phrases +/// - Analyze sentiment +/// - Detect personally identifiable information (PII) +/// - Analyze syntax and parts of speech +/// +/// # Arguments +/// +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + let Opt { region, verbose } = Opt::parse(); + + let region_provider = RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")); + + if verbose { + println!("Comprehend client version: {}", aws_sdk_comprehend::meta::PKG_VERSION); + println!( + "Region: {}", + region_provider.region().await.unwrap().as_ref() + ); + println!(); + } + + let shared_config = aws_config::from_env().region(region_provider).load().await; + let client = Client::new(&shared_config); + + let scenario = ComprehendScenario::new(client); + + match scenario.run().await { + Ok(()) => { + println!("Comprehend getting started scenario completed successfully!"); + } + Err(e) => { + eprintln!("Error running Comprehend scenario: {}", e); + std::process::exit(1); + } + } + + Ok(()) +} +// snippet-end:[comprehend.rust.getting-started] \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/bin/hello.rs b/rustv1/examples/comprehend/src/bin/hello.rs new file mode 100644 index 00000000000..5e0607780e0 --- /dev/null +++ b/rustv1/examples/comprehend/src/bin/hello.rs @@ -0,0 +1,100 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +#![allow(clippy::result_large_err)] + +use aws_config::meta::region::RegionProviderChain; +use aws_sdk_comprehend::{config::Region, meta::PKG_VERSION, Client, Error}; +use clap::Parser; + +#[derive(Debug, Parser)] +struct Opt { + /// The AWS Region. + #[structopt(short, long)] + region: Option, + + /// Whether to display additional information. + #[structopt(short, long)] + verbose: bool, +} + +// snippet-start:[comprehend.rust.hello] +/// A simple example demonstrating Amazon Comprehend by detecting the dominant language +/// in a sample text. +async fn detect_sample_language(client: &aws_sdk_comprehend::Client) { + let sample_text = "Hello, how are you today? I hope you're having a great day!"; + + println!("Analyzing sample text: \"{}\"", sample_text); + + let response = client + .detect_dominant_language() + .text(sample_text) + .send() + .await; + + match response { + Ok(output) => { + if let Some(languages) = output.languages { + println!("Detected languages:"); + for language in languages { + println!( + " Language: {} (confidence: {:.2}%)", + language.language_code().unwrap_or("unknown"), + language.score().unwrap_or(0.0) * 100.0 + ); + } + } else { + println!("No languages detected."); + } + } + Err(err) => { + let err = err.into_service_error(); + let meta = err.meta(); + let message = meta.message().unwrap_or("unknown"); + let code = meta.code().unwrap_or("unknown"); + eprintln!("Error detecting language: ({code}) {message}"); + } + } +} +// snippet-end:[comprehend.rust.hello] + +/// Hello Amazon Comprehend - demonstrates basic language detection. +/// +/// # Arguments +/// +/// * `[-r REGION]` - The Region in which the client is created. +/// If not supplied, uses the value of the **AWS_REGION** environment variable. +/// If the environment variable is not set, defaults to **us-west-2**. +/// * `[-v]` - Whether to display additional information. +#[tokio::main] +async fn main() -> Result<(), Error> { + tracing_subscriber::fmt::init(); + let Opt { region, verbose } = Opt::parse(); + + let region_provider = RegionProviderChain::first_try(region.map(Region::new)) + .or_default_provider() + .or_else(Region::new("us-west-2")); + + println!(); + println!("Hello Amazon Comprehend!"); + println!(); + + if verbose { + println!("Comprehend client version: {}", PKG_VERSION); + println!( + "Region: {}", + region_provider.region().await.unwrap().as_ref() + ); + println!(); + } + + let shared_config = aws_config::from_env().region(region_provider).load().await; + let client = Client::new(&shared_config); + + detect_sample_language(&client).await; + + println!(); + println!("Hello Amazon Comprehend completed successfully!"); + + Ok(()) +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/comprehend.rs b/rustv1/examples/comprehend/src/comprehend.rs new file mode 100644 index 00000000000..4b229aecadc --- /dev/null +++ b/rustv1/examples/comprehend/src/comprehend.rs @@ -0,0 +1,138 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aws_sdk_comprehend::{Client, Error as ComprehendError}; +use aws_sdk_comprehend::types::{DominantLanguage, Entity, KeyPhrase, PiiEntity, SentimentScore, SyntaxToken}; + +/// A wrapper around the Comprehend client to provide higher-level operations. +pub struct ComprehendManager { + client: Client, +} + +impl ComprehendManager { + /// Create a new ComprehendManager with the given client. + pub fn new(client: Client) -> Self { + Self { client } + } + + /// Detect the dominant language in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// + /// # Returns + /// A vector of DominantLanguage structs with language codes and confidence scores + pub async fn detect_dominant_language(&self, text: &str) -> Result, ComprehendError> { + let response = self + .client + .detect_dominant_language() + .text(text) + .send() + .await?; + + Ok(response.languages.unwrap_or_default()) + } + + /// Detect entities in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// * `language_code` - The language code (e.g., "en" for English) + /// + /// # Returns + /// A vector of Entity structs with entity information and confidence scores + pub async fn detect_entities(&self, text: &str, language_code: &str) -> Result, ComprehendError> { + let response = self + .client + .detect_entities() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + Ok(response.entities.unwrap_or_default()) + } + + /// Detect key phrases in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// * `language_code` - The language code (e.g., "en" for English) + /// + /// # Returns + /// A vector of KeyPhrase structs with phrases and confidence scores + pub async fn detect_key_phrases(&self, text: &str, language_code: &str) -> Result, ComprehendError> { + let response = self + .client + .detect_key_phrases() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + Ok(response.key_phrases.unwrap_or_default()) + } + + /// Detect sentiment in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// * `language_code` - The language code (e.g., "en" for English) + /// + /// # Returns + /// A tuple containing the sentiment string and sentiment scores + pub async fn detect_sentiment(&self, text: &str, language_code: &str) -> Result<(String, Option), ComprehendError> { + let response = self + .client + .detect_sentiment() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + let sentiment = response.sentiment.map(|s| s.as_str().to_string()).unwrap_or_else(|| "UNKNOWN".to_string()); + let sentiment_score = response.sentiment_score; + + Ok((sentiment, sentiment_score)) + } + + /// Detect personally identifiable information (PII) in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// * `language_code` - The language code (e.g., "en" for English) + /// + /// # Returns + /// A vector of PiiEntity structs with PII information and confidence scores + pub async fn detect_pii_entities(&self, text: &str, language_code: &str) -> Result, ComprehendError> { + let response = self + .client + .detect_pii_entities() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + Ok(response.entities.unwrap_or_default()) + } + + /// Detect syntax elements in the given text. + /// + /// # Arguments + /// * `text` - The text to analyze + /// * `language_code` - The language code (e.g., "en" for English) + /// + /// # Returns + /// A vector of SyntaxToken structs with syntax information + pub async fn detect_syntax(&self, text: &str, language_code: &str) -> Result, ComprehendError> { + let response = self + .client + .detect_syntax() + .text(text) + .language_code(language_code.into()) + .send() + .await?; + + Ok(response.syntax_tokens.unwrap_or_default()) + } +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/getting_started/mod.rs b/rustv1/examples/comprehend/src/getting_started/mod.rs new file mode 100644 index 00000000000..cea5f448350 --- /dev/null +++ b/rustv1/examples/comprehend/src/getting_started/mod.rs @@ -0,0 +1,7 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod scenario; + +#[cfg(test)] +pub mod tests; \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/getting_started/scenario.rs b/rustv1/examples/comprehend/src/getting_started/scenario.rs new file mode 100644 index 00000000000..b4086b93f56 --- /dev/null +++ b/rustv1/examples/comprehend/src/getting_started/scenario.rs @@ -0,0 +1,160 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use crate::comprehend::ComprehendManager; +use aws_sdk_comprehend::Client; + +/// Demonstrates various Amazon Comprehend text analysis capabilities. +pub struct ComprehendScenario { + manager: ComprehendManager, +} + +impl ComprehendScenario { + /// Create a new ComprehendScenario with the given client. + pub fn new(client: Client) -> Self { + Self { + manager: ComprehendManager::new(client), + } + } + + /// Run the complete Comprehend basics scenario. + /// + /// This demonstrates: + /// - Language detection + /// - Entity detection + /// - Key phrase detection + /// - Sentiment analysis + /// - PII detection + /// - Syntax analysis + pub async fn run(&self) -> Result<(), Box> { + let sample_text = "Hello, my name is John Doe and I work at Amazon Web Services in Seattle. \ + I'm really excited about machine learning and natural language processing! \ + You can reach me at john.doe@example.com or call me at (555) 123-4567. \ + Today is a wonderful day for learning about AWS services."; + + println!("=== Amazon Comprehend Basics Scenario ==="); + println!(); + println!("Sample text for analysis:"); + println!("\"{}\"", sample_text); + println!(); + + // Step 1: Detect dominant language + println!("1. Detecting dominant language..."); + let languages = self.manager.detect_dominant_language(sample_text).await?; + + if languages.is_empty() { + println!(" No languages detected."); + return Ok(()); + } + + let primary_language = &languages[0]; + let language_code = primary_language.language_code().unwrap_or("en"); + + println!(" Primary language: {} (confidence: {:.2}%)", + language_code, + primary_language.score().unwrap_or(0.0) * 100.0); + + if languages.len() > 1 { + println!(" Other detected languages:"); + for lang in &languages[1..] { + println!(" - {}: {:.2}%", + lang.language_code().unwrap_or("unknown"), + lang.score().unwrap_or(0.0) * 100.0); + } + } + println!(); + + // Step 2: Detect entities + println!("2. Detecting entities..."); + let entities = self.manager.detect_entities(sample_text, language_code).await?; + + if entities.is_empty() { + println!(" No entities detected."); + } else { + println!(" Found {} entities:", entities.len()); + for entity in &entities { + println!(" - {}: {} (confidence: {:.2}%)", + entity.r#type().unwrap().as_str(), + entity.text().unwrap_or("unknown"), + entity.score().unwrap_or(0.0) * 100.0); + } + } + println!(); + + // Step 3: Detect key phrases + println!("3. Detecting key phrases..."); + let key_phrases = self.manager.detect_key_phrases(sample_text, language_code).await?; + + if key_phrases.is_empty() { + println!(" No key phrases detected."); + } else { + println!(" Found {} key phrases:", key_phrases.len()); + for phrase in &key_phrases { + println!(" - \"{}\" (confidence: {:.2}%)", + phrase.text().unwrap_or("unknown"), + phrase.score().unwrap_or(0.0) * 100.0); + } + } + println!(); + + // Step 4: Detect sentiment + println!("4. Analyzing sentiment..."); + let (sentiment, sentiment_scores) = self.manager.detect_sentiment(sample_text, language_code).await?; + + println!(" Overall sentiment: {}", sentiment); + if let Some(scores) = sentiment_scores { + println!(" Sentiment scores:"); + println!(" - Positive: {:.2}%", scores.positive().unwrap_or(0.0) * 100.0); + println!(" - Negative: {:.2}%", scores.negative().unwrap_or(0.0) * 100.0); + println!(" - Neutral: {:.2}%", scores.neutral().unwrap_or(0.0) * 100.0); + println!(" - Mixed: {:.2}%", scores.mixed().unwrap_or(0.0) * 100.0); + } else { + println!(" No sentiment scores available."); + } + println!(); + + // Step 5: Detect PII entities + println!("5. Detecting personally identifiable information (PII)..."); + let pii_entities = self.manager.detect_pii_entities(sample_text, language_code).await?; + + if pii_entities.is_empty() { + println!(" No PII entities detected."); + } else { + println!(" Found {} PII entities:", pii_entities.len()); + for pii in &pii_entities { + println!(" - {}: {} (confidence: {:.2}%)", + pii.r#type().unwrap().as_str(), + sample_text.chars() + .skip(pii.begin_offset().unwrap_or(0) as usize) + .take((pii.end_offset().unwrap_or(0) - pii.begin_offset().unwrap_or(0)) as usize) + .collect::(), + pii.score().unwrap_or(0.0) * 100.0); + } + } + println!(); + + // Step 6: Detect syntax + println!("6. Analyzing syntax (first 10 tokens)..."); + let syntax_tokens = self.manager.detect_syntax(sample_text, language_code).await?; + + if syntax_tokens.is_empty() { + println!(" No syntax tokens detected."); + } else { + println!(" Found {} syntax tokens (showing first 10):", syntax_tokens.len()); + for (i, token) in syntax_tokens.iter().take(10).enumerate() { + println!(" {}. \"{}\": {} (confidence: {:.2}%)", + i + 1, + token.text().unwrap_or("unknown"), + token.part_of_speech().unwrap().tag().unwrap().as_str(), + token.part_of_speech().unwrap().score().unwrap_or(0.0) * 100.0); + } + if syntax_tokens.len() > 10 { + println!(" ... and {} more tokens", syntax_tokens.len() - 10); + } + } + println!(); + + println!("=== Comprehend Basics Scenario Complete ==="); + Ok(()) + } +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/getting_started/tests/mod.rs b/rustv1/examples/comprehend/src/getting_started/tests/mod.rs new file mode 100644 index 00000000000..40881692baa --- /dev/null +++ b/rustv1/examples/comprehend/src/getting_started/tests/mod.rs @@ -0,0 +1,86 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +use aws_config::BehaviorVersion; +use aws_sdk_comprehend::Client; +use crate::getting_started::scenario::ComprehendScenario; + +#[tokio::test] +async fn test_comprehend_scenario() { + let config = aws_config::defaults(BehaviorVersion::latest()) + .load() + .await; + let client = Client::new(&config); + let scenario = ComprehendScenario::new(client); + + // Run the scenario - this will make real API calls + let result = scenario.run().await; + + // The scenario should complete successfully + assert!(result.is_ok(), "Comprehend scenario should complete successfully: {:?}", result); +} + +#[tokio::test] +async fn test_detect_language() { + let config = aws_config::defaults(BehaviorVersion::latest()) + .load() + .await; + let client = Client::new(&config); + + let response = client + .detect_dominant_language() + .text("Hello, how are you today?") + .send() + .await; + + assert!(response.is_ok(), "Language detection should succeed"); + + let languages = response.unwrap().languages.unwrap_or_default(); + assert!(!languages.is_empty(), "Should detect at least one language"); + + // The first language should be English with high confidence + let primary_language = &languages[0]; + assert_eq!(primary_language.language_code().unwrap_or(""), "en"); + assert!(primary_language.score().unwrap_or(0.0) > 0.9, "English detection confidence should be high"); +} + +#[tokio::test] +async fn test_detect_sentiment() { + let config = aws_config::defaults(BehaviorVersion::latest()) + .load() + .await; + let client = Client::new(&config); + + let response = client + .detect_sentiment() + .text("I love using AWS services! They are fantastic.") + .language_code("en".into()) + .send() + .await; + + assert!(response.is_ok(), "Sentiment detection should succeed"); + + let sentiment_response = response.unwrap(); + assert!(sentiment_response.sentiment.is_some(), "Should detect sentiment"); + assert!(sentiment_response.sentiment_score.is_some(), "Should have sentiment scores"); +} + +#[tokio::test] +async fn test_detect_entities() { + let config = aws_config::defaults(BehaviorVersion::latest()) + .load() + .await; + let client = Client::new(&config); + + let response = client + .detect_entities() + .text("John works at Amazon in Seattle.") + .language_code("en".into()) + .send() + .await; + + assert!(response.is_ok(), "Entity detection should succeed"); + + let entities = response.unwrap().entities.unwrap_or_default(); + assert!(!entities.is_empty(), "Should detect entities"); +} \ No newline at end of file diff --git a/rustv1/examples/comprehend/src/lib.rs b/rustv1/examples/comprehend/src/lib.rs new file mode 100644 index 00000000000..0359da8dc0b --- /dev/null +++ b/rustv1/examples/comprehend/src/lib.rs @@ -0,0 +1,5 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +pub mod comprehend; +pub mod getting_started; \ No newline at end of file