<?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: Mohit Agnihotri</title>
    <description>The latest articles on Forem by Mohit Agnihotri (@mohit_agnihotri_5).</description>
    <link>https://forem.com/mohit_agnihotri_5</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%2F1523067%2F1bb2aaeb-a3e9-4036-bf71-1c9f7bea0d68.jpg</url>
      <title>Forem: Mohit Agnihotri</title>
      <link>https://forem.com/mohit_agnihotri_5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/mohit_agnihotri_5"/>
    <language>en</language>
    <item>
      <title>Viral-O-Meter for YouTube (Built with n8n + Bright Data)</title>
      <dc:creator>Mohit Agnihotri</dc:creator>
      <pubDate>Sun, 31 Aug 2025 14:31:25 +0000</pubDate>
      <link>https://forem.com/mohit_agnihotri_5/viral-o-meter-for-youtube-built-with-n8n-bright-data-4kho</link>
      <guid>https://forem.com/mohit_agnihotri_5/viral-o-meter-for-youtube-built-with-n8n-bright-data-4kho</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-n8n-2025-08-13"&gt;AI Agents Challenge powered by n8n and Bright Data&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Viral-O-Meter for YouTube&lt;/strong&gt; — an n8n + Bright Data agent that checks a keyword's viral potential in real time.  &lt;/p&gt;

