<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Yaldram Arena]]></title><description><![CDATA[I'm Arsalan Ahmed, a Full Stack JavaScript Developer and Tech Lead. I write tutorials on JavaScript, TypeScript, React, UI design systems, and now exploring LLM]]></description><link>https://yaldram.hashnode.dev</link><generator>RSS for Node</generator><lastBuildDate>Sun, 15 Nov 2026 18:05:24 GMT</lastBuildDate><atom:link href="https://yaldram.hashnode.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Stop Wrapping Controllers in Try-Catch: The express-async-handler Solution]]></title><description><![CDATA[Simplify error handling in Express using `express-async-handler` for clean, concise, and efficient code without repetitive `try-catch` blocks]]></description><link>https://yaldram.hashnode.dev/stop-wrapping-controllers-in-try-catch-the-express-async-handler-solution</link><guid isPermaLink="true">https://yaldram.hashnode.dev/stop-wrapping-controllers-in-try-catch-the-express-async-handler-solution</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Express]]></category><category><![CDATA[APIs]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Thu, 19 Sep 2024 04:23:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Vl6nLPF67rg/upload/64226e80ff42b87ba167e98d26ec2162.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>As a JavaScript developer, you've probably seen Express controllers wrapped in <code>try-catch</code> blocks to handle async errors. While this works, it can make your code repetitive and cluttered. Enter <a target="_blank" href="https://www.npmjs.com/package/express-async-handler"><code>express-async-handler</code></a>: a simple tool that eliminates the need for <code>try-catch</code> in every controller. It's designed to handle async errors keeping your code clean and easy to read. In this post, we'll explore how <code>express-async-handler</code> can simplify your Express code and make error handling a breeze.</p>
<h3 id="heading-the-current-scene-try-catch-overload">The Current Scene: Try-Catch Overload</h3>
<p>Picture this in your Express app:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserById = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(req.params.id);
    <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User not found"</span> });
    res.status(<span class="hljs-number">200</span>).json(user);
  } <span class="hljs-keyword">catch</span> (error) {
    res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Server error"</span>, <span class="hljs-attr">error</span>: error.message });
  }
};

<span class="hljs-comment">// Using the controller</span>
app.get(<span class="hljs-string">"/users/:id"</span>, getUserById);
</code></pre>
<p>See that <code>try-catch</code> wrapping everything? It's like a safety blanket for your code. It works, sure, but imagine doing this for every single controller.</p>
<h3 id="heading-enter-express-async-handler-your-codes-new-best-friend">Enter <code>express-async-handler</code>: Your Code's New Best Friend</h3>
<ol>
<li>Install it:</li>
</ol>
<pre><code class="lang-bash">npm install express-async-handler
</code></pre>
<ol start="2">
<li>Refactor your controller by removing <code>try-catch</code>:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserById = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(req.params.id);
  <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User not found"</span> });
  <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json(user);
};
</code></pre>
<ol start="3">
<li>Use it in your route:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> asyncHandler <span class="hljs-keyword">from</span> <span class="hljs-string">"express-async-handler"</span>;

app.get(<span class="hljs-string">"/users/:id"</span>, asyncHandler(getUserById));
</code></pre>
<ol start="4">
<li>Now that we've streamlined our controllers, let's add a global error handler to catch any errors:</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> express <span class="hljs-keyword">from</span> <span class="hljs-string">'express'</span>;

<span class="hljs-keyword">const</span> app = express();

