用 AWS SDK for Java 构建反馈情感分析器(FSA)多服务应用:从 Lambda 处理程序到 CDK 部署

发布时间:2026/9/25 5:22:47

用 AWS SDK for Java 构建反馈情感分析器(FSA)多服务应用:从 Lambda 处理程序到 CDK 部署 示例工程教程后端【免费下载链接】aws-doc-sdk-examplesWelcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.项目地址https://gitcode.com/gh_mirrors/aw/aws-doc-sdk-examples点击查看免费下载本文基于 aws-doc-sdk-examples 仓库中的javav2/usecases/creating_fsa_app教程完整讲解如何使用 AWS SDK for Java (v2) 的异步客户端开发一个反馈情感分析器Feedback Sentiment AnalyzerFSA应用S3 接收用户上传的多语言评论图片经 EventBridge 触发 Step Functions 工作流依次调用 Amazon Textract、Comprehend、Translate、Polly 完成“OCR 提取 → 情感判定 → 英文翻译 → 语音合成”并把结果写入 DynamoDB 与 S3。读完后你将掌握多服务事件驱动工作流的编排方式、四个 AWS Lambda 处理程序Handlers与五个异步 Service 类的完整实现、Maven 依赖配置BOM、shade 插件以及通过 AWS CDK 一键部署整套基础设施的方法。一、应用目标与服务全景FSA 应用模拟一个酒店场景住客在评论卡上以法语等多种语言写下反馈酒店方希望通过自动化流水线提取文字、判断情感倾向、翻译成英文并生成可播放的语音。该应用完成以下六件事源自 README用 Amazon S3 存储桶托管静态网站资源并通过 Amazon CloudFront 分发站点通过 Amazon Cognito 为 Amazon API Gateway 提供认证访问API Gateway 把条目写入 S3 存储桶随后触发 Amazon EventBridge 规则启动 AWS Step Functions 工作流Step Functions 工作流编排 AWS Lambda、Amazon Textract、Amazon Comprehend、Amazon Translate 和 Amazon Polly 执行业务核心逻辑元数据存入 Amazon DynamoDB音频文件存入第 3 步提到的同一 S3 存储桶API Gateway 从 DynamoDB 读取元数据返回给前端。从源码结构看四个 Lambda 后端函数分别对应四个机器学习/媒体服务Lambda 函数使用的服务异步客户端职责ExtractTextAmazon TextractTextractAsyncClient从 S3 中的图片提取文本AnalyzeSentimentAmazon ComprehendComprehendAsyncClient检测文本语言与情感TranslateTextAmazon TranslateTranslateAsyncClient把文本翻译成英文SynthesizeAudioAmazon Polly S3 Transfer ManagerPollyAsyncClient、S3AsyncClientCRT合成 MP3 音频并上传 S3二、前置条件完成本教程需要一个 AWS 账号Java IDE教程使用 IntelliJJava JDK 17与仓库 pom.xml 中maven.compiler.source/target 17一致Maven 3.6 或更高版本。注意事项原文档 Important 一节文档涉及的 AWS 服务均包含在 AWS Free Tier 中该代码未在全部 AWS 区域测试部分服务只在特定区域可用源码中各客户端统一硬编码Region.US_EAST_1跨区域部署时需自行调整运行代码可能产生费用完成教程后务必删除所有资源需按 SDK 文档正确配置开发环境。所需 AWS 资源全部由仓库配套的 AWS CDK 脚本创建无需在 AWS 管理控制台中手动创建任何资源。三、理解 FSA 应用FSA 前端是一个基于 Cloudscape Design System 的 React 应用支持把包含文字的图片上传到 S3 存储桶文字可以是法语等各种语言的客户评论。用户通过 Amazon Cognito 认证后应用会展示所有已上传图片、翻译后的文字以及一个可以收听 Amazon Polly 生成音频的按钮。3.1 图片上传后的工作流图片进入存储桶后EventBridge 规则被触发并启动 Step Functions 工作流各步骤如下ExtractText从图片中提取文本可能是法语等其他语言AnalyzeSentiment获取文本的情感例如判定正面或负面ContinueIfPositive根据情感值路由工作流——若为正面Positive进入下一步 TranslateTextTranslateText把文本翻译成英文SynthesizeAudio把英文文本转换成 MP3 音频文件并放入 S3 存储桶PutPositiveComment把数据写入 Amazon DynamoDB 表。注意客户端 React 应用在工作流成功完成、数据写入 S3 与 DynamoDB 之后才会显示任何数据。该 DynamoDB 表由运行 AWS CDK 脚本时自动创建详见 feedback_sentiment_analyzer 的 CDK 说明。3.2 AWS Lambda 函数命名约定后端由上述四个 Lambda 函数实现使用 AWS SDK for Java v2。注意这些是短名称控制台中显示的完整名称取决于 CDK 配置格式为{NAME}{Function Name}例如fsa-user-java-SynthesizeAudio134971D4-x8Q5178Y4ZBH。这些 Lambda 无需手动部署全部由 CDK 脚本完成。四、创建 IntelliJ 项目在 IntelliJ IDE 中依次选择File、New、Project在New Project对话框中选择Maven然后选择NextGroupId填写aws-fsaArtifactId填写fsa_app选择Next再选择Finish。五、添加 POM 依赖README 要求项目pom.xml与仓库中的 POM 保持一致。仓库实际文件为 pom.xml其要点如下通过dependencyManagement导入software.amazon.awssdk:bom:2.21.20与org.apache.logging.log4j:log4j-bom:2.19.0两个 BOM统一各 SDK 模块版本SDK 模块依赖包括textract、comprehend、translate、polly、s3、s3control、dynamodb、lambda以及apache-client排除了commons-logging以消除日志冲突software.amazon.awssdk.crt:aws-crt:0.25.1为S3AsyncClient.crtBuilder()提供基于 AWS CRT 的异步 S3 客户端software.amazon.awssdk:s3-transfer-manager:2.20.26S3 Transfer Manager用于高吞吐上传com.amazonaws:aws-lambda-java-core:1.2.2与com.amazonaws:aws-lambda-java-events:3.11.1Lambda Java 运行时 APIRequestHandler、Context与事件模型com.googlecode.json-simple:json-simple:1.1Handlers 与 Services 间以org.json.simple.JSONObject传递结果构建插件maven-shade-plugin:3.3.0在package阶段执行shade把所有依赖打进单个 fat JAR——这正是 Lambda 部署包能“一个 JAR 走天下”的原因maven-surefire-plugin:2.22.2负责运行测试测试依赖junit-jupiter-api/junit-jupiter-engine5.9.0scope 为test。六、创建 Java 类在main/java下创建包com.example.fsa代码放入其子包。6.1 Handlers 包四个 Lambda 处理程序包com.example.fsa.handlers中的每个类都是一个独立 Lambda 函数的处理程序使用 AWS Lambda Java 运行时 API 的RequestHandler接口实现输入类型均为MapString, ObjectStep Functions 传入的 JSON 载荷通过context.getLogger().log(...)输出 CloudWatch 日志。AnalyzeSentimentHandler接收source_text字段调用情感服务后返回含sentiment与language_code的 JSON对应源码 AnalyzeSentimentHandler.javapackage com.example.fsa.handlers; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.example.fsa.services.DetectSentimentService; import org.json.simple.JSONObject; import java.util.Map; public class AnalyzeSentimentHandler implements RequestHandlerMapString, Object, JSONObject { Override public JSONObject handleRequest(MapString, Object requestObject, Context context) { String sourceText (String) requestObject.get(source_text); context.getLogger().log(Extracted text: sourceText); DetectSentimentService detectSentimentService new DetectSentimentService(); JSONObject jsonOb detectSentimentService.detectSentiments(sourceText); context.getLogger().log(JSON: jsonOb.toJSONString()); return jsonOb; } }ExtractTextHandler从 EventBridge 事件载荷中取出bucket与object两个字段调用 Textract 服务提取文本对应 ExtractTextHandler.javapackage com.example.fsa.handlers; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.example.fsa.services.ExtractTextService; import java.util.Map; public class ExtractTextHandler implements RequestHandlerMapString, Object, String{ Override public String handleRequest(MapString, Object requestObject, Context context) { // Get the Amazon Simple Storage Service (Amazon S3) bucket and object key from the Amazon EventBridge event. ExtractTextService textService new ExtractTextService(); String bucket (String) requestObject.get(bucket); String fileName (String) requestObject.get(object); context.getLogger().log(*** Bucket: bucket , fileName: fileName); String extractedText textService.getCardText(bucket, fileName); context.getLogger().log(*** Text: extractedText); return extractedText; } }SynthesizeAudioHandler读取translated_text、bucket、object在 key 后追加.mp3先用 Polly 合成音频再上传 S3对应 SynthesizeAudioHandler.javapackage com.example.fsa.handlers; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.example.fsa.services.PollyService; import com.example.fsa.services.S3Service; import java.io.IOException; import java.io.InputStream; import java.util.Map; public class SynthesizeAudioHandler implements RequestHandlerMapString, Object, String { Override public String handleRequest(MapString, Object requestObject, Context context) { S3Service s3Service new S3Service(); PollyService pollyService new PollyService(); String translatedText (String) requestObject.get(translated_text); String bucket (String) requestObject.get(bucket); String key (String) requestObject.get(object); key key .mp3; // Appends .mp3 to the existing value of key context.getLogger().log(*** Translated Text: translatedText and new key is key); try { InputStream is pollyService.synthesize(translatedText); String audioFile s3Service.putAudio(is, bucket, key); context.getLogger().log(You have successfully added the audioFile in bucket); return audioFile ; } catch (IOException e) { throw new RuntimeException(e); } } }TranslateTextHandler读取extracted_text与source_language_code翻译后以{translated_text: ...}形式返回对应 TranslateTextHandler.javapackage com.example.fsa.handlers; import com.amazonaws.services.lambda.runtime.Context; import com.amazonaws.services.lambda.runtime.RequestHandler; import com.example.fsa.services.TranslateService; import org.json.simple.JSONObject; import java.util.Map; public class TranslateTextHandler implements RequestHandlerMapString, Object, JSONObject { Override public JSONObject handleRequest(MapString, Object requestObject, Context context) { TranslateService translateService new TranslateService(); String sourceText (String) requestObject.get(extracted_text); String lanCode (String) requestObject.get(source_language_code); context.getLogger().log(sourceText: sourceText lang code: lanCode); String translatedText translateService.translateText(lanCode, sourceText); context.getLogger().log(Translated text : translatedText); JSONObject jsonResponse new JSONObject(); jsonResponse.put(translated_text, translatedText); return jsonResponse; } }6.2 Services 包基于异步客户端的 AWS 操作包com.example.fsa.services中的类使用 AWS SDK for Java (v2)异步服务客户端执行各类 AWS 操作。从源码结构看五个类采用统一模式静态字段 private static synchronized懒加载获取单例客户端Lambda 容器可复用避免每次调用重建连接池请求发出后统一用CompletableFuture.join()阻塞等待结果——在 Lambda 这种“短任务、重结果”的场景下这种写法把异步客户端的吞吐优势与同步代码的可读性结合了起来。DetectSentimentService先定语言再定情感DetectSentimentService.java 使用ComprehendAsyncClient完成两步先用detectDominantLanguage判定文本主导语言再用该语言码调用detectSentiment判定情感。注意DetectSentimentRequest必须显式指定languageCode这正是先做语言检测的原因当无法识别语言时返回哨兵值No languages found。package com.example.fsa.services; import org.json.simple.JSONObject; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.comprehend.ComprehendAsyncClient; import software.amazon.awssdk.services.comprehend.model.ComprehendException; import software.amazon.awssdk.services.comprehend.model.DetectDominantLanguageRequest; import software.amazon.awssdk.services.comprehend.model.DetectDominantLanguageResponse; import software.amazon.awssdk.services.comprehend.model.DetectSentimentRequest; import software.amazon.awssdk.services.comprehend.model.DetectSentimentResponse; import software.amazon.awssdk.services.comprehend.model.DominantLanguage; import java.util.List; import java.util.concurrent.CompletableFuture; public class DetectSentimentService { private static ComprehendAsyncClient comprehendAsyncClient; private static synchronized ComprehendAsyncClient getComprehendAsyncClient() { if (comprehendAsyncClient null) { comprehendAsyncClient ComprehendAsyncClient.builder() .region(Region.US_EAST_1) .build(); } return comprehendAsyncClient; } public JSONObject detectSentiments(String text){ try { String languageCode detectTheDominantLanguage(text); DetectSentimentRequest detectSentimentRequest DetectSentimentRequest.builder() .text(text) .languageCode(languageCode) .build(); CompletableFuture? future getComprehendAsyncClient().detectSentiment(detectSentimentRequest); future.join(); // Wait for the operation to complete and get the result DetectSentimentResponse detectSentimentResult (DetectSentimentResponse) future.join(); JSONObject jsonObject new JSONObject(); jsonObject.put(sentiment, detectSentimentResult.sentimentAsString()); jsonObject.put(language_code, languageCode); return jsonObject; } catch (ComprehendException e) { System.err.println(e.awsErrorDetails().errorMessage()); throw e; } } public String detectTheDominantLanguage(String text){ try { DetectDominantLanguageRequest request DetectDominantLanguageRequest.builder() .text(text) .build(); CompletableFuture? future getComprehendAsyncClient().detectDominantLanguage(request); future.join(); DetectDominantLanguageResponse resp (DetectDominantLanguageResponse) future.join(); ListDominantLanguage allLanList resp.languages(); if (!allLanList.isEmpty()) { DominantLanguage firstLanguage allLanList.get(0); return firstLanguage.languageCode(); } else { return No languages found; } } catch (ComprehendException e) { System.out.println(e.getMessage()); throw e; } } }ExtractTextService只拼接 WORD 级别的 BlockExtractTextService.java 使用TextractAsyncClient对 S3 中的图片执行DetectDocumentText。响应中的文本按Block块组织代码只保留BlockType.WORD类型的块并逐个以空格拼接从而跳过 LINE/PAGE 等聚合块得到按阅读顺序排列的纯文本。异常处理上区分了业务异常TextractException与客户端异常SdkClientException两者均打印后原样重抛。package com.example.fsa.services; import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.textract.model.BlockType; import software.amazon.awssdk.services.textract.model.Document; import software.amazon.awssdk.services.textract.model.DetectDocumentTextRequest; import software.amazon.awssdk.services.textract.model.DetectDocumentTextResponse; import software.amazon.awssdk.services.textract.model.Block; import software.amazon.awssdk.services.textract.TextractAsyncClient; import software.amazon.awssdk.services.textract.model.S3Object; import software.amazon.awssdk.services.textract.model.TextractException; import java.util.concurrent.CompletableFuture; public class ExtractTextService { private static TextractAsyncClient textractAsyncClient; private static synchronized TextractAsyncClient getTextractAsyncClient() { if (textractAsyncClient null) { textractAsyncClient TextractAsyncClient.builder() .region(Region.US_EAST_1) .build(); } return textractAsyncClient; } public String getCardText(String bucketName, String obName) { try { S3Object s3Object S3Object.builder() .bucket(bucketName) .name(obName) .build(); Document myDoc Document.builder() .s3Object(s3Object) .build(); DetectDocumentTextRequest detectDocumentTextRequest DetectDocumentTextRequest.builder() .document(myDoc) .build(); StringBuilder completeText new StringBuilder(); CompletableFuture? future getTextractAsyncClient().detectDocumentText(detectDocumentTextRequest); future.join(); DetectDocumentTextResponse textResponse (DetectDocumentTextResponse) future.join(); for (Block block : textResponse.blocks()) { if (block.blockType() BlockType.WORD) { if (completeText.length() 0) { completeText.append(block.text()); } else { completeText.append( ).append(block.text()); } } } return completeText.toString(); } catch (TextractException e) { System.err.println(e.awsErrorDetails().errorMessage()); throw e; // Re-throw the exception. } catch (SdkClientException e) { System.err.println(e.getMessage()); throw e; // Re-throw the exception. } } }PollyService动态发现神经语音并合成 MP3PollyService.java 的合成流程分三步构造DescribeVoicesRequest并指定engine(neural)通过PollyAsyncClient.describeVoices异步请求可用语音列表future.join()阻塞等待随后用 Java 流在结果中过滤出名为Joanna的语音找不到则抛出RuntimeException(Voice not found)构造SynthesizeSpeechRequest输入文本、OutputFormat.MP3、voiceId通过synthesizeSpeech(request, AsyncResponseTransformer.toBlockingInputStream())把响应转换为ResponseInputStream最终返回包含合成音频的InputStream。package com.example.fsa.services; import software.amazon.awssdk.core.ResponseInputStream; import software.amazon.awssdk.core.async.AsyncResponseTransformer; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.polly.PollyAsyncClient; import software.amazon.awssdk.services.polly.model.DescribeVoicesRequest; import software.amazon.awssdk.services.polly.model.PollyException; import software.amazon.awssdk.services.polly.model.SynthesizeSpeechRequest; import software.amazon.awssdk.services.polly.model.SynthesizeSpeechResponse; import software.amazon.awssdk.services.polly.model.Voice; import software.amazon.awssdk.services.polly.model.DescribeVoicesResponse; import software.amazon.awssdk.services.polly.model.OutputFormat; import java.io.IOException; import java.io.InputStream; import java.util.concurrent.CompletableFuture; public class PollyService { private static PollyAsyncClient pollyAsyncClient; private static synchronized PollyAsyncClient getPollyAsyncClient() { if (pollyAsyncClient null) { Region region Region.US_EAST_1; pollyAsyncClient PollyAsyncClient.builder() .region(region) .build(); } return pollyAsyncClient; } public InputStream synthesize(String text) throws IOException { try { DescribeVoicesRequest describeVoicesRequest DescribeVoicesRequest.builder() .engine(neural) .build(); CompletableFuture? future getPollyAsyncClient().describeVoices(describeVoicesRequest); DescribeVoicesResponse describeVoicesResult (DescribeVoicesResponse) future.join(); Voice voice describeVoicesResult.voices().stream() .filter(v - v.name().equals(Joanna)) .findFirst() .orElseThrow(() - new RuntimeException(Voice not found)); SynthesizeSpeechRequest request SynthesizeSpeechRequest.builder() .text(text) .outputFormat(OutputFormat.MP3) .voiceId(voice.id()) .build(); CompletableFutureResponseInputStreamSynthesizeSpeechResponse audioFuture getPollyAsyncClient().synthesizeSpeech(request, AsyncResponseTransformer.toBlockingInputStream()); InputStream audioInputStream audioFuture.join(); return audioInputStream; } catch (PollyException e) { System.err.println(e.awsErrorDetails().errorMessage()); throw e; } } }S3Service用 Transfer Manager 上传 MP3S3Service.java 使用 Amazon S3 Transfer Manager API 上传 MP3 文件。实现细节值得注意底层客户端用S3AsyncClient.crtBuilder()构建即基于 AWS CRT 的高性能异步 S3 客户端对应 pom.xml 中的aws-crt依赖AsyncRequestBody.forBlockingInputStream(null)创建一个“稍后提供流”的BlockingInputStreamAsyncRequestBody——先注册上传任务再在body.writeInputStream(is)时把 Polly 返回的音频流写入Transfer Manager 负责分片与并发upload.completionFuture().join()确保上传完成后才返回。package com.example.fsa.services; import software.amazon.awssdk.core.async.AsyncRequestBody; import software.amazon.awssdk.core.async.BlockingInputStreamAsyncRequestBody; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.services.s3.model.S3Exception; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.Upload; import java.io.IOException; import java.io.InputStream; public class S3Service { private static S3AsyncClient s3AsyncClient; private static synchronized S3AsyncClient getS3AsyncClient() { if (s3AsyncClient null) { s3AsyncClient S3AsyncClient.crtBuilder() .region(Region.US_EAST_1) .build(); } return s3AsyncClient; } // Put the audio file into the Amazon S3 bucket. public String putAudio(InputStream is, String bucketName, String key) throws S3Exception, IOException { try { S3TransferManager transferManager S3TransferManager.builder() .s3Client(getS3AsyncClient()) .build(); // null indicates a stream will be provided later. BlockingInputStreamAsyncRequestBody body AsyncRequestBody.forBlockingInputStream(null); Upload upload transferManager.upload(builder - builder .requestBody(body) .putObjectRequest(req - req.bucket(bucketName).key(key)) .build()); body.writeInputStream(is); upload.completionFuture().join(); return key; } catch (S3Exception e) { System.err.println(e.getMessage()); throw e; } } }TranslateService定向翻译为英文TranslateService.java 使用TranslateAsyncClient.translateText源语言码取自 Comprehend 的语言检测结果目标语言固定en返回textResponse.translatedText()。package com.example.fsa.services; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.translate.TranslateAsyncClient; import software.amazon.awssdk.services.translate.model.TranslateException; import software.amazon.awssdk.services.translate.model.TranslateTextRequest; import software.amazon.awssdk.services.translate.model.TranslateTextResponse; import java.util.concurrent.CompletableFuture; public class TranslateService { private static TranslateAsyncClient translateAsyncClient; private static synchronized TranslateAsyncClient getTranslateAsyncClient() { if (translateAsyncClient null) { translateAsyncClient TranslateAsyncClient.builder() .region(Region.US_EAST_1) .build(); } return translateAsyncClient; } public String translateText(String lanCode, String text) { try { TranslateTextRequest textRequest TranslateTextRequest.builder() .sourceLanguageCode(lanCode) .targetLanguageCode(en) .text(text) .build(); CompletableFuture? future getTranslateAsyncClient().translateText(textRequest); TranslateTextResponse textResponse (TranslateTextResponse) future.join(); return textResponse.translatedText(); } catch (TranslateException e) { System.err.println(e.awsErrorDetails().errorMessage()); throw e; } } }七、部署 AWS 资源至此业务逻辑代码全部完成接下来部署 Lambda 函数与 API Gateway 端点等 AWS 资源。不要逐个在控制台中手动创建直接运行配套提供的 AWS CDK 脚本即可。完整的 CDK 运行说明见 Feedback Sentiment Analyzer (FSA)。7.1 检查 Lambda 角色的权限每个 Lambda 函数都有一个用于调用该函数的角色例如AnalyzeSentiment函数的角色形如java-AnalyzeSentimentServiceR-14R5C2CE32WCM具体名称取决于 CDK 配置。请确保每个角色具备调用对应服务的权限否则可能出现如下报错user: arn:aws:sts::xxxx:assumed-role/fsa-user-java-fnTranslateTextServiceRole41F86E1F-7K31GKO5HOUF is not authorized to perform: comprehend:DetectDominantLanguage because no identity-based policy allows the comprehend:DetectDominantLanguage action该报错直接对应DetectSentimentService.detectTheDominantLanguage的调用链fnTranslateText所关联的角色缺少comprehend:DetectDominantLanguage身份策略。修复方式是按 IAM 文档为角色补充相应服务权限。7.2 检查 Lambda 配置选项可检查并调整各函数的超时时间timeout与内存分配等配置项例如 Textract OCR 类任务通常需要比简单文本处理更长的超时预算。7.3 运行应用运行完 AWS CDK 脚本后使用 CDK 说明中给出的 Amazon CloudFront 分发 URL 访问客户端应用。在 React 客户端上传图片后工作流被触发可在 AWS Step Functions 中查看执行进度成功完成时每个状态均为绿色S3 存储桶中出现对应的.mp3文件DynamoDB 表中出现一条新记录。八、本地验证集成测试用例仓库在 FSATests.java 中提供了五个按Order排序的Tag(IntegrationTest)集成测试无需部署 Lambda 就能在本地串起整条服务链testTextExtractiontextService.getCardText(bucket, object)断言非空testSentimentAnalysis提取文本后做情感检测testTranslation先用detectTheDominantLanguage取得语言码再翻译testAudioSynthesis走完“提取 → 语言 → 翻译 → Polly 合成”全链路testS3Upload最后一步把objectName .mp3通过s3Service.putAudio上传到存储桶。运行前需把文件顶部的bucketName与objectName两个常量替换为你自己的存储桶与图片对象名并确保本地凭证具备 S3、Textract、Comprehend、Translate、Polly 权限。这五个测试方法也恰好复刻了 Step Functions 工作流中 ExtractText → AnalyzeSentiment → TranslateText → SynthesizeAudio → PutPositiveComment 的数据流可以视作工作流的本地等价验证。九、收尾与后续步骤部署验证完成后务必按照 CDK 说明删除全部资源避免持续计费所有客户端类中Region.US_EAST_1为硬编码若在其他区域部署需同步修改五个 Service 类中的区域设置更多 AWS 多服务示例可参考 javav2/usecases 目录下的其他用例。相关文件索引教程文档READMEMaven 配置pom.xmlLambda 处理程序handlers 包异步服务封装services 包集成测试FSATests.java配套 CDK 部署说明feedback_sentiment_analyzer README赞分享示例工程教程后端【免费下载链接】aws-doc-sdk-examplesWelcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below.项目地址https://gitcode.com/gh_mirrors/aw/aws-doc-sdk-examples点击查看免费下载相关推荐使用AWS Java SDK构建反馈情感分析应用的技术实践使用AWS Java SDK构建反馈情感分析应用的技术实践 引言客户反馈处理的智能化革命 在当今数字化时代企业每天都会收到大量的客户反馈这些反馈可能来自各示例工程教程后端Feedback Sentiment AnalyzerFSA实战指南基于 AWS 多语言 SDK 构建跨服务评论情感分析应用Feedback Sentiment AnalyzerFSA实战指南基于 AWS 多语言 SDK 构建跨服务评论情感分析应用 Feedback Senti示例工程教程后端RepViT架构解密repvit_m0_9.dist_300e_in1k如何融合CNN与ViT优势RepViT架构解密repvit_m0_9.dist_300e_in1k如何融合CNN与ViT优势 repvit_m0_9.dist_300e_in1k是一款上一篇PowerDNS三大组件对比何时选择权威、递归还是负载均衡下一篇Czkawka Windows 安装指南3 步装好重复文件清理神器创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
延伸阅读

