<?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>DEV Community: Amit Wani</title>
    <description>The latest articles on DEV Community by Amit Wani (@mtwn105).</description>
    <link>https://dev.to/mtwn105</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F728995%2Fc44c0cc5-8fbf-4c42-ab4f-e1957baeb03a.jpeg</url>
      <title>DEV Community: Amit Wani</title>
      <link>https://dev.to/mtwn105</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mtwn105"/>
    <language>en</language>
    <item>
      <title>ContractBridge: Let Local Gemma Repair API Drift Without Trusting It Blindly</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Sun, 25 Oct 2026 21:15:50 +0000</pubDate>
      <link>https://dev.to/mtwn105/contractbridge-let-local-gemma-repair-api-drift-without-trusting-it-blindly-4fk9</link>
      <guid>https://dev.to/mtwn105/contractbridge-let-local-gemma-repair-api-drift-without-trusting-it-blindly-4fk9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/hacktoberfest-week3-2026-10-19"&gt;Hacktoberfest Open-Source AI Challenge Week 3: Slow and Steady&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Imagine an API provider releases v2. The route moves, request fields are rearranged, and the response uses a different status value. Your client has not changed, but checkout is suddenly broken.&lt;/p&gt;

&lt;p&gt;Fixing this usually means comparing two contracts, writing a temporary adapter, testing it, patching the client, and remembering to remove the adapter later. It is repetitive work at exactly the moment when you are already under pressure.&lt;/p&gt;

&lt;p&gt;I built ContractBridge to handle the repetitive parts while leaving the important decision with a person. Gemma suggests how the old and new contracts fit together. Regular code checks that suggestion, builds both fixes, and tests them. Nothing goes live until someone reviews and approves it.&lt;/p&gt;

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

&lt;p&gt;ContractBridge sits between an application and an API it depends on. Most of the time it simply passes requests through. When the provider stops matching the contract the client expects, it records the mismatch and starts a repair workflow.&lt;/p&gt;

&lt;p&gt;One approved declarative mapping drives two outputs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a temporary compatibility bridge that can restore new requests;&lt;/li&gt;
&lt;li&gt;a permanent client patch, plus a draft pull request when GitHub is configured.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The temporary bridge does not disappear just because a patch was merged. ContractBridge waits until the matching version is actually deployed and a direct test succeeds without translation. Only then can it retire the workaround.&lt;/p&gt;

&lt;p&gt;That cleanup is one of my favorite parts. The bridge has a clear exit instead of becoming another forgotten compatibility layer.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft75uckgb5n2f4en5ltj4.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ft75uckgb5n2f4en5ltj4.png" alt="ContractBridge architecture: a scoped gateway, a human-approved repair loop, and two repairs from one mapping" width="800" height="560"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 1. A scoped gateway detects drift. Local Gemma proposes a mapping, deterministic checks verify it, and a human controls activation. One approved mapping drives the temporary and permanent repairs.&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;&lt;strong&gt;Video demo:&lt;/strong&gt;&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/nVuJo8_GQ3Q" width="710" height="399"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The demo is intentionally local and synthetic. It contains no production traffic, customer data, or payment data. A small shopping client expects &lt;code&gt;POST /v1/orders&lt;/code&gt;; the provider is switched to a v2 contract with &lt;code&gt;POST /v2/purchases&lt;/code&gt;, nested buyer data, renamed array fields, a nested response, and a changed lifecycle enum.&lt;/p&gt;

&lt;p&gt;From the repository root, the complete example starts with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/bootstrap.sh &lt;span class="nt"&gt;--example&lt;/span&gt; shopping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Step 1: Prove the unchanged client works against v1
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;examples/provider/provider.json&lt;/code&gt; set to &lt;code&gt;{"version":"v1"}&lt;/code&gt;, the unchanged client placed synthetic order &lt;code&gt;ord-7001&lt;/code&gt; successfully.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w42x0boetdq2yneo3p4.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F6w42x0boetdq2yneo3p4.png" alt="The unchanged shopping client confirms order ord-7001 against the v1 provider" width="800" height="603"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 2. The unchanged example client completes a real request against the synthetic v1 provider. No payment is collected.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2: Switch only the provider to v2
&lt;/h3&gt;

&lt;p&gt;I changed the provider configuration to:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"v2"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The same checkout then failed. The cart stayed intact, and the failed POST was not automatically replayed.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs01qrqglkv3cug3oh91b.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fs01qrqglkv3cug3oh91b.png" alt="The unchanged shopping client reports that checkout is temporarily unavailable after the provider switches to v2" width="799" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure 3. Provider v2 breaks the unchanged client. ContractBridge records the failure instead of pretending the request is safe to retry.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 3: See what ContractBridge caught
&lt;/h3&gt;

&lt;p&gt;The operator console showed the failed request and the 404 from the provider. Nothing had been repaired or rerouted yet. This was simply the starting point for the investigation.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4sgrd04jd1ugddx63kly.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4sgrd04jd1ugddx63kly.png" alt="ContractBridge operator console showing the newly detected degraded incident" width="799" height="564"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 4. The incident as it appeared before ContractBridge proposed a repair.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 4: Check the Sentry issue
&lt;/h3&gt;

&lt;p&gt;The same failure also appeared in Sentry as &lt;code&gt;UpstreamContractDrift&lt;/code&gt;. Sentry kept the useful context, including the monitored API transaction and the exact application frame, while ContractBridge's privacy policy withheld the exception details.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xxmszihpge48wixz28i.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F4xxmszihpge48wixz28i.png" alt="Sentry showing the UpstreamContractDrift issue with privacy-safe exception details and the ContractBridge application frame" width="800" height="789"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 5. Sentry shows where the contract failure happened without exposing the request or response payload.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 5: Review Gemma's proposed repair
&lt;/h3&gt;

&lt;p&gt;Gemma ran locally and suggested six mapping rules for the changed route, fields, arrays, and status value. ContractBridge turned that suggestion into a candidate and ran 12 checks in a locked-down container before showing it to me.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq0te8v10ubandvhf2km.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fiq0te8v10ubandvhf2km.png" alt="ContractBridge review screen with the verified candidate, 12 passing isolated tests, activity history, and six mapping rules" width="800" height="789"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 6. Gemma suggested the mapping, then regular code built and tested the candidate before review.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The test container had no network access or Docker socket, and it could not write to its root filesystem. This kept the model's suggestion inside a narrow, testable path.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 6: Send a correction back to Gemma
&lt;/h3&gt;

&lt;p&gt;I rejected the first candidate because I wanted the &lt;code&gt;PLACED&lt;/code&gt; to &lt;code&gt;CONFIRMED&lt;/code&gt; status change called out clearly. ContractBridge saved my feedback and asked Gemma to revise the mapping.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdnn6h7kik6516is81d5.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcdnn6h7kik6516is81d5.png" alt="Operator review panel showing the requested semantic correction while Gemma revises the mapping" width="800" height="135"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 7. Rejection is recorded feedback, not an override that bypasses verification.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The revision came back through the same review screen and had to pass the checks again.&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 7: Approve the repair
&lt;/h3&gt;

&lt;p&gt;Once the revised mapping looked right, I approved it. ContractBridge activated the temporary bridge and prepared a permanent application patch. I had not connected GitHub for this demo, so it produced the patch locally instead of pretending it had opened a pull request.&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzhfmkqc1bjkflp91p6t1.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fzhfmkqc1bjkflp91p6t1.png" alt="ContractBridge console showing an active runtime bridge, a verified permanent repair, recorded approval, and 12 passing isolated checks" width="800" height="777"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 8. The approved mapping now powers the temporary bridge and the permanent patch.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 8: Retry with the unchanged client
&lt;/h3&gt;

&lt;p&gt;With the provider still on v2, the unchanged client placed a new order through the active bridge. The application confirmed synthetic order &lt;code&gt;ord-7002&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0vrp3iskhmlj7noe6mt.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fl0vrp3iskhmlj7noe6mt.png" alt="The unchanged shopping client confirms order ord-7002 through the active v2 compatibility bridge" width="800" height="603"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 9. A new request succeeds through the approved bridge. This is not a replay of the failed POST.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The part I cared about most was the full sequence. The client worked on v1, failed when only the provider changed, and worked again after I reviewed the repair. The failed order was never replayed. Gemma never produced code for the system to execute. Rejecting the first suggestion led to a new suggestion, not a shortcut around the review step.&lt;/p&gt;

&lt;p&gt;Because GitHub was not connected for this demo, ContractBridge produced a patch I could download and inspect. It did not claim to have opened a pull request.&lt;/p&gt;

&lt;p&gt;I also tried cases that should not be repaired automatically. In one of them, v2 required a delivery method that the old client never supplied. ContractBridge left the incident waiting for a person instead of inventing a value to make the test pass.&lt;/p&gt;

&lt;p&gt;When you are finished, stop the example with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./scripts/stop.sh &lt;span class="nt"&gt;--example&lt;/span&gt; shopping
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;

&lt;p&gt;The project is MIT licensed and available at &lt;a href="https://github.com/mtwn105/contractbridge" rel="noopener noreferrer"&gt;github.com/mtwn105/contractbridge&lt;/a&gt;.&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/contractbridge" rel="noopener noreferrer"&gt;
        contractbridge
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Self-healing API compatibility control plane: detects contract drift, verifies a local Gemma mapping, restores traffic, and prepares a permanent client fix.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ContractBridge&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Recover now. Fix permanently. Remove the workaround when production is healthy.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;ContractBridge is a plug-in control plane for API contract drift. A registered
application sends an API call through its scoped gateway. When the upstream
response no longer matches the contract that application expects, ContractBridge
records an incident and asks a local open-weight Gemma model for a constrained
declarative mapping.&lt;/p&gt;
&lt;p&gt;One verified mapping drives two repairs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Temporary runtime repair:&lt;/strong&gt; a deterministic compatibility proxy can restore
traffic only after an operator approves the verified candidate, isolated tests
pass, and the built artifact matches those approved inputs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Permanent code repair:&lt;/strong&gt; the same mapping produces a reviewable client patch
and, when configured, a real GitHub draft pull request.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The temporary rule remains active after merge. It is retired only after the
registered deployment reports the matching commit and authorized synthetic probes
show that the deployed client works with translation bypassed.&lt;/p&gt;
&lt;p&gt;The core…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/contractbridge" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Detect drift without replaying the failed request
&lt;/h3&gt;

&lt;p&gt;Every integration registers the client-expected OpenAPI contract, an operator-allowed upstream origin, and a selected operation. The gateway forwards calls directly until the response no longer matches what the client expects.&lt;/p&gt;

&lt;p&gt;A failed business POST is not silently retried. ContractBridge records the mismatch and starts investigating, but it treats the original request as failed or unknown. A broken response does not prove that an upstream side effect never happened, so an automatic replay could create a duplicate order.&lt;/p&gt;

&lt;p&gt;ContractBridge uses &lt;a href="https://github.com/oasdiff/oasdiff" rel="noopener noreferrer"&gt;&lt;code&gt;oasdiff&lt;/code&gt;&lt;/a&gt; to find structural breaking changes, then applies its own limited schema analysis. A diff can show that &lt;code&gt;state&lt;/code&gt; became &lt;code&gt;status&lt;/code&gt;, but it cannot decide whether &lt;code&gt;PLACED&lt;/code&gt; and &lt;code&gt;CONFIRMED&lt;/code&gt; mean the same thing to the business.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Ask Gemma for data, not executable code
&lt;/h3&gt;

&lt;p&gt;The semantic step runs locally through Ollama. Gemma sees small excerpts from the two schemas and sanitized examples, then returns a structured transformation plan.&lt;/p&gt;

&lt;p&gt;The plan can describe supported operations such as field copies, renames, nesting, flattening, array-item mappings, reviewed constants, and reviewed enum translations. It cannot include arbitrary Python, shell commands, or network instructions.&lt;/p&gt;

&lt;p&gt;This boundary is deliberate: the model proposes data; trusted code interprets it. Generated model code is never executed.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Verify in an isolated container
&lt;/h3&gt;

&lt;p&gt;The candidate must validate against both API schemas and independent synthetic fixtures. Trusted templates generate the adapter and tests. A worker builds the exact inputs and runs compile, fixture, and HTTP behavior checks in an isolated container.&lt;/p&gt;

&lt;p&gt;Mocks and fixtures are still limited evidence. A passing fixture proves that one example works, not that every valid payload will work. That is why ContractBridge keeps the contract comparison, example fixtures, model suggestion, and build result as separate pieces of evidence.&lt;/p&gt;

&lt;p&gt;Model behavior can change too. I keep the model details, validation results, artifact hashes, and failures so I can rerun the same cases after changing the model or its instructions.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Make review bind to the exact candidate
&lt;/h3&gt;

&lt;p&gt;The review screen brings the contract changes, field mappings, fixtures, test result, and open questions together. Approval is tied to that exact candidate, so an old approval cannot activate a newly generated one.&lt;/p&gt;

&lt;p&gt;Rejecting a candidate is useful feedback, not a dead end. The next Gemma attempt receives the review comment, but it still has to pass the same checks and return for approval.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Use Temporal for the long wait
&lt;/h3&gt;

&lt;p&gt;The repair is not one quick request. It may wait for review, retry a temporary model failure, prepare a draft pull request, wait for deployment, and finally check whether the client works without the bridge. &lt;a href="https://docs.temporal.io/" rel="noopener noreferrer"&gt;Temporal&lt;/a&gt; keeps that process moving even if a worker restarts.&lt;/p&gt;

&lt;p&gt;The local Compose stack uses Temporal's persistent development server for demonstration. It is not presented as a production Temporal deployment.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Retire the bridge with evidence
&lt;/h3&gt;

&lt;p&gt;The same approved mapping produces the runtime bridge and the permanent patch, keeping them from drifting into two unrelated interpretations. ContractBridge never merges or deploys the patch itself.&lt;/p&gt;

