<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Todd Sharp</title>
    <description>The latest articles on Forem by Todd Sharp (@recursivecodes).</description>
    <link>https://forem.com/recursivecodes</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F895331%2F59774920-1938-4c2e-b293-efa14fe46948.jpg</url>
      <title>Forem: Todd Sharp</title>
      <link>https://forem.com/recursivecodes</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/recursivecodes"/>
    <language>en</language>
    <item>
      <title>Creating Interactive Gaming Experiences with Amazon GameLift Streams and Amazon Interactive Video Service</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Wed, 11 Feb 2026 00:32:08 +0000</pubDate>
      <link>https://forem.com/aws/creating-interactive-gaming-experiences-with-amazon-gamelift-streams-and-amazon-interactive-video-2l9j</link>
      <guid>https://forem.com/aws/creating-interactive-gaming-experiences-with-amazon-gamelift-streams-and-amazon-interactive-video-2l9j</guid>
      <description>&lt;p&gt;If you're in the business of creating video games, you know that creating and marketing a game is not easy. Game studios face numerous challenges related to sales and marketing, gamer experience, and of course testing &amp;amp; development. For example, studios might struggle with choosing a distribution and monetization strategy as well as think about player acquisition and retention, piracy and cheating, platform and hardware support, and much more. Not to mention the actual development related issues like choosing an engine, language, framework and how to conduct play testing and validation. &lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/4Fa_B3LxEVM"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;There's no easy road to making a profitable game that is fun to play and stands out from the crowd. You're swimming in a large pool that is full of talented sharks for a small piece of every gamer's time, money and attention. One of the best paths to success is creating a unique, engaging experience with endless playability and high potential for viral moments. This requires a solution that creates shared community experiences around your gameplay. In this post, we'll look at a solution that we've been working on called "Project Engage" that can help you to create dynamic, engaging gaming experiences with AWS.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enabling Your Game’s Success with AWS
&lt;/h2&gt;

&lt;p&gt;Everyone knows that viral moments on social media are the cheat code that can skyrocket your game into the hearts and minds of players around the world. User-generated content live streaming platforms like Twitch have launched many games from small, indie studios into viral community superstardom. The combination of Amazon GameLift Streams, Amazon Interactive Video Service (Amazon IVS) and AWS AppSync is one approach that you can utilize to create a unique, interactive gaming experiences that delight both your players and your community.&lt;/p&gt;

&lt;p&gt;So what are these services and how can you use them?&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 1: Boost Your Game with the Cloud
&lt;/h2&gt;

&lt;p&gt;Amazon GameLift Streams is cloud gaming on AWS. It's an AWS service that gives anyone with an internet connection the ability to play fun and exciting games without needing high-end hardware. Amazon GameLift Streams is an AWS service that enables publishers to spawn on-demand, low latency games to players, globally at up to 1080p at 60 FPS. Players don't need a $3000 rig with a specialized GPU - just a stable connection and a controller or keyboard and mouse. Amazon GameLift Streams is easy to get started with and it directly addresses some of the challenges related to distribution that traditionally plague game studios. As we'll see below, when you combine it with Amazon IVS, you'll also be equipped to address some of the challenges around player acquisition and retention that keep you up at night.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa4i3tqh7lim1d5cjfb0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foa4i3tqh7lim1d5cjfb0.png" alt="Amazon GameLift Streams"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 2: User-Generated Content Is the New Meta
&lt;/h2&gt;

&lt;p&gt;Amazon IVS is managed live streaming at scale on AWS. Like Amazon GameLift Streams, it has a proud lineage as it was born from the popular live-streaming platform Twitch. Since it was built by video experts and is powered by a global network of purpose-built, video optimized infrastructure, it enables you to focus on what matters: your community and your gamer’s experience. It’s not some watered-down, knock-off version. It’s the same servers and pipes that deliver Twitch’s traffic fully available for your live streaming workloads. This means that you can build high-quality, globally scalable, ultra-low latency interactive live streaming applications. &lt;/p&gt;

&lt;p&gt;We’ll dig deeper into the different ways that you can broadcast your Amazon GameLift Streams to Amazon IVS below, but there are two main approaches for this solution. The first (and most performant) option is to stream directly from the Amazon GameLift Streams instance via a small "sidecar" binary, like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5egrqbil7nkj9digeul7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5egrqbil7nkj9digeul7.png" alt="GameLift Streams Sidecar Broadcast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The second option is to utilize the Amazon IVS Web Broadcast SDK to re-stream the gameplay from the player’s browser.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhewfbcqtcl6mkwsqcjx4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhewfbcqtcl6mkwsqcjx4.png" alt="GameLift Streams Web Broadcast"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Want recordings for AI-based analysis or VOD playback later? Amazon IVS can record your live streams directly to Amazon Simple Storage Service (Amazon S3), so with some simple configuration your streams are automatically stored for future use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dcsve5t7l5v878t4oly.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8dcsve5t7l5v878t4oly.png" alt="GameLift Streams Recorded to S3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 3: Chat, Is This Real?
&lt;/h2&gt;

&lt;p&gt;AWS AppSync is the "glue" that binds these experiences by empowering you to send low-latency, high throughput chat and messages between your viewers and players. This messaging channel enables you to create dynamic gameplay that changes based on live-stream viewer feedback. Want to spawn a health pickup when viewers send their love to the player? Done. Want to modify the environment, or spawn enemies based on community interactions? No problem! What about giving your players new monetization options based on the popularity of their streams or their connection with the community? Easy! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvfilqosxnhx6x08dwfl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmvfilqosxnhx6x08dwfl.png" alt="Adding Interactivity with AppSync"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Level 4: Opening the Loot Box
&lt;/h2&gt;

&lt;p&gt;This combination of AWS services helps game developers solve some of their biggest problems. Betting and regulated gaming studios can give players real-time interaction from stream viewers which means that the viewers can also place wagers directly on the action which provides another level of excitement and entertainment. Instead of "leaning back" and consuming, they're "leaning forward" and participating. In this video, the game player is on the &lt;strong&gt;left&lt;/strong&gt;, and the live stream viewer is on the &lt;strong&gt;right&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/Q82XVKCzCf4"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Cheat Code for Viral Success
&lt;/h2&gt;

&lt;p&gt;Depending on your use case and requirements, there are several ways to approach this solution. GameLift Streams are delivered to the player via an ultra-low latency WebRTC connection. &lt;/p&gt;

&lt;h3&gt;
  
  
  Direct Broadcasting From the GameLift Streams Instance (Sidecar)
&lt;/h3&gt;

&lt;p&gt;For use cases that demand less network and resource utilization on the client side, the Amazon IVS broadcast can be sent directly from the Amazon GameLift Streams instance via the sidecar approach that was mentioned earlier in this post. In this approach, a small binary is packaged along with the game binary and deployed alongside the application. When the Amazon GameLift Session is launched, necessary configuration environment variables are passed via the Amazon GameLift Streams API. These variables contain an Amazon IVS participant token, as well as several video configuration arguments (for resolution, FPS, bitrate, etc.).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgq34unrvojulag2y6hmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgq34unrvojulag2y6hmt.png" alt="Full Arch (Direct Broadcast)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see in the following video, the latency with the sidecar approach is nearly imperceptible. Because the viewer interactions are handled via AWS AppSync, there is no need to sacrifice any user interactivity and engagement. Again, the player is on the &lt;strong&gt;left&lt;/strong&gt;, and the viewer is on the &lt;strong&gt;right&lt;/strong&gt;. If you’re interested in viewing the measured latency between the player and viewer, try to pause the video at different points and check the timer in the upper left corner.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/FQeGqvR4OR8"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebroadcasting From the Player's Client (Amazon IVS Web Broadcast SDK)
&lt;/h3&gt;

&lt;p&gt;Another option is to rebroadcast the gameplay. Once the GameLift Stream is received on the player side, you can capture that stream in the player’s browser and re-stream it to Amazon IVS via the Amazon IVS Web Broadcast SDK. This requires a bit more bandwidth on the player’s side, but it’s usually not enough to be noticeable or have much impact on the experience. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpt22cokpeb7etys9f2ih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpt22cokpeb7etys9f2ih.png" alt="Full Arch (Web Broadcast)"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The architecture shown above is demonstrated in the following video. On the &lt;strong&gt;left&lt;/strong&gt; side of the screen, the player is playing in fullscreen mode, and the live stream view is shown on the &lt;strong&gt;right&lt;/strong&gt; hand of the screen. There’s a barely perceivable amount of latency at times, but it’s not enough to impact the viewer interactivity. Notice how the viewer interactions (chat messages and emotes) are integrated into the game, so the player can feel the community support and engagement. Near the end of the video, you can see another advantage of using Amazon IVS real-time stages for the broadcast when you see the viewer’s view exit fullscreen. Since Amazon IVS real-time stages support multiple participants publishing, the player’s webcam and microphone are published as a separate stream so that viewers can see and hear the player without blocking the gameplay with a webcam overlay.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/svwXRzBABcI"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Easter Egg: Passing Control Between Multiple Participants
&lt;/h2&gt;

&lt;p&gt;Play testing should happen early and often, but approaches vary. Some studios have dedicated testers, while others contract out and request recorded sessions for analysis. Imagine a system where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Play testers play directly from their browser without downloading the game (+1XP)&lt;/li&gt;
&lt;li&gt;You could join interactive sessions and provide real-time feedback (+10XP)&lt;/li&gt;
&lt;li&gt;Sessions automatically record to Amazon S3 for analysis (+100XP)&lt;/li&gt;
&lt;li&gt;Participants could pass gameplay control between each other (+10000XP)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since Amazon GameLift Streams supports reconnecting to recently disconnected streams, this is achievable. Implement a control request system via AppSync messages—when a request is approved, the current session disconnects and passes the reconnect ID to the new player, who reconnects and broadcasts gameplay to other participants &lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/3WTIY871ddw"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;h2&gt;
  
  
  Will You Accept the Quest?
&lt;/h2&gt;

&lt;p&gt;To try this solution, we have created a couple of sample repos on GitHub that can be used with your AWS account. First, you will need to build the &lt;a href="https://github.com/aws-samples/sample-gamelift-streams-ivs-broadcast-client" rel="noopener noreferrer"&gt;sidecar client application&lt;/a&gt; and place it in the same directory as your game binary. Then upload the sidecar and game binary to an S3 bucket and create a GameLift Streams Application and Stream Group in your AWS account. Once you have the Stream Group and Application IDs, you can deploy the &lt;a href="https://github.com/aws-samples/sample-amazon-gamelift-streams-multiview-amazon-ivs-react-app" rel="noopener noreferrer"&gt;sample multi-view React web app&lt;/a&gt; to your AWS account using to the deployment instructions in the repo. &lt;/p&gt;

&lt;p&gt;Amazon GameLift Streams, Amazon IVS, and AWS AppSync offer numerous opportunities to improve your game development lifecycle and differentiate your games in a competitive market. Together, these services help create unique, interactive gaming experiences. It's time to level up your games on AWS.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>gamedev</category>
      <category>amazonivs</category>
      <category>amazongameliftstreams</category>
    </item>
    <item>
      <title>Virtual Assistants with Amazon IVS and OpenAI's Realtime API</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Wed, 01 Oct 2025 12:52:35 +0000</pubDate>
      <link>https://forem.com/aws/virtual-assistants-with-amazon-ivs-and-openais-realtime-api-1oa0</link>
      <guid>https://forem.com/aws/virtual-assistants-with-amazon-ivs-and-openais-realtime-api-1oa0</guid>
      <description>&lt;p&gt;We recently &lt;a href="https://dev.to/aws/building-virtual-agents-with-amazon-nova-sonic-s2s-23m7"&gt;explored building a virtual agent&lt;/a&gt; that seamlessly joins your Amazon Interactive Video Service (Amazon IVS) real-time streams as a conversational assistant with vision capabilities. While Amazon Nova Sonic S2S delivers solid performance and integrates beautifully with the AWS ecosystem, you might be curious about harnessing OpenAI's cutting-edge real-time model for your agents. This post walks you through a demo integration that makes this possible.&lt;/p&gt;

&lt;p&gt;Before we dive into the technical details, here's a glimpse of what a conversation looks like with OpenAI's real-time model working behind the scenes.&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/ku3in2Lzdiw"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;The results speak for themselves: crisp, natural voice quality, lightning-fast response times, and remarkably accurate visual analysis that nails what it's looking at. It's genuinely impressive how well everything comes together.&lt;/p&gt;

&lt;h2&gt;
  
  
  ❓ How Is This Different?
&lt;/h2&gt;

&lt;p&gt;This integration leverages the Python &lt;code&gt;aiortc&lt;/code&gt; library to tap into the remote participant's stream, channeling their audio directly into the &lt;code&gt;gpt-realtime&lt;/code&gt; model. Meanwhile, the agent establishes itself as a publisher on the Amazon IVS stage. When &lt;code&gt;gpt-realtime&lt;/code&gt; generates its response, that audio flows right back into the agent's published feed. Need vision? The agent captures the current frame from the remote participant and instantly analyzes what's happening. It's elegantly straightforward - the &lt;code&gt;gpt-realtime&lt;/code&gt; model essentially becomes another participant that both publishes and subscribes to the stage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wsdlymwc123lqpf2iyc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9wsdlymwc123lqpf2iyc.png" alt="gpt-realtime virtual agent arch"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🤖 Try It Out!
&lt;/h2&gt;

&lt;p&gt;Ready to get your hands dirty? Start by spinning up a new Amazon IVS stage and generating a remote participant token for your agent (refer to the &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/what-is.html" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; for more info if you're new to IVS).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ivs-realtime create-stage &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"my-stage"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--region&lt;/span&gt; us-east-1 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--participant-token-configurations&lt;/span&gt; &lt;span class="s1"&gt;'[
    {
      "duration": 720,
      "attributes": {
        "username": "gpt-realtime-agent"
      }
    },
    {
      "duration": 720,
      "attributes": {
        "username": "local-participant"
      }
    }
  ]'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s1"&gt;'{stageArn: stage.arn, gptParticipant: {participantId: participantTokens[0].participantId, token: participantTokens[0].token}, localParticipant: {participantId: participantTokens[1].participantId, token: participantTokens[1].token}}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--no-cli-pager&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will produce output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stageArn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ivs:us-east-1:639934345351:stage/abcdef123456"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gptParticipant"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"participantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"6APQqRu2XnqK"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ...."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"localParticipant"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"participantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"m243ru5A2idL"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ...."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No client app yet? No problem - you can publish directly from the AWS Management Console. If you are using the AWS Console, make sure to grab your participant ID from the 'Stage sessions' section by clicking the active session ID. &lt;/p&gt;

&lt;p&gt;You can also try things out with &lt;a href="https://codepen.io/amazon-ivs/full/ZEqgrpo" rel="noopener noreferrer"&gt;this CodePen&lt;/a&gt;. Paste the &lt;code&gt;token&lt;/code&gt; from the &lt;code&gt;localParticipant&lt;/code&gt; into the &lt;strong&gt;Token&lt;/strong&gt; input box and click 'Join' to publish to your new stage.&lt;/p&gt;

&lt;p&gt;Next, clone the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/" rel="noopener noreferrer"&gt;sample repo&lt;/a&gt; and navigate to the &lt;code&gt;stages-gpt-realtime&lt;/code&gt; directory. The &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-gpt-realtime/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt; there walks you through the setup process. There's even a &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-gpt-realtime/MANAGING_OPENAI_ASSISTANT_DEMO.md" rel="noopener noreferrer"&gt;simple management script&lt;/a&gt; that you can use to launch agent instances via WebSocket messages from the frontend. When you're ready to roll, fire up the script with your credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;gpt&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;realtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;GPT_PARTICIPANT_TOKEN&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;LOCAL_PARTICIPANT_ID&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;openai&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;OPENAI_API_KEY&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your agent will hop onto the stage, subscribe to your local participant, and you're off to the races with real-time AI conversations!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lxc2w06ec0zslzv08jx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9lxc2w06ec0zslzv08jx.png" alt="Real-time virtual assistant"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The script provides a simplified video track with an audio visualization which can be overridden for your use case. I personally like to create a client side visualization which tends to be a bit cleaner and more responsive (as you can see in the video above).&lt;/p&gt;

&lt;h2&gt;
  
  
  👏 Extending The Solution
&lt;/h2&gt;