更多相关文章

2026/9/25 5:17:47

工业互联网智慧运维落地:从数据采集到预测性维护闭环

简介:本资源是一份面向工业互联网从业者、智能制造工程师及企业数字化转型决策者的《工业互联网智慧运维整体解决方案》PPT课件,聚焦破解传统设备维护响应慢、定位难、成本高、协同差等痛点,系统阐述基于云计算、物联网、AI与数字孪生的智能维…

2026/9/25 6:12:48

毕业论文降AI处理中的格式保留技巧与工具选择

1. 毕业论文降AI格式保留的核心痛点每年毕业季,最让学生头疼的不是论文写作本身,而是最后的降AI环节。很多同学发现,辛辛苦苦写好的论文,经过降AI处理后,格式全乱了套。标题层级消失、表格错位、公式变成乱码、参考文献…

2026/9/25 6:12:48

Keil5同时安装STM32与C51冲突原因及共存方案

1. 为什么Keil5同时装STM32和C51会“打架”?——从许可证机制看根本矛盾我第一次在实验室电脑上装完Keil MDK-ARM v5.38,兴冲冲点开C51安装包准备给老学长的8051课程项目配环境时,弹窗直接把我钉在原地:“Keil C51已检测到现有ARM…

2026/9/25 6:12:48