&lt;p&gt;Merge is only intent. Retirement requires deployment evidence for the expected commit and successful synthetic probes with translation bypassed. If those checks fail, the bridge stays active and the failure remains visible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Does Open Innovation Matter?
&lt;/h2&gt;

&lt;p&gt;API contracts can describe private endpoints, internal field names, and business rules. Running &lt;a href="https://ai.google.dev/gemma" rel="noopener noreferrer"&gt;Gemma&lt;/a&gt; locally through Ollama lets the semantic proposal happen without sending those contracts to a hosted inference API.&lt;/p&gt;

&lt;p&gt;Local execution is only part of the value. The prompt schema, validator, interpreter, fixtures, and evaluation cases are inspectable. Another compatible model can be tested against the same dataset instead of being trusted because its name changed on an API endpoint.&lt;/p&gt;

&lt;p&gt;I describe Gemma as &lt;strong&gt;open-weight&lt;/strong&gt;. ContractBridge itself is MIT licensed, while the Gemma weights are downloaded separately under &lt;a href="https://ai.google.dev/gemma/terms" rel="noopener noreferrer"&gt;Gemma's terms&lt;/a&gt;. Keeping that distinction clear matters.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lazy Payoff
&lt;/h2&gt;

&lt;p&gt;ContractBridge removes a sequence of mechanical chores from the incident path: collecting the two contracts, drafting mappings, generating two repair forms, building a test bundle, preserving evidence, and checking when the workaround can be retired.&lt;/p&gt;

&lt;p&gt;One reviewed mapping becomes both the temporary bridge and the permanent patch. The operator still makes the semantic decision, but does not have to hand-write two translators or remember a cleanup ticket later.&lt;/p&gt;

&lt;p&gt;The bridge adds an extra hop, so it is meant to be temporary. The permanent patch is what removes that cost and returns the application to a normal direct connection.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prize Categories
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Gemma:&lt;/strong&gt; Gemma handles the part that needs semantic judgment while the rest of the repair stays testable and reviewable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Temporal:&lt;/strong&gt; Temporal keeps the repair moving through retries, human review, deployment, and eventual bridge removal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Best Use of Sentry:&lt;/strong&gt; Sentry catches the contract failure and points back to the application code while ContractBridge keeps private payload details out of the event.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Limits I Want to Keep Visible
&lt;/h2&gt;

&lt;p&gt;The current engine handles one selected JSON POST operation within a bounded OpenAPI 3.0/3.1 subset. Authentication changes, missing business data, undeclared semantics, arbitrary source rewriting, and unsupported schemas stop for human action.&lt;/p&gt;

&lt;p&gt;Permanent repair currently targets a registered declarative Python client. The GitHub path creates a draft PR when configured; the demonstrated run did not configure GitHub and therefore did not create one.&lt;/p&gt;

&lt;p&gt;Most importantly, this is a controlled local demonstration with synthetic fixtures. Passing those fixtures is not proof of universal compatibility, production reliability, or semantic correctness. The useful result is narrower: a repeatable way to let a local model help with the ambiguous part while deterministic checks and a human retain authority over production behavior.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>hf26challenge</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>DecipherIt: Building a NotebookLM-Inspired AI Research Assistant powered by Bright Data</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Sun, 25 May 2025 22:13:33 +0000</pubDate>
      <link>https://dev.to/mtwn105/decipherit-building-a-notebooklm-inspired-ai-research-assistant-powered-by-bright-data-ckf</link>
      <guid>https://dev.to/mtwn105/decipherit-building-a-notebooklm-inspired-ai-research-assistant-powered-by-bright-data-ckf</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;/p&gt;

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

&lt;p&gt;&lt;strong&gt;DecipherIt&lt;/strong&gt; is a cutting-edge AI-powered research assistant inspired by &lt;strong&gt;Google NotebookLM&lt;/strong&gt; that revolutionizes how researchers, students, and professionals explore, analyze, and synthesize information from the web. The platform transforms any combination of documents, URLs, or topics into comprehensive research notebooks complete with AI-generated summaries, interactive Q&amp;amp;A capabilities, audio overviews, visual mindmaps, and automatically generated FAQs.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem DecipherIt Solves
&lt;/h3&gt;

&lt;p&gt;Traditional research is time-consuming and fragmented. Researchers often struggle with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Information Overload&lt;/strong&gt;: Sifting through countless sources manually&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geo-restrictions&lt;/strong&gt;: Unable to access content from different regions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Detection&lt;/strong&gt;: Getting blocked when trying to scrape valuable data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesis Challenges&lt;/strong&gt;: Difficulty connecting insights across multiple sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Converting research into different formats for various audiences&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;DecipherIt addresses these challenges by leveraging &lt;strong&gt;Bright Data's MCP Server&lt;/strong&gt; to provide unrestricted, intelligent web access combined with advanced AI agents that can understand, synthesize, and present information in multiple formats.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;p&gt;🔬 &lt;strong&gt;Deep Research&lt;/strong&gt; - Conduct thorough research on any topic with AI-assisted analysis and synthesis&lt;br&gt;
🔍 &lt;strong&gt;Multi-Source Research&lt;/strong&gt; - Seamlessly integrate documents, URLs, and manual text into unified research spaces&lt;br&gt;
🤖 &lt;strong&gt;AI-Powered Summaries&lt;/strong&gt; - Generate comprehensive, well-structured research analyses using advanced AI agents&lt;br&gt;
💬 &lt;strong&gt;Interactive Q&amp;amp;A&lt;/strong&gt; - Chat with your research materials using natural language queries&lt;br&gt;
🎧 &lt;strong&gt;Audio Overviews&lt;/strong&gt; - AI-generated podcast-style audio summaries with multiple voices&lt;br&gt;
❓ &lt;strong&gt;Smart FAQ Generation&lt;/strong&gt; - Automatically create relevant FAQs from your research content&lt;br&gt;
🧠 &lt;strong&gt;Visual Mindmaps&lt;/strong&gt; - Generate interactive, hierarchical mindmaps to visualize research structure and connections&lt;br&gt;
🌐 &lt;strong&gt;Global Web Access&lt;/strong&gt; - Bypass geo-restrictions and bot detection using Bright Data's infrastructure&lt;/p&gt;
&lt;h3&gt;
  
  
  🔍 &lt;strong&gt;Detailed Feature Overview&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;🔬 Deep Research&lt;/strong&gt;&lt;br&gt;
DecipherIt's AI agents conduct comprehensive research by strategically planning data collection, discovering diverse sources through Bright Data's global search capabilities, and synthesizing information from multiple perspectives. The system can research any topic from current events to academic subjects, providing thorough analysis that rivals human researchers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🔍 Multi-Source Research&lt;/strong&gt;&lt;br&gt;
Users can combine various input types in a single research project: upload documents (PDF, DOCX, PPTX, XLSX), add custom URLs for specific web content, input manual text for direct analysis, or simply enter topics for AI-driven discovery. All sources are processed and integrated into a unified research space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🤖 AI-Powered Summaries&lt;/strong&gt;&lt;br&gt;
Specialized CrewAI agents work together to create comprehensive research summaries. The Research Analyst synthesizes information from all sources, while the Content Writer crafts engaging, well-structured analyses that highlight key insights, trends, and connections across the research material.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;💬 Interactive Q&amp;amp;A&lt;/strong&gt;&lt;br&gt;
Using vector embeddings and semantic search through Qdrant database, users can ask natural language questions about their research content. The system provides contextual answers by retrieving relevant information from all processed sources, enabling deep exploration of the research material.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🎧 Audio Overviews&lt;/strong&gt;&lt;br&gt;
On-demand feature that transforms research into engaging podcast-style audio content. The Podcast Script Generator agent creates conversational scripts, which are then converted to high-quality audio using LemonFox TTS with multiple AI voices, making research accessible in audio format.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;❓ Smart FAQ Generation&lt;/strong&gt;&lt;br&gt;
AI agents automatically analyze research content to generate relevant, insightful questions and comprehensive answers. This feature helps users understand key aspects of their research topic and provides quick access to important information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧠 Visual Mindmaps&lt;/strong&gt;&lt;br&gt;
The Mindmap Creator agent analyzes research structure to generate interactive, hierarchical visualizations with up to 5 levels of depth. Built with react-mindmap-visualiser, these mindmaps help users understand complex topics at a glance and navigate research relationships visually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🌐 Global Web Access&lt;/strong&gt;&lt;br&gt;
Powered by Bright Data's MCP Server, DecipherIt bypasses geo-restrictions and bot detection to access content from anywhere in the world. This ensures comprehensive research coverage and access to diverse, authoritative sources that traditional scraping methods cannot reach.&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;🚀 &lt;strong&gt;Live Demo&lt;/strong&gt;: &lt;a href="https://decipherit.xyz" rel="noopener noreferrer"&gt;https://decipherit.xyz&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Demo Credentials&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email: &lt;a href="mailto:demo@dev.to"&gt;demo@dev.to&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Password: demodemo@123&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📂 &lt;strong&gt;GitHub Repository&lt;/strong&gt;: &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/decipher-research-agent" rel="noopener noreferrer"&gt;
        decipher-research-agent
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Turn topics, links, and files into AI-generated research notebooks — summarize, explore, and ask anything.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🔍 DecipherIt - AI-Powered Research Assistant&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b5efb4a4a2fc0db3c09f48d5d072813603a59bcfde4985f8aff9ffcfff8adca2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446563697068657249742d41492532305265736561726368253230417373697374616e742d626c75653f7374796c653d666f722d7468652d6261646765266c6f676f3d646174613a696d6167652f7376672b786d6c3b6261736536342c50484e325a79423361575230614430694d6a51694947686c6157646f644430694d6a516949485a705a58644362336739496a41674d4341794e4341794e4349675a6d6c7362443069626d39755a53496765473173626e4d39496d6830644841364c79393364336375647a4d7562334a6e4c7a49774d44417663335a6e496a344b50484268644767675a4430695454457949444a4d4d544d754d446b674f4334794e6b77794d4341355444457a4c6a4135494445314c6a63305444457949444979544445774c6a6b78494445314c6a6330544451674f5577784d4334354d5341344c6a49325444457949444a614969426d6157787350534a6a64584a795a57353051323973623349694c7a344b5043397a646d632b"&gt;&lt;img src="https://camo.githubusercontent.com/b5efb4a4a2fc0db3c09f48d5d072813603a59bcfde4985f8aff9ffcfff8adca2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446563697068657249742d41492532305265736561726368253230417373697374616e742d626c75653f7374796c653d666f722d7468652d6261646765266c6f676f3d646174613a696d6167652f7376672b786d6c3b6261736536342c50484e325a79423361575230614430694d6a51694947686c6157646f644430694d6a516949485a705a58644362336739496a41674d4341794e4341794e4349675a6d6c7362443069626d39755a53496765473173626e4d39496d6830644841364c79393364336375647a4d7562334a6e4c7a49774d44417663335a6e496a344b50484268644767675a4430695454457949444a4d4d544d754d446b674f4334794e6b77794d4341355444457a4c6a4135494445314c6a63305444457949444979544445774c6a6b78494445314c6a6330544451674f5577784d4334354d5341344c6a49325444457949444a614969426d6157787350534a6a64584a795a57353051323973623349694c7a344b5043397a646d632b" alt="DecipherIt Logo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Transform your research process with AI-powered intelligence&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://nextjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3e2e7f1311e2c973fbaf78b931c58686f23339932f390f135088a5c1b41cc206/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4e6578742e6a732d31352e332e322d626c61636b3f7374796c653d666c61742d737175617265266c6f676f3d6e6578742e6a73" alt="Next.js"&gt;&lt;/a&gt;
&lt;a href="https://reactjs.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/dceb2c2665087de4b8fab7799a2ee92eee3487a153196f0062da9410b74bf717/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f52656163742d31392e302e302d626c75653f7374796c653d666c61742d737175617265266c6f676f3d7265616374" alt="React"&gt;&lt;/a&gt;
&lt;a href="https://python.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/807252c6cff24d131a3381ca3bfb31e16b34adfc533e605432a3ebffd29ff466/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f507974686f6e2d332e31322d626c75653f7374796c653d666c61742d737175617265266c6f676f3d707974686f6e" alt="Python"&gt;&lt;/a&gt;
&lt;a href="https://fastapi.tiangolo.com/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/52e7a33de1924de56694007a2814ffa098b57d026f9c0f1720cd457beae66cb5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f466173744150492d4c61746573742d677265656e3f7374796c653d666c61742d737175617265266c6f676f3d66617374617069" alt="FastAPI"&gt;&lt;/a&gt;
&lt;a href="https://typescriptlang.org/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b995d8224e72a0fa717f2cdb567c2c5c47320652afbf91c370e227cfb94c542b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f547970655363726970742d352e302d626c75653f7374796c653d666c61742d737175617265266c6f676f3d74797065736372697074" alt="TypeScript"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://decipherit.xyz" rel="nofollow noopener noreferrer"&gt;🚀 Live Demo&lt;/a&gt; • &lt;a href="https://github.com/mtwn105/decipher-research-agent#installation" rel="noopener noreferrer"&gt;🛠️ Installation&lt;/a&gt; • &lt;a href="https://github.com/mtwn105/decipher-research-agent#contributing" rel="noopener noreferrer"&gt;🤝 Contributing&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;⭐ Star on GitHub!&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;a href="https://www.star-history.com/#mtwn105/decipher-research-agent&amp;amp;Date" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/5b14edc45e6c157a728256b8cebf2bdc5b5960a12614f018e1ffbe3d92c37c8a/68747470733a2f2f6170692e737461722d686973746f72792e636f6d2f7376673f7265706f733d6d74776e3130352f64656369706865722d72657365617263682d6167656e7426747970653d44617465" alt="Star History Chart"&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Overview&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;DecipherIt is a cutting-edge AI-powered research assistant inspired by &lt;strong&gt;Google NotebookLM&lt;/strong&gt; that revolutionizes how researchers, students, and professionals explore, analyze, and synthesize information from the web. The platform transforms any combination of documents, URLs, or topics into comprehensive research notebooks complete with AI-generated summaries, interactive Q&amp;amp;A capabilities, audio overviews, visual mindmaps, and automatically generated FAQs.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;The Problem DecipherIt Solves&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Traditional research is time-consuming and fragmented. Researchers often struggle with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Information Overload&lt;/strong&gt;: Sifting through countless sources manually&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Geo-restrictions&lt;/strong&gt;: Unable to access content from different regions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bot Detection&lt;/strong&gt;: Getting blocked when trying to scrape valuable data&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesis Challenges&lt;/strong&gt;: Difficulty connecting insights across multiple sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accessibility&lt;/strong&gt;: Converting research into different formats for various audiences&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;DecipherIt addresses these challenges by leveraging…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/decipher-research-agent" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Video Demo
&lt;/h3&gt;