&lt;p&gt;This sample gives you the foundation to start building something amazing. Dig into the repo code and OpenAI's documentation to discover how you can supercharge the solution - add custom tools for function calling, or transform the &lt;code&gt;gpt-realtime&lt;/code&gt; model into a smart transcription service for your stages. Drop a comment and let me know what creative solutions you'll build with Amazon IVS and &lt;code&gt;gpt-realtime&lt;/code&gt;!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>ai</category>
      <category>openai</category>
    </item>
    <item>
      <title>Live Streaming to Amazon IVS on an ESP32 Microcontroller with Embedded Sensor Metadata</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Fri, 19 Sep 2025 12:32:53 +0000</pubDate>
      <link>https://forem.com/recursivecodes/live-streaming-to-amazon-ivs-on-an-esp32-microcontroller-with-embedded-sensor-metadata-17mj</link>
      <guid>https://forem.com/recursivecodes/live-streaming-to-amazon-ivs-on-an-esp32-microcontroller-with-embedded-sensor-metadata-17mj</guid>
      <description>&lt;p&gt;Until recently, quality live streaming from embedded devices like an ESP32 was severely limited. ESP32-CAM boards can only produce low-quality, low frame rate (5-15 FPS) streams of MJPEG images via RTSP at resolutions like 320x240. These microcontrollers simply didn't have enough CPU and RAM for real video processing with modern codecs. Then Espressif changed everything by releasing the &lt;a href="https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32p4/esp32-p4-function-ev-board/index.html" rel="noopener noreferrer"&gt;ESP32-P4-Function-EV-Board&lt;/a&gt;, which features a dual-core 400MHz RISC-V processor, 32MB PSRAM, and most importantly, a hardware H.264 encoder capable of 1080P@30fps streaming. It's a game changer to be sure, but all of that hardware is nothing without a software library to push those beautifully encoded H264 streams to a valid destination. Thankfully Espressif came through &lt;em&gt;again&lt;/em&gt; with the &lt;code&gt;esp-webrtc-solution&lt;/code&gt; &lt;a href="https://github.com/espressif/esp-webrtc-solution/" rel="noopener noreferrer"&gt;library&lt;/a&gt;. So does it live up to they hype? More importantly, can we integrate it with a managed live streaming service like Amazon IVS? Let's find out!&lt;/p&gt;

&lt;p&gt;⚠️ &lt;strong&gt;Disclaimer&lt;/strong&gt;: This is a personal project!&lt;/p&gt;

&lt;h2&gt;
  
  
  📟 The Board
&lt;/h2&gt;

&lt;p&gt;🛑 Before we go any further - just look at this thing!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fih9et015u6g8mn0j0ee9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fih9et015u6g8mn0j0ee9.jpg" alt="ESP32-P4-Function-EV" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⛔️ &lt;strong&gt;Note&lt;/strong&gt;: Ignore that connected sensor for a moment. We'll get to that!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It's beautiful! The form factor is reminiscent of a Raspberry Pi - a huge step up from the tiny ESP32 boards we're used to seeing. Granted, sometimes a smaller board is better when we're integrating it into a larger project that we want to be compact, but with all the horsepower 🐎 this thing has, it was bound to be a little larger than usual. The kit I bought even comes with a full display, but I'm not using it for now. Side note: I'd love a nice project case for this kit, but I haven't found any available yet. To give you the full picture, here are the specs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dual-core 400MHz RISC-V processor&lt;/strong&gt; with 32MB PSRAM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hardware H.264 video encoder&lt;/strong&gt; for real-time streaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1920x1080 Full HD video&lt;/strong&gt; at 25fps&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIPI-CSI camera interface&lt;/strong&gt; (2MP camera included)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MIPI-DSI display output&lt;/strong&gt; (7" 1024x600 touchscreen included)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Wi-Fi 6 &amp;amp; Bluetooth 5 LE&lt;/strong&gt; via ESP32-C6 module&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;10/100 Ethernet port&lt;/strong&gt; for wired networking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dual USB 2.0 ports&lt;/strong&gt; (Type-A host + Type-C device)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professional audio system&lt;/strong&gt; with codec, microphone, and 3W amplifier (bring your own speaker)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;40-pin GPIO header&lt;/strong&gt; for sensor/peripheral expansion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MicroSD card slot&lt;/strong&gt; for storage expansion&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Built-in USB Serial/JTAG&lt;/strong&gt; debugging&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bottom Line: The ESP32-P4-Function-EV isn't just another microcontroller - it's a complete multimedia development platform that brings professional-grade video, audio, and connectivity features that would require multiple separate boards and components with traditional ESP32 setups. If I had one complaint, it's that the video color from the included 2MP SC2336 camera seems a bit off (see screenshot below). It's not terrible, but we're used to much higher quality cameras these days. I may try to find a way to upgrade that in the future.&lt;/p&gt;

&lt;h2&gt;
  
  
  🤝 Integrating with Amazon IVS
&lt;/h2&gt;

&lt;p&gt;About a month ago, me and my friend &lt;a href="https://kiro.dev" rel="noopener noreferrer"&gt;Kiro&lt;/a&gt; started trying to get the ESP32-P4 working with Amazon IVS real-time stages. Since stages &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;support WHIP ingest&lt;/a&gt;, I started with the &lt;a href="https://github.com/espressif/esp-webrtc-solution/tree/main/solutions/whip_demo" rel="noopener noreferrer"&gt;&lt;code&gt;whip_demo&lt;/code&gt;&lt;/a&gt; sample solution. I quickly ran into a few issues with the core library - one major blocker in particular was that it didn't properly support redirects during SDP negotiation. This meant that when requesting an SDP for the IVS stage, the participant token was stripped from the request resulting in a &lt;code&gt;400&lt;/code&gt; error. I worked on a fix for this (and a few other feature requests) and submitted a few PRs that have all been integrated into the core library (thank you &lt;a href="https://github.com/TempoTian" rel="noopener noreferrer"&gt;@TempoTian&lt;/a&gt;!).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvquiw01iypdbr3istdm8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvquiw01iypdbr3istdm8.png" alt="Published live stream" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yeah, the color is a bit off. But the resolution and latency is amazing! &lt;/p&gt;

&lt;h2&gt;
  
  
  🏷️ SEI Support
&lt;/h2&gt;

&lt;p&gt;Once I got the board broadcasting to Amazon IVS, the next step was pretty obvious (to me at least). This is a microcontroller with 55 programmable GPIO pins. It was &lt;em&gt;made&lt;/em&gt; to read sensors, why not come up with a way to publish all that potential data? And since real-time stages have support for &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/web-publish-subscribe.html#web-publish-subscribe-sei-attributes" rel="noopener noreferrer"&gt;Supplemental Enhancement Information (SEI)&lt;/a&gt;, why not add support for publishing sensor (or really any data) as SEI? This required another PR to add a hook into the core lib to expose the video frames so that we can manipulate it to insert the SEI NAL units. Once this hook was implemented, Kiro and I were able to implement an SEI publishing system. This is why my image of the board above has a DHT-11 sensor attached.  If you're interested in how this works, check the DHT-11 markdown doc in the repo (link below).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmp94bvtsw8iwiyz8le4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frmp94bvtsw8iwiyz8le4.png" alt="SEI Sensor Data" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🎉 Try it Out!
&lt;/h2&gt;

&lt;p&gt;To try it out for yourself, check out the &lt;a href="https://github.com/recursivecodes/ivs-esp-whip-demo" rel="noopener noreferrer"&gt;&lt;code&gt;ivs-esp-whip-demo&lt;/code&gt;&lt;/a&gt; on GitHub. &lt;/p&gt;

&lt;p&gt;The documentation is pretty solid in the repo and should help you get it up and running. If you have any questions, post them below. For problems getting it running or enhancement ideas, please file an issue on the repo! &lt;/p&gt;

&lt;p&gt;Happy streaming!&lt;/p&gt;

</description>
      <category>livestreaming</category>
      <category>esp32</category>
      <category>aws</category>
      <category>amazonivs</category>
    </item>
    <item>
      <title>4 Ways to Supercharge Your HLS Live Streaming App with AI-Powered Analysis</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Wed, 17 Sep 2025 13:52:36 +0000</pubDate>
      <link>https://forem.com/aws/4-ways-to-supercharge-your-hls-live-streaming-app-with-ai-powered-analysis-4mob</link>
      <guid>https://forem.com/aws/4-ways-to-supercharge-your-hls-live-streaming-app-with-ai-powered-analysis-4mob</guid>
      <description>&lt;p&gt;Amazon IVS customers building live streaming platforms want to focus on creating engaging experiences, not wrestling with complex video analysis pipelines. While we handle the heavy lifting of low-latency HLS delivery, they get to focus on the things they are great at - content discovery 🔍, moderation 🛡️, and user engagement 💫. In our &lt;a href="https://dev.to/aws/5-ways-to-improve-your-ugc-live-streaming-app-with-ai-1ib9"&gt;last post&lt;/a&gt;, we looked at how to solve some of these problems in real-time WebRTC based streams. Since that post, I've gotten many questions from developers keep asking us about AI solutions for low-latency (RTMP+HLS) channel analysis 🤖, so in this post we're going to dig into four powerful ways to use AI and open-source tools to transform your live streaming app's capabilities!&lt;/p&gt;

&lt;h2&gt;
  
  
  1️⃣ Real-Time Frame Analysis for Content Discovery
&lt;/h2&gt;