AC6328A主从一体蓝牙透传实战:AT指令配置与避坑指南

1. 项目概述与主从一体架构拆解1.1 AC6328A是什么,为什么它值得用AC6328A是珠海杰理科技推出的一款低功耗蓝牙SoC芯片,这颗料在消费电子、物联网透传、智能家居控制这类场景里出镜率很高。它内置了BLE 5.x协议栈,原生支持串口透传&#xff0c…

2026/9/25 6:12:48

庐山派K230 Web监控实战:H.264+WebSocket+MSE低延迟方案

1. 庐山派K230做Web监控,我为什么选这条路庐山派K230这颗板子最近在创客圈里热度不低,6TOPS的NPU算力、双核RISC-V加一颗专用AI核、自带MIPI CSI接口和千兆网口,价格还压在两百块以内。很多人拿到手第一反应是跑个YOLO做目标检测,…

2026/9/24 20:24:47

GAMP 5 基于风险的计算机化系统验证:软件分类与审计追踪实践

简介:《A Risk-Based Approach to Compliant GxP Computerized Systems》即业内熟知的GAMP 5指南,面向制药企业质量与IT合规人员、验证工程师及计算机化系统管理者,用于解决GxP法规环境下系统合规性难以科学落地的问题。文档以风险管理为主线…