&lt;p&gt;📺 Watch DecipherIt in action:&lt;/p&gt;

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

&lt;p&gt;The video demonstrates:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Setting up a new research notebook&lt;/li&gt;
&lt;li&gt;Adding multiple sources (URLs, documents, text)&lt;/li&gt;
&lt;li&gt;AI-powered research and analysis process&lt;/li&gt;
&lt;li&gt;Exploring generated summaries and insights&lt;/li&gt;
&lt;li&gt;Using interactive features like Q&amp;amp;A and mindmaps&lt;/li&gt;
&lt;li&gt;Generating audio overviews&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Screenshots
&lt;/h3&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%2Frorif1inudcgue2pu7n6.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%2Frorif1inudcgue2pu7n6.png" alt="DecipherIt-LandingPage"&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%2Fu51mv10ryf7mkgs703lh.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%2Fu51mv10ryf7mkgs703lh.png" alt="DecipherIt-Dashboard"&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%2Fbc60xvomh309yudeqyis.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%2Fbc60xvomh309yudeqyis.png" alt="DecipherIt-Create-New-Notebook"&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%2Fnsdr4jb243i3asb4tiz0.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%2Fnsdr4jb243i3asb4tiz0.png" alt="DecipherIt-Create-New-Notebook-2"&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%2Ffxmyqtmyaijdmnhrdyqi.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%2Ffxmyqtmyaijdmnhrdyqi.png" alt="DecipherIt-Notebook"&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%2F13zvdoh5v79ea8ywi2zn.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%2F13zvdoh5v79ea8ywi2zn.png" alt="DecipherIt-Notebook-Summary"&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%2Fc2ykro5wauyzf92c3v1j.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%2Fc2ykro5wauyzf92c3v1j.png" alt="DecipherIt-Notebook-Audio"&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%2Fb1athxv41vkommi396cv.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%2Fb1athxv41vkommi396cv.png" alt="DecipherIt-Notebook-Chat"&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%2F0wzx169ezx8896ywmhiw.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%2F0wzx169ezx8896ywmhiw.png" alt="DecipherIt-Notebook-FAQ"&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%2Fi71kzjril590mpro8me0.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%2Fi71kzjril590mpro8me0.png" alt="DecipherIt-Notebook-Mindmap"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Input Your Research Sources&lt;/strong&gt;: Enter any topic, upload documents, add custom URLs, or input manual text&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Planning&lt;/strong&gt;: The system creates a strategic research plan using specialized AI agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Discovery&lt;/strong&gt;: Bright Data's search engine finds relevant sources globally&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligent Scraping&lt;/strong&gt;: Bright Data extracts content and converts it to clean markdown format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI Analysis&lt;/strong&gt;: Multiple AI agents analyze, synthesize, and create comprehensive summaries&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-Format Output&lt;/strong&gt;: Get research summaries, FAQs, visual mindmaps, and podcast-style audio overviews&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Frontend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15&lt;/strong&gt; with App Router&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;React 19&lt;/strong&gt; with concurrent features&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TypeScript 5&lt;/strong&gt; for type safety&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tailwind CSS 4&lt;/strong&gt; for styling&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shadcn/ui&lt;/strong&gt; component library&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Auth&lt;/strong&gt; for authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;react-mindmap-visualiser&lt;/strong&gt; for interactive mindmap visualization&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Backend
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Python 3.12&lt;/strong&gt; with FastAPI&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CrewAI&lt;/strong&gt; for multi-agent orchestration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bright Data MCP Server&lt;/strong&gt; for web access&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Qdrant&lt;/strong&gt; vector database for semantic search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SQLAlchemy&lt;/strong&gt; with PostgreSQL&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LemonFox TTS&lt;/strong&gt; for audio generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  AI &amp;amp; ML Services
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Google Gemini&lt;/strong&gt; via OpenRouter for LLM capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;OpenAI Embeddings&lt;/strong&gt; for semantic search&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MarkItDown&lt;/strong&gt; for document processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  CrewAI Crews Overview
&lt;/h3&gt;

&lt;p&gt;DecipherIt employs a sophisticated multi-crew architecture powered by &lt;strong&gt;CrewAI&lt;/strong&gt;:&lt;/p&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Planning Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent&lt;/strong&gt;: Web Scraping Strategy Expert&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt;: Generate 3 targeted search queries for comprehensive topic coverage&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Link Discovery Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent&lt;/strong&gt;: Link Discovery Specialist&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt;: Find authoritative sources using Bright Data search engine&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Web Scraping Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent&lt;/strong&gt;: Expert Web Scraping Engineer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt;: Extract clean markdown content from URLs using Bright Data scraper&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Research Analysis Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent&lt;/strong&gt;: Senior Research Analyst&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt;: Synthesize multi-source data into comprehensive research insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Content Creation Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt;: Research Analyst + Content Writer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks&lt;/strong&gt;: Create engaging blog posts + Generate 10 detailed FAQs&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Audio Overview Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt;: Research Analyst + Conversation Planner + Script Writer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks&lt;/strong&gt;: Analyze content + Plan conversation + Generate 4-5 minute podcast transcript&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Mindmap Generation Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agents&lt;/strong&gt;: Content Analyzer + Mindmap Creator&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tasks&lt;/strong&gt;: Identify hierarchical themes + Build interactive visualizations (up to 5 levels)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  &lt;strong&gt;Chat Response Crew&lt;/strong&gt;
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Agent&lt;/strong&gt;: Decipher (Analytical Assistant)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Task&lt;/strong&gt;: Answer questions using vector search and chat context with source citations&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Architecture
&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%2Fg2tf92be6yvkqj1semxd.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%2Fg2tf92be6yvkqj1semxd.png" alt="Decipher-It Architecture"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Used Bright Data's Infrastructure
&lt;/h2&gt;

&lt;p&gt;Bright Data's &lt;strong&gt;&lt;a href="https://github.com/brightdata-com/brightdata-mcp" rel="noopener noreferrer"&gt;MCP (Model Context Protocol) Server&lt;/a&gt;&lt;/strong&gt; is the backbone of DecipherIt's web access capabilities. Here's how I integrated it:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Official MCP Server Integration&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;mcp&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StdioServerParameters&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;crewai_tools&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;MCPServerAdapter&lt;/span&gt;

&lt;span class="n"&gt;server_params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;StdioServerParameters&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pnpm&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;dlx&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;@brightdata/mcp&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BRIGHT_DATA_API_TOKEN&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BROWSER_AUTH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BRIGHT_DATA_BROWSER_AUTH&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  2. &lt;strong&gt;Two Core Tools Implementation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Search Engine Tool&lt;/strong&gt; - For discovering relevant sources:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;web_scraping_link_collector_tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_engine&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Scrape as Markdown Tool&lt;/strong&gt; - For extracting clean content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;web_scraping_tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scrape_as_markdown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. &lt;strong&gt;Multi-Agent Workflow&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I created specialized CrewAI agents that leverage Bright Data's tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Link Collector Agent&lt;/strong&gt;: Uses &lt;code&gt;search_engine&lt;/code&gt; to find relevant sources based on research topics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Scraper Agent&lt;/strong&gt;: Uses &lt;code&gt;scrape_as_markdown&lt;/code&gt; to extract clean, structured content from discovered URLs&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Parallel Processing for Scale&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Execute multiple scraping tasks in parallel
&lt;/span&gt;&lt;span class="n"&gt;web_scraping_tasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;web_scraping_tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;web_scraping_crew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;current_time&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;web_scraping_results&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gather&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;web_scraping_tasks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. &lt;strong&gt;Data Processing &amp;amp; AI Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here's how we process the scraped data and integrate it with our AI agents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Process scraped content for AI analysis
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;integrate_scraped_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;web_scraping_results&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;scraped_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

    &lt;span class="c1"&gt;# Extract clean content from Bright Data results
&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;links&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;web_scraping_results&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;scraped_data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Clean markdown format
&lt;/span&gt;            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;title&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="c1"&gt;# Create vector embeddings for semantic search
&lt;/span&gt;    &lt;span class="n"&gt;embeddings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;create_embeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;scraped_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Store in Qdrant vector database
&lt;/span&gt;    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;store_in_vector_db&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scraped_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Trigger AI analysis crew
&lt;/span&gt;    &lt;span class="n"&gt;research_result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;research_content_crew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kickoff_async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;scraped_data&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;scraped_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;current_time&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;strftime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%Y-%m-%d %H:%M:%S&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;research_result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Frontend integration with React and TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Research hook for managing AI-powered research&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useResearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;research&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setResearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Research&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;startResearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;sources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResearchSource&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/research&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;sources&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nf"&gt;setResearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Research failed:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;finally&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;setIsLoading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;research&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isLoading&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;startResearch&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. &lt;strong&gt;Seamless Integration with AI Pipeline&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The scraped data from Bright Data flows seamlessly into DecipherIt's multi-layered AI processing system:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Immediate Processing:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vector embeddings&lt;/strong&gt; created using OpenAI embeddings and stored in Qdrant for semantic search capabilities&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Contextual analysis&lt;/strong&gt; by Research Analyst agents to synthesize information from multiple sources&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic FAQ generation&lt;/strong&gt; by analyzing content patterns and extracting key insights&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;On-Demand Generation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Audio script creation&lt;/strong&gt; when users request podcast-style overviews, processed by specialized TTS agents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mindmap structure analysis&lt;/strong&gt; for hierarchical visualization when users want visual representations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Q&amp;amp;A responses&lt;/strong&gt; powered by vector similarity search through processed content&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Real-time web data access through Bright Data's infrastructure dramatically enhanced DecipherIt's AI system performance compared to traditional static data approaches:&lt;/p&gt;

&lt;h3&gt;
  
  
  🚀 &lt;strong&gt;Key Improvements&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Real-Time Information Access&lt;/strong&gt;: Unlike AI systems limited by training data cutoffs, DecipherIt's agents access current information including breaking news, latest research papers, and up-to-date statistics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Global Content Discovery&lt;/strong&gt;: Bright Data's search engine enables AI agents to discover diverse perspectives from global sources, access region-specific content, and find specialized publications that static systems cannot reach.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clean Data Processing&lt;/strong&gt;: The Bright Data's tool provides structured, clean content that AI agents process more effectively, improving analysis accuracy and reducing noise.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Enhancements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Interactive Mindmap&lt;/strong&gt;: Enhanced mindmap features with expandable nodes, custom styling, and export options&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Notifications&lt;/strong&gt;: Automated email alerts for research completion and important updates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Mobile App&lt;/strong&gt;: Native mobile experience for research on-the-go&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More Robust Retry Mechanism&lt;/strong&gt;: Improved background task handling with intelligent retry logic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Live Status Updates&lt;/strong&gt;: Real-time agent activity monitoring and progress tracking&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;More Complex Scraping&lt;/strong&gt;: Advanced web scraping capabilities for dynamic content and complex sites&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Social Sign-ins&lt;/strong&gt;: Integration with Google, GitHub, and other social authentication providers&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;DecipherIt demonstrates the power of combining Bright Data's robust web access infrastructure with advanced AI agents. By leveraging the &lt;strong&gt;Bright Data MCP Server&lt;/strong&gt;, we've created a research assistant that can access, analyze, and synthesize information from across the global web without the typical limitations of traditional scraping methods.&lt;/p&gt;

&lt;p&gt;The platform showcases how real-time web data access can dramatically improve AI system performance, making research faster, more comprehensive, and more reliable than ever before.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://dev.to"&gt;DEV.to&lt;/a&gt; and &lt;a href="https://brightdata.com" rel="noopener noreferrer"&gt;Bright Data&lt;/a&gt; for organizing this amazing hackathon that made DecipherIt possible! The opportunity to build with Bright Data's powerful infrastructure has been invaluable in bringing this project to life.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>Vibe Coded AI Stock Analyst with Amazon Q in 1 Hour!</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 12 May 2025 06:13:09 +0000</pubDate>
      <link>https://dev.to/mtwn105/vibe-coded-ai-stock-analyst-with-amazon-q-in-1-hour-20hf</link>
      <guid>https://dev.to/mtwn105/vibe-coded-ai-stock-analyst-with-amazon-q-in-1-hour-20hf</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/aws-amazon-q-v2025-04-30"&gt;Amazon Q Developer "Quack The Code" Challenge&lt;/a&gt;: Crushing the Command Line &amp;amp; Exploring Possibilities&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built 🛠️📈
&lt;/h2&gt;

&lt;p&gt;I have built &lt;strong&gt;Stock Pulse&lt;/strong&gt;. Stock Pulse is a Python tool that analyzes stocks using financial metrics, news trends, and AI-powered sentiment analysis. It provides investment recommendations (BUY, SELL, HOLD) with detailed reasoning based on comprehensive analysis.&lt;/p&gt;

&lt;p&gt;I have used &lt;strong&gt;Amazon Q Developer CLI&lt;/strong&gt; to &lt;strong&gt;Vibe Code&lt;/strong&gt; this in under &lt;strong&gt;1 hour&lt;/strong&gt; without writing a single line of code. I have recorded my full vibe-coding session. It can be found in the Demo section below.&lt;/p&gt;