&lt;p&gt;Want to know what's actually happening in your streams beyond just titles and tags? Frame-by-frame analysis using Claude via Amazon Bedrock can provide incredibly detailed descriptions of live content, perfect for content discovery, accessibility, and moderation.&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/channels-subscribe/ivs-channel-subscribe-&amp;lt;br&amp;gt;%0Aanalyze-frames.py" rel="noopener noreferrer"&gt;ivs-channel-subscribe-analyze-frames.py&lt;/a&gt; script in &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;. Once configured, run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python channels-subscribe/ivs-channel-subscribe-analyze-frames.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--playlist-url&lt;/span&gt; &lt;span class="s2"&gt;"https://example.com/playlist.m3u8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--highest-quality&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--analysis-interval&lt;/span&gt; 30
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you detailed frame analysis output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-15 15:48:35,507 - INFO - 🤖 VideoFrameAnalyzer initialized with 3.0s interval
2025-09-15 15:48:35,507 - INFO - 🌍 Using Bedrock region: us-east-1
2025-09-15 15:48:35,507 - INFO - 🧠 Using model: us.anthropic.claude-sonnet-4-20250514-v1:0
2025-09-15 15:48:35,507 - INFO - 🤖 Video frame analysis enabled (every 3.0s)
2025-09-15 15:48:36,073 - INFO - 📊 Stream FPS: 30.0
2025-09-15 15:48:36,074 - INFO - 🚫 Video display disabled - press Ctrl+C to quit
2025-09-15 15:48:36,254 - INFO - 🔍 Analyzing frame...
2025-09-15 15:48:47,551 - INFO - ✅ Frame analysis completed
2025-09-15 15:48:47,551 - INFO - 📝 Analysis: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;This video frame shows a professional kitchen environment with a chef actively cooking. Here's what I observe:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Person:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A chef wearing traditional white chef's attire (white chef's coat and white apron)&lt;/li&gt;
&lt;li&gt;The chef appears to be middle-aged and is focused on cooking at the stovetop&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Kitchen Environment:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Commercial-grade stainless steel kitchen with professional equipment&lt;/li&gt;
&lt;li&gt;Multiple cooking stations visible with gas burners&lt;/li&gt;
&lt;li&gt;Industrial ventilation hood system overhead with exhaust fans&lt;/li&gt;
&lt;li&gt;Stainless steel prep surfaces and countertops throughout&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Cooking Activity:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The chef is working at a stovetop with what appears to be a pan containing yellow/golden colored food (possibly eggs, butter, or a sauce)&lt;/li&gt;
&lt;li&gt;Active cooking in progress, suggesting this is during meal preparation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Equipment &amp;amp; Features:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Professional-grade gas range with multiple burners&lt;/li&gt;
&lt;li&gt;Overhead heat lamps/warming lights visible&lt;/li&gt;
&lt;li&gt;Industrial kitchen ventilation system&lt;/li&gt;
&lt;li&gt;Red rubber anti-fatigue floor mats for safety and comfort&lt;/li&gt;
&lt;li&gt;Various kitchen tools and equipment visible in the background&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Setting:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;This appears to be a high-end restaurant or commercial kitchen&lt;/li&gt;
&lt;li&gt;The lighting suggests this could be during active service hours&lt;/li&gt;
&lt;li&gt;The setup indicates this is likely a live cooking demonstration or behind-the-scenes view of restaurant operations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The overall scene captures the fast-paced, professional environment of commercial food preparation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This analysis is perfect for automatically categorizing streams, generating accessibility descriptions, or powering content-based recommendations! 👨‍🍳🍝&lt;/p&gt;

&lt;h2&gt;
  
  
  2️⃣ Live Transcription with Timed Metadata Publishing
&lt;/h2&gt;

&lt;p&gt;Real-time transcription isn't just great for accessibility - it's a goldmine for content discovery and moderation. The &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/channels-subscribe/ivs-channel-subscribe-transcribe.py" rel="noopener noreferrer"&gt;ivs-channel-subscribe-transcribe.py&lt;/a&gt; script uses OpenAI Whisper for multi-language transcription and can even publish results back to your IVS channel as timed metadata.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python channels-subscribe/ivs-channel-subscribe-transcribe.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--playlist-url&lt;/span&gt; &lt;span class="s2"&gt;"https://example.com/playlist.m3u8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--language&lt;/span&gt; en &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--whisper-model&lt;/span&gt; base &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--publish-transcript-as-timed-metadata&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will produce output that looks similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-15 15:52:46,480 - INFO - 🎤 Starting audio chunk recording
2025-09-15 15:52:53,317 - INFO - ⏹️  Stopping recording after 6.84s with 346 frames
2025-09-15 15:52:53,338 - INFO - Processing audio chunk 6 in memory (shape: (118101,))
[TRANSCRIPT] A little bit of salt, a little bit of cracked pepper. We're gonna let that sweat a little bit. I have a big pot of pasta water here.
2025-09-15 15:52:54,167 - INFO - ✅ Published transcript metadata chunk 1/1 (150 bytes)
...
[TRANSCRIPT] right before I don't want to go into brown brown brown so we're going to put some Italian parsley in there.
...
[TRANSCRIPT] And it's not just for color, it's fragrant, it's earthy balances, the dish. I'm gonna go in with our spaghetti.
2025-09-15 15:53:07,786 - INFO - ✅ Published transcript metadata chunk 1/1 (129 bytes)
2025-09-15 15:53:07,786 - INFO - 🎉 Successfully published 1/1 transcript chunks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On the player side, we can &lt;a href="https://docs.aws.amazon.com/ivs/latest/LowLatencyUserGuide/metadata.html#metadata-consuming" rel="noopener noreferrer"&gt;consume the metadata&lt;/a&gt; and render it as a caption or translate it as necessary.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyckzcg0js2860h1kw0ak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyckzcg0js2860h1kw0ak.png" alt="Metadata transcript" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Of course this data can also be persisted to your app's database and subsequently queried by your app. Which means your viewers can search for streams by actual spoken content in addition to using the transcripts for captions and automated content moderation! 🗣️📝&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ Comprehensive Video Segment Analysis
&lt;/h2&gt;

&lt;p&gt;Another options is to analyze the video content itself (not just a single frame). The &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-&amp;lt;br&amp;gt;%0Apython-demos/blob/mainline/channels-subscribe/ivs-channel-subscribe-analyze-video.py" rel="noopener noreferrer"&gt;ivs-channel-subscribe-analyze-video.py&lt;/a&gt; script records video segments and analyzes them using TwelveLabs Pegasus for holistic content understanding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python channels-subscribe/ivs-channel-subscribe-analyze-video.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--playlist-url&lt;/span&gt; &lt;span class="s2"&gt;"https://example.com/playlist.m3u8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--analysis-duration&lt;/span&gt; 15 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--highest-quality&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This provides incredibly rich analysis:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-15 15:57:14,710 - INFO - 🤖 VideoAnalyzer initialized with 15.0s recording duration
2025-09-15 15:57:14,710 - INFO - 🌍 Using Bedrock region: us-west-2
2025-09-15 15:57:14,710 - INFO - 🧠 Using model: us.twelvelabs.pegasus-1-2-v1:0
2025-09-15 15:57:14,710 - INFO - 🤖 Video analysis enabled (recording duration: 15.0s)
2025-09-15 15:57:15,220 - INFO - 📊 Stream FPS: 30.0
2025-09-15 15:57:15,221 - INFO - 🚫 Video display disabled - press Ctrl+C to quit
2025-09-15 15:57:15,226 - INFO - 🎥 Starting audio and video chunk recording
2025-09-15 15:57:30,238 - INFO - ⏹️  Stopping recording after 15.01s
2025-09-15 15:57:30,238 - INFO - ✅ Recorded 349 video frames
2025-09-15 15:57:30,238 - INFO - ✅ Recorded 0 audio frames
2025-09-15 15:57:32,890 - INFO - ✅ Successfully encoded video: 3428047 bytes, 4570732 base64 chars
2025-09-15 15:57:32,891 - INFO - 🔍 Analyzing video...
2025-09-15 15:57:52,693 - INFO - ✅ Video analysis completed
2025-09-15 15:57:52,693 - INFO - 📝 Analysis:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In the video from a live stream, a chef dressed in a white uniform is seen in a kitchen setting. He is initially holding a small piece of red chili pepper, which he brings to his mouth to taste. The text overlay on the video reads "ONE PASTAS" and "PASTA AGIO OLIO WITH PEPPERONCINO." After tasting the chili pepper, the chef puts it down and picks up a knife to chop the chili pepper on a white cutting board. The text overlay changes to indicate that he likes very spicy food and is going to use two chili peppers without removing the seeds, suggesting the dish will be quite hot. The chef continues to chop the chili pepper while the camera focuses on his actions. The background of the kitchen includes various equipment and ingredients, but the primary focus remains on the chef and his task of preparing the spicy pasta dish.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This analysis is perfect for content categorization, highlight generation, and creating searchable content libraries!&lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Advanced Audio-Video Synchronization
&lt;/h2&gt;

&lt;p&gt;For the most sophisticated analysis, &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/channels-subscribe/ivs-channel-subscribe-analyze-audio-video.py" rel="noopener noreferrer"&gt;ivs-channel-subscribe-analyze-audio-video.py&lt;/a&gt; uses PyAV for proper audio-video stream handling with perfect synchronization.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python channels-subscribe/ivs-channel-subscribe-analyze-audio-video.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--playlist-url&lt;/span&gt; &lt;span class="s2"&gt;"https://example.com/playlist.m3u8"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--analysis-duration&lt;/span&gt; 20 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--highest-quality&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach ensures your AI analysis captures the complete context of both audio and video streams, making it ideal for complex content like educational streams, gaming commentary, or multi-person discussions where timing matters! 🎯⚡ Here's the output for this script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2025-09-15 16:00:06,306 - INFO - 🤖 VideoAnalyzer initialized with 15.0s recording duration
2025-09-15 16:00:06,306 - INFO - 🌍 Using Bedrock region: us-west-2
2025-09-15 16:00:06,306 - INFO - 🧠 Using model: us.twelvelabs.pegasus-1-2-v1:0
2025-09-15 16:00:06,306 - INFO - 🤖 Video analysis enabled &lt;span class="o"&gt;(&lt;/span&gt;recording duration: 15.0s&lt;span class="o"&gt;)&lt;/span&gt;
2025-09-15 16:00:06,306 - INFO - 🚫 Video display disabled - press Ctrl+C to quit
2025-09-15 16:00:06,306 - INFO - 🔗 Opening stream with PyAV...
2025-09-15 16:00:07,096 - INFO - 🔊 Found audio stream: aac, 48000Hz, 2 channels
2025-09-15 16:00:07,096 - INFO - 📺 Found video stream: h264, 360x640
2025-09-15 16:00:07,100 - INFO - 🎥 Starting audio and video chunk recording
2025-09-15 16:00:24,348 - INFO - ⏹️  Stopping recording after 17.25s
2025-09-15 16:00:24,348 - INFO - ✅ Recorded 615 video frames
2025-09-15 16:00:24,348 - INFO - ✅ Recorded 963 audio frames
2025-09-15 16:00:29,360 - INFO - ✅ Successfully encoded video: 6016865 bytes, 8022488 &lt;span class="nb"&gt;base64 &lt;/span&gt;chars
2025-09-15 16:00:29,367 - INFO - 🔍 Analyzing video...
2025-09-15 16:01:06,321 - INFO - ✅ Video analysis completed &lt;span class="o"&gt;(&lt;/span&gt;finish reason: unknown&lt;span class="o"&gt;)&lt;/span&gt;
2025-09-15 16:01:06,321 - INFO - 📝 Analysis:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;In the video, a chef is preparing a dish of pasta with pesto. Early on, the chef uses tongs to transfer the pasta from a pan to a plate, where the pasta is coated in a green pesto sauce with visible red pepper flakes. The chef then grates some fresh pecorino cheese over the pasta using a metal grater, as mentioned in the dialogue. The chef carefully distributes the pasta and cheese, ensuring a well-presented dish. The camera captures these actions in detail, focusing on the chef's hand movements and the final presentation of the pasta.&lt;/p&gt;

&lt;p&gt;Throughout the video, there are clear and readable captions overlaid on the screen, providing additional information about the dish and the chef's actions. The captions mention the type of pasta, the sauce used, and the chef's name. The overall presentation is professional and visually appealing, making it suitable for content discovery, moderation, or accessibility purposes. The chef holds up the plate towards the end, giving a clear view of the vibrant colors and textures of the pasta dish.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  🏁 Summary
&lt;/h2&gt;

&lt;p&gt;AI-powered channel analysis opens up incredible possibilities for live streaming platforms:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Content Discovery&lt;/strong&gt;: Let users find streams by actual content, not just titles 🔍&lt;br&gt;
• &lt;strong&gt;Accessibility&lt;/strong&gt;: Automatic captions and descriptions for all users ♿&lt;br&gt;
• &lt;strong&gt;Moderation&lt;/strong&gt;: Real-time content analysis for safety and compliance 🛡️&lt;br&gt;
• &lt;strong&gt;Monetization&lt;/strong&gt;: Target ads based on actual stream content 💰&lt;br&gt;
• &lt;strong&gt;Engagement&lt;/strong&gt;: Generate highlights and clips automatically ✨&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/" rel="noopener noreferrer"&gt;sample repository&lt;/a&gt; provides everything you need to get started. What creative ways will you use AI to enhance your streaming platform? Drop your ideas in the comments! &lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>ai</category>
      <category>livestreaming</category>
    </item>
    <item>
      <title>5 Ways to Improve Your UGC Live Streaming App with AI</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Wed, 03 Sep 2025 14:45:51 +0000</pubDate>
      <link>https://forem.com/aws/5-ways-to-improve-your-ugc-live-streaming-app-with-ai-1ib9</link>
      <guid>https://forem.com/aws/5-ways-to-improve-your-ugc-live-streaming-app-with-ai-1ib9</guid>
      <description>&lt;p&gt;Most of the customers that depend on Amazon IVS for managed live streaming would rather focus on what they do best - creating safe and engaging communities - instead of worrying about the challenges related to delivering low-latency live video to a global audience at scale. Which makes total sense - if they can depend on us to handle the complexities related to video, they can focus on creating the best possible user experience. There are enough challenges that they have to worry about. Things like monetization, moderation, content discovery, analytics (and much more) are tricky enough to manage without having to worry about transcoding, packaging and delivery of video bits around the world. As I talk to developers around the world, many are starting to ask about how they might use AI to help solve some of these problems. So in this post, we'll take a look at three possible ways to use AI and various open-source tools to make it easier to create a better UX for a social UGC live streaming application. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🐉 &lt;strong&gt;Here Be Dragons!&lt;/strong&gt; Some of the methods that we'll look at below all utilize the WebRTC-HTTP Egress Protocol - or WHEP - to subscribe to an Amazon IVS real-time stage. Technically this is an &lt;em&gt;unsupported&lt;/em&gt; protocol on Amazon IVS. This means that the usage of WHEP and the endpoints related to subscribing to a real-time stream are not documented, and you'll be unable to receive support related to WHEP if you have any issues. That said, all of the scripts below have been tested to work as of the initial publish date of this blog post. Keep this in mind before implementing any of these solutions and consider this post experimental and educational!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1️⃣ Transcribing a Real-Time Stream
&lt;/h2&gt;

&lt;p&gt;Providing captions (and even translations) for a live stream is great for viewer engagement and helps to make your app accessible for all users, but it's not the only reason why you might want to transcribe a real-time stream. Once you've got a running transcript you can now use AI to summarize the content of that stream and use it for moderation discovery purposes. Now your viewers can find the perfect live stream based on the actual content of the stream, not just based on what the streamer decided to use for a title, description and tags. &lt;/p&gt;

&lt;p&gt;To transcribe a real-time live stream, check out the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-subscribe/ivs-stage-subscribe-transcribe.py" rel="noopener noreferrer"&gt;&lt;code&gt;ivs-stage-subscribe-transcribe.py&lt;/code&gt;&lt;/a&gt; script in &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/" rel="noopener noreferrer"&gt;this repo&lt;/a&gt;. Once you've configured the script, you can run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participant123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will give you output that looks similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-02 15:10:21,022 - INFO - Processing audio chunk 1 in memory (shape: (80000,))
[TRANSCRIPT] or a correction? I mean, that's kind of, you kind of glance over the...
2025-09-02 15:10:26,037 - INFO - Processing audio chunk 2 in memory (shape: (80000,))
[TRANSCRIPT] important part there. that's a mighty big that ellipsis in that reply.
2025-09-02 15:10:31,037 - INFO - Processing audio chunk 3 in memory (shape: (80000,))
[TRANSCRIPT] it is doing a whole heck of a lot of work right there. She kind of went
2025-09-02 15:10:36,020 - INFO - Processing audio chunk 4 in memory (shape: (80000,))
[TRANSCRIPT] from zero to a billion in one giant step.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script is a great starting point. You can modify it for your needs by persisting each transcript to a database, or publishing it over a WebSocket. &lt;/p&gt;

&lt;h2&gt;
  
  
  2️⃣ Analyzing Individual Frames of a Real-Time Stream
&lt;/h2&gt;

&lt;p&gt;As we just saw, transcribing can provide a huge amount of context for discover, moderation and more. But it's only part of the story - sometimes what is unspoken can provide the rest. For this, we can grab individual frames from the live stream and analyze them with Amazon Bedrock. The repo that we looked at earlier has an example of frame analysis in the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-subscribe/ivs-stage-subscribe-analyze-frames.py" rel="noopener noreferrer"&gt;&lt;code&gt;ivs-stage-subscribe-analyze-frames.py&lt;/code&gt;&lt;/a&gt; demo. Once this script is ready to run (check out the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/README.md" rel="noopener noreferrer"&gt;https://github.com/aws-samples/sample-amazon-ivs-python-demos/README.md&lt;/a&gt; for setup instructions) you can run it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;analyze&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;frames&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participant123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;analysis&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;interval&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will provide output like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-02 15:18:38,449 - INFO - 🤖 Frame analysis enabled (interval: 5.0s)
2025-09-02 15:18:38,552 - INFO - 🧊 ICE connection state changed to: completed
2025-09-02 15:18:38,598 - INFO - 🔗 Connection state changed to: connected
2025-09-02 15:18:44,140 - INFO - 🔍 Analyzing frame for participant y1rhVboBJgQb...
2025-09-02 15:18:51,417 - INFO - ✅ Frame analysis completed for participant y1rhVboBJgQb
2025-09-02 15:18:51,417 - INFO - 📝 Analysis: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's the analysis broken out for readability:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is a screenshot from a Twitch live stream showing:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Main Subject&lt;/strong&gt;: A middle-aged man with a gray beard wearing a black baseball cap and what appears to be a white hoodie or jacket with orange/red accents. He's speaking into a black microphone and appears to be seated in a dark gaming chair.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting&lt;/strong&gt;: The background shows a dimly lit room with purple/blue ambient lighting. There's a framed picture or artwork visible on the wall behind him, and the Twitch logo is prominently displayed in purple neon-style lighting on the left side of the frame.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UI Elements&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A chat message is visible at the bottom from user "raymondcamden" asking "hey betty - can you explain the entirety of all existence, starting from the big bang to the current time?"&lt;/li&gt;
&lt;li&gt;There's an anime-style avatar/VTuber character visible in the bottom right corner - appears to be a figure with green hair&lt;/li&gt;
&lt;li&gt;An orange circular logo/symbol is visible in the upper right&lt;/li&gt;
&lt;li&gt;The typical Twitch streaming interface elements are present&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Activity&lt;/strong&gt;: This appears to be an interactive streaming session where the streamer is responding to viewer questions or comments, likely in a talk show or Q&amp;amp;A format rather than gaming content.&lt;/p&gt;

&lt;p&gt;The overall aesthetic suggests this is a professional streaming setup with deliberate lighting and branding elements.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This kind of overview is so much more helpful than anything even the streamer themselves could provide.&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ Analyzing Audio/Video Chunks in a Real-Time Stream
&lt;/h2&gt;

&lt;p&gt;We can take #2 one step further, and instead of analyzing a single video frame we can use TwelveLabs Pegasus to analyze a chunk of actual video (including audio). This combines the effectiveness of transcription (audio context) and frame analysis into a single, holistic analysis.&lt;/p&gt;

&lt;p&gt;Try &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-subscribe/ivs-stage-subscribe-analyze-video.py" rel="noopener noreferrer"&gt;&lt;code&gt;ivs-stage-subscribe-analyze-video.py&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;analyze&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;video&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;subscribe&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;participant123&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzM4NCJ9...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;analysis&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;duration&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will provide output like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;2025-09-02 15:22:37,494 - INFO - 🔍 Video analysis active - recording 10.0 second videos
2025-09-02 15:22:37,494 - INFO - 🔄 1 connection(s) active. Press Ctrl+C to exit.
2025-09-02 15:22:37,494 - INFO - 🎵 Starting audio processing task
2025-09-02 15:22:37,494 - INFO - 🧐 Starting audio and video processing task
2025-09-02 15:22:37,494 - INFO - 🤖 Video analysis enabled (duration: 10.0s)
2025-09-02 15:22:37,596 - INFO - 🧊 ICE connection state changed to: completed
2025-09-02 15:22:37,647 - INFO - 🔗 Connection state changed to: connected
2025-09-02 15:22:37,745 - INFO - 🎥 Starting audio and video chunk recording
2025-09-02 15:22:47,776 - INFO - ⏹️  Stopping recording after 10.03s
2025-09-02 15:22:47,776 - INFO - ✅ Recorded 301 video frames
2025-09-02 15:22:47,776 - INFO - ✅ Recorded 501 audio frames
2025-09-02 15:22:56,227 - INFO - ✅ Successfully encoded video: 1001838 bytes, 1335784 base64 chars
2025-09-02 15:22:56,233 - INFO - 🔍 Analyzing video for participant eBJWcH5N8zSk...
2025-09-02 15:23:02,471 - INFO - ✅ Video analysis completed for participant eBJWcH5N8zSk (finish reason: unknown)
2025-09-02 15:23:02,471 - INFO - 📝 Analysis: 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, breaking out the analysis for readability:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In the video, a man is seated in a chair, speaking into a microphone. &lt;/p&gt;

&lt;p&gt;He is wearing a black cap and a gray hoodie. The background includes a Twitch logo on the left side and a world map on the right side, with a cartoon image of a girl with green hair also visible on the right. &lt;/p&gt;

&lt;p&gt;The man appears to be engaging in a conversation with an audience or a specific person named Betty, as indicated by the text overlay that reads, "Ask a question in chat with Betty!" and "Hey Betty! Can you explain the entirety of the universe starting from the big bang to the current time?" &lt;/p&gt;

&lt;p&gt;The dialogue suggests that the man is asking about the origins of the universe. The overall setting is that of a live stream or video call, where the man is addressing viewers and possibly discussing topics related to gaming or history.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is &lt;em&gt;super helpful&lt;/em&gt; for content discovery, moderation and analysis. Imagine being able to monetize a stream based on the exact content within it!&lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Indexing VODs with TwelveLabs Marengo
&lt;/h2&gt;

&lt;p&gt;Analyzing live video is amazing and powerful, but VODs are just as important to any social UGC video platform. TwelveLabs Marengo can be used via Amazon Bedrock to generate embeddings from video, text, audio, or image inputs. These embeddings can be used for similarity search, clustering, and other machine learning tasks which means your users can easily search for and discover VODs based on the actual video content itself! Check out &lt;a href="https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-marengo.html?trk=769a1a2b-8c19-4976-9c45-b6b1226c7d20&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;the docs&lt;/a&gt; to learn more.&lt;/p&gt;

&lt;h2&gt;
  
  
  5️⃣ Curating VOD Highlights
&lt;/h2&gt;

&lt;p&gt;The key to growth for any social UGC video application is social clip sharing. I've previously blogged about a simple way you can curate clips for social sharing which can help your users easily create their next viral highlight. Check out &lt;a href="https://dev.to/aws/auto-generating-clips-for-social-media-from-live-streams-with-the-strands-agents-sdk-1kkj"&gt;this post&lt;/a&gt; to learn how!&lt;/p&gt;

&lt;h2&gt;
  
  
  🏁 Summary
&lt;/h2&gt;

&lt;p&gt;There are tons of ways to improve the UX of your social UGC live streaming application, and AI is only making it easier for developers. What is your favorite way to use AI with video? Post it in the comments below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>livestreaming</category>
      <category>ai</category>
    </item>
    <item>
      <title>Publishing Real-Time Video via WHIP to Amazon IVS</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Fri, 29 Aug 2025 15:19:12 +0000</pubDate>
      <link>https://forem.com/aws/publishing-real-time-video-via-whip-to-amazon-ivs-p7f</link>
      <guid>https://forem.com/aws/publishing-real-time-video-via-whip-to-amazon-ivs-p7f</guid>
      <description>&lt;p&gt;Traditionally, Amazon IVS real-time stages are used in mobile or web applications. For these types of applications, we offer great SDKs for &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/broadcast-web.html" rel="noopener noreferrer"&gt;web&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/broadcast-ios.html" rel="noopener noreferrer"&gt;iOS&lt;/a&gt; and &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/broadcast-android.html" rel="noopener noreferrer"&gt;Android&lt;/a&gt;. But sometimes your application &lt;em&gt;isn't&lt;/em&gt; a web or mobile application. Or, sometimes your &lt;em&gt;viewers&lt;/em&gt; are on web or mobile but your &lt;em&gt;publisher&lt;/em&gt; isn't. There are several use cases that could fall into the "need to publish from something other than a browser or mobile application" bucket, and in this post I'd like to highlight a few various options. All of the options that we'll look at below are possible because Amazon IVS stages supports the WebRTC-HTTP Ingest Protocol (&lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/rt-stream-ingest.html" rel="noopener noreferrer"&gt;WHIP&lt;/a&gt;). So if you're looking to broadcast from a desktop app, headless server, or any other platform that supports WHIP, read on to learn more!&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Stage
&lt;/h2&gt;

