<?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: Tej Hagargi</title>
    <description>The latest articles on DEV Community by Tej Hagargi (@tejhagargi).</description>
    <link>https://dev.to/tejhagargi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3327574%2Fb71b119f-f2ac-404d-bb94-eb5d743f525f.jpg</url>
      <title>DEV Community: Tej Hagargi</title>
      <link>https://dev.to/tejhagargi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tejhagargi"/>
    <language>en</language>
    <item>
      <title>Implementing a Retrieval-Augmented Generation (RAG) Chatbot with LangChain, Firebase, and Pinecone</title>
      <dc:creator>Tej Hagargi</dc:creator>
      <pubDate>Thu, 25 Sep 2025 10:50:48 +0000</pubDate>
      <link>https://dev.to/tejhagargi/implementing-a-retrieval-augmented-generation-rag-chatbot-with-langchain-firebase-and-pinecone-3pm4</link>
      <guid>https://dev.to/tejhagargi/implementing-a-retrieval-augmented-generation-rag-chatbot-with-langchain-firebase-and-pinecone-3pm4</guid>
      <description>&lt;p&gt;Recently, I was working on a Retrieval-Augmented Generation (RAG) chatbot where users can upload PDFs or where I can scrape structured website data. The goal was to convert this data into embeddings, store it in a vector database, and then use it to answer user queries.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Extract Raw Text&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From pdf&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { PdfReader } from 'pdfreader';

let text = '';
const pdfReader = new PdfReader();

await new Promise&amp;lt;void&amp;gt;((resolve, reject) =&amp;gt; {
  pdfReader.parseBuffer(buffer, (err: any, item: any) =&amp;gt; {
    if (err) reject(err);
    else if (!item) resolve();
    else if (item.text) text += item.text + ' ';
  });
});

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

&lt;/div&gt;



&lt;p&gt;From scraped website data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function extractTextFromScrapedData(data: ScrapedData): string {
  const sections: string[] = [];

  if (data.about) sections.push(`About: ${data.about}`);
  if (data.services) sections.push(`Services: ${data.services.join('\n• ')}`);
  if (data.contact?.phone) sections.push(`Phone: ${data.contact.phone}`);

  return sections.join('\n\n');
}

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 2: Split Text into Chunks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Long documents need to be split so the LLM can handle them. I used LangChain’s RecursiveCharacterTextSplitter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { RecursiveCharacterTextSplitter } from "@langchain/textsplitters";
import { Document } from "@langchain/core/documents";

const doc = new Document({ pageContent: text });
const splitter = new RecursiveCharacterTextSplitter({
  chunkSize: 1000,
  chunkOverlap: 200
});

const allSplits = await splitter.splitDocuments([doc]);
console.log("Chunks created:", allSplits.length);

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 3: Generate Embeddings + Store&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is the most important part:&lt;br&gt;
When you call vectorStore.addDocuments(), LangChain automatically calls your embedding model (e.g. OpenAI, Cohere) and saves those vectors into your configured database (Pinecone in my case).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import { vectorStore } from "@/app/lib/langchain";

// Store with namespace (client-specific)
await vectorStore.addDocuments(allSplits, { namespace: clientId });
console.log("✅ Documents added to vectorStore");

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Step 4: Retrieve Context During Chat&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user asks a question, we retrieve the top-k similar chunks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const retrieved = await vectorStore.similaritySearchWithScore(
  userMessage,
  3,
  { namespace: clientId }
);

const relevantMatches = retrieved.filter(([doc, score]) =&amp;gt; score &amp;gt; 0.6);
console.log("Relevant matches:", relevantMatches.length);

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  The other chunking methods are :
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Agentic Chunking → LLM-guided, semantic-aware chunking based on meaning and context.&lt;/li&gt;
&lt;li&gt;CharacterTextSplitter → Splits by character count (simple, fast).&lt;/li&gt;
&lt;li&gt;RecursiveCharacterTextSplitter → Splits by hierarchy (paragraph → sentence → word → char). Most commonly used.&lt;/li&gt;
&lt;li&gt;TokenTextSplitter → Splits by tokens, aligns with model tokenization.&lt;/li&gt;
&lt;li&gt;MarkdownTextSplitter → Splits Markdown docs by headers/sections.&lt;/li&gt;
&lt;li&gt;HTMLTextSplitter → Splits HTML while respecting tags.&lt;/li&gt;
&lt;li&gt;CodeTextSplitter → Splits source code by functions, classes, logical blocks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Refer to this doc for more clarifying &lt;br&gt;
&lt;a href="https://js.langchain.com/docs/tutorials/rag/" rel="noopener noreferrer"&gt;DOC&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Happy Coding, Keep Striving.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>llm</category>
      <category>typescript</category>
      <category>tutorial</category>
      <category>rag</category>
    </item>
    <item>
      <title>Docker Essentials for Beginners: What I Learned Building My First Node.js App</title>
      <dc:creator>Tej Hagargi</dc:creator>
      <pubDate>Sun, 06 Jul 2025 10:46:40 +0000</pubDate>
      <link>https://dev.to/tejhagargi/docker-essentials-for-beginners-what-i-learned-building-my-first-nodejs-app-5606</link>
      <guid>https://dev.to/tejhagargi/docker-essentials-for-beginners-what-i-learned-building-my-first-nodejs-app-5606</guid>
      <description>&lt;p&gt;Over the past few days, I’ve been diving into Docker and learning how it simplifies development and deployment. I started with a basic Node.js app and ended up understanding key Docker concepts that I’m sharing below — explained in simple terms from a beginner’s point of view.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Docker?