&lt;h3&gt;
  
  
  Features ✨
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🔍 Analyze multiple stocks at once&lt;/li&gt;
&lt;li&gt;💹 Fetch financial metrics and news data using yfinance&lt;/li&gt;
&lt;li&gt;🤖 Utilize OpenAI's GPT-4o-mini model for intelligent analysis&lt;/li&gt;
&lt;li&gt;📈 Generate investment signals with detailed reasoning&lt;/li&gt;
&lt;li&gt;⚠️ Identify key factors and potential risks&lt;/li&gt;
&lt;li&gt;💻 Command-line interface and Streamlit web UI&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Screenshots 🖼️
&lt;/h3&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%2Fougxkrn6y2n857o0pbbg.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%2Fougxkrn6y2n857o0pbbg.png" alt="Stock Pulse CLI"&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%2Fumpht88n22dgauo0a8qb.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%2Fumpht88n22dgauo0a8qb.png" alt="Stock Pulse CLI - Analysis Output"&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%2Fme433wq7sy3n675z31wn.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%2Fme433wq7sy3n675z31wn.png" alt="Stock Pulse CLI - Stock News"&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%2Fefo2kmlbu4obupkktbsw.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%2Fefo2kmlbu4obupkktbsw.png" alt="Stock Pulse CLI - Metrics"&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%2F6qjr2xzky7kzg0y2a72x.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%2F6qjr2xzky7kzg0y2a72x.png" alt="Stock Pulse UI - Analysis Output 1"&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%2Fjtxfi4kyto2mcjurg1kc.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%2Fjtxfi4kyto2mcjurg1kc.png" alt="Stock Pulse UI - Analysis Output 2"&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%2F7bmtpsacz655a2j9dvg6.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%2F7bmtpsacz655a2j9dvg6.png" alt="Stock Pulse UI - Stock News"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Streamlit Link: &lt;a href="https://stock-pulse-amit-wani.streamlit.app" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;br&gt;
Vibe-Coding Session Demo:&lt;br&gt;
  &lt;iframe src="https://www.youtube.com/embed/FP5kS3BJrLE"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Code Repository 🗃️
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/stock-pulse" rel="noopener noreferrer"&gt;
        stock-pulse
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Feel the pulse of the market with AI-powered stock insights. Vibe Coded with Amazon Q Developer CLI in 1 hour!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Stock Pulse&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Feel the pulse of the market with AI-powered stock insights.&lt;/p&gt;
&lt;p&gt;Vibe Coded with Amazon Q Developer CLI in 1 hour!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Stock Pulse is a Python tool that analyzes stocks using financial metrics, news trends, and AI-powered sentiment analysis. It provides investment recommendations (BUY, SELL, HOLD) with detailed reasoning based on comprehensive analysis.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Analyze multiple stocks at once&lt;/li&gt;
&lt;li&gt;Fetch financial metrics and news data using yfinance&lt;/li&gt;
&lt;li&gt;Utilize OpenAI's GPT-4o-mini model for intelligent analysis&lt;/li&gt;
&lt;li&gt;Generate investment signals with detailed reasoning&lt;/li&gt;
&lt;li&gt;Identify key factors and potential risks&lt;/li&gt;
&lt;li&gt;Command-line interface and Streamlit web UI&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installation&lt;/h2&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Clone the repository:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;git clone https://github.com/yourusername/stock-pulse.git
cd stock-pulse
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Install dependencies using Poetry:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;poetry install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a &lt;code&gt;.env&lt;/code&gt; file with your OpenAI API key:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;cp .env.example .env
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then edit the &lt;code&gt;.env&lt;/code&gt; file to add your OpenAI API key.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Command Line Interface&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Analyze stocks using the command line:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Analyze a single stock&lt;/span&gt;
poetry run python&lt;/pre&gt;…
&lt;/div&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/stock-pulse" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I Used Amazon Q Developer 🤖⚡
&lt;/h2&gt;

&lt;p&gt;I have used &lt;strong&gt;Amazon Q Developer CLI&lt;/strong&gt; to &lt;strong&gt;Vibe Code&lt;/strong&gt; this project in under &lt;strong&gt;1 hour&lt;/strong&gt; without writing a single line of code manually.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Prompt 📝
&lt;/h3&gt;

&lt;p&gt;I kickstarted the development by giving Amazon Q a single, well-crafted prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;i want to create a stock analysis script in python using langchain and langgraph with using openai llm with gpt-4o-mini model. 

use poetry for deps management. poetry is already installed on the system. 

use yfinance tools from langchain for news and price data. use last 1 year price return. 
also use other financial metrics from yfinance like roce, roe, etc. and llm will analyze and return recommendation with signal - BUY,SELL,HOLD and reasoning for it. 

accept list of tickers as argument to the script. 

use poetry to setup project and add deps. dont create pyproject.toml by yourself. 

use python best practices and folder structure for a cli.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Amazon Q responded by generating an organized, ready-to-run CLI project using &lt;strong&gt;Poetry&lt;/strong&gt;, fetching real-time stock data, and integrating GPT-4o-mini for analysis and recommendations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Iterative Development with Q 🔁💡
&lt;/h3&gt;

&lt;p&gt;I continued to use Amazon Q Developer CLI throughout the process for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Debugging and resolving errors by simply pasting the error logs into Q.&lt;/li&gt;
&lt;li&gt;Requesting code refactors and feature enhancements (e.g., adding streamlit UI or news items in output).&lt;/li&gt;
&lt;li&gt;Running Git commands and pushing my code without switching terminals.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Zero Manual Edits ✋❌
&lt;/h3&gt;

&lt;p&gt;From project initialization to the final commit, I &lt;strong&gt;did not write or modify any code manually&lt;/strong&gt;. Every change—big or small—was executed through &lt;strong&gt;Amazon Q Developer CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To show full transparency and the incredible capability of Amazon Q, I’ve recorded my entire coding session, which you can find in the demo video above.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Amazon Q Was a Game-Changer 💥🎯
&lt;/h3&gt;

&lt;p&gt;Amazon Q isn’t just another coding assistant—it’s an AI developer. It allowed me to stay in flow, innovate rapidly, and push creative boundaries, eliminating friction from the development lifecycle. &lt;/p&gt;

&lt;p&gt;From initializing the project with Poetry to handling dependencies, coding logic, bug fixing, git commands, and even feature iterations—Amazon Q handled everything like a true coding copilot. I never had to touch the code manually.&lt;/p&gt;

&lt;p&gt;I’ve also recorded my entire coding session (watch the demo video above) to showcase how seamlessly Q guided me through the entire development lifecycle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion ✅🎉
&lt;/h2&gt;

&lt;p&gt;Participating in the &lt;strong&gt;Amazon Q Developer "Quack The Code" Challenge&lt;/strong&gt; was a fun and productive experience. I built an intelligent UI &amp;amp; CLI-based stock analysis tool using LangChain, LangGraph, and OpenAI—all within an hour—thanks to the power of &lt;strong&gt;Amazon Q Developer CLI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This project proved that with the right tools and a powerful AI assistant like Amazon Q Developer, building complex and intelligent applications becomes fast, efficient, and even enjoyable.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>awschallenge</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>AudioIntel - Transform Audio into Actionable Intelligence</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 25 Nov 2024 04:29:09 +0000</pubDate>
      <link>https://dev.to/mtwn105/audiointel-transform-audio-into-actionable-intelligence-nd8</link>
      <guid>https://dev.to/mtwn105/audiointel-transform-audio-into-actionable-intelligence-nd8</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/assemblyai"&gt;AssemblyAI Challenge&lt;/a&gt;: Sophisticated Speech-to-Text &amp;amp; No More Monkey Business.&lt;/em&gt; 🏆&lt;/p&gt;

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

&lt;p&gt;I built &lt;strong&gt;AudioIntel&lt;/strong&gt; - a powerful platform that transforms audio content into actionable intelligence using AssemblyAI's cutting-edge APIs. The platform helps users extract valuable insights from audio content through advanced transcription, analysis, and AI-powered features. ✨&lt;/p&gt;

&lt;h3&gt;
  
  
  🔗 Live Demo: &lt;a href="https://audiointel.amitwani.dev" rel="noopener noreferrer"&gt;https://audiointel.amitwani.dev&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  🎥 Demo Video
&lt;/h3&gt;

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

&lt;h2&gt;
  
  
  Journey 🗺️
&lt;/h2&gt;

&lt;h3&gt;
  
  
  The Inspiration 💡
&lt;/h3&gt;

&lt;p&gt;The idea for AudioIntel came from my own struggles with processing audio content efficiently. As someone who consumes a lot of podcasts, interviews, and video content, I often found myself wanting to quickly extract key insights without listening to hours of content. I realized this was a common pain point for many content creators, researchers, and professionals. 🎧&lt;/p&gt;

&lt;h3&gt;
  
  
  Learning &amp;amp; Iterations 📚
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🔄 Integration with AssemblyAI's powerful APIs for transcription and analysis&lt;/li&gt;
&lt;li&gt;🗣️ Leveraging AssemblyAI's speaker diarization and sentiment analysis features&lt;/li&gt;
&lt;li&gt;🧠 Leveraging AssemblyAI with LeMUR for summarization, question answering, and intelligent content analysis&lt;/li&gt;
&lt;li&gt;⚠️ Error handling in audio processing and real-time status updates&lt;/li&gt;
&lt;li&gt;🔄 State management for handling complex UI interactions&lt;/li&gt;
&lt;li&gt;⚡ Performance optimization for processing large audio files&lt;/li&gt;
&lt;li&gt;💾 Database integration using Neon PostgreSQL with Drizzle ORM&lt;/li&gt;
&lt;li&gt;🔒 User authentication implementation with Better Auth&lt;/li&gt;
&lt;li&gt;🌐 Language translation features using Google Translate API&lt;/li&gt;
&lt;li&gt;📤 File upload handling through UploadThing integration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Features Showcase ✨
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multiple Input Sources 📥
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;📁 File Upload: Support for various audio formats through UploadThing integration&lt;/li&gt;
&lt;li&gt;🎙️ Browser Recording: Direct audio capture using the Web Audio API&lt;/li&gt;
&lt;li&gt;📺 YouTube Integration: YouTube video to audio conversion and analysis&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Real-time Analysis 📊
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;👥 Speaker diarization with timeline visualization&lt;/li&gt;
&lt;li&gt;😊 Sentiment analysis with color-coded segments&lt;/li&gt;
&lt;li&gt;🔍 Interactive transcript search and navigation&lt;/li&gt;
&lt;li&gt;💬 Interactive chat with the transcript&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Smart Content Generation 📝
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🤖 AI-powered blog post creation&lt;/li&gt;
&lt;li&gt;💭 Context-aware chat interface&lt;/li&gt;
&lt;li&gt;📌 Key sections identification with timestamps&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Language Translation 🌍
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;🔄 Translate transcript to multiple languages&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Screenshots 📸
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Multiple Sources - Audio file, Record file &amp;amp; YouTube 📱
&lt;/h3&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%2Fj43w6y8wwarb6clixx0w.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%2Fj43w6y8wwarb6clixx0w.png" alt="audioFile" width="800" height="319"&gt;&lt;/a&gt;&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%2F2a3swa9qnaca1ifu0fr2.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%2F2a3swa9qnaca1ifu0fr2.png" alt="recordAudio" width="800" height="283"&gt;&lt;/a&gt;&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%2Fa6db5cszift2m85x4zwq.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%2Fa6db5cszift2m85x4zwq.png" alt="youtube" width="800" height="360"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Overview &amp;amp; Analysis 📊
&lt;/h3&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%2Fzvjhd3srphwat77n0y71.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%2Fzvjhd3srphwat77n0y71.png" alt="overview" width="800" height="375"&gt;&lt;/a&gt;&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%2F9yzx3udswhlht4upuqbl.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%2F9yzx3udswhlht4upuqbl.png" alt="summary" width="800" height="289"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Interactive Features ⚡
&lt;/h3&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%2Fplbecd84yypenaxuhq5a.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%2Fplbecd84yypenaxuhq5a.png" alt="transcript" width="800" height="390"&gt;&lt;/a&gt;&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%2Fndolv1e12r8uk0f063ve.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%2Fndolv1e12r8uk0f063ve.png" alt="chat" width="800" height="377"&gt;&lt;/a&gt;&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%2F24zmegps45yqssa210pj.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%2F24zmegps45yqssa210pj.png" alt="blog" width="800" height="386"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Tech Stack 💻
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;🔥 &lt;strong&gt;Framework&lt;/strong&gt;: Next.js 14 with App Router&lt;/li&gt;
&lt;li&gt;📝 &lt;strong&gt;Language&lt;/strong&gt;: TypeScript&lt;/li&gt;
&lt;li&gt;💾 &lt;strong&gt;Database&lt;/strong&gt;: Neon PostgreSQL with Drizzle ORM&lt;/li&gt;
&lt;li&gt;🎨 &lt;strong&gt;UI&lt;/strong&gt;: Tailwind CSS + shadcn/ui&lt;/li&gt;
&lt;li&gt;🎙️ &lt;strong&gt;Audio Processing&lt;/strong&gt;: AssemblyAI&lt;/li&gt;
&lt;li&gt;📤 &lt;strong&gt;File Upload&lt;/strong&gt;: UploadThing&lt;/li&gt;
&lt;li&gt;📊 &lt;strong&gt;Analytics&lt;/strong&gt;: OpenPanel&lt;/li&gt;
&lt;li&gt;🔒 &lt;strong&gt;Authentication&lt;/strong&gt;: Better Auth&lt;/li&gt;
&lt;li&gt;🌐 &lt;strong&gt;Translation&lt;/strong&gt;: Google Translate&lt;/li&gt;
&lt;li&gt;🚀 &lt;strong&gt;Deployment&lt;/strong&gt;: Vercel&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Techincal Archicture 🏗️
&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%2Fgo76j5khuigft192bykb.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%2Fgo76j5khuigft192bykb.png" alt="tech-architecture" width="682" height="441"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Technical Implementation ⚙️
&lt;/h2&gt;
&lt;h3&gt;
  
  
  AssemblyAI Integration 🔌