&lt;p&gt;Before we can test out any of the following methods, we'll need to first create an Amazon IVS real-time stage. We can create a stage and a single participant token for testing out all of the methods below with the following command via the AWS CLI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws ivs-realtime create-stage &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="s2"&gt;"whip-demo-stage"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--participant-token-configurations&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nv"&gt;userId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo-whip-broadcaster,capabilities&lt;span class="o"&gt;=&lt;/span&gt;PUBLISH,SUBSCRIBE,duration&lt;span class="o"&gt;=&lt;/span&gt;720
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will give us output similar to the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"stage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"arn"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:ivs:us-east-1:[redacted]:stage/[redacted]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"whip-demo-stage"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"autoParticipantRecordingConfiguration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"endpoints"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"whip"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://f99084460c35.global-bm.whip.live-video.net"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"participantTokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"participantId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[redacted]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ.[redacted]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"userId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"demo-whip-broadcaster"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"capabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"PUBLISH"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"SUBSCRIBE"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've removed some bits for brevity, but the important part going forward is the &lt;code&gt;token&lt;/code&gt; value. Take note of these and let's dig into the various options.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note:&lt;/strong&gt; You'll notice that the WHIP endpoint returned is not the WHIP endpoint that we'll use below. The one we'll use is a &lt;em&gt;global&lt;/em&gt; endpoint (&lt;code&gt;https://global.whip.live-video.net&lt;/code&gt;) which is load-balanced and will ultimately redirect to the most appropriate endpoint for each session. For more information, refer to the &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;docs&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  1️⃣ Broadcasting with OBS
&lt;/h2&gt;

&lt;p&gt;Broadcasting via WHIP with OBS is quite easy! In &lt;em&gt;Settings&lt;/em&gt; -&amp;gt; &lt;em&gt;Stream&lt;/em&gt;, choose &lt;code&gt;WHIP&lt;/code&gt; under &lt;em&gt;Service&lt;/em&gt;. Then enter the &lt;code&gt;https://global.whip.live-video.net&lt;/code&gt; as the endpoint for your stage and your participant &lt;code&gt;token&lt;/code&gt; as the &lt;em&gt;Bearer Token&lt;/em&gt;. For best performance, make sure your stream matches the &lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/obs-whip-support.html" rel="noopener noreferrer"&gt;recommended settings&lt;/a&gt; in the IVS docs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmc820sf51zy9rz2nrzp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmc820sf51zy9rz2nrzp.png" alt="OBS Settings" width="800" height="215"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're ready to start streaming! Click &lt;em&gt;Start Streaming&lt;/em&gt;, then go to the stage details in the AWS console to view your stream.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjikv0wikqxdup8p9prnx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjikv0wikqxdup8p9prnx.png" alt="OBS Console Subscribe" width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the next few options, we'll be using the command line. To simplify the inputs, set your stage token as an environment variable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;STAGE_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ.[redacted]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  2️⃣ Broadcasting with Python's &lt;code&gt;aiortc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Another option for broadcasting to a stage with WHIP is &lt;code&gt;aiortc&lt;/code&gt; which is a library for Web Real-Time Communication (WebRTC) and Object Real-Time Communication (ORTC) in Python. With &lt;code&gt;aiortc&lt;/code&gt;, we can publish from a user's webcam and microphone, or by using a pre-recorded video. I recently published a full &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos" rel="noopener noreferrer"&gt;repo&lt;/a&gt; of demos showing various use cases of &lt;code&gt;aiortc&lt;/code&gt; with Amazon IVS, and to test out publishing an MP4, refer to the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-python-demos/blob/mainline/stages-publish/ivs-stage-publish.py" rel="noopener noreferrer"&gt;&lt;code&gt;ivs-stage-publish.py&lt;/code&gt;&lt;/a&gt; script in that repo. Once you've checked out the project and configured it as necessary, you can publish an MP4 like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;python&lt;/span&gt; &lt;span class="n"&gt;ivs&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;stage&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;py&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="n"&gt;STAGE_TOKEN&lt;/span&gt; \
  &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mp4&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;an&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mp4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The script output is pretty detailed, but once you see the following message, your video is ready to view.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;2025-08-29 10:44:16,786 - INFO - 🎉 WebRTC publishing established!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aabuxoaa1aniccno7is.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aabuxoaa1aniccno7is.png" alt="aiortc console view" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  3️⃣ Broadcasting with FFMPEG
&lt;/h2&gt;

&lt;p&gt;Another option, which is relatively new, is to broadcast to an Amazon IVS stage via FFMPEG. Back in June FFMPEG &lt;a href="https://www.phoronix.com/news/FFmpeg-Lands-WHIP-Muxer" rel="noopener noreferrer"&gt;merged the long-outstanding WHIP muxer&lt;/a&gt; into the mainline repo. You'll need to &lt;a href="https://trac.ffmpeg.org/wiki/CompilationGuide/macOS#CompilingFFmpegyourself" rel="noopener noreferrer"&gt;compile it from source&lt;/a&gt; to enable WHIP (make sure to include the &lt;code&gt;--enable-muxer=whip&lt;/code&gt; and &lt;code&gt;--enable-libharfbuzz&lt;/code&gt; options). Once it's compiled you can use the same &lt;code&gt;endpoint&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt; from earlier to publish an MP4.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-re&lt;/span&gt; &lt;span class="nt"&gt;-stream_loop&lt;/span&gt; &lt;span class="nt"&gt;-1&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-i&lt;/span&gt; /path/to/an.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="nt"&gt;-profile&lt;/span&gt;:v baseline &lt;span class="nt"&gt;-c&lt;/span&gt;:a copy &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; whip &lt;span class="nt"&gt;-authorization&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$STAGE_TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://global.whip.live-video.net"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Again, take a look at the AWS console to view your stream. (Yes, I'm using the same picture from earlier - it's literally the same result 😆).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aabuxoaa1aniccno7is.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8aabuxoaa1aniccno7is.png" alt="ffmpeg console view" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  4️⃣ Broadcasting with &lt;code&gt;srtc&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;The final option that we'll look at in this post is an open-source library called &lt;code&gt;srtc&lt;/code&gt; (&lt;a href="https://github.com/kmansoft/srtc/" rel="noopener noreferrer"&gt;repo&lt;/a&gt;). This is a "simple" WebRTC implementation written in C++ as a side project by Kostya Vasilyev, one of the brilliant Amazon IVS engineers. You can use the library to create your own WebRTC application, but for simple testing you can download the &lt;a href="https://github.com/kmansoft/srtc/releases" rel="noopener noreferrer"&gt;latest release&lt;/a&gt; for your OS and the &lt;code&gt;sintel.h264&lt;/code&gt; file from the release page. Then, you can publish a test stream with the &lt;code&gt;srtc_publish&lt;/code&gt; binary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;./srtc_publish &lt;span class="nt"&gt;--url&lt;/span&gt; https://global.whip.live-video.net &lt;span class="nt"&gt;--token&lt;/span&gt; &lt;span class="nv"&gt;$STAGE_TOKEN&lt;/span&gt; &lt;span class="nt"&gt;--file&lt;/span&gt; ./sintel.h264 &lt;span class="nt"&gt;--loop&lt;/span&gt;
&lt;span class="k"&gt;***&lt;/span&gt; Using &lt;span class="nb"&gt;source &lt;/span&gt;file: ./sintel.h264
&lt;span class="k"&gt;***&lt;/span&gt; Using WHIP URL:    https://global.whip.live-video.net
&lt;span class="k"&gt;***&lt;/span&gt; Loading ./sintel.h264
&lt;span class="k"&gt;***&lt;/span&gt; PeerConnection state: connecting
&lt;span class="k"&gt;***&lt;/span&gt; PeerConnection state: connected
Played    25 video frames
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;🔇 &lt;strong&gt;Note:&lt;/strong&gt; The command line demo publishes &lt;strong&gt;video only&lt;/strong&gt;. The project is intended to be used as a dependency for building your own applications, so audio is not included in the command line demo utility.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Again, preview the stream in the AWS console.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvxf7ut99uanoyvw17k6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flvxf7ut99uanoyvw17k6.png" alt="srtc preview" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, we've looked at several ways to publish to an Amazon IVS real-time stage using the WebRTC HTTP Ingest Protocol (WHIP). I hope this post helped you to realize the possibilites of WebRTC and real-time streaming outside of traditional web and mobile applications and maybe inspired you to think beyond the "usual" approach to publishing real-time video. If you have questions, or ideas about how you might use WHIP with Amazon IVS, please share them below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>webrtc</category>
      <category>whip</category>
    </item>
    <item>
      <title>Strands Agents SDK を使用してライブストリームからソーシャルメディア用のクリップを自動生成する</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Mon, 25 Aug 2025 12:41:47 +0000</pubDate>
      <link>https://forem.com/aws/strands-agents-sdk-woshi-yong-siteraibusutorimukarasosiyarumedeiayong-nokuritupuwozi-dong-sheng-cheng-suru-219n</link>
      <guid>https://forem.com/aws/strands-agents-sdk-woshi-yong-siteraibusutorimukarasosiyarumedeiayong-nokuritupuwozi-dong-sheng-cheng-suru-219n</guid>
      <description>&lt;p&gt;生成 AI は、大量のデータを分析し、指示に基づいてデータの意味ある箇所を特定し、要約することに優れています。データのソースは何でも構いません。あなたのメールの受信箱、ローカル上の大きなテキストファイル、またはインターネット上のウェブページなど。大量のデータを含む大きなタスクは完璧にこなせなくても、タスクを効率よくスタートさせることができます。私が開発者からよく相談される話題の一つは、AI をどのようにビデオコンテンツの分析に活用できるかということです。マルチモーダル LLM は大きく進歩してきましたが、1 時間ほどのライブストリーム録画を取り込んで要約させたり、ソーシャルメディアで共有するためのクリップを提案してもらったりできるレベルにはまだ達していません。この問題を解決するためには、本記事で紹介する少し異なるアプローチを取る必要があります。&lt;/p&gt;

&lt;h2&gt;
  
  
  ソリューション概要
&lt;/h2&gt;

&lt;p&gt;ライブストリームの録画（VOD）を分析するツールを作成するために、私は以下のアプローチを取りました：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;HLS メディアをローカルにダウンロードし、 MP4 形式に変換&lt;/li&gt;
&lt;li&gt;MP4 ファイルの文字起こしを作成&lt;/li&gt;
&lt;li&gt;AI エージェントを用いて、文字起こしを元にクリップ候補となる開始/終了タイムスタンプを特定&lt;/li&gt;
&lt;li&gt;特定されたタイムスタンプに基づいて MP4「クリップ」を作成&lt;/li&gt;
&lt;li&gt;作業の要約を生成&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  ソリューションアーキテクチャ
&lt;/h2&gt;

&lt;p&gt;このソリューションの実装では、新しい &lt;a href="https://strandsagents.com/" rel="noopener noreferrer"&gt;Strands Agents SDK&lt;/a&gt; を試してみることにしました。Strands Agent SDKはエージェント構築のための比較的新しいフレームワークであり、エージェントがプロンプトへの応答を生成する際に利用できるツールを簡単に定義できることが特徴です。このソリューションでは、エージェントが実行されるマシンに &lt;a href="https://ffmpeg.org/" rel="noopener noreferrer"&gt;FFmpeg&lt;/a&gt; と &lt;a href="https://github.com/openai/whisper" rel="noopener noreferrer"&gt;Whisper&lt;/a&gt; がインストールされている必要があります。私はローカルで作業していますが、FastAPI や他の Web フレームワークを使用してサーバーベースのソリューションに簡単に変換でき、Docker や Podman のコンテナとしてでクラウドにデプロイできます。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1dfsddm8sdf1t9swb45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1dfsddm8sdf1t9swb45.png" alt="Strands Clipping Solution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  ツールの定義
&lt;/h2&gt;

&lt;p&gt;Strands Agents の概要は公式ドキュメントで説明されているので、ここでは割愛します。代わりに、デモを通じて実際の動作を確認していきましょう。&lt;/p&gt;

&lt;p&gt;まずは、Python の新しい仮想環境を作成します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;次に、必要な依存関係をインストールします。次の内容を &lt;code&gt;requirements.txt&lt;/code&gt; に記述します：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FFmpeg-python
git+https://github.com/openai/whisper.git
strands-agents
strands-agents-tools 
click
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;依存関係をインストールします：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;続いて、&lt;code&gt;agent.py&lt;/code&gt; ファイルを作成し、依存関係のインポートを定義します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;shutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;whisper&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;whisper.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_writer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;use_aws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;一時作業用のディレクトリを作成し、一時ファイル用の変数をいくつか定義します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdtemp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mp4_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;mp4_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mp4_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;transcript_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.vtt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;transcript_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;これで、エージェントがタスクを完了するために必要なツールを定義することができます。ツールは、 &lt;code&gt;@tool&lt;/code&gt; デコレータを用いることで定義できます。&lt;br&gt;
最初のツールは、指定された URL 先の HLS プレイリストである &lt;code&gt;m3u8&lt;/code&gt; ファイルを、FFmpeg を用いて &lt;code&gt;mp4&lt;/code&gt; ファイルとしてダウンロードします。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_m3u8_to_mp4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_m3u8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_m3u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;acodec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;vcodec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;crf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bsf:a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aac_adtstoasc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quiet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved stream to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;次のツールは、Whisper を用いて MP4 ファイルの文字起こしを行います。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transcribe_mp4&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transcribing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;whisper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vtt_writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vtt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;vtt_writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transcribe complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;最後のツールは、エージェントが特定した開始/終了タイムスタンプを基に、指定された時間範囲で元の &lt;code&gt;mp4&lt;/code&gt; ファイルから新しいクリップを生成する機能です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_mp4_clip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;FFmpeg を用いて mp4 をクリップする&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quiet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;FFmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  エージェントへのプロンプト
&lt;/h2&gt;

&lt;p&gt;ツールの定義が終わりましたので、エージェントのインスタンスを作成しましょう。エージェントには、先ほど作成したカスタムツールと、必要に応じて使用できる組み込みツール（&lt;code&gt;file_read&lt;/code&gt;、&lt;code&gt;file_write&lt;/code&gt;、&lt;code&gt;use_aws&lt;/code&gt; など）を渡します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;create_mp4_clip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;convert_m3u8_to_mp4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;transcribe_mp4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;use_aws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;次に、ユーザーに &lt;code&gt;verbose&lt;/code&gt; モード（FFmpeg と Whisper の標準出力を表示）で実行するかを確認し、&lt;code&gt;m3u8&lt;/code&gt;（HLS プレイリスト）URL の入力を求めます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enable verbose output?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m3u8_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter M3U8 URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;そして、エージェントにプロンプトを渡します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
      your purpose is to generate small clips from a larger live stream 
      so that they can be shared on social media.
      your task involves the following steps:

      1. download the HLS segments and convert them to an MP4 file
      2. transcribe the downloaded MP4 using whisper
      3. analyze the transcript to identify potential clips
      4. create the clips
      5. provide a summary of your work

      here are some details:

      Step 1: using the tool `convert_m3u8_to_mp4`:
      given the HLS manifest file located at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m3u8_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,
      convert the live stream to an MP4 and save it to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.

      Step 2: using the tool `transcribe_mp4`:
      transcribe the MP4 and save the transcript to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transcript_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.
      this will produce a timestamped transcript from the live stream. 

      Step 3: take a look at the transcript and identify a list of suggested 
      timestamps (start and end) for clips that might be good to share 
      on social media. provide a suggested title, the start and end 
      timestamp, the transcript in that section, a summary/description 
      and several tags.

      Step 4: using the tool `create_mp4_clip`:
      after you have identified them, create an mp4 for each based on 
      the timestamp identified. use the original mp4 that was created 
      in the first step that is located at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.
      each output file should use a kebab case mp4 filename
      generated from your suggested title. 
      save the new clips in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.

      do not cleanup the temp directory at this time, even though 
      you have a tool that can perform this step. 

      Step 5: provide a summary of your work, 
      in the summary, output the following information for each clip:
        - Title
        - Start Time
        - End Time 
        - Transcript
        - Summary
        - Tags
        - File Location of Clip
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  アプリケーションの実行
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;python agent.py&lt;/code&gt; コマンドでアプリケーションを実行すると、verbose モードの有効化と URL の入力が求められます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Enable verbose output? &lt;span class="o"&gt;[&lt;/span&gt;y/N]: 
Enter M3U8 URL:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;今回は、私の友人である &lt;a href="https://rup12.net/" rel="noopener noreferrer"&gt;Darko Mesaroš&lt;/a&gt; の&lt;a href="https://www.twitch.tv/videos/2427797850" rel="noopener noreferrer"&gt;最近のライブストリーム&lt;/a&gt;を用いてエージェントをテストしました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I'll help you generate small clips from the larger live stream following the steps you've outlined. Let's begin:

## Step 1: Download the HLS segments and convert them to an MP4 file

First, I'll convert the HLS manifest file to an MP4.
Tool #1: convert_m3u8_to_mp4
Saved stream to /[redacted]/0a464c96-e071-4300-83d7-a74eeee82e28.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;期待通りの結果です。プロンプト通りに MP4 ファイルが正常に作成されました。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Step 2: Transcribe the MP4 file

Now, I'll transcribe the downloaded MP4 file:
Tool #3: transcribe_mp4
Transcribing /[redacted]/0a464c96-e071-4300-83d7-a74eeee82e28.mp4 to 55c5f5f6-85ed-46d4-80f9-d455f6c51fcb.vtt
/[redacted]/transcribe.py:132: UserWarning: FP16 is not supported on CPU; using FP32 instead
  warnings.warn("FP16 is not supported on CPU; using FP32 instead")
Detected language: English
Transcribe complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;そして文字起こしも完了しました！次は、この文字起こしを分析してクリップ候補を提案してくれるはずです。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Step 3: Analyze the transcript to identify potential clips

Based on the transcript, I'll identify several potential clips that could be good to share on social media. These will be moments that are engaging, informative, or entertaining.

### Clip 1: Stream Introduction and Technical Difficulties

**Title:** "Starting a Creative Coding Stream with Rust"

**Start Time:** 01:26.580
**End Time:** 02:12.220

**Transcript:**
"NOW! We're live. Yes. Okay. Now there's audio. There's audio. Okay. I was like, ah, um, so last moment I had to cut off my, um, what is it called? My, uh, my audio. Not only my whole Thunderbolt docked here because it just froze. So lost all my audio and everything else as I went along. So how do you, how do we, Jay? How are you doing my friend? It has been way too long. So I hope you're doing good. Um, welcome to the show. Welcome. Welcome. It has been actually, um, actually even a good old while for myself in the terms of live streaming. I think I have a stream for like 20 days. So incredibly happy to be back. So yeah, let's do some live streaming."

**Summary:** The streamer begins their first live stream in 20 days, explaining how they had technical difficulties with their audio setup when trying to start the stream. Despite the challenges, they're enthusiastic about being back and connecting with viewers.

**Tags:** #RustDevelopment #LiveCoding #StreamingTech #CreativeCoding #TechnicalDifficulties

### Clip 2: Introducing GGEZ - A Rust Game Engine

**Title:** "What is GGEZ? A Rust Game Engine for Creative Coding"

**Start Time:** 02:30.860
**End Time:** 03:29.820

**Transcript:**
"Um, okay. So the plan for today, my friends, is to do some stuff with, well, as always, Rust. So I'm going to do some creative coding today. Something with, um, um, Rust and a, and a framework I was using over the last few days called, GGE. It is a, I think they call themselves like a rust game engine thing. Like not terribly serious. It's not a full blown game engine. Um, it's a, it's a thing and it kind of does graphics. It is very similar to like P5JS, which is a very much, uh, an artistic type of coding framework, which I used in the past stream a long time ago. And, and of course, P5JS comes from processing. If anybody knows what processing is, um, so processing is an old framework. I think it uses its own bespoke language to do like graphics and like stuff. So, um, that's the whole plan today to do a little bit of that. Um, and have some fun."

**Summary:** The streamer introduces GGEZ, a Rust game engine framework they'll be using for creative coding. They explain how it's similar to P5JS and Processing, highlighting that it's not a full game engine but a tool for making graphics and creative coding projects.

**Tags:** #RustProgramming #GGEZ #GameDevelopment #CreativeCoding #GraphicsProgramming

### Clip 3: Drawing Fire - Creative Coding Goal

**Title:** "Let's Draw Fire with Rust: My Creative Coding Challenge"

**Start Time:** 06:03.980
**End Time:** 07:09.740

**Transcript:**
"So what, why would I like to do is I would love to do some creative coding, but in Rust. So, so that's the plan for today. Do a little bit of that. Um, there's no certain point to today. Like, in a sense, like we're not building up to, we're going to share. We're going to try to draw some pixels on the screen. We're not going to go too crazy and be like S.D.L type of approach. And I'm like, just super complicated. We're going to just do, um, squares and circles and whatnot. So, um, I want to try to draw flames. This is one of my, one of my tests when I draw this, these kinds of, when I work with these, a kind of artistic tools is like, can I draw fire, right? A C doughnut. Is, is a C doughnut, so. I know a C, oh, oh, wow. This would be a, I mean, probably at one point, I'm not as good as, as being able to do something like this. I know this whole thing code that actually is shaped like doughnut and it's just math. I'm not as good as math in this, but, um, yeah, yeah, yeah. We're going to try to draw some flames just simple as that. And I've done that in the past in Lua, but I want to try to do a Darwin rust. And I want to use this GGZ to set it up."

**Summary:** The streamer explains their goal for the creative coding session: to draw flames using Rust and GGEZ. They mention this as their go-to test when trying out new creative coding frameworks, comparing it to the famous "donut" code visualization but clarifying they'll stick to something simpler that they've previously implemented in Lua.

**Tags:** #RustCreativeCoding #DigitalArt #FlameSimulation #CreativeTech #VisualProgramming

### Clip 4: Setting Up GGEZ Fundamentals

**Title:** "How GGEZ Works: The Core Architecture of a Rust Game Engine"

**Start Time:** 12:46.140
**End Time:** 13:21.340

**Transcript:**
"So the way this works is that, um, your application has, um, basically a state, a main state where it kind of keeps stuff between frames. And, um, it has specific events on that state. That means as your application runs, there is a draw event, and there's an update event. And within those two events, you can do certain things. Now, of course, in the draw event, you draw on the screen, and the update event, you update whatever you're doing. And those are the two, two main important things we're going to be creating. And GGZ requires you to do it in a specific way."

**Summary:** The streamer explains the fundamental architecture of GGEZ, detailing how the game loop works with a main state that maintains data between frames, and the two key events - draw and update - that form the backbone of any GGEZ application.

**Tags:** #GameDevelopment #RustProgramming #GameLoop #GGEZ #GraphicsProgramming
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;出力が長々と続きますが、まさに期待通りです。指定された 20 分のライブストリームを分析し、「魅力的で、情報に富み、または娯楽性のある」4 つのクリップ候補が提案されています。この要約を見る限り、ソーシャルメディアで共有するのに適した、長時間ストリームから抽出すべき短時間クリップを見つける作業を非常にうまく行っています。&lt;br&gt;
次のステップは、実際の &lt;code&gt;mp4&lt;/code&gt; クリップファイルの生成です。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Now I'll create MP4 clips for each of the identified segments:
Tool #6: create_mp4_clip
Tool #7: create_mp4_clip
Tool #8: create_mp4_clip
Tool #9: create_mp4_clip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;最後に、エージェントが全作業の要約を提供します。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;## Step 5: Summary of Work

### Clip 1: Starting a Creative Coding Stream with Rust
- **Title:** Starting a Creative Coding Stream with Rust
- **Start Time:** 00:01:26.580
- **End Time:** 00:02:12.220
- **Transcript:** "NOW! We're live. Yes. Okay. Now there's audio. There's audio. Okay. I was like, ah, um, so last moment I had to cut off my, um, what is it called? My, uh, my audio. Not only my whole Thunderbolt docked here because it just froze. So lost all my audio and everything else as I went along. So how do you, how do we, Jay? How are you doing my friend? It has been way too long. So I hope you're doing good. Um, welcome to the show. Welcome. Welcome. It has been actually, um, actually even a good old while for myself in the terms of live streaming. I think I have a stream for like 20 days. So incredibly happy to be back. So yeah, let's do some live streaming."
- **Summary:** The streamer begins their first live stream in 20 days, explaining how they had technical difficulties with their audio setup when trying to start the stream. Despite the challenges, they're enthusiastic about being back and connecting with viewers.
- **Tags:** #RustDevelopment #LiveCoding #StreamingTech #CreativeCoding #TechnicalDifficulties
- **File Location:** /[redacted]/starting-a-creative-coding-stream-with-rust.mp4

[trimmed for brevity]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;以下に、エージェントが長いライブストリームから生成したクリップの一例です：&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/h_rND7go2nU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  エージェントの拡張
&lt;/h2&gt;

&lt;p&gt;必要に応じて、例えば生成された &lt;code&gt;mp4&lt;/code&gt; ファイルを S3 バケットにアップロードするようエージェントに指示することもできます。その場合、処理中に生成された一時ファイルをクリーンアップするツールも作成したくなるでしょう。エージェントを拡張するツールはいくらでも追加できます。&lt;/p&gt;

&lt;p&gt;このソーシャルクリップ生成エージェントにどのような拡張機能を追加したいですか？Strands Agents フレームワークをどのように活用していますか？コメントでぜひお聞かせください。&lt;/p&gt;

&lt;p&gt;原文は&lt;a href="https://dev.to/aws/auto-generating-clips-for-social-media-from-live-streams-with-the-strands-agents-sdk-1kkj"&gt;こちら&lt;/a&gt;です。&lt;br&gt;
本ブログは Amazon Web Services Japan Startup Solutions Architect の &lt;a href="https://x.com/prog893" rel="noopener noreferrer"&gt;Torgayev Tamirlan&lt;/a&gt; が翻訳しました。&lt;/p&gt;

&lt;p&gt;写真出展：&lt;a href="https://unsplash.com/@sangharsh_l?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Sangharsh Lohakare&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-close-up-of-a-blue-and-purple-structure-8o_LkMpo8ug?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>livestreaming</category>
      <category>strandsagents</category>
    </item>
    <item>
      <title>Building Virtual Agents with Amazon Nova Sonic S2S</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Wed, 13 Aug 2025 16:59:04 +0000</pubDate>
      <link>https://forem.com/aws/building-virtual-agents-with-amazon-nova-sonic-s2s-23m7</link>
      <guid>https://forem.com/aws/building-virtual-agents-with-amazon-nova-sonic-s2s-23m7</guid>
      <description>&lt;p&gt;One of the more intriguing and helpful use cases of generative AI is voice agents. Advancements in speech recognition and synthesis have blurred the lines between human and machine to the point where it no longer feels like you're speaking to a terrible robot from a 1980's sci-fi flick. There's something strangely soothing to me about speaking to a virtual agent these days. There's no need to worry that the person on the other end of the line has had an awful day, or just spilled their coffee on their lap. Just a friendly, no-nonsense bot who is happy to help you. Of course there are exceptions to this - but I'd rather talk to a bot than a human for most customer service interactions these days. So what does it take to create your own virtual agent that understands your speech and responds to you with a friendly demeanor and a human-like voice? Let's take a look! &lt;/p&gt;

&lt;h2&gt;
  
  
  Agent Demo
&lt;/h2&gt;

&lt;p&gt;Before we dig into things, here's a quick video showing the agent in action. There's room for a bit of improvement here since the Nova S2S agent is not optimized for WebRTC communication. We've got to buffer the audio a bit to make things sound clear and smooth when streaming over WebRTC. Using tools (as we'll talk about in a bit) will also incur a bit of delay, since the agent needs to first invoke the tool before it can parse and summarize the data and respond. But overall, it's an amazing experience and opens up the door to many possibilities.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/pH_GrzPjzX0"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Amazon Nova Sonic
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.aws.amazon.com/ai/responsible-ai/nova-sonic/overview.html" rel="noopener noreferrer"&gt;Amazon Nova Sonic&lt;/a&gt; is a foundation model created by &lt;a href="https://labs.amazon.science/" rel="noopener noreferrer"&gt;Amazon AGI Labs&lt;/a&gt; with a bidirectional streaming API. This means you can speak to it, and it can respond by speaking to you. No need to convert speech-to-text, or text-to-speech  - the model supports direct audio input and output. Right off the top, this is a huge win. TTS and STS are not terribly difficult to implement these days, but removing the need to concern yourself with these tasks lets you focus on building the experience of your application and enhancing your agent with custom tools that can provide it with deep contextual knowledge. Want to build a reservation system for your customers? No problem - just wire up your agent with the tools that it needs to access the user's data and it'll be able to retrieve and modify reservations through simple conversations. Practically any use case that you can think of is possible. &lt;a href="https://nova.amazon.com/sonic" rel="noopener noreferrer"&gt;Try it out&lt;/a&gt; for yourself without writing a single line of code. When you're ready to implement your own agent, check out the &lt;a href="https://docs.aws.amazon.com/nova/latest/userguide/speech.html" rel="noopener noreferrer"&gt;user guide&lt;/a&gt; - or read on in this post to learn how I created a demo that shows you how to integrate your Nova Sonic agent into an Amazon IVS real-time stream.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building A Live-Stream Agent
&lt;/h2&gt;

&lt;p&gt;Running in the browser or on the command line is an excellent use-case for a voice agent. But wouldn't it be super cool if the agent could actually join as a virtual participant in a WebRTC based video call? Yeah, I thought so too - so about a month ago I started playing around with the Python library &lt;a href="https://github.com/aiortc/aiortc/" rel="noopener noreferrer"&gt;&lt;code&gt;aiortc&lt;/code&gt;&lt;/a&gt; to provide an integration between  Amazon IVS and a Nova Sonic agent. Here's how it works:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User joins an Amazon IVS real-time stage with camera and microphone in the browser&lt;/li&gt;
&lt;li&gt;Agent script launched&lt;/li&gt;
&lt;li&gt;Agent subscribes to a single user's audio and video

&lt;ul&gt;
&lt;li&gt;Pipe user's audio into Nova Sonic&lt;/li&gt;
&lt;li&gt;Captures video frames &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Agent joins as a publisher, with dynamically generated speech visualization video track&lt;/li&gt;

&lt;li&gt;Agent listens for user audio, and responds (invoking 'tools' as necessary)&lt;/li&gt;

&lt;li&gt;Agent audio is published as an audio track to the stage&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tools ⚒️
&lt;/h2&gt;

&lt;p&gt;The demo agent has a few tools to demonstrate Nova Sonic's ability to augment the agent's contextual and domain-specific knowledge. The simplest example is asking the agent for the current time. Because the agent is trained on a static dataset, it has no way to determine the current date or time. But if we expose a tool for this, it's really easy to add this potentially import context to the agent. The tool can use simple Python (&lt;code&gt;datetime.now()&lt;/code&gt;) or can be more complex, like calling third-party APIs or using SDKs to retrieve dynamic data. For example, the demo in the repo linked in this post has a weather tool that can get the current weather via a remote API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Giving the Agent Vision 🤖👀
&lt;/h2&gt;

&lt;p&gt;Because the agent script is subscribed to the user's video feed, it seemed logical to give the agent the ability to "see" the user. You can literally ask it to describe what you look like or what it sees in the environment around you. You can even ask it to tell you what you're holding in your hand. When it determines that it needs to use its "vision" tool, it grabs the latest video frame and passes it to a multi-modal LLM for image analysis. The analysis is returned to the agent which summarizes it and tells you what it saw.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out!
&lt;/h2&gt;

&lt;p&gt;If you'd like to try it out for yourself, clone the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-aiortc-demos" rel="noopener noreferrer"&gt;demo repo&lt;/a&gt; to your machine and refer to the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-aiortc-demos/blob/mainline/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt;. There are several different use cases in that repo, so refer to the &lt;code&gt;stages-nova-s2s&lt;/code&gt; directory for this demo (but check out the other demos too!). There's also a &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-aiortc-demos/blob/mainline/stages-nova-s2s/README.md" rel="noopener noreferrer"&gt;Nova Sonic specific README&lt;/a&gt; in that directory that goes into a bit more detail.&lt;/p&gt;

&lt;p&gt;Once you've cloned the repo, create an Amazon IVS real-time stage and publish to it. You can do this right from the Amazon IVS Console. Once you're publishing to the stage, you'll need to find your participant ID. On the stage details page (the page that you're using to publish your camera), scroll down to &lt;strong&gt;Stage sessions&lt;/strong&gt; and select the &lt;strong&gt;ACTIVE&lt;/strong&gt; session.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5s81zk2hy3wy0uyrd8k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5s81zk2hy3wy0uyrd8k.png" alt="Stage sessions"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the session details page, scroll down to &lt;strong&gt;Stage participants&lt;/strong&gt; and find the &lt;strong&gt;CONNECTED&lt;/strong&gt; participant and copy the &lt;strong&gt;Participant Id&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36na4bn715wxcajkg0sa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36na4bn715wxcajkg0sa.png" alt="Stage participants"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Head back to the stage details page and generate a participant token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0yf845xl3h1kymbdhff.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft0yf845xl3h1kymbdhff.png" alt="Create token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7lcq29q2bz4kfr3s9ub.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr7lcq29q2bz4kfr3s9ub.png" alt="Token dialog"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, copy the newly generated token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonjpee7u60iyuxuokw3k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fonjpee7u60iyuxuokw3k.png" alt="Copy token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Launch the new agent with the agent's generated token and the original participant's id:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python ivs-stage-nova-s2s.py &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--token&lt;/span&gt;  eyJhbGciOiJLTVMiLCJ0eXAiOiJKV1QifQ... &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--subscribe-to&lt;/span&gt; 43QZqauB2sFz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few seconds, you'll see your agent join the stage and you'll be able to chat with it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jww9hfd7buwdg3917zt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5jww9hfd7buwdg3917zt.png" alt="Stage with agent"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Feel free to check out the source code in the &lt;a href="https://github.com/aws-samples/sample-amazon-ivs-aiortc-demos" rel="noopener noreferrer"&gt;demo repo&lt;/a&gt; to learn how to enhance and customize the agent in your own applications. Try to add your own custom tools and give the agent domain specific superpowers! This demo should give you a great start towards building your own voice agents powered by Amazon IVS and Amazon Nova Sonic. &lt;/p&gt;

&lt;p&gt;For more information, refer to the user guides and documentation for Amazon IVS and Amazon Nova Sonic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/ivs/latest/RealTimeUserGuide/what-is.html" rel="noopener noreferrer"&gt;Amazon IVS Real-Time User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/ai/responsible-ai/nova-sonic/overview.html" rel="noopener noreferrer"&gt;Amazon Nova Sonic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nova.amazon.com/sonic" rel="noopener noreferrer"&gt;Try Nova Sonic&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ivs.rocks/real-time" rel="noopener noreferrer"&gt;IVS Rocks&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So what will you build with Amazon Nova Sonic and Amazon IVS?&lt;/p&gt;

</description>
      <category>aws</category>
      <category>ai</category>
      <category>amazonivs</category>
      <category>livestreaming</category>
    </item>
    <item>
      <title>Auto-Generating Clips for Social Media from Live Streams with the Strands Agents SDK</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Fri, 06 Jun 2025 17:12:34 +0000</pubDate>
      <link>https://forem.com/aws/auto-generating-clips-for-social-media-from-live-streams-with-the-strands-agents-sdk-1kkj</link>
      <guid>https://forem.com/aws/auto-generating-clips-for-social-media-from-live-streams-with-the-strands-agents-sdk-1kkj</guid>
      <description>&lt;p&gt;Generative AI is excellent at analyzing large amounts of data and identifying and summarizing a meaningful subset of the data based on a guided set of instructions. The source of the data could be anything - your email inbox, a large text file on your machine or a webpage on the internet. It's not perfect, but it can give you a head start on large tasks that involve a lot of data. One of the things I get asked about a lot by developers is how they can use AI to analyze video content. Multimodal LLMs have come a long way, but they're not quite at the point where they could ingest an hour's worth of video from a live stream and provide a summary or identify potential clips for sharing on social media. But there's another approach that we can take to solve this problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution Overview
&lt;/h2&gt;

&lt;p&gt;In order to create a tool to analyze a video-on-demand (VOD) from a live stream, I settled on the following approach.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download/convert the HLS media to a local MP4&lt;/li&gt;
&lt;li&gt;Transcribe the MP4 &lt;/li&gt;
&lt;li&gt;Ask an AI agent to identify start/end timestamps for potential clips based on the transcript&lt;/li&gt;
&lt;li&gt;Create MP4 'clips' based on the identified timestamps&lt;/li&gt;
&lt;li&gt;Summarize the work&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Solution Architecture
&lt;/h2&gt;

&lt;p&gt;To accomplish this task, I decided to try out the new &lt;a href="https://strandsagents.com/" rel="noopener noreferrer"&gt;Strands Agents SDK&lt;/a&gt;. It's a fairly new framework for building agents that has a simple way to define tools that the agent can use to assist in responding to prompts. For this solution, we'll need &lt;a href="https://ffmpeg.org" rel="noopener noreferrer"&gt;FFMPEG&lt;/a&gt; and &lt;a href="https://github.com/openai/whisper" rel="noopener noreferrer"&gt;Whisper&lt;/a&gt; installed on the machine where the agent runs. I'll be working locally, but this could easily be converted to a server-based solution using FastAPI or another web framework and deployed to the cloud in a Docker/Podman container. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1dfsddm8sdf1t9swb45.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm1dfsddm8sdf1t9swb45.png" alt="Strands Clipping Solution"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Defining Tools
&lt;/h2&gt;

&lt;p&gt;I won't cover how to get started with Strands Agents since the docs do a great job of that. Instead, we'll walk through this demo and see how it works. &lt;/p&gt;

&lt;p&gt;Of course we start with a fresh virtual environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv
&lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next we'll need to install our dependencies. Place the following in &lt;code&gt;requirements.txt&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg-python
git+https://github.com/openai/whisper.git
strands-agents
strands-agents-tools 
click
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And install the dependencies with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in &lt;code&gt;agent.py&lt;/code&gt;, we'll define our imports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;uuid&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;shutil&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;whisper&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;whisper.utils&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;get_writer&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;strands_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;use_aws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a temp working directory and some variables for our temp files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempfile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;mkdtemp&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;mp4_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.mp4&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;mp4_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mp4_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;transcript_file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uuid4&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.vtt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;transcript_path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we can start defining the tools that our agent will need to complete the task. For this we use the &lt;code&gt;@tool&lt;/code&gt; decorator. The first tool will take the &lt;code&gt;m3u8&lt;/code&gt; URL for the HLS playlist and download it as an &lt;code&gt;mp4&lt;/code&gt; with FFMPEG.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;convert_m3u8_to_mp4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_m3u8&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path_to_m3u8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;acodec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;vcodec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;crf&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bsf:a&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;aac_adtstoasc&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quiet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Saved stream to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next tool will transcribe the MP4 with Whisper.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;transcribe_mp4&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transcribing &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;whisper&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;vtt_writer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;get_writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;vtt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;vtt_writer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;transcript_file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Transcribe complete&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, a tool that will take the start/end timestamps that the agent identifies and generate a new clip from the original &lt;code&gt;mp4&lt;/code&gt; at the given start/end time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_mp4_clip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;clip an mp4 using ffmpeg&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;start_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;end_time&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;output&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;copy&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;loglevel&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;verbose&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;quiet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ffmpeg&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;overwrite_output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Prompting the Agent
&lt;/h2&gt;

&lt;p&gt;Now that our tools are defined, we can create an instance of the agent. Here we are passing our custom tools, as well as some built-in tools like &lt;code&gt;file_read&lt;/code&gt;, &lt;code&gt;file_write&lt;/code&gt; and &lt;code&gt;use_aws&lt;/code&gt; that the agent can use as necessary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;agent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;create_mp4_clip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;convert_m3u8_to_mp4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;transcribe_mp4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;file_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;use_aws&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll prompt the user to ask if they'd like to run in &lt;code&gt;verbose&lt;/code&gt; mode (which will provide STDIO output from FFMPEG and Whisper) and ask them to provide the &lt;code&gt;m3u8&lt;/code&gt; (HLS playlist) URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;verbose&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;confirm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enable verbose output?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;m3u8_url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;click&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Enter M3U8 URL&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And now we can pass a prompt to the agent.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nf"&gt;agent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
      your purpose is to generate small clips from a larger live stream 
      so that they can be shared on social media.
      your task involves the following steps:

      1. download the HLS segments and convert them to an MP4 file
      2. transcribe the downloaded MP4 using whisper
      3. analyze the transcript to identify potential clips
      4. create the clips
      5. provide a summary of your work

      here are some details:

      Step 1: using the tool `convert_m3u8_to_mp4`:
      given the HLS manifest file located at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;m3u8_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;,
      convert the live stream to an MP4 and save it to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.

      Step 2: using the tool `transcribe_mp4`:
      transcribe the MP4 and save the transcript to &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;transcript_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.
      this will produce a timestamped transcript from the live stream. 

      Step 3: take a look at the transcript and identify a list of suggested 
      timestamps (start and end) for clips that might be good to share 
      on social media. provide a suggested title, the start and end 
      timestamp, the transcript in that section, a summary/description 
      and several tags.

      Step 4: using the tool `create_mp4_clip`:
      after you have identified them, create an mp4 for each based on 
      the timestamp identified. use the original mp4 that was created 
      in the first step that is located at &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;mp4_path&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.
      each output file should use a kebab case mp4 filename
      generated from your suggested title. 
      save the new clips in &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;temp_dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.

      do not cleanup the temp directory at this time, even though 
      you have a tool that can perform this step. 

      Step 5: provide a summary of your work, 
      in the summary, output the following information for each clip:
        - Title
        - Start Time
        - End Time 
        - Transcript
        - Summary
        - Tags
        - File Location of Clip
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Running the Application
&lt;/h2&gt;

&lt;p&gt;When we run the application using &lt;code&gt;python agent.py&lt;/code&gt; we'll be prompted  to toggle verbose mode and provide the URL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Enable verbose output? &lt;span class="o"&gt;[&lt;/span&gt;y/N]: 
Enter M3U8 URL:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I decided to test the agent out with a &lt;a href="https://www.twitch.tv/videos/2427797850" rel="noopener noreferrer"&gt;recent live stream&lt;/a&gt; from my friend &lt;a href="https://rup12.net/" rel="noopener noreferrer"&gt;Darko Mesaroš&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'll help you generate small clips from the larger live stream following the steps you've outlined. Let's begin:

&lt;span class="gu"&gt;## Step 1: Download the HLS segments and convert them to an MP4 file&lt;/span&gt;

First, I'll convert the HLS manifest file to an MP4.
Tool #1: convert_m3u8_to_mp4
Saved stream to /[redacted]/0a464c96-e071-4300-83d7-a74eeee82e28.mp4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looks good - the MP4 file was generated as expected based on our prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Step 2: Transcribe the MP4 file&lt;/span&gt;

Now, I'll transcribe the downloaded MP4 file:
Tool #3: transcribe_mp4
Transcribing /[redacted]/0a464c96-e071-4300-83d7-a74eeee82e28.mp4 to 55c5f5f6-85ed-46d4-80f9-d455f6c51fcb.vtt
/[redacted]/transcribe.py:132: UserWarning: FP16 is not supported on CPU; using FP32 instead
  warnings.warn("FP16 is not supported on CPU; using FP32 instead")
Detected language: English
Transcribe complete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the transcript was generated! Now it should analyze the transcript to identify some clips.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Step 3: Analyze the transcript to identify potential clips&lt;/span&gt;

Based on the transcript, I'll identify several potential clips that could be good to share on social media. These will be moments that are engaging, informative, or entertaining.

&lt;span class="gu"&gt;### Clip 1: Stream Introduction and Technical Difficulties&lt;/span&gt;

&lt;span class="gs"&gt;**Title:**&lt;/span&gt; "Starting a Creative Coding Stream with Rust"

&lt;span class="gs"&gt;**Start Time:**&lt;/span&gt; 01:26.580
&lt;span class="gs"&gt;**End Time:**&lt;/span&gt; 02:12.220

&lt;span class="gs"&gt;**Transcript:**&lt;/span&gt;
"NOW! We're live. Yes. Okay. Now there's audio. There's audio. Okay. I was like, ah, um, so last moment I had to cut off my, um, what is it called? My, uh, my audio. Not only my whole Thunderbolt docked here because it just froze. So lost all my audio and everything else as I went along. So how do you, how do we, Jay? How are you doing my friend? It has been way too long. So I hope you're doing good. Um, welcome to the show. Welcome. Welcome. It has been actually, um, actually even a good old while for myself in the terms of live streaming. I think I have a stream for like 20 days. So incredibly happy to be back. So yeah, let's do some live streaming."

&lt;span class="gs"&gt;**Summary:**&lt;/span&gt; The streamer begins their first live stream in 20 days, explaining how they had technical difficulties with their audio setup when trying to start the stream. Despite the challenges, they're enthusiastic about being back and connecting with viewers.

&lt;span class="gs"&gt;**Tags:**&lt;/span&gt; #RustDevelopment #LiveCoding #StreamingTech #CreativeCoding #TechnicalDifficulties

&lt;span class="gu"&gt;### Clip 2: Introducing GGEZ - A Rust Game Engine&lt;/span&gt;

&lt;span class="gs"&gt;**Title:**&lt;/span&gt; "What is GGEZ? A Rust Game Engine for Creative Coding"

&lt;span class="gs"&gt;**Start Time:**&lt;/span&gt; 02:30.860
&lt;span class="gs"&gt;**End Time:**&lt;/span&gt; 03:29.820

&lt;span class="gs"&gt;**Transcript:**&lt;/span&gt;
"Um, okay. So the plan for today, my friends, is to do some stuff with, well, as always, Rust. So I'm going to do some creative coding today. Something with, um, um, Rust and a, and a framework I was using over the last few days called, GGE. It is a, I think they call themselves like a rust game engine thing. Like not terribly serious. It's not a full blown game engine. Um, it's a, it's a thing and it kind of does graphics. It is very similar to like P5JS, which is a very much, uh, an artistic type of coding framework, which I used in the past stream a long time ago. And, and of course, P5JS comes from processing. If anybody knows what processing is, um, so processing is an old framework. I think it uses its own bespoke language to do like graphics and like stuff. So, um, that's the whole plan today to do a little bit of that. Um, and have some fun."

&lt;span class="gs"&gt;**Summary:**&lt;/span&gt; The streamer introduces GGEZ, a Rust game engine framework they'll be using for creative coding. They explain how it's similar to P5JS and Processing, highlighting that it's not a full game engine but a tool for making graphics and creative coding projects.

&lt;span class="gs"&gt;**Tags:**&lt;/span&gt; #RustProgramming #GGEZ #GameDevelopment #CreativeCoding #GraphicsProgramming

&lt;span class="gu"&gt;### Clip 3: Drawing Fire - Creative Coding Goal&lt;/span&gt;

&lt;span class="gs"&gt;**Title:**&lt;/span&gt; "Let's Draw Fire with Rust: My Creative Coding Challenge"

&lt;span class="gs"&gt;**Start Time:**&lt;/span&gt; 06:03.980
&lt;span class="gs"&gt;**End Time:**&lt;/span&gt; 07:09.740

&lt;span class="gs"&gt;**Transcript:**&lt;/span&gt;
"So what, why would I like to do is I would love to do some creative coding, but in Rust. So, so that's the plan for today. Do a little bit of that. Um, there's no certain point to today. Like, in a sense, like we're not building up to, we're going to share. We're going to try to draw some pixels on the screen. We're not going to go too crazy and be like S.D.L type of approach. And I'm like, just super complicated. We're going to just do, um, squares and circles and whatnot. So, um, I want to try to draw flames. This is one of my, one of my tests when I draw this, these kinds of, when I work with these, a kind of artistic tools is like, can I draw fire, right? A C doughnut. Is, is a C doughnut, so. I know a C, oh, oh, wow. This would be a, I mean, probably at one point, I'm not as good as, as being able to do something like this. I know this whole thing code that actually is shaped like doughnut and it's just math. I'm not as good as math in this, but, um, yeah, yeah, yeah. We're going to try to draw some flames just simple as that. And I've done that in the past in Lua, but I want to try to do a Darwin rust. And I want to use this GGZ to set it up."

&lt;span class="gs"&gt;**Summary:**&lt;/span&gt; The streamer explains their goal for the creative coding session: to draw flames using Rust and GGEZ. They mention this as their go-to test when trying out new creative coding frameworks, comparing it to the famous "donut" code visualization but clarifying they'll stick to something simpler that they've previously implemented in Lua.

&lt;span class="gs"&gt;**Tags:**&lt;/span&gt; #RustCreativeCoding #DigitalArt #FlameSimulation #CreativeTech #VisualProgramming

&lt;span class="gu"&gt;### Clip 4: Setting Up GGEZ Fundamentals&lt;/span&gt;

&lt;span class="gs"&gt;**Title:**&lt;/span&gt; "How GGEZ Works: The Core Architecture of a Rust Game Engine"

&lt;span class="gs"&gt;**Start Time:**&lt;/span&gt; 12:46.140
&lt;span class="gs"&gt;**End Time:**&lt;/span&gt; 13:21.340

&lt;span class="gs"&gt;**Transcript:**&lt;/span&gt;
"So the way this works is that, um, your application has, um, basically a state, a main state where it kind of keeps stuff between frames. And, um, it has specific events on that state. That means as your application runs, there is a draw event, and there's an update event. And within those two events, you can do certain things. Now, of course, in the draw event, you draw on the screen, and the update event, you update whatever you're doing. And those are the two, two main important things we're going to be creating. And GGZ requires you to do it in a specific way."

&lt;span class="gs"&gt;**Summary:**&lt;/span&gt; The streamer explains the fundamental architecture of GGEZ, detailing how the game loop works with a main state that maintains data between frames, and the two key events - draw and update - that form the backbone of any GGEZ application.

&lt;span class="gs"&gt;**Tags:**&lt;/span&gt; #GameDevelopment #RustProgramming #GameLoop #GGEZ #GraphicsProgramming
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's a lot of output, but it's done exactly what we wanted. It analyzed the 20 minute stream that I provided and identified 4 clips that would be "engaging, informative, or entertaining". Based on the summary, I think it does a really good job at finding small clips of the larger stream that would be good for sharing on social media.&lt;/p&gt;

&lt;p&gt;The next step is to generate the &lt;code&gt;mp4&lt;/code&gt; files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Now I'll create MP4 clips for each of the identified segments:
Tool #6: create_mp4_clip
Tool #7: create_mp4_clip
Tool #8: create_mp4_clip
Tool #9: create_mp4_clip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the agent summarizes all of the work&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## Step 5: Summary of Work&lt;/span&gt;

&lt;span class="gu"&gt;### Clip 1: Starting a Creative Coding Stream with Rust&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Title:**&lt;/span&gt; Starting a Creative Coding Stream with Rust
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Start Time:**&lt;/span&gt; 00:01:26.580
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**End Time:**&lt;/span&gt; 00:02:12.220
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Transcript:**&lt;/span&gt; "NOW! We're live. Yes. Okay. Now there's audio. There's audio. Okay. I was like, ah, um, so last moment I had to cut off my, um, what is it called? My, uh, my audio. Not only my whole Thunderbolt docked here because it just froze. So lost all my audio and everything else as I went along. So how do you, how do we, Jay? How are you doing my friend? It has been way too long. So I hope you're doing good. Um, welcome to the show. Welcome. Welcome. It has been actually, um, actually even a good old while for myself in the terms of live streaming. I think I have a stream for like 20 days. So incredibly happy to be back. So yeah, let's do some live streaming."
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Summary:**&lt;/span&gt; The streamer begins their first live stream in 20 days, explaining how they had technical difficulties with their audio setup when trying to start the stream. Despite the challenges, they're enthusiastic about being back and connecting with viewers.
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**Tags:**&lt;/span&gt; #RustDevelopment #LiveCoding #StreamingTech #CreativeCoding #TechnicalDifficulties
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="gs"&gt;**File Location:**&lt;/span&gt; /[redacted]/starting-a-creative-coding-stream-with-rust.mp4