&lt;p&gt;It pulls top YouTube results for a keyword via Bright Data’s Verified Node, normalizes metrics (views/likes/length), computes robust stats (median &amp;amp; p75 views, like rate, Shorts share, median lengths), and asks an AI &lt;strong&gt;Agent&lt;/strong&gt; to deliver a GO/NO_GO verdict, recommended format (Shorts vs Long-form), ideal length band, content angles, and hooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Who it helps:&lt;/strong&gt; creators &amp;amp; marketers who want a quick, data-driven green‑light before spending time on a video.&lt;/p&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Video walkthrough:&lt;/strong&gt; &lt;a href="https://youtu.be/vJgj8UrPAmw" rel="noopener noreferrer"&gt;https://youtu.be/vJgj8UrPAmw&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live agent:&lt;/strong&gt; &lt;a href="https://dev-challenge-brightdata.app.n8n.cloud/form/trend-finder" rel="noopener noreferrer"&gt;https://dev-challenge-brightdata.app.n8n.cloud/form/trend-finder&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  n8n Workflow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Gist (workflow JSON):&lt;/strong&gt; &lt;a href="https://gist.github.com/mohitagnihotri/062a1cee13e30bcdeccba3aaa8895b61" rel="noopener noreferrer"&gt;https://gist.github.com/mohitagnihotri/062a1cee13e30bcdeccba3aaa8895b61&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Key nodes:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bright Data (Verified Node):&lt;/strong&gt; Data Collector (trigger collection &amp;amp; fetch snapshot), Web Unlocker when needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code (Normalize):&lt;/strong&gt; converts raw fields to numeric (views/likes), derives &lt;code&gt;views_per_day&lt;/code&gt;, parses HH:MM:SS, classifies Shorts vs Long-form.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code (Stats):&lt;/strong&gt; computes medians/quantiles and seeds a suggested length band (±20% around top‑quartile median).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Agent (AI):&lt;/strong&gt; consumes the enriched JSON and returns structured recommendations.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Report:&lt;/strong&gt; send proper analysis report to given email through Gmail.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  Technical Implementation
&lt;/h2&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%2F60fqs03bkisusnhmwn1p.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%2F60fqs03bkisusnhmwn1p.jpg" alt="n8n workflow" width="800" height="183"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High-level flow&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Ingest with Bright Data&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;Data Collector&lt;/strong&gt; to collect YouTube search/results pages by keyword.
&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;Deliver Snapshot / Get Snapshot Content&lt;/strong&gt; to fetch structured results.
&lt;/li&gt;
&lt;li&gt;If regional blocks occur, enable &lt;strong&gt;Web Unlocker&lt;/strong&gt; automatically in the Verified Node.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Normalize (Code Node #1)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Parse numeric strings like “58,613”, “1.2M/1.2K” → integers.
&lt;/li&gt;
&lt;li&gt;Parse &lt;code&gt;video_length&lt;/code&gt; (seconds or HH:MM:SS) → &lt;code&gt;length_seconds&lt;/code&gt; &amp;amp; &lt;code&gt;length_hms&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;Derive &lt;code&gt;views_per_day&lt;/code&gt;, compute &lt;code&gt;like_rate_pct&lt;/code&gt;, detect &lt;code&gt;post_type&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stats (Code Node #2)&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Compute &lt;strong&gt;median / p75&lt;/strong&gt; for views, &lt;strong&gt;median like rate&lt;/strong&gt;, &lt;strong&gt;Shorts share %&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Compute &lt;strong&gt;median length (all)&lt;/strong&gt; and &lt;strong&gt;median length among the top quartile by views&lt;/strong&gt;.
&lt;/li&gt;
&lt;li&gt;Create a &lt;strong&gt;recommended_seed&lt;/strong&gt; with an anchor length (top‑quartile median) and a &lt;strong&gt;±20% band&lt;/strong&gt;; include a &lt;strong&gt;format_hint&lt;/strong&gt; based on top performers.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Agent&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;System Prompt:&lt;/strong&gt; “You are a YouTube content viability analyst …” (uses &lt;code&gt;benchmarks&lt;/code&gt; &amp;amp; &lt;code&gt;recommended_seed&lt;/code&gt; if present; otherwise computes).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User Prompt:&lt;/strong&gt; “Analyze the following dataset … { JSON.stringify($json, null, 2) }”
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output:&lt;/strong&gt; deterministic JSON with &lt;strong&gt;verdict&lt;/strong&gt;, &lt;strong&gt;confidence&lt;/strong&gt;, &lt;strong&gt;recommended format/length&lt;/strong&gt;, &lt;strong&gt;angles&lt;/strong&gt;, &lt;strong&gt;hooks&lt;/strong&gt;, and &lt;strong&gt;checklist&lt;/strong&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Outputs&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Post reports to provided email through Gmail.
&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%2F43q18ln5506kbt3sju9n.png" alt="output" width="800" height="1074"&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Design choices&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No external assumptions:&lt;/strong&gt; Agent reasons only over the provided dataset.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustness:&lt;/strong&gt; use medians and quantiles to resist outliers.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actionability:&lt;/strong&gt; force the Agent to output clear ranges (seconds + mm:ss), angles, hooks, and checklist.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Bright Data Verified Node
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoints used:&lt;/strong&gt; &lt;em&gt;Data Collector&lt;/em&gt; (trigger &amp;amp; deliver snapshots), &lt;em&gt;Web Unlocker&lt;/em&gt; when geo or bot blocks are detected.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Why Bright Data?&lt;/strong&gt; Verified, production-ready node in n8n; handles real-time collection and anti-bot hurdles without brittle DIY scraping.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Schema highlights:&lt;/strong&gt; title, url, views, likes, video_length, date_posted, channel, post_type, plus derived fields (&lt;code&gt;views_per_day&lt;/code&gt;, &lt;code&gt;like_rate_pct&lt;/code&gt;, &lt;code&gt;length_seconds&lt;/code&gt;).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cost control:&lt;/strong&gt; run snapshots on-demand and cap concurrent collections; cache daily to reduce duplicate fetches.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;&lt;strong&gt;What worked&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verified Node made collection straightforward; &lt;strong&gt;Deliver Snapshot&lt;/strong&gt; gave predictable JSON.
&lt;/li&gt;
&lt;li&gt;Separating &lt;strong&gt;normalize&lt;/strong&gt; and &lt;strong&gt;stats&lt;/strong&gt; steps simplified prompt design and let the Agent stay lightweight.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Challenges&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mixed units &amp;amp; locales:&lt;/strong&gt; views “K/M” + comma separators → solved via a single parser.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shorts vs Long-form detection:&lt;/strong&gt; use explicit &lt;code&gt;post_type&lt;/code&gt; when present; fallback to &lt;code&gt;&amp;lt;60s&lt;/code&gt;.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recency bias:&lt;/strong&gt; compute &lt;code&gt;views_per_day&lt;/code&gt; to compare older vs newer videos fairly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;What I learned&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Scrapping without tools like BrightData is not possible as IP gets blocked, get 403 error etc.&lt;/li&gt;
&lt;li&gt;Learnt unfamiliar n8n nodes like Merge etc.&lt;/li&gt;
&lt;li&gt;Framing the Agent’s output as strict JSON drives consistent downstream automation.
&lt;/li&gt;
&lt;li&gt;Anchoring recommended length to the &lt;strong&gt;top‑quartile median&lt;/strong&gt; yields practical targets that mirror what performs best.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>n8nbrightdatachallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Latency Slayer: a Redis 8 semantic cache gateway that makes LLMs feel instant</title>
      <dc:creator>Mohit Agnihotri</dc:creator>
      <pubDate>Sun, 10 Aug 2025 17:57:45 +0000</pubDate>
      <link>https://forem.com/mohit_agnihotri_5/latency-slayer-a-redis-8-semantic-cache-gateway-that-makes-llms-feel-instant-2klh</link>
      <guid>https://forem.com/mohit_agnihotri_5/latency-slayer-a-redis-8-semantic-cache-gateway-that-makes-llms-feel-instant-2klh</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/redis-2025-07-23"&gt;Redis AI Challenge&lt;/a&gt;: Real-Time AI Innovators&lt;/em&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%2Foh1cbxuqdrpt0iolgn57.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%2Foh1cbxuqdrpt0iolgn57.png" alt="Cover" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Latency Slayer&lt;/strong&gt; is a tiny Rust reverse-proxy that sits in front of any LLM API.&lt;br&gt;&lt;br&gt;
It uses &lt;strong&gt;embeddings + vector search&lt;/strong&gt; in Redis 8 to detect “repeat-ish” prompts and return a cached answer instantly. New prompts are answered once by the LLM and stored with per-field TTLs, so only the &lt;strong&gt;response&lt;/strong&gt; expires while metadata persists.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why it matters:&lt;/strong&gt; dramatically lower &lt;strong&gt;latency&lt;/strong&gt; and &lt;strong&gt;cost&lt;/strong&gt;, with transparent drop-in integration for any chat or RAG app.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core tricks&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Redis Query Engine + HNSW vectors (COSINE)&lt;/strong&gt; to find semantically similar earlier prompts. &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Hash field expiration&lt;/strong&gt; (&lt;code&gt;HSETEX&lt;/code&gt; / &lt;code&gt;HGETEX&lt;/code&gt;) so we can expire just the “response” field without deleting the whole hash.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Streams&lt;/strong&gt; for real-time hit-rate &amp;amp; latency metrics, rendered in a tiny dashboard.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Video:&lt;/strong&gt; &lt;a href="https://youtu.be/lA-d4WO0Fjg" rel="noopener noreferrer"&gt;https://youtu.be/lA-d4WO0Fjg&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repo:&lt;/strong&gt; &lt;a href="https://github.com/mohitagnihotri/latency_slayer" rel="noopener noreferrer"&gt;https://github.com/mohitagnihotri/latency_slayer&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshots:&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%2F2lr2nexs2lz7q0df5wb9.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%2F2lr2nexs2lz7q0df5wb9.png" alt="Dashboard Screenshot1" width="800" height="472"&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%2Fziiqplm3qxum0xg6ke7s.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%2Fziiqplm3qxum0xg6ke7s.png" alt="Dashboard Screenshot2" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Redis 8
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vector search (HNSW, COSINE)&lt;/strong&gt; on a HASH document that stores an embedding field (FP32, 1536-d from OpenAI text-embedding-3-small).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-field TTL on hashes&lt;/strong&gt;: &lt;code&gt;HSETEX&lt;/code&gt; to set the response field and its TTL in a single step; &lt;code&gt;HGETEX&lt;/code&gt; to read and optionally refresh TTLs. This gives granular cache lifetimes without deleting other fields (like usage or model metadata).
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Streams&lt;/strong&gt;: &lt;code&gt;XADD analytics:cache&lt;/code&gt; per request; the dashboard subscribes and renders hit rate, token savings, and latency deltas in real time.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data model (simplified)
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;cache:{fingerprint}&lt;/code&gt; → Hash fields: &lt;code&gt;prompt&lt;/code&gt;, &lt;code&gt;resp&lt;/code&gt;, &lt;code&gt;meta&lt;/code&gt;, &lt;code&gt;usage&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt; (with &lt;code&gt;resp&lt;/code&gt; having its own TTL)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;vec:{fingerprint}&lt;/code&gt; → Vector field + tags (&lt;code&gt;model&lt;/code&gt;, &lt;code&gt;route&lt;/code&gt;, &lt;code&gt;user&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Stream: &lt;code&gt;analytics:cache&lt;/code&gt; with &lt;code&gt;{event, hit, latency_ms, tokens_saved}&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Why Redis 8?
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; field-level expiration commands on hashes make cache lifecycle clean and safe.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New&lt;/strong&gt; int8 vectors keep memory low and speed high.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Battle-tested&lt;/strong&gt; Streams/PubSub give us real-time observability with a tiny footprint.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What’s next
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Prefetch: predict likely next prompts and warm them proactively.&lt;/li&gt;
&lt;li&gt;Hybrid filters: combine vector similarity + tags (model/route) for stricter cache hits.&lt;/li&gt;
&lt;li&gt;Cold-start tuning: adapt hit threshold by route and user cohort.&lt;/li&gt;
&lt;li&gt;Currently storing FP32 vectors for simplicity; INT8 quantization is planned to lower memory and speed up search&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redischallenge</category>
      <category>devchallenge</category>
      <category>database</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