&lt;/h3&gt;

&lt;p&gt;I leveraged several powerful features from AssemblyAI's SDK:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Transcription API&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transcript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;assemblyai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;transcripts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;transcribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;audio&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileUrl&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;speaker_labels&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;summarization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;summary_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;conversational&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;summary_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bullets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sentiment_analysis&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LeMUR for Content Generation&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Generate blog post&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;blogPostResponse&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;assemblyai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lemur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transcript_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Generate a blog post from the transcript in markdown format`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;final_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-3-5-sonnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Generate actionable insights&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;insights&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;assemblyai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lemur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;task&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transcript_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transcript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;prompt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Provide actionable insights from the transcript`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;final_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-3-5-sonnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;LeMUR for Interactive Chat&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;qas&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;assemblyai&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lemur&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;questionAnswer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;transcript_ids&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;transcriptId&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;final_model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anthropic/claude-3-5-sonnet&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;questions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;question&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;userMessage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;answer_format&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;short sentence&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Future Enhancements 🚀
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-language support&lt;/li&gt;
&lt;li&gt;Advanced analytics dashboard&lt;/li&gt;
&lt;li&gt;API endpoints&lt;/li&gt;
&lt;li&gt;Custom templates&lt;/li&gt;
&lt;li&gt;Advanced search capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Source Code 🔗
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/audio-intel" rel="noopener noreferrer"&gt;
        audio-intel
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      AudioIntel - Audio/Video Intelligence, Transcripts, Summary, and much more 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;🎙️ AudioIntel&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;Transform audio into actionable intelligence with our powerful AI platform. AudioIntel helps you extract valuable insights from audio content through transcription, analysis, and AI-powered features.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;a href="https://audiointel.amitwani.dev" rel="nofollow noopener noreferrer"&gt;Live Demo&lt;/a&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;✨ Features&lt;/h2&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;🎵 &lt;strong&gt;Multiple Input Methods&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Upload audio files (MP3, WAV)&lt;/li&gt;
&lt;li&gt;Record directly in browser&lt;/li&gt;
&lt;li&gt;Analyze YouTube videos&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🤖 &lt;strong&gt;AI-Powered Analysis&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Smart summaries and key takeaways&lt;/li&gt;
&lt;li&gt;Sentiment analysis&lt;/li&gt;
&lt;li&gt;Speaker identification&lt;/li&gt;
&lt;li&gt;Actionable insights generation&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;📝 &lt;strong&gt;Content Generation&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Automatic blog post creation&lt;/li&gt;
&lt;li&gt;Interactive chat with transcripts&lt;/li&gt;
&lt;li&gt;Key sections identification&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔍 &lt;strong&gt;Advanced Features&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Timeline view with precise timestamps&lt;/li&gt;
&lt;li&gt;Multi-speaker detection&lt;/li&gt;
&lt;li&gt;Searchable transcripts&lt;/li&gt;
&lt;li&gt;Real-time sentiment tracking&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🚀 Getting Started&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Prerequisites&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Node.js 18+&lt;/li&gt;
&lt;li&gt;npm or yarn&lt;/li&gt;
&lt;li&gt;AssemblyAI API key&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Clone the repository&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;git clone https://github.com/yourusername/audio-intel.git
cd audio-intel
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="2"&gt;
&lt;li&gt;Install dependencies&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or&lt;/span&gt;
yarn install&lt;/pre&gt;

&lt;/div&gt;
&lt;ol start="3"&gt;
&lt;li&gt;Set up environment variables&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;cp .env.example .env&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Required environment variables:&lt;/p&gt;
&lt;div class="snippet-clipboard-content notranslate position-relative overflow-auto"&gt;&lt;pre class="notranslate"&gt;&lt;code&gt;ASSEMBLYAI_API_KEY=your_api_key
NEXT_PUBLIC_APP_URL=http://localhost:3000
UPLOADTHING_TOKEN=your_uploadthing_token
GOOGLE_GENERATIVE_AI_API_KEY=your_google_generative_ai_api_key
GOOGLE_TRANSLATE_API_KEY=your_google_translate_api_key
BETTER_AUTH_SECRET=your_better_auth_secret
BETTER_AUTH_BASE_URL=http://localhost:3000
DATABASE_URL=your_database_url
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ol start="4"&gt;
&lt;li&gt;Run the development server&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm run dev
&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; or&lt;/span&gt;
yarn dev&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Open…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/audio-intel" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Submission 📝
&lt;/h2&gt;

&lt;p&gt;This submission was made for the &lt;a href="https://dev.to/challenges/assemblyai"&gt;AssemblyAI Challenge&lt;/a&gt; for &lt;strong&gt;"Sophisticated Speech-to-Text"&lt;/strong&gt; &amp;amp; &lt;strong&gt;"No More Monkey Business"&lt;/strong&gt; Prompts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion 🎉
&lt;/h2&gt;

&lt;p&gt;I had a great time participating in the AssemblyAI Challenge and learned a lot from the experience. I'm looking forward to seeing what other developers come up with! 🚀&lt;/p&gt;

&lt;p&gt;Thank you Dev.To &amp;amp; AssemblyAI for organizing this challenge and providing such a great platform for developers to showcase their skills! 🎉&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>assemblyaichallenge</category>
      <category>ai</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>MailTales - Make Emails Fun Again!</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 02 Sep 2024 05:56:50 +0000</pubDate>
      <link>https://dev.to/mtwn105/mailtales-make-emails-fun-again-5d9l</link>
      <guid>https://dev.to/mtwn105/mailtales-make-emails-fun-again-5d9l</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/nylas"&gt;Nylas Challenge&lt;/a&gt;: AI Expedition &amp;amp; Galaxy Brain&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;MailTales is a web app designed to breathe life into your email inbox. With the help of &lt;strong&gt;Nylas&lt;/strong&gt; &amp;amp; AI, MailTales offers unique and creative ways to interact with your emails, transforming them into bite-sized stories, engaging summaries, and even providing insights through sentiment analysis. You can try it &lt;a href="https://mailtales.amitwani.dev" rel="noopener noreferrer"&gt;https://mailtales.amitwani.dev&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;MailTales: You can go to &lt;a href="https://mailtales.amitwani.dev" rel="noopener noreferrer"&gt;https://mailtales.amitwani.dev&lt;/a&gt;&lt;br&gt;
&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/zk88KqHMCR0"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Chat Over Your Inbox&lt;/strong&gt;: With MailTales, you can chat with your email inbox!&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%2F0pl9tbbdi70lidxwthsd.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%2F0pl9tbbdi70lidxwthsd.png" alt="chat-over-emails" width="800" height="459"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;AI-Powered Email Summaries&lt;/strong&gt;: MailTales provides concise, AI-generated summaries of your emails&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%2Fau67ahoawtfe8ig4kpdh.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%2Fau67ahoawtfe8ig4kpdh.png" alt="ai-summary" width="800" height="280"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Listen to AI-Generated Stories&lt;/strong&gt;: MailTales can convert the content of your emails into engaging audio stories.&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%2Fsm4ufaabt6j2ctrnt8pt.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%2Fsm4ufaabt6j2ctrnt8pt.png" alt="ai-story" width="800" height="364"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sentiment Analysis and Categorization&lt;/strong&gt;: MailTales' sentiment analysis feature helps you understand the tone of your messages. The app also categorizes emails based on their 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%2Fyjrfywjchv34ju53yrbg.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%2Fyjrfywjchv34ju53yrbg.png" alt="sentiment" width="800" height="248"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Code
&lt;/h2&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/MailTales" rel="noopener noreferrer"&gt;
        MailTales
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Turn your Emails into Captivating Stories
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;MailTales&lt;/h1&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Make emails fun again!&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;MailTales is a web app designed to breathe life into your email inbox. With the help of &lt;strong&gt;Nylas&lt;/strong&gt; &amp;amp; AI, MailTales offers unique and creative ways to interact with your emails, transforming them into bite-sized stories, engaging summaries, and even providing insights through sentiment analysis. You can try it &lt;a href="https://mailtales.amitwani.dev" rel="nofollow noopener noreferrer"&gt;https://mailtales.amitwani.dev&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Youtube - &lt;a href="https://youtu.be/zk88KqHMCR0" rel="nofollow noopener noreferrer"&gt;https://youtu.be/zk88KqHMCR0&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Features&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Chat Over Your Inbox&lt;/strong&gt;: With MailTales, you can chat with your email inbox!&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/3807b4b6ed87b071780171125923d0c261c967ec3d37f04211b9c5ba8813acf9/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f30706c39746262646937306c69647877746873642e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/3807b4b6ed87b071780171125923d0c261c967ec3d37f04211b9c5ba8813acf9/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f30706c39746262646937306c69647877746873642e706e67" alt="chat-over-emails"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;AI-Powered Email Summaries&lt;/strong&gt;: MailTales provides concise, AI-generated summaries of your emails&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/b1489800ec372955720ca0aca679fe9cd4758a22caa55743492275423610293a/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f6175363761686f6177746665386967346b7064682e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/b1489800ec372955720ca0aca679fe9cd4758a22caa55743492275423610293a/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f6175363761686f6177746665386967346b7064682e706e67" alt="ai-summary"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listen to AI-Generated Stories&lt;/strong&gt;: MailTales can convert the content of your emails into engaging audio stories.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/73f72c756375db60178bd483781653866e67d3642f54ea8dba0c99a083fb1209/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f736d34756661616274366a326374726e743870742e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/73f72c756375db60178bd483781653866e67d3642f54ea8dba0c99a083fb1209/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f736d34756661616274366a326374726e743870742e706e67" alt="ai-story"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Sentiment Analysis and Categorization&lt;/strong&gt;: MailTales' sentiment analysis feature helps you understand the tone of your messages. The app also categorizes emails based on their content.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/22219b3f0858725d8aa4175e96843d20ed72aa9bf6bc808741828f7e272ff270/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f796a726679776a63687633346a753533797262672e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/22219b3f0858725d8aa4175e96843d20ed72aa9bf6bc808741828f7e272ff270/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f796a726679776a63687633346a753533797262672e706e67" alt="sentiment"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Tech Stack&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Full Stack:&lt;/strong&gt; NextJS
&lt;strong&gt;Backend:&lt;/strong&gt; NodeJS
&lt;strong&gt;Deployment:&lt;/strong&gt; Vercel, Fly.io
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL
&lt;strong&gt;Queues:&lt;/strong&gt; Upstash Kafka
&lt;strong&gt;Email:&lt;/strong&gt; Nylas
&lt;strong&gt;AI:&lt;/strong&gt; Gemini&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Architecture&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/1cb799a9cdface4f517257c19fb61c9bdf45ffba6c2b5ca72ea3e68b9b46729b/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f707335787369666c756d6969376d376172766a712e706e67"&gt;&lt;img src="https://camo.githubusercontent.com/1cb799a9cdface4f517257c19fb61c9bdf45ffba6c2b5ca72ea3e68b9b46729b/68747470733a2f2f6465762d746f2d75706c6f6164732e73332e616d617a6f6e6177732e636f6d2f75706c6f6164732f61727469636c65732f707335787369666c756d6969376d376172766a712e706e67" alt=" mail-tales-architecture"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Nylas:&lt;/strong&gt;…&lt;/p&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/MailTales" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Full Stack:&lt;/strong&gt; NextJS&lt;br&gt;
&lt;strong&gt;Backend:&lt;/strong&gt; NodeJS&lt;br&gt;
&lt;strong&gt;Deployment:&lt;/strong&gt; Vercel, Fly.io&lt;br&gt;
&lt;strong&gt;Database:&lt;/strong&gt; PostgreSQL&lt;br&gt;
&lt;strong&gt;Queues:&lt;/strong&gt; Upstash Kafka&lt;br&gt;
&lt;strong&gt;Email:&lt;/strong&gt; Nylas&lt;br&gt;
&lt;strong&gt;AI:&lt;/strong&gt; Gemini&lt;/p&gt;
&lt;h3&gt;
  
  
  Architecture
&lt;/h3&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%2Fps5xsiflumii7m7arvjq.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%2Fps5xsiflumii7m7arvjq.png" alt="&lt;br&gt;
![mail-tales-architecture](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/djz8c5hbsmbhpu7l6qiu.png)" width="690" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Nylas:&lt;/strong&gt; Nylas is used for authentication of user and fetching their emails from inbox&lt;br&gt;
&lt;strong&gt;Gemini:&lt;/strong&gt; Gemini is used for generating AI responses as well as generating embeddings. Model used for generating responses is &lt;code&gt;gemini-1.5-flash&lt;/code&gt; and for embeddings it is &lt;code&gt;text-embedding-004&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Postgres:&lt;/strong&gt; Postgres is used to store user and emails data. &lt;code&gt;@vercel/postgres&lt;/code&gt; is used for this.&lt;br&gt;
&lt;strong&gt;Upstash Kafka:&lt;/strong&gt; Upstash Kafka is used for the job of generating email embeddings. Generating email embeddings is done by a NodeJS Backend by consuming messages from Upstash Kafka topic.&lt;/p&gt;
&lt;h2&gt;
  
  
  Your Journey
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Nylas
&lt;/h3&gt;

&lt;p&gt;I have used &lt;strong&gt;Nylas&lt;/strong&gt; to get email inbox and its contents. I have used the &lt;strong&gt;Nylas NodeJS SDK&lt;/strong&gt; for this. Logging in the user was very easy using the SDK. The &lt;code&gt;grantId&lt;/code&gt; received is then saved to the DB for further requests. Overall it was really interesting experience in building on top of &lt;strong&gt;Nylas&lt;/strong&gt; features. There are many more features which are still left to explore!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get Emails&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ListMessagesQueryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INBOX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nylas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;grantId&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Search Emails&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ListMessagesQueryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;in&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;INBOX&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;limit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;searchQueryNative&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pageToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pageToken&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;nylas&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;grantId&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;queryParams&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Upstash Kafka
&lt;/h3&gt;

