亚马逊AWS官方博客

基于 Amazon Bedrock 构建 Slack 图像生成助手 App

引言

在当今的商业环境中,视觉内容变得越来越重要。无论是营销材料、产品演示还是客户交流,引人入胜的图像和视觉效果都可以提高内容的吸引力和影响力。然而,创建高质量的视觉内容通常需要专业的设计技能和昂贵的工具,这对于许多企业来说是一个挑战。

在本文中,我们将介绍如何基于 Amazon Bedrock 托管的 SDXL 基础模型构建一个 Slack 图像生成助手 App。该 Slack App 允许 Slack 用户通过发送文本提示来请求生成图像,并将生成的图像直接发送到 Slack 频道。这不仅为团队提供了一种创建视觉内容的简单方式,而且还可以促进协作和讨论。

Amazon Bedrock 是一项完全托管的基础模型(FM)服务,通过单个 API 提供来自 AI21 Labs、Anthropic、Cohere、Meta、Mistral AI、Stability AI 和 Amazon 等领先人工智能公司的高性能基础模型,以及通过安全性、隐私性和负责任的人工智能构建生成式人工智能应用程序所需的一系列广泛功能。由于 Amazon Bedrock 是无服务器的,因此您无需管理任何基础设施,并且可以使用已经熟悉的 AWS 服务将生成式人工智能功能安全地集成和部署到您的应用程序中。

解决方案概述

在这篇博客中,我们将介绍如何在 AWS Lambda 中部署 Slack 网关服务,用于接收 Slack 消息并使用 Amazon Bedrock 及其托管的 Stability AI SDXL 基础模型生成相应的图像。我们利用了多个 Amazon 云服务来构建一个健壮的解决方案:Secrets Manager 用于安全地存储密钥,DynamoDB 用于防止重复消息处理,S3 Bucket 和 CloudFront 用于存储和分发生成的图像。通过将所有这些服务与 AWS Lambda 结合使用,我们可以构建一个无服务器的、可扩展的应用程序,用于处理 Slack 消息并生成图像。

先决条件

可用的亚马逊云科技账户

Amazon Bedrock Stable AI SDXL 基础模型服务已启用

已创建私有的 S3 Bucket 用于存储生成的图像

通过 CloudFront 分发私有 S3 Bucket 中的图像,实现静态内容加速,同时也可以配置 CloudFront 实现 API Gateway 动态加速

创建 Slack App

在 Slack 工作区中创建一个新的 Slack 应用程序,启用 “im:history”、”chat:write” 和 “commands” 作用域,具体步骤如下:

1. 打开 https://api.slack.com/apps/new 并选择”From a manifest”

2. 选择要将应用程序安装到的工作区

3. 将以下 yaml 格式的 template 的内容复制到文本框中(在 YAML 选项卡内),然后单击“下一步”

display_information:
  name: SDXL
features:
  app_home:
    home_tab_enabled: true
    messages_tab_enabled: false
    messages_tab_read_only_enabled: false
  bot_user:
    display_name: SDXL
    always_online: false
oauth_config:
  scopes:
    bot:
      - im:read
      - im:write
      - chat:write
      - app_mentions:read
      - im:history
      - incoming-webhook
settings:
  event_subscriptions:
    request_url: https://tobemodified.com
    bot_events:
      - app_home_opened
      - app_mention
      - message.im
  org_deploy_enabled: false
  socket_mode_enabled: false
  token_rotation_enabled: false

4. 查看配置,然后单击“Create”

完成 App 创建后,查看 Signing Secret,接下来会通过 Cloudformation 保存到 Secret Manager 中

5. 选择左边栏 OAuth & Permissions,点击 Install to Workspace,然后点击 Allow

查看生成的 OAuth Token,接下来会通过 Cloudformation 保存到 Secret Manager 中

创建 Amazon 云服务

我们将使用 CloudFormation 来部署所需的 Amazon 云服务,包括 Lambda 函数、API Gateway、Secrets Manager 和 DynamoDB。CloudFormation 模板将自动配置所有必需的资源,简化了部署过程。

点击 Launch Stack 以创建 Cloudformation 堆栈

依次填写用于保存 Bedrock SDXL 产生的图片的私有 S3 Bucket、用于分发图片的 Cloudfronnt 分配、Slack App 签名密钥、Slack App OAuth Token,勾选 acknowledge然后 Create stack

Stack 创建完成后,复制 SlackAPIGatewayEndpoint

将 SlackAPIGatewayEndpoint 配置为事件订阅的请求 URL,替换模版中的默认值,如果显示 Verified 表示 Slack App 连接 Lambda 函数成功,点击 Save Changes

Lambda 函数介绍

Lambda 函数将处理来自 Slack 的事件,调用 Amazon Bedrock 生成图像,并将图像上传到 S3 存储桶。该函数首先验证 Slack 签名以确保请求来自 Slack。然后,它处理 URL 验证挑战或实际的 Slack 消息事件。对于消息事件,它会将客户端消息 ID 和时间戳写入 DynamoDB 表,以防止重复处理。

import json
import boto3
# import ...