&lt;/h2&gt;

&lt;p&gt;Docker simplifies application development, deployment, and scaling by packaging your app along with its dependencies into containers. These containers run the same way in development, testing, or production — ensuring consistency across environments.&lt;/p&gt;

&lt;p&gt;First rule: Make sure Docker Desktop is running before executing any Docker commands.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Docker Commands I Learned
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it ubuntu         # Image
docker container ls           # List running containers
docker container ls -a        # List all containers (including stopped)
docker start &amp;lt;container&amp;gt;      # Start a stopped container
docker stop &amp;lt;container&amp;gt;       # Stop a running container
docker exec &amp;lt;container&amp;gt; ls    # Run commands inside the container from host
docker exec -it &amp;lt;container&amp;gt; bash  # Open shell inside the container

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Understanding Images vs Containers
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Images are the blueprint (environment setup, app code).&lt;/li&gt;
&lt;li&gt;Containers are the live, running instances of those images.&lt;/li&gt;
&lt;li&gt;Multiple containers can use the same image — they are isolated from each other.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Creating &amp;amp; Sharing Custom Images
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Write a Dockerfile to define environment &amp;amp; dependencies.&lt;/li&gt;
&lt;li&gt;Build the image (docker build -t codebro-image .).&lt;/li&gt;
&lt;li&gt;Push it to Docker Hub.&lt;/li&gt;
&lt;li&gt;Your teammates can run it using:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull your-dockerhub/codebro-image
docker run -it your-dockerhub/codebro-image

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Docker Networking
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Bridge Network (Default)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Isolated network created by Docker.&lt;/li&gt;
&lt;li&gt;Containers can talk to each other using names (if on custom bridge).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network inspect bridge

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Host Network&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Shares host machine’s network.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --network=host your-image

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;None Network&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No network access (complete isolation).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it --network=none alpine

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Create a Custom Network&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker network create my-custom-network

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Port Mapping &amp;amp; Environment Variables
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Expose ports from container to host:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 1025:1025 image-name

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

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Pass environment variables:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -p 1025:1025 -e key=value -e key=value image-name

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Volume Mounting
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Attach host folders to containers for persistent storage:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -it -v /Users/tejhagargi/Desktop:/home/abc ubuntu

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

&lt;/div&gt;



&lt;p&gt;Changes in /home/abc inside container reflect on your desktop and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  Layer Caching
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Each line in a Dockerfile becomes a layer. Docker reuses unchanged layers to speed up builds.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18           # Layer 1
WORKDIR /app           # Layer 2
COPY package.json .    # Layer 3
RUN npm install        # Layer 4
COPY . .               # Layer 5
CMD ["node", "index.js"]  # Layer 6

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

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multi-Stage Builds
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Build your app in one stage and copy only the necessary files to a clean final image.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:18 AS builder
WORKDIR /app
COPY . .
RUN npm install &amp;amp;&amp;amp; npm run build

FROM node:18-slim
WORKDIR /app
COPY --from=builder /app/dist ./dist
CMD ["node", "dist/index.js"]

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

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Try My Dockerized Node App&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker pull tejhagargi/myfirstnodeapp_docker
docker run -it -p 3000:3000 tejhagargi/myfirstnodeapp_docker

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

&lt;/div&gt;



&lt;p&gt;`FROM ubuntu &lt;/p&gt;

&lt;p&gt;RUN apt-get update&lt;/p&gt;

&lt;p&gt;RUN apt-get install -y curl&lt;/p&gt;

&lt;p&gt;RUN curl -sL &lt;a href="https://deb.nodesource.com/setup_18.x" rel="noopener noreferrer"&gt;https://deb.nodesource.com/setup_18.x&lt;/a&gt; | bash -&lt;/p&gt;

&lt;p&gt;RUN apt-get upgrade -y &lt;/p&gt;

&lt;p&gt;RUN apt-get install -y nodejs&lt;/p&gt;

&lt;p&gt;COPY package-lock.json package-lock.json&lt;br&gt;
COPY package.json package.json&lt;br&gt;
COPY main.js main.js&lt;/p&gt;

&lt;p&gt;RUN npm install&lt;/p&gt;

&lt;p&gt;ENTRYPOINT [ "node", "main.js" ]&lt;br&gt;
`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrapping Up&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Learning Docker has helped me understand how to ship applications reliably. Whether you’re working solo or with a team, containerization is a powerful tool that makes life easier.&lt;/p&gt;

&lt;p&gt;If you're also learning Docker, feel free to drop questions or tips in the comments!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🧑‍💻 Happy Dockering!&lt;br&gt;
— Tej Hagargi&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