&lt;p&gt;Used Upstash Kafka's REST API to produce message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPSTASH_KAFKA_REST_URL&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/produce`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`Basic &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPSTASH_KAFKA_REST_AUTH&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;generate-email-embeddings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Used &lt;code&gt;kafkajs&lt;/code&gt; in the backend to consume the messages&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;kafka&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Kafka&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;brokers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPSTASH_KAFKA_BROKERS&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;sasl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;mechanism&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;scram-sha-256&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPSTASH_KAFKA_USERNAME&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;UPSTASH_KAFKA_PASSWORD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;logLevel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;logLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ERROR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;kafka&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;groupId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;consumer_group_1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;run&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate-email-embeddings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fromBeginning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;consumer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;eachMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;topic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="nx"&gt;partition&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;offset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

      &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Generating email embeddings for user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

      &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;generateEmailEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gemini &amp;amp; Vercel AI SDK
&lt;/h3&gt;

&lt;p&gt;Used Vercel AI SDK to interact with Gemini models.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get Streaming Response&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getGoogleResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;streamText&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;google&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-1.5-flash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nx"&gt;system&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Generate Embeddings&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;generateEmbeddings&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;emailStrings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;embeddings&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;embedMany&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;google&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;text-embedding-004&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="na"&gt;values&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;emailStrings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;embeddings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, this was the first time of using NextJS and building a proper RAG agent from the scratch using Vercel AI SDK, so overall a great learning experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future Scope
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;More deeper insights into mailbox&lt;/li&gt;
&lt;li&gt;Integration of AI in alot of parts of the app&lt;/li&gt;
&lt;li&gt;Crafting beautiful professional replies.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;It was a great experience in building this app using &lt;strong&gt;Nylas&lt;/strong&gt; &amp;amp; &lt;strong&gt;Gemini&lt;/strong&gt; over NextJS. I have learnt alot in the last week while building this project. Thanks to &lt;strong&gt;Dev.To&lt;/strong&gt; as well for providing such platforms for building the projects.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>nylaschallenge</category>
      <category>api</category>
      <category>ai</category>
    </item>
    <item>
      <title>Redis Performance Testing</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Sat, 23 Dec 2023 14:18:54 +0000</pubDate>
      <link>https://dev.to/mtwn105/redis-performance-testing-1e57</link>
      <guid>https://dev.to/mtwn105/redis-performance-testing-1e57</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;Redis Benchmark&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Redis Benchmark is a command-line tool that comes bundled with Redis. It is designed to simulate various scenarios and workloads, helping you evaluate the performance of your Redis server. Whether you are a developer fine-tuning your application or an administrator optimizing system resources, Redis Benchmark provides valuable insights into your Redis instance's capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation:
&lt;/h3&gt;

&lt;p&gt;If you have Redis installed on your system, Redis Benchmark is likely available. To use it, open a terminal and simply type:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command will execute the benchmark with default settings, providing you with a quick overview of your Redis server's performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Benchmarking Workloads&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Simple Operations:
&lt;/h4&gt;

&lt;p&gt;Start by testing the basic operations, such as GET and SET commands. These operations are fundamental to Redis, and their performance directly impacts the overall responsiveness of your application. Use the following command to run a simple benchmark:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-t&lt;/span&gt; get,set
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will test the throughput and latency of GET and SET commands, giving you an idea of how quickly Redis can handle these operations.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Pipelining:
&lt;/h4&gt;

&lt;p&gt;Pipelining allows you to send multiple commands to Redis in a single request, reducing the number of round trips between the client and server. Test the impact of pipelining on performance with the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;,get &lt;span class="nt"&gt;-P&lt;/span&gt; 16
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adjust the value &lt;code&gt;-P&lt;/code&gt; to set the number of commands to pipeline.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Parallel Connections:
&lt;/h4&gt;

&lt;p&gt;Simulate real-world scenarios by testing the performance of parallel connections. This helps identify how well your Redis instance scales under increased load:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;redis-benchmark &lt;span class="nt"&gt;-t&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt;,get &lt;span class="nt"&gt;-c&lt;/span&gt; 50 &lt;span class="nt"&gt;-n&lt;/span&gt; 100000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, 50 clients will perform 100,000 SET and GET operations concurrently.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Analyzing Results&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Once the benchmark is completed, Redis Benchmark provides detailed output, including throughput, latency, and other performance metrics. Analyze this data to identify potential bottlenecks or areas for improvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  Documentation
&lt;/h3&gt;

&lt;p&gt;More documentation can be found at &lt;a href="https://redis.io/docs/management/optimization/benchmarks/" rel="noopener noreferrer"&gt;Redis benchmark | Redis&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redis</category>
      <category>performance</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Shoppable - E-commerce For Everyone</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 29 Aug 2022 20:57:00 +0000</pubDate>
      <link>https://dev.to/mtwn105/shoppable-e-commerce-for-everyone-4ab8</link>
      <guid>https://dev.to/mtwn105/shoppable-e-commerce-for-everyone-4ab8</guid>
      <description>&lt;h2&gt;
  
  
  Overview of My Submission
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Shoppable&lt;/strong&gt; is A Platform to create an online store for your business. &lt;strong&gt;&lt;em&gt;Powered by Redis Stack!&lt;/em&gt;&lt;/strong&gt;. You can visit it &lt;strong&gt;&lt;a href="https://shoppable.amitwani.dev" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1e4jg5kt4ei7xpx1fem9.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%2F1e4jg5kt4ei7xpx1fem9.png" alt="image" width="800" height="433"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Submission Category:
&lt;/h2&gt;

&lt;p&gt;My category would be &lt;strong&gt;Microservice Mavens&lt;/strong&gt; as this project has 6 decoupled backend microservices and one frontend&lt;/p&gt;

&lt;h3&gt;
  
  
  Languages/Technologies Used
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;NodeJS&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Angular&lt;/strong&gt;&lt;br&gt;
&lt;strong&gt;Redis Stack&lt;/strong&gt; (RedisJSON, RedisSearch, Redis Streams)&lt;/p&gt;
&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

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

&lt;h2&gt;
  
  
  Additional Info
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Process Flow
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Merchant can register on the platform and create a store&lt;/li&gt;
&lt;li&gt;He can add the items to inventory&lt;/li&gt;
&lt;li&gt;A customer can visit that merchant store&lt;/li&gt;
&lt;li&gt;Customer can purchase items listed by merchant&lt;/li&gt;
&lt;li&gt;Merchant will receive the order and will fulfill it&lt;/li&gt;
&lt;li&gt;Customer will receive notifications regarding the order&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Technical Overview
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;There are 6 microservices (merchant, inventory, customer, order, update, file-upload)&lt;/li&gt;
&lt;li&gt;All servers are based on &lt;strong&gt;NodeJS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The client is based on &lt;strong&gt;Angular&lt;/strong&gt; and &lt;strong&gt;Angular Material&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;An nginx is used to route request to various microservices as a reverse proxy&lt;/li&gt;
&lt;li&gt;Redis Stack is integrated with the help of &lt;strong&gt;&lt;a href="https://github.com/redis/redis-om-node" rel="noopener noreferrer"&gt;Redis OM&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/redis/node-redis" rel="noopener noreferrer"&gt;Node Redis&lt;/a&gt;&lt;/strong&gt; NodeJS libraries&lt;/li&gt;
&lt;li&gt;Redis Stack is hosted on Redis Cloud itself&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RedisJSON&lt;/strong&gt;, &lt;strong&gt;RedisSearch&lt;/strong&gt; and &lt;strong&gt;Redis Streams&lt;/strong&gt; has been used&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RedisJSON&lt;/strong&gt; is used to store JSON documents for various schema such as Merchant, Customer, Product, Order, etc.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RedisSearch&lt;/strong&gt; is used alongside RedisJSON to search through different repositories&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Redis Streams&lt;/strong&gt; is used for publishing and listening to order updates and send email using &lt;strong&gt;Mailjet&lt;/strong&gt; to the customer regarding the update&lt;/li&gt;
&lt;li&gt;Apart from this, &lt;strong&gt;Google Cloud Storage&lt;/strong&gt; is also used to store images of the products uploaded by the merchant&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture
&lt;/h3&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%2F7atrl8a6vveda9a3k2sn.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%2F7atrl8a6vveda9a3k2sn.png" alt="shoppable_architecture" width="800" height="512"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Application Screenshots
&lt;/h3&gt;

&lt;p&gt;Merchant Login&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%2Fuij935vwilf4xym8f6uu.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%2Fuij935vwilf4xym8f6uu.png" alt="Login" width="755" height="595"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merchant Dashboard&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%2Fijwgxci1lhl9v7v9e1i9.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%2Fijwgxci1lhl9v7v9e1i9.png" alt="Merchant Dashboard" width="683" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merchant Inventory&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%2Fgjbcr7oxc21oy4omn4qx.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%2Fgjbcr7oxc21oy4omn4qx.png" alt="Merchant Inventory" width="671" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merchant Add/Edit Product&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%2Fo2b9d3qdlqwm01n7ax0a.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%2Fo2b9d3qdlqwm01n7ax0a.png" alt="Merchant Add/Edit Product" width="668" height="476"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merchant Orders&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%2Fb6qw9dhjaje7szbdqief.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%2Fb6qw9dhjaje7szbdqief.png" alt="Merchant Orders" width="685" height="283"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Store Home&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%2Fi5cgv45jy2l1ppdlwm81.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%2Fi5cgv45jy2l1ppdlwm81.png" alt="Store Home" width="669" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Product Page&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%2Fweii8m3xqfyxwj2w9a1i.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%2Fweii8m3xqfyxwj2w9a1i.png" alt="Product Page" width="680" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cart&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%2Fiksivh2eog79y91fqvgr.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%2Fiksivh2eog79y91fqvgr.png" alt="Cart" width="677" height="307"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Order Details&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%2Fma1kmi75go9u1zro1qsf.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%2Fma1kmi75go9u1zro1qsf.png" alt="Order Details" width="663" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Email Notification&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%2F1skzkpl6a6l7ing76kjk.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%2F1skzkpl6a6l7ing76kjk.png" alt="Email Notification" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;More details are available on the GitHub repo:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/Shopable" rel="noopener noreferrer"&gt;
        Shopable
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A Platform to create an online store for your business. Powered by Redis Stack!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Shoppable - E-commerce for Everyone&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A Platform to create an online store for your business
Powered by Redis Stack!&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/187288703-1ff8c94f-75d7-4547-b86d-f01959a9511f.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F187288703-1ff8c94f-75d7-4547-b86d-f01959a9511f.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Powered By&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Redis Stack&lt;/strong&gt; (RedisJSON, RedisSearch, Redis Streams)
&lt;strong&gt;NodeJS&lt;/strong&gt;
&lt;strong&gt;Angular&lt;/strong&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Demo Video&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;Checkout video &lt;a href="https://youtu.be/sxY6KHoRkn8" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How it works&lt;/h2&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Process flow&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Merchant can register on the platform and create a store&lt;/li&gt;
&lt;li&gt;He can add the items to inventory&lt;/li&gt;
&lt;li&gt;A customer can visit that merchant store&lt;/li&gt;
&lt;li&gt;Customer can purchase items listed by merchant&lt;/li&gt;
&lt;li&gt;Merchant will receive the order and will fulfill it&lt;/li&gt;
&lt;li&gt;Customer will receive notifications regarding the order&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Technical Overview&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;There are 6 microservices (merchant, inventory, customer, order, update, file-upload)&lt;/li&gt;
&lt;li&gt;All servers are based on &lt;strong&gt;NodeJS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;The client is based on &lt;strong&gt;Angular&lt;/strong&gt; and &lt;strong&gt;Angular Material&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;An nginx is used to route request to various microservices as a reverse proxy&lt;/li&gt;
&lt;li&gt;Redis Stack is integrated with the help of &lt;strong&gt;&lt;a href="https://github.com/redis/redis-om-node" rel="noopener noreferrer"&gt;Redis OM&lt;/a&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;a href="https://github.com/redis/node-redis" rel="noopener noreferrer"&gt;Node Redis&lt;/a&gt;&lt;/strong&gt; NodeJS libraries&lt;/li&gt;
&lt;li&gt;Redis Stack is hosted on Redis Cloud itself&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/Shopable" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;





&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Check out &lt;a href="https://redis.io/docs/stack/get-started/clients/#high-level-client-libraries" rel="noopener noreferrer"&gt;Redis OM&lt;/a&gt;, client libraries for working with Redis as a multi-model database.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Use &lt;a href="https://redis.info/redisinsight" rel="noopener noreferrer"&gt;RedisInsight&lt;/a&gt; to visualize your data in Redis.&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Sign up for a &lt;a href="https://redis.info/try-free-dev-to" rel="noopener noreferrer"&gt;free Redis database&lt;/a&gt;.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>redishackathon</category>
      <category>node</category>
      <category>webdev</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Create a Chatbot using WhatsApp Cloud API</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 27 Jun 2022 05:02:05 +0000</pubDate>
      <link>https://dev.to/mtwn105/create-a-chatbot-using-whatsapp-cloud-api-18d9</link>
      <guid>https://dev.to/mtwn105/create-a-chatbot-using-whatsapp-cloud-api-18d9</guid>
      <description>&lt;p&gt;Hello folks, today in this article, we will be going through how you can create a chatbot and integrate it with &lt;strong&gt;WhatsApp Cloud API&lt;/strong&gt;. We will be also giving this chatbot a brain using an &lt;strong&gt;OpenAI&lt;/strong&gt; model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;To create a WhatsApp chatbot you will need a few Prerequisites:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Meta Business Account&lt;/li&gt;