<span class="hljs-comment">// Global Error Handler</span>
app.use(<span class="hljs-function">(<span class="hljs-params">error, req, res, next</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log.(<span class="hljs-string">`Oops! <span class="hljs-subst">${error.stack}</span>`</span>);

  res.status(<span class="hljs-number">500</span>).json({
    <span class="hljs-attr">status</span>: <span class="hljs-literal">false</span>,
    <span class="hljs-attr">statusCode</span>: <span class="hljs-number">500</span>,
    <span class="hljs-attr">message</span>: <span class="hljs-string">`Something went wrong on our end. We're on it!`</span>
  });
});
</code></pre>
<p>That's it! No more <code>try-catch</code> clutter. If an error pops up, <code>express-async-handler</code> catches it and passes it to <strong>Express's global error handler</strong>. With <code>express-async-handler</code>, you're writing less boilerplate and focusing more on what your code actually does.</p>
<h3 id="heading-middleware-your-requests-pit-stop">Middleware: Your Request's Pit Stop</h3>
<p>Middleware is a function that runs between receiving a request and sending a response. Think of it as an assistant that can:</p>
<ul>
<li><p>Check if a user is logged in</p>
</li>
<li><p>Validate data</p>
</li>
<li><p>Log request details</p>
</li>
<li><p>Modify the request or response</p>
</li>
</ul>
<p>Here’s a basic middleware example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> logRequest = <span class="hljs-function">(<span class="hljs-params">req, res, next</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Received a <span class="hljs-subst">${req.method}</span> request to <span class="hljs-subst">${req.url}</span>`</span>);
  next(); <span class="hljs-comment">// Don't forget this! It passes control to the next middleware</span>
};

app.use(logRequest); <span class="hljs-comment">// Use this middleware globally for all routes</span>
</code></pre>
<p>In this case, <code>logRequest</code> logs all incoming requests and is used globally, meaning it will run on every route in your app.</p>
<h4 id="heading-how-middleware-works">How Middleware Works</h4>
<p>Middleware functions take three arguments: <code>req</code> (request), <code>res</code> (response), and <code>next</code>. <strong>The</strong> <code>next()</code> <strong>function is crucial—it passes control to the next middleware in the stack. Without it, the request-response cycle would stop and the request would hang.</strong></p>
<p>Middleware can be applied <strong>globally</strong>, as in the <code>logRequest</code> example, or <strong>individually</strong> to specific routes. For instance:</p>
<pre><code class="lang-javascript">router.post(
  <span class="hljs-string">'/'</span>,
  validateRequestBody(todosSchema), <span class="hljs-comment">// Middleware for request validation</span>
  asyncHandler(todosController.createTodo)
);
</code></pre>
<p>Here, <code>validateRequestBody</code> checks whether the request body matches the <code>todosSchema</code> before the request reaches the controller. In a similar fashion, you can add custom middlewares for tasks like validating data, authenticating users, or logging specific details on individual routes or across your entire app. <strong><mark>Our controllers function as middleware too.</mark></strong></p>
<h3 id="heading-global-error-handler-your-apps-safety-net">Global Error Handler: Your App's Safety Net</h3>
<p>A <strong>global error handler</strong> in Express is special middleware that catches errors from anywhere in your app. Here’s a simple example:</p>
<pre><code class="lang-javascript">app.use(<span class="hljs-function">(<span class="hljs-params">error, req, res, next</span>) =&gt;</span> {
  <span class="hljs-built_in">console</span>.error(error.stack);
  res.status(<span class="hljs-number">500</span>).send(<span class="hljs-string">'Oops! Something went wrong'</span>);
});
</code></pre>
<p>In this basic setup, any unhandled errors will be logged, and the user will get a general error message. But in a real-world app, you often need more specific error handling based on the error type.</p>
<p>The great thing about this approach is that it works hand-in-hand with <code>express-async-middleware</code> and other custom middlewares like <code>validateRequestBody</code> that we discussed earlier:</p>
<pre><code class="lang-javascript">router.post(
  <span class="hljs-string">'/'</span>,
  validateRequestBody(todosSchema),
  asyncHandler(todosController.createTodo)
);
</code></pre>
<pre><code class="lang-javascript">app.use(<span class="hljs-function">(<span class="hljs-params">error, req, res, next</span>) =&gt;</span> {
  logger.fatal(<span class="hljs-string">`Error: <span class="hljs-subst">${error.stack}</span>`</span>);

  <span class="hljs-keyword">if</span> (error <span class="hljs-keyword">instanceof</span> ValidationError) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">400</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'Validation failed'</span>,
      <span class="hljs-attr">errors</span>: error.validationErrors
    });
  }

  <span class="hljs-keyword">if</span> (error.code === <span class="hljs-string">'FOREIGN_KEY_CONSTRAINT'</span>) {
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
      <span class="hljs-attr">message</span>: <span class="hljs-string">'Database error: Constraint violation. Please ensure that related data exists before proceeding.'</span>
    });
  }

  <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({
    <span class="hljs-attr">message</span>: <span class="hljs-string">'Something unusual happened'</span>
  });
});
</code></pre>
<p>If <code>validateRequestBody</code> throws a validation error, it’s automatically caught by the global error handler. Similarly, database-related errors can also be managed here.</p>
<p>Using this centralized error handling along with <code>express-async-handler</code> and other custom middlewares means you no longer need repetitive <code>try-catch</code> blocks in each route. Instead, you have a streamlined, clean solution that handles errors in a single place, making your app more maintainable and easier to debug.</p>
<h3 id="heading-cracking-open-express-async-handler">Cracking Open express-async-handler</h3>
<p>If you check the <a target="_blank" href="https://github.com/Abazhenov/express-async-handler/blob/master/index.js"><code>express-async-handler</code> codebase</a>, it's just <strong>8 lines of code</strong>—yes, only 8! It’s a simple <strong>curried function</strong>—a function that returns another function. Below is a simplified version, let's peek under the hood:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">asyncHandler</span>(<span class="hljs-params">controllerFunction</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">asyncMiddleware</span>(<span class="hljs-params">req, res, next</span>) </span>{
    <span class="hljs-keyword">const</span> controllerPromise = controllerFunction(req, res, next);
    <span class="hljs-keyword">return</span> <span class="hljs-built_in">Promise</span>.resolve(controllerPromise).catch(next);
  };
}
</code></pre>
<ol>
<li><p><strong>The Wrapper</strong>: <code>asyncHandler</code> is the main function that creates a middleware wrapper. It takes a <code>controllerFunction</code> as its argument, which is the function that handles the route logic.</p>
</li>
<li><p><strong>The Return</strong>: The <code>asyncHandler</code> function returns another function (<code>asyncMiddleware</code>). This returned function is the actual middleware used in Express.</p>
</li>
<li><p><strong>The Magic</strong>: When this function runs, it:</p>
<ul>
<li><p>Calls your controller function</p>
</li>
<li><p>Wraps the result in a Promise (in case it's not already one)</p>
</li>
<li><p>Attaches a <code>.catch()</code> handler to the promise. If the promise is rejected (an error occurs), the error is passed to the <code>next</code> function, which forwards it to the global error handler.</p>
</li>
</ul>
</li>
</ol>
<p>In plain English: <code>express-async-handler</code> takes your controller, runs it, and makes sure any errors are caught and sent to the global error handler. This tiny piece of code saves you from writing <code>try-catch</code> blocks everywhere. It's a small tool that makes a big difference in keeping your code clean and error-free.</p>
<h3 id="heading-when-its-okay-to-use-try-catch-in-controllers">When It’s Okay to Use <code>try-catch</code> in Controllers</h3>
<p>There’s nothing wrong with using a <code>try-catch</code> block inside a controller when you need to handle <strong>specific, localized errors</strong>. The key takeaway is balance. For <strong>global or repetitive errors</strong>, using <code>express-async-handler</code> and a global error handler middleware is the best approach. However, for unique situations that are controller-specific, a <code>try-catch</code> makes sense and is perfectly valid:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> getUserById = <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> user = <span class="hljs-keyword">await</span> User.findById(req.params.id);
    <span class="hljs-keyword">if</span> (!user) <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">404</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"User not found"</span> });
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">200</span>).json(user);
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-comment">// Handle specific route errors, e.g., database constraints</span>
    <span class="hljs-keyword">if</span> (error.code === <span class="hljs-string">"E203"</span>) {
      <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">message</span>: <span class="hljs-string">"Server error"</span>, <span class="hljs-attr">error</span>: error.message });
    }

    <span class="hljs-comment">// Let the global error handler take care of any other errors</span>
    <span class="hljs-keyword">throw</span> error;
  }
};

app.get(<span class="hljs-string">"/users/:id"</span>, asyncHandler(getUserById));
</code></pre>
<h3 id="heading-wrapping-up-cleaner-safer-express">Wrapping Up: Cleaner, Safer Express</h3>
<p>We've explored how to simplify error handling in Express, and here's the takeaway:</p>
<ul>
<li><p><strong>Say Goodbye to Try-Catch Overload</strong>: <code>express-async-handler</code> eliminates repetitive <code>try-catch</code> blocks.</p>
</li>
<li><p><strong>Cleaner Code</strong>: Your controllers are now focused and streamlined.</p>
</li>
<li><p><strong>Global Error Handling</strong>: Catch errors with a centralized error handler.</p>
</li>
<li><p><strong>Middleware Magic</strong>: Middleware transforms your app's flow and keeps things tidy.</p>
</li>
<li><p><strong>Simple Yet Powerful</strong>: A few clever lines of code make a big difference.</p>
</li>
</ul>
<p>If you’re looking to build Express apps from scratch, check out this complete TypeScript starter that follows clean coding principles and includes end-to-end testing: <a target="_blank" href="https://github.com/yaldram/express-typescript-starter">express-typescript-starter</a>. I’ve also written a 7-part series on it—<a target="_blank" href="https://dev.to/yaldram/series/18758">take a look here</a>. Until next time Happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[GEN AI for JavaScript Devs:  Building a Pizza Chatbot with Node.js - Part 2]]></title><description><![CDATA[Learn to enhance your pizza chatbot with Node.js by streaming AI responses, parsing markdown, and switching to cost-effective LLMs]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-building-a-pizza-chatbot-with-nodejs-part-2</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-building-a-pizza-chatbot-with-nodejs-part-2</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[openai]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[chatbot]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Sat, 31 Aug 2024 16:47:17 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/TStCoAiFjDY/upload/ccf1839284ac51269c4a428ded2aa93e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>In the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-building-a-pizza-chatbot-with-nodejs-part-1">previous post</a>, we built a simple pizza chatbot using the OpenAI SDK that could handle pizza orders. We discussed several features necessary for a consistent chatbot experience, such as streaming LLM responses, parsing markdown content generated by the LLM into HTML, and exploring alternative LLMs and SDKs for potentially more cost-effective options.</p>
<p>In this second part on building a pizza chatbot with Node.js, we'll implement these features. If you haven’t read the first part yet, I recommend doing so before diving into this post.</p>
<h3 id="heading-streaming-openai-responses-in-an-express-api">Streaming OpenAI Responses in an Express API</h3>
<p>To enable streaming responses in our Express API, we need to pass the <code>stream: true</code> parameter to the OpenAI SDK. Instead of waiting for the LLM to generate the entire response, this approach streams the data as it arrives, enhancing the chat experience—especially for longer responses. This is the same technique used in ChatGPT-like interfaces to provide a smoother and more interactive user experience.</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">"/api/chat-streaming"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> conversations = req.body.conversations;

  <span class="hljs-keyword">try</span> {
    <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
      <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
      <span class="hljs-attr">messages</span>: [...context, ...conversations],
      <span class="hljs-attr">stream</span>: <span class="hljs-literal">true</span>,
    });

    <span class="hljs-keyword">const</span> stream = response.toReadableStream();
    <span class="hljs-keyword">const</span> reader = stream.getReader();

    <span class="hljs-keyword">const</span> decoder = <span class="hljs-keyword">new</span> TextDecoder();
    <span class="hljs-keyword">let</span> assistantMessage = <span class="hljs-string">""</span>;

    <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
      <span class="hljs-keyword">const</span> { done, value } = <span class="hljs-keyword">await</span> reader.read();
      <span class="hljs-keyword">if</span> (done) <span class="hljs-keyword">break</span>;

      <span class="hljs-keyword">const</span> chunk = decoder.decode(value);
      <span class="hljs-keyword">const</span> lines = chunk.split(<span class="hljs-string">"\n"</span>);

      <span class="hljs-keyword">for</span> (<span class="hljs-keyword">const</span> line <span class="hljs-keyword">of</span> lines) {
        <span class="hljs-keyword">if</span> (line.trim() === <span class="hljs-string">""</span>) <span class="hljs-keyword">continue</span>;
        <span class="hljs-keyword">const</span> json = <span class="hljs-built_in">JSON</span>.parse(line);
        <span class="hljs-keyword">const</span> content = json.choices[<span class="hljs-number">0</span>]?.delta?.content || <span class="hljs-string">""</span>;
        assistantMessage += content;
        res.write(content);
      }
    }

    <span class="hljs-keyword">return</span> res.end();
  } <span class="hljs-keyword">catch</span> (error) {
    <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error during streaming:"</span>, error);
    <span class="hljs-keyword">return</span> res.status(<span class="hljs-number">500</span>).json({ <span class="hljs-attr">error</span>: <span class="hljs-string">"An error occurred during streaming"</span> });
  }
});
</code></pre>
<p>The streaming part involves getting a continuous flow of data from OpenAI's API and sending it to the client in real-time. Here’s how it works:</p>
<ul>
<li><p><code>response.toReadableStream()</code>:</p>
<ul>
<li><p>The <code>response</code> object from the OpenAI API call has a method called <code>toReadableStream()</code>. This converts the response into a stream that can be read piece by piece instead of all at once.</p>
</li>
<li><p>Think of a stream like a faucet where water (data) flows gradually, instead of filling a whole bucket and then using it. You get the data as soon as it arrives.</p>
</li>
</ul>
</li>
<li><p><code>const reader = stream.getReader()</code>:</p>
<ul>
<li>The stream is read using a <code>reader</code>. The <code>getReader()</code> method gives us a way to read the stream's data chunk by chunk.</li>
</ul>
</li>
<li><p><code>const decoder = new TextDecoder();</code>:</p>
<ul>
<li>The <code>TextDecoder</code> i<strong>s used to convert the chunks of data (which are in a raw format) into readable text</strong>.</li>
</ul>
</li>
<li><p><strong>Reading the Stream in a Loop</strong>:</p>
<ul>
<li><p>The <code>while (true)</code> loop continuously reads from the stream until there is no more data (<code>done</code> becomes <code>true</code>).</p>
</li>
<li><p><code>await</code> <a target="_blank" href="http://reader.read"><code>reader.read</code></a><code>()</code> reads the next chunk of data from the stream.</p>
<ul>
<li><p><code>done</code>: A flag that tells if the stream has finished (<code>true</code> when there’s no more data).</p>
</li>
<li><p><code>value</code>: The actual chunk of data.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Processing the Data</strong>:</p>
<ul>
<li><p>Each chunk of data is decoded into text using <code>decoder.decode(value)</code>.</p>
</li>
<li><p>The decoded text (which might be several lines) is split into individual lines using <code>chunk.split("\n")</code>.</p>
</li>
<li><p>The loop goes through each line. If a line is empty (just a newline character), it skips it.</p>
</li>
</ul>
</li>
<li><p><strong>Sending Data to the Client</strong>:</p>
<ul>
<li><p>For each non-empty line, the line is parsed as JSON (<code>JSON.parse(line)</code>), and the relevant content (the AI's message) is extracted.</p>
</li>
<li><p><code>res.write(content)</code> sends this content to the client as soon as it’s available.</p>
</li>
<li><p><strong>This means the client starts receiving parts of the AI's response immediately, without waiting for the whole response to be ready</strong>.</p>
</li>
</ul>
</li>
<li><p><strong>Ending the Response</strong>:</p>
<ul>
<li>Once the stream has no more data (<code>done</code> becomes <code>true</code>), the loop exits, and <code>res.end()</code> <strong>is called to signal that the response is complete</strong>.</li>
</ul>
</li>
</ul>
<h3 id="heading-receiving-streams-on-the-frontend">Receiving Streams on the Frontend</h3>
<p>Now that we have the backend code set up for streaming, let’s look at how to handle this data on the frontend. Replace the script code from the previous tutorial with the following:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> conversations = [];

    <span class="hljs-keyword">const</span> initialMessage =
      <span class="hljs-string">"Hi there! 😊 Ready to place your pizza order 🍕 or have any questions? Let me know!"</span>;
    addMessageToChat(<span class="hljs-string">"Assistant"</span>, initialMessage, <span class="hljs-string">"assistant"</span>);

    <span class="hljs-built_in">document</span>
      .getElementById(<span class="hljs-string">"chat-form"</span>)
      .addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-keyword">async</span> (event) =&gt; {
        event.preventDefault();

        <span class="hljs-keyword">const</span> userMessage = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"message-input"</span>).value;
        <span class="hljs-keyword">if</span> (!userMessage) <span class="hljs-keyword">return</span>;

        addMessageToChat(<span class="hljs-string">"User"</span>, userMessage, <span class="hljs-string">"user"</span>);
        conversations.push({ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: userMessage });
        <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"message-input"</span>).value = <span class="hljs-string">""</span>;
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/chat-streaming"</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
          <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ conversations }),
        });

        <span class="hljs-keyword">const</span> reader = response.body.getReader();
        <span class="hljs-keyword">const</span> decoder = <span class="hljs-keyword">new</span> TextDecoder();
        <span class="hljs-keyword">let</span> assistantMessage = <span class="hljs-string">""</span>;

        <span class="hljs-comment">// Create the assistant message element once</span>
        <span class="hljs-keyword">const</span> assistantMessageElement = addMessageToChat(
          <span class="hljs-string">"Assistant"</span>,
          <span class="hljs-string">""</span>,
          <span class="hljs-string">"assistant"</span>
        );

        <span class="hljs-keyword">while</span> (<span class="hljs-literal">true</span>) {
          <span class="hljs-keyword">const</span> { done, value } = <span class="hljs-keyword">await</span> reader.read();
          <span class="hljs-keyword">if</span> (done) <span class="hljs-keyword">break</span>;

          <span class="hljs-keyword">const</span> chunk = decoder.decode(value);
          assistantMessage += chunk;

          <span class="hljs-comment">// Update the existing message element with the latest content</span>
          updateMessageInChat(assistantMessageElement, assistantMessage);
        }

        conversations.push({
          <span class="hljs-attr">role</span>: <span class="hljs-string">"assistant"</span>,
          <span class="hljs-attr">content</span>: assistantMessage,
        });
      });

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addMessageToChat</span>(<span class="hljs-params">sender, message, className</span>) </span>{
      <span class="hljs-keyword">const</span> chat = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"chat-area"</span>);
      <span class="hljs-keyword">const</span> messageElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
      messageElement.className = <span class="hljs-string">`chat-message <span class="hljs-subst">${className}</span>`</span>;
      messageElement.innerHTML = <span class="hljs-string">`&lt;strong&gt;<span class="hljs-subst">${sender}</span>:&lt;/strong&gt; &lt;span class="message-content"&gt;<span class="hljs-subst">${message}</span>&lt;/span&gt;`</span>;
      chat.appendChild(messageElement);
      chat.scrollTop = chat.scrollHeight;
      <span class="hljs-keyword">return</span> messageElement.querySelector(<span class="hljs-string">".message-content"</span>); <span class="hljs-comment">// Return the span where the message content is displayed</span>
    }

    <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateMessageInChat</span>(<span class="hljs-params">element, message</span>) </span>{
      element.innerHTML = message;
      <span class="hljs-keyword">const</span> chat = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"chat-area"</span>);
      chat.scrollTop = chat.scrollHeight; <span class="hljs-comment">// Keep the chat scrolled to the bottom</span>
    }
  });
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Let's break down the streaming part of our frontend code, focusing on how messages from the backend are received and displayed in real-time.</p>
<ol>
<li><p><strong>Sending the User Message and Making the POST Request</strong>:</p>
<ul>
<li><p>When the user submits a message in the chat, it’s added to the <code>conversations</code> array and displayed in the chat window.</p>
</li>
<li><p>A POST request is then sent to the <code>/api/chat-streaming</code> endpoint with the <code>conversations</code> array in the request body.</p>
</li>
</ul>
</li>
<li><p><strong>Receiving the Stream</strong>:</p>
<ul>
<li><p>Once the POST request is sent, the frontend starts receiving a streamed response from the server.</p>
</li>
<li><p>The <code>response.body.getReader()</code> method is used to create a <code>reader</code> that reads the incoming stream of data chunk by chunk.</p>
</li>
</ul>
</li>
<li><p><strong>Decoding the Stream</strong>:</p>
<ul>
<li>A <code>TextDecoder</code> is used to convert each chunk of raw data into a readable text string.</li>
</ul>
</li>
<li><p><strong>Creating the Assistant Message Element</strong>:</p>
<ul>
<li><p>When the streaming starts, an empty message element is created for the assistant using the <code>addMessageToChat</code> function.</p>
</li>
<li><p>This element is added to the chat area, but it starts with no content because the full response hasn’t been received yet.</p>
</li>
<li><p>The <code>addMessageToChat</code> function returns the specific <code>span</code> element where the assistant's message content will be displayed.</p>
</li>
</ul>
</li>
<li><p><strong>Updating the Assistant Message in Real-Time</strong>:</p>
<ul>
<li><p>As chunks of the assistant's message are received from the stream, the message content is gradually built up in the <code>assistantMessage</code> variable.</p>
</li>
<li><p>After each chunk is received, the <code>updateMessageInChat</code> function is called to update the content of the already-created message element in the chat.</p>
</li>
<li><p>This means that the assistant’s message appears to be typing out in real-time, giving the user immediate feedback as the AI generates its response.</p>
</li>
</ul>
</li>
<li><p><strong>Finalizing the Message</strong>:</p>
<ul>
<li>Once the stream is fully read (indicated by <code>done</code> being <code>true</code>), the full message from the assistant is finalized and added to the <code>conversations</code> array.</li>
</ul>
</li>
</ol>
<h3 id="heading-parsing-markdown-to-html-on-the-frontend">Parsing Markdown to HTML on the Frontend</h3>
<p>One issue we’ve encountered is that while the LLM generates great markdown text, we're unable to display it properly on the frontend. To resolve this, we'll use the <code>marked</code> library to parse markdown into HTML. First, include it in your HTML header:</p>
<pre><code class="lang-html"><span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"https://cdn.jsdelivr.net/npm/marked/marked.min.js"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<p>Next, update your <code>updateMessage</code> function to integrate the <code>marked</code> library. This will convert the streamed content from markdown to HTML in real time:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">updateMessageInChat</span>(<span class="hljs-params">element, message</span>) </span>{
    <span class="hljs-comment">// Convert markdown to HTML using marked.js</span>
    <span class="hljs-keyword">const</span> htmlContent = marked.parse(message);
    element.innerHTML = htmlContent; <span class="hljs-comment">// Update the message content with HTML</span>
    <span class="hljs-keyword">const</span> chat = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"chat-area"</span>);
    chat.scrollTop = chat.scrollHeight; <span class="hljs-comment">// Keep the chat scrolled to the bottom</span>
}
</code></pre>
<p>Now, run the code and send this message: <code>show me the menu please</code>. Watch how the LLM streams the response in real time and how we beautifully render the markdown.</p>
<h3 id="heading-using-llama-from-together-ai">Using LLaMA from Together AI</h3>
<p>In one of our <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case">previous posts</a>, we highlighted the importance of choosing the right LLM for the right job, as it directly impacts both pricing and performance. For instance, there's no need to use the latest and most expensive LLM for simple tasks like generating emails, etc.</p>
<p>In this section, we'll switch from OpenAI's GPT-4o Mini to Meta's LLaMA 3 8B from Together AI. Here’s a comparison of their pricing:</p>
<ul>
<li><p><strong>GPT-4o Mini</strong>: $0.15 per million input tokens, $0.60 per million output tokens</p>
</li>
<li><p><strong>Meta's LLaMA 3 8B</strong>: $0.055 per million input tokens, $0.055 per million output tokens</p>
</li>
</ul>
<p>Together AI offers a more affordable option, and it’s compatible with the OpenAI SDK for streaming content. Here’s how to make the switch:</p>
<ol>
<li><p>Get your API keys from Together AI.</p>
</li>
<li><p>Update your API configuration:</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAI({
   <span class="hljs-attr">apiKey</span>: process.env.TOGETHER_API_KEY,
   <span class="hljs-attr">baseURL</span>: <span class="hljs-string">"https://api.together.xyz/v1"</span>,
 });
</code></pre>
</li>
<li><p>Update the model in your request</p>
<pre><code class="lang-javascript"> <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
   <span class="hljs-attr">model</span>: <span class="hljs-string">"meta-llama/Llama-3-8b-chat-hf"</span>,
   <span class="hljs-attr">messages</span>: [...context, ...conversations],
   <span class="hljs-attr">stream</span>: <span class="hljs-literal">true</span>,
 });
</code></pre>
</li>
</ol>
<p>That’s it! You’ve successfully changed the API key, updated the URL, and switched the model. Test your app to see the new setup in action.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this post, we built upon our previous work by implementing streaming for our chatbot, adding markdown parsing for enhanced content display, and exploring how to switch LLMs to optimize for cost and performance. In the next post, we'll dive into function calling with the OpenAI SDK and explore how to implement it effectively. Until then, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Gen AI for JavaScript Devs: Building a Pizza Chatbot with Node.js – Part 1]]></title><description><![CDATA[Build a simple pizza chatbot using Node.js, Express, and OpenAI. Learn setup, prompting techniques, and create a functional chat interface]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-building-a-pizza-chatbot-with-nodejs-part-1</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-building-a-pizza-chatbot-with-nodejs-part-1</guid><category><![CDATA[generative ai]]></category><category><![CDATA[chatbot]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[openai]]></category><category><![CDATA[#PromptEngineering]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[HTML5]]></category><category><![CDATA[CSS]]></category><category><![CDATA[Express]]></category><category><![CDATA[Node.js]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Sat, 31 Aug 2024 12:55:02 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/zlKdLdMREtE/upload/9a7ab4b158163fca36dbe1e4853e8170.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>In our ongoing series, we've explored the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-hands-on-with-openai-sdk">OpenAI SDK</a> and dived into various <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-exploring-open-ai-alternatives-mistral-llama-and-more">LLMs (Large Language Models) and their SDKs</a>. In the previous post we've covered <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-prompting-techniques">prompting techniques</a> gaining a solid foundation in generative AI. Now, it's time to put all that learning into practice.</p>
<p>In this post, we’ll build a simple yet effective pizza chatbot using the skills we've acquired. From utilizing LLM SDKs like OpenAI to applying advanced prompting techniques, we’ll bring all these elements together to create something tangible. While this chatbot won't have database connectivity—something we can add later—it serves as a great starting point to showcase the power of AI.</p>
<p>The inspiration for this chatbot comes from a course I previously mentioned, offered by <a target="_blank" href="https://learn.deeplearning.ai/courses/chatgpt-prompt-eng/lesson/8/chatbot">DeepLearning.AI.</a> The course demonstrated these concepts in a Jupyter Notebook, and I highly recommend it for anyone interested in prompting techniques. In this post, we’ll take that foundational knowledge and transform it into a fully-fledged chatbot.</p>
<h3 id="heading-setting-up-the-server">Setting Up the Server</h3>
<p>In this section, we'll set up a simple Node.js application using Express, with one endpoint for basic text generation with OpenAI. Open your terminal and run the following commands to initialize your Node.js app and install the necessary dependencies:</p>
<pre><code class="lang-bash">mkdir pizza-chatbot
<span class="hljs-built_in">cd</span> pizza-chatbot
npm init -y
npm install express openai dotenv
</code></pre>
<p>Next, create a file named <code>server.js</code> and set up a basic Express server. Here's the code:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { OpenAI } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);
<span class="hljs-keyword">const</span> path = <span class="hljs-built_in">require</span>(<span class="hljs-string">"path"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = <span class="hljs-number">3000</span>;

<span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAI({
  <span class="hljs-attr">apiKey</span>: process.env.OPENAI_PROJECT_KEY,
});

app.use(express.static(path.join(__dirname, <span class="hljs-string">"public"</span>)));
app.use(express.json());

app.get(<span class="hljs-string">"/"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">return</span> res.sendFile(path.join(__dirname, <span class="hljs-string">"public"</span>, <span class="hljs-string">"index.html"</span>));
});

app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`Server is running on http://localhost:<span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<ul>
<li><p><code>app.use(express.static(...))</code> serves static files like HTML, CSS, and JavaScript from the <code>public</code> directory.</p>
</li>
<li><p><code>app.use(express.json())</code> allows us to parse incoming JSON requests.</p>
</li>
<li><p>We create an <code>OpenAI</code> instance using the API key stored in our <code>.env</code> file.</p>
</li>
<li><p>The <code>app.get("/")</code> route serves our <code>index.html</code> file when a user visits the root URL (<code>/</code>) of our application.</p>
</li>
<li><p>The server listens on port 3000, and when it's running, you can access the app at <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>.</p>
</li>
</ul>
<h3 id="heading-implementing-the-chat-endpoint">Implementing the Chat Endpoint</h3>
<p>Let's create the chat endpoint, which will handle conversations between our pizza chatbot and the user.</p>
<pre><code class="lang-javascript">app.post(<span class="hljs-string">"/api/chat"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
  <span class="hljs-keyword">const</span> conversations = req.body.conversations;

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [...context, ...conversations],
  });

  <span class="hljs-keyword">const</span> assistantMessage = response.choices[<span class="hljs-number">0</span>].message.content;

  <span class="hljs-keyword">return</span> res.json({ <span class="hljs-attr">message</span>: assistantMessage });
});
</code></pre>
<ul>
<li><p>The endpoint receives an array of previous conversations from the frontend via the <code>conversations</code> variable. This array holds the back-and-forth messages between the user and the chatbot.</p>
</li>
<li><p>We use OpenAI's <code>chat.completions.create</code> method to generate a response. The method takes in a list of messages, which includes the predefined <code>context</code> (the chatbot's system instructions) and the ongoing <code>conversations</code>.</p>
</li>
</ul>
<h4 id="heading-managing-conversations-with-context"><strong>Managing Conversations with Context</strong></h4>
<p>LLMs (Large Language Models) like GPT-4 are stateless, meaning they don’t remember previous interactions. To keep the conversation flowing, we need to manage the context ourselves by sending the history of the conversation with each new request. There are many advanced techniques to manage context, such as:</p>
<ul>
<li><p><strong>Using Vector Databases</strong>: To store and retrieve relevant conversation history efficiently.</p>
</li>
<li><p><strong>Summarizing Previous Conversations</strong>: To avoid exceeding token limits by summarizing older parts of the conversation.</p>
</li>
<li><p><strong>Reducing Context Length</strong>: By trimming unnecessary details from previous interactions.</p>
</li>
</ul>
<p>These techniques can help in more complex scenarios, but for now, we’re keeping it simple.</p>
<h3 id="heading-crafting-the-system-prompt">Crafting the System Prompt</h3>
<p>The system prompt is a crucial part of our chatbot’s functionality. Here’s the prompt we’re using:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> context = [
  {
    <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
    <span class="hljs-attr">content</span>: <span class="hljs-string">`
      You are OrderBot, an automated service designed to take orders for a pizza restaurant. Start by greeting the customer warmly. Then, proceed to collect their order, ensuring you ask for all the details like toppings, sizes, and extras to accurately identify each item on the menu.
      Once the order is complete, ask whether the customer prefers pickup or delivery. If they choose delivery, be sure to collect the delivery address. Summarize the entire order afterward and confirm if the customer wants to add anything else.
      Finally, collect the payment details. Throughout the conversation, keep your responses short, friendly, and conversational to ensure a smooth ordering experience.
      The menu includes:
      Pepperoni Pizza: $12.95 (Large), $10.00 (Medium), $7.00 (Small)
      Cheese Pizza: $10.95 (Large), $9.25 (Medium), $6.50 (Small)
      Eggplant Pizza: $11.95 (Large), $9.75 (Medium), $6.75 (Small)
      Fries: $4.50 (Large), $3.50 (Small)
      Greek Salad: $7.25
      Toppings:
      Extra Cheese: $2.00
      Mushrooms: $1.50
      Sausage: $3.00
      Canadian Bacon: $3.50
      AI Sauce: $1.50
      Peppers: $1.00
      Drinks:
      Coke: $3.00 (Large), $2.00 (Medium), $1.00 (Small)
      Sprite: $3.00 (Large), $2.00 (Medium), $1.00 (Small)
      Bottled Water: $5.00
    `</span>,
  },
];
</code></pre>
<p><strong>Breaking Down the Prompt:</strong></p>
<ul>
<li><p><strong>Role as a System</strong>: The prompt begins by establishing the chatbot’s role as "OrderBot," which sets the expectations for how it should behave and respond.</p>
</li>
<li><p><strong>Guided Interaction</strong>: It instructs the chatbot to greet the customer warmly, take their order, and ask specific questions about the order details, such as toppings and sizes.</p>
</li>
<li><p><strong>Customer Experience</strong>: The prompt emphasizes a friendly and conversational tone, ensuring that the chatbot’s responses are not only accurate but also pleasant for the user.</p>
</li>
<li><p><strong>Menu Details</strong>: The entire menu is included in the prompt, so the chatbot has all the necessary information to assist the customer in real-time.</p>
</li>
<li><p><strong>Handling the Order Process</strong>: The prompt outlines the steps to collect the order, summarize it, ask for pickup or delivery options, and finally, request payment details.</p>
</li>
</ul>
<p><strong>Prompting Technique</strong>:</p>
<ul>
<li><p><strong>Role-based Prompting</strong>: This technique clearly defines the chatbot’s role and tasks, guiding it to perform a specific function—taking pizza orders in this case.</p>
</li>
<li><p><strong>Contextual Prompting</strong>: By including the entire menu and detailed instructions, the prompt provides a rich context for the chatbot, enabling it to generate more accurate and relevant responses.</p>
</li>
</ul>
<p>This well-structured prompt ensures that the chatbot delivers a smooth and coherent user experience.</p>
<h3 id="heading-designing-the-frontend">Designing the Frontend</h3>
<p>Now that we’ve set up the backend for our chat application, let’s move on to creating the frontend. We’ll be building a simple chat interface using HTML, CSS, and JavaScript. First, create a <code>public</code> folder in your project directory. Inside this folder, create two separate files: <code>index.html</code> and <code>styles.css</code>. In the <code>styles.css</code> file, add the following CSS code:</p>
<pre><code class="lang-css"><span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: Arial, sans-serif;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">100vh</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f0f0f0</span>;
}

