A interatividade e a imprevisibilidade das plataformas de conteúdo gerado pelo usuário (UGC) de transmissão ao vivo são uma grande parte do motivo pelo qual são tão populares. Mas essa imprevisibilidade significa que as comunidades devem ser diligentes no monitoramento de seu conteúdo para garantir que ele atenda às diretrizes da comunidade ou à política de uso aceitável e seja apropriado, seguro e acolhedor para todos os usuários. Isso geralmente resulta em um sistema de moderação em que os usuários relatam possíveis ofensas às diretrizes da comunidade e os moderadores ou administradores tomam as medidas necessárias. Muitas vezes, esse é um processo manual que deixa muito a desejar.
As ferramentas de Inteligência Artificial (IA) e Aprendizado de Máquina (ML) melhoraram nos últimos anos, e os desenvolvedores podem usar essas ferramentas para auxiliar na moderação de suas comunidades. Nesta postagem, veremos uma maneira de fazer isso com o Amazon Interactive Video Service (Amazon IVS) e o Amazon Rekognition.
Analisar cada quadro de cada transmissão ao vivo em um aplicativo com AI/ML seria uma tarefa muito cara e difícil. Em vez disso, os desenvolvedores podem analisar amostras das transmissões ao vivo em seus aplicativos em uma frequência especificada para ajudar seus moderadores, alertando-os se houver conteúdo que precise de revisão adicional por um moderador humano. Não é uma solução 100% perfeita, mas é uma maneira de automatizar a moderação de conteúdo e ajudar a facilitar o trabalho dos moderadores.
Esta solução envolve os seguintes passos:
Usaremos o AWS Serverless Application Model (SAM) para facilitar a criação da regra e das funções. Aqui está todo o arquivo template.yaml
que descreve as permissões necessárias, a regra do Amazon EventBridge, a camada AWS Lambda (para a dependência do AWS SDK) e as definições de função. Vamos detalhar isso abaixo.
AWSTemplateFormatVersion: '2010-09-09' Transform: 'AWS::Serverless-2016-10-31' Description: Amazon IVS Moderation Functions Globals: Function: Runtime: nodejs18.x Timeout: 30 MemorySize: 128 Api: EndpointConfiguration: Type: REGIONAL Cors: AllowMethods: "'GET, POST, OPTIONS'" AllowHeaders: "'Content-Type'" AllowOrigin: "'*'" MaxAge: "'600'" Resources: IvsChatLambdaRefLayer: Type: AWS::Serverless::LayerVersion Properties: LayerName: sam-app-dependencies Description: Dependencies for sam app ContentUri: dependencies/ CompatibleRuntimes: - nodejs18.x LicenseInfo: "MIT" RetentionPolicy: Retain IVSAccessPolicy: Type: AWS::IAM::Policy Properties: PolicyName: IVSModerationAccessPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - 's3:GetObject' - 's3:GetObjectAcl' - 'ivschat:SendEvent' - 'ivs:StopStream' - 'rekognition:DetectModerationLabels' Resource: '*' Roles: - Ref: ModerateImageRole - Ref: StopStreamRole ApiAccessPolicy: Type: AWS::IAM::Policy Properties: PolicyName: ApiAccessPolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - 'sts:AssumeRole' Resource: '*' Roles: - Ref: ModerateImageRole - Ref: StopStreamRole EventRule: Type: AWS::Events::Rule Properties: Description: EventRule State: ENABLED EventPattern: source: - aws.s3 detail-type: - "Object Created" detail: bucket: name: - ivs-demo-channel-stream-archive object: key: - suffix: .jpg Targets: - Arn: !GetAtt ModerateImage.Arn Id: MyLambdaFunctionTarget PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref ModerateImage Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt EventRule.Arn ModerateImage: Type: 'AWS::Serverless::Function' Properties: Environment: Variables: DEMO_CHAT_ARN: 'arn:aws:ivschat:us-east-1:[redacted]:room/[redacted]' DEMO_CHANNEL_ARN: 'arn:aws:ivs:us-east-1:[redacted]:channel/[redacted]' Handler: index.moderateImage Layers: - !Ref IvsChatLambdaRefLayer CodeUri: lambda/ StopStream: Type: 'AWS::Serverless::Function' Properties: Environment: Variables: DEMO_CHAT_ARN: 'arn:aws:ivschat:us-east-1:[redacted]:room/[redacted]' DEMO_CHANNEL_ARN: 'arn:aws:ivs:us-east-1:[redacted]:channel/[redacted]' Handler: index.stopStream Layers: - !Ref IvsChatLambdaRefLayer CodeUri: lambda/ Events: Api1: Type: Api Properties: Path: /stop-stream Method: POST Outputs: ApiURL: Description: "API endpoint URL for Prod environment" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
Há muita coisa acontecendo nesse arquivo, então vamos dividi-lo um pouco. Primeiro, criamos uma camada para habilitar a inclusão do AWS SDK for JavaScript (v3) em nossa função.
IvsChatLambdaRefLayer: Type: AWS::Serverless::LayerVersion Properties: LayerName: sam-app-dependencies Description: Dependencies for sam app ContentUri: dependencies/ CompatibleRuntimes: - nodejs18.x LicenseInfo: "MIT" RetentionPolicy: Retain
No diretório dependencies/nodejs
, há um arquivo package.json
que inclui os módulos que nossa função precisa.
{ "dependencies": { "@aws-sdk/client-ivs": "^3.289.0", "@aws-sdk/client-ivschat": "^3.289.0", "@aws-sdk/client-rekognition": "^3.289.0" } }
A próxima seção, identificada pelas chaves IVSAccessPolicy
e APIAccessPolicy
, fornece ao nosso aplicativo sem servidor a capacidade de acessar as APIs necessárias ( s3:GetObject
, s3:GetObjectAcl
, ivschat:SendEvent
, ivs:StopStream
e rekognition:DetectModerationLabels
) e expor o método stop stream que criaremos abaixo por meio do Amazon API Gateway.
Em seguida, criamos a regra do Amazon EventBridge. A propriedade name
em bucket
deve corresponder ao nome do bucket do Amazon S3 que você configurou em sua configuração de gravação. A gravação no Amazon S3 cria vários arquivos, incluindo listas de reprodução e mídia HLS, para que possamos filtrar essa regra para disparar apenas para nossas miniaturas, definindo a key
sob object
como suffix: jpg
.
EventRule: Type: AWS::Events::Rule Properties: Description: EventRule State: ENABLED EventPattern: source: - aws.s3 detail-type: - "Object Created" detail: bucket: name: - ivs-demo-channel-stream-archive object: key: - suffix: .jpg Targets: - Arn: !GetAtt ModerateImage.Arn Id: MyLambdaFunctionTarget
Em seguida, damos à regra as permissões necessárias para invocar a função AWS Lambda.
PermissionForEventsToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref ModerateImage Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt EventRule.Arn
Agora podemos definir nossa função que será invocada pela regra do Amazon EventBridge.
ModerateImage: Type: 'AWS::Serverless::Function' Properties: Environment: Variables: DEMO_CHAT_ARN: 'arn:aws:ivschat:us-east-1:[redacted]:room/[redacted]' DEMO_CHANNEL_ARN: 'arn:aws:ivs:us-east-1:[redacted]:channel/[redacted]' Handler: index.moderateImage Layers: - !Ref IvsChatLambdaRefLayer CodeUri: lambda/
Observação: estou declarando DEMO_CHAT_ARN
e DEMO_CHANNEL_ARN
como variáveis de ambiente, mas seu aplicativo provavelmente derivaria os valores ARN do evento passado para a função, pois você provavelmente usaria essa funcionalidade com mais do que apenas um único canal do Amazon IVS.
Por fim, podemos definir a função que será utilizada para interromper um stream, caso seja necessário.
StopStream: Type: 'AWS::Serverless::Function' Properties: Environment: Variables: DEMO_CHAT_ARN: 'arn:aws:ivschat:us-east-1:[redacted]:room/[redacted]' DEMO_CHANNEL_ARN: 'arn:aws:ivs:us-east-1:[redacted]:channel/[redacted]' Handler: index.stopStream Layers: - !Ref IvsChatLambdaRefLayer CodeUri: lambda/ Events: Api1: Type: Api Properties: Path: /stop-stream Method: POST
Agora que descrevemos nossa infraestrutura com AWS SAM, vamos criar as funções que descrevemos. Em index.mjs
, import
as classes SDK, recuperamos os valores Arn das variáveis de ambiente que passamos e criamos instâncias dos clientes necessários para nossas funções.
import { IvsClient, StopStreamCommand } from "@aws-sdk/client-ivs"; import { IvschatClient, SendEventCommand } from "@aws-sdk/client-ivschat"; import { RekognitionClient, DetectModerationLabelsCommand } from "@aws-sdk/client-rekognition"; const chatArn = process.env.DEMO_CHAT_ARN; const channelArn = process.env.DEMO_CHANNEL_ARN; const ivsClient = new IvsClient(); const ivsChatClient = new IvschatClient(); const rekognitionClient = new RekognitionClient();
A função moderateImage
receberá o evento Amazon EventBridge, extrairá o bucket
e key
do evento e enviará um DetectModerationLabelsCommand
por meio do rekognitionClient
para detectar qualquer conteúdo inapropriado ou ofensivo em imagens com base nas categorias
export const moderateImage = async (event) => { console.log('moderateImage:', JSON.stringify(event, null, 2)); const bucket = event.detail.bucket.name; const key = event.detail.object.key; const detectLabelsCommandInput = { Image: { S3Object: { Bucket: bucket, Name: key, } }, }; const detectLabelsRequest = new DetectModerationLabelsCommand(detectLabelsCommandInput); const detectLabelsResponse = await rekognitionClient.send(detectLabelsRequest); if (detectLabelsResponse.ModerationLabels) { sendEvent('STREAM_MODERATION', detectLabelsResponse.ModerationLabels); } };
Se necessário, a função moderateImage
chama sendEvent
para publicar um evento personalizado para qualquer cliente front-end conectado a uma determinada sala de bate-papo do Amazon IVS.
const sendEvent = async (eventName, eventDetails) => { const sendEventInput = { roomIdentifier: chatArn, attributes: { streamModerationEvent: JSON.stringify(eventDetails), }, eventName, }; const sendEventRequest = new SendEventCommand(sendEventInput); await ivsChatClient.send(sendEventRequest); };
Seu front-end pode decidir como lidar com esse evento e a lógica para publicar esse evento dependerá de suas necessidades de negócios. Talvez você prefira acionar um alarme personalizado no CloudWatch, enviar um e-mail ou publicar uma notificação via Amazon SNS? As necessidades de cada aplicativo diferem, mas os dados de moderação estão disponíveis neste ponto para fazer o que você precisa.
O método stopStream
usa o ivsClient
para enviar um StopStreamCommand
. Novamente, a implementação disso depende de você. Você pode até automatizar totalmente esse comando se o resultado do Amazon Rekognition corresponder a uma determinada categoria ou exceder um nível de confiança.
export const stopStream = async (event) => { console.log('stopStream:', JSON.stringify(event, null, 2)); try { const stopStreamRequest = new StopStreamCommand({ channelArn }); const stopStreamResponse = await ivsClient.send(stopStreamRequest); responseObject.body = JSON.stringify(stopStreamResponse); } catch (err) { responseObject.statusCode = err?.name === 'ChannelNotBroadcasting' ? 404 : 500; responseObject.body = JSON.stringify(err); } return responseObject; };
Em minha demonstração, decidi ouvir os eventos personalizados e exibir os resultados em uma exibição de moderador que mostra o item detectado e o nível de confiança. Também apresento ao moderador um botão 'Stop Stream' que invoca o método stopStream
por meio do Amazon API Gateway exposto.
Nesta postagem, aprendemos como usar o Amazon Rekognition para ajudar os moderadores humanos a moderar o conteúdo nos aplicativos que eles criam usando o Amazon IVS. Se você quiser saber mais sobre como o Amazon IVS pode ajudar a criar comunidades UGC mais seguras, confira as seguintes postagens de blog: