<?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: Suman Kumar</title>
    <description>The latest articles on Forem by Suman Kumar (@sumankalia).</description>
    <link>https://forem.com/sumankalia</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%2F1019495%2Ff74431d4-6f36-428c-9097-a71e7d03c437.jpg</url>
      <title>Forem: Suman Kumar</title>
      <link>https://forem.com/sumankalia</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sumankalia"/>
    <language>en</language>
    <item>
      <title>[Boost]</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Tue, 27 May 2025 03:10:33 +0000</pubDate>
      <link>https://forem.com/sumankalia/-5b3n</link>
      <guid>https://forem.com/sumankalia/-5b3n</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-story__hidden-navigation-link"&gt;🧠 NewsPulse AI – Real-Time News Analysis with LLMs &amp;amp; Web Scraping via Bright Data&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sumankalia" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1019495%2Ff74431d4-6f36-428c-9097-a71e7d03c437.jpg" alt="sumankalia profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sumankalia" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Suman Kumar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Suman Kumar
                
              
              &lt;div id="story-author-preview-content-2525926" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sumankalia" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1019495%2Ff74431d4-6f36-428c-9097-a71e7d03c437.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Suman Kumar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 25 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" id="article-link-2525926"&gt;
          🧠 NewsPulse AI – Real-Time News Analysis with LLMs &amp;amp; Web Scraping via Bright Data
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/brightdatachallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;brightdatachallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdata"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdata&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;34&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              14&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>[Boost]</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Tue, 27 May 2025 03:10:33 +0000</pubDate>
      <link>https://forem.com/sumankalia/-1ip1</link>
      <guid>https://forem.com/sumankalia/-1ip1</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-story__hidden-navigation-link"&gt;🧠 NewsPulse AI – Real-Time News Analysis with LLMs &amp;amp; Web Scraping via Bright Data&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/sumankalia" class="crayons-avatar  crayons-avatar--l  "&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%2Fuser%2Fprofile_image%2F1019495%2Ff74431d4-6f36-428c-9097-a71e7d03c437.jpg" alt="sumankalia profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/sumankalia" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Suman Kumar
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Suman Kumar
                
              
              &lt;div id="story-author-preview-content-2525926" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/sumankalia" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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%2Fuser%2Fprofile_image%2F1019495%2Ff74431d4-6f36-428c-9097-a71e7d03c437.jpg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Suman Kumar&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 25 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" id="article-link-2525926"&gt;
          🧠 NewsPulse AI – Real-Time News Analysis with LLMs &amp;amp; Web Scraping via Bright Data
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/devchallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;devchallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/brightdatachallenge"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;brightdatachallenge&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdata"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdata&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;34&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              14&lt;span class="hidden s:inline"&gt; comments&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            7 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>🧠 NewsPulse AI – Real-Time News Analysis with LLMs &amp; Web Scraping via Bright Data</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Sun, 25 May 2025 18:17:42 +0000</pubDate>
      <link>https://forem.com/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep</link>
      <guid>https://forem.com/sumankalia/newspulseai-real-time-news-intelligence-powered-by-web-data-agents-2bep</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-2025-05-07"&gt;Bright Data AI Web Access Hackathon&lt;/a&gt;&lt;/em&gt;&lt;br&gt;
We built NewsPulse AI to explore a simple but powerful question:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;"What if you could instantly see how different media outlets spin the same story?"&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In a world flooded with headlines, bias, and misinformation, NewsPulse AI acts like an AI-powered research assistant. You ask a question, and it fetches, scrapes, analyzes, and visualizes fresh news articles in real-time—just like a human researcher, but supercharged.&lt;/p&gt;

&lt;p&gt;🚀 What It Does&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;🔍 Enter any news-related query (e.g. farmers protest, AI in education, etc.)&lt;/li&gt;
&lt;li&gt;🌐 NewsPulse fetches real-time articles via Bright Data’s MCP scraping infrastructure&lt;/li&gt;
&lt;li&gt;🧠 LangChain &amp;amp; GPT-3.5 process each article for:&lt;/li&gt;
&lt;li&gt;Sentiment (positive/neutral/negative)&lt;/li&gt;
&lt;li&gt;Bias&lt;/li&gt;
&lt;li&gt;Political lean&lt;/li&gt;
&lt;li&gt;Toxicity and propaganda presence&lt;/li&gt;
&lt;li&gt;📊 Get aggregate insights and transparent logs instantly&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;NewsPulse AI is an intelligent real-time news analysis engine that allows users to query any news-related topic and instantly receive a stream of analyzed articles. It mimics how a human researcher might discover, navigate, extract, and interact with web content—but does it entirely autonomously.&lt;/p&gt;

&lt;p&gt;The project solves the problem of understanding media bias, misinformation, and sentiment across different news sources in real-time. Whether a user wants to explore how different platforms cover a political event, assess the emotional tone of news about a public figure, or analyze the presence of propaganda or toxicity in media, NewsPulse AI provides deep insights in seconds.&lt;/p&gt;
&lt;h3&gt;
  
  
  🔧 Deep Integration with FastMCP via STDIO
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;🔥 One of the key differentiators of our solution is that we have directly integrated Bright Data’s official MCP source code with our Node.js backend using FastMCP over standard input/output (STDIO).&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Running the FastMCP server inside our Express (Node.js) environment&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Communicating with it through STDIO (stdin/stdout)&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Launching and managing scraping methods programmatically from Node.js&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This level of integration is not just plug-and-play—it required fine-tuning STDIO communication and handling input/output streams carefully. But it makes our backend much more flexible and efficient, enabling real-time task execution without relying on HTTP or RPC overhead.&lt;/p&gt;

&lt;p&gt;It also aligns perfectly with Bright Data’s vision for real-time AI agents interacting with the open web, giving us full control over tool orchestration, logging, and performance.&lt;/p&gt;
&lt;h3&gt;
  
  
  🛠️ Tech Stack &amp;amp; Architecture
&lt;/h3&gt;

&lt;p&gt;Our project is built entirely on modern, open-source tools optimized for real-time web data extraction and analysis:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt;: React + Vite&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Node.js + Express&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Orchestration&lt;/strong&gt;: LangChain + OpenAI GPT-3.5 Turbo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scraping Infrastructure&lt;/strong&gt;: Bright Data MCP (FastMCP Server)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication&lt;/strong&gt;: REST APIs + WebSocket (for real-time logs &amp;amp; results)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Hosted on an EC2 instance with persistent STDIO-based communication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;⚡ No Database Used:&lt;/strong&gt;&lt;br&gt;
We do &lt;strong&gt;not persist any data&lt;/strong&gt;. Everything — from scraping to analysis — happens &lt;strong&gt;live from the open web&lt;/strong&gt;. This ensures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Real-time results&lt;/strong&gt; for every query&lt;/li&gt;
&lt;li&gt;No stale or outdated information&lt;/li&gt;
&lt;li&gt;Transparent validation that scraping works on-demand&lt;/li&gt;
&lt;li&gt;Compliance with the &lt;strong&gt;hackathon’s goal of showcasing live data access&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This stateless, no-DB approach proves the reliability of Bright Data’s infrastructure in powering real-time AI agents without any dependency on pre-stored content.&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%2Fdv8n0vubam5yits71r9i.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%2Fdv8n0vubam5yits71r9i.png" alt="Project artchitecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Video Demo&lt;br&gt;
  &lt;/p&gt;
&lt;div&gt;
    &lt;iframe src="https://www.youtube.com/embed/WHBH2baw1YQ"&gt;
    &lt;/iframe&gt;
  &lt;/div&gt;


&lt;p&gt;&lt;strong&gt;📁 GitHub Repo:&lt;/strong&gt; &lt;a href="https://github.com/sumankalia/news-pulse-ai" rel="noopener noreferrer"&gt;https://github.com/sumankalia/news-pulse-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;🌐 Live Site: &lt;br&gt;
&lt;strong&gt;Frontend:&lt;/strong&gt; &lt;a href="http://ec2-16-170-239-65.eu-north-1.compute.amazonaws.com:5173/" rel="noopener noreferrer"&gt;http://ec2-16-170-239-65.eu-north-1.compute.amazonaws.com:5173/&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; &lt;a href="http://ec2-16-170-239-65.eu-north-1.compute.amazonaws.com:4002/api/articles/ping" rel="noopener noreferrer"&gt;http://ec2-16-170-239-65.eu-north-1.compute.amazonaws.com:4002/api/articles/ping&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📸 Screenshots:&lt;/p&gt;

&lt;p&gt;🔍 &lt;strong&gt;Search Input Interface –&lt;/strong&gt; Users can enter any news-related query, such as “farmers protest” or “AI in education,” to fetch real-time news articles and analyze them instantly.&lt;br&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%2Fsvxl64llmunabnldxr7q.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%2Fsvxl64llmunabnldxr7q.png" alt="Search field for user query"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;⚙️ &lt;strong&gt;Real-Time Query Processing –&lt;/strong&gt; The system uses Bright Data’s MCP server to fetch and analyze fresh articles from Indian news sources. Logs show live scraping and analysis updates for transparency and debugging.&lt;br&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%2Fuh3x9hgye7cd8u4ptbeb.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%2Fuh3x9hgye7cd8u4ptbeb.png" alt="Analyzing the query and showing logs"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📰 &lt;strong&gt;Scraped Article Snapshot –&lt;/strong&gt; A detailed preview of an individual article showing title, source, timestamp, and extracted summary. Each result is processed for bias, sentiment, and lean.&lt;br&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%2Fhchek7dvsqhb48fqni20.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%2Fhchek7dvsqhb48fqni20.png" alt="One scraped result from the list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📊 &lt;strong&gt;Sentiment, Bias, and Political Lean Breakdown –&lt;/strong&gt; Each article undergoes NLP-based analysis to categorize tone (positive/neutral/negative), detect media bias, and predict political inclination.&lt;br&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%2Fdfx3rwwcf73g1e2xr3ep.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%2Fdfx3rwwcf73g1e2xr3ep.png" alt="All the sentiment analysis details"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;📈 &lt;strong&gt;Aggregate Insights Dashboard –&lt;/strong&gt; Provides a summary of all fetched articles, highlighting sentiment distribution, bias frequency, and lean trends to help users quickly assess media coverage patterns.&lt;br&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%2Fgshzyp2j6t3i3n2sankc.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%2Fgshzyp2j6t3i3n2sankc.png" alt="Overall analysis of all the articles"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  How I Used Bright Data's Infrastructure
&lt;/h2&gt;