<span class="hljs-selector-id">#chat</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80%</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">90%</span>;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">position</span>: relative;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">0</span> <span class="hljs-number">0.625rem</span> <span class="hljs-built_in">rgba</span>(<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0.1</span>);
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
}

<span class="hljs-selector-id">#chat-area</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">overflow-y</span>: auto;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">padding-bottom</span>: <span class="hljs-number">3.5rem</span>;
}

<span class="hljs-selector-class">.chat-message</span> {
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0.625rem</span> <span class="hljs-number">0</span>;
}

<span class="hljs-selector-class">.user</span> {
  <span class="hljs-attribute">text-align</span>: right;
}

<span class="hljs-selector-class">.assistant</span> {
  <span class="hljs-attribute">text-align</span>: left;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f6f6f6</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.625rem</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.3125rem</span>;
}

<span class="hljs-selector-id">#message-input</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.625rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">0.0625rem</span> solid <span class="hljs-number">#ccc</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
}

<span class="hljs-selector-id">#send-button</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.625rem</span> <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#ffffff</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-id">#chat-form</span> {
  <span class="hljs-attribute">position</span>: absolute;
  <span class="hljs-attribute">bottom</span>: <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">left</span>: <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">right</span>: <span class="hljs-number">1.25rem</span>;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">gap</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding-right</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">padding-left</span>: <span class="hljs-number">2rem</span>;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">background</span>: <span class="hljs-number">#ffffff</span>;
}
</code></pre>
<p>In the <code>index.html</code> file, paste the following code:</p>
<pre><code class="lang-xml"><span class="hljs-meta">&lt;!DOCTYPE <span class="hljs-meta-keyword">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">html</span> <span class="hljs-attr">lang</span>=<span class="hljs-string">"en"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">charset</span>=<span class="hljs-string">"UTF-8"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">meta</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"viewport"</span> <span class="hljs-attr">content</span>=<span class="hljs-string">"width=device-width, initial-scale=1.0"</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">title</span>&gt;</span>Chat<span class="hljs-tag">&lt;/<span class="hljs-name">title</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"styles.css"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"chat"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"chat-area"</span>&gt;</span>

      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">form</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"chat-form"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">input</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"text"</span>
          <span class="hljs-attr">id</span>=<span class="hljs-string">"message-input"</span>
          <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter your message here..."</span>
          <span class="hljs-attr">required</span>
        /&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"send-button"</span>&gt;</span>Send<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">form</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
<p>Run <code>node server.js</code> from your terminal and open your browser and go to <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a> to view the chat interface.</p>
<h3 id="heading-handling-chat-actions">Handling Chat Actions</h3>
<p>Now that we have our chat interface set up, let's make it functional by sending the user's messages to the server and displaying the response from our chatbot. We’ll achieve this using JavaScript to handle the form submission and update the chat UI.</p>
<p>To start, we’ll add a <code>&lt;script&gt;</code> tag at the end of our <code>index.html</code> file and include the following JavaScript code:</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
  <span class="hljs-built_in">document</span>.addEventListener(<span class="hljs-string">"DOMContentLoaded"</span>, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">const</span> conversations = [];

    <span class="hljs-comment">// Send an initial message when the page loads</span>
    <span class="hljs-keyword">const</span> initialMessage =
      <span class="hljs-string">"Hi there! 😊 Ready to place your pizza order 🍕 or have any questions? Let me know!"</span>;
    addMessageToChat(<span class="hljs-string">"Assistant"</span>, initialMessage, <span class="hljs-string">"assistant"</span>);

    <span class="hljs-comment">// Set up the form submit event listener</span>
    <span class="hljs-built_in">document</span>
      .getElementById(<span class="hljs-string">"chat-form"</span>)
      .addEventListener(<span class="hljs-string">"submit"</span>, <span class="hljs-keyword">async</span> (event) =&gt; {
        event.preventDefault(); <span class="hljs-comment">// Prevent the default form submission</span>

        <span class="hljs-keyword">const</span> userMessage = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"message-input"</span>).value;
        <span class="hljs-keyword">if</span> (!userMessage) <span class="hljs-keyword">return</span>; <span class="hljs-comment">// Do nothing if the input is empty</span>

        <span class="hljs-comment">// Add user message to chat</span>
        addMessageToChat(<span class="hljs-string">"User"</span>, userMessage, <span class="hljs-string">"user"</span>);

        <span class="hljs-comment">// Add the user's message to the conversation</span>
        conversations.push({ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: userMessage });

        <span class="hljs-comment">// Send the user message to the server</span>
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> fetch(<span class="hljs-string">"/api/chat"</span>, {
          <span class="hljs-attr">method</span>: <span class="hljs-string">"POST"</span>,
          <span class="hljs-attr">headers</span>: { <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span> },
          <span class="hljs-attr">body</span>: <span class="hljs-built_in">JSON</span>.stringify({ conversations }),
        });

        <span class="hljs-keyword">const</span> data = <span class="hljs-keyword">await</span> response.json();
        <span class="hljs-keyword">const</span> assistantMessage = data.message;

        <span class="hljs-comment">// Add assistant's response to chat</span>
        addMessageToChat(<span class="hljs-string">"Assistant"</span>, assistantMessage, <span class="hljs-string">"assistant"</span>);

        <span class="hljs-comment">// Update the conversation with the assistant's message</span>
        conversations.push({ <span class="hljs-attr">role</span>: <span class="hljs-string">"assistant"</span>, <span class="hljs-attr">content</span>: assistantMessage });

        <span class="hljs-comment">// Clear the input field</span>
        <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"message-input"</span>).value = <span class="hljs-string">""</span>;
      });
  });

  <span class="hljs-comment">// Function to add messages to the chat</span>
  <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">addMessageToChat</span>(<span class="hljs-params">sender, message, className</span>) </span>{
    <span class="hljs-keyword">const</span> chat = <span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">"chat-area"</span>);
    <span class="hljs-keyword">const</span> messageElement = <span class="hljs-built_in">document</span>.createElement(<span class="hljs-string">"div"</span>);
    messageElement.className = <span class="hljs-string">`chat-message <span class="hljs-subst">${className}</span>`</span>;
    messageElement.innerHTML = <span class="hljs-string">`&lt;strong&gt;<span class="hljs-subst">${sender}</span>:&lt;/strong&gt; &lt;span class="message-content"&gt;<span class="hljs-subst">${message}</span>&lt;/span&gt;`</span>;
    chat.appendChild(messageElement);
    chat.scrollTop = chat.scrollHeight;
    <span class="hljs-keyword">return</span> messageElement.querySelector(<span class="hljs-string">".message-content"</span>); <span class="hljs-comment">// Return the span where the message content is displayed</span>
  }
</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
</code></pre>
<ul>
<li><p>We are adding a dummy initial message from the assistant (chatbot) when the page loads to greet the user.</p>
</li>
<li><p>We are using the <code>fetch</code> API to send the conversation to the server. Once the server responds, we display the assistant's message in the chat and update the conversation array.</p>
</li>
<li><p>The <code>addMessageToChat</code> function takes care of adding both user and assistant messages to the chat UI. It dynamically creates a new <code>div</code> element for each message, appends it to the chat area, and scrolls to the latest message.</p>
</li>
</ul>
<h4 id="heading-testing-the-chat-application"><strong>Testing the Chat Application</strong></h4>
<ol>
<li><p>Ensure your server is running by executing <code>node server.js</code> in your terminal.</p>
</li>
<li><p>Open your browser and go to <a target="_blank" href="http://localhost:3000"><code>http://localhost:3000</code></a>. You should see the initial greeting message. Type a message in the input field and click "Send" to see the chat in action.</p>
</li>
<li><p>Finish your chat with the bot by ordering a pizza and check if it follows your instructions correctly.</p>
</li>
</ol>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1725107240829/b5389296-0a12-421f-b9a4-5c160b320c95.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this post, we built a basic pizza chatbot using Node.js, Express, and OpenAI. In the next post we will be:</p>
<h4 id="heading-1-adding-streaming-responses"><strong>1. Adding Streaming Responses</strong></h4>
<p>Currently, our chatbot sends a response all at once, which might not provide the best user experience. In a real-world application, streaming responses—where the chatbot sends responses incrementally—can make interactions feel more natural like the ChatGPT Interface. We'll implement streaming in an API and handle it on the frontend for a smoother chat experience.</p>
<h4 id="heading-2-handling-markdown-responses"><strong>2. Handling Markdown Responses</strong></h4>
<p>Our chatbot’s responses include markdown formatting, which can be less user-friendly. Instead of directly sending markdown, we could parse it into HTML on the frontend. This approach will make the responses more visually appealing and easier to read.</p>
<h4 id="heading-3-cost-and-model-considerations"><strong>3. Cost and Model Considerations</strong></h4>
<p>As discussed in our previous posts, the choice of language model (LLM) can impact both cost and performance. While the <code>gpt-4o-mini</code> model is quite powerful, it might be more than necessary for a simple chatbot. We’ll explore alternatives like Mistral or other cost-effective models, which can help reduce both inference time and expenses.</p>
<p>Until then, keep coding 😊.</p>
]]></content:encoded></item><item><title><![CDATA[Gen AI for JavaScript Devs: Exploring Open AI Alternatives: Mistral, Llama, and More]]></title><description><![CDATA[Explore AI alternatives for JavaScript devs, including Mistral, Llama, Cohere, and more. Dive into SDKs and model options]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-exploring-open-ai-alternatives-mistral-llama-and-more</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-exploring-open-ai-alternatives-mistral-llama-and-more</guid><category><![CDATA[genai]]></category><category><![CDATA[llm]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[openai]]></category><category><![CDATA[MistralAI]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Tue, 20 Aug 2024 13:10:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1724159370309/21f4471f-6f64-4aa0-80fa-9329b84263f5.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction:</h3>
<p>In our previous posts in this series, we explored the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-hands-on-with-openai-sdk">OpenAI SDK</a>, in <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-working-with-the-openai-sdk">one of the posts</a> we delved into LLM parameters like temperature, top-p, and top-k. We also covered various <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-prompting-techniques">prompting techniques</a>. In <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case">another post</a>, we explored how to choose the right LLM by comparing pricing across providers and open-source models like Mistral and Llama. We also discussed why you might consider these alternatives for your specific needs.</p>
<p>For instance, when <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case#heading-pricing">discussing pricing</a>, we found that Mistral AI can be up to <strong><mark>10 times cheaper</mark></strong> than OpenAI's ChatGPT, depending on your needs. You can use the Mistral 7B model from providers like <a target="_blank" href="https://www.together.ai/">Together AI</a> or <a target="_blank" href="https://groq.com/">Groq</a> if it fits your use case.</p>
<p>In this post, we'll dive into working with alternative AI SDKs, focusing on providers like Cohere, Anthropic, Together AI and models like Mistral, Llama, and more.</p>
<h3 id="heading-together-ai">Together AI</h3>
<p><a target="_blank" href="https://www.together.ai">Together AI</a> is a powerful platform that offers over 100 open-source LLMs. From text generation models like <a target="_blank" href="https://mistral.ai/">Mistral</a> to the latest <a target="_blank" href="https://llama.meta.com/">LLaMA 3.1 from Facebook</a>, and Google's <a target="_blank" href="https://ai.google.dev/gemma">Gemma 2</a>, to cutting-edge image generation models like <a target="_blank" href="https://stability.ai/news/stable-diffusion-3">Stable Diffusion</a>, Together AI has it all. Many of these models are fine-tuned versions of their originals, making them even better for specific tasks.</p>
<p>One example of a fine-tuned model available on Together AI is the Llama-2-7B-32K-Instruct. This model is built on Meta’s Llama-2 architecture and optimized for handling instruction-based tasks more effectively.</p>
<p>Getting started with Together AI is straightforward. Simply navigate to <a target="_blank" href="https://api.together.ai/">Together AI</a>, sign in, and you'll receive $50 in free credits. Fill out some basic information, get your API keys, and save them for later use. In the playground, you can choose from a variety of models, adjust parameters like temperature, top-p, and top-k, and experiment with your prompts. You can also visit the <a target="_blank" href="https://api.together.ai/models">models page</a> to compare inference costs and make an informed decision. Below is a simple example of using the Together JS SDK.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> Together = <span class="hljs-built_in">require</span>(<span class="hljs-string">"together-ai"</span>)

<span class="hljs-keyword">const</span> togetherAI = <span class="hljs-keyword">new</span> Together({
  <span class="hljs-attr">apiKey</span>: process.env.TOGETHER_API_KEY,
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> togetherAI.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo"</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span>
      }
    ],
  });

  <span class="hljs-built_in">console</span>.log(response.choices[<span class="hljs-number">0</span>].message);
}