&lt;li&gt;A Meta Developer Account&lt;/li&gt;
&lt;li&gt;An OpenAI Account&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can create these easily using your existing Facebook account or create a new one.&lt;/p&gt;

&lt;p&gt;Once you have all of these ready, we can get started by configuring in Meta Developer account to enable WhatsApp integration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Create Meta App
&lt;/h3&gt;

&lt;p&gt;Logon to &lt;a href="https://developers.facebook.com/apps/" rel="noopener noreferrer"&gt;https://developers.facebook.com/apps/&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Create a New App.&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%2Fi4q5okp52n4qfier5e4t.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%2Fi4q5okp52n4qfier5e4t.png" alt="Image description" width="800" height="187"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Choose &lt;strong&gt;Business&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwbv78kyiv4rafmvsmtqi.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%2Fwbv78kyiv4rafmvsmtqi.png" alt="Image description" width="800" height="391"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose your &lt;strong&gt;Business Manager Account&lt;/strong&gt; and enter other details&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%2Fdrgxog3717gz99w8h5m9.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%2Fdrgxog3717gz99w8h5m9.png" alt="Image description" width="800" height="427"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Click on &lt;strong&gt;Create App&lt;/strong&gt; and your app will be created.&lt;/p&gt;

&lt;h3&gt;
  
  
  Add WhatsApp Integration
&lt;/h3&gt;

&lt;p&gt;Open your app page and you will land on this screen.&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%2Fezvo1x40gafq2bd7bxsb.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%2Fezvo1x40gafq2bd7bxsb.png" alt="Image description" width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Scroll down and find &lt;strong&gt;WhatsApp&lt;/strong&gt;. Click on &lt;strong&gt;Set up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmafaq9tsh92dxe59par.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%2Fwmafaq9tsh92dxe59par.png" alt="Image description" width="487" height="423"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  WhatsApp Configuration
&lt;/h3&gt;

&lt;p&gt;You will see this screen. Here you have been assigned &lt;strong&gt;a Temporary Token&lt;/strong&gt; and &lt;strong&gt;a Test WhatsApp Number&lt;/strong&gt;. We will use these to send and receive messages on that Test WhatsApp Number. In future, if you want, you can connect real numbers as well which will be a proper WhatsApp Business account. &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%2Fsc06lfikhta4zjald6rv.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%2Fsc06lfikhta4zjald6rv.png" alt="Image description" width="800" height="447"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You have to configure a few recipient WhatsApp numbers for testing, up to 5 numbers can be added.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;Phone Number ID&lt;/strong&gt; shown will be used later to use WhatsApp Cloud API, so keep it handy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication Token
&lt;/h3&gt;

&lt;p&gt;The final piece of configuration is generation of an authentication token which will be used while communicating with Meta APIs. &lt;/p&gt;

&lt;p&gt;Log on to &lt;a href="https://business.facebook.com/" rel="noopener noreferrer"&gt;https://business.facebook.com/&lt;/a&gt; and open your Business Settings.&lt;/p&gt;

&lt;p&gt;Navigate to the &lt;strong&gt;System Users&lt;/strong&gt; section from left-hand menu&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%2Fb7cvkdj1a34b77skacgv.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%2Fb7cvkdj1a34b77skacgv.png" alt="Image description" width="434" height="339"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;You can add a user or if it already exists, click on &lt;strong&gt;Generate New Token&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0r8zum32vrtgm4lvjwuv.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%2F0r8zum32vrtgm4lvjwuv.png" alt="Image description" width="800" height="321"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the app you created earlier and check &lt;strong&gt;whatsapp_business_management&lt;/strong&gt; and &lt;strong&gt;whatsapp_business_messaging&lt;/strong&gt; permissions and then copy this token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Application
&lt;/h2&gt;

&lt;p&gt;So we will develop our application using &lt;strong&gt;NodeJS and Express&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We will install basic dependencies like &lt;code&gt;express&lt;/code&gt; &lt;code&gt;morgan&lt;/code&gt; &lt;code&gt;helmet&lt;/code&gt; &lt;code&gt;cors&lt;/code&gt; &lt;code&gt;axios&lt;/code&gt; &lt;code&gt;dotenv&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We will create two API routes one for verification of the webhook (this will be only used once) and one to receive messages/updates from WhatsApp&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GET &lt;code&gt;/api/webhook&lt;/code&gt; - To verify this webhook&lt;/li&gt;
&lt;li&gt;POST &lt;code&gt;/api/webhook&lt;/code&gt; - To receive messages from WhatsApp&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, we can configure a webhook in WhatsApp so that every time a message or update comes we will get notified of that and we can respond accordingly.&lt;/p&gt;

&lt;p&gt;This GET API of &lt;code&gt;/api/webhook&lt;/code&gt; will be used for verification of this webhook where WhatsApp will send a token and a couple of parameters and we will verify if all those matches whatever is configured on our server. It is called a Verification Token. We create a random long verification token and store it in the environment variables of our server.&lt;/p&gt;

&lt;p&gt;This will be our API route for GET &lt;code&gt;/api/webhook&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/webhook&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;VERIFY_TOKEN&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;VERIFY_TOKEN&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Parse params from the webhook verification request&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hub.mode&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hub.verify_token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;challenge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;hub.challenge&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="c1"&gt;// Check if a token and mode were sent&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Missing mode or token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&gt;// Check the mode and token sent are correct&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subscribe&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;token&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;VERIFY_TOKEN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Respond with 200 OK and challenge token from the request&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;WEBHOOK_VERIFIED&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;challenge&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Responds with '403 Forbidden' if verify tokens do not match&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendStatus&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;403&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify our webhook we go to &lt;strong&gt;WhatsApp Configuration&lt;/strong&gt; from the Meta App page&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%2Fa2m3j0gr4uw34dydamo4.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%2Fa2m3j0gr4uw34dydamo4.png" alt="Image description" width="420" height="323"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Add the &lt;strong&gt;Webhook API URL&lt;/strong&gt; and the &lt;strong&gt;Verification token&lt;/strong&gt; and click on &lt;strong&gt;Verify and Save&lt;/strong&gt;. You can use a proxy like &lt;strong&gt;ngrok&lt;/strong&gt; if you are still in development. Webhook URL must be an HTTPS one with no Self-signed certificate in the chain.&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Webhook fields&lt;/strong&gt;, Subscribe to &lt;strong&gt;messages&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85eazr6civwi974zsp70.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%2F85eazr6civwi974zsp70.png" alt="Image description" width="800" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now for the receiving messages webhook, POST &lt;code&gt;/api/webhook&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/api/webhook&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Parse the request body from the POST&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Check the Incoming webhook message&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Incoming webhook: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Validate the webhook&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;// Handle the event&lt;/span&gt;
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;whatsapp_business_account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

        &lt;span class="c1"&gt;// Handle the message&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;field&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;messages&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
              &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="c1"&gt;// Handle the value&lt;/span&gt;
              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;change&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;contacts&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

              &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

              &lt;span class="c1"&gt;// Handle messages&lt;/span&gt;
              &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                  &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                  &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
                  &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;waid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;msgId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Message from &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;waid&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;
                  &lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error occured &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is how we will extract messages from the incoming webhook when the user sends a Text message on the configured number. We can use this text message and then reply accordingly. &lt;/p&gt;

&lt;p&gt;For our application, we pass this as a prompt to an OpenAPI model and then get a response from the AI and respond to the user. We are using &lt;code&gt;openai&lt;/code&gt; package for this.&lt;/p&gt;

&lt;p&gt;For responding to the user, we will use the &lt;code&gt;https://graph.facebook.com/v13.0/&amp;lt;phonenumberid&amp;gt;/messages&lt;/code&gt; API endpoint with the authentication token we collected earlier in Headers like below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;axios&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHATSAPP_SEND_MESSAGE_API&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;messaging_product&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;whatsapp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;recipient_type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;individual&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;waid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;preview_url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;reply&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bearer &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WHATSAPP_TOKEN&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By this response will be send to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This is how we will use WhatsApp Cloud API and integrate WhatsApp with your application. There are endless possibilities since Meta recently made this API available to all, which was earlier only available to business owners or BSP (Business Service Partners). &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Documentation:&lt;/strong&gt; &lt;a href="https://developers.facebook.com/docs/whatsapp/cloud-api/reference" rel="noopener noreferrer"&gt;https://developers.facebook.com/docs/whatsapp/cloud-api/reference&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>webdev</category>
      <category>showdev</category>
    </item>
    <item>
      <title>How to speed up a Web App loading time by 10x faster!</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 16 May 2022 05:40:38 +0000</pubDate>
      <link>https://dev.to/mtwn105/how-to-speed-up-a-web-app-loading-time-by-10x-faster-1oke</link>
      <guid>https://dev.to/mtwn105/how-to-speed-up-a-web-app-loading-time-by-10x-faster-1oke</guid>
      <description>&lt;p&gt;Hello folks, Today I will discuss, how I speeded up the loading time of my Web App built using Angular or any SPA (Single Page Application).&lt;/p&gt;

&lt;p&gt;Before diving into the article, let's first understand how a Single Page Application (SPA) works be it developed using any web framework (Angular, React, etc.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Single Page Application
&lt;/h2&gt;

&lt;p&gt;The single-page application is a web application that interacts with the user by dynamically rewriting the current page, rather than loading entire new pages from the server.  &lt;/p&gt;

&lt;p&gt;In SPA, when the browser makes the first request to the server, the server sends back the &lt;code&gt;index.html&lt;/code&gt; file. and that's basically it. that's the only time an HTML file is served. the HTML file has a script tag for the &lt;code&gt;.js&lt;/code&gt; file which is going to take control of the &lt;code&gt;index.html&lt;/code&gt; page. All subsequent calls return just the data, usually in JSON format. the application uses this JSON data to update the page dynamically. However, the page never reloads.&lt;/p&gt;

&lt;p&gt;The client (and not the server) handles the job of transforming data to HTML once the application has started. basically, most of the modern SPA frameworks like Angular, React, and Vue has a templating engine of sorts running in your browser to generate the HTML.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewmtm9j9oyxxmrjaqfo1.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%2Fewmtm9j9oyxxmrjaqfo1.png" alt="SPA" width="800" height="323"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Now let's come to the problem or one of the drawbacks of using a SPA. Since the initial &lt;code&gt;index.html&lt;/code&gt; is very lightweight, most hard work is being done by the subsequent Javascript files fetched from the server and the client executing that JS in the browser. &lt;/p&gt;

&lt;p&gt;As our project starts to become complex with a lot of components and dependencies, the bundled JS file sizes get bigger with time. &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%2F3b5unhueqglzvjexbize.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%2F3b5unhueqglzvjexbize.png" alt="FileSizeBefore" width="693" height="25"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Here you can see this is a bundled JS generated by the building of an Angular App which is more than 1 MB 🤯. This file has to get loaded in browsers which takes a good amount of time and the user has to wait for the first painting of the webpage.&lt;/p&gt;

&lt;p&gt;Though React is much lighter weight, one can definitely reduce this size by compressing these JS files. That's what we will do next.&lt;/p&gt;

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

&lt;p&gt;We will discuss one of the ways to deal with this problem, which is to compress the bundle JS files and serve their compressed versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Compress Bundled JS files
&lt;/h3&gt;

&lt;p&gt;In Angular, to generate a compressed version of these JS files, we can use &lt;code&gt;gzipper&lt;/code&gt; to compress files to &lt;code&gt;gzip&lt;/code&gt; format. &lt;/p&gt;

&lt;p&gt;We add a dev dependency in &lt;code&gt;package.json&lt;/code&gt; for &lt;code&gt;gzipper&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"gzipper"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^7.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We also update our build script in &lt;code&gt;package.json&lt;/code&gt; to gzip the files after building using &lt;code&gt;gzipper&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ng build &amp;amp;&amp;amp; gzipper compress --verbose ./dist/client/"&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when we build our application using &lt;code&gt;npm run build&lt;/code&gt; we will get two versions of that JS file. One is a non-compressed one and one is compressed with the &lt;code&gt;.js.gz&lt;/code&gt; extension.&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%2F090c2bekkwyb9w2baev8.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%2F090c2bekkwyb9w2baev8.png" alt="FileSizeAfter" width="724" height="26"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see the gzipped version of the Javascript file is almost 4 times smaller (1.2 MB to 300 KB)&lt;br&gt;
Along with JS, all HTML, CSS and asset files are also gzipped reducing their sizes by more than 50%.&lt;/p&gt;
&lt;h3&gt;
  
  
  Nginx
&lt;/h3&gt;

&lt;p&gt;Now comes the role of Nginx, we need something to serve these compressed versions of Javascript files, we will be using Nginx for this. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;nginx.conf&lt;/code&gt; - The configuration file for Nginx we will these four lines to the &lt;code&gt;server&lt;/code&gt; object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    gzip on;
    gzip_min_length 1000;
    gzip_proxied expired no-cache no-store private auth;
    gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will enable the gzip compression and when serving the files, if the gzip compression is supported by the browser, Nginx will serve the smaller gzip version thus reducing the loading time by up to 10X.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This marks the end of this article. This was of the many ways to speed up the loading time of a Single Page Application. As your app gets to production-grade at scale, this will be very useful. &lt;/p&gt;

&lt;p&gt;For React, you can refer to &lt;a href="https://codetoart.com/blog/how-to-load-react-web-app-faster" rel="noopener noreferrer"&gt;this&lt;/a&gt; article to see how to generate build files in gzipped version.&lt;/p&gt;

&lt;p&gt;If you like this article, keep in touch with me on my socials or support me if you want. &lt;br&gt;
If you have any feedback, do let me know in the comments.&lt;/p&gt;