2026/9/23 12:06:55

安全托管MSSP实战:从静态防御到人机协同的攻防运营与应急响应

简介:这份PPT围绕互联网业务安全托管服务展开,面向企业安全负责人、IT运维人员及关注MSSP/MSS选型的读者,重点回应传统安全过度依赖人工、碎片化静态防御难以对抗产业化攻击等痛点。资源共1个pptx文件,包体约30.63MB,以…

2026/9/25 0:02:35

AI元人文:从工具使用到思维重构的深度探索

最近半年我一直在琢磨一件事:AI元人文到底是什么?说白了,就是“用元视角重新审视人与AI的关系”,也在“探索AI如何反向逼着我们发现自己的思考边界”。标题里的“元探索”,在我看就是一层套一层的追问——当你用AI解决…

2026/9/25 0:02:35

Python+CNN车牌识别实战:从数据预处理到模型训练与部署

简介:基于Python与卷积神经网络的车牌识别项目,面向计算机视觉初学者及智能交通开发者,目标是帮助用户掌握从数据预处理、模型构建到实际部署的完整流程。压缩包共25个文件,包含jpg/png图像样本、py训练脚本、md说明文档、dat数据…

2026/9/25 0:02:35

Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保…

2026/9/22 16:34:32

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/22 20:01:30

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/22 13:25:41

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