main();
</code></pre>
<p>If you've been following this series, you'll notice that the code is very similar to the OpenAI SDK. This means you can easily use both OpenAI's models and Together AI in your application without a steep learning curve. You can even migrate from OpenAI to the latest open-source models with ease.</p>
<h3 id="heading-anthrophics-claude-llms">Anthrophic's Claude LLMs</h3>
<p><a target="_blank" href="https://www.anthropic.com/">Anthropic</a>, founded in 2021 by former OpenAI members, focuses on creating safe and reliable AI systems. Backed by major companies like Amazon and Google, Anthropic has advanced its research significantly.</p>
<p>Their latest model, Claude 3, comes in three versions: Haiku, Sonnet, and Opus, each offering different levels of capability. With a context window of up to 200K tokens, Claude 3 can handle long conversations and complex tasks effectively. In June 2024, Anthropic released Claude 3.5 Sonnet, which is faster, more accurate, and excels at complex tasks like customer support and multi-step workflows.</p>
<p>Go to <a target="_blank" href="https://console.anthropic.com">Anthropic's console</a> and create your first API key. You'll get $5 in credit. Remember, Claude is a proprietary model, not open source. You can check its pricing <a target="_blank" href="https://www.anthropic.com/pricing#anthropic-api">here</a>. Below is the code to make a request to Anthropic's LLM.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> Anthropic = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@anthropic-ai/sdk"</span>);

<span class="hljs-keyword">const</span> anthropic = <span class="hljs-keyword">new</span> Anthropic({
  <span class="hljs-attr">apiKey</span>: process.env.ANTHROPHIC_API_KEY,
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> anthropic.messages.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"claude-3-5-sonnet-20240620"</span>,
    <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">1000</span>,
    <span class="hljs-attr">temperature</span>: <span class="hljs-number">0</span>,
    <span class="hljs-attr">system</span>: <span class="hljs-string">"You are a teacher."</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: [
          {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"text"</span>,
            <span class="hljs-attr">text</span>: <span class="hljs-string">"What is the capital of India?"</span>,
          },
        ],
      },
    ],
  });

  <span class="hljs-built_in">console</span>.log(response.content[<span class="hljs-number">0</span>].text);
}

main();
</code></pre>
<h3 id="heading-cohere">Cohere</h3>
<p>Cohere is a leading AI platform focused on natural language processing (NLP) for enterprise applications. In 2024, they launched Cohere Command, a suite of generative AI models designed for complex business tasks like customer support automation and content creation.</p>
<p>Cohere's SDK is packed with tools and connectors that enhance their language models, making it easy for businesses to integrate advanced NLP features. You can perform tasks like text generation, translation, and classification, all accessible through the <a target="_blank" href="https://dashboard.cohere.com/">Cohere dashboard</a>.</p>
<p>One unique feature is "connectors," which allow you to add tools like web search, enabling the model to access the latest information from the web. Cohere is a powerful platform that I use in my applications, and I plan to create a separate tutorial to cover all its features in detail.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> { CohereClient } = <span class="hljs-built_in">require</span>(<span class="hljs-string">'cohere-ai'</span>);

<span class="hljs-keyword">const</span> cohere = <span class="hljs-keyword">new</span> CohereClient({
  <span class="hljs-attr">token</span>: process.env.COHERE_API_KEY,
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> cohere.chat({
    <span class="hljs-attr">chatHistory</span>: [],
    <span class="hljs-attr">message</span>: <span class="hljs-string">'What is the price of Nvidia stock?'</span>,
    <span class="hljs-comment">// perform web search.</span>
    <span class="hljs-attr">connectors</span>: [{ <span class="hljs-attr">id</span>: <span class="hljs-string">'web-search'</span> }],
  });

  <span class="hljs-built_in">console</span>.log(response);
}

main();
</code></pre>
<p>Check the model's response, and you'll see a <code>documents</code> key—this contains all the information it retrieved from a web search. You can even create custom connectors to access your own data, like from OneDrive. This makes Cohere very powerful.</p>
<h3 id="heading-mistral">Mistral</h3>
<p><a target="_blank" href="https://mistral.ai/"><strong>Mistral AI</strong></a> is a French startup, founded in April 2023 by ex-Meta and Google DeepMind employees, focusing on open-source large language models (LLMs). Their <a target="_blank" href="https://mistral.ai/technology/#models">model family</a> includes the powerful <strong>Mistral 7B</strong> with 7 billion parameters, the efficient <strong>Mixtral 8x7B</strong> with up to 45 billion parameters, and the versatile <strong>Mistral Large</strong>. People love Mistral AI for its commitment to open-source, customization options via fine tuning the models, compute efficiency, and accessibility through various platforms, making advanced AI tools available to everyone.</p>
<p>Head to the <a target="_blank" href="https://console.mistral.ai/">Mistral console</a>, sign up for a free trial, create your API keys, and follow the code below.</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> { Mistral } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"@mistralai/mistralai"</span>);

<span class="hljs-keyword">const</span> mistral = <span class="hljs-keyword">new</span> Mistral({ <span class="hljs-attr">apiKey</span>: process.env.MISTRAL_API_KEY });

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> chatResponse = <span class="hljs-keyword">await</span> mistral.chat.complete({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"mistral-large-latest"</span>,
    <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span> }],
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Chat:"</span>, chatResponse.choices[<span class="hljs-number">0</span>].message.content);
}

main();
</code></pre>
<h3 id="heading-conclusion">Conclusion</h3>
<p>Besides the providers mentioned, we also have <a target="_blank" href="https://www.anyscale.com/">Anyscale AI</a>, <a target="_blank" href="https://www.edenai.co/">Eden AI</a>, and cloud providers like <a target="_blank" href="https://aws.amazon.com/bedrock/">AWS</a>, <a target="_blank" href="https://azure.microsoft.com/en-in/products/ai-studio/">Azure</a>, and <a target="_blank" href="https://cloud.google.com/developers/vertex-ai">Google</a> which offer proprietary models like ChatGPT and Anthropic’s models, along with open-source options like Mistral and Llama. No matter which model you choose, always check its capabilities, pricing, and response time. In the next tutorial, we’ll use everything we’ve learned so far to build a pizza chatbot with Node.js. 🍕🤖. Until next time, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Gen AI for JavaScript Devs: Introduction to Prompting Techniques]]></title><description><![CDATA[Learn key prompting techniques to get the best out of Large Language Models (LLMs) for JavaScript development]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-prompting-techniques</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-prompting-techniques</guid><category><![CDATA[openai]]></category><category><![CDATA[llm]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><category><![CDATA[#PromptEngineering]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Sat, 17 Aug 2024 14:47:48 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723905264322/9d26095e-e632-4b58-a90e-40b7db005024.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In our <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-foundation-models-and-llms">previous post</a>, which kicked off this series on Large Language Models (LLMs), we explored how LLMs differ from traditional models. One key difference is how LLMs work—they are designed to generate text based on the prompts we give them. Think of it like starting a conversation: you give the LLM a prompt, and it responds by completing it by generating text.</p>
<p>The quality of the output from an LLM heavily depends on the prompt you provide. The more detailed and clear your prompt is, the better the response you’ll get from the LLM. That’s why understanding how to craft good prompts is so important when working with these models. In this post, we'll dive deeper into working with the OpenAI SDK and explore some popular techniques for crafting effective prompts.</p>
<p>If you want to master the art of prompting, DeepLearning.AI's "<a target="_blank" href="https://learn.deeplearning.ai/courses/chatgpt-prompt-eng/lesson/1/introduction">ChatGPT Prompt Engineering for Beginners</a>" is the perfect launchpad. This course breaks down the basics of prompt engineering into easy-to-digest lessons, making it accessible even if you're new to AI. You'll explore various prompting techniques that can significantly enhance the effectiveness of your interactions with ChatGPT. It's a must for anyone looking to unlock the full potential of AI in their projects.</p>
<h3 id="heading-basics-of-prompting">Basics of Prompting</h3>
<p>Let’s start with some basic prompts. Imagine we want to write a LinkedIn post about a potential business deal. Below are two prompts—one basic and one with more context —showing how different prompts can lead to different responses. You’ll see how adding context and a system message helps generate more relevant and effective results.</p>
<p><strong>Basic Prompt -</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"Write a LinkedIn connection request.."</span>,
      }],
  });
</code></pre>
<p><strong>Advanced Prompt -</strong></p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">'system'</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">'You are a professional Linkedin user.'</span>
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"Write a personalized LinkedIn connection request to a potential business partner. Mention a shared interest in technology and set a collaborative tone."</span>,
      }],
  });
</code></pre>
<p>In this advanced example, the system message “You are a professional LinkedIn user” helps the LLM generate a more tailored and context-aware connection request. By providing specific details in the prompt, we guide the LLM to produce a message that is not only more engaging but also aligns with the intended purpose. Give the code a try to see the generated response. You can also experiment with the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-working-with-the-openai-sdk#heading-fine-tuning-llm-responses-what-is-llm-temperature">temperature setting</a> to get different results. The <a target="_blank" href="https://platform.openai.com/playground/chat?models=gpt-4o">OpenAI Playground</a> provides a user-friendly interface for this.</p>
<p><strong>How to Write Good Prompts:</strong></p>
<ol>
<li><p>Your Prompt should comprise of the <strong>main goal: What you want the LLM to do</strong> and <strong>Extra info: Details to help the LLM understand better.</strong></p>
</li>
<li><p>Give the AI a role (if needed): Example: <em><mark>You're a Twitter expert who writes popular tweets. Write a tweet about hiking</mark></em>.</p>
</li>
<li><p>Add extra rules or information: Example: <em><mark>Write a tweet about hiking. Use no more than two emojis. Focus on nature lovers. Mention 2 benefits of hiking often</mark></em>.</p>
</li>
<li><p>LLM Output is a starting point, fine tune and adjust it as needed. Tell it what parts need to be improved.</p>
</li>
</ol>
<p><strong>Add Meaningful Context to your Prompts:</strong></p>
<ul>
<li><p>Prefer short, focused sentences.</p>
</li>
<li><p>Add important keywords &amp; avoid unnecessary information.</p>
</li>
<li><p>Define the target audience (for tweets, LinkedIn posts, blog posts)</p>
</li>
<li><p>Control tone, style &amp; length of the output.</p>
</li>
<li><p>You can also control the output format (JSON, etc.)</p>
</li>
</ul>
<h3 id="heading-zero-shot-prompting">Zero Shot Prompting</h3>
<p>Zero-shot prompting is a way to use LLM without giving it special examples. You simply ask the LLM to do a task, and it tries its best using what it already knows. Use zero-shot prompting when:</p>
<ul>
<li><p>You need a quick answer.</p>
</li>
<li><p>The task is simple.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"Tell me how AI helps in hospitals."</span>,
      }],
  });
</code></pre>
<p><strong><mark>In the above example, the LLM gives a helpful answer just from your question, without needing extra information or examples</mark></strong>.</p>
<h3 id="heading-one-shot-prompting">One-Shot Prompting</h3>
<p>One-shot prompting is when you give the LLM one example to help it understand what you want. It's like showing someone how to do something once before asking them to try it themselves. Use one-shot prompting when:</p>
<ul>
<li><p>You want the LLM to follow a specific style.</p>
</li>
<li><p>The task is a bit tricky.</p>
</li>
<li><p>You need to guide the LLM without giving too many instructions.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">'system'</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`You are a professional LinkedIn user. 
        Your task is to write a LinkedIn post announcing new events like the below example.
        Example: 'Greetings from XYZ Corp. Excited to announce our new partnership with XYZ Corp. Together, we're driving innovation in the tech industry!`</span>
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"Now write a LinkedIn post announcing a new product launch."</span>,
      }],
  });
</code></pre>
<p><strong><mark>By giving one example, you help the LLM understand the tone and style you want, so it can give you a better answer</mark></strong>.</p>
<h3 id="heading-few-shot-prompting">Few-Shot Prompting</h3>
<p>Few-shot prompting is when you give the LLM a handful of examples before asking it to do a task. It's like showing someone how to do something a few times before they try it on their own. Use few-shot prompting when:</p>
<ul>
<li><p>You want the LLM to follow a specific pattern</p>
</li>
<li><p>You need the LLM to sort things into categories</p>
</li>
<li><p>You're working on tasks where examples really help, like translating languages in a particular style or particular tone, e.g. Translate some German text into Shakespearian English.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">'system'</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`You are a professional news reader. 
        Your task is to categorize news articles the below examples.
        Article 1: "New electric car saves energy and drives far." Topic: Technology
        Artilce 2: "Latest clothing styles are changing how people dress on the street." Topic: Fashion`</span>
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`What's the topic of this article: "Meditation helps people feel less stressed and focus better".`</span>,
      }],
  });
</code></pre>
<p><strong><mark>By showing a few examples, you help the LLM understand how to sort articles into the right topics.</mark></strong></p>
<h3 id="heading-chain-of-thought-prompting">Chain-of-Thought Prompting</h3>
<p>Chain-of-Thought prompting is like asking the AI to "show its work." Instead of just giving an answer, the AI explains how it got there, step by step. Use Chain-of-Thought prompting when:</p>
<ul>
<li><p>You have a tricky problem to solve.</p>
</li>
<li><p>You want to see how the AI thinks and want to verify it.</p>
</li>
<li><p>The task has multiple steps.</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`Solve the following math problem and show your work: What is 25% of 80?`</span>,
      }],
  });