[trimmed for brevity]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here's an example of one of the clips that our agent generated for us from the longer live stream.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/h_rND7go2nU"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Enhancing the Agent
&lt;/h2&gt;

&lt;p&gt;If we wanted to, we could prompt the agent to upload the resulting &lt;code&gt;mp4&lt;/code&gt; files to an S3 bucket. If we did that, we might want to also create a tool that cleans up the temp files that were generated during the process. There's no limit to the amount of tools we can create to enhance the agent.&lt;/p&gt;

&lt;p&gt;What kind of enhancements would you want to see with this social clip generating agent? How are you using the Strands Agents framework? Let me know in the comments.&lt;/p&gt;

&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@sangharsh_l?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Sangharsh Lohakare&lt;/a&gt; on &lt;a href="https://unsplash.com/photos/a-close-up-of-a-blue-and-purple-structure-8o_LkMpo8ug?utm_content=creditCopyText&amp;amp;utm_medium=referral&amp;amp;utm_source=unsplash" rel="noopener noreferrer"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>livestreaming</category>
      <category>strandsagents</category>
    </item>
    <item>
      <title>MCP サーバーを活用して Amazon Q デベロッパーCLIの能力を強化しよう</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Fri, 02 May 2025 16:24:31 +0000</pubDate>
      <link>https://forem.com/aws/mcp-sabawohuo-yong-site-amazon-q-deberotupaclinoneng-li-woqiang-hua-siyou-1ka0</link>
      <guid>https://forem.com/aws/mcp-sabawohuo-yong-site-amazon-q-deberotupaclinoneng-li-woqiang-hua-siyou-1ka0</guid>
      <description>&lt;p&gt;少し前に、Model Context Protocol (MCP) が LLM アプリケーションに不足しているコンテキストを補完する方法について、&lt;a href="https://dev.to/aws/hype-or-hope-mcphapazurunopisuka-2kn4"&gt;4部構成のブログシリーズ&lt;/a&gt;で紹介しました。このシリーズでは、AWS リソース管理を支援する&lt;a href="https://dev.to/aws/aws-sabisutolian-xi-surutamenokasutamu-mcp-sabawozuo-cheng-suru-risosunoguan-li-50bj"&gt;カスタムMCPサーバー&lt;/a&gt;を構築しました。次に、&lt;a href="https://dev.to/aws/aws-sabisutolian-xi-surutamenokasutamu-mcp-sabawozuo-cheng-suru-rag-naretuzibesutoyuteiriteiwozhui-jia-suru-4a1a"&gt;RAG ナレッジベースとユーティリティ&lt;/a&gt;をサーバーに追加して、AWS サービスのドメイン固有知識を持たせることで、新しいアプリケーションの学習と開発を迅速に進められるようにしました。最後に、MCP サーバーが提供するツールを利用して Amazon Bedrock を通じて Claude 3.7 Sonnet を呼び出す&lt;a href="https://dev.to/aws/aws-nosabisutorisosuwoxue-xi-oyobiguan-li-surutamenokasutamu-mcp-kuraiantowozuo-cheng-suru-4dp6"&gt;カスタム MCP クライアント&lt;/a&gt;を作成しました。&lt;/p&gt;

&lt;p&gt;カスタム MCP クライアントの開発は MCP と Amazon Bedrock について理解を深めるための良い練習になりましたが、実際には私たちの MCP サーバーは MCP プロトコルに対応するどのクライアントとも連携できます。今回は、これまで作成したカスタム MCP サーバーを Amazon Q Developer CLI と連携させる方法をご紹介します。&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon Q Developer
&lt;/h2&gt;

&lt;p&gt;まだ &lt;a href="https://aws.amazon.com/jp/q/developer/?nc1=h_ls" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt; をお試しでない方は、ぜひインストールして使ってみることをお勧めします。優れた生成 AI を搭載したコーディング支援ツールとして、お気に入りの IDE と連携し、開発作業を強力にサポートします。また、&lt;code&gt;q chat&lt;/code&gt; コマンドで起動できるコマンドラインベースのアシスタント、Amazon Q Developer CLI も含まれています。執筆時点ではちょうど、この &lt;a href="https://aws.amazon.com/jp/blogs/devops/extend-the-amazon-q-developer-cli-with-mcp/" rel="noopener noreferrer"&gt;Amazon Q Developer CLI&lt;/a&gt; がカスタムMCPサーバーに対応するようになりました。この新機能の詳細は&lt;a href="https://aws.amazon.com/jp/blogs/news/extend-the-amazon-q-developer-cli-with-mcp/" rel="noopener noreferrer"&gt;発表ブログ&lt;/a&gt;をご覧いただくとして、ここでは Amazon IVS 用MCPサーバーを実際に追加して試してみましょう！&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon Q Developer CLI にカスタム MCP サーバーを追加する
&lt;/h2&gt;

&lt;p&gt;まず、&lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html?b=cli&amp;amp;p=overview&amp;amp;s=hero" rel="noopener noreferrer"&gt;Amazon Qをインストール&lt;/a&gt;し、AWS Builder ID で認証を行います。既にインストール済みの場合は、バージョンが &lt;code&gt;1.9.0&lt;/code&gt; 以上であることをご確認ください。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgdwix0m4lbrbax0s1ez.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgdwix0m4lbrbax0s1ez.png" alt="Amazon Q Release Notes" width="800" height="602"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;次に、&lt;code&gt;~/.aws/amazonq&lt;/code&gt; 配下にある &lt;code&gt;mcp.json&lt;/code&gt; というファイルで MCP サーバーを定義しましょう。このファイルに、Amazon Q が MCP サーバーと連携できるように、必要な情報を記述しなければなりません。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"amazon-ivs-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/projects/demos/ivs-mcp/amazon-ivs-mcp-server-demo/index.js"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;mcpServer&lt;/code&gt; オブジェクトの中に、&lt;code&gt;amazon-ivs-mcp-server&lt;/code&gt; というキーでオブジェクトを定義します。このキー名自体は好きに書いてもいいのですが、追加するサーバーの概要が伝わるものにすると良いでしょう。このキーに対してバリューとなるオブジェクトでは、実行コマンド (node) と、MCP サーバーに渡すを引数 (args) 配列を指定します。必要に応じて、env オブジェクトでは環境変数を定義することもできます。私の場合は、環境変数をセッションで設定しているので、このファイルでの明示的な定義は不要です。&lt;/p&gt;

&lt;p&gt;最後に、&lt;code&gt;q chat&lt;/code&gt; コマンドで Amazon Q Developer CLI を起動しましょう。このブログシリーズで作成した Amazon IVS MCP サーバーが正しく設定されていれば、起動時に利用可能なツール一覧に表示されます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;$ q chat
To learn more about MCP safety, see https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-mcp-security.html
⚠ amazon_ivs_mcp_server has the following warning:
The following tool names are changed:
&lt;span class="p"&gt; -&lt;/span&gt; amazon_ivs_mcp_server___get-logging-configuration -&amp;gt; amazon_ivs_mcp_server___getloggingconfiguration
&lt;span class="p"&gt; -&lt;/span&gt; amazon_ivs_mcp_server___get-playback-restriction-policy -&amp;gt; amazon_ivs_mcp_server___getplaybackrestrictionpolicy
...more warnings
✓ 1 of 1 mcp servers initialized
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;⚠️の警告は気にしないでください。これは、Amazon Q がツール名を命名規則に合わせて変更したことを通知しているだけです。重要なのは「✓ 1 of 1 mcp servers initialized」という部分です。MCP サーバーとAmazon Q Developer CLI の連携に成功しました！&lt;/p&gt;

&lt;h2&gt;
  
  
  ツールの管理
&lt;/h2&gt;

&lt;p&gt;ツールを管理するためのコマンドがいくつか用意されています。利用可能なコマンドの一覧は &lt;code&gt;/help&lt;/code&gt; コマンドで確認できます。以下はツール関連のコマンド一覧です：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;/tools        View and manage tools and permissions
  &lt;span class="nb"&gt;help        &lt;/span&gt;Show an explanation &lt;span class="k"&gt;for &lt;/span&gt;the trust &lt;span class="nb"&gt;command
  &lt;/span&gt;trust       Trust a specific tool or tools &lt;span class="k"&gt;for &lt;/span&gt;the session
  untrust     Revert a tool or tools to per-request confirmation
  trustall    Trust all tools &lt;span class="o"&gt;(&lt;/span&gt;equivalent to deprecated /acceptall&lt;span class="o"&gt;)&lt;/span&gt;
  reset       Reset all tools to default permission levels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ツールが「trust (信頼)」されていない場合、Amazon Q Developer CLI がそのツールを使用する必要があると判断したときに、「信頼」するかどうかの確認が表示されます。&lt;/p&gt;

&lt;h2&gt;
  
  
  Amazon Q Developer CLI から Amazon IVS MCP サーバーを利用する
&lt;/h2&gt;

&lt;p&gt;これで、Amazon IVS があるアカウントについて Amazon Q に質問できるようになりました。例えば：&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tell me about the last streaming session on demo-stage&lt;br&gt;
(demo-stageでの最後のストリーミングセッションについて教えて)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;と聞くと、次のような応答が返ってきます：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'll help you find information about the last streaming session on "demo-stage". To do this, I need to first check if this stage exists and then retrieve
its session information.

Let me first list the available IVS Real-Time stages to find the one named "demo-stage":

🛠️  Using tool: list-stages from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running list-stages with the param:
 ⋮  {
 ⋮    "arguments": {},
 ⋮    "name": "list-stages"
 ⋮  }
Allow this action? Use 't' to trust (always allow) this tool for the session. [y/n/t]:
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;list-stages&lt;/code&gt; ツールを信頼するために「t」と入力すると、ツールが実行されます。Amazon Q は質問に答えるために必要な情報を収集するまで、さまざまなツールを順次実行していきます。&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I found the "demo-stage" in the list. Now let me get the stage sessions for this stage to find the last streaming session:

🛠️  Using tool: list-stage-sessions from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running list-stage-sessions with the param:
 ⋮  {
 ⋮    "arguments": {
 ⋮      "arn": "arn:aws:ivs:us-east-1:[redacted]:stage/[redacted]"
 ⋮    },
 ⋮    "name": "list-stage-sessions"
 ⋮  }

🛠️  Using tool: get-stage-session from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running get-stage-session with the param:
 ⋮  {
 ⋮    "arguments": {
 ⋮      "sessionId": "st-[redacted]",
 ⋮      "stageArn": "arn:aws:ivs:us-east-1:[redacted]:stage/[redacted]"
 ⋮    },
 ⋮    "name": "get-stage-session"
 ⋮  }

🛠️  Using tool: list-participants from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running list-participants with the param:
 ⋮  {
 ⋮    "arguments": {
 ⋮      "arn": "arn:aws:ivs:us-east-1:[redacted]:stage/[redacted]",
 ⋮      "sessionId": "st-[redacted]"
 ⋮    },
 ⋮    "name": "list-participants"
 ⋮  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;最終的に、ステージセッションの概要が詳細に表示されます：&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;Based on the information I've gathered, here are the details about the last streaming session on "demo-stage":

&lt;span class="gu"&gt;## Last Streaming Session Details&lt;/span&gt;

• &lt;span class="gs"&gt;**Stage Name**&lt;/span&gt;: demo-stage
• &lt;span class="gs"&gt;**Session ID**&lt;/span&gt;: st-[redacted]
• &lt;span class="gs"&gt;**Start Time**&lt;/span&gt;: April 24, 2025 at 15:50:38 UTC
• &lt;span class="gs"&gt;**End Time**&lt;/span&gt;: April 24, 2025 at 16:55:06 UTC
• &lt;span class="gs"&gt;**Duration**&lt;/span&gt;: Approximately 1 hour and 5 minutes

&lt;span class="gu"&gt;### Participant Information:&lt;/span&gt;
• Total participants: 8
• 6 participants published content during the session
• 1 participant was identified with user ID "[redacted]"
• All participants are now disconnected

The session had multiple participants joining at different times, with the first participant joining at 15:50:37 UTC and the last one joining at 16:41:06 UTC. None of the participants had recording enabled during this session.
(このセッションには複数の参加者が異なる時間に参加し、最初の参加者はUTC 15:50:37に参加し、最後の参加者はUTC 16:41:06に参加しました。このセッション中、録画を有効にした参加者はいませんでした。)

This was the most recent session on the demo-stage, which ended about 6 days ago.
(これがdemo-stageでの最新のセッションで、約6日前に終了しました。)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Amazon Q Developer CLIを使った Amazon IVS の迅速なプロトタイピング
&lt;/h2&gt;

&lt;p&gt;前回の記事で作成したカスタム MCP クライアントと同様に、Amazon Q に簡単なプロトタイプアプリケーションを作成してもらうことができ、その際に Amazon IVS の専門知識とツールを活用できるようになります。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;using the latest version of the amazon ivs web broadcast sdk, create a simple prototype application to broadcast to an amazon ivs low-latency channel. within the UI, include input elements for ingest endpoint and stream key, and let the user choose their webcam and mic. refer to the latest documentation as necessary: &lt;a href="https://aws.github.io/amazon-ivs-web-broadcast/docs/low-latency-sdk-guides/introduction" rel="noopener noreferrer"&gt;https://aws.github.io/amazon-ivs-web-broadcast/docs/low-latency-sdk-guides/introduction&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(最新バージョンの Amazon IVS Web Broadcast SDK を使用して、Amazon IVS 低レイテンシーチャンネルに配信するシンプルなプロトタイプアプリケーションを作成してください。UI内には、インジェストエンドポイントとストリームキーの入力要素を含め、ユーザーがウェブカムとマイクを選択できるようにしてください。必要に応じて最新のドキュメントを参照してください：&lt;a href="https://aws.github.io/amazon-ivs-web-broadcast/docs/low-latency-sdk-guides/introduction" rel="noopener noreferrer"&gt;https://aws.github.io/amazon-ivs-web-broadcast/docs/low-latency-sdk-guides/introduction&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;このプロンプトに対して、Amazon IVS 低レイテンシースチャンネルへの配信が可能なシンプルな HTML アプリケーションが生成されます。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczjuezynvezhdtwdo8wy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fczjuezynvezhdtwdo8wy.png" alt="Low-latency Broadcast Prototype" width="800" height="922"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  まとめ
&lt;/h2&gt;

&lt;p&gt;本記事では、カスタム MCP サーバーを Amazon Q Developer CLI でしようできるように設定する方法を紹介しました。この機能は自作の MCP サーバーだけでなく、信頼できる既存の MCP サーバーを追加して Amazon Q の能力を拡張できるため、開発者にとって非常に強力なツールとなります。ぜひ、インストールして試してみてください！&lt;/p&gt;

&lt;p&gt;原文は&lt;a href="https://dev.to/aws/live-streaming-from-the-amazon-q-developer-cli-4phb"&gt;こちら&lt;/a&gt;です。&lt;br&gt;
本ブログは Amazon Web Services Japan Startup Solutions Architect の &lt;a href="https://x.com/prog893" rel="noopener noreferrer"&gt;Torgayev Tamirlan&lt;/a&gt; が翻訳しました。&lt;/p&gt;

</description>
      <category>aws</category>
      <category>mcp</category>
      <category>amazonivs</category>
    </item>
    <item>
      <title>What Would a Live Stream Look Like on a Commodore 64?</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Fri, 02 May 2025 15:56:43 +0000</pubDate>
      <link>https://forem.com/aws/what-would-a-live-stream-look-like-on-a-commodore-64-42p4</link>
      <guid>https://forem.com/aws/what-would-a-live-stream-look-like-on-a-commodore-64-42p4</guid>
      <description>&lt;p&gt;This morning my buddy &lt;a href="https://raymondcamden.com" rel="noopener noreferrer"&gt;Raymond Camden&lt;/a&gt; shared a fun little experiment. He has been playing around with a bit of "vibe coding", and decided to ask Claude to create a simple HTML file to take an image from the DOM and generate a "pixel art" version of that image. I was immediately curious if I could get &lt;a href="https://aws.amazon.com/q/developer" rel="noopener noreferrer"&gt;Amazon Q Developer&lt;/a&gt; to create a similar demo to pixelate a webcam in real-time. This led me down quite a fun path that ended up with an absolutely amazing solution. Let me tell you about it...&lt;/p&gt;

&lt;h2&gt;
  
  
  The Inspiration
&lt;/h2&gt;

&lt;p&gt;Here's Raymond's solution. A fun, but rather basic pixel art demo.&lt;/p&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/cfjedimaster/embed/OPPQedp?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I loved the effect, but thought it would be even better if applied to a webcam stream in real-time!&lt;/p&gt;

&lt;h2&gt;
  
  
  First Iteration - Pixelate a Webcam
&lt;/h2&gt;

&lt;p&gt;My first prompt simply asked Amazon Q to create an HTML file that uses the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Insertable_Streams_for_MediaStreamTrack_API" rel="noopener noreferrer"&gt;Insertable Streams for MediaStreamTrack API&lt;/a&gt; to pixelate a webcam. The result was pretty good!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd5myo36tzilkf2mwk79.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsd5myo36tzilkf2mwk79.png" alt="Pixelated Video"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It even added a parameter to specify the pixel size, so you could modify how much pixelization to add to the resulting video.&lt;/p&gt;

&lt;p&gt;Here's an 8 pixel version:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhysqj15oj67edg1du16.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzhysqj15oj67edg1du16.png" alt="Light Pixels"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And a 16 pixel version:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgteoh27admwlvk4tlwtm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgteoh27admwlvk4tlwtm.png" alt="Heavy Pixels"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Second Iteration - Commodore 64 Style
&lt;/h2&gt;

&lt;p&gt;The pixel effect was great, and it immediately made me think of the "old days" and the low-level graphics that I grew up with. I shared it with my buddy and well-known retro computing enthusiast &lt;a href="https://rup12.net" rel="noopener noreferrer"&gt;Darko Mesaroš&lt;/a&gt; and told him that it reminded me of what a live stream would look like on a Commodore 64. Being the expert that he was, he mentioned that the C64 pixels were double-wide, so I went back to Amazon Q and asked it to create a version that would reflect what a live stream would look like on a C64. It knew the proper pixel ratio, and even took the initiative to modify the pixel colors to the authenticate 16-color C64 palette! Glorious!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferdcapnomomvbru0i2wh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ferdcapnomomvbru0i2wh.png" alt="C64 Pixels!"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Iteration - The Full C64 Webcam Simulator
&lt;/h2&gt;

&lt;p&gt;Feeling quite happy with the results, I decided to prompt Amazon Q to  update the UI to a full C64 experience. My prompt was rather vague as I decided to see what it could come up with. The final result was so much more than I could have expected. Amazon Q even decided to include a full terminal with a C64 style blinking cursor. You can try it out for yourself below. Choose a camera, click 'START CAMERA', and then type &lt;code&gt;RUN&lt;/code&gt; at the C64 prompt!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Note&lt;/strong&gt;: CodePen can't get webcam permissions when running in embedded mode here on dev.to. Visit the pen in a new browser tab to&lt;a href="https://codepen.io/Todd-Sharp/full/KwwoPNw" rel="noopener noreferrer"&gt; try it out&lt;/a&gt;!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe height="600" src="https://codepen.io/Todd-Sharp/embed/KwwoPNw?height=600&amp;amp;default-tab=result&amp;amp;embed-version=2"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;This was a fun experiment to see what I could create with the Amazon Q Developer CLI, and it helped me learn more about using the Insertable Streams API to modify a video track at the frame level. Sometimes learning new things can be fun just by vibing with an assistant to build a silly, throwaway app like this. &lt;/p&gt;

&lt;p&gt;Did this post inspire you to create something similar? Post your ideas and screenshots in the comments below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>amazonivs</category>
      <category>retrocomputing</category>
      <category>commodore64</category>
    </item>
    <item>
      <title>Live Streaming From the Amazon Q Developer CLI</title>
      <dc:creator>Todd Sharp</dc:creator>
      <pubDate>Thu, 01 May 2025 15:51:08 +0000</pubDate>
      <link>https://forem.com/aws/live-streaming-from-the-amazon-q-developer-cli-4phb</link>
      <guid>https://forem.com/aws/live-streaming-from-the-amazon-q-developer-cli-4phb</guid>
      <description>&lt;p&gt;I've blogged recently about building your own Model Context Protocol (MCP) &lt;a href="https://dev.to/recursivecodes/series/31222"&gt;server and client&lt;/a&gt; to help manage your Amazon Interactive Video Service (Amazon IVS) resources (or, any AWS service!). We also saw how to &lt;a href="https://dev.to/aws/turbo-charge-the-amazon-q-developer-cli-with-mcp-servers-fl5"&gt;turbo charge&lt;/a&gt; 🏎️ the Amazon Q Developer CLI with the custom MCP server that we created in the previous series. Today I want to talk about another tool 🛠️ you can put in your live streaming developer toolbox 🧰. In this post we'll look at a way to actually start a live stream test broadcast directly from the Amazon Q Developer CLI.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wait, What 🤯?
&lt;/h2&gt;

&lt;p&gt;Yes, you read that correctly 😍! In this post we're going to add a way to start a test broadcast to an Amazon IVS real-time stage with Amazon Q. Since we've built a custom MCP server and given Amazon Q access to all those tools, it's much easier to get started prototyping live streaming applications. As your building new applications, you often need to test things out. What better way to test a live streaming application than to start a simple test stream?&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding a WebRTC Test Tool
&lt;/h2&gt;

&lt;p&gt;Broadcast to a WebRTC endpoint from the command line has always been notoriously difficult. There's a WHIP plugin for gStreamer, but you have to install Rust and compile it yourself. And after that pain, you actually have to construct a gStreamer pipeline which can be equally painful. Thankfully my co-worker Kostya Vasilyev - one of the amazing engineers on the Amazon IVS video team - has created an open-source project in his free time called &lt;code&gt;srtc&lt;/code&gt; (which stands for "simple" WebRTC [&lt;a href="https://github.com/kmansoft/srtc/" rel="noopener noreferrer"&gt;repo&lt;/a&gt;]). This amazing project includes a sample implementation that runs from the command line and can broadcast H264 video to a WHIP endpoint like the kind supported by Amazon IVS real-time stages. This means that we can compile the command line demo and use the resulting binary (which is less than 1MB!) to broadcast to a stage with a very simple command from the terminal. No convoluted and time consuming plugin compiling, no third-party dependencies (except OpenSSL, which you've most likely already got installed), no messy pipelines!&lt;/p&gt;