&lt;p&gt;Till next time, Peace.! &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>beginners</category>
      <category>webdev</category>
      <category>angular</category>
    </item>
    <item>
      <title>Read your Favorite Podcasts - PodText</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Mon, 11 Apr 2022 11:58:59 +0000</pubDate>
      <link>https://dev.to/mtwn105/read-your-favorite-podcasts-podtext-4f0p</link>
      <guid>https://dev.to/mtwn105/read-your-favorite-podcasts-podtext-4f0p</guid>
      <description>&lt;p&gt;Hello folks, this post is regarding my submission for &lt;strong&gt;Deepgram Hackathon&lt;/strong&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  Idea
&lt;/h3&gt;

&lt;p&gt;So many of us wants to listen to various amazing podcasts out there, but due to time constraints we are not able to give so much time and attention to listen to them. What if its possible to read the transcript of the podcast in a text version, that's struck my mind. &lt;br&gt;
I decided to create an web app to &lt;strong&gt;Read the podcasts - PodText&lt;/strong&gt;. &lt;/p&gt;


&lt;h3&gt;
  
  
  Overview of My Submission
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;PodText&lt;/strong&gt; will allow us to browse through &lt;strong&gt;Top Podcasts&lt;/strong&gt; of various genres and read transcripts for each episode of a podcast.&lt;br&gt;
Podcast metadata and audio has been fetched using Podcast API by &lt;strong&gt;Listennotes&lt;/strong&gt;. Audio to Text transcription is done using &lt;strong&gt;Deepgram&lt;/strong&gt;'s API.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt; &lt;a href="//podtext.amitwani.dev"&gt;podtext.amitwani.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Note: Currently, Podcasts are served from Mock server of Listennotes to avoid exhaustion of API quota&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Submission Category
&lt;/h3&gt;

&lt;p&gt;Accessibility Advocates &lt;/p&gt;


&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;NextJS&lt;/li&gt;
&lt;li&gt;NextUI&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Railway.app&lt;/li&gt;
&lt;li&gt;Listennotes&lt;/li&gt;
&lt;li&gt;Deepgram&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Details
&lt;/h3&gt;

&lt;p&gt;I have created a NextJS app along with NextUI as a UI library.&lt;br&gt;
Created pages for showing Genres (&lt;code&gt;genres/[id]&lt;/code&gt;), Podcasts (&lt;code&gt;podcasts/[id]&lt;/code&gt;), Episodes (&lt;code&gt;episodes/[id]&lt;/code&gt;) details. &lt;br&gt;
Created an API route &lt;code&gt;api/transcribe&lt;/code&gt; which is used to transcribe the audio of Podcast to text using Deepgram. Podcast audio will be fetched from Listennotes' CDN on the fly itself.&lt;/p&gt;


&lt;h3&gt;
  
  
  Link to Code on GitHub
&lt;/h3&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/podtext" rel="noopener noreferrer"&gt;
        podtext
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      View Text Versions of your favorite podcasts!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Podtext&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Read your favorite podcasts&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;Link:&lt;/strong&gt; &lt;a href="https://github.com/mtwn105/podtextpodtext.up.railway.app" rel="noopener noreferrer"&gt;podtext.amitwani.dev&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Idea&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;So many of us wants to listen to various amazing podcasts out there, but due to time constraints we are not able to give so much time and attention to listen to them. What if its possible to read the transcript of the podcast in a text version, that's struck my mind.
I decided to create an web app to &lt;strong&gt;Read the podcasts - PodText&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Tech Stack&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;NextJS&lt;/li&gt;
&lt;li&gt;NextUI&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Railway.app&lt;/li&gt;
&lt;li&gt;Listennotes&lt;/li&gt;
&lt;li&gt;Deepgram&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/podtext" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;h3&gt;
  
  
  Screenshots/Demo
&lt;/h3&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/46c09374980f4bc28c5cb983373e75ac"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;h3&gt;
  
  
  Future Improvements
&lt;/h3&gt;

&lt;p&gt;There's always room for improvement, here are some things which can be added or done better in this&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Better UI/UX&lt;/li&gt;
&lt;li&gt;Ability to Play Podcast&lt;/li&gt;
&lt;li&gt;Ability to search podcasts&lt;/li&gt;
&lt;li&gt;Caching podcast transcriptions&lt;/li&gt;
&lt;li&gt;Improved SEO&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;I have learned a lot while making this project. This has been my first proper project on NextJS, still much improvement is needed on this front. Had fun with using Deepgram's API very easy to use and straight forward. &lt;br&gt;
Looking forward to everyone's submissions and more such hackathons.&lt;/p&gt;

&lt;p&gt;Till next time, peace!&lt;/p&gt;

</description>
      <category>hackwithdg</category>
      <category>nextjs</category>
      <category>react</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Manage your GitHub Starred Repositories</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Tue, 05 Apr 2022 04:22:26 +0000</pubDate>
      <link>https://dev.to/mtwn105/manage-your-github-starred-repositories-16po</link>
      <guid>https://dev.to/mtwn105/manage-your-github-starred-repositories-16po</guid>
      <description>&lt;p&gt;Hello folks, this is a quick article about how you can manage your &lt;strong&gt;GitHub's starred repositories&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;You must have come across hundreds of awesome GitHub repositories but the problem is it's very hard to find the one you want at that moment in time.&lt;/p&gt;

&lt;p&gt;For this, we usually &lt;strong&gt;star&lt;/strong&gt; our GitHub repositories, but we forget about them.&lt;/p&gt;

&lt;p&gt;To solve this, I came across this feature in GitHub (still in beta), where you can &lt;strong&gt;create lists&lt;/strong&gt; to &lt;strong&gt;organize&lt;/strong&gt; your starred repositories.&lt;/p&gt;

&lt;p&gt;To do this you just click on the &lt;strong&gt;arrow icon&lt;/strong&gt; next to &lt;strong&gt;Star&lt;/strong&gt;&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%2Fasic2yg6xgkopfxjicew.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%2Fasic2yg6xgkopfxjicew.png" alt="Star" width="484" height="143"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will be presented with a dropdown to &lt;strong&gt;select&lt;/strong&gt; an existing list or &lt;strong&gt;create&lt;/strong&gt; a new list&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%2Fjtpj59q371kdb0ygq22w.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%2Fjtpj59q371kdb0ygq22w.png" alt="List" width="393" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you select a list, it will be saved in that list.&lt;br&gt;
You can revisit it by going to &lt;strong&gt;Your Stars&lt;/strong&gt;&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%2Fsa7bupeen3cqy3uaikzm.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%2Fsa7bupeen3cqy3uaikzm.png" alt="YourStars" width="246" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And you can see all your lists, you can go through them, search in them, etc.&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%2Frwetnpntw5tszya1dx9u.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%2Frwetnpntw5tszya1dx9u.png" alt="StarList" width="800" height="165"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That's it for this article. Hope you found it useful. Share your thoughts down below.&lt;/p&gt;

&lt;p&gt;Till next time, peace.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>github</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Journal CLI - Write Journal in Notion using CLI</title>
      <dc:creator>Amit Wani</dc:creator>
      <pubDate>Sun, 20 Mar 2022 07:03:22 +0000</pubDate>
      <link>https://dev.to/mtwn105/journal-cli-write-journal-in-notion-using-cli-5071</link>
      <guid>https://dev.to/mtwn105/journal-cli-write-journal-in-notion-using-cli-5071</guid>
      <description>&lt;p&gt;Hello folks, today I tried to play around with Notion API and NodeJS to create a CLI which can write Journal for you and store it in a Notion Database.&lt;/p&gt;

&lt;p&gt;These days, there is a lot of stuff going on in our lives and we want to focus on the ones which matter most to us. One way to solve this is by writing a journal and sorting this chaotic mess. &lt;/p&gt;

&lt;p&gt;Using &lt;a href="https://notion.so" rel="noopener noreferrer"&gt;Notion&lt;/a&gt;, we can create beautiful interactive notes and much more. Using the power of notion and efficiency of CLI, I developed this quick way, you can start journaling, by answering just 5 questions at the end of the day and the Journal will be saved in a database in Notion.!&lt;/p&gt;

&lt;p&gt;NPM Link - &lt;a href="https://www.npmjs.com/package/journal-notion-cli" rel="noopener noreferrer"&gt;https://www.npmjs.com/package/journal-notion-cli&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Duplicate Template
&lt;/h3&gt;

&lt;p&gt;To Get Started Duplicate this &lt;a href="https://amit-wani.notion.site/amit-wani/Journal-a19377f6b17d47768e03d4ffe62a030d" rel="noopener noreferrer"&gt;Notion Template&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installation
&lt;/h3&gt;

&lt;p&gt;Then Install Journal CLI from NPM using&lt;br&gt;
&lt;code&gt;npm i -g journal-notion-cli&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Connect to Notion
&lt;/h3&gt;

&lt;p&gt;Connect to the notion by running &lt;code&gt;journal connect&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Write Journal
&lt;/h3&gt;

&lt;p&gt;Write a journal every day using &lt;code&gt;journal write&lt;/code&gt; and answer a few questions.&lt;/p&gt;
&lt;h3&gt;
  
  
  Demo
&lt;/h3&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%2Fa5qe9ss6lze48a2yz5ko.gif" 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%2Fa5qe9ss6lze48a2yz5ko.gif" alt="Demo" width="1024" height="1024"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Source Code
&lt;/h3&gt;

&lt;p&gt;If you like it and want to know more, do check out the GitHub repo at &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fassets.dev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/mtwn105" rel="noopener noreferrer"&gt;
        mtwn105
      &lt;/a&gt; / &lt;a href="https://github.com/mtwn105/journal-cli" rel="noopener noreferrer"&gt;
        journal-cli
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A CLI to write journal for you and save it to a Notion database!
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Journal CLI&lt;/h1&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;&lt;a href="https://www.npmjs.com/package/journal-notion-cli" rel="nofollow noopener noreferrer"&gt;NPM Link&lt;/a&gt;&lt;/h3&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;A CLI to write journal for you and save it to a Notion database!&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.producthunt.com/posts/journal-cli?utm_source=badge-featured&amp;amp;utm_medium=badge&amp;amp;utm_souce=badge-journal-cli" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/05ecfc6c6c1cefa93729217c2ffb2f3cde523bb56b8a515a3aee4cb3557cd4b4/68747470733a2f2f6170692e70726f6475637468756e742e636f6d2f776964676574732f656d6265642d696d6167652f76312f66656174757265642e7376673f706f73745f69643d333337393332267468656d653d6c69676874" alt="Journal CLI - Write daily journal in notion using CLI | Product Hunt" width="250" height="54"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121193-9ffe743c-352e-48c4-b43b-a577190ae658.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121193-9ffe743c-352e-48c4-b43b-a577190ae658.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Demo&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/62e127b009b446898d58b8100523d9a4c07e2d52d998ebf7af1ff63619700893/68747470733a2f2f6d65646961342e67697068792e636f6d2f6d656469612f5a6666716158696c434d6c66454b48335a462f67697068792e6769663f6369643d373930623736313163663139633034306364386132306666313163363165363237343539363966316363636662633762267269643d67697068792e6769662663743d67"&gt;&lt;img src="https://camo.githubusercontent.com/62e127b009b446898d58b8100523d9a4c07e2d52d998ebf7af1ff63619700893/68747470733a2f2f6d65646961342e67697068792e636f6d2f6d656469612f5a6666716158696c434d6c66454b48335a462f67697068792e6769663f6369643d373930623736313163663139633034306364386132306666313163363165363237343539363966316363636662633762267269643d67697068792e6769662663743d67" alt="demo"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Installation&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;Run &lt;code&gt;npm i -g journal-notion-cli&lt;/code&gt; to install the cli.&lt;/p&gt;
&lt;p&gt;Start using by &lt;code&gt;journal connect&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Help Command &lt;code&gt;journal --help&lt;/code&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Duplicate this page to your notion&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://amit-wani.notion.site/amit-wani/Journal-a19377f6b17d47768e03d4ffe62a030d" rel="nofollow noopener noreferrer"&gt;https://amit-wani.notion.site/amit-wani/Journal-a19377f6b17d47768e03d4ffe62a030d&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159122439-d5a9aa76-0648-441d-8376-ab9262108b38.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159122439-d5a9aa76-0648-441d-8376-ab9262108b38.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Connect to notion &lt;code&gt;journal connect&lt;/code&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121300-df0be909-9ec9-4ab8-82e1-ef669eee0d20.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121300-df0be909-9ec9-4ab8-82e1-ef669eee0d20.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121314-9396644f-e288-4334-8640-1317af6b671d.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121314-9396644f-e288-4334-8640-1317af6b671d.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121372-95cf0824-7cba-40b9-a876-7eea6737b51b.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121372-95cf0824-7cba-40b9-a876-7eea6737b51b.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121402-31dac731-6139-41af-a8a5-d4653b5ae395.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121402-31dac731-6139-41af-a8a5-d4653b5ae395.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Write journal every day using &lt;code&gt;journal write&lt;/code&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121444-939ed87b-1ae1-412d-955e-c8bc1a8327bb.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121444-939ed87b-1ae1-412d-955e-c8bc1a8327bb.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121477-b0809f0b-205c-449c-8239-54d984986350.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121477-b0809f0b-205c-449c-8239-54d984986350.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://user-images.githubusercontent.com/12975481/159121481-fa9020b0-aff2-4449-9df7-af869410461a.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fuser-images.githubusercontent.com%2F12975481%2F159121481-fa9020b0-aff2-4449-9df7-af869410461a.png" alt="image"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Buy me a coffee&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/mtwn105" rel="nofollow noopener noreferrer"&gt;coffee&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/mtwn105/journal-cli" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;If you like this tool, do support me by using the "Buy me a coffee" button, and keep reading my content by subscribing to newsletters. Till next time, peace.&lt;/p&gt;

&lt;h3&gt;
  
  
  Buy me a coffee
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://www.buymeacoffee.com/mtwn105" rel="noopener noreferrer"&gt;https://www.buymeacoffee.com/mtwn105&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>bash</category>
    </item>
  </channel>
</rss>