</code></pre>
<p><strong><mark>By explaining each step, the AI shows you its thinking process. This helps you understand the answer better and makes sure the AI is on the right track.</mark></strong></p>
<h3 id="heading-prompts-with-output-templates">Prompts with Output Templates</h3>
<p>Output templates are like forms you give the AI to fill out. They help you get information in a neat, organized way. Use output templates when:</p>
<ul>
<li><p>You want information in the same format every time</p>
</li>
<li><p>You need to compare different things easily</p>
</li>
<li><p>You're making lists or collecting specific details</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`Tell me about 5 great summer vacation spots. Use this form:
            Place:
            When to go:
            How warm it gets:
            How much sun you'll see:
            How often it rains:
        `</span>,
      }],
  });
</code></pre>
<p><strong><mark>By using a template, you get all the information you want in a tidy, easy-to-read format.</mark></strong></p>
<h3 id="heading-perspective-prompting">Perspective Prompting</h3>
<p>Perspective prompting involves framing your prompt from a specific point of view or role. By doing this, you guide the LLM to generate responses that align with a particular perspective, making the output more tailored and relevant. Use perspective prompting when:</p>
<ul>
<li><p>You want answers from a specific point of view</p>
</li>
<li><p>You need to understand different roles or experiences</p>
</li>
<li><p>You're creating content for particular groups of people</p>
</li>
</ul>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [{
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">`Create a travel plan for a 2-week yoga retreat in Austria from the perspective of a yoga trainer.`</span>,
      }],
  });
</code></pre>
<h3 id="heading-laddering-prompting">Laddering Prompting</h3>
<p>Laddering prompting involves breaking down a complex task into smaller, manageable prompts. Instead of tackling everything at once, you handle each part step by step. This approach helps in building detailed and accurate responses, especially for intricate projects. Use laddering prompting when:</p>
<ol>
<li><p>The task is too big or complex for one question</p>
</li>
<li><p>You need to break down a problem into smaller steps</p>
</li>
<li><p>You want a well-organized, step-by-step answer</p>
</li>
</ol>
<p>For example, if you're writing a long report, you might first ask about the main topics, then about each topic in detail, and finally how to put it all together.</p>
<p>Another example, imagine you want to create a complete REST API. Instead of trying to do it all in one prompt, you can break it down into smaller steps, setup the project, connect to the database, create schemas, create endpoints, etc.</p>
<h3 id="heading-delimiters-in-prompts">Delimiters in Prompts</h3>
<p>Delimiters are used to clearly separate different parts of a prompt, making it easier for AI to understand and respond accurately. Common delimiters include triple quotation marks (<code>"""</code>) and XML tags (<code>&lt;tag&gt;</code>). These helps structure the prompt, ensuring that instructions, examples, and other information are distinct and easy to follow.</p>
<h4 id="heading-example-1-triple-quotation-marks">Example 1: Triple Quotation Marks</h4>
<p>Triple quotation marks are useful for enclosing larger blocks of text. They help in clearly demarcating sections within a prompt.</p>
<pre><code class="lang-plaintext">Instruction: Please summarize the text delimited by """.
""" your text .... """
</code></pre>
<h4 id="heading-example-2-xml-tags">Example 2: XML Tags</h4>
<p>XML tags provide a more structured way to label different parts of a prompt. This method is particularly useful for complex prompts with multiple sections.</p>
<pre><code class="lang-plaintext">&lt;instruction&gt;
Please summarize the following text.
&lt;/instruction&gt;
&lt;text&gt;
your text ....
&lt;/text&gt;
</code></pre>
<h3 id="heading-enhancing-your-prompts">Enhancing your Prompts</h3>
<p>If you're ever unsure about crafting the perfect prompt, why not let the LLM help you out? You can ask the model itself to generate prompts, making the process much easier. <mark>Once you've got your prompts, it's crucial to compare the outputs to see which ones deliver the best results</mark>. Tools like <a target="_blank" href="https://www.youtube.com/watch?v=8wD7xeIF3uY">Anthropic's workbench</a> are great for this—allowing you to generate, test, and compare prompts in one powerful platform. You can even run test cases to fine-tune your prompts. If you're curious about how different LLMs respond to the same prompts, <a target="_blank" href="https://www.airtrain.ai/features/llm-playground">Airtrain.ai</a> lets you compare outputs side by side, helping you choose the best LLM for your needs. And for managing and observing your prompts, <a target="_blank" href="https://pezzo.ai/">Pezzo</a> offers a comprehensive platform to keep everything organized and optimized.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this article, we explored various prompting techniques and discussed how to tailor prompts for better results with LLMs. To reiterate, the prompt you define directly influences the output you get from the model. Crafting effective prompts is crucial for your day-to-day tasks and applications.</p>
<p>Make sure to include relevant context in your prompts to guide the LLM effectively. Don't hesitate to experiment with different prompts and compare multiple responses to find the best outcome. LLMs are versatile tools used for various tasks, including translation, content creation, and more. Tailor your prompts to fit each specific use case to maximize their effectiveness.</p>
<p>In the next post, we'll dive into using other LLM SDKs. We'll explore how to work with open-source models such as Mistral and Llama, as well as proprietary LLMs offered by Cohere and Anthropic. Until then, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Gen AI for JavaScript Devs: Working with the OpenAI SDK]]></title><description><![CDATA[Discover memory, temperature, top-P, and top-K in LLMs using OpenAI SDK. Learn to balance context, cost, and creativity in responses]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-working-with-the-openai-sdk</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-working-with-the-openai-sdk</guid><category><![CDATA[llm]]></category><category><![CDATA[AI]]></category><category><![CDATA[open ai]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Thu, 15 Aug 2024 16:23:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723738595672/db7340c9-5526-4520-81f7-281f11674ae0.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-hands-on-with-openai-sdk">Last time</a>, we set up our project with OpenAI SDK and made our first API call. Now, we're going deeper into the SDK's features and exploring key concepts in large language models (LLMs). In this post, we'll cover:</p>
<ol>
<li><p><strong>Memory in LLMs</strong>: How to keep context in chatbots.</p>
</li>
<li><p><strong>Temperature</strong>: What it is and how it affects LLM responses.</p>
</li>
<li><p><strong>Top-P and Top-K</strong>: Tweaking these to improve LLM responses.</p>
</li>
</ol>
<p>While we're using OpenAI's SDK, these concepts apply to most LLMs and their tools.</p>
<h3 id="heading-memory-in-llms-understanding-context-and-pricing">Memory in LLMs: Understanding Context and Pricing</h3>
<p>LLMs Don't Have Built-in Memory. LLMs don't remember previous conversations on their own. They're designed to generate text based on the input they receive at that moment. This means each time you ask a question, it's like starting a new conversation. Let's look at an example:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> responseOne = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4 year olds."</span>,
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span>,
      },
    ],
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"First Response"</span>, responseOne.choices[<span class="hljs-number">0</span>].message);

  <span class="hljs-keyword">const</span> responseTwo = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"How large is it?"</span>,
      },
    ],
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Second Response"</span>, responseTwo.choices[<span class="hljs-number">0</span>].message);
}
</code></pre>
<p>The responses:</p>
<pre><code class="lang-plaintext">First Response {
  role: 'assistant',
  content: "The capital of India is New Delhi! It's a big city where the government works and many important decisions are made. Do you want to know more about New Delhi?",
  refusal: null
}
Second Response {
  role: 'assistant',
  content: 'Could you please provide more context or specify what "it" refers to? That way, I can give you a more accurate answer.',
  refusal: null
}
</code></pre>
<p>As you can see, the second response doesn't know we were talking about New Delhi. The LLM treats each request as brand new.</p>
<h3 id="heading-managing-memory-the-developers-job">Managing Memory: The Developer's Job</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> messages = [
    {
      <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
      <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4 year olds."</span>,
    },
  ];

  messages.push({
    <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
    <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span>,
  });

  <span class="hljs-keyword">const</span> responseOne = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    messages,
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"First Response"</span>, responseOne.choices[<span class="hljs-number">0</span>].message);

  messages.push({
    <span class="hljs-attr">role</span>: responseOne.choices[<span class="hljs-number">0</span>].message.role,
    <span class="hljs-attr">content</span>: responseOne.choices[<span class="hljs-number">0</span>].message.content,
  });

  messages.push({
    <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
    <span class="hljs-attr">content</span>: <span class="hljs-string">"How large is it ?"</span>,
  });

  <span class="hljs-keyword">const</span> responseTwo = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    messages,
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"Second Response"</span>, responseTwo.choices[<span class="hljs-number">0</span>].message);
}
</code></pre>
<p>Above is a simple way to maintain context in our conversations with the LLM. We can keep track of all messages in a <code>messages</code> array, which includes both user inputs and AI responses. Whenever we make a new request to the LLM, we send the entire <code>messages</code> array along with it.</p>
<p>This method is quite straightforward. It’s easy to implement, and it ensures that the LLM has access to the full conversation history. But there is an issue. <strong>As conversations get longer, passing the entire history to the LLM for each new message increases the token count</strong>. <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case#heading-pricing"><strong>This directly impacts your costs</strong></a>. For example, after 20 messages, you'd be sending all 20 previous messages plus the new one each time.</p>
<p>There are more sophisticated ways to handle memory, like using libraries such as <a target="_blank" href="https://python.langchain.com/v0.1/docs/modules/memory/">LangChain's Memory feature</a>. These can help manage long conversations more efficiently, but they're complex enough to warrant their own tutorial in the future.</p>
<p>Other LLM providers, like <a target="_blank" href="https://cohere.com/">Cohere</a>, make it even easier. Their SDK allows you to simply add a <code>conversation_id</code>, and it will automatically <a target="_blank" href="https://docs.cohere.com/docs/chat-api#using-conversation_id-to-save-chat-history">manage the conversation</a> history and context for you.</p>
<p>Few approaches to LLM memory management as highlighted below -</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td>Approach</td><td>Pro</td><td>Con</td></tr>
</thead>
<tbody>
<tr>
<td>Pass the entire conversation</td><td>Maintains full context.</td><td>Can quickly hit token limits and increase costs.</td></tr>
<tr>
<td>Keep only recent messages</td><td>Balances context and token count.</td><td>May lose some important earlier context.</td></tr>
<tr>
<td>Summarize previous messages</td><td>Maintains context while reducing token count.</td><td>Requires additional LLM processing and may lose some details.</td></tr>
</tbody>
</table>
</div><h3 id="heading-pricing-control-limiting-tokens">Pricing Control: Limiting Tokens</h3>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4 year olds."</span>,
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span>,
      },
    ],
  });

  <span class="hljs-built_in">console</span>.dir(response, { <span class="hljs-attr">depth</span>: <span class="hljs-literal">null</span>, <span class="hljs-attr">colors</span>: <span class="hljs-literal">true</span> });
}
</code></pre>
<p>I have discussed in depth about tokens, in my <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-decoding-llms-from-tokens-to-embeddings">previous post</a>. Tokens are the basic units that LLMs process. They can be parts of words, whole words, or even punctuation marks. <strong>LLMs charge based on the number of tokens used, both in your input (prompt) and in the generated output.</strong> In the example above we are printing the whole response object -</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">id</span>: <span class="hljs-string">'chatcmpl-9wUBsQCvYQGWOvZif7UWrPl0vPefs'</span>,
  <span class="hljs-attr">object</span>: <span class="hljs-string">'chat.completion'</span>,
  <span class="hljs-attr">created</span>: <span class="hljs-number">1723726104</span>,
  <span class="hljs-attr">model</span>: <span class="hljs-string">'gpt-4o-mini-2024-07-18'</span>,
  <span class="hljs-attr">choices</span>: [
    {
      <span class="hljs-attr">index</span>: <span class="hljs-number">0</span>,
      <span class="hljs-attr">message</span>: {
        <span class="hljs-attr">role</span>: <span class="hljs-string">'assistant'</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"The capital of India is New Delhi! It's a big city with lots of important buildings and places. Would you like to know more about India or its culture?"</span>,
        <span class="hljs-attr">refusal</span>: <span class="hljs-literal">null</span>
      },
      <span class="hljs-attr">logprobs</span>: <span class="hljs-literal">null</span>,
      <span class="hljs-attr">finish_reason</span>: <span class="hljs-string">'stop'</span>
    }
  ],
  <span class="hljs-attr">usage</span>: { <span class="hljs-attr">prompt_tokens</span>: <span class="hljs-number">30</span>, <span class="hljs-attr">completion_tokens</span>: <span class="hljs-number">32</span>, <span class="hljs-attr">total_tokens</span>: <span class="hljs-number">62</span> },
  <span class="hljs-attr">system_fingerprint</span>: <span class="hljs-string">'fp_507c9469a1'</span>
}
</code></pre>
<p>In the LLM's response, you can see the usage. For example, if it shows 62 tokens were used, that's what you'll be charged for. You can check the pricing for Open AI models <a target="_blank" href="https://openai.com/api/pricing/">here</a>.</p>
<p>To check token counts before sending requests:</p>
<ol>
<li><p>Use OpenAI's '<a target="_blank" href="https://www.npmjs.com/package/tiktoken">tiktoken</a>' package.</p>
</li>
<li><p>Or use this handy tool: <a target="_blank" href="https://platform.openai.com/tokenizer">OpenAI Platform Token Counter</a>.</p>
</li>
</ol>
<p>When building apps with LLMs, it's crucial to manage costs. Here are two ways to limit token usage:</p>
<ol>
<li><p><strong>Limiting Input Tokens</strong>: Use the '<a target="_blank" href="https://www.npmjs.com/package/tiktoken">tiktoken</a>' package to count tokens in your prompt. Adjust your prompt if it's too long.</p>
</li>
<li><p><strong>Limiting Output Tokens</strong>: Use the '<strong>max_tokens</strong>' parameter in your API call. This sets a cap on how many tokens the LLM can generate in its response</p>
</li>
</ol>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
  <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
  <span class="hljs-attr">messages</span>: [<span class="hljs-comment">/* your messages here */</span>],
  <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">100</span>  <span class="hljs-comment">// This limits the response to 100 tokens</span>
});
</code></pre>
<p>Why Limit Tokens?</p>
<ul>
<li><p><strong>Cost Control</strong>: Prevent unexpected high bills.</p>
</li>
<li><p><strong>Performance</strong>: Shorter responses can be generated faster.</p>
</li>
<li><p><strong>Focused Answers</strong>: Encourages more concise, targeted responses.</p>
</li>
</ul>
<p>Remember, finding the right balance is key. Too few tokens might cut off important information, while too many could lead to unnecessary costs.</p>
<h3 id="heading-fine-tuning-llm-responses-what-is-llm-temperature">Fine-tuning LLM Responses: What is LLM Temperature?</h3>
<p>As discussed in the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-foundation-models-and-llms">previous post</a> LLMs are text generation models. It starts by reading the context you've provided (prompt), much like reading a book and trying to guess the next word.</p>
<p><strong>Example:</strong> If the LLM is completing the sentence "The sky is ______," it might assign probabilities like this:</p>
<ul>
<li><p>"blue" (40% chance)</p>
</li>
<li><p>"cloudy" (30% chance)</p>
</li>
<li><p>"clear" (20% chance)</p>
</li>
<li><p>"beautiful" (10% chance)</p>
</li>
</ul>
<p>The LLM is likely to choose "blue," but sometimes it might surprise you. This variety makes LLM responses feel natural and diverse.</p>
<p>Temperature is a setting that controls how creative or predictable an AI's responses will be. Think of it like a creativity knob you can adjust. How Temperature Works:</p>
<ol>
<li><p><strong>Low Temperature (0 to 0.5)</strong>: The AI plays it safe. It gives predictable, common answers. Good for tasks needing accurate, consistent responses. Example: Answering factual questions, a quiz chatbot, etc.</p>
</li>
<li><p><strong>High Temperature (0.5 to 1)</strong>: The AI gets more creative. It might give unusual or unexpected answers. Good for tasks needing originality. Example: Brainstorming ideas, writing stories, a sales pitch chatbot, etc.</p>
</li>
</ol>
<p>Example in code:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
  <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
  <span class="hljs-attr">messages</span>: [<span class="hljs-comment">/* your messages here */</span>],
  <span class="hljs-attr">temperature</span>: <span class="hljs-number">0.7</span>  <span class="hljs-comment">// Adjust this value between 0 and 1</span>
});
</code></pre>
<ul>
<li><p>Low temperature doesn't mean "better" - it depends on what you need.</p>
</li>
<li><p>Experiment with different settings to find what works best for your task.</p>
</li>
</ul>
<p>By adjusting temperature, you can fine-tune the AI's responses to better suit your needs, whether you're looking for creativity or consistency. <mark>You can try playing around with different temperature values for your prompts at the </mark> <a target="_blank" href="https://platform.openai.com/playground/chat?models=gpt-4o"><mark>OpenAI Playgournd</mark></a><mark>.</mark></p>
<h3 id="heading-fine-tuning-llm-responses-top-p-amp-top-k-parameters">Fine-tuning LLM Responses: Top-P &amp; Top-K parameters</h3>
<p>Now, let’s talk about <a target="_blank" href="https://www.youtube.com/watch?v=aDmp2Uim0zQ">top-p and top-k</a>, which influence how the LLM chooses words.</p>
<p><strong>Top-P (Nucleus Sampling):</strong> Imagine you're at an ice cream shop, and the flavors represent words. Top-P is like saying, "I'll only look at flavors that make up <strong>75%</strong> of all sales." This approach is flexible—you might consider just a few super popular flavors or a larger mix.</p>
<p><strong>Example:</strong> If top-p is 0.75 and you have:</p>
<ul>
<li><p>Vanilla (40% popularity)</p>
</li>
<li><p>Chocolate (35% popularity)</p>
</li>
<li><p>Strawberry (15% popularity)</p>
</li>
<li><p>Mint (10% popularity)</p>
</li>
</ul>
<p>You'd only consider Vanilla, Chocolate, and Strawberry because they add up to over 75%. <strong>This is how the LLM will generate text, if you set the</strong> <code>top_p</code> <strong>parameter</strong>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
  <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
  <span class="hljs-attr">messages</span>: [<span class="hljs-comment">/* your messages here */</span>],
  <span class="hljs-attr">top_p</span>: <span class="hljs-number">0.75</span>
});
</code></pre>
<p><strong>Top-K:</strong> On the other hand, top-k is like saying, "I'll only look at the top 3 most popular flavors," regardless of their exact popularity. Example - If top-k is 3, you always consider Vanilla, Chocolate, and Strawberry. <strong>This is how the LLM will generate text, if you set the</strong> <code>top_K</code> <strong>parameter</strong>. You can play with all these parameters in the <a target="_blank" href="https://platform.openai.com/playground/chat?models=gpt-4o">Open AI Playground</a>. <mark>The OpenAI SDK doesn't offer a top-k setting, but other LLM providers do, like </mark> <a target="_blank" href="https://www.anthropic.com/"><mark>Anthropic's Claude</mark></a>.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> anthropic.messages.create({
  <span class="hljs-attr">model</span>: <span class="hljs-string">"claude-3-5-sonnet-20240620"</span>,
  <span class="hljs-attr">max_tokens</span>: <span class="hljs-number">1024</span>,
  <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"Hello, Claude"</span> }],
  <span class="hljs-attr">top_K</span>: <span class="hljs-number">50</span>
});
</code></pre>
<p><strong>How They Differ from Temperature:</strong> While top-p and top-k decide which words the LLM can choose from, the temperature setting adjusts how "daring" the AI is in making its choices.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In this tutorial, we explored OpenAI SDK, focusing on memory, conversational context, and tokens. We discussed how tokens impact pricing and how to fine-tune LLM responses using parameters like temperature, Top-P, and Top-K, all with the popular OpenAI SDK. In the next tutorial, we'll dive into some prompting techniques with OpenAI SDK. Until then, keep coding!</p>
]]></content:encoded></item><item><title><![CDATA[Gen AI for JavaScript Devs: Hands-on with OpenAI SDK]]></title><description><![CDATA[Get started with the OpenAI SDK in JavaScript. Learn how to integrate ChatGPT into your projects and customize interactions]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-hands-on-with-openai-sdk</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-hands-on-with-openai-sdk</guid><category><![CDATA[JavaScript]]></category><category><![CDATA[llm]]></category><category><![CDATA[open ai]]></category><category><![CDATA[chatgpt]]></category><category><![CDATA[basics]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Wed, 14 Aug 2024 16:29:19 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1723652932297/baa0795d-9dc1-4759-8e04-fd30d74fcc36.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In our <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case">previous posts</a>, we explored the basics of Large Language Models (LLMs) and how to choose the right one for your needs. Now, it’s time to roll up our sleeves and dive into the code. This post is getting started with using the OpenAI SDK in JavaScript, enabling you to bring the power of ChatGPT directly into your projects.</p>
<h3 id="heading-getting-your-openai-project-keys">Getting Your OpenAI Project Keys</h3>
<p>First things first—let’s get you set up with the necessary credentials. Head over to the <a target="_blank" href="https://platform.openai.com">OpenAI platform</a> and log in using your ChatGPT credentials (or create an account if you’re new). Once logged in, go to <a target="_blank" href="https://platform.openai.com/settings/profile">User Settings &gt; OpenAI API</a>. You might need to set up billing—it’s a quick process and just a formality to get started.</p>
<p>OpenAI organizes your work neatly: your account can house multiple projects under one organization, which is great for managing different AI applications.</p>
<p>Now, let’s create your <strong>Project Key</strong>. Navigate to <a target="_blank" href="https://platform.openai.com/api-keys">API Keys &gt; OpenAI API</a> and click <strong>"Create secret key."</strong> Select your project, and voilà! Your key is ready. Make sure to copy and store it safely—you won’t be able to see it again. With this key in hand, you’re all set to start working with the OpenAI SDK.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">💡</div>
<div data-node-type="callout-text">A quick reminder: working with the SDK isn’t free. As we covered in a <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case">previous post</a>, LLMs are billed based on the tokens you use (both in your prompts and the AI’s responses). You can keep track of your usage in the <a target="_blank" href="https://platform.openai.com/settings/organization/billing/overview">OpenAI Billing Dashboard</a>.</div>
</div>

<h3 id="heading-making-a-request-with-the-openai-sdk">Making a Request with the OpenAI SDK</h3>
<p>Now for the fun part—let’s get your Node.js project set up. Follow these steps to get up and running:</p>
<ol>
<li><p><strong>Install the necessary packages</strong>:</p>
<pre><code class="lang-bash"> npm install openai dotenv
</code></pre>
</li>
<li><p><strong>Create a</strong> <code>.env</code> file in the root of your project, and add your OpenAI Project key:</p>
<pre><code class="lang-plaintext"> OPENAI_PROJECT_KEY=your_openai_project_key_here
</code></pre>
</li>
<li><p><strong>Create a file named</strong> <code>app.js</code> and paste the following code:</p>
<pre><code class="lang-javascript"> <span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
 <span class="hljs-keyword">const</span> { OpenAI } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);

 <span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAI({
   <span class="hljs-attr">apiKey</span>: process.env.OPENAI_PROJECT_KEY,
 });

 <span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
   <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
     <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
     <span class="hljs-attr">messages</span>: [{ <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span> }],
   });

   <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"AI Response"</span>, response.choices[<span class="hljs-number">0</span>].message);
 }

 main();
</code></pre>
</li>
<li><p>After you run your code, you should see something like this in your terminal:</p>
<pre><code class="lang-plaintext"> AI Response {
   role: 'assistant',
   content: 'The capital of India is New Delhi.',
   refusal: null
 }
</code></pre>
</li>
</ol>
<p>Congratulations! You’ve just made your first AI call. Let’s break down what’s happening:</p>
<ul>
<li><p><strong>Model</strong>: When working with the OpenAI SDK, it’s important to select the right LLM for your needs. OpenAI offers <a target="_blank" href="https://platform.openai.com/docs/models">various models</a>. <strong><mark>Each model has unique strengths, context length, and pricing</mark></strong>. For instance, GPT-3.5 is great for text generation, while <code>gpt-4o</code> and <code>gpt-4o-mini</code> can handle both text and images. Check the pricing for each model <a target="_blank" href="https://openai.com/api/pricing/">here</a>. Consider your project’s requirements before choosing a model. <mark>I highly recommend you read my </mark> <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case"><mark>previous post</mark></a> <mark>on this topic.</mark></p>
</li>
<li><p><strong>Making the Request</strong>: You asked the AI a question—“What is the capital of India?”—which you sent in an array of messages with the role set to <code>'user'</code>. This role tells the AI that the message is coming from a user.</p>
</li>
<li><p><strong>The Response</strong>: The AI replies with a message where the role is <code>'assistant'</code>. This indicates the response is from the AI, and the content contains the actual answer: “The capital of India is New Delhi.”</p>
</li>
<li><p><strong>The Role Parameter</strong>: The role parameter is key to managing conversations. By setting <code>role: 'user'</code>, you tell the AI that the message is from the user. When the AI responds, it uses <code>role: 'assistant'</code> to indicate that it’s replying. This system helps structure interactions.</p>
</li>
</ul>
<h4 id="heading-customizing-roles"><strong>Customizing Roles</strong></h4>
<p>You can add more depth to your interactions by customizing roles. For example, you can introduce a <code>'system'</code> role to guide the AI’s behavior:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
        { <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4-year-olds."</span> },
        { <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span> }
    ],
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"AI Response"</span>, response.choices[<span class="hljs-number">0</span>].message);
}
</code></pre>
<p>Here’s what the AI might say:</p>
<pre><code class="lang-plaintext">AI Response {
  role: 'assistant',
  content: "The capital of India is New Delhi! It's a big city where important government buildings are located. Have you ever seen pictures of New Delhi? It has beautiful parks and monuments!",
  refusal: null
}
</code></pre>
<p>In this example, the <code>system</code> role acts as a guide, setting the context for the AI. By telling the AI to be a friendly teacher, you influence how it responds to the user’s question. The <code>system</code> role is handy for scenarios where you need consistent behavior from the AI. For example:</p>
<ul>
<li><p><strong>Customer Support</strong>: Set the AI to be patient and empathetic.</p>
</li>
<li><p><strong>Educational Tool</strong>: Instruct the AI to be detailed and thorough in its explanations.</p>
</li>
<li><p><strong>Creative Writing</strong>: Guide the AI to adopt a particular style or tone, like being humorous or serious.</p>
</li>
</ul>
<h3 id="heading-working-with-multimodal-llms"><strong>Working with Multimodal LLMs</strong></h3>
<p>Using multimodal LLMs like <code>gpt-4o-mini</code> is straightforward. These models can handle both text and images, offering a wide range of applications. Here’s how you can work with an image in your AI request:</p>
<pre><code class="lang-javascript"><span class="hljs-built_in">require</span>(<span class="hljs-string">"dotenv/config"</span>);
<span class="hljs-keyword">const</span> { OpenAI } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"openai"</span>);
<span class="hljs-keyword">const</span> fs = <span class="hljs-built_in">require</span>(<span class="hljs-string">"fs"</span>);

<span class="hljs-keyword">const</span> openai = <span class="hljs-keyword">new</span> OpenAI({
  <span class="hljs-attr">apiKey</span>: process.env.OPENAI_PROJECT_KEY,
});

<span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> base64Image = Buffer.from(fs.readFileSync(<span class="hljs-string">"laptop.jpeg"</span>)).toString(<span class="hljs-string">"base64"</span>);

  <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> openai.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>,
        <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4-year-olds."</span>,
      },
      {
        <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>,
        <span class="hljs-attr">content</span>: [
          { <span class="hljs-attr">type</span>: <span class="hljs-string">"text"</span>, <span class="hljs-attr">text</span>: <span class="hljs-string">"What is this image about?"</span> },
          {
            <span class="hljs-attr">type</span>: <span class="hljs-string">"image_url"</span>,
            <span class="hljs-attr">image_url</span>: { <span class="hljs-attr">url</span>: <span class="hljs-string">`data:image/png;base64,<span class="hljs-subst">${base64Image}</span>`</span> },
          },
        ],
      },
    ],
  });

  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">"AI Response"</span>, response.choices[<span class="hljs-number">0</span>].message);
}
</code></pre>
<p>Here’s an example of what the AI might say:</p>
<pre><code class="lang-plaintext">AI Response {
  role: 'assistant',
  content: "The image shows a laptop, specifically a MacBook Pro, with a scenic nature background displayed on the screen. The background seems to depict hills and trees, suggesting a beautiful outdoor landscape. The laptop's keyboard and trackpad are visible as well. It appears to be resting on a colorful tablecloth.",
  refusal: null
}
</code></pre>
<p>In this case, the content for the user is an array of objects, containing both text and image data. The <code>image_url</code> can either be a base64 encoded string for images stored on your device or a regular URL for images from the web.</p>
<h3 id="heading-streaming">Streaming</h3>
<p>The <code>stream</code> parameter is an option you can use when making requests to the OpenAI API. By default, when you request a completion from the API, the entire response is generated and sent back to you all at once. This can take some time, especially for longer responses.</p>
<p>When you set the <code>stream</code> parameter to <code>true</code>, the API sends the response back in smaller chunks as they are generated. This means you can start processing or displaying the response before the entire completion is finished.</p>
<p>You might want to use the <code>stream</code> parameter in situations where providing <strong>real-time feedback</strong> is crucial, such as in chat applications where streaming can make <strong>interactions feel more responsive</strong>. It’s also beneficial for tasks that generate long responses, as it allows you to start processing the data sooner rather than waiting for the entire response to be generated. Additionally, streaming can significantly enhance the user experience by <strong>reducing perceived latency</strong>, making your application feel faster and more interactive.</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">async</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">main</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> stream = <span class="hljs-keyword">await</span> openAI.chat.completions.create({
    <span class="hljs-attr">model</span>: <span class="hljs-string">"gpt-4o-mini"</span>,
    <span class="hljs-attr">messages</span>: [
        { <span class="hljs-attr">role</span>: <span class="hljs-string">"system"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"You are a friendly teacher, teaching 4-year-olds."</span> },
        { <span class="hljs-attr">role</span>: <span class="hljs-string">"user"</span>, <span class="hljs-attr">content</span>: <span class="hljs-string">"What is the capital of India?"</span> }
    ],
    <span class="hljs-attr">stream</span>: <span class="hljs-literal">true</span>,
  });

  <span class="hljs-keyword">for</span> <span class="hljs-keyword">await</span> (<span class="hljs-keyword">const</span> chunk <span class="hljs-keyword">of</span> stream) {
    process.stdout.write(chunk.choices[<span class="hljs-number">0</span>]?.delta?.content || <span class="hljs-string">""</span>);
  }
}

main()
</code></pre>
<h3 id="heading-conclusion"><strong>Conclusion</strong></h3>
<p>In this post, we finally got our hands dirty with some code, starting with the OpenAI Node.js SDK. I encourage you to experiment with different models and prompts to familiarize yourself with the SDK. In our next post, we’ll dive deeper into the OpenAI SDK, exploring LLM memory, tokens, temperature, and other parameters you can tweak. Until next time, happy coding!</p>
]]></content:encoded></item><item><title><![CDATA[GEN AI for JavaScript Devs: Picking the Ideal LLM for Your Use Case]]></title><description><![CDATA[A guide for JavaScript developers on choosing the best large language model (LLM) for various use cases, with practical tips and pricing insights]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-picking-the-ideal-llm-for-your-use-case</guid><category><![CDATA[genai]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[llm]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Tue, 23 Jul 2024 10:38:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721731007757/44896494-25a2-4fe1-add8-acbd912a81d3.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In our <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-decoding-llms-from-tokens-to-embeddings">previous post</a>, we explored how large language models (LLMs) generate text without delving into the complexities of machine learning. Today, we'll tackle an essential question for developers: How do you choose the right LLM for your project?</p>
<p>The world of LLMs is vast and growing rapidly. We have open source LLMs like <a target="_blank" href="https://mistral.ai/">Mistral from Mistral AI</a>, <a target="_blank" href="https://llama.meta.com/">LLaMA from Facebook</a>. We have Proprietary LLMs like <a target="_blank" href="https://openai.com/index/gpt-4/">GPT-4 from OpenAI</a>, <a target="_blank" href="https://ai.google/discover/palm2">PaLM from Google</a>. LLMs generating images like <a target="_blank" href="https://stability.ai/">Stable Diffusion</a> models. Multimodal LLMs (working with text, speech, and images) like <a target="_blank" href="https://gemini.google.com/app?hl=en-IN">Gemini from Google</a>, <a target="_blank" href="https://openai.com/index/hello-gpt-4o/">GPT-4o from OpenAI</a>. Other LLM providers like <a target="_blank" href="https://www.anthropic.com/claude">Claude AI from Anthropic</a>, <a target="_blank" href="https://cohere.com/">Cohere AI</a>. Cloud providers offering both open source and proprietary AI service like <a target="_blank" href="https://azure.microsoft.com/en-us/products/ai-studio">Azure AI Studio</a>, <a target="_blank" href="https://aws.amazon.com/bedrock/">Amazon Bedrock</a>, <a target="_blank" href="https://cloud.google.com/vertex-ai">Google Cloud Vertex AI</a>. Finally we have LLM platforms like <a target="_blank" href="https://huggingface.co/pricing#endpoints">HugginFace</a>, <a target="_blank" href="https://www.anyscale.com/">AnyScale</a>, <a target="_blank" href="https://www.together.ai/">Together AI</a>, <a target="_blank" href="https://groq.com/">Groq</a> offering a wide range of LLM solutions.</p>
<p>As JavaScript developers new to this field, choosing the right LLM can seem overwhelming. Let's dive deeper into this topic and explore how to make the best choice for your application and use case.</p>
<h3 id="heading-some-key-factors-in-choosing-an-ai-model">Some Key Factors in Choosing an AI Model:</h3>
<p><strong>Modality</strong>: Decide if you need a model that works with text, images, or both. For example, if you're building a chatbot, a text-based model like <a target="_blank" href="https://openai.com/index/gpt-4/">GPT-4</a> might suffice. But if you're creating an app that generates images from text descriptions, you'd need a text-to-image model like <a target="_blank" href="https://openai.com/index/dall-e-3/">DALL-E</a>.</p>
<p>If your application requires handling text, images, and audio simultaneously, consider a multimodal model like <a target="_blank" href="https://openai.com/index/hello-gpt-4o/">GPT-4o</a>. While the examples mentioned are from OpenAI, don't limit yourself to one provider. Explore offerings from other companies like <a target="_blank" href="https://www.anthropic.com/">Anthropic's</a> or <a target="_blank" href="https://cohere.com/">Cohere's</a> offerings. <strong>Remember, choosing the right modality is crucial as it significantly impacts both pricing and performance.</strong></p>
<p><strong>Model Size:</strong> Larger models generally perform better but need more computing power. Think of it like engine size in cars - a bigger engine (more parameters) usually means more power, but also higher fuel consumption. For instance, a 1 billion parameter model might work for simple tasks, while complex reasoning might require models with 100+ billion parameters.</p>
<p>However, it's crucial to match the model size to your specific use case. For example, if you're building a spam filter for emails, you don't need a massive model like <a target="_blank" href="https://openai.com/index/gpt-4/">GPT-4</a> (with its 1.76 trillion parameters). A smaller model like <a target="_blank" href="https://mistral.ai/news/announcing-mistral-7b/">Mistral 7B</a>, with 7 billion parameters, could be more than sufficient for such a task.</p>
<p>While larger models often excel at complex tasks, they may be overkill for simpler applications. <strong>Smaller models are generally much cheaper to run</strong>. They require less computing power and memory, which translates to lower operational costs. <strong>Smaller models typically provide faster inference times</strong>, which can be crucial for real-time applications like chatbots or content moderation systems.</p>
<p><strong>Task-Specific Models</strong>: For specialized tasks, look for models trained specifically for that purpose. They can often outperform larger, general-purpose models at a lower cost. For example <a target="_blank" href="https://huggingface.co/llmware/slim-summary-tiny-tool">this model</a> from llmware, providing a small, fast inference for high-quality summarizations of complex business documents.</p>
<p><strong>Accuracy vs. Speed</strong>: Continuing from the previous point, larger models often provide higher accuracy but at the cost of slower processing times. The best choice depends on your specific application's requirements.</p>
<p>For a real-time translation app, you might prioritize speed over perfect accuracy. Users typically need quick translations during conversations or while reading, and small inaccuracies are usually tolerable. In this case, a smaller, faster model could be more suitable.</p>
<p>Conversely, for a medical diagnosis assistant, accuracy is paramount, even if it takes a bit longer to process. In this scenario, using a larger, more comprehensive model would be justified, as the stakes are much higher and even small errors could have serious consequences.</p>
<p><strong>Deployment Options</strong>: Your choice depends on factors like your technical capabilities, budget, data privacy requirements, and specific model needs. For example, a small startup might start with a cloud service for quick deployment, while a large healthcare company might opt for on-premises deployment to ensure data privacy.</p>
<p>Services like <a target="_blank" href="https://azure.microsoft.com/en-us/products/ai-studio">Azure AI Studio</a>, <a target="_blank" href="https://aws.amazon.com/bedrock/">AWS Bedrock</a>, or <a target="_blank" href="https://cloud.google.com/vertex-ai">Google Vertex AI</a> offer ready-to-use infrastructure. These are convenient if you're already using these cloud providers.</p>
<p>If you prefer full control or have strict data privacy requirements, you might deploy on your own hardware. This involves setting up and maintaining your infrastructure, including purchasing GPUs to run models efficiently. You could use open-source models like <a target="_blank" href="https://llama.meta.com/">Meta's LLaMA</a> in this scenario. This option requires more technical expertise but offers maximum control.</p>
<p>Services like <a target="_blank" href="https://novita.ai/">Novita AI</a> provide GPU resources for training, fine-tuning, and deploying models. Companies like <a target="_blank" href="https://www.together.ai/">Together AI</a>, <a target="_blank" href="https://www.anyscale.com/">Anyscale AI</a>, <a target="_blank" href="https://portkey.ai/">Portkey</a>, <a target="_blank" href="https://abacus.ai/">Abacus AI</a>, <a target="_blank" href="https://groq.com/">Groq</a> and <a target="_blank" href="https://www.edenai.co/">Eden AI</a> offer platforms to use various open-source models. These can be good options if you are starting out.</p>
<h3 id="heading-evaluating-large-language-models">Evaluating Large Language Models</h3>
<p>Evaluating LLMs can be complex, with many detailed resources available online. However, for JavaScript developers new to LLMs, the process doesn't have to be overwhelming. Here's a simplified approach:</p>
<ol>
<li><p>Focus on your project's specific needs. For example, if you're building a chatbot, test different models with sample conversations.</p>
</li>
<li><p>Ask yourself these key questions:</p>
<ul>
<li><p>Does the model understand the context?</p>
</li>
<li><p>Are its responses helpful and relevant?</p>
</li>
<li><p>Is it fast enough for your application?</p>
</li>
</ul>
</li>
<li><p>Leverage existing APIs from providers like OpenAI or Hugging Face. These often come with JavaScript SDKs, making it easier to experiment without dealing with underlying complexities.</p>
</li>
<li><p>Use comparison tools to evaluate different models. For instance, <a target="_blank" href="https://www.youtube.com/watch?v=Vf6ZQFzOKgY">Airtrain AI's</a> LLM playground is a free tool that allows you to compare model outputs side by side. You can also checkout <a target="_blank" href="https://artificialanalysis.ai/">Artificial Analysis</a> for more detailed comparisons. Remember, the best model for your project is the one that works well for your specific use case.</p>
</li>
</ol>
<p>For those interested in more in-depth evaluation, resources like the <a target="_blank" href="https://huggingface.co/spaces/open-llm-leaderboard/open_llm_leaderboard">Hugging Face Open LLM Leaderboard</a> or articles from <a target="_blank" href="https://www.confident-ai.com/blog/llm-evaluation-metrics-everything-you-need-for-llm-evaluation">Confident AI</a> and <a target="_blank" href="https://www.singlestore.com/blog/complete-guide-to-evaluating-large-language-models/">SingleStore</a> provide comprehensive guides on LLM evaluation metrics and methods. However, for beginners, starting with practical testing and gradually expanding your evaluation criteria as you gain experience is often the most effective approach.</p>
<h3 id="heading-practical-tips-for-implementation">Practical Tips for Implementation</h3>
<p>Starting simple and gradually increasing complexity as you learn is often the best approach for beginners. This strategy allows you to gain practical experience while managing costs and complexity effectively:</p>
<ol>
<li><p><strong>Find Working Examples</strong>: Search GitHub and online tutorials for existing implementations. This can give you a head start and show you best practices.</p>
</li>
<li><p><strong>Use Labeled Data</strong>: Create small, relevant datasets (30-100 samples) to test model performance for your specific use case. This helps you evaluate real-world effectiveness.</p>
</li>
<li><p><strong>Start Small</strong>: Begin with smaller models and scale up as needed. This approach is similar to optimizing JavaScript applications and can significantly reduce costs.</p>
</li>
<li><p><strong>Plan for Updates</strong>: Design your system to easily switch between different models. For example, if you start with GPT-4 but later want to try Claude from Anthropic, make this transition smooth. Platforms like <a target="_blank" href="https://portkey.ai/features/ai-gateway">Portkey</a> offer unified SDKs that allow you to use multiple AI providers with the same codebase, making it easier to experiment and optimize.</p>
</li>
</ol>
<h3 id="heading-understanding-context-length-in-llms">Understanding Context Length in LLMs</h3>
<p>LLMs are stateless, meaning they don’t retain memory of previous conversations. Each interaction is independent, making the concept of a context window crucial.</p>
<p>A context window is the maximum amount of text (measured in tokens or words) that an LLM can process in a single interaction. The size of the context window determines how much information the model can consider when generating responses.</p>
<p><strong>Comparing Popular LLMs:</strong></p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>Language Model</strong></td><td><strong>Context Length</strong></td></tr>
</thead>
<tbody>
<tr>
<td>GPT-3.5</td><td>4096 tokens</td></tr>
<tr>
<td>GPT-4</td><td>8192 tokens</td></tr>
<tr>
<td>Claude</td><td>100,000 tokens</td></tr>
<tr>
<td>Mistral</td><td>2048 tokens</td></tr>
<tr>
<td>Llama</td><td>2048 tokens</td></tr>
</tbody>
</table>
</div><ul>
<li><p><strong>Long Conversations</strong>: If the conversation exceeds the context window, older parts may be cut off. Chat clients solve this by selectively including relevant history in each prompt.</p>
</li>
<li><p><strong>Large Text Summarization</strong>: Texts longer than the context window are "chunked"—summarized in parts and then combined.</p>
</li>
</ul>
<h3 id="heading-pricing">Pricing</h3>
<p>Let's address the crucial aspect of pricing. As mentioned in my <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-decoding-llms-from-tokens-to-embeddings#heading-understanding-tokens-in-llms">previous post</a>, LLM usage is priced based on tokens. <strong>Pricing often (not always) differs for input tokens (your prompts) and output tokens (the model's responses). You're charged for both input and output tokens.</strong></p>
<p>For example, comparing <a target="_blank" href="https://openai.com/index/hello-gpt-4o/">GPT-4o</a> (from OpenAI) with <a target="_blank" href="https://www.together.ai/products#inference">Mistral 7B</a> (offered by Together AI):</p>
<ul>
<li><p>GPT-4o: Input: $5.00 per 1M tokens &amp; Output: $15.00 per 1M tokens</p>
</li>
<li><p>Mistral 7B: $0.20 per 1M tokens (both input and output)</p>
</li>
<li><p><strong>Mistral 7B is 25 times cheaper for input tokens, 75 times cheaper for output tokens. On average, 50 times cheaper when considering both input and output tokens equally.</strong></p>
</li>
<li><p>This significant price difference highlights why choosing the right model for your use case is crucial.</p>
</li>
</ul>
<p><strong>Key Pricing Considerations</strong>:</p>
<ol>
<li><p><strong>Model Size vs. Cost</strong>: Larger models generally cost more. Ensure you're not using an overpowered (and overpriced) model for simple tasks. For instance, using GPT-4o for basic text classification would be unnecessarily expensive. Begin with smaller, more cost-effective models that can handle your task adequately. If you need GPT-4o's capabilities, consider starting with its more economical smaller version <a target="_blank" href="https://openai.com/index/gpt-4o-mini-advancing-cost-efficient-intelligence/">GPT-4o</a> mini (launched by OpenAI recently).</p>
</li>
<li><p><strong>Compare Providers</strong>: Even for the same open-source model (like Mistral 7B or LLaMA), <a target="_blank" href="https://anakin.ai/blog/mistral-api/">prices vary</a> across platforms. Compare offerings from providers like <a target="_blank" href="https://www.together.ai/pricing">Together AI</a>, <a target="_blank" href="https://anakin.ai/">Anakin</a>, etc. Consider both pricing and performance (latency, uptime).</p>
</li>
<li><p><strong>Cloud Provider Offerings</strong>: If using Azure AI Studio, AWS Bedrock, or Google Vertex AI, compare their LLM offerings. These platforms often provide a range of models at different price points.</p>
</li>
<li><p><strong>Optimizing Token Usage</strong>: Be mindful of how you structure prompts. Efficient prompts can reduce token count, lowering costs.</p>
</li>
<li><p><strong>Volume Discounts</strong>: For high-volume usage, many providers may offer discounted rates. Factor this in for long-term projects.</p>
</li>
<li><p><strong>Pricing Calculators</strong>: Use pricing calculators like <a target="_blank" href="https://yourgpt.ai/tools/openai-and-other-llm-api-pricing-calculator">YourGPT</a> or <a target="_blank" href="https://llm-price.com/">LLMPricing</a> to estimate costs across different models and providers.</p>
</li>
</ol>
<p>Remember, the cheapest option isn't always the best. Balance cost with performance, reliability, and your specific needs. Start with smaller, cost-effective models and scale up as necessary, continuously monitoring your usage and costs.</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>We've covered a lot of ground in this post, from understanding different types of LLMs to evaluating their performance and considering crucial factors like pricing. Choosing the right LLM for your project involves balancing capabilities, costs, and practical implementation details.</p>
<p><strong>Remember, the best model isn't always the largest or most expensive, but the one that best fits your specific use case and budget. <mark>Start small, experiment, and scale as needed.</mark></strong></p>
<p>In our next post, we'll get our hands dirty with some actual code, exploring how to use the OpenAI JavaScript SDK to bring the power of LLMs into your projects. Get ready to turn all this knowledge into action!</p>
]]></content:encoded></item><item><title><![CDATA[GEN AI for JavaScript Devs: Decoding LLMS, from Tokens to Embeddings]]></title><description><![CDATA[Learn how Large Language Models work, from tokenization to embeddings, made simple for JavaScript developers. Understand LLM intricacies easily]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-decoding-llms-from-tokens-to-embeddings</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-decoding-llms-from-tokens-to-embeddings</guid><category><![CDATA[gen ai]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Mon, 22 Jul 2024 05:18:23 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721395748660/7048ffa2-a5d8-4ecf-a151-fa4c4f48ab45.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>In the <a target="_blank" href="https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-foundation-models-and-llms">first tutorial</a> of our series, we explored foundation models and Large Language Models (LLMs). We took a glimpse at their basics, evolution, and use cases. In this part, we'll dive deeper into how they work. We'll explore how a computer program can be intelligent enough to produce emails, translate text, summarize data, and understand our language - all without the typical machine learning complexities.</p>
<p>LLMs are not human; they simply predict and generate text based on patterns. As a fellow JavaScript developer, I'll explain how this "magic" is possible in terms we can easily understand. We'll uncover how these seemingly intelligent programs process and generate human-like text.</p>
<h3 id="heading-how-do-llms-work">How do LLMs Work?</h3>
<p>Large Language Models (LLMs) are advanced AI systems designed to understand and generate human-like text. They learn from vast amounts of text data using a method called self-supervised learning. Here’s a simple breakdown of how they work:</p>
<h4 id="heading-key-steps-in-llm-functioning">Key Steps in LLM Functioning:</h4>
<ol>
<li><p><strong>Input Processing</strong>:</p>
<ul>
<li>When you type something, the LLM first breaks down your text into smaller pieces called tokens. For example, the sentence "Hello world!" might be split into tokens like ["Hello", "world", "!"].</li>
</ul>
</li>
<li><p><strong>Vector Conversion</strong>:</p>
<ul>
<li>These tokens are then converted into vectors. Think of vectors as lists of numbers that represent the tokens in a way the model can understand. For instance, the token "Hello" might be represented as a vector like [0.1, 0.2, 0.3, 0.4].</li>
</ul>
</li>
<li><p><strong>Model Processing</strong>:</p>
<ul>
<li>The LLM processes these vectors using its neural network, which is often based on a transformer architecture. This step is where the model uses its knowledge to understand the context and relationships between the tokens.</li>
</ul>
</li>
<li><p><strong>Output Generation</strong>:</p>
<ul>
<li>The model generates a response in the form of new vectors. These output vectors are the model's predictions of what the next tokens should be.</li>
</ul>
</li>
<li><p><strong>Text Conversion</strong>:</p>
<ul>
<li>Finally, the output vectors are converted back into tokens, and these tokens are combined to form human-readable text. So, the vectors might be translated back into words or parts of words to create a sentence.</li>
</ul>
</li>
</ol>
<p>Throughout this process, LLMs use their training on massive datasets to predict the most likely next word or sequence of words. This allows them to generate responses that are coherent and make sense in the given context.</p>
<h3 id="heading-understanding-tokens-in-llms">Understanding Tokens in LLMs</h3>
<p>Tokens are the fundamental units that Large Language Models (LLMs) use to process language. Tokenization is the process of breaking down text into these smaller, manageable units. Tokens can be words, subwords, or even characters, serving as the basic elements for processing language in LLMs.</p>
<p>When a user inputs a prompt, the LLM's tokenizer converts the text into a series of tokens. These tokens are typically represented as numbers, with each token corresponding to a unique identifier in the model's vocabulary. This numerical representation allows the LLM to process and manipulate text efficiently. Every LLM has a different tokenizer. For example, you can experiment with the tokenizers used by GPT-3.5 and GPT-4 <a target="_blank" href="https://platform.openai.com/tokenizer">here</a>.</p>
<p><strong>Understanding tokens is important, especially if you are integrating LLMs like ChatGPT into your application. This is because you are charged based on both the input and output tokens – the text you input and the text generated by the model. We will dive deeper into billing in the next post, but this is how tokens play a crucial role in it.</strong></p>
<h3 id="heading-vectors-and-embeddings-in-large-language-models-llms">Vectors and Embeddings in Large Language Models (LLMs)</h3>
<p>Vectors are lists of numbers used to represent words or tokens in LLMs. Think of them as numerical versions of words. For example, "cat" might be represented as [0.2, 0.4, 0.6]. Embeddings are a <strong><mark>specific type of vector</mark></strong> used in LLMs. They are dense, continuous representations of words or tokens that <strong><mark>capture meaning</mark></strong>.</p>
<p>Key Features:</p>
<ol>
<li><p><strong>High-Dimensional Space</strong>: Vectors and embeddings exist in a space with many dimensions, allowing LLMs to capture complex relationships between words.</p>
</li>
<li><p><strong>Meaning Capture</strong>: Words with similar meanings have similar vectors. For example, "king" and "queen" might have close vector representations.</p>
</li>
<li><p><strong>Mathematical Operations</strong>: Machine learning models can now perform operations on these vectors to understand language. For example: "king" - "man" + "woman" ≈ "queen"</p>
</li>
</ol>
<h3 id="heading-similarity-searches-in-llms">Similarity Searches in LLMs</h3>
<p>Imagine you're trying to find a book in a massive library where every book is represented by a unique code. That's similar to how LLMs use embeddings to find relevant information. <strong>The actual process is very complex, involving many calculations and adjustments, but here is the basic idea</strong>:</p>
<ol>
<li><p><strong>Convert Text to Vector</strong>: The LLM turns your search phrase into a special code (embedding). Example: You search for "healthy breakfast ideas" → [0.2, 0.5, 0.8]</p>
</li>
<li><p><strong>Compare Embeddings</strong>: It compares your search codes. Example: It might find these codes:</p>
<ul>
<li><p>"Nutritious morning meals" → [0.3, 0.4, 0.7]</p>
</li>
<li><p>"Fast food options" → [0.1, 0.2, 0.3]</p>
</li>
</ul>
</li>
<li><p><strong>Measure Closeness</strong>: The LLM calculates how similar these codes are to your search. Example: "Nutritious morning meals" is closer to "healthy breakfast ideas" than "Fast food options".</p>
</li>
<li><p><strong>Retrieve Information</strong>: It presents the most closely related information.</p>
</li>
</ol>
<p>This process helps LLMs quickly find relevant information from vast amounts of data. This is the main reason why LLMs use vectors—machines understand numbers and don’t have consciousness like humans. By using vectors, LLMs can efficiently match and retrieve information. This is how ChatGPT answers your questions so effectively. Pretty neat, right?</p>
<h3 id="heading-conclusion">Conclusion</h3>
<p>In conclusion, understanding the intricate workings of LLMs, from tokenization to embeddings, provides valuable insights into how these powerful AI systems process and generate human-like text. In the next tutorial, we will cover how to choose the right LLM for your use case. We’ll explore the different LLMs available in the market, their use cases, pricing, and more. See you in the next one!</p>
]]></content:encoded></item><item><title><![CDATA[GEN AI for JavaScript Devs: Introduction to Foundation Models and LLMs.]]></title><description><![CDATA[Learn to use Generative AI and Large Language Models for JavaScript: foundation concepts, implementation techniques, and practical applications]]></description><link>https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-foundation-models-and-llms</link><guid isPermaLink="true">https://yaldram.hashnode.dev/gen-ai-for-javascript-devs-introduction-to-foundation-models-and-llms</guid><category><![CDATA[gen ai]]></category><category><![CDATA[llm]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Beginner Developers]]></category><dc:creator><![CDATA[Arsalan Yaldram]]></dc:creator><pubDate>Fri, 19 Jul 2024 05:00:46 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1721315001584/a169af45-29d8-4796-b601-b657c96d2927.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-introduction">Introduction</h3>
<p>Hey there, fellow JS developers!</p>
<p>Artificial Intelligence, particularly Generative AI (Gen AI), is revolutionizing our industry. We're already using tools like ChatGPT for code generation and image creation, but AI's potential goes far beyond these applications.</p>
<p>As JavaScript developers, it's crucial to understand how we can harness the power of Gen AI in our own applications. How can we integrate ChatGPT-like functionality into our projects? How can we leverage AI to enhance user experiences and solve complex problems?</p>
<p>In this series, we'll dive deep into the world of Gen AI from a JS developer's perspective. We'll cover the basics, explore how it works, and learn to implement Gen AI features in our applications. Whether you're an AI novice or looking to expand your skills, this series aims to equip you with practical knowledge and insights. Let's kick things off by introducing Gen AI and its fundamental concepts.</p>
<h3 id="heading-what-is-a-foundation-model">What is a Foundation Model?</h3>
<p>Foundation Models represent a paradigm shift in machine learning. Unlike traditional models designed for specific tasks, these large-scale neural networks are trained on vast amounts of data, enabling them to perform a wide array of functions. The power of Foundation Models lies in their ability to process and "understand" enormous volumes of information in a fraction of the time it would take a human.</p>
<p>To illustrate the efficiency of Foundation Models, consider this: reading everything on the internet would take a human approximately 255,000 years, while a Foundation Model can accomplish this feat in just a few months. This incredible efficiency is what makes Foundation Models so exciting and powerful.</p>
<p>Foundation Models learn natural patterns from data, enabling them to perform tasks like classification, question-answering, and summarization without specific training for each task, making them highly efficient for various applications. Unlike traditional models designed for a single task, Foundation Models can handle multiple tasks simultaneously by learning general data representations. For instance, while a traditional model might only do sentiment analysis, a Foundation Model can perform sentiment analysis, language translation, and text generation all at once. This multi-task capability comes from their training on huge amount of diverse datasets, allowing them to capture complex relationships and transfer knowledge across different domains.</p>
<h3 id="heading-what-are-large-language-models-and-their-evolution">What are Large Language Models and their Evolution?</h3>
<p>Large Language Models (LLMs) are a specific type of Foundation Model designed to understand and generate human-like text. The most famous example is ChatGPT, an impressive chatbot that can engage in human-like conversations on various topics.</p>
<p>The evolution of LLMs can be traced back to 2017 with the introduction of the Transformer architecture. This was followed by the development of BERT (Bidirectional Encoder Representations from Transformers) and GPT-1 (Generative Pre-trained Transformer) in 2018, which set new benchmarks in natural language processing tasks. Since then, we've seen an explosion in the scale and capabilities of language models.</p>
<p>LLMs are called "large" because they contain an enormous number of parameters - typically tens to hundreds of billions. These parameters are the numbers that define how the model processes input and generates output. Parameters in LLMs are essentially the learned values that the model uses to make predictions. They represent the knowledge the model has acquired during training. These parameters are adjusted during the training process to minimize the difference between the model's predictions and the actual correct outputs.</p>
<p>Some well-known LLMs and their parameter counts include:</p>
<ol>
<li><p><strong>GPT-3</strong> (Generative Pre-trained Transformer 3) by OpenAI: 175 billion parameters</p>
</li>
<li><p><strong>PaLM</strong> (Pathways Language Model) by Google: 540 billion parameters</p>
</li>
<li><p><strong>LLaMA</strong> (Large Language Model Meta AI) by Meta: ranges from 7 billion to 70 billion parameters</p>
</li>
</ol>
<p>A Large Language Model (LLM) with more parameters can understand and generate more nuanced and accurate responses, as it has a greater capacity to learn from diverse and complex data patterns.With more parameters, an LLM can capture a wider range of linguistic subtleties, enabling it to perform a variety of tasks with higher precision and adaptability.</p>
<h3 id="heading-how-do-large-language-models-work">How do Large Language Models Work?</h3>
<p>Large Language Models (LLMs) use self-supervised learning, which differs from traditional supervised learning methods by relying on vast amounts of unlabeled text data instead of carefully labeled datasets. This eliminates the need for manual labeling, allowing training on much larger datasets. A labeled dataset pairs each piece of data with the correct answer or category, like an image labeled "cat" or "dog" for image recognition. Creating such datasets is time-consuming making LLMs' ability to learn from unlabeled data extremely valuable.</p>
<p><strong>The core task of most LLMs is predicting the next word in a sequence</strong>. By doing this repeatedly on enormous text collections, the models learn complex language patterns and relationships, considering the entire context to understand nuances and generate coherent text.</p>
<p>LLMs use a neural network architecture called a transformer, designed to handle sequences of data like sentences or code. Transformers understand each word's context by considering its relationship to every other word in the sentence, allowing the model to grasp the overall structure and meaning.</p>
<p>During training, the model starts with random predictions for the next word in a sentence. With each iteration, it adjusts its internal parameters to improve its predictions. Over time, the model becomes skilled at generating coherent sentences and understanding language in various contexts.</p>
<h3 id="heading-customizing-llms">Customizing LLMS</h3>
<ol>
<li><p><strong>Fine-tuning</strong>: Updating the model's parameters using domain-specific data to improve performance on particular tasks. Imagine you have a basic recipe book with general recipes for various dishes. Fine-tuning is like adding specific instructions and tweaks to make the recipes better suited for a particular cuisine, like Italian. So, you take the general pasta recipe and refine it using authentic Italian ingredients and techniques to make it perfect for Italian cooking.</p>
</li>
<li><p><strong>Pre-training</strong>: Creating new Foundation Models tailored to specific domains or modalities using substantial computational resources and unique datasets. Think of pre-training as building a brand-new, specialized encyclopedia from scratch. You gather a huge amount of information and spend a lot of time and effort organizing it specifically for a topic like space exploration. This new encyclopedia is now tailored to provide detailed and specific information about space sciences.</p>
</li>
<li><p><strong>Reinforcement Learning with Human Feedback</strong>: Refining model outputs using human preferences, addressing challenges in subjective interpretation. Consider teaching a child to draw. The child makes a drawing, and you give feedback, like saying, "I like how you drew the sun, but can you make it bigger and add some more rays?" The child takes your advice and adjusts their drawing. Over time, with more feedback, the child learns to draw better.</p>
</li>
</ol>
<h3 id="heading-working-with-llms">Working with LLMS</h3>
<ol>
<li><p><strong>Prompt Engineering</strong>: Crafting effective prompts to elicit desired responses from the model. This is often the first step in using a model for a specific task. Imagine you're at a restaurant and want a specific dish. Instead of just saying, "I want something to eat," you give a clear prompt: "Can I have a spaghetti carbonara with extra cheese and a side of garlic bread?" This specific request helps the waiter bring exactly what you want, similar to how a well-crafted prompt helps an AI model generate the desired response.</p>
</li>
<li><p><strong>Retrieval Augmented Generation (RAG)</strong>: Enhancing model responses by incorporating relevant information retrieved from a corpus of documents. Suppose you're writing an article about the history of the internet. Instead of relying solely on your memory, you look up and include key facts from reliable sources, like books or online articles, to make your article more accurate and informative. Similarly, RAG improves model responses by incorporating relevant information retrieved from the internet or your documents.</p>
</li>
</ol>
<p>We will explore all these methods in detail in the upcoming tutorials.</p>
<h3 id="heading-applications-of-large-language-models">Applications of Large Language Models</h3>
<p>LLMs have a wide range of applications in various fields:</p>
<ul>
<li><p>Chatbots, virtual assistants and customer service</p>
</li>
<li><p>Content generation</p>
</li>
<li><p>Language translation</p>
</li>
<li><p>Summarisation</p>
</li>
<li><p>Software development (code generation and review)</p>
</li>
</ul>
<h3 id="heading-challenges-and-considerations">Challenges and Considerations</h3>
<p>While LLMs offer immense potential, they also come with challenges:</p>
<ul>
<li><p>The need for substantial computational resources, especially for larger models.</p>
</li>
<li><p>The importance of choosing the right model and customisation technique for specific use cases.</p>
</li>
<li><p>The potential for unexpected outputs, particularly when processing long or complex inputs.</p>
</li>
</ul>
<h3 id="heading-small-language-models">Small Language Models</h3>
<p>Small Language Models (SLMs) are a streamlined alternative to large language models like GPT-3. <strong>With fewer parameters—often under 100 million</strong>—SLMs are faster, more cost-effective, and energy-efficient, making them ideal for use in edge devices, mobile phones, and specialized tasks.</p>
<p><strong>Key Advantages of SLMs</strong>:</p>
<ul>
<li><p><strong>Speed &amp; Efficiency</strong>: Faster inference and real-time processing.</p>
</li>
<li><p><strong>Cost-Effective</strong>: Easier and cheaper to train and deploy.</p>
</li>
<li><p><strong>Energy-Efficient</strong>: Suitable for devices with limited power, like mobile phones or IoT devices.</p>
</li>
</ul>
<p><strong>Examples of Popular SLMs</strong>:</p>
<ul>
<li><p><strong>DistilBERT (OpenAI)</strong>: 82 million parameters, great for tasks like text classification and sentiment analysis.</p>
</li>
<li><p><strong>ALBERT (Google)</strong>: 12 million parameters, optimized for efficiency with fewer resources.</p>
</li>
<li><p><strong>ELECTRA Small (Google)</strong>: 14.5 million parameters, designed for tasks requiring real-time processing.</p>
</li>
</ul>
<h3 id="heading-conclusion">Conclusion</h3>
<p>We've covered the essentials of GEN AI, from Foundation Models to Large Language Models. This overview sets the stage for our journey into AI from a JavaScript developer's perspective. In our next post, we'll delve deeper into the workings of these models. We'll explore key concepts like tokens and embeddings, focusing on what's relevant for JS developers rather than diving into Machine Learning complexities.</p>
<p>See you in the next one!</p>
]]></content:encoded></item></channel></rss>