def handler(event, context):
    event_body = json.loads(event.get("body"))
    response = None

    # Verify the Slack signature
    if not verify_slack_signature(event['headers'], event['body']):
        return {
            'statusCode': 401,
            'body': json.dumps({'error': 'Invalid Slack signature'})
        }

    if event_body.get("type") == "url_verification":
        response = {
            'statusCode': 200,
            'body': event_body['challenge']
        }
    else:
        client_msg_id = event_body['event']['client_msg_id']
        try:
            table.put_item(
                Item={
                    'client_msg_id': client_msg_id,
                    'timestamp': int(time.time())  # Add a timestamp for replay attack prevention
                },
                ConditionExpression='attribute_not_exists(client_msg_id)'
            )

            response = handle_message(event_body)

        except ClientError as e:
            if e.response['Error']['Code'] != 'ConditionalCheckFailedException':
                return {
                    'statusCode': 200,
                    'body': json.dumps('Event already processed')
                }
    return response

handle_message 函数提取实际的消息文本,调用 call_bedrock 函数生成图像,并将生成的图像 URL 发送回 Slack 频道。

def handle_message(slack_body):
    slack_text = slack_body.get('event').get('text')
    slack_user = slack_body.get('event').get('user')
    channel = slack_body.get('event').get('channel')

    pattern = r'<@\w+>\s*(.+)'
    match = re.search(pattern, slack_text)
    if match:
        slack_text = match.group(1)

    image_url = call_bedrock(slack_text)

    data = {
        'channel': channel,
        'blocks': [
            {
                "type": "section",
                "text": {
                    "type": "mrkdwn",
                    "text": f"<@{slack_user}> Generated Image:"
                }
            },
            {
                "type": "image",
                "image_url": image_url,
                "alt_text": "Generated Image"
            }
        ]
    }

    headers = {'Authorization': f'Bearer {slack_token}', 'Content-Type': 'application/json'}
    http.request('POST', slack_api_url, headers=headers, body=json.dumps(data))

    return {'statusCode': 200, 'body': json.dumps({'msg': "message received"})}

call_bedrock 函数调用 Amazon Bedrock 服务生成图像,并将生成的图像上传到 S3 存储桶,并返回 CloudFront 分发的图像 URL。

def call_bedrock(question):
    client = boto3.client("bedrock-runtime")
    model_id = "stability.stable-diffusion-xl-v1"

    native_request = {
        "text_prompts": [{"text": question}],
        "style_preset": "photographic",
        "seed": random.randint(0, 4294967295),
        "cfg_scale": 10,
        "steps": 30,
    }

    request = json.dumps(native_request)

    try:
        response = client.invoke_model(modelId=model_id, body=request)
    except Exception as e:
        print(f"Error calling Bedrock AI model: {e}")
        return "Sorry, I'm having trouble processing your request right now."

    model_response = json.loads(response["body"].read())
    base64_image_data = model_response["artifacts"][0]["base64"]

    image_key = f"{S3_PREFIX}{str(uuid.uuid4())}.png"
    s3_client.put_object(
        Bucket=S3_BUCKET_NAME,
        Key=image_key,
        Body=base64.b64decode(base64_image_data),
        ContentType="image/png"
    )

    image_url = f"https://{CLOUDFRONT_NAME}/{image_key}"

    return image_url

验证 Slack App

现在,您可以在 Slack 频道中发送消息,Lambda 函数将调用 Amazon Bedrock 生成相应的图像,并将图像发送回 Slack 频道。通过@SlackAppName + 提示词的方式向 App 提问,第 1 次使用的时候,需要点击 Invite Them,手机 App 输给效果如下:

选择 Invite Them 后,Slack App SDXL 根据提示词输出了图片:

总结

通过 Amazon Cloudformation 部署了所需的云服务之后,您需要将 API Gateway 端点配置为 Slack App 的事件订阅 URL。然后,每当 Slack 用户在频道中发送文本提示时,Lambda 函数就会被触发,调用 Bedrock 服务生成相应的图像,并将图像发送回 Slack 频道。通过利用 Amazon Bedrock 以及 Lambda、API Gateway、Secrets Manager 和 DynamoDB 等服务的强大功能,您可以轻松构建一个功能强大的 、基于无服务器架构的、Slack 图像生成助手 App。这不仅可以提高团队的工作效率,还可以激发创造力,促进更好的协作和沟通。


*前述特定亚马逊云科技生成式人工智能相关的服务仅在亚马逊云科技海外区域可用,亚马逊云科技中国仅为帮助您了解行业前沿技术和发展海外业务选择推介该服务。

参考资料

Slack Quickstart: Send a mesage

Verifying requests from Slack

Invoke Stable Diffusion XL on Amazon Bedrock to generate an image

本篇作者

刘佳鑫

西云数据解决方案架构师,目前为西云客户提供架构设计、解决方案、云原生及 GenAI 应用原型开发,加入西云数据前,主要面向运营商、零售等行业客户提供移动无线网络、5G MEC、虚拟化、容器化及应用持续交付等产品及解决方案。

李琳

亚马逊云科技解决方案架构师,负责面向跨国企业客户的云计算方案架构咨询和设计,客户涵盖医疗、零售、制造等行业。熟悉云原生网络技术及混合云网络架构。

王高雄

西云数据高级解决方案架构师,主要负责基于 AWS 云计算方案的咨询与架构设计。曾就职于多家世界 500 强企业,拥有 16 年的互联网、制造、零售、政府和金融等行业客户服务和技术管理经验,在短视频、互联网金融、零售、游戏、电商、制造、智慧城市等多个领域都拥有丰富的项目实践经验。现专注企业云原生架构和 GenAI 发展,致力将前沿技术应用于企业业务场景,推动数字化转型。

赵克鸣

亚马逊云科技解决方案架构师,负责云计算解决方案的咨询和设计。热爱 AI/ML 领域的技术研究,并通过可实施的解决方案,帮助客户取得业务价值。