&lt;p&gt;This project is powered by &lt;strong&gt;Bright Data’s MCP infrastructure&lt;/strong&gt;, particularly the &lt;strong&gt;FastMCP server&lt;/strong&gt;, which enables our AI agent to simulate human browsing behavior and extract structured information in real time. Here’s how the four key actions were implemented:&lt;/p&gt;
&lt;h3&gt;
  
  
  1. Discover
&lt;/h3&gt;

&lt;p&gt;We use &lt;strong&gt;LangChain&lt;/strong&gt; with a custom PromptTemplate to dynamically route user queries to one of four scraping methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;scrape_as_article&lt;/code&gt;: Direct article URLs&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;scrape_a_homepage&lt;/code&gt;: Homepage or latest headline queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;search_via_google&lt;/code&gt;: Informational and broad-topic queries&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;search_via_bing&lt;/code&gt;: Dynamic, JS-heavy search result pages
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;switch (result.method) {
      case "scrape_as_article":
        data = await runToolCall("scrape_as_article", { url: query });
        break;
      case "scrape_a_homepage":
        data = await runToolCall("scrape_a_homepage", {
          url: result?.homepageUrl,
        });
        break;
      case "search_via_google":
        data = await runToolCall("search_via_google", { query });
        break;
      case "search_via_bing":
        processedResults = await searchViaBing({
          query,
          userId,
        });
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;LangChain decides the optimal route based on user intent, and our backend follows through using the selected method.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. Access
&lt;/h3&gt;

&lt;p&gt;We leverage Bright Data’s FastMCP to access dynamic and protected web pages like news homepages or search results.&lt;/p&gt;

&lt;p&gt;Here’s what happens:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First, we load the target page (e.g., a news homepage or Bing/Google search results).&lt;/li&gt;
&lt;li&gt;We then &lt;strong&gt;scrape all the article&lt;/strong&gt; links visible on that page.&lt;/li&gt;
&lt;li&gt;Next, we go &lt;strong&gt;article-by-article&lt;/strong&gt;, scraping each one individually for full content and metadata.&lt;/li&gt;
&lt;li&gt;This method helps us analyze &lt;strong&gt;multiple perspectives&lt;/strong&gt; from a single page, all without hitting stale data or relying on pre-saved content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This smart multi-link scraping approach powers our real-time insights across 50+ articles per query.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Step 1: Navigate to the target page (homepage or search results)
await runToolCall("scraping_browser_navigate", {
  url: "https://www.newswebsite.com/",
});

// Step 2: Wait for articles to load on the page
await runToolCall("scraping_browser_wait_for", {
  selector: "article a[href]",
  timeout: 10000,
});

// Step 3: Extract all article links
const linksResult = await runToolCall("scraping_browser_links", {});

// Step 4: Iterate through each link and trigger detailed article scraping
for (const link of linksResult.links) {
  await runToolCall("scrape_as_article", { url: link });
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Extract
&lt;/h3&gt;

&lt;p&gt;We extract detailed article metadata, including:&lt;br&gt;
    • title, content, url, published date, author, source, and image&lt;/p&gt;

&lt;p&gt;Bright Data supports extraction via:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ &lt;strong&gt;rawHtml&lt;/strong&gt; – full HTML of the scraped content&lt;/li&gt;
&lt;li&gt;✅ &lt;strong&gt;markdown&lt;/strong&gt; – clean, AI-friendly summary format
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server.addTool({
  name: "scrape_a_homepage",
  description:
    "Scrape a single webpage URL with advanced options for " +
    "content extraction and get back the results in MarkDown language. " +
    "This tool can unlock any webpage even if it uses bot detection or " +
    "CAPTCHA.",
  parameters: z.object({ url: z.string().url() }),
  execute: tool_fn("scrape_a_homepage", async ({ url }) =&amp;gt; {
    let response = await axios({
      url: "https://api.brightdata.com/request",
      method: "POST",
      data: {
        url,
        zone: unlocker_zone,
        format: "raw",
        data_format: "markdown",
      },
      headers: api_headers(),
      responseType: "text",
    });
    return response.data;
  }),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;We utilized a combination of &lt;strong&gt;custom and prebuilt functions&lt;/strong&gt; to clean the raw data and extract the necessary information for analysis.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Interact
&lt;/h3&gt;

&lt;p&gt;This is where &lt;strong&gt;Bright Data’s full capabilities come to life&lt;/strong&gt;. In the search_via_bing method, we simulate a full browser interaction flow using MCP tools:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Navigate to Bing.com&lt;/li&gt;
&lt;li&gt;Wait for the page to load&lt;/li&gt;
&lt;li&gt;Clear the input field&lt;/li&gt;
&lt;li&gt;Enter the search text&lt;/li&gt;
&lt;li&gt;Press Enter&lt;/li&gt;
&lt;li&gt;Wait ~5 seconds&lt;/li&gt;
&lt;li&gt;Wait for a result-related HTML selector to appear&lt;/li&gt;
&lt;li&gt;Scrape result links using scraping_browser_links&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This closely &lt;strong&gt;mimics human behavior&lt;/strong&gt;, allowing us to pull data from otherwise inaccessible or JS-heavy websites.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const url = "https://www.bing.com/news";
  const searchSelector = "input#sb_form_q";
  const searchText = query;
  const processedResults = [];


    // Navigate to the webpage using scraping_browser_navigate
    await runToolCall("scraping_browser_navigate", {
      url,
    });

    await runToolCall("scraping_browser_wait_for", {
      selector: searchSelector,
      timeout: 10000,
    });

    // Clear the search field first using scraping_browser_type
    await runToolCall("scraping_browser_type", {
      selector: searchSelector,
      text: "",
      submit: false,
    });
    // Type the search text using scraping_browser_type
    await runToolCall("scraping_browser_type", {
      selector: searchSelector,
      text: searchText,
      submit: false,
    });
    // Press Enter to submit the search
    await runToolCall("scraping_browser_press", {
      key: "Enter",
    });
    // Wait for the search results to load
    // First wait for network to be idle
    await new Promise((resolve) =&amp;gt; setTimeout(resolve, 3000));

    // Wait for search results container
    await runToolCall("scraping_browser_wait_for", {
      selector: 'a.linkBtn[aria-label="Best match"]',
      timeout: 50000,
    });
    // Additional wait for search results to be fully loaded
    await new Promise((resolve) =&amp;gt; setTimeout(resolve, 2000));
    // Wait for article links to be present
    await runToolCall("scraping_browser_wait_for", {
      selector: "article a[href*='/articles/']",
      timeout: 5000,
    });
    // Get all links from the page using scraping_browser_links
    const linksResult = await runToolCall("scraping_browser_links", {});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;Before integrating Bright Data’s MCP server, our initial architecture relied on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sequential proxy rotation&lt;/strong&gt; using Bright Data’s Residential, Web Unlocker, and Mobile proxies&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Headless browser automation via Puppeteer&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Custom code for region-based rotation and JavaScript-rendered scraping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;While functional, this method had &lt;strong&gt;significant drawbacks&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High latency per article (6–12 seconds)&lt;/li&gt;
&lt;li&gt;Increased code complexity and maintenance overhead&lt;/li&gt;
&lt;li&gt;Failures on JS-heavy or protected pages&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  🚀 Transition to Bright Data MCP (FastMCP Server)
&lt;/h3&gt;

&lt;p&gt;By switching to the Fast MCP server, we achieved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱ &lt;strong&gt;~80% reduction in scraping latency&lt;/strong&gt; per article&lt;/li&gt;
&lt;li&gt;💡 Seamless access to protected and JavaScript-heavy sites with zero-code browser interaction&lt;/li&gt;
&lt;li&gt;⚙️ Lightweight, declarative scraping powered by &lt;strong&gt;STDIO&lt;/strong&gt; communication between our Node.js backend and MCP server&lt;/li&gt;
&lt;li&gt;📦 Simplified architecture (less boilerplate, no Puppeteer or manual proxy handling)&lt;/li&gt;
&lt;li&gt;✅ Greater reliability across countries and site types — with support for region-specific scraping&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;We are now scraping 50+ articles across multiple countries in real time without bottlenecks or rate-limiting issues.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can even compare our old Puppeteer-based proxy project here:&lt;br&gt;
👉 Legacy Puppeteer Proxy Scraper &lt;a href="https://inspiring-taffy-5808f5.netlify.app/" rel="noopener noreferrer"&gt;https://inspiring-taffy-5808f5.netlify.app/&lt;/a&gt;&lt;br&gt;
And see how Bright Data MCP gave us a 10x better development and performance experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Improvements
&lt;/h2&gt;

&lt;p&gt;We built NewsPulse AI to meet hackathon goals with a real-time, stateless architecture. For the next phase, we plan to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Integrate a Vector DB&lt;/strong&gt; (like Pinecone or Qdrant) to enable semantic search and avoid redundant scraping.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add a Scalable Job Queue&lt;/strong&gt; for handling spikes using tools like BullMQ or Redis.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Implement Auth &amp;amp; API Keys&lt;/strong&gt; to support user-specific usage and rate-limiting.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Secure Secrets Properly&lt;/strong&gt;, moving all credentials to secret managers for a real deployment.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Improve UX&lt;/strong&gt; with features like sentiment trend visualizations, historical comparisons, and saved analyses.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These updates will make the platform more robust, scalable, and production-ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;NewsPulse AI showcases how powerful AI agents become when paired with open, real-time, structured web data. We didn’t just build a tool—we built a thinking system that mimics human research patterns at internet speed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Lovingly crafted by Suman and his wife Sarita. 💫&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;🙌 Shoutout&lt;br&gt;
Big thanks to the team at Bright Data! Loved integrating your MCP platform.&lt;/p&gt;

&lt;p&gt;If you're reading this and found Bright Data useful, give their repo some love:&lt;br&gt;
🌟 &lt;a href="https://github.com/luminati-io/brightdata-mcp" rel="noopener noreferrer"&gt;https://github.com/luminati-io/brightdata-mcp&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>Smart Doctor: AI-Powered Medical Assistant with Human-in-the-Loop Access Control using Permit.io- Permissions Redefined</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Sun, 04 May 2025 15:51:00 +0000</pubDate>
      <link>https://forem.com/sumankalia/smart-doctor-ai-powered-medical-assistant-with-human-in-the-loop-access-control-using-permitio--1peh</link>
      <guid>https://forem.com/sumankalia/smart-doctor-ai-powered-medical-assistant-with-human-in-the-loop-access-control-using-permitio--1peh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/permit_io"&gt;Permit.io Authorization Challenge&lt;/a&gt;: AI Access Control&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Smart Doctor&lt;/strong&gt; is an AI-powered medical assistant that allows patients to enter symptoms and receive instant diagnosis and treatment suggestions using &lt;strong&gt;OpenAI (ChatGPT)&lt;/strong&gt;. But we didn’t stop there — this app is designed to mirror real-world workflows with built-in &lt;strong&gt;authorization controls&lt;/strong&gt;, ensuring AI suggestions are always reviewed by licensed doctors before reaching the patient.&lt;/p&gt;

&lt;p&gt;It’s more than a demo — it’s a realistic, scalable solution that demonstrates responsible AI integration with &lt;strong&gt;fine-grained, role-based and attribute-based access control (ABAC)&lt;/strong&gt; using &lt;strong&gt;Permit.io&lt;/strong&gt;.&lt;/p&gt;

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

&lt;p&gt;🧪 Live Frontend: &lt;a href="https://rainbow-parfait-febebb.netlify.app/auth/login" rel="noopener noreferrer"&gt;https://rainbow-parfait-febebb.netlify.app/auth/login&lt;/a&gt;&lt;br&gt;
⚙️ Live Backend API: &lt;a href="https://smart-doctor-backend.onrender.com/api/" rel="noopener noreferrer"&gt;https://smart-doctor-backend.onrender.com/api/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test Credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Role        Username       Password
Admin       admin      2025DEVChallenge
Doctor      doctor     2025DEVChallenge
Patient     patient    2025DEVChallenge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Project Repo
&lt;/h2&gt;

&lt;p&gt;🔗 GitHub: &lt;a href="https://github.com/sumankalia/smart-doctor" rel="noopener noreferrer"&gt;https://github.com/sumankalia/smart-doctor&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🛡️ Feature Access Table
&lt;/h1&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%2F74t6yczaisas23dx67mv.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%2F74t6yczaisas23dx67mv.png" alt="Feature Access control" width="800" height="579"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  🛡️ Authorization for AI Applications with Permit.io
&lt;/h1&gt;

&lt;p&gt;In Smart Doctor, authorization is more than just frontend role checks — it's enforced through centralized policies with Permit.io, tightly integrated into our backend system. Here's how we leveraged Permit to secure our AI-driven healthcare platform:&lt;/p&gt;

&lt;h3&gt;
  
  
  ✅ Real-Time User Sync with Permit
&lt;/h3&gt;

&lt;p&gt;As soon as a user is created in MongoDB, we sync them in real-time with Permit using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await permitInstance.api.syncUser({
  key: user._id.toString(),
  first_name: user.firstName,
  last_name: user.lastName || ".",
  email: user.email,
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures every user exists in the Permit dashboard and can be managed through policies.&lt;/p&gt;

&lt;p&gt;🔐 Automatic Role Assignment&lt;br&gt;
After syncing, we assign roles dynamically via:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;await permitInstance.api.assignRole({
  role: roleMap.Doctor, // or Admin, Patient
  tenant: "default",
  user: user._id.toString(),
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This lets us externalize access logic entirely — users can only see or perform actions based on their role and the resource state (e.g., AI diagnosis approved or not).&lt;/p&gt;

&lt;h2&gt;
  
  
  Walkthrough
&lt;/h2&gt;

&lt;p&gt;Here’s a step-by-step walkthrough of how Smart Doctor works, showcasing the full user flow and fine-grained access control in action.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Patient: Submit a New Case&lt;/strong&gt;&lt;br&gt;
A logged-in patient starts by submitting symptoms using a simple form.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The frontend sends this data to the backend API.&lt;/li&gt;
&lt;li&gt;The backend calls the OpenAI API to generate a diagnosis and treatment plan.&lt;/li&gt;
&lt;li&gt;The case is then assigned to the doctor with the lowest workload.&lt;/li&gt;
&lt;/ul&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%2F9nxxtqxfhyygss42fenx.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%2F9nxxtqxfhyygss42fenx.png" alt="Patient Preview" width="800" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. AI: Generate Diagnosis + Treatment&lt;/strong&gt;&lt;br&gt;
Using the submitted symptoms, the backend triggers a call to OpenAI (ChatGPT model) and returns a recommended diagnosis and treatment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const userQuery = `
      Symptoms: ${symptoms}
      Case Description: ${caseDescription}
      Additional Information: ${additionalInfo}

      Please provide your response in two sections:
      1. Possible Diagnosis
      2. Suggested Treatment Plan
 `;


const chatCompletion = await openai.chat.completions.create({
      model: process.env.OPENAI_MODEL,
      messages: [
        {
          role: "system",
          content: userQuery,
        },
        {
          role: "user",
          content: `Please analyze the following medical case and 
         provide a professional medical assessment:\n\n${userQuery}`,
        },
      ],
      temperature: 0.7, 
      max_tokens: 1000,
    });

const aiResponse = chatCompletion.choices[0].message.content;

&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%2F3fm7zc3y9lxo341pxbmt.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%2F3fm7zc3y9lxo341pxbmt.png" alt="AI Response" width="800" height="330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Doctor: Review + Approve/Override&lt;/strong&gt;&lt;br&gt;
Doctors are notified of new cases assigned to them. They can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View AI-generated results&lt;/li&gt;
&lt;li&gt;Approve the diagnosis/treatment&lt;/li&gt;
&lt;li&gt;Override and edit them&lt;/li&gt;
&lt;li&gt;Add additional notes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Permit.io enforces that only doctors assigned to the case have edit permissions on that record.&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%2Fuj0n0epzf81bsu9t8767.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%2Fuj0n0epzf81bsu9t8767.png" alt="Dashboard" width="800" height="433"&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%2Fv3270zpv7ubwwmp5k4pd.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%2Fv3270zpv7ubwwmp5k4pd.png" alt="AI suggested Dignosis" width="800" height="636"&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%2Fan0wngu35atzkl18z0qt.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%2Fan0wngu35atzkl18z0qt.png" alt="AI suggested Treatment" width="800" height="662"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Admin: Manage Ecosystem (Without Overreach)&lt;/strong&gt;&lt;br&gt;
Admins can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View all users and cases&lt;/li&gt;
&lt;li&gt;Reassign doctors&lt;/li&gt;
&lt;li&gt;Update case status&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;BUT: Admins cannot modify diagnosis or treatment fields. This safeguard is enforced using ABAC policies in Permit.io.&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%2Fi6mi01hlq2xifv45qkwk.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%2Fi6mi01hlq2xifv45qkwk.png" alt="Admin dashboard" width="800" height="433"&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%2Fjy2aqqyl98gdxxk8fjld.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%2Fjy2aqqyl98gdxxk8fjld.png" alt="Admin medical case access" width="800" height="813"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Role-Based UI Access&lt;/strong&gt;&lt;br&gt;
Each user role has a distinct UI:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patients:&lt;/strong&gt; Can only view their own cases and AI response.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctors:&lt;/strong&gt; Can edit AI output only for cases assigned to them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admins:&lt;/strong&gt; Full visibility but restricted write access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Permit.io&lt;/strong&gt; checks are run before every sensitive action using custom middleware.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Middleware check
 let permitted;
 if (resource === roleMap.Patient || resource === roleMap.Doctor) {
   permitted = await permitInstance.check(decoded._id.toString(), 
      action, {
          type: "users",
          attributes: {
            role: resource,
          },
        });
      } else {
        permitted = await permitInstance.check(
          decoded._id.toString(),
          action,
          resource
    );
 }

checkPermission("create", "medical_test")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;6. Edge Cases &amp;amp; Safeguards&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If AI fails, the doctor is prompted to diagnose manually.&lt;/li&gt;
&lt;li&gt;Patients cannot re-edit submitted cases.&lt;/li&gt;
&lt;li&gt;Unauthorized access triggers a 403 Forbidden from the backend.&lt;/li&gt;
&lt;/ul&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%2Fbvs06n7ejsk88fkjxpl0.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%2Fbvs06n7ejsk88fkjxpl0.png" alt="AI response" width="800" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  My Journey
&lt;/h2&gt;

&lt;p&gt;The idea sparked from the growing use of AI in health tech, and the need to design systems where &lt;strong&gt;AI doesn’t overstep boundaries&lt;/strong&gt;. I wanted to explore:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How can AI suggest treatment, but still leave the final word to humans?&lt;/li&gt;
&lt;li&gt;How can we &lt;strong&gt;govern AI responses&lt;/strong&gt; using access policies?&lt;/li&gt;
&lt;li&gt;How can a real app enforce that &lt;strong&gt;patients can’t view unapproved AI content&lt;/strong&gt;, and &lt;strong&gt;admins can’t tamper with diagnoses?&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I explored &lt;strong&gt;Permit.io&lt;/strong&gt; as the perfect ABAC solution. It allowed me to define policies externally while keeping the code clean and scalable. The &lt;strong&gt;biggest challenge&lt;/strong&gt; was getting Permit and the AI logic to talk smoothly, but once I modularized permissions (middlewares for &lt;code&gt;protect&lt;/code&gt; and &lt;code&gt;checkPermission&lt;/code&gt;), it all clicked.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authorization for AI Applications with Permit.io
&lt;/h2&gt;

&lt;p&gt;This project is a practical demonstration of &lt;strong&gt;AI Access Control&lt;/strong&gt; in healthcare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Patients&lt;/strong&gt; can submit symptoms and view &lt;strong&gt;only doctor-approved AI results&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Doctors&lt;/strong&gt; can review, approve, or override &lt;strong&gt;AI-generated diagnosis and treatment&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Admins&lt;/strong&gt; can manage users and assignments but &lt;strong&gt;can’t access AI data&lt;/strong&gt; — a deliberate, governance-first design.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How Permit.io Helped
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Used &lt;strong&gt;Permit.io’s ABAC model&lt;/strong&gt; with resource-level permissions (&lt;code&gt;users&lt;/code&gt;, &lt;code&gt;medical_cases&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Defined roles (&lt;code&gt;patient&lt;/code&gt;, &lt;code&gt;doctor&lt;/code&gt;, &lt;code&gt;admin&lt;/code&gt;) and enforced actions like &lt;code&gt;read&lt;/code&gt;, &lt;code&gt;update&lt;/code&gt;, &lt;code&gt;approve&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;Added &lt;code&gt;checkPermission("update", "medical_case")&lt;/code&gt; middleware to secure AI-related endpoints.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By separating AI generation from user access, and wrapping it in &lt;strong&gt;Permit.io-driven access gates&lt;/strong&gt;, the app shows how AI can remain useful &lt;strong&gt;without being unchecked&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Special Thanks
&lt;/h2&gt;

&lt;p&gt;Huge thanks to &lt;strong&gt;Permit.io&lt;/strong&gt; for building a developer-friendly access control system and for organizing this hackathon!&lt;/p&gt;

&lt;p&gt;Built with ❤️ by Suman Kumar&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>permitchallenge</category>
      <category>webdev</category>
      <category>security</category>
    </item>
    <item>
      <title>Boost Node.js Performance with Worker Threads 🚀 | Multithreading Explained!</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Sun, 30 Mar 2025 11:35:43 +0000</pubDate>
      <link>https://forem.com/sumankalia/boost-nodejs-performance-with-worker-threads-multithreading-explained-5cdj</link>
      <guid>https://forem.com/sumankalia/boost-nodejs-performance-with-worker-threads-multithreading-explained-5cdj</guid>
      <description>&lt;p&gt;Node.js is great for handling multiple requests asynchronously, but what if I tell you it struggles with CPU-intensive tasks?&lt;/p&gt;

&lt;p&gt;You may have noticed the server slows down when processing large files or running complex calculations.&lt;/p&gt;

&lt;p&gt;As we know, Node.js runs on a single thread, meaning CPU-heavy tasks like large calculations or image processing can block the server.&lt;/p&gt;

&lt;p&gt;The async/await can’t help because JS’s event loop is still single-threaded.&lt;/p&gt;

&lt;p&gt;Well, the solution for this problem is “Worker Threads!”&lt;/p&gt;

&lt;p&gt;Worker Threads help us run tasks in separate threads without blocking the main event loop.&lt;/p&gt;

&lt;p&gt;We will understand this by a simple example of a CPU-intensive calculation with and without Worker Threads.&lt;/p&gt;

&lt;p&gt;So, first we’ll create a function to calculate the “perfect numbers” below a certain number.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function isPerfectNumber(num) {
    // Find all divisors and sum them
    let sum = 0;
    for(let i = 1; i &amp;lt; num; i++) {
        if(num % i === 0) {
            sum += i;
        }
    }
    // If sum of divisors equals the number, it's perfect
    return sum === num;
}

 function findPerfectNumbers(maxNumber) {
    const perfectNumbers = [];
    // Check each number up to maxNumber
    for(let i = 1; i &amp;lt;= maxNumber; i++) {
        if(isPerfectNumber(i)) {
            perfectNumbers.push(i);
        }
    }
    return perfectNumbers;
}

module.exports = {
    isPerfectNumber,
    findPerfectNumbers
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will use this to check if it's blocking the next process while execution. We’ll also add a function that will log the count after executing the “Main thread finished” log.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
console.log("Main thread started");

console.time("Without Worker");
console.log("Result:", findPerfectNumbers(100000));
console.timeEnd("Without Worker");

console.log("Main thread finished");

// Add a simple counting task to show blocking
console.log("\nStarting simple counting task...");
console.time("Simple Count");
let count = 0;
for(let i = 0; i &amp;lt; 10; i++) {
    console.log(`Counting: ${i}`);
    count++;
    // Small delay to make the counting visible
    const start = Date.now();
    while(Date.now() - start &amp;lt; 1000) {} // Busy wait for 1 second
}

console.timeEnd("Simple Count");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above example, when we run it, we’ll notice that when the execution of “findPerfectNumbers” starts, it blocks the other execution for approximately. 7 seconds(in my Macbook Air). After its execution, the counter starts executing.&lt;/p&gt;

&lt;p&gt;Now, we have understood the problem, that we can’t block the server for any process for this long time. The server must be responsive. So, for these types of heavy calculations, we use Worker Threads.&lt;/p&gt;

&lt;p&gt;Let’s solve this problem with the Worker Thread.&lt;/p&gt;

&lt;p&gt;“worker_threads” is a core module of Node.js; we don’t have to install it separately.&lt;/p&gt;

&lt;p&gt;Let’s create a separate file as “worker.js”&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { parentPort } = require('worker_threads');
const { findPerfectNumbers } = require('./helpers');

//Listen for messages from the main thread
parentPort.on('message', (num) =&amp;gt; {
    const result = findPerfectNumbers(num);
    parentPort.postMessage(result); //Send result back
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this file, we’ll write the worker logic. Basically, it will listen for the “message” from parentPort or from the main thread where it's called. When it receives this event, it starts executing and returns the result to the main thread after execution.&lt;/p&gt;

&lt;p&gt;Now, we will call this worker from our main file,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const { Worker } = require('worker_threads');

// Create a worker thread
const worker = new Worker('./worker.js');

worker.postMessage(100000); // Send a number to the worker for calculation

worker.on('message', (result) =&amp;gt; {
    console.log("Worker Result:", result);
});

console.log("Main thread continues executing...");



// Add a simple counting task to show blocking
console.log("\nStarting simple counting task...");
console.time("Simple Count");
let count = 0;
for(let i = 0; i &amp;lt; 10; i++) {
    console.log(`Counting: ${i}`);
    count++;
    // Small delay to make the counting visible
    const start = Date.now();
    while(Date.now() - start &amp;lt; 1000) {} // Busy wait for 1 second
}

console.timeEnd("Simple Count");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the main file, we basically define the worker first, by giving the path of the worker file, and then post a “message” event to the worker. In this case, we are sending the number “1,00,000”. And then we’ll listen for the “message” event from the worker by using the “on” method. After this, we have used the same logic to log the count.&lt;/p&gt;

&lt;p&gt;The result of this is as expected. After the worker is called for the calculation, the main thread is not blocked and starts executing the next count script immediately. And when the result of the Worker Thread is ready, it’ll send it back through the “message” event.&lt;/p&gt;

&lt;p&gt;We can use this in case of CPU-intensive tasks. Better not to use these for asynchronous tasks like database queries.&lt;/p&gt;

&lt;p&gt;Github- &lt;a href="https://github.com/sumankalia/react_web_workers/tree/type" rel="noopener noreferrer"&gt;https://github.com/sumankalia/react_web_workers/tree/type&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to watch this tutorial on YouTube in Hindi. Here's the link&lt;/p&gt;

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

&lt;p&gt;If you like the above article, please clap on the article.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>node</category>
      <category>multithreading</category>
      <category>worker</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Web workers in ReactJs</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Sat, 16 Sep 2023 07:16:58 +0000</pubDate>
      <link>https://forem.com/sumankalia/web-workers-in-reactjs-4bc7</link>
      <guid>https://forem.com/sumankalia/web-workers-in-reactjs-4bc7</guid>
      <description>&lt;p&gt;Have you ever faced a situation in which you are executing a block of code and it is freezing the UI for a few seconds? If yes then you surely need a solution to handle that block of code in the background. &lt;/p&gt;

&lt;p&gt;In React we have a simple way to do these types of CPU-intensive processes in the background with the help of web workers. First of all what a web worker is?&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;web worker&lt;/strong&gt; is a JavaScript feature that allows you to run scripts in the background, separate from the main thread of your web page. This background execution enables you to perform tasks concurrently without blocking the user interface (UI) or causing it to become unresponsive. Web workers are particularly useful for handling computationally intensive or time-consuming operations without impacting the user's experience.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;use cases&lt;/strong&gt; for a web worker are &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Complex Calculations:&lt;/strong&gt; Web workers are ideal for performing complex mathematical calculations or data processing tasks without impacting the main thread.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Large Data Handling:&lt;/strong&gt; When dealing with large datasets or files, web workers can help process and parse the data in the background.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Background Services:&lt;/strong&gt; Web workers can be used to run background services such as periodic data synchronization or background notifications.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, let's try to implement a web worker in a React application.&lt;/p&gt;

&lt;p&gt;First, we create a react project, and then we use a service &lt;a href="https://fakerjs.dev/" rel="noopener noreferrer"&gt;faker&lt;/a&gt; to create 25000 user records.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { faker } from '@faker-js/faker';

export function fetchUsers() {
    const users = [];

    for (let i = 0; i &amp;lt; 25000; i++) {
        let id = i + 1;
        let name = faker.person.fullName();
        let email = faker.internet.email();
        let joinedOn = faker.date.recent();
        let commentCount = faker.number.int({ min: 0, max: 100 });
        let user = {
            id,
            name,
            email,
            joinedOn,
            commentCount
        };
        users.push(user);
    }
    return Promise.resolve(users);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, our goal is to sort these records ascending and descending based on "commentCount" by using a web worker.&lt;/p&gt;

&lt;p&gt;So, first, we will create two files "src/app.worker.js" and "src/WebWorker.js".&lt;/p&gt;

&lt;p&gt;In the "app.worker.js" file we will export an arrow function in which we will add an event listener on the window object(self) to listen to the "message". This "message" will be triggered from the UI with "users" and "type"(ascending or descending" variables.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default () =&amp;gt; {
  self.addEventListener('message', e =&amp;gt; { // eslint-disable-line no-restricted-globals
      if (!e) return;
      let { users, type } = e.data;

      if(type === "asc") {
        users = users.sort((a, b) =&amp;gt; a.commentCount - b.commentCount);
      } else {
        users = users.sort((a, b) =&amp;gt; b.commentCount - a.commentCount);
      }

      postMessage(users);
  })
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we will sort it according to the "type" variable and return it by "postMesssage" method.&lt;/p&gt;

&lt;p&gt;And in the "WebWorker.js" we will export a class.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export default class WebWorker {
    constructor(worker) {
        const code = worker.toString();
        const blob = new Blob(['('+code+')()']);
        return new Worker(URL.createObjectURL(blob));
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will simply change the worker we defined in "app.worker.js" to an object URL.&lt;/p&gt;

&lt;p&gt;Now, let's connect this webworker to the UI.&lt;/p&gt;

&lt;p&gt;First we will import both the "worker" and "WebWorker" from the respective files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import worker from './app.worker.js';
import WebWorker from './WebWorker';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will initialize the "WebWorker" with the argument "worker".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const webWorker = new WebWorker(worker);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First, we will work on the ascending logic. So, we will send the "users" and "type" to the worker by the "postMessage" method on this web worker.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webWorker.postMessage({ users, type: "asc"});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will listen to the "message" and get the sorted data from the web worker like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webWorker.addEventListener('message', (event) =&amp;gt; {
            const sortedList = event.data;

            setUsers(sortedList);
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same logic we will add for the descending function as well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;webWorker.postMessage({ users, type: "desc"});
        webWorker.addEventListener('message', (event) =&amp;gt; {
            const sortedList = event.data;

            setUsers(sortedList);
        });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, now our sorting is working fine. But don't forget to terminate the web worker at the time of component unmounting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return () =&amp;gt; {
            webWorker.terminate()
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, finally, our application will look something like this.&lt;/p&gt;

&lt;p&gt;Working Example- &lt;a href="https://6505555525bea36e699fd62c--monumental-cuchufli-bc3416.netlify.app/" rel="noopener noreferrer"&gt;https://6505555525bea36e699fd62c--monumental-cuchufli-bc3416.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github- &lt;a href="https://github.com/sumankalia/react_web_workers/tree/type" rel="noopener noreferrer"&gt;https://github.com/sumankalia/react_web_workers/tree/type&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want to watch this tutorial on YouTube in Hindi. Here's the link&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/2QR1XOr1MyI"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you like the above article, please clap on the article.&lt;/p&gt;

&lt;p&gt;Thanks for reading.&lt;/p&gt;

</description>
      <category>website</category>
      <category>performance</category>
      <category>react</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Top AI Tools for Boosting Productivity in 2023: From Grammarly to ChatGPT</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Mon, 20 Mar 2023 13:21:37 +0000</pubDate>
      <link>https://forem.com/sumankalia/10-top-ai-tools-for-boosting-productivity-in-2023-from-grammarly-to-chatgpt-541g</link>
      <guid>https://forem.com/sumankalia/10-top-ai-tools-for-boosting-productivity-in-2023-from-grammarly-to-chatgpt-541g</guid>
      <description>&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%2Fh3ysj0rt88dfdj1lefnp.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%2Fh3ysj0rt88dfdj1lefnp.jpg" alt="AI Title Image" width="720" height="480"&gt;&lt;/a&gt;&lt;br&gt;
Artificial intelligence has become an integral part of modern-day technology and has transformed various aspects of our lives. AI tools have proven to be incredibly useful in increasing productivity in a wide range of industries, from healthcare to finance to marketing. In this article, we will look at the top 10 AI tools that can help you increase your productivity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. ChatGPT&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ChatGPT is a chatbot powered by OpenAI that can help you perform a variety of tasks, from answering questions to generating text. It uses natural language processing to understand user input and provide helpful responses. ChatGPT can help you save time and increase productivity by automating tasks that would normally require manual effort.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Grammarly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grammarly is an AI-powered writing tool that can help you enhance your writing skills and eliminate grammatical errors. It not only checks for grammar, spelling, and punctuation errors, but it also offers suggestions for improving sentence structure, word choice, and style. This tool is particularly useful for writers, editors, and content creators.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Hootsuite Insights&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Hootsuite Insights is an AI tool that helps businesses monitor their social media activity and track their brand’s online reputation. It analyzes social media data to provide insights into customer sentiment, brand mentions, and trending topics. This tool can help businesses make informed decisions about their social media strategy and improve their online presence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Trello&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Trello is a project management tool that uses AI to help you organize your tasks and projects. It allows you to create boards, lists, and cards to keep track of your progress and deadlines. Trello also uses AI to suggest the best time to schedule tasks based on your productivity patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. SalesForce Einstein&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;SalesForce Einstein is an AI-powered sales tool that can help sales teams streamline their processes and improve their sales performance. It uses machine learning to analyze customer data and offer insights into sales trends, customer behavior, and sales forecasts. This tool can help sales teams prioritize leads and improve their conversion rates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. QuickBooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;QuickBooks is an accounting tool that uses AI to automate financial tasks and improve accuracy. It can help businesses manage invoices, expenses, and payroll, and it can also generate financial reports. This tool can save businesses time and money by streamlining their accounting processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;7. Siri&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Siri is an AI-powered virtual assistant that can help you perform tasks on your Apple devices. It can help you set reminders, send messages, make phone calls, and search the web using voice commands. This tool can help you save time and increase productivity by allowing you to perform tasks hands-free.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;8. Wunderlist&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wunderlist is a to-do list app that uses AI to help you organize your tasks and prioritize your workload. It allows you to create to-do lists, set reminders, and collaborate with others on projects. Wunderlist also uses AI to suggest the best time to schedule tasks based on your productivity patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;9. Blackbox AI&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Blackbox AI is an AI-powered email tool that uses natural language processing to help you manage your inbox and increase productivity. It can analyze your email history to identify important messages and prioritize your inbox accordingly. Blackbox AI can also suggest responses to emails based on your previous conversations. This tool can help you stay organized and focused on important tasks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;10. Otter.ai&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Otter.ai is an AI-powered transcription tool that can help you transcribe and organize your meetings and interviews. It uses machine learning to transcribe audio recordings into text, and it can also identify speakers and differentiate between them. This tool can save you time and improve productivity by eliminating the need for manual transcription.&lt;/p&gt;

&lt;p&gt;In conclusion, AI tools have the potential to revolutionize the way we work and increase our productivity. These top 10 AI tools can help you improve your writing&lt;/p&gt;

&lt;p&gt;Thanks for reading 😀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
      <category>news</category>
    </item>
    <item>
      <title>Why You Should Learn the MERN Stack in 2023?</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Tue, 14 Mar 2023 08:08:45 +0000</pubDate>
      <link>https://forem.com/sumankalia/why-you-should-learn-the-mern-stack-in-2023-335j</link>
      <guid>https://forem.com/sumankalia/why-you-should-learn-the-mern-stack-in-2023-335j</guid>
      <description>&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%2Ffv01e97zql9kygnetyvp.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%2Ffv01e97zql9kygnetyvp.jpg" alt="MERN Stack" width="720" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the ever-evolving world of web development, staying up to date with the latest technologies and frameworks is crucial to your success. One technology that has been gaining popularity in recent years is the MERN stack, which stands for MongoDB, Express.js, React, and Node.js. In this article, we’ll explore why you should consider learning the MERN stack in 2023.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High Demand for MERN Stack Developers-&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As more and more companies move their businesses online, the demand for skilled web developers continues to grow. According to a recent survey by Stack Overflow, JavaScript is the most popular programming language, with React and Node.js ranking as the second and third most popular web frameworks, respectively. This means that there is a high demand for developers who are skilled in the MERN stack, as it combines all three of these popular technologies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full-Stack Development with JavaScript-&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the biggest advantages of the MERN stack is that it allows you to build full-stack web applications using only JavaScript. This means that you can write both the front-end and back-end of your application using the same language, making it easier to maintain and debug your code. This also means that you can use a single set of tools and libraries for your entire application, reducing the complexity of your development environment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Scalability and Flexibility&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The MERN stack is highly scalable and flexible, making it a great choice for building large and complex applications. MongoDB, for example, is a NoSQL database that can handle large amounts of unstructured data, while Node.js is known for its ability to take a high volume of simultaneous connections. This makes the MERN stack ideal for building applications that need to handle a large number of users and data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Large Community and Extensive Resources&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;One of the advantages of using a popular technology stack like MERN is that it has a large and active community of developers. This means that you can find extensive documentation, tutorials, and resources online to help you learn and solve problems as you build your application. Additionally, there are many open-source libraries and tools available for the MERN stack, which can save you time and effort in development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Future-Proofing Your Skills&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learning the MERN stack can be a great investment in your future career as a web developer. With its popularity and demand, it is likely to remain relevant and in demand for years to come. Additionally, the skills you gain from learning the MERN stack can be easily transferable to other popular web frameworks and technologies, such as MEAN (MongoDB, Express.js, Angular, and Node.js) or GraphQL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In conclusion, the MERN stack is a powerful and versatile technology stack that can help you build scalable and flexible web applications using only JavaScript. With its high demand, extensive resources, and future-proofing potential, it is definitely worth considering learning in 2023. So, if you’re ready to take your web development skills to the next level, start exploring the MERN stack today!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Record Screen App with Javascript</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Mon, 06 Mar 2023 06:12:55 +0000</pubDate>
      <link>https://forem.com/sumankalia/record-screen-app-with-javascript-1dif</link>
      <guid>https://forem.com/sumankalia/record-screen-app-with-javascript-1dif</guid>
      <description>&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%2Fwj09a998mcpoxcjjm7nx.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%2Fwj09a998mcpoxcjjm7nx.jpg" alt="Record Screen app thumbnail" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Below is the tutorial on how we can use Screen Record API in javascript.&lt;/p&gt;

&lt;p&gt;First, we will create an index.html file in a newly created project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;html&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;meta charset="UTF-8" /&amp;gt;

    &amp;lt;link rel="stylesheet" type="text/css" href="index.css" /&amp;gt;
    &amp;lt;link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-GLhlTQ8iRABdZLl6O3oVMWSktQOp6b7In1Zl3/Jr59b6EGGoI1aFkw7cmDA6j6gD"
      crossorigin="anonymous"
    /&amp;gt;
    &amp;lt;title&amp;gt;Screen capture api Demo&amp;lt;/title&amp;gt;
  &amp;lt;/head&amp;gt;

  &amp;lt;body&amp;gt;
    &amp;lt;div class="container"&amp;gt;
      &amp;lt;h3&amp;gt;
        Click the "Start" button to begin video recording. You can stop the
        video by clicking the creatively-named "Stop" button. The "Download"
        button will download the received data
      &amp;lt;/h3&amp;gt;
      &amp;lt;br /&amp;gt;
      &amp;lt;div class="row"&amp;gt;
        &amp;lt;div class="col-md-4 col-sm-12"&amp;gt;
          &amp;lt;h2&amp;gt;Preview&amp;lt;/h2&amp;gt;
          &amp;lt;video id="preview" width="300" height="200" autoplay muted&amp;gt;&amp;lt;/video&amp;gt;
          &amp;lt;button id="startButton" class="btn btn-primary mt-2"&amp;gt;
            Start Recording
          &amp;lt;/button&amp;gt;
          &amp;lt;button id="stopButton" class="btn btn-danger mt-2"&amp;gt;
            Stop Recording
          &amp;lt;/button&amp;gt;
          &amp;lt;div&amp;gt;
            &amp;lt;pre id="log"&amp;gt;&amp;lt;/pre&amp;gt;
          &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class="col-md-4 col-sm-12"&amp;gt;
          &amp;lt;h2&amp;gt;Recording&amp;lt;/h2&amp;gt;
          &amp;lt;video id="recording" width="300" height="200" controls&amp;gt;&amp;lt;/video&amp;gt;
          &amp;lt;br /&amp;gt;
          &amp;lt;a id="downloadButton" class="btn btn-success mt-2"&amp;gt; Download &amp;lt;/a&amp;gt;
        &amp;lt;/div&amp;gt;
      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;script src="script.js"&amp;gt;&amp;lt;/script&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am using “bootstrap” as the styling library and have added some CSS styling in the index.css file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;body {
  font: 14px "Open Sans", "Arial", sans-serif;
}

.container {
  margin: auto;
  background: paleturquoise;
  height: 800px;
}

video {
  margin-top: 2px;
  border: 1px solid black;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result will look something like this.&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%2F9cxqkpfh478ttu7m4867.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%2F9cxqkpfh478ttu7m4867.png" alt="HTML Preview" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, we will write some javascript, first, we will add a script.js file and import this into our index.html file.&lt;/p&gt;

&lt;p&gt;First, we will define all the elements by getting them from id’s defined.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let preview = document.getElementById("preview");
let recording = document.getElementById("recording");
let startButton = document.getElementById("startButton");
let stopButton = document.getElementById("stopButton");
let downloadButton = document.getElementById("downloadButton");
let logElement = document.getElementById("log");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever a user clicks on the “Start Recording” button it will call the method “navigator.mediaDevices.getDisplayMedia”. And we will pass a JSON object with two keys video and audio. This configuration will allow the app to record the video and audio.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;navigator.mediaDevices
      .getDisplayMedia({
        video: true,
        audio: true,
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above method will return a “promise”. In the “then” block we will get the “stream” which will be the MediaStreamTrack object of javascript. We will use this stream to show the live preview in the preview window.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;navigator.mediaDevices
      .getDisplayMedia({
        video: true,
        audio: true,
      })
      .then((stream) =&amp;gt; {
        preview.srcObject = stream;
        preview.captureStream =
          preview.captureStream || preview.mozCaptureStream;
        return new Promise((resolve) =&amp;gt; (preview.onplaying = resolve));
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we will call another and then block on the same promise which will call a method “startRecording” and we will pass the “preview.captureStream()” in this method. The “captureStream” will return a MediaStream object which is streaming a real-time capture of the content being rendered in the media element.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;navigator.mediaDevices
      .getDisplayMedia({
        video: true,
        audio: true,
      })
      .then((stream) =&amp;gt; {
        preview.srcObject = stream;
        preview.captureStream =
          preview.captureStream || preview.mozCaptureStream;
        return new Promise((resolve) =&amp;gt; (preview.onplaying = resolve));
      })
      .then(() =&amp;gt; startRecording(preview.captureStream()))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the “startRecording” method will be as follows&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function startRecording(stream) {
  //start recording
  recorder = new MediaRecorder(stream); //api to record media in javascript provides different functionalities
  // as media pause, resume, start, stop, requestData - request blob of recorded media
  let data = [];

  //ondataavailable - fires periodically each time timeslice milliseconds of media have been recorded or
  //when the entire media is recorded if no timeslice is specified
  recorder.ondataavailable = (event) =&amp;gt; data.push(event.data);
  recorder.start(); //strt the recording

  log('"Recording..."');

  //when stopped it will resolve the promise
  let stopped = new Promise((resolve, reject) =&amp;gt; {
    recorder.onstop = resolve;
    recorder.onerror = (event) =&amp;gt; reject(event.name);
  });

  //when stopped it will return the data when it is recorded and stopped completely
  return Promise.all([stopped, recorder]).then(() =&amp;gt; data);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above method, we are using a “log” method to log messages in the app.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function log(msg) {
  //log messages on screen
  logElement.innerHTML = msg + "\n";
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have to add the functionality for the “stop” button.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stopButton.addEventListener(
  "click",
  function () {
    //passing the stream as argument - MediaStreamTrack
    stop(preview.srcObject);
  },
  false
);


function stop(stream) {
  if (recorder.state == "recording") {
    recorder.stop();
  }

  //getTracks = returns a sequence that represents all 
  //the MediaStreamTrack objects and stop
  //all of them
  stream.getTracks().forEach((track) =&amp;gt; track.stop());
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you stop the recording it will stop every stream track as well as the recorder instance.&lt;/p&gt;

&lt;p&gt;After this, we will add functionality for the recorded video preview and the downloading of recorded media. For this, we have to add another then block in the “getDisplayMedia” method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;navigator.mediaDevices
      .getDisplayMedia({
        video: true,
        audio: true,
      })
      .then((stream) =&amp;gt; {
        preview.srcObject = stream;
        preview.captureStream =
          preview.captureStream || preview.mozCaptureStream;
        return new Promise((resolve) =&amp;gt; (preview.onplaying = resolve));
      })
      .then(() =&amp;gt; startRecording(preview.captureStream()))
      .then((recordedChunks) =&amp;gt; {
        let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
        recording.src = URL.createObjectURL(recordedBlob);
        downloadButton.href = recording.src;
        downloadButton.download = "RecordedVideo.webm";

        log(
          "Successfully recorded " +
            recordedBlob.size +
            " bytes of " +
            recordedBlob.type +
            " media."
        );
      })
      .catch(log);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the last “then” block we will get the recorded media chunks and now, we will create a “blob” object with the type “video/webm” and also set the “recording.src” equal to “recordedBlob”. It will preview the recorded media. Then in the next step, we will set the download button ‘href’ equal to the recorded media URL. And the “downloadButton.download” is equal to the name of the exported file.&lt;/p&gt;

&lt;p&gt;When we will click on the “download” button it will start downloading the recorded media.&lt;/p&gt;

&lt;p&gt;The final script.js file will look something like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let preview = document.getElementById("preview");
let recording = document.getElementById("recording");
let startButton = document.getElementById("startButton");
let stopButton = document.getElementById("stopButton");
let downloadButton = document.getElementById("downloadButton");
let logElement = document.getElementById("log");
let recorder;

function log(msg) {
  //log messages on screen
  logElement.innerHTML = msg + "\n";
}

function startRecording(stream) {
  //start recording
  recorder = new MediaRecorder(stream); //api to record media in javascript provides different functionalities
  // as media pause, resume, start, stop, requestData - request blob of recorded media
  let data = [];

  //ondataavailable - fires periodically each time timeslice milliseconds of media have been recorded or
  //when the entire media is recorded if no timeslice is specified
  recorder.ondataavailable = (event) =&amp;gt; data.push(event.data);
  recorder.start(); //strt the recording

  log('"Recording..."');

  //when stopped it will resolve the promise
  let stopped = new Promise((resolve, reject) =&amp;gt; {
    recorder.onstop = resolve;
    recorder.onerror = (event) =&amp;gt; reject(event.name);
  });

  //when stopped it will return the data when it is recorded and stopped completely
  return Promise.all([stopped, recorder]).then(() =&amp;gt; data);
}

function stop(stream) {
  if (recorder.state == "recording") {
    recorder.stop();
  }

  //getTracks = returns a sequence that represents all the MediaStreamTrack objects and stops
  //all them
  stream.getTracks().forEach((track) =&amp;gt; track.stop());
}

startButton.addEventListener(
  "click",
  function () {
    navigator.mediaDevices
      .getDisplayMedia({
        video: true,
        audio: true,
      })
      .then((stream) =&amp;gt; {
        //stream - MediaStreamTrack
        preview.srcObject = stream;
        // downloadButton.href = stream;
        preview.captureStream =
          preview.captureStream || preview.mozCaptureStream;
        return new Promise((resolve) =&amp;gt; (preview.onplaying = resolve));
      })
      .then(() =&amp;gt; startRecording(preview.captureStream()))
      //captureStream() will return a MediaStream object
      //which is streaming a real-time capture of the
      // content being rendered in the media element.
      .then((recordedChunks) =&amp;gt; {
        let recordedBlob = new Blob(recordedChunks, { type: "video/webm" });
        recording.src = URL.createObjectURL(recordedBlob);
        downloadButton.href = recording.src;
        downloadButton.download = "RecordedVideo.webm";

        log(
          "Successfully recorded " +
            recordedBlob.size +
            " bytes of " +
            recordedBlob.type +
            " media."
        );
      })
      .catch(log);
  },
  false
);

stopButton.addEventListener(
  "click",
  function () {
    //passing the recorded chunks as argument
    stop(preview.srcObject);
  },
  false
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The final app will look like this&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%2F264n5jdbbn55ribfbvth.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%2F264n5jdbbn55ribfbvth.png" alt="Final App Preview" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub- &lt;a href="https://github.com/sumankalia/screen_capture_and_download" rel="noopener noreferrer"&gt;https://github.com/sumankalia/screen_capture_and_download&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live Preview- &lt;a href="https://main--cool-semolina-7c039d.netlify.app/" rel="noopener noreferrer"&gt;https://main--cool-semolina-7c039d.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Youtube tutorial link in “Hindi”-&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ZqQ77p4THeE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for reading 😀&lt;/p&gt;

</description>
      <category>turorial</category>
      <category>javascript</category>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How to integrate EditorJs in ReactJs</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Thu, 23 Feb 2023 07:06:44 +0000</pubDate>
      <link>https://forem.com/sumankalia/how-to-integrate-editorjs-in-reactjs-2l6l</link>
      <guid>https://forem.com/sumankalia/how-to-integrate-editorjs-in-reactjs-2l6l</guid>
      <description>&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%2Fwae5o0nxb24708se2igb.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%2Fwae5o0nxb24708se2igb.jpg" alt="Article Editor" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
If you ever worked with front-end development, you will surely know how difficult it is to integrate a rich text editor into your application. There are a lot of rich text libraries out there which are compatible with different javascript frameworks.&lt;/p&gt;

&lt;p&gt;A few days ago, I was searching for a rich text editor. This was not the first time I was going to integrate a rich text editor in a React application. In the past times, I have used the react-quill, DraftJs, WYSIWYG, etc. But this time the requirements were quite different and somebody suggested me this editor — &lt;a href="https://editorjs.io" rel="noopener noreferrer"&gt;Editorjs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://editorjs.io" rel="noopener noreferrer"&gt;Editorjs&lt;/a&gt; is a pretty popular editor backed up by a good dev team with time-to-time updates. This editor is pretty different from other rich text editors out there.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Block Style Editor-&lt;/strong&gt; every piece of content in the editor is a block. A block can be anything — a paragraph, header, image, or literally anything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clean JSON data output-&lt;/strong&gt; It gives the final data output in JSON format&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Supports Plugins-&lt;/strong&gt; It supports plugins to add any feature in this editor ie. paragraphs, images, quote,s, etc. We can also create and integrate our custom plugins.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Clear Documentation-&lt;/strong&gt; The documentation is clear and helpful.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, let’s discuss how we can integrate it into our React project.&lt;/p&gt;

&lt;p&gt;First, we need to install this library with npm — &lt;a href="https://www.npmjs.com/package/@editorjs/editorjs" rel="noopener noreferrer"&gt;@editorjs/editorjs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then we will create a component as EditorComponent.js in our code repository.&lt;/p&gt;

&lt;p&gt;In this component, we will return a “div” with “id=editorjs”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const EditorComponent = () =&amp;gt; {
    return  &amp;lt;&amp;gt;&amp;lt;div id='editorjs'&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/&amp;gt;;
} 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will use this “id” attribute to integrate the editors in this div.&lt;/p&gt;

&lt;p&gt;In the next step, we will create a method to initialize the EditorJs class imported from the Editorjs library.&lt;/p&gt;

&lt;p&gt;First, we will import the EditorJs class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import EditorJS from "@editorjs/editorjs";
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will initiate this class in a method and call this method in “useEffect” hook while initial load of the page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const initEditor = () =&amp;gt; {
       const editor = new EditorJS({
          holder: 'editorjs',
          onReady: () =&amp;gt; {
            ejInstance.current = editor;
          },
          autofocus: true,
          data: DEFAULT_INITIAL_DATA,
          onChange: async () =&amp;gt; {
            let content = await editor.saver.save();

            console.log(content);
          }
        });
      };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet, the “holder” key value should be the same as the id of the div defined in the first step.&lt;/p&gt;

&lt;p&gt;We are using the “ejInstance” reference to the editor to check if the editor is loaded already or not.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const ejInstance = useRef();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The “autofocus” will focus the editor on the first load. In the data key, we can pass the initial data.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const DEFAULT_INITIAL_DATA =  {
      "time": new Date().getTime(),
      "blocks": [
        {
          "type": "header",
          "data": {
            "text": "This is my awesome editor!",
            "level": 1
          }
        },
      ]
  }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the onChange method, we will get the editor data in “content”.&lt;/p&gt;

&lt;p&gt;To make sure the editor load only once we have to add this condition in “useEffect”.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; useEffect(() =&amp;gt; {
    if (ejInstance.current === null) {
      initEditor();
    }

    return () =&amp;gt; {
      ejInstance?.current?.destroy();
      ejInstance.current = null;
    };
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we will destroy the instance while the component unmounts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a plugin&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;By default, Editorjs provides only simple text or paragraphs, but if we want to add more functionality like, headings, upload images, embeds, etc. Then, we need to use different plugins provided by EditorJs team.&lt;/p&gt;

&lt;p&gt;In this application, we will use the “Header” plugin to enable headings. For this, we have to install a package- &lt;a href="https://www.npmjs.com/package/@editorjs/header" rel="noopener noreferrer"&gt;@editorjs/header&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To enable this in the editor we need to add a key “tools” in the editor instance like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const editor = new EditorJS({
          holder: 'editorjs',
          onReady: () =&amp;gt; {
            ejInstance.current = editor;
          },
          autofocus: true,
          data: DEFAULT_INITIAL_DATA,
          onChange: async () =&amp;gt; {
            let content = await editor.saver.save();

            console.log(content);
          },
          tools: { 
            header: Header, 
          },
        });
      };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need other plugins, you can check them on this &lt;a href="https://github.com/editor-js/awesome-editorjs" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to build a custom plugin, you can check this &lt;a href="https://editorjs.io/the-first-plugin/" rel="noopener noreferrer"&gt;link&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GitHub Link- &lt;a href="https://github.com/sumankalia/react-editorjs" rel="noopener noreferrer"&gt;https://github.com/sumankalia/react-editorjs&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check youtube video in &lt;strong&gt;Hindi&lt;/strong&gt;-&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/CGOexlZRfCg"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;Thanks for reading 😀&lt;/p&gt;

</description>
      <category>react</category>
      <category>editorjs</category>
      <category>tutorial</category>
      <category>wysiwyg</category>
    </item>
    <item>
      <title>Export Excel(XLSX) file in react with images and custom styles in ReactJs</title>
      <dc:creator>Suman Kumar</dc:creator>
      <pubDate>Thu, 02 Feb 2023 11:37:42 +0000</pubDate>
      <link>https://forem.com/sumankalia/export-excelxlsx-file-in-react-with-images-and-custom-styles-in-reactjs-2195</link>
      <guid>https://forem.com/sumankalia/export-excelxlsx-file-in-react-with-images-and-custom-styles-in-reactjs-2195</guid>
      <description>&lt;p&gt;If you have ever worked with react and NodeJs. Then you have surely added the export excel file in any of your projects. Exporting an excel file might be easy but sometimes we have to export a more custom excel file with some custom styles as marking cells with different colors and sometimes we  also need to add the images in the same file.&lt;/p&gt;

&lt;p&gt;For this, you have different options to export the file whether in NodeJs or ReactJs. But, today we will discuss a way to export a feature-rich excel file in ReactJs. We are exporting it in ReactJs. So, it would be useful for both React and full-stack developers.&lt;/p&gt;




&lt;p&gt;For this, we are going to use a third-party package - &lt;a href="https://www.npmjs.com/package/exceljs" rel="noopener noreferrer"&gt;ExecelJs&lt;/a&gt;&lt;br&gt;
Why ExcelJs- because it offers a lot of features and works with bulk data. I have tested it with a spreadsheet file with over 50000 records.&lt;br&gt;
This package is used to read, manipulate and write spreadsheet data and styles to XLSX and JSON&lt;/p&gt;



&lt;p&gt;We will understand the process by creating a react app by create-react-app.&lt;br&gt;
We will add a free API to get data - &lt;a href="https://dummyjson.com/products" rel="noopener noreferrer"&gt;https://dummyjson.com/products&lt;/a&gt;&lt;/p&gt;



&lt;p&gt;In the app, we will first load the data from the API. We will get 30 product data with details of id, title, price, photo, etc. Then, we will create a table with product data id, title, price, thumbnail, 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%2Fcig2v5259sqv3o5x2dvp.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%2Fcig2v5259sqv3o5x2dvp.png" alt="Image description" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Our primary focus is to export the same table's data in a spreadsheet(xlsx) file. The spreadsheet's data will look something like this&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%2Fmkgl3cspx5agi079muv0.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%2Fmkgl3cspx5agi079muv0.png" alt="Image description" width="800" height="653"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have also added a conditional styling for the price if the price is between 50 and 1000 then the cell will be red colour.&lt;/p&gt;
&lt;h3&gt;
  
  
  Implementation
&lt;/h3&gt;

&lt;p&gt;First, we will install the ExcelJs package in our project.&lt;/p&gt;

&lt;p&gt;Then, we will call the API to get the data and set it in the state on the first-page load.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const [data, setData] = useState([]);
  useEffect(() =&amp;gt; {
    fetch("https://dummyjson.com/products")
      .then((res) =&amp;gt; res.json())
      .then(async (data) =&amp;gt; {
        setData(data);
      })
      .then((json) =&amp;gt; console.log(json));
  }, []);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will add a button as "Export" on top of the table, when someone clicks on this button it will create a spreadsheet and download it in the front end side.&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%2Fobbxe276228p7x7v2f1c.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%2Fobbxe276228p7x7v2f1c.png" alt="The export button above the table on extreme right" width="800" height="73"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will create a new workbook with Exceljs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const workbook = new ExcelJS.Workbook();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we will add a sheet to this workbook&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sheet = workbook.addWorksheet("My Sheet");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we have to add an image to every row in the spreadsheet. So, we will add some default height to every row in the sheet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sheet.properties.defaultRowHeight = 80;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have the first row of the sheet as the header of the sheet with different column titles. So we will add some styles to this as well ie. some borders, fonts, fill, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sheet.getRow(1).border = {
      top: { style: "thick", color: { argb: "FFFF0000" } },
      left: { style: "thick", color: { argb: "000000FF" } },
      bottom: { style: "thick", color: { argb: "F08080" } },
      right: { style: "thick", color: { argb: "FF00FF00" } },
    };

    sheet.getRow(1).fill = {
      type: "pattern",
      pattern: "darkVertical",
      fgColor: { argb: "FFFF00" },
    };

    sheet.getRow(1).font = {
      name: "Comic Sans MS",
      family: 4,
      size: 16,
      bold: true,
    };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will define the columns, this will be an array of objects. And each object has three keys header, key, and width. The "header" is the title of the column, the "key" must be the same as the JSON key of data to map data in the column, and the "width" is the width of the column.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sheet.columns = [
      {
        header: "Id",
        key: "id",
        width: 10,
      },
      { header: "Title", key: "title", width: 32 },
      {
        header: "Brand",
        key: "brand",
        width: 20,
      },
      {
        header: "Category",
        key: "category",
        width: 20,
      },
      {
        header: "Price",
        key: "price",
        width: 15,
      },
      {
        header: "Rating",
        key: "rating",
        width: 10,
      },
      {
        header: "Photo",
        key: "thumbnail",
        width: 30,
      },
    ];
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, it's time to add the data in each column with the same key name we have in column objects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;data?.products?.map((product) =&amp;gt; {
        sheet.addRow({
          id: product?.id,
          title: product?.title,
          brand: product?.brand,
          category: product?.category,
          price: product?.price,
          rating: product?.rating,
        });
      })
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above code is to add simple data to the sheet. But for the images, we need to have a different approach.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const promise = Promise.all(
      data?.products?.map(async (product, index) =&amp;gt; {
        const rowNumber = index + 1;
        sheet.addRow({
          id: product?.id,
          title: product?.title,
          brand: product?.brand,
          category: product?.category,
          price: product?.price,
          rating: product?.rating,
        });

        const result = await toDataURL(product?.thumbnail);
        const splitted = product?.thumbnail.split(".");
        const extName = splitted[splitted.length - 1];

        const imageId2 = workbook.addImage({
          base64: result.base64Url,
          extension: extName,
        });

        sheet.addImage(imageId2, {
          tl: { col: 6, row: rowNumber },
          ext: { width: 100, height: 100 },
        });
      })
    );
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we are calling an async method "toDataURL", in which we are passing the image URL and getting the base64 encoded image.&lt;/p&gt;

&lt;p&gt;Then, we are getting the image extension in the next step ie. png, jpeg, etc.&lt;/p&gt;

&lt;p&gt;Then, we will create the imageId2 object, by base64 image string and the image extension. And, in the next step, we pass it to the sheet.addImage() method with the "tl" key(column and row) and "ext" key(to define the height and width).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const toDataURL = (url) =&amp;gt; {
  const promise = new Promise((resolve, reject) =&amp;gt; {
    var xhr = new XMLHttpRequest();
    xhr.onload = function () {
      var reader = new FileReader();
      reader.readAsDataURL(xhr.response);
      reader.onloadend = function () {
        resolve({ base64Url: reader.result });
      };
    };
    xhr.open("GET", url);
    xhr.responseType = "blob";
    xhr.send();
  });

  return promise;
};
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;The above method is to convert an image from URL to base64 encoded.&lt;/em&gt;&lt;br&gt;
 &lt;br&gt;
In this method, we will call the URL and get the image data, and convert it to a base64 encoded image.&lt;/p&gt;

&lt;p&gt;After this step, we will have a promise. Now, in the "then" block of the promise we will add the price column styles to fill the cell red if the price is between 50 and 1000.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;promise.then(() =&amp;gt; {
      const priceCol = sheet.getColumn(5);

      // iterate over all current cells in this column
      priceCol.eachCell((cell) =&amp;gt; {
        const cellValue = sheet.getCell(cell?.address).value;
        // add a condition to set styling
        if (cellValue &amp;gt; 50 &amp;amp;&amp;amp; cellValue &amp;lt; 1000) {
          sheet.getCell(cell?.address).fill = {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FF0000" },
          };
        }
      });
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, in the last step, we use the workbook writeBuffer method to create the xlsx file and download it as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;workbook.xlsx.writeBuffer().then(function (data) {
        const blob = new Blob([data], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        const url = window.URL.createObjectURL(blob);
        const anchor = document.createElement("a");
        anchor.href = url;
        anchor.download = "download.xlsx";
        anchor.click();
        window.URL.revokeObjectURL(url);
      });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above code snippet we are getting data after the promise is resolved, then we will create it to buffer and define the type of the file ie. spreadsheet.&lt;/p&gt;

&lt;p&gt; Then we are creating a temporary anchor to download the file by giving the file name "download.xlsx". And we will click this anchor programmatically and download the file and revoke the anchor in the next step as well.&lt;/p&gt;

&lt;p&gt;Now finally the download function and price styling step will look something like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;promise.then(() =&amp;gt; {
      const priceCol = sheet.getColumn(5);

      // iterate over all current cells in this column
      priceCol.eachCell((cell) =&amp;gt; {
        const cellValue = sheet.getCell(cell?.address).value;
        // add a condition to set styling
        if (cellValue &amp;gt; 50 &amp;amp;&amp;amp; cellValue &amp;lt; 1000) {
          sheet.getCell(cell?.address).fill = {
            type: "pattern",
            pattern: "solid",
            fgColor: { argb: "FF0000" },
          };
        }
      });

      workbook.xlsx.writeBuffer().then(function (data) {
        const blob = new Blob([data], {
          type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
        });
        const url = window.URL.createObjectURL(blob);
        const anchor = document.createElement("a");
        anchor.href = url;
        anchor.download = "download.xlsx";
        anchor.click();
        window.URL.revokeObjectURL(url);
      });
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Link- &lt;a href="https://github.com/sumankalia/export-xlsx-react" rel="noopener noreferrer"&gt;https://github.com/sumankalia/export-xlsx-react&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Live demo- &lt;a href="https://63da86a84679e413b00fd738--dreamy-pithivier-43351e.netlify.app/" rel="noopener noreferrer"&gt;https://63da86a84679e413b00fd738--dreamy-pithivier-43351e.netlify.app/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Youtube video link in Hindi - &lt;iframe width="710" height="399" src="https://www.youtube.com/embed/24PFCm1IvHc"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/PHzcA5R40h4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;If you find this article helpful, please do like this and follow me.&lt;/p&gt;

&lt;p&gt;Thanks for reading&lt;/p&gt;

</description>
      <category>react</category>
      <category>excel</category>
      <category>images</category>
      <category>styles</category>
    </item>
  </channel>
</rss>