&lt;p&gt;To get started, visit the &lt;code&gt;srtc&lt;/code&gt; repo and follow the instructions in the &lt;code&gt;README.md&lt;/code&gt; to compile the &lt;code&gt;cmdline_demo&lt;/code&gt;. Rename the compiled binary to &lt;code&gt;srtc&lt;/code&gt; and make it executable with &lt;code&gt;chmod +x srtc&lt;/code&gt;. To avoid licensing and third-party dependencies, &lt;code&gt;srtc&lt;/code&gt; publishes raw H264, so you will have to convert your videos to raw H264, but this is easy to do with FFMPEG. Plus, you only have to do this once (and &lt;code&gt;srtc&lt;/code&gt; includes a sample &lt;code&gt;.h264&lt;/code&gt; that you can use. Here's how to convert an &lt;code&gt;.mp4&lt;/code&gt; to &lt;code&gt;.h264&lt;/code&gt; if you want to use your own video instead of the sample included in the repo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ffmpeg &lt;span class="nt"&gt;-i&lt;/span&gt; /path/to/a.mp4 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-c&lt;/span&gt;:v libx264 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-profile&lt;/span&gt;:v baseline &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-level&lt;/span&gt; 3.0 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-preset&lt;/span&gt; medium &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-an&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-f&lt;/span&gt; h264 &lt;span class="se"&gt;\&lt;/span&gt;
  test.h264
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Starting a Test Stream with Amazon Q 🎥
&lt;/h2&gt;

&lt;p&gt;Once you've got the compiled binary, you can run it directly from the command line. You don't really need Amazon Q for that, but it would require you to look up a stage ARN and create a participant token. Since the custom Amazon IVS MCP server can easily do that, we can just ask Amazon Q to run a test broadcast for us!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh2k4zhmz999qnnx0qwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyh2k4zhmz999qnnx0qwx.png" alt="Amazon Q Invoking srtc" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;💡&lt;strong&gt;Tip&lt;/strong&gt;: The Amazon Q Developer CLI already has access to the AWS CLI, so you don't &lt;em&gt;need&lt;/em&gt; to use the Amazon IVS MCP Server, but since it includes so many other helpful tools, why wouldn't you?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's prompt Amazon Q to start a test stream with &lt;code&gt;srtc&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;using the tool called 'srtc' located at /path/to/srtc start a test stream to Amazon IVS. run '--help' to determine the necessary parameters. generate a participant token for 'demo-stage' and use the whip endpoint &lt;a href="https://global.whip.live-video.net" rel="noopener noreferrer"&gt;https://global.whip.live-video.net&lt;/a&gt;. there is a file called 'test.h264' in that directory that you can use. use screen to run the command in the background.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'll help you start a test stream to Amazon IVS using the srtc tool with screen to run it in the background.

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command:
/path/to/srtc -h

Usage: /path/to/srtc [options]
Options:
  -f, --file &lt;span class="nt"&gt;&amp;lt;path&amp;gt;&lt;/span&gt;    Path to H.264 file (default: sintel.h264)
  -u, --url &lt;span class="nt"&gt;&amp;lt;url&amp;gt;&lt;/span&gt;      WHIP server URL (default: http://localhost:8080/whip)
  -t, --token &lt;span class="nt"&gt;&amp;lt;token&amp;gt;&lt;/span&gt;  WHIP authorization token
  -h, --help           Show this help message
 ⋮
 ● Completed in 0.26s

🛠️  Using tool: list-stages (trusted) from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running list-stages with the param:
 ⋮  {
 ⋮    "arguments": {},
 ⋮    "name": "list-stages"
 ⋮  }
 ⋮
 ● Completed in 0.204s

🛠️  Using tool: create-stage-participant-token (trusted) from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running create-stage-participant-token with the param:
 ⋮  {
 ⋮    "arguments": {
 ⋮      "capabilities": [
 ⋮        "PUBLISH",
 ⋮        "SUBSCRIBE"
 ⋮      ],
 ⋮      "duration": 60,
 ⋮      "stageArn": "arn:aws:ivs:us-east-1:[redacted]:stage/[redacted]",
 ⋮      "userId": "srtc-test-user"
 ⋮    },
 ⋮    "name": "create-stage-participant-token"
 ⋮  }
 ⋮
 ● Completed in 0.85s

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command:
cd /path/to/srtc &amp;amp;&amp;amp; ls -la test.h264

-rw-r--r--  1 shartodd  staff  16674002 Apr 30 14:33 test.h264

 ⋮
 ● Completed in 0.28s

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command: which screen

/usr/bin/screen

 ⋮
 ● Completed in 0.29s

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command:
cd /path/to/srtc &amp;amp;&amp;amp; screen -dmS srtc-test /path/to/srtc -f test.h264 -u https://global.whip.live-video.net -t eyJhbGciOiJ[redacted] &amp;amp;&amp;amp; echo "Started srtc in screen session named 'srtc-test'"

Started srtc in screen session named 'srtc-test'

 ⋮
 ● Completed in 0.235s

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command: screen -ls

There is a screen on:
&lt;span class="p"&gt;    78126.&lt;/span&gt;srtc-test (Detached)
1 Socket in /var/folders/gg/wkf00k7d60z26pxcv3s4_tlr0000gr/T/.screen.

 ⋮
 ● Completed in 0.20s

I've successfully started a test stream to Amazon IVS using the srtc tool in a screen session. Here's what I did:
&lt;span class="p"&gt;
1.&lt;/span&gt; First, I checked the help information for the srtc tool to understand the required parameters.
&lt;span class="p"&gt;2.&lt;/span&gt; I found the demo-stage in the list of available stages with ARN: arn:aws:ivs:us-east-1:[redacted]:stage/[redacted].
&lt;span class="p"&gt;3.&lt;/span&gt; I generated a participant token for the demo-stage with both PUBLISH and SUBSCRIBE capabilities, valid for 60 minutes.
&lt;span class="p"&gt;4.&lt;/span&gt; I verified that the test.h264 file exists in the specified directory.
&lt;span class="p"&gt;5.&lt;/span&gt; I confirmed that screen is available on your system.
&lt;span class="p"&gt;6.&lt;/span&gt; I started the srtc tool in a detached screen session named 'srtc-test' with the following parameters:
&lt;span class="p"&gt;
*&lt;/span&gt; File: test.h264
&lt;span class="p"&gt;*&lt;/span&gt; URL: https://global.whip.live-video.net
&lt;span class="p"&gt;*&lt;/span&gt; Token: The participant token generated for the demo-stage

The screen session is now running in the background with the name 'srtc-test' and session ID 78126. The srtc tool is streaming the test.h264 file to your
Amazon IVS Real-Time stage.

To manage this screen session later, you can use these commands:
• To list all screen sessions: screen -ls
• To reattach to the session: screen -r srtc-test
• To terminate the session: screen -X -S srtc-test quit

The stream will continue running in the background until you manually stop it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If we head over to the AWS Console and check the details for &lt;code&gt;demo-stage&lt;/code&gt;, we can confirm that the test video is being broadcasted!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyivd2299t0qsgrv74y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feyivd2299t0qsgrv74y8.png" alt="Test Subscribe" width="800" height="651"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To stop the broadcast we can manually run the commands that Amazon Q suggested, or ask it to run the command for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'll stop the test stream that's running in the screen session for you.

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command:
screen -X -S srtc-test quit
 ⋮
 ● Completed in 0.33s

🛠️  Using tool: execute_bash (trusted)
 ⋮
 ● I will run the following shell command: screen -ls
No Sockets found in /var/folders/gg/wkf00k7d60z26pxcv3s4_tlr0000gr/T/.screen.
 ⋮
 ● Completed in 0.28s

I've successfully stopped the test stream. The screen session named 'srtc-test' has been terminated, and the srtc tool is no longer streaming to Amazon IVS.

I verified that there are no more screen sessions running on your system. The test broadcast to the demo-stage has been completely stopped.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Adding Test Broadcast to a Custom MCP Server
&lt;/h2&gt;

&lt;p&gt;Again, this isn't 100% necessary, but I do like the fact that we can wrap the necessary logic in a few MCP server tools and let the server handle the token generation and starting the stream. Here is a diagram to help you visualize how this approach is different from the one we discussed above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs793m6igu6seqfsjcy99.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs793m6igu6seqfsjcy99.png" alt="srtc mcp overview" width="800" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Server Tools
&lt;/h2&gt;

&lt;p&gt;To broadcast a test stream from Amazon Q, we'll add two tools to the custom MCP server that we created in the previous series. We'll need to pass the path to &lt;code&gt;srtc&lt;/code&gt; into the server as an environment variable. This path can be set in your terminal, or hardcoded into the &lt;code&gt;mcp.json&lt;/code&gt; configuration (see my &lt;a href="https://dev.to/aws/turbo-charge-the-amazon-q-developer-cli-with-mcp-servers-fl5"&gt;last post&lt;/a&gt; for how to do that).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;testBroadcastPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TEST_BROADCAST_PATH&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;testBroadcastPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// broadcast-test-stream-to-stage&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;broadcast-test-stream-to-stage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Initiate a test stream broadcast to a stage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ARN of the stage to which this token is scoped.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
      &lt;span class="nx"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// get a participant token for the stage&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;test-user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;capabilities&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PUBLISH&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SUBSCRIBE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;720&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stageArn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;capabilities&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;duration&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;command&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CreateParticipantTokenCommand&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;ivsRealTimeClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;command&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;srtcProcess&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;srtcProcess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testBroadcastPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/srtc`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-f&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;testBroadcastPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/test.h264`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-u&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://global.whip.live-video.net&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-t&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;participantToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;
        &lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;detached&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;stdio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ignore&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="nx"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;srtcProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;srtcProcess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unref&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;started&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pid&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// stop-broadcast-test-stream-to-stage&lt;/span&gt;
  &lt;span class="nx"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;stop-broadcast-test-stream-to-stage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Stops the test stream broadcast to a stage&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;The pid of the test stream process.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;pid&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kill&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;-9&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;shell&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;stopped&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt;
      &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Live Streaming from the Amazon Q CLI!
&lt;/h2&gt;

&lt;p&gt;Now we can just ask Amazon Q to start a test stream on 'demo-stage'.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;lets broadcast a test stream to 'demo-stage'&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;I'll help you broadcast a test stream to a stage named 'demo-stage'. First, let's check if this stage exists in your AWS IVS account.&lt;span class="sb"&gt;


&lt;/span&gt;🛠️  Using tool: list-stages from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running list-stages with the param:
 ⋮  {
 ⋮    "arguments": {},
 ⋮    "name": "list-stages"
 ⋮  }
 ⋮
 ● Completed in 0.248s&lt;span class="sb"&gt;


&lt;/span&gt;I found a stage named 'demo-stage' in your AWS IVS account. Let's broadcast a test stream to it.

🛠️  Using tool: broadcast-test-stream-to-stage from mcp server amazon_ivs_mcp_server
 ⋮
 ● Running broadcast-test-stream-to-stage with the param:
 ⋮  {
 ⋮    "arguments": {
 ⋮      "stageArn": "arn:aws:ivs:us-east-1:[redacated]:stage/[redacated]"
 ⋮    },
 ⋮    "name": "broadcast-test-stream-to-stage"
 ⋮  }
 ⋮
 ● Completed in 0.117s

Great! I've successfully started broadcasting a test stream to the 'demo-stage'. Here's what I did:
&lt;span class="p"&gt;
1.&lt;/span&gt; Found the stage named 'demo-stage' in your AWS IVS account
&lt;span class="p"&gt;2.&lt;/span&gt; Started broadcasting a test stream to the stage

The test stream is now running with process ID 55960.

To stop the test stream when you're done, let me know and I can help you terminate it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In this post, we examined several ways to start a broadcast on an Amazon IVS real-time stage to help you test your live streaming applications. &lt;/p&gt;

&lt;p&gt;Have you embraced generative-AI tools in your development workflow? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>aws</category>
      <category>mcp</category>
      <category>amazonivs</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
