<?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" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ react js - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ react js - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 19 Aug 2026 10:05:28 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/react-js/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ High-Frequency Real-Time Data in React: From Ring Buffers to OffscreenCanvas ]]>
                </title>
                <description>
                    <![CDATA[ React is great at many things. But if you've ever tried pushing thousands of data points per second through it, you'll quickly learn that React isn't a firehose. It's more like a garden hose. Try forc ]]>
                </description>
                <link>https://www.freecodecamp.org/news/high-frequency-real-time-data-in-react-from-ring-buffers-to-offscreencanvas/</link>
                <guid isPermaLink="false">6a84d268fa401f6597cd200e</guid>
                
                    <category>
                        <![CDATA[ react js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ performance ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ canvas ]]>
                    </category>
                
                    <category>
                        <![CDATA[ realtime ]]>
                    </category>
                
                    <category>
                        <![CDATA[ workers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ concurrency ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vineeth Pawar ]]>
                </dc:creator>
                <pubDate>Tue, 18 Aug 2026 21:45:12 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/uploads/covers/5e1e335a7a1d3fcc59028c64/c3ffaae8-51d5-4add-9a9e-e49443e49746.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>React is great at many things. But if you've ever tried pushing thousands of data points per second through it, you'll quickly learn that React isn't a firehose. It's more like a garden hose.</p>
<p>Try forcing too much through it, and either the lawn floods (your DOM) or the pipe bursts (your app).</p>
<p>There's a second observation that pairs with the first. Your laptop has 8 to 16 CPU cores. Your React app uses 1 of them, almost always. The main thread handles JavaScript, the DOM, layout, and paint setup. The other cores sit idle while the main thread struggles to keep a 60fps frame budget.</p>
<p>Both problems have the same shape: you need to keep React out of the hot path, and you need to use more than one thread. The patterns that get you there also happen to be the patterns behind Figma's canvas engine, Bloomberg's trading dashboards, and every biosignal viewer you've seen.</p>
<p>In one project, I had to visualise 19 EEG (brainwave) channels, each sending about 1,000 data points per second. That's almost 19,000 updates per second. If you feed all of that directly into React, the UI doesn't just slow down. It faints dramatically.</p>
<p>This article is the end-to-end architecture I landed on: the ring buffers, workers, shared memory, off-main rendering, and specific patterns that hold up under sustained multi-hour load.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a href="#heading-whos-already-doing-this">Who's Already Doing This?</a></p>
</li>
<li><p><a href="#heading-the-1khz-math">The 1kHz Math</a></p>
</li>
<li><p><a href="#heading-where-it-usually-goes-wrong">Where it Usually Goes Wrong</a></p>
</li>
<li><p><a href="#heading-the-mental-model-air-traffic-control-plus-a-kitchen-brigade">The Mental Model: Air Traffic Control Plus a Kitchen Brigade</a></p>
</li>
<li><p><a href="#heading-step-1-stop-putting-samples-in-react-state">Step 1: Stop Putting Samples in React State</a></p>
</li>
<li><p><a href="#heading-step-2-separate-shape-from-values">Step 2: Separate Shape from Values</a></p>
</li>
<li><p><a href="#heading-step-3-move-heavy-work-off-the-main-thread">Step 3: Move Heavy Work Off the Main Thread</a></p>
</li>
<li><p><a href="#heading-step-4-render-off-main-with-offscreencanvas">Step 4: Render Off Main with OffscreenCanvas</a></p>
</li>
<li><p><a href="#heading-step-5-decimate-before-you-draw">Step 5: Decimate Before You Draw</a></p>
</li>
<li><p><a href="#heading-step-6-wrap-an-external-renderer">Step 6: Wrap an External Renderer</a></p>
</li>
<li><p><a href="#heading-step-7-when-canvas-isnt-enough-reach-for-webgl">Step 7: When Canvas isn't Enough, Reach for WebGL</a></p>
</li>
<li><p><a href="#heading-step-8-keep-memory-flat">Step 8: Keep Memory Flat</a></p>
</li>
<li><p><a href="#heading-step-9-scheduling-strategies">Step 9: Scheduling Strategies</a></p>
</li>
<li><p><a href="#heading-step-10-measure-sustained-performance">Step 10: Measure Sustained Performance</a></p>
</li>
<li><p><a href="#heading-case-study-19-eeg-channels">Case Study: 19 EEG Channels</a></p>
</li>
<li><p><a href="#heading-benchmarks-single-thread-vs-multi-thread">Benchmarks: Single Thread vs Multi-Thread</a></p>
</li>
<li><p><a href="#heading-the-coopcoep-catch">The COOP/COEP Catch</a></p>
</li>
<li><p><a href="#heading-production-tradeoffs">Production Tradeoffs</a></p>
</li>
<li><p><a href="#heading-should-you-build-like-this">Should You Build Like This?</a></p>
</li>
<li><p><a href="#heading-wrapping-up">Wrapping Up</a></p>
</li>
<li><p><a href="#heading-references">References</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<p>To get the most out of this article, you'll want:</p>
<ul>
<li><p><strong>Working knowledge of React 18 or 19.</strong> You should be comfortable with <code>useState</code>, <code>useEffect</code>, <code>useRef</code>, and the difference between mounting and re-rendering.</p>
</li>
<li><p><strong>TypeScript basics.</strong> Most examples are in TypeScript. You should be able to read type annotations without stopping.</p>
</li>
<li><p><strong>A rough sense of the browser main thread and event loop.</strong> You don't need to have written a Web Worker, but knowing what "blocking the main thread" means will make Step 3 easier.</p>
</li>
<li><p><strong>Familiarity with Canvas 2D or a chart library</strong> is a plus, not a requirement. If you've drawn anything on a canvas, you're ready.</p>
</li>
<li><p><strong>A laptop that can run modern Chrome or Edge.</strong> The examples rely on <code>SharedArrayBuffer</code>, <code>OffscreenCanvas</code>, and Atomics, which need a Chromium-based browser and cross-origin isolation (covered later in the article).</p>
</li>
</ul>
<p>You don't need prior experience with Web Workers, ring buffers, or WebGL. This article introduces each in the context of a real problem.</p>
<h2 id="heading-whos-already-doing-this">Who's Already Doing This?</h2>
<p>The patterns in this article aren't experimental. They're the architecture behind production apps that ingest and render high-frequency data:</p>
<ul>
<li><p><strong>Trading and finance dashboards</strong> (Bloomberg, Hyperliquid, dYdX, every serious market viewer) push thousands of price ticks per second through canvas-rendered grids.</p>
</li>
<li><p><strong>Figma</strong> runs its entire canvas engine in WebAssembly inside a worker. The main thread renders React for the chrome only.</p>
</li>
<li><p><strong>Google Docs and Microsoft Loop</strong> run their document models in workers, with the DOM as the projection.</p>
</li>
<li><p><strong>Charting libraries</strong> like LightningChart, uPlot, Plotly, and ECharts draw on Canvas or WebGL and treat React as a wrapper.</p>
</li>
<li><p><strong>Biosignal, ECG, EEG, and motion-capture apps</strong> routinely process samples at 1kHz or higher and stream them to live plots.</p>
</li>
<li><p><strong>Observability and APM tools</strong> (Datadog live tail, Grafana real-time panels) decouple ingestion from render to keep tabs responsive.</p>
</li>
<li><p><strong>Audio editors and visualisers</strong>, plus anything using the Web Audio API with a waveform display.</p>
</li>
<li><p><strong>transformers.js and ONNX Runtime Web</strong> place ML inference in workers by default.</p>
</li>
</ul>
<p>Different domains, same trick: React owns what changes rarely, something else owns what changes at refresh rate, and heavy work happens on threads that aren't the main one.</p>
<h2 id="heading-the-1khz-math">The 1kHz Math</h2>
<p>Some numbers to make the problem concrete.</p>
<ul>
<li><p>A sample arrives every 1ms.</p>
</li>
<li><p>A 60Hz display refreshes every 16.67ms.</p>
</li>
<li><p>So in one frame, you'll receive roughly <strong>16 to 17 samples per stream</strong>.</p>
</li>
<li><p>With 19 active streams (the EEG case), that's <strong>300 to 320 samples per frame</strong>.</p>
</li>
</ul>
<p>If you <code>setState</code> on each sample, React tries to do around 19,000 renders per second. It can't, so it skips frames. The UI stutters and your laptop fans take off.</p>
<p>If you <code>setState</code> once per frame with the batch of ~320 samples, React does 60 renders per second, which is easy.</p>
<p>That single reframe is the entire trick, and it will echo through every step below.</p>
<h2 id="heading-where-it-usually-goes-wrong">Where it Usually Goes Wrong</h2>
<p>Here's the version of the code I see in most real-time React apps the first time they try this. It looks reasonable. It's also the source of every bit of jank the team will spend the next two weeks tracking down.</p>
<pre><code class="language-tsx">import { useEffect, useState } from "react";

export default function NaiveChart({ socket }) {
  const [data, setData] = useState&lt;number[]&gt;([]);

  useEffect(() =&gt; {
    socket.on("newPoint", (point: number) =&gt; {
      setData((prev) =&gt; [...prev, point]); // re-renders every time
    });
  }, [socket]);

  return &lt;div&gt;{data.length} points&lt;/div&gt;;
}
</code></pre>
<p>Three problems baked into seven lines:</p>
<ol>
<li><p><strong>Every incoming sample triggers a re-render:</strong> At 1kHz that's 1,000 renders per second. React was never going to be happy about that.</p>
</li>
<li><p><code>[...prev, point]</code> <strong>allocates a new array on every push:</strong> At 1kHz that's a new array per millisecond, all of which the garbage collector has to clean up. The heap climbs, GC pauses lengthen, the fan kicks in.</p>
</li>
<li><p><strong>There's no upper bound on the array:</strong> Run this for an hour and you have 3.6 million numbers in memory, all of which React has to consider on every render.</p>
</li>
</ol>
<p>The fix isn't one trick. It's a stack of small ones, each addressing one of those failure modes and, eventually, the deeper problem of the main thread being the only thread.</p>
<h2 id="heading-the-mental-model-air-traffic-control-plus-a-kitchen-brigade">The Mental Model: Air Traffic Control Plus a Kitchen Brigade</h2>
<p>Before the code, two metaphors that will keep the pieces straight.</p>
<p><strong>First, air traffic control:</strong> Three roles, one airport.</p>
<ul>
<li><p>The <strong>control tower</strong> (your store) sees every plane (every sample) and tracks where it is.</p>
</li>
<li><p>The <strong>ground crew</strong> (React) sets up the runways and gates: the layout that planes use.</p>
</li>
<li><p>The <strong>pilots</strong> (the draw loop) actually fly. They look at the tower for clearance and act every few seconds.</p>
</li>
</ul>
<p>The control tower doesn't pull a gate from the ground crew every time a plane moves. It just holds the data. The ground crew rearranges gates when the schedule changes, which is rare. The pilots act constantly, at their own rate, off the tower's data.</p>
<p><strong>Second, a kitchen brigade:</strong> A restaurant kitchen at peak hour. One head chef can't make every dish. The classical brigade has stations: sauce, fish, pastry, garde manger, plating, and service. Each station owns a slice of the meal. The expediter coordinates timing.</p>
<ul>
<li><p>The <strong>expediter</strong> is your main thread.</p>
</li>
<li><p>The <strong>stations</strong> are your workers.</p>
</li>
<li><p>The <strong>plating window</strong> is your shared memory.</p>
</li>
<li><p>The <strong>dishes going to tables</strong> are your rendered frames.</p>
</li>
</ul>
<p>A single chef trying to do everything serially is your main-thread-only frontend. A brigade is your worker-based one. The brigade is faster because cuts, sauces, and sears happen in parallel, not because any one cook is faster than the soloist. The expediter doesn't cook, they orchestrate.</p>
<p>Everything below is a specific application of these two ideas.</p>
<h2 id="heading-step-1-stop-putting-samples-in-react-state">Step 1: Stop Putting Samples in React State</h2>
<p>The single biggest mistake in real-time React apps is treating every sample as state, which it isn't. State is what determines <em>which components exist and how they're arranged</em>. A live plot is one component. The 60,000 samples scrolling across it aren't 60,000 pieces of state. They're one buffer.</p>
<p>You want a store that lives outside React. A ring buffer over a typed array gives you constant-time inserts and a bounded heap:</p>
<pre><code class="language-ts">type Listener = () =&gt; void;

export function createSampleStore(capacity: number) {
  const buf = new Float32Array(capacity);
  let head = 0;
  let size = 0;
  const listeners = new Set&lt;Listener&gt;();

  return {
    push(sample: number) {
      buf[head] = sample;
      head = (head + 1) % capacity;
      if (size &lt; capacity) size++;
    },
    pushBatch(samples: Float32Array) {
      for (let i = 0; i &lt; samples.length; i++) {
        buf[head] = samples[i];
        head = (head + 1) % capacity;
        if (size &lt; capacity) size++;
      }
    },
    read(): Float32Array {
      if (size &lt; capacity) return buf.subarray(0, size);
      const out = new Float32Array(capacity);
      out.set(buf.subarray(head));
      out.set(buf.subarray(0, head), capacity - head);
      return out;
    },
    subscribe(l: Listener) {
      listeners.add(l);
      return () =&gt; listeners.delete(l);
    },
  };
}
</code></pre>
<p>Notice what's not here: no <code>useState</code>, no setter, no React anything. It's just plain JavaScript. The store can accept a million pushes per second and React won't care, because React isn't subscribed.</p>
<p>Here are the ring buffer mechanics, visualised:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779361162753/2374fc6e-429c-4a8a-8b31-30fb51c6052c.png" alt="Ring buffer with eight indexed slots, a head pointer advancing each push and wrapping around when it reaches the end, providing constant-time inserts and a bounded heap" style="display:block;margin:0 auto" width="1600" height="463" loading="lazy">

<p>We have head advances on every push and wraps at capacity. Reads pull a window of the last N samples in chronological order. The result is constant time and a bounded heap.</p>
<p>A simpler stop-gap, when you don't want a typed buffer yet, is to put the rolling window in a ref instead of state:</p>
<pre><code class="language-tsx">import { useEffect, useRef } from "react";

export default function RefChart({ socket }) {
  const bufferRef = useRef&lt;number[]&gt;([]);

  useEffect(() =&gt; {
    socket.on("newPoint", (point: number) =&gt; {
      bufferRef.current.push(point);
      if (bufferRef.current.length &gt; 1000) {
        bufferRef.current.shift();
      }
    });
  }, [socket]);

  return &lt;div&gt;Streaming {bufferRef.current.length} points&lt;/div&gt;;
}
</code></pre>
<p>This is the "10x faster than <code>NaiveChart</code>, still not great" version. The render doesn't trigger on every push, but you also won't see updates unless something else re-renders. For real plotting, pair the ref with a <code>requestAnimationFrame</code> draw loop (see Step 2).</p>
<h2 id="heading-step-2-separate-shape-from-values">Step 2: Separate Shape from Values</h2>
<p>React renders when the <em>shape</em> of the UI changes. New plot? Re-render. Removed plot? Re-render. Switched from line to bar? Re-render. None of those happen at 1000Hz. They happen a few times a minute, when the user clicks something.</p>
<p>The <em>values</em> inside each plot change at the data rate. Those should never touch React.</p>
<p>Concretely:</p>
<pre><code class="language-tsx">function LivePlot({ store }: { store: SampleStore }) {
  const canvasRef = useRef&lt;HTMLCanvasElement&gt;(null);

  useEffect(() =&gt; {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext("2d")!;

    let raf = 0;
    const draw = () =&gt; {
      const samples = store.read();
      drawSeries(ctx, samples);
      raf = requestAnimationFrame(draw);
    };
    raf = requestAnimationFrame(draw);
    return () =&gt; cancelAnimationFrame(raf);
  }, [store]);

  return &lt;canvas ref={canvasRef} width={1200} height={300} /&gt;;
}
</code></pre>
<p>React renders this component once. The <code>useEffect</code> runs once. The <code>requestAnimationFrame</code> loop reads from the store on every frame.</p>
<p>The store can be pushed to at any rate the source can manage. The user sees a smooth 60fps line whether the source is sending 100 samples per second or 100,000. The instinct to wire <code>samples</code> into <code>useState</code> is wrong, so resist it.</p>
<h3 id="heading-selective-subscriptions-when-you-do-need-react-in-the-loop">Selective Subscriptions When You Do Need React in the Loop</h3>
<p>Sometimes a component genuinely depends on the data (summary stats, axis labels, or a live value badge). For that, use a store with selective subscriptions so only the components that care re-render. Zustand makes this trivial:</p>
<pre><code class="language-ts">import { create } from "zustand";

const useDataStore = create&lt;{ latest: number | null; setLatest: (v: number) =&gt; void }&gt;((set) =&gt; ({
  latest: null,
  setLatest: (v) =&gt; set({ latest: v }),
}));

function LatestBadge() {
  // Only re-renders when latest changes, not when other store fields do.
  const latest = useDataStore((state) =&gt; state.latest);
  return &lt;div&gt;Latest: {latest?.toFixed(2)}&lt;/div&gt;;
}
</code></pre>
<p>Pair this with RAF coalescing on the writes (call <code>setLatest</code> once per frame, not once per sample) and you get a React component that updates smoothly at 60fps no matter what the data rate is.</p>
<p><code>useSyncExternalStore</code> is the native equivalent and works against any pub-sub store, including the ring buffer above. Use whichever feels lighter for your team.</p>
<h2 id="heading-step-3-move-heavy-work-off-the-main-thread">Step 3: Move Heavy Work Off the Main Thread</h2>
<p>The store and imperative draw loop handle React's contribution to the bottleneck. The main thread itself is still doing all the ingest, parsing, and math. Everything past ~50,000 samples per second per stream needs more.</p>
<p>The browser gives you four escape hatches: Web Workers, transferable objects, <code>SharedArrayBuffer</code> + Atomics, and <code>OffscreenCanvas</code>. Each solves a specific problem.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779369113008/d1d608c9-8078-4339-91e1-c9ee221bf014.png" alt="Browser process model with the renderer process containing the main thread, dedicated workers, shared workers, a service worker, and a compositor thread; the GPU process containing the GPU thread for WebGL and WebGPU; and the network process containing the network thread for fetch and WebSocket, with communication between main and worker types happening via postMessage" style="display:block;margin:0 auto" width="1600" height="1006" loading="lazy">

<p>The main thread runs JavaScript, the DOM, layout, and paint setup. Workers are isolated JavaScript contexts with their own event loops. They can't touch the DOM, they can't share memory by default, and every cross-thread message is async and copied unless you transfer it.</p>
<p>Three properties matter as you design against this model:</p>
<ul>
<li><p><strong>Workers can't touch the DOM:</strong> That's the point. They run pure JavaScript. Perfect for data work, network parsing, math, codecs, ML inference.</p>
</li>
<li><p><strong>Communication is async:</strong> No shared variable to read in the middle of a function. Plan APIs around requests and events.</p>
</li>
<li><p><strong>Data copies, unless you transfer or share it:</strong> Structured clone is the default, transferable objects skip the copy, and <code>SharedArrayBuffer</code> skips it permanently.</p>
</li>
</ul>
<h3 id="heading-dedicated-workers-in-practice">Dedicated Workers in Practice</h3>
<p>Here's a minimal worker for ingest:</p>
<pre><code class="language-ts">// worker.ts
self.onmessage = (event) =&gt; {
  const { samples } = event.data;
  // Decode, filter, decimate. The main thread doesn't see any of this.
  const summary = computeStats(samples);
  postMessage(summary);
};
</code></pre>
<pre><code class="language-tsx">// main thread
import { useEffect, useRef } from "react";

export default function WorkerChart({ socket, store }) {
  const workerRef = useRef&lt;Worker&gt;();

  useEffect(() =&gt; {
    workerRef.current = new Worker(new URL("./worker.ts", import.meta.url), {
      type: "module",
    });

    workerRef.current.onmessage = (event) =&gt; {
      store.pushBatch(event.data); // pre-processed, cheap to ingest
    };

    socket.on("newPoint", (point: number) =&gt; {
      workerRef.current?.postMessage({ point });
    });

    return () =&gt; workerRef.current?.terminate();
  }, [socket, store]);

  return &lt;LivePlot store={store} /&gt;;
}
</code></pre>
<p>Three things to internalise about workers.</p>
<p>First, workers are real processes from the runtime's perspective. Each has its own heap, event loop, and <code>globalThis</code>. Starting one costs about 1 to 5ms. Don't spin them up inside hot paths.</p>
<p>Second, module workers are the modern default. <code>type: "module"</code> enables ES modules inside the worker, including <code>import</code>. The legacy <code>importScripts</code> is for classic workers, so avoid it for new code.</p>
<p>Finally, bundlers know about workers. Vite, Webpack, esbuild, and Rspack all detect the <code>new Worker(new URL("./x.ts", import.meta.url))</code> pattern and produce a separate chunk for the worker.</p>
<h3 id="heading-a-worker-pool-that-scales-with-cores">A Worker Pool That Scales with Cores</h3>
<p>For CPU-bound work (parsing binary frames, decoding audio, computing FFTs), a pool spreads jobs across all available cores:</p>
<pre><code class="language-ts">class WorkerPool {
  private workers: Worker[];
  private next = 0;
  private pending = new Map&lt;string, (result: unknown) =&gt; void&gt;();

  constructor(scriptUrl: URL, size = Math.max(1, navigator.hardwareConcurrency - 1)) {
    this.workers = Array.from({ length: size }, () =&gt; {
      const w = new Worker(scriptUrl, { type: "module" });
      w.onmessage = (event) =&gt; {
        const cb = this.pending.get(event.data.id);
        if (!cb) return;
        this.pending.delete(event.data.id);
        cb(event.data.result);
      };
      return w;
    });
  }

  async run&lt;T&gt;(kind: string, payload: unknown, transferables: Transferable[] = []): Promise&lt;T&gt; {
    const id = crypto.randomUUID();
    const result = new Promise&lt;T&gt;((resolve) =&gt; this.pending.set(id, resolve as (r: unknown) =&gt; void));
    const worker = this.workers[this.next];
    this.next = (this.next + 1) % this.workers.length;
    worker.postMessage({ id, kind, payload }, transferables);
    return result;
  }
}

export const pool = new WorkerPool(new URL("./decoder.worker.ts", import.meta.url));
</code></pre>
<p>Round-robin distribution with one worker per core minus one. Pending requests resolve when the matching response arrives. It's cheap, predictable, and scales linearly until you hit memory bandwidth limits.</p>
<h3 id="heading-transferable-objects-the-no-copy-path">Transferable Objects, the No-copy Path</h3>
<p><code>postMessage</code> clones the payload by default. Cloning a 10MB buffer takes milliseconds and doubles your memory use. The fix is to <strong>transfer</strong> the buffer instead.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779369124743/0a53c521-618c-48ec-a5c5-935e1acdbf1a.png" alt="Side-by-side comparison of postMessage modes: default postMessage clones the buffer with a copy landing in both the main heap and the worker heap via structured clone, while Transferable transfers ownership so the same buffer exists once with ownership moving from main to worker" style="display:block;margin:0 auto" width="1600" height="4546" loading="lazy">

<p>The semantics: when you transfer a buffer, the sender loses access. The receiver gains it, with no copy and an O(1) handoff.</p>
<pre><code class="language-ts">const buf = new ArrayBuffer(10 * 1024 * 1024); // 10 MB
new Uint8Array(buf).set(somePayload);

worker.postMessage({ buf }, [buf]); // second arg = list of transferables
// `buf` is now detached on this side. Accessing it throws.
</code></pre>
<p>The list of transferable types in 2026 includes <code>ArrayBuffer</code> (and any typed-array view backed by one), <code>MessagePort</code>, <code>ImageBitmap</code>, <code>OffscreenCanvas</code>, the stream types (<code>ReadableStream</code>, <code>WritableStream</code>, <code>TransformStream</code>), <code>RTCDataChannel</code>, <code>VideoFrame</code>, <code>AudioData</code>, and the WebTransport streams. The most useful for React plus real-time work are <code>ArrayBuffer</code>, <code>OffscreenCanvas</code>, and <code>MessagePort</code>.</p>
<p>A common pitfall is that forgetting to transfer creates silent slowness. The app works, but it copies every message. Profile worker <code>postMessage</code> calls. If they're showing milliseconds for "small" payloads, you're cloning when you should be transferring.</p>
<pre><code class="language-ts">// Bad: copies every frame.
worker.postMessage({ samples: float32Array });

// Good: transfers the underlying buffer.
worker.postMessage({ samples: float32Array }, [float32Array.buffer]);
</code></pre>
<p>The buffer is detached after transfer, so the sender needs to re-allocate (or pull from a pool of pre-allocated buffers) if it wants to keep producing.</p>
<h3 id="heading-sharedarraybuffer-and-atomics">SharedArrayBuffer and Atomics</h3>
<p>Transfer hands a buffer off. <strong>Sharing</strong> lets both threads see the same memory simultaneously.</p>
<pre><code class="language-ts">const sab = new SharedArrayBuffer(1024 * 1024); // 1 MB shared
worker.postMessage({ sab });

// Both main and worker now hold references to the same memory.
const viewMain = new Int32Array(sab);
// Inside worker:
// const viewWorker = new Int32Array(event.data.sab);
</code></pre>
<p>Three properties matter.</p>
<p><code>SharedArrayBuffer</code> needs cross-origin isolation. Your page must be served with <code>Cross-Origin-Opener-Policy: same-origin</code> and <code>Cross-Origin-Embedder-Policy: require-corp</code>. Without these headers, <code>SharedArrayBuffer</code> is undefined in the browser. Covered in more detail later in the article.</p>
<p>You also need <code>Atomics</code> for synchronisation. Multiple threads writing to the same memory without coordination produces undefined results. <code>Atomics</code> gives you compare-and-swap, load, store, add, sub, wait, and notify operations on typed array views.</p>
<pre><code class="language-ts">const sab = new SharedArrayBuffer(8);
const view = new Int32Array(sab);

// Main thread: wake any worker that's waiting on slot 0.
Atomics.store(view, 0, 1);
Atomics.notify(view, 0, 1);

// Worker: block until slot 0 changes from 0.
const result = Atomics.wait(view, 0, 0); // "ok", "not-equal", or "timed-out"
</code></pre>
<p>And lock-free ring buffers are the killer app. A producer-consumer queue between two threads with no locking, no <code>postMessage</code> round-trip, and no GC pressure. The data sits in the shared buffer. Atomics coordinate read/write positions.</p>
<p>Here's a minimal SPSC (single-producer, single-consumer) ring buffer:</p>
<pre><code class="language-ts">type SharedRing = {
  data: Float32Array;          // payload
  control: Int32Array;         // [head, tail]
};

function createSharedRing(capacity: number): SharedRing {
  const sab = new SharedArrayBuffer(capacity * 4 + 16);
  const control = new Int32Array(sab, 0, 4);   // [head, tail, ...]
  const data = new Float32Array(sab, 16, capacity);
  return { data, control };
}

function push(ring: SharedRing, value: number): boolean {
  const head = Atomics.load(ring.control, 0);
  const tail = Atomics.load(ring.control, 1);
  const next = (head + 1) % ring.data.length;
  if (next === tail) return false; // full
  ring.data[head] = value;
  Atomics.store(ring.control, 0, next);
  return true;
}

function pop(ring: SharedRing): number | null {
  const tail = Atomics.load(ring.control, 1);
  const head = Atomics.load(ring.control, 0);
  if (tail === head) return null; // empty
  const value = ring.data[tail];
  Atomics.store(ring.control, 1, (tail + 1) % ring.data.length);
  return value;
}
</code></pre>
<p>The producer writes from one thread. The consumer reads from another, neither blocks, and there's no <code>postMessage</code> between them. At signal rates, this is the only architecture that scales.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779369132294/fcefe558-040e-41d3-b759-a8c10c5d5502.png" alt="Single-producer single-consumer ring buffer over SharedArrayBuffer: the producer (ingest worker) writes at the head pointer and increments it, the consumer (render thread) reads from the tail pointer and increments it, both pointers stored in the shared buffer and updated with atomic operations" style="display:block;margin:0 auto" width="1600" height="308" loading="lazy">

<p>For multi-producer or multi-consumer queues, you need compare-and-swap loops (<code>Atomics.compareExchange</code>). They get fiddly fast. Most production setups use SPSC where they can and fall back to message-passing where they can't.</p>
<h3 id="heading-in-electron-ingest-in-the-main-process">In Electron, Ingest in the Main Process</h3>
<p>The same idea applies one level up. With Electron and a native SDK, you can ingest samples in the <strong>main process</strong>, buffer there, and forward batches across IPC at the renderer's refresh cadence. One IPC message per sample at 1kHz will saturate IPC. One IPC message per frame with a batch of 16 samples is trivial.</p>
<pre><code class="language-ts">// electron main: buffer in Node, flush at 60Hz
let pending: number[] = [];

device.on("sample", (value) =&gt; pending.push(value));

setInterval(() =&gt; {
  if (pending.length === 0) return;
  const batch = new Float32Array(pending);
  pending = [];
  // Transferable to avoid the structured-clone copy.
  mainWindow.webContents.send("device:samples", batch.buffer, [batch.buffer]);
}, 1000 / 60);
</code></pre>
<pre><code class="language-ts">// preload: expose a thin subscription API to the renderer
contextBridge.exposeInMainWorld("device", {
  onSamples: (cb: (samples: Float32Array) =&gt; void) =&gt; {
    const handler = (_: unknown, buf: ArrayBuffer) =&gt; cb(new Float32Array(buf));
    ipcRenderer.on("device:samples", handler);
    return () =&gt; ipcRenderer.removeListener("device:samples", handler);
  },
});
</code></pre>
<pre><code class="language-tsx">// renderer: feed the store from the bridge
useEffect(() =&gt; {
  return window.device.onSamples((batch) =&gt; store.pushBatch(batch));
}, []);
</code></pre>
<p>The renderer thread of the renderer touches only one batch per frame, no matter how fast the device is. The data work happens upstream.</p>
<h2 id="heading-step-4-render-off-main-with-offscreencanvas">Step 4: Render Off Main with <code>OffscreenCanvas</code></h2>
<p>The DOM is single-threaded. The Canvas API used to be too. <code>OffscreenCanvas</code> breaks that: a canvas you can transfer to a worker, where it draws independently of main.</p>
<pre><code class="language-ts">// Main thread
const canvas = canvasRef.current!;
const offscreen = canvas.transferControlToOffscreen();
worker.postMessage({ canvas: offscreen }, [offscreen]);
</code></pre>
<pre><code class="language-ts">// Worker
let ctx: OffscreenCanvasRenderingContext2D | null = null;

self.onmessage = (event) =&gt; {
  if (event.data.canvas) {
    ctx = event.data.canvas.getContext("2d");
    return;
  }
  if (event.data.samples &amp;&amp; ctx) {
    drawSeries(ctx, event.data.samples);
  }
};
</code></pre>
<p>The main thread is now free to handle clicks, hover, and other interaction without competing with the draw loop. The worker draws at its own rate, against whatever data it has.</p>
<p>Combined with <code>SharedArrayBuffer</code>, you get the cleanest real-time rendering pipeline available in the browser:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779369135331/1a205236-981d-4df7-8b21-698d15b84a63.png" alt="Rendering pipeline off the main thread: a data source feeds an ingest worker which writes into a SharedArrayBuffer, which a render worker owning an OffscreenCanvas reads to issue GPU commands that update the DOM, while the main thread reads a summary from the SharedArrayBuffer for React UI" style="display:block;margin:0 auto" width="1600" height="260" loading="lazy">

<p>The ingest worker writes samples into the shared buffer. The render worker reads them and draws. Main only reads summaries (FPS, latest value, channel labels) and renders chrome. No data ever crosses through main's event loop.</p>
<p>For 19-channel signal at 1kHz, this is the only architecture that keeps a guaranteed 60fps on a laptop, with headroom.</p>
<h2 id="heading-step-5-decimate-before-you-draw">Step 5: Decimate Before You Draw</h2>
<p>A 1200-pixel-wide canvas can show, at best, 1200 distinct X positions. If you have 60,000 samples in your window and you draw all of them, you do 50 times more work than the user can see.</p>
<p>Pick the right point per pixel column. The "min-max" pattern works well for signals: for each pixel column, find the minimum and maximum value in that range and draw a vertical line between them. This is visually identical to drawing every point, but it's much cheaper.</p>
<pre><code class="language-ts">function drawDecimated(
  ctx: CanvasRenderingContext2D,
  samples: Float32Array,
  width: number,
) {
  const samplesPerPixel = samples.length / width;
  ctx.beginPath();
  for (let x = 0; x &lt; width; x++) {
    const start = Math.floor(x * samplesPerPixel);
    const end = Math.floor((x + 1) * samplesPerPixel);
    let min = Infinity;
    let max = -Infinity;
    for (let i = start; i &lt; end; i++) {
      const v = samples[i];
      if (v &lt; min) min = v;
      if (v &gt; max) max = v;
    }
    ctx.moveTo(x, scale(min));
    ctx.lineTo(x, scale(max));
  }
  ctx.stroke();
}
</code></pre>
<p><a href="https://en.wikipedia.org/wiki/Downsampling_(signal_processing)">Decimation</a> is the single biggest CPU win in real-time visualisation, and almost nobody does it.</p>
<p>A more visually faithful variant is <strong>LTTB (Largest Triangle Three Buckets)</strong>, an algorithm that picks one representative sample per bucket while preserving the visual shape better than min-max. It's worth the read if you're plotting non-signal data like stock charts where peaks and dips matter individually. Most good chart libraries (uPlot, Plotly, ECharts) include decimation out of the box.</p>
<h2 id="heading-step-6-wrap-an-external-renderer">Step 6: Wrap an External Renderer</h2>
<p>You don't always need to write the draw loop yourself. React is great at lifecycle management. Imperative chart libraries are great at raw performance. The right move is often to let React mount and unmount the chart while the library handles the fast inner loop.</p>
<pre><code class="language-tsx">import Uplot from "uplot";
import "uplot/dist/uPlot.min.css";
import { useEffect, useRef } from "react";

export default function UPlotChart({ data }: { data: AlignedData }) {
  const ref = useRef&lt;HTMLDivElement&gt;(null);
  const plotRef = useRef&lt;Uplot | null&gt;(null);

  useEffect(() =&gt; {
    const opts = {
      title: "Realtime Chart",
      width: 600,
      height: 300,
      series: [{}, { label: "Signal" }],
    };
    plotRef.current = new Uplot(opts, data, ref.current!);
    return () =&gt; plotRef.current?.destroy();
  }, []);

  useEffect(() =&gt; {
    plotRef.current?.setData(data); // imperative update, no React render
  }, [data]);

  return &lt;div ref={ref} /&gt;;
}
</code></pre>
<p>uPlot, TimeChart, ECharts, Plotly, LightningChart, and the others all follow this shape: instantiate inside <code>useEffect</code>, call <code>setData</code> imperatively, and destroy on unmount. React orchestrates and the library renders.</p>
<p>The general pattern, for any imperative renderer, looks like this:</p>
<pre><code class="language-tsx">function ChartWrapper({ config, data }) {
  const ref = useRef&lt;HTMLDivElement&gt;(null);

  useEffect(() =&gt; {
    const chart = new SomeFastChartLib(ref.current, config);
    chart.setData(data);
    return () =&gt; chart.destroy();
  }, [config, data]);

  return &lt;div ref={ref} /&gt;;
}
</code></pre>
<p>This is the highest-ROI move if you're not in a domain where you need pixel-level control over the drawing. Reach for a library first, and only write your own draw loop when no library fits.</p>
<h2 id="heading-step-7-when-canvas-isnt-enough-reach-for-webgl">Step 7: When Canvas isn't Enough, Reach for WebGL</h2>
<p>Canvas 2D handles a few thousand line segments per frame comfortably. Past that, you start spending milliseconds in <code>stroke()</code> itself.</p>
<p>WebGL (or its higher-level wrappers like <code>regl</code>, <code>twgl</code>, <code>pixi.js</code>, <code>deck.gl</code>) moves the rendering to the GPU. You pay an upfront cost (writing shaders and managing buffers) for the ability to draw millions of points without breaking a sweat.</p>
<p>Here's a minimal WebGL "line strip with a single vertex shader" sketch:</p>
<pre><code class="language-ts">const gl = canvas.getContext("webgl2")!;

const program = gl.createProgram()!;
// ... compile vertex + fragment shaders, link, get attribute location ...

const samplesBuffer = gl.createBuffer();
function drawWebGL(samples: Float32Array) {
  gl.bindBuffer(gl.ARRAY_BUFFER, samplesBuffer);
  gl.bufferData(gl.ARRAY_BUFFER, samples, gl.STREAM_DRAW);
  gl.useProgram(program);
  gl.drawArrays(gl.LINE_STRIP, 0, samples.length);
}
</code></pre>
<p>The pattern is the same as Canvas 2D: an imperative draw call inside the RAF loop. The difference is the GPU does the actual rasterising. Most real-time charting libraries that claim "millions of points" are doing exactly this under the hood.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1779361166770/22241c5c-446b-4026-88fb-33e3caad3831.png" alt="Decision tree comparing rendering options: Canvas 2D for up to a few thousand points, WebGL for tens of thousands or more, and WebGPU for 3D, custom shaders, or compute once stable" style="display:block;margin:0 auto" width="1600" height="1351" loading="lazy">

<p>Default to Canvas 2D, and escalate to WebGL only when you can prove Canvas is the bottleneck on the Profiler.</p>
<h2 id="heading-step-8-keep-memory-flat">Step 8: Keep Memory Flat</h2>
<p>Real-time apps die slowly. They run smoothly for an hour and then the laptop fan kicks in. The cause is almost always memory.</p>
<p>There are three rules that keep the heap calm.</p>
<p>First, use typed arrays for numeric data. A <code>Float32Array</code> of 60,000 floats is 240KB. A plain JavaScript array of the same size is around 1.4MB and creates GC pressure on every push.</p>
<p>Second, bound everything. Use ring buffers, not growing arrays. Put caps on history, queues, and pending work. Anything that <em>can</em> grow unbounded eventually will.</p>
<p>Third, reuse buffers. Allocate once in setup, and reuse across frames. Allocating a fresh array per frame at 60fps is 60 allocations per second per plot. Multiply by plot count.</p>
<pre><code class="language-ts">// Bad: fresh array every frame.
function drawFrame() {
  const snapshot = store.read(); // returns a new Float32Array
  drawDecimated(ctx, snapshot, width);
}

// Better: reuse a draw buffer.
const drawBuf = new Float32Array(WINDOW_SIZE);

function drawFrame() {
  store.readInto(drawBuf); // writes into the existing buffer
  drawDecimated(ctx, drawBuf, width);
}
</code></pre>
<p>These rules aren't React-specific. They're the rules any real-time system follows. The reason they need stating is that React-shaped thinking ("derive a new array each render") is the opposite of what real-time wants.</p>
<h2 id="heading-step-9-scheduling-strategies">Step 9: Scheduling Strategies</h2>
<p>A worker pool with no scheduling is just a queue. Sometimes you want priority: a user-driven action should jump ahead of a background sweep.</p>
<h3 id="heading-priority-queues">Priority Queues</h3>
<p>A small priority scheduler:</p>
<pre><code class="language-ts">type Priority = "high" | "normal" | "low";

class PriorityPool {
  private queues: Record&lt;Priority, Job[]&gt; = { high: [], normal: [], low: [] };
  private idle: Worker[];

  enqueue(job: Job, priority: Priority = "normal") {
    if (this.idle.length &gt; 0) {
      const worker = this.idle.pop()!;
      this.dispatch(worker, job);
    } else {
      this.queues[priority].push(job);
    }
  }

  private next(): Job | null {
    for (const p of ["high", "normal", "low"] as const) {
      const j = this.queues[p].shift();
      if (j) return j;
    }
    return null;
  }

  private dispatch(worker: Worker, job: Job) {
    worker.postMessage(job.payload, job.transferables);
    worker.onmessage = (event) =&gt; {
      job.resolve(event.data);
      const next = this.next();
      if (next) this.dispatch(worker, next);
      else this.idle.push(worker);
    };
  }
}
</code></pre>
<p>Three buckets are usually enough: high (user-initiated), normal (steady-state work), low (background sweeps, prefetch, telemetry flushing).</p>
<h3 id="heading-chunkable-work">Chunkable Work</h3>
<p>A job that takes 2 seconds blocks a worker for 2 seconds. If you want to keep workers responsive to higher-priority jobs, the job has to be chunkable.</p>
<pre><code class="language-ts">// In the worker:
self.onmessage = async (event) =&gt; {
  const { id, kind, payload } = event.data;
  if (kind === "decode_large") {
    const total = payload.byteLength;
    for (let i = 0; i &lt; total; i += CHUNK) {
      const chunk = decodeChunk(payload, i, Math.min(i + CHUNK, total));
      self.postMessage({ id, kind: "progress", chunk, offset: i });
      // Yield so the worker can check its message queue.
      await new Promise((r) =&gt; setTimeout(r, 0));
    }
    self.postMessage({ id, kind: "done" });
  }
  if (kind === "cancel") {
    // ... abort the current job
  }
};
</code></pre>
<p>Yielding inside a worker isn't free, but it lets the worker process cancellation messages or higher-priority jobs interleaved with the big task. For long jobs (like a firmware flash, large file decode, or big render), this is essential.</p>
<h3 id="heading-fan-out-and-fan-in">Fan-out and Fan-in</h3>
<p>Split a big job into N pieces, dispatch each to a different worker, and gather the results.</p>
<pre><code class="language-ts">async function decodeFile(buffer: ArrayBuffer): Promise&lt;DecodedFrame[]&gt; {
  const chunks = splitBuffer(buffer, 8);
  const results = await Promise.all(
    chunks.map((chunk) =&gt; pool.run&lt;DecodedFrame[]&gt;("decode", chunk, [chunk])),
  );
  return results.flat();
}
</code></pre>
<p>This gives you linear speedup on parallelisable workloads, up to the worker count. It's critical for batch operations like decoding a recording, summarising a long document, or computing embeddings for a folder.</p>
<h2 id="heading-step-10-measure-sustained-performance">Step 10: Measure Sustained Performance</h2>
<p>A spike on the Profiler is one thing. A slow heap creep over an hour is another. For real-time apps, you measure two things.</p>
<p>First, frame consistency. Are you holding 60fps consistently, or dropping occasional frames? A simple FPS meter:</p>
<pre><code class="language-ts">let lastTime = performance.now();
let frames = 0;

function rafLoop(now: number) {
  frames++;
  if (now - lastTime &gt;= 1000) {
    const fps = (frames * 1000) / (now - lastTime);
    frames = 0;
    lastTime = now;
    console.log(`fps: ${fps.toFixed(1)}`);
  }
  requestAnimationFrame(rafLoop);
}
requestAnimationFrame(rafLoop);
</code></pre>
<p>A more honest measure is the worst frame in a window. Average frame time hides the jank.</p>
<p>Second, heap stability. Open DevTools Memory tab, take a heap snapshot, run the app for ten minutes, take another snapshot, and then compare. The diff should be flat. If it's growing, you have a leak: retained listeners, growing arrays, or closures holding onto large objects.</p>
<p>For real apps, wire heap usage and FPS into your analytics so you spot regressions before users complain.</p>
<h2 id="heading-case-study-19-eeg-channels">Case Study: 19 EEG Channels</h2>
<p>Back to the project that started this article: we have nineteen channels, each at 1kHz, all rendered simultaneously, and all needing to stay smooth across multi-hour recording sessions.</p>
<p>The first build used <strong>LightningChart</strong>. It's powerful, capable, and beautiful. But it's also heavy. Memory usage climbed noticeably, the chart's own internals were doing a lot of work for our use case (which was 19 simple line plots, not full multi-axis financial charts), and the licensing was a friction point.</p>
<p>We switched to <strong>uPlot</strong>. It's tiny, fast, and written specifically for time-series. Memory usage dropped, render time per frame went from "occasionally over budget" to "always under," and my machine stopped sounding like it was about to take off. The chart library change alone bought us most of the headroom we needed.</p>
<p>The architecture around the chart did the rest. The pipeline runs on four threads:</p>
<ul>
<li><p><strong>One ingest worker</strong> reads from the device SDK over IPC (Electron main process to renderer).</p>
</li>
<li><p><strong>One</strong> <code>SharedArrayBuffer</code> holds the rolling window for all 19 channels.</p>
</li>
<li><p><strong>One render worker</strong> reads the SAB and draws to an <code>OffscreenCanvas</code>.</p>
</li>
<li><p><strong>Main thread</strong> renders chrome: channel labels, controls, and the FPS meter.</p>
</li>
</ul>
<p>The shared buffer layout is one big <code>Float32Array</code> indexed as <code>[channel * samplesPerChannel + sampleIndex]</code>. The ingest worker writes new samples and advances per-channel head pointers (stored in an <code>Int32Array</code> slice of the SAB). The render worker reads the latest window each frame.</p>
<pre><code class="language-ts">const CHANNELS = 19;
const WINDOW_SAMPLES = 60_000;

const sab = new SharedArrayBuffer(CHANNELS * WINDOW_SAMPLES * 4 + CHANNELS * 4);
const heads = new Int32Array(sab, 0, CHANNELS);
const samples = new Float32Array(sab, CHANNELS * 4, CHANNELS * WINDOW_SAMPLES);

function writeSample(channel: number, value: number) {
  const head = Atomics.load(heads, channel);
  samples[channel * WINDOW_SAMPLES + head] = value;
  Atomics.store(heads, channel, (head + 1) % WINDOW_SAMPLES);
}
</code></pre>
<p>The renderer reads the channel buffers, decimates per pixel column, and draws:</p>
<pre><code class="language-ts">// render.worker.ts
function drawFrame() {
  const ctx = offscreenCtx;
  ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
  for (let ch = 0; ch &lt; CHANNELS; ch++) {
    const start = ch * WINDOW_SAMPLES;
    drawDecimatedRow(ctx, samples.subarray(start, start + WINDOW_SAMPLES), ch);
  }
  requestAnimationFrame(drawFrame);
}
</code></pre>
<p>On a 2024 M3 MacBook Pro, this holds 60fps with 19 channels at 1kHz, and 144fps if the display supports it. The main thread stays under 1% utilisation. Workers consume the spare cores. The user feels something that used to require a native app.</p>
<p>The lesson, in short: most of the work is choosing the right tool for the inner loop, and getting out of its way.</p>
<h2 id="heading-benchmarks-single-thread-vs-multi-thread">Benchmarks: Single Thread vs Multi-Thread</h2>
<p>Here are numbers from running comparable workloads on a 2024 M3 MacBook Pro. They're indicative, not promissory.</p>
<table>
<thead>
<tr>
<th>Workload</th>
<th>Main thread only</th>
<th>Worker pool</th>
<th>Workers + SAB</th>
<th>Workers + SAB + OffscreenCanvas</th>
</tr>
</thead>
<tbody><tr>
<td>Parse 100MB binary file</td>
<td>4.2s (UI frozen)</td>
<td>1.1s</td>
<td>1.0s</td>
<td>1.0s</td>
</tr>
<tr>
<td>Decode 1,000 frames</td>
<td>920ms</td>
<td>280ms</td>
<td>240ms</td>
<td>240ms</td>
</tr>
<tr>
<td>Render 1M-point chart</td>
<td>24fps</td>
<td>24fps</td>
<td>28fps</td>
<td>60fps</td>
</tr>
<tr>
<td>Telemetry: 4 streams x 1000Hz</td>
<td>22fps</td>
<td>38fps</td>
<td>55fps</td>
<td>60fps</td>
</tr>
<tr>
<td>EEG: 19 channels x 1kHz</td>
<td>12fps</td>
<td>25fps</td>
<td>48fps</td>
<td>60fps (144fps possible)</td>
</tr>
<tr>
<td>Main-thread JS time per frame</td>
<td>22ms</td>
<td>8ms</td>
<td>4ms</td>
<td>&lt; 1ms</td>
</tr>
<tr>
<td>Memory overhead</td>
<td>baseline</td>
<td>+50MB</td>
<td>+20MB</td>
<td>+20MB</td>
</tr>
<tr>
<td>Worker spin-up latency (first call)</td>
<td>0</td>
<td>2-5ms</td>
<td>2-5ms</td>
<td>5-10ms</td>
</tr>
</tbody></table>
<p>The pattern: workers alone help, and workers plus shared memory help more. Workers plus shared memory plus <code>OffscreenCanvas</code> is what gets you to "the main thread is doing nothing and the chart is still smooth."</p>
<p>For chart-heavy apps, the leap from "workers" to "workers plus <code>OffscreenCanvas</code>" is the biggest single architectural improvement available without leaving the browser.</p>
<h2 id="heading-the-coopcoep-catch">The COOP/COEP Catch</h2>
<p><code>SharedArrayBuffer</code> and high-resolution timers were tightened in 2020 after Spectre/Meltdown. To use them, your page must be served with two HTTP headers:</p>
<pre><code class="language-plaintext">Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
</code></pre>
<p>This opts your page into "cross-origin isolation." Within an isolated context, <code>SharedArrayBuffer</code> exists, <code>performance.now()</code> is high-resolution, and various other restricted APIs work.</p>
<p>Outside an isolated context, <code>SharedArrayBuffer</code> is undefined, <code>performance.now()</code> is throttled to about 1ms precision, and Atomics throw.</p>
<p>The cost is significant. <code>require-corp</code> means every cross-origin resource (images from a CDN, embedded YouTube videos, third-party fonts, analytics scripts) must explicitly opt in by setting <code>Cross-Origin-Resource-Policy: cross-origin</code> or <code>Cross-Origin-Embedder-Policy: credentialless</code>. Many third-party services don't, which breaks their embedding.</p>
<p>There are two practical options:</p>
<ul>
<li><p><strong>For an Electron app:</strong> the renderer process can be configured to use these headers easily. Most production Electron apps that want real-time visualisation enable them by default.</p>
</li>
<li><p><strong>For a browser app:</strong> weigh the embeds you'd lose against the performance you'd gain. If your app is the main attraction (Figma, Google Docs), opt in. If you depend on third-party widgets, the cost is real.</p>
</li>
</ul>
<p>For chart-heavy or signal-heavy apps that need SAB, the Electron path is usually cleaner.</p>
<h2 id="heading-production-tradeoffs">Production Tradeoffs</h2>
<p>Here are the five real costs of everything above.</p>
<ul>
<li><p><strong>Code complexity:</strong> A worker-driven app has 2 to 4 times the source files of a single-threaded one (main + workers + shared types). It's worth it for the right scale, but painful for a trivial app.</p>
</li>
<li><p><strong>Debugging:</strong> Stack traces split across threads. Chrome DevTools handles this well in 2026 (each worker has its own debugger panel), but it's still more work than a single-thread bug.</p>
</li>
<li><p><strong>Bundle size:</strong> Each worker is a separate chunk. Tree-shaking inside workers is sometimes worse than in main (less mature). Audit worker bundles separately.</p>
</li>
<li><p><strong>Startup latency:</strong> Spinning up workers at app start adds 50 to 200ms. Pre-warm them during the splash screen, or accept the first-frame delay.</p>
</li>
<li><p><strong>Browser API gaps:</strong> <code>localStorage</code>, <code>document</code>, and most DOM APIs aren't available in workers. Some libraries silently rely on them and break. Test in a worker context before bundling a library you haven't tried there.</p>
</li>
</ul>
<p>There are three trade-offs specific to the imperative rendering pattern:</p>
<ul>
<li><p><strong>Declarative animation of the data:</strong> The chart frame, labels, and controls all stay declarative. The data inside the chart becomes imperative.</p>
</li>
<li><p><strong>Easy snapshot testing of the rendered output:</strong> A canvas has no DOM you can query. Test the data path separately from the draw path. Snapshot the store output, not the pixels.</p>
</li>
<li><p><strong>React's component story for the inner loop:</strong> The draw loop is a closure. Composing draw loops is harder than composing components. Pick your component boundary carefully so each canvas does one thing.</p>
</li>
</ul>
<p>For most apps these costs aren't worth paying. For an app that has to render 1kHz data smoothly, they're the price of admission.</p>
<h2 id="heading-should-you-build-like-this">Should You Build Like This?</h2>
<p>If your data rate is below 30 updates per second per stream, none of this is needed. Naïve <code>setState</code> per batch will work. Profile first, optimise second.</p>
<p>This architecture earns its keep when:</p>
<ul>
<li><p>You have many streams or sensors</p>
</li>
<li><p>Ingestion is sustained, not bursty</p>
</li>
<li><p>The UX promise is smooth motion for hours, not seconds</p>
</li>
<li><p>You'd rather not rewrite the UI in a native language to get there</p>
</li>
</ul>
<p>The boring rule: start with <code>requestAnimationFrame</code> coalescing and external stores. Promote to workers when those aren't enough. Promote to shared memory when worker <code>postMessage</code> is the bottleneck. Promote to <code>OffscreenCanvas</code> when the render loop itself becomes the bottleneck. Each step is a real architectural investment. Take them in order.</p>
<h2 id="heading-wrapping-up">Wrapping Up</h2>
<p>React can handle real-time visualisation if you use it the right way. Instead of pushing React to do everything, use it as the conductor. Let specialised libraries and workers handle the heavy lifting.</p>
<p>These are the three rules that hold up across every high-frequency React app I've built:</p>
<ol>
<li><p><strong>Workers do the work, while main does the UI.</strong> If main is doing math, you've put the math in the wrong place.</p>
</li>
<li><p><strong>Transfer if you can, share if you must.</strong> Both beat cloning. Sharing is more complex than transferring.</p>
</li>
<li><p><strong>Let React orchestrate. Let specialised tools render.</strong> The store owns the data, the draw loop owns the values, and React owns the shape.</p>
</li>
</ol>
<p>Get those right and your React app stops being a one-core system that flinches at high-frequency data. It becomes a real multi-core system that scales with the hardware, ingests without dropping, and renders without stuttering.</p>
<p>The cores are right there. Use them.</p>
<h2 id="heading-references">References</h2>
<ul>
<li><p><a href="https://github.com/leeoniya/uPlot">uPlot</a>: tiny, fast, focused on time-series.</p>
</li>
<li><p><a href="https://github.com/huww98/TimeChart">TimeChart</a>: high-performance real-time chart on WebGL.</p>
</li>
<li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers">Using Web Workers in React</a>: MDN reference.</p>
</li>
<li><p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer">SharedArrayBuffer on MDN</a>: the shared-memory primitive.</p>
</li>
<li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas">OffscreenCanvas on MDN</a>: rendering off the main thread.</p>
</li>
<li><p><a href="https://web.dev/articles/coop-coep">COOP and COEP explainer</a>: what cross-origin isolation buys you.</p>
</li>
</ul>
 ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ How to Build a Team of AI Agents for Your Website for Free Using Agno and Groq ]]>
                </title>
                <description>
                    <![CDATA[ AI is quickly changing the way we work, and more and more companies are using it to help them get and retain clients. Teams are also using AI to create innovative and responsive websites capable of engaging visitors while also providing helpful infor... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/build-a-team-of-ai-agents-for-your-website-for-free/</link>
                <guid isPermaLink="false">67eb1b3398e2cf5154940366</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                    <category>
                        <![CDATA[ react js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ programming ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Python ]]>
                    </category>
                
                    <category>
                        <![CDATA[ AI ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Artificial Intelligence ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Andrew Baisden ]]>
                </dc:creator>
                <pubDate>Mon, 31 Mar 2025 22:46:11 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1742397437476/0ffa13b0-c668-40d7-864f-596f523f6101.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>AI is quickly changing the way we work, and more and more companies are using it to help them get and retain clients. Teams are also using AI to create innovative and responsive websites capable of engaging visitors while also providing helpful information.</p>
<p>AI agents are powerful tools for customer services. Having them power your platforms and websites might sound like an expensive proposition with high technical expertise required. But with the emergence of new modern platforms like Agno and Groq, it’s now easier to integrate an AI agent system into your website while still staying within budget.</p>
<p>In this article, you’ll go through the process of developing your own AI agent ecosystem (for free). This will enable you to have a website that can handle customer enquiries, create content, analyse a user's behaviour, and provide custom personal experiences for each user. It's a fantastic setup because you can automate part of your business, speeding up lead generation and freeing up your time to work on more high-priority tasks.</p>
<p>This article is for developers who are familiar with JavaScript, React, and Python. Even if you don’t have a complete understanding of all three, as long as you are a beginner or junior with some knowledge, you should be able to understand at least some of the code. For example, JavaScript and Python are pretty similar syntax-wise, so if you have experience with either of them, then just reading through the codebase will give you an idea of how everything works.</p>
<p>For this tutorial, we’ll build a portfolio website. But you can use the ideas and concepts you learn here for any type of website, regardless of whether you are a solo entrepreneur or part of a large company. With these tools and frameworks, it's possible to transform your web presence without going over budget.</p>
<h2 id="heading-table-of-contents">Table of Contents</h2>
<ul>
<li><p><a class="post-section-overview" href="#prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#what-are-ai-agents">What Are AI Agents?</a></p>
</li>
<li><p><a class="post-section-overview" href="#what-are-agno-and-groq-cloud">What Are Agno and Groq Cloud?</a></p>
</li>
<li><p><a class="post-section-overview" href="#what-you-will-be-building">What You Will Be Building</a></p>
</li>
<li><p><a class="post-section-overview" href="#building-our-python-backend">Building Our Python Backend</a></p>
<ul>
<li><p><a class="post-section-overview" href="#creating-an-account-on-groq-cloud">Creating an Account on Groq Cloud</a></p>
</li>
<li><p><a class="post-section-overview" href="#setting-up-our-python-project">Setting Up Our Python Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#working-on-the-python-codebase">Working on the Python Codebase</a></p>
</li>
<li><p><a class="post-section-overview" href="#running-our-python-backend">Running Our Python Backend</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#building-our-react-frontend">Building Our React Frontend</a></p>
</li>
<li><p><a class="post-section-overview" href="#conclusion">Conclusion</a></p>
</li>
<li><p><a class="post-section-overview" href="#stay-up-to-date-with-tech-programming-productivity-and-ai">Stay Up to Date with Tech, Programming, Productivity, and AI</a></p>
</li>
</ul>
<h2 id="heading-prerequisites">Prerequisites</h2>
<ul>
<li><p>Prior knowledge of JavaScript, React, and Python</p>
</li>
<li><p><a target="_blank" href="https://www.python.org/">Python</a> installed and setup locally on your computer</p>
</li>
<li><p>An account on <a target="_blank" href="https://groq.com/">Groq Cloud</a></p>
</li>
<li><p>A code editor/IDE installed like <a target="_blank" href="https://www.cursor.com/en">Cursor</a>, <a target="_blank" href="https://codeium.com/windsurf">Windsurf</a>, or <a target="_blank" href="https://code.visualstudio.com/">VS Code</a></p>
</li>
</ul>
<h2 id="heading-what-are-ai-agents">What Are AI Agents?</h2>
<p>AI agents are computer systems or programs that are designed to use artificial intelligence to interact with their world and achieve certain objectives. They are able to perceive their world – through sensors, user input, or data – and act to achieve goals, typically with some degree of autonomy. This means that they will decide things for themselves, sometimes with little to no human intervention, depending on how they were designed.</p>
<h2 id="heading-what-are-agno-and-groq-cloud">What are Agno and Groq Cloud?</h2>
<p>Agno is a lightweight library that lets you build Multimodal Agents. It’s an AI inference engine designed to optimise LLMs for speed and performance. This means it can provide super-fast AI model inference with reduced latency and improved resource utilisation. It has the potential to replace current inference platforms like NVIDIA TensorRT or Hugging Face's Text Generation Inference (TGI).</p>
<p>Groq Cloud is a cloud-based AI inference platform based on Groq LPU (Language Processing Unit) chips, which are optimised for ultra-low-latency AI workloads. Groq is great at high-speed token generation rates, making it perfect for real-time AI applications like chatbots, AI coding help, and other latency-sensitive workloads. The Groq Cloud platform offers free access to its large language models (LLMs) through a free tier, but there are some usage limits.</p>
<p>If you go to the <a target="_blank" href="https://console.groq.com/playground">Groq Cloud Playground</a> you can find LLM models from different companies like:</p>
<ul>
<li><p>Qwen</p>
</li>
<li><p>DeepSeek R1</p>
</li>
<li><p>Google Gemma 2</p>
</li>
<li><p>Hugging Face</p>
</li>
<li><p>Meta llama</p>
</li>
<li><p>Mistral AI</p>
</li>
<li><p>OpenAI</p>
</li>
</ul>
<p>This is great because Groq Cloud gives us the flexibility to choose from any of these AI LLM models for our AI agent application. Agno basically acts as the orchestration layer for multiple AI agents. In our case, that would be WelcomeAgent, ProjectAgent, CareerAgent, BusinessAdvisor and ResearchAgent.</p>
<p>The platform is able to manage their conversations, task delegation, and memory. When any of our AI agents need to reason or generate output, Agno then uses Groq Cloud, which can run large language models (LLMs), and it does this with ultra-low latency. The advantage to this is that it ensures that it has fast and efficient responses. Groq Cloud itself is not an LLM – rather, it is a high-performance inference engine which hosts and serves LLMs from lots of different providers.</p>
<p>For this project, we will use Meta’s LLaMA 3 model because it strikes a strong balance between performance and accuracy and is openly accessible. This means that it is well-suited for the AI agents in our portfolio website.</p>
<p>It's worth mentioning that we could have used the LLaMA model from <a target="_blank" href="http://llama.com">llama.com</a>. Still, instead we will use it via Groq Cloud, because, this way, we get better optimisation, more capabilities, and better-quality responses for each AI agent. This is because Groq Cloud gives us the flexibility to test and choose between different AI models if we wish to do so, and that means that we can get the best one for our needs.</p>
<h2 id="heading-what-you-will-be-building">What You Will Be Building</h2>
<p>Today, you will be building a portfolio website that incorporates AI agents with which anyone can interact. These AI agents are like customer service representatives because anyone can ask them questions about your skills and portfolio, and they will provide the person with information.</p>
<p>This is great because it means that potential clients can learn anything about you 24/7 without having actually to talk to you when you are unavailable. You could even use this portfolio as a template for building your portfolio website or as inspiration for creating one.</p>
<p>In total, there will be five AI agents on your portfolio website:</p>
<ul>
<li><p>WelcomeAgent: a specialist in helping users navigate the website, whether the user is an employer, client, or fellow programmer</p>
</li>
<li><p>ProjectAgent: a project specialist that can provide information about projects, technology, and challenges</p>
</li>
<li><p>CareerAgent: a career specialist that can provide information about skills, experience, and professional background</p>
</li>
<li><p>BusinessAdvisor: a client specialist that can provide information about services, pricing, and project details</p>
</li>
<li><p>ResearchAgent: a research specialist that can provide information about technology, trends, and industry news</p>
</li>
</ul>
<p>The massive benefit of incorporating AI agents into a portfolio website is that they can create a personalised experience by providing an interactive experience which is tailor-made and not as easily replicated on other, more generic websites.</p>
<p>This can set your website apart because, as opposed to having a static website for showcasing your talent, an AI agent is capable of guiding visitors, answering queries about your projects, and recommending relevant work based on an interest.</p>
<p>Another great feature is the ability to simulate a conversation, which can make the portfolio feel more dynamic, engaging, and immersive while also demonstrating how good you are at working with modern tooling.</p>
<p>All of this combined provides you with a practical and approachable way to explore AI agents. This can be a real-world example and a personal project that does not require the implementation of a full-scale business application to see how valuable this type of concept can be.</p>
<p>The website will have the following six pages:</p>
<ul>
<li><p>Home – the main webpage</p>
</li>
<li><p>Projects – showcasing some featured projects and technical skills</p>
</li>
<li><p>Career – showing skills, experience, education, and certifications</p>
</li>
<li><p>Services – client services and the engagement process</p>
</li>
<li><p>Research – a way to search the web regarding the tech industry</p>
</li>
<li><p>Contact – a page with a form to contact the user</p>
</li>
</ul>
<p>You can see what your frontend React application will look like below:</p>
<p>First, you have your portfolio homepage:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977313487/4ac8fd65-4d3a-4da1-80b8-4b4ff5136e7e.png" alt="AI Portfolio Home Page" class="image--center mx-auto" width="2538" height="2668" loading="lazy"></p>
<p>Next is your Projects page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977426609/1c05544d-5255-40c2-85da-d072c8ecd6fc.png" alt="AI Portfolio Projects Page" class="image--center mx-auto" width="2492" height="2656" loading="lazy"></p>
<p>Now you have your Career page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977482985/ce61c17e-d948-49b5-83fa-7a77556796b5.png" alt="AI Portfolio Career Page" class="image--center mx-auto" width="2478" height="2664" loading="lazy"></p>
<p>Then you have the Services page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977517562/45614042-68b1-466a-9c43-b5f6aa5fde26.png" alt="AI Portfolio Services Page" class="image--center mx-auto" width="2488" height="2666" loading="lazy"></p>
<p>Then you can see your Research and Insights page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977558018/c2c083be-bd9a-4fac-9713-ff6c895d0cb0.png" alt="AI Portfolio Research &amp; Insights Page" class="image--center mx-auto" width="2512" height="2664" loading="lazy"></p>
<p>Lastly, you have your Contact page:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977630020/3c73726a-7de2-46af-a474-ce03fa3ace7b.png" alt="AI Contact Me Page" class="image--center mx-auto" width="2498" height="2654" loading="lazy"></p>
<p>Now, let's begin building your application, starting with the Python Backend.</p>
<h2 id="heading-building-our-python-backend">Building Our Python Backend</h2>
<p>For this tutorial I will be using macOS, and the commands should also work on Linux. If you’re a Windows user, most of the commands should work (although there are some differences like activating a Python environment). You can find the correct commands by searching if need be – and you’ll know if your terminal gives you errors when trying to run a command.</p>
<h3 id="heading-creating-an-account-on-groq-cloud">Creating An Account On Groq Cloud</h3>
<p>As mentioned earlier, we will use Meta’s LLaMA 3 via Groq Cloud, which is ideal. So, first, we have to create an account on <a target="_blank" href="https://console.groq.com/login">Groq Cloud</a>, as shown here.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977123301/80f8a1a6-de52-4a3d-870a-25c1067c13eb.png" alt="Creating an account on Groq Cloud" class="image--center mx-auto" width="2052" height="1350" loading="lazy"></p>
<p>Once you have created an account on Groq Cloud, go to the API Keys page and create an API Key as shown in this example. I gave mine the name <code>team-ai-agents</code>:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977205655/7c7dcc3e-685b-4383-b80a-4d8088be7d2d.png" alt="Creating a Groq Cloud API Key" class="image--center mx-auto" width="1498" height="321" loading="lazy"></p>
<p>You should have an API Key that looks like this example, so make sure that you save it somewhere safe – we will need it later.</p>
<pre><code class="lang-shell">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
</code></pre>
<h3 id="heading-setting-up-our-python-project">Setting Up Our Python Project</h3>
<p>Ok, now let's quickly set up our project. Navigate to a location on your computer, like the desktop, and create a folder called <code>ai-agent-app</code>. <code>cd</code> into the project folder and get ready – we’re going to start building our backend using Python.</p>
<p>I recommend installing <code>agno</code> and <code>groq</code> locally in a Python virtual environment. First, use this terminal command to setup a Python virtual environment inside of your <code>ai-agent-app</code> folder:</p>
<pre><code class="lang-shell">python3 -m venv venv
source venv/bin/activate
cd venv
</code></pre>
<p>Note: depending on your local Python environment, you might need to use either the <code>python</code> or <code>python3</code> command for running Python commands. In my environment and examples, I use <code>python3</code>, so adjust the command to suit your needs.</p>
<p>The same applies when using either <code>pip</code> or <code>pip3</code> when installing Python packages. You can check to see which version of Python and pip you have installed with the <code>python --version</code>, <code>python3 --version</code> , <code>pip --version</code> and <code>pip3 --version</code> commands in your terminal window.</p>
<p>The above command should create a <code>venv</code> folder inside of your <code>ai-agent-app</code> folder. This will be your REST backend with all of your API endpoints which your React frontend will use later on in this tutorial. Your Python virtual environment has also been activated.</p>
<p>To activate and deactivate your Python environment, you can use these commands:</p>
<pre><code class="lang-shell"># Activate on macOS/Linux
source venv/bin/activate

# Activate on Windows
venv\Scripts\activate

# Deactivate works on all platforms
conda deactivate
</code></pre>
<p>At this point, its a good idea to open the project in your code editor. Now you’ll need to install <code>agno</code> and <code>groq</code> using <code>pip</code> alongside a few other packages: <code>flask</code>, <code>requests</code>, and <code>python-dotenv</code>. You need these packages for setting up your server environment, so go ahead and install them all with this command:</p>
<pre><code class="lang-shell">pip install agno
pip install groq
pip install flask
pip install flask_cors
pip install requests
pip install python-dotenv
</code></pre>
<p>With these Python packages installed, you’re now ready to set up your API for this project. We’ll be using the Python web application framework Flask, along with the CORS package so that we can access the server anywhere. At the same time, we’ll also use the requests module, which allows us to send HTTP requests using Python.</p>
<p>Note that you’ll also need a <code>.env</code> file for your API keys, so make sure you have installed the <code>python-dotenv</code> package in your Python environment, although in some cases, it's installed automatically.</p>
<h3 id="heading-working-on-the-python-codebase">Working On The Python Codebase</h3>
<p>Alright, time to make a start on the codebase. But first, let's generate all of the files for your project. You can do this simply by running the run script I created for the project. Run this command in the <code>venv</code> folder:</p>
<pre><code class="lang-shell">mkdir agents
touch .env main.py
cd agents
touch __init__.py base_agent.py career_agent.py client_agent.py project_agent.py research_agent.py welcome_agent.py
</code></pre>
<p>With this script, you should now have:</p>
<ul>
<li><p>Created a <code>.env</code> file for your API Keys</p>
</li>
<li><p>Created an agents folder with all of the files for creating your different AI agents</p>
</li>
<li><p>Created a <code>main.py</code> file, which will be the main project file for your entire backend app</p>
</li>
</ul>
<p>Ok, your files are set. All that’s left is to add the codebase, and the backend is complete. Let's start with the <code>.env</code> file, as it only needs one line of code and that is for your API key. See my example and update it with your own API Key:</p>
<pre><code class="lang-shell">GROQ_API_KEY="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"
</code></pre>
<p>Your application now has an API key, which gives you access to Groq Cloud. Now let’s start to add the code for all the various AI agents. The first file we’ll work on will be the <code>__init__.py</code> which holds the imports for all of the AI agent files.</p>
<p>Add this code to the file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.welcome_agent <span class="hljs-keyword">import</span> WelcomeAgent
<span class="hljs-keyword">from</span> agents.project_agent <span class="hljs-keyword">import</span> ProjectAgent
<span class="hljs-keyword">from</span> agents.career_agent <span class="hljs-keyword">import</span> CareerAgent
<span class="hljs-keyword">from</span> agents.client_agent <span class="hljs-keyword">import</span> ClientAgent
<span class="hljs-keyword">from</span> agents.research_agent <span class="hljs-keyword">import</span> ResearchAgent

<span class="hljs-comment"># Export all agents</span>
__all__ = [<span class="hljs-string">'WelcomeAgent'</span>, <span class="hljs-string">'ProjectAgent'</span>, <span class="hljs-string">'CareerAgent'</span>, <span class="hljs-string">'ClientAgent'</span>, <span class="hljs-string">'ResearchAgent'</span>]
</code></pre>
<p>As you can see, all of the classes for the AI agents will be imported and exported from here so you can use them in your <code>main.py</code> file later.</p>
<p>Ok, good. Now, we have 6 AI agent files to work on, beginning with the <code>base_agent.py</code> file.</p>
<p>Make sure that you add this code to the file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agno.agent <span class="hljs-keyword">import</span> Agent
<span class="hljs-keyword">from</span> agno.models.groq <span class="hljs-keyword">import</span> Groq
<span class="hljs-keyword">import</span> os


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseAgent</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, description, avatar=<span class="hljs-string">"default_avatar.png"</span></span>):</span>

        self.name = name
        self.description = description
        self.avatar = avatar
        self.model = Groq(id=<span class="hljs-string">"llama-3.3-70b-versatile"</span>)
        self.agent = Agent(model=self.model, markdown=<span class="hljs-literal">True</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_response</span>(<span class="hljs-params">self, query, stream=False</span>):</span>

        <span class="hljs-keyword">return</span> self.agent.get_response(query, stream=stream)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">print_response</span>(<span class="hljs-params">self, query, stream=True</span>):</span>

        <span class="hljs-keyword">return</span> self.agent.print_response(query, stream=stream)
</code></pre>
<p>This class uses the <code>agno</code> framework to create AI agents powered by Groq's LLama 3.3 70B model, which is free to use with some usage restrictions for API calls. This should be fine for your project. It provides the basic structure that other specialised agents in the application can inherit from and extend with domain-specific functionality.</p>
<p>The model we chose is available on the Groq Cloud platform, and we can change it if we want to. Each model has pros and cons, and a cut-off date for how up-to-date it is, so you can expect to get different results. Just keep in mind that using an up to date LLM like OpenAI will provide better results, but you might have to pay for it.</p>
<p>The next file we will work on will be the <code>career_agent.py</code> file.</p>
<p>And this is this code required for it:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.base_agent <span class="hljs-keyword">import</span> BaseAgent


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CareerAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            name=<span class="hljs-string">"CareerGuide"</span>,
            description=<span class="hljs-string">"I'm the career specialist. I can provide information about skills, experience, and job suitability."</span>,
            avatar=<span class="hljs-string">"career_avatar.png"</span>
        )

        self.skills = {
            <span class="hljs-string">"languages"</span>: [<span class="hljs-string">"Python"</span>, <span class="hljs-string">"JavaScript"</span>, <span class="hljs-string">"TypeScript"</span>, <span class="hljs-string">"Java"</span>, <span class="hljs-string">"SQL"</span>],
            <span class="hljs-string">"frameworks"</span>: [<span class="hljs-string">"React"</span>, <span class="hljs-string">"Vue.js"</span>, <span class="hljs-string">"Node.js"</span>, <span class="hljs-string">"Django"</span>, <span class="hljs-string">"Flask"</span>, <span class="hljs-string">"Spring Boot"</span>],
            <span class="hljs-string">"tools"</span>: [<span class="hljs-string">"Git"</span>, <span class="hljs-string">"Docker"</span>, <span class="hljs-string">"AWS"</span>, <span class="hljs-string">"Azure"</span>, <span class="hljs-string">"CI/CD"</span>, <span class="hljs-string">"Kubernetes"</span>],
            <span class="hljs-string">"soft_skills"</span>: [<span class="hljs-string">"Team leadership"</span>, <span class="hljs-string">"Project management"</span>, <span class="hljs-string">"Agile methodologies"</span>, <span class="hljs-string">"Technical writing"</span>, <span class="hljs-string">"Client communication"</span>]
        }

        self.experience = [
            {
                <span class="hljs-string">"title"</span>: <span class="hljs-string">"Senior Full Stack Developer"</span>,
                <span class="hljs-string">"company"</span>: <span class="hljs-string">"Tech Innovations Inc."</span>,
                <span class="hljs-string">"period"</span>: <span class="hljs-string">"2020-Present"</span>,
                <span class="hljs-string">"responsibilities"</span>: [
                    <span class="hljs-string">"Led development of cloud-based SaaS platform"</span>,
                    <span class="hljs-string">"Managed team of 5 developers"</span>,
                    <span class="hljs-string">"Implemented CI/CD pipeline reducing deployment time by 40%"</span>,
                    <span class="hljs-string">"Architected microservices infrastructure"</span>
                ]
            },
            {
                <span class="hljs-string">"title"</span>: <span class="hljs-string">"Full Stack Developer"</span>,
                <span class="hljs-string">"company"</span>: <span class="hljs-string">"WebSolutions Co."</span>,
                <span class="hljs-string">"period"</span>: <span class="hljs-string">"2017-2020"</span>,
                <span class="hljs-string">"responsibilities"</span>: [
                    <span class="hljs-string">"Developed responsive web applications using React and Node.js"</span>,
                    <span class="hljs-string">"Implemented RESTful APIs and database schemas"</span>,
                    <span class="hljs-string">"Collaborated with UX/UI designers to implement user-friendly interfaces"</span>,
                    <span class="hljs-string">"Participated in code reviews and mentored junior developers"</span>
                ]
            },
            {
                <span class="hljs-string">"title"</span>: <span class="hljs-string">"Junior Developer"</span>,
                <span class="hljs-string">"company"</span>: <span class="hljs-string">"StartUp Labs"</span>,
                <span class="hljs-string">"period"</span>: <span class="hljs-string">"2015-2017"</span>,
                <span class="hljs-string">"responsibilities"</span>: [
                    <span class="hljs-string">"Built and maintained client websites"</span>,
                    <span class="hljs-string">"Developed custom WordPress plugins"</span>,
                    <span class="hljs-string">"Implemented responsive designs and cross-browser compatibility"</span>,
                    <span class="hljs-string">"Assisted in database design and optimization"</span>
                ]
            }
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_skills_summary</span>(<span class="hljs-params">self</span>):</span>

        prompt = <span class="hljs-string">f"""
        Generate a professional summary of the following skills for a portfolio website:

        Programming Languages: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(self.skills[<span class="hljs-string">'languages'</span>])}</span>
        Frameworks &amp; Libraries: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(self.skills[<span class="hljs-string">'frameworks'</span>])}</span>
        Tools &amp; Platforms: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(self.skills[<span class="hljs-string">'tools'</span>])}</span>
        Soft Skills: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(self.skills[<span class="hljs-string">'soft_skills'</span>])}</span>

        Format the response in markdown with appropriate sections and highlights.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_experience_summary</span>(<span class="hljs-params">self</span>):</span>

        experience_text = <span class="hljs-string">"# Work Experience\n\n"</span>
        <span class="hljs-keyword">for</span> job <span class="hljs-keyword">in</span> self.experience:
            experience_text += <span class="hljs-string">f"## <span class="hljs-subst">{job[<span class="hljs-string">'title'</span>]}</span> at <span class="hljs-subst">{job[<span class="hljs-string">'company'</span>]}</span>\n"</span>
            experience_text += <span class="hljs-string">f"**<span class="hljs-subst">{job[<span class="hljs-string">'period'</span>]}</span>**\n\n"</span>
            experience_text += <span class="hljs-string">"**Responsibilities:**\n"</span>
            <span class="hljs-keyword">for</span> resp <span class="hljs-keyword">in</span> job[<span class="hljs-string">'responsibilities'</span>]:
                experience_text += <span class="hljs-string">f"- <span class="hljs-subst">{resp}</span>\n"</span>
            experience_text += <span class="hljs-string">"\n"</span>

        prompt = <span class="hljs-string">f"""
        Based on the following work experience, generate a professional career summary for a portfolio website:

        <span class="hljs-subst">{experience_text}</span>

        Highlight career progression, key achievements, and growth. Format the response in markdown.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">assess_job_fit</span>(<span class="hljs-params">self, job_description</span>):</span>

        skills_flat = []
        <span class="hljs-keyword">for</span> skill_category <span class="hljs-keyword">in</span> self.skills.values():
            skills_flat.extend(skill_category)

        experience_flat = []
        <span class="hljs-keyword">for</span> job <span class="hljs-keyword">in</span> self.experience:
            experience_flat.extend(job[<span class="hljs-string">'responsibilities'</span>])

        prompt = <span class="hljs-string">f"""
        Assess the fit for the following job description based on the skills and experience provided:

        Job Description:
        <span class="hljs-subst">{job_description}</span>

        Skills:
        <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(skills_flat)}</span>

        Experience:
        <span class="hljs-subst">{<span class="hljs-string">' '</span>.join(experience_flat)}</span>

        Provide an analysis of strengths, potential gaps, and overall suitability for the role. Format the response in markdown.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)
</code></pre>
<p>This agent is designed to help users with career-related tasks such as:</p>
<ul>
<li><p>Creating professional summaries of technical and soft skills</p>
</li>
<li><p>Generating career narratives based on work experience</p>
</li>
<li><p>Evaluating job fit by comparing skills and experience against job descriptions</p>
</li>
</ul>
<p>The agent uses the LLM capabilities of the base agent (using Groq's LLama 3.3 70B model) to generate natural language responses that are formatted in markdown, making them suitable for inclusion in portfolio websites, résumés, or job applications. This file has sample career data, and in a real implementation, this would come from a database</p>
<p>Ok time for the next AI agent – this time it’s <code>client_agent.py</code>, which receives this code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.base_agent <span class="hljs-keyword">import</span> BaseAgent


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClientAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            name=<span class="hljs-string">"BusinessAdvisor"</span>,
            description=<span class="hljs-string">"I'm the client specialist. I can provide information about services, pricing, and project details."</span>,
            avatar=<span class="hljs-string">"client_avatar.png"</span>
        )

        self.services = {
            <span class="hljs-string">"web_development"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Web Development"</span>,
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"Custom web application development using modern frameworks and best practices."</span>,
                <span class="hljs-string">"pricing_model"</span>: <span class="hljs-string">"Project-based or hourly"</span>,
                <span class="hljs-string">"price_range"</span>: <span class="hljs-string">"$5,000 - $50,000 depending on complexity"</span>,
                <span class="hljs-string">"timeline"</span>: <span class="hljs-string">"4-12 weeks depending on scope"</span>,
                <span class="hljs-string">"technologies"</span>: [<span class="hljs-string">"React"</span>, <span class="hljs-string">"Vue.js"</span>, <span class="hljs-string">"Node.js"</span>, <span class="hljs-string">"Django"</span>, <span class="hljs-string">"Flask"</span>]
            },
            <span class="hljs-string">"mobile_development"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Mobile App Development"</span>,
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"Native and cross-platform mobile application development for iOS and Android."</span>,
                <span class="hljs-string">"pricing_model"</span>: <span class="hljs-string">"Project-based"</span>,
                <span class="hljs-string">"price_range"</span>: <span class="hljs-string">"$8,000 - $60,000 depending on complexity"</span>,
                <span class="hljs-string">"timeline"</span>: <span class="hljs-string">"6-16 weeks depending on scope"</span>,
                <span class="hljs-string">"technologies"</span>: [<span class="hljs-string">"React Native"</span>, <span class="hljs-string">"Flutter"</span>, <span class="hljs-string">"Swift"</span>, <span class="hljs-string">"Kotlin"</span>]
            },
            <span class="hljs-string">"consulting"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Technical Consulting"</span>,
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"Expert advice on architecture, technology stack, and development practices."</span>,
                <span class="hljs-string">"pricing_model"</span>: <span class="hljs-string">"Hourly"</span>,
                <span class="hljs-string">"price_range"</span>: <span class="hljs-string">"$150 - $250 per hour"</span>,
                <span class="hljs-string">"timeline"</span>: <span class="hljs-string">"Ongoing or as needed"</span>,
                <span class="hljs-string">"technologies"</span>: [<span class="hljs-string">"Various based on client needs"</span>]
            }
        }

        self.process = [
            <span class="hljs-string">"Initial consultation to understand requirements"</span>,
            <span class="hljs-string">"Proposal and quote preparation"</span>,
            <span class="hljs-string">"Contract signing and project kickoff"</span>,
            <span class="hljs-string">"Design and prototyping phase"</span>,
            <span class="hljs-string">"Development sprints with regular client feedback"</span>,
            <span class="hljs-string">"Testing and quality assurance"</span>,
            <span class="hljs-string">"Deployment and launch"</span>,
            <span class="hljs-string">"Post-launch support and maintenance"</span>
        ]

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_services_overview</span>(<span class="hljs-params">self</span>):</span>

        services_text = <span class="hljs-string">"# Services Offered\n\n"</span>
        <span class="hljs-keyword">for</span> service_id, service <span class="hljs-keyword">in</span> self.services.items():
            services_text += <span class="hljs-string">f"## <span class="hljs-subst">{service[<span class="hljs-string">'name'</span>]}</span>\n"</span>
            services_text += <span class="hljs-string">f"<span class="hljs-subst">{service[<span class="hljs-string">'description'</span>]}</span>\n\n"</span>
            services_text += <span class="hljs-string">f"**Pricing Model**: <span class="hljs-subst">{service[<span class="hljs-string">'pricing_model'</span>]}</span>\n"</span>
            services_text += <span class="hljs-string">f"**Price Range**: <span class="hljs-subst">{service[<span class="hljs-string">'price_range'</span>]}</span>\n"</span>
            services_text += <span class="hljs-string">f"**Timeline**: <span class="hljs-subst">{service[<span class="hljs-string">'timeline'</span>]}</span>\n"</span>
            services_text += <span class="hljs-string">f"**Technologies**: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(service[<span class="hljs-string">'technologies'</span>])}</span>\n\n"</span>

        prompt = <span class="hljs-string">f"""
        Generate a professional overview of the following services for a programmer's portfolio website:

        <span class="hljs-subst">{services_text}</span>

        Format the response in markdown with appropriate sections and highlights.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_service_details</span>(<span class="hljs-params">self, service_id</span>):</span>

        <span class="hljs-keyword">if</span> service_id <span class="hljs-keyword">in</span> self.services:
            service = self.services[service_id]
            prompt = <span class="hljs-string">f"""
            Generate a detailed description for the following service:

            Service Name: <span class="hljs-subst">{service[<span class="hljs-string">'name'</span>]}</span>
            Description: <span class="hljs-subst">{service[<span class="hljs-string">'description'</span>]}</span>
            Pricing Model: <span class="hljs-subst">{service[<span class="hljs-string">'pricing_model'</span>]}</span>
            Price Range: <span class="hljs-subst">{service[<span class="hljs-string">'price_range'</span>]}</span>
            Timeline: <span class="hljs-subst">{service[<span class="hljs-string">'timeline'</span>]}</span>
            Technologies: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(service[<span class="hljs-string">'technologies'</span>])}</span>

            Include information about the value proposition, typical deliverables, and client benefits. Format the response in markdown.
            """</span>
            <span class="hljs-keyword">return</span> self.get_response(prompt)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Service not found. Please check the service ID and try again."</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">explain_process</span>(<span class="hljs-params">self</span>):</span>

        process_text = <span class="hljs-string">"# Client Engagement Process\n\n"</span>
        <span class="hljs-keyword">for</span> i, step <span class="hljs-keyword">in</span> enumerate(self.process, <span class="hljs-number">1</span>):
            process_text += <span class="hljs-string">f"## Step <span class="hljs-subst">{i}</span>: <span class="hljs-subst">{step}</span>\n\n"</span>

        prompt = <span class="hljs-string">f"""
        Based on the following client engagement process, generate a detailed explanation for potential clients:

        <span class="hljs-subst">{process_text}</span>

        For each step, provide a brief explanation of what happens, what the client can expect, and any deliverables. Format the response in markdown.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_proposal</span>(<span class="hljs-params">self, project_description</span>):</span>

        prompt = <span class="hljs-string">f"""
        Generate a professional project proposal based on the following client requirements:

        Project Description:
        <span class="hljs-subst">{project_description}</span>

        Include the following sections:
        1. Project Understanding
        2. Proposed Approach
        3. Estimated Timeline
        4. Estimated Budget Range
        5. Next Steps

        Base your proposal on the services and processes described in the portfolio. Format the response in markdown.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)
</code></pre>
<p>This agent is designed to help users with client and business-related tasks such as:</p>
<ul>
<li><p>Providing overviews of available services for marketing materials</p>
</li>
<li><p>Generating detailed service descriptions for specific offerings</p>
</li>
<li><p>Explaining the client engagement process to potential clients</p>
</li>
<li><p>Creating customised project proposals based on client requirements</p>
</li>
</ul>
<p>The agent also uses the LLM capabilities of the base agent (using Groq's LLama 3.3 70B model) to generate professional, business-oriented content formatted in markdown. Like before, this file also has sample service data.</p>
<p>Now we can start to work on the <code>project_agent.py</code> file and add this code to its codebase:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.base_agent <span class="hljs-keyword">import</span> BaseAgent


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProjectAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            name=<span class="hljs-string">"TechExpert"</span>,
            description=<span class="hljs-string">"I'm the project specialist. I can provide detailed information about any project in this portfolio."</span>,
            avatar=<span class="hljs-string">"project_avatar.png"</span>
        )

        self.projects = {
            <span class="hljs-string">"project1"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"E-commerce Platform"</span>,
                <span class="hljs-string">"tech_stack"</span>: [<span class="hljs-string">"React"</span>, <span class="hljs-string">"Node.js"</span>, <span class="hljs-string">"MongoDB"</span>, <span class="hljs-string">"Express"</span>],
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"A full-stack e-commerce platform with user authentication, product catalog, shopping cart, and payment processing."</span>,
                <span class="hljs-string">"highlights"</span>: [<span class="hljs-string">"Responsive design"</span>, <span class="hljs-string">"RESTful API"</span>, <span class="hljs-string">"Stripe integration"</span>, <span class="hljs-string">"JWT authentication"</span>],
                <span class="hljs-string">"github_link"</span>: <span class="hljs-string">"https://github.com/username/ecommerce-platform"</span>,
                <span class="hljs-string">"demo_link"</span>: <span class="hljs-string">"https://ecommerce-demo.example.com"</span>
            },
            <span class="hljs-string">"project2"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Task Management App"</span>,
                <span class="hljs-string">"tech_stack"</span>: [<span class="hljs-string">"Vue.js"</span>, <span class="hljs-string">"Firebase"</span>, <span class="hljs-string">"Tailwind CSS"</span>],
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"A real-time task management application with collaborative features, notifications, and progress tracking."</span>,
                <span class="hljs-string">"highlights"</span>: [<span class="hljs-string">"Real-time updates"</span>, <span class="hljs-string">"User collaboration"</span>, <span class="hljs-string">"Drag-and-drop interface"</span>, <span class="hljs-string">"Progressive Web App"</span>],
                <span class="hljs-string">"github_link"</span>: <span class="hljs-string">"https://github.com/username/task-manager"</span>,
                <span class="hljs-string">"demo_link"</span>: <span class="hljs-string">"https://taskmanager-demo.example.com"</span>
            },
            <span class="hljs-string">"project3"</span>: {
                <span class="hljs-string">"name"</span>: <span class="hljs-string">"Data Visualization Dashboard"</span>,
                <span class="hljs-string">"tech_stack"</span>: [<span class="hljs-string">"Python"</span>, <span class="hljs-string">"Django"</span>, <span class="hljs-string">"D3.js"</span>, <span class="hljs-string">"PostgreSQL"</span>],
                <span class="hljs-string">"description"</span>: <span class="hljs-string">"An interactive dashboard for visualizing complex datasets with filtering, sorting, and export capabilities."</span>,
                <span class="hljs-string">"highlights"</span>: [<span class="hljs-string">"Interactive charts"</span>, <span class="hljs-string">"Data filtering"</span>, <span class="hljs-string">"CSV/PDF export"</span>, <span class="hljs-string">"Responsive design"</span>],
                <span class="hljs-string">"github_link"</span>: <span class="hljs-string">"https://github.com/username/data-dashboard"</span>,
                <span class="hljs-string">"demo_link"</span>: <span class="hljs-string">"https://dataviz-demo.example.com"</span>
            }
        }

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_project_list</span>(<span class="hljs-params">self</span>):</span>

        project_list = <span class="hljs-string">"# Available Projects\n\n"</span>
        <span class="hljs-keyword">for</span> project_id, project <span class="hljs-keyword">in</span> self.projects.items():
            project_list += <span class="hljs-string">f"## <span class="hljs-subst">{project[<span class="hljs-string">'name'</span>]}</span>\n"</span>
            project_list += <span class="hljs-string">f"**Tech Stack**: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(project[<span class="hljs-string">'tech_stack'</span>])}</span>\n"</span>
            project_list += <span class="hljs-string">f"<span class="hljs-subst">{project[<span class="hljs-string">'description'</span>]}</span>\n\n"</span>

        <span class="hljs-keyword">return</span> project_list

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_project_details</span>(<span class="hljs-params">self, project_id</span>):</span>

        <span class="hljs-keyword">if</span> project_id <span class="hljs-keyword">in</span> self.projects:
            project = self.projects[project_id]
            prompt = <span class="hljs-string">f"""
            Generate a detailed description for the following project:

            Project Name: <span class="hljs-subst">{project[<span class="hljs-string">'name'</span>]}</span>
            Tech Stack: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(project[<span class="hljs-string">'tech_stack'</span>])}</span>
            Description: <span class="hljs-subst">{project[<span class="hljs-string">'description'</span>]}</span>
            Highlights: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(project[<span class="hljs-string">'highlights'</span>])}</span>
            GitHub: <span class="hljs-subst">{project[<span class="hljs-string">'github_link'</span>]}</span>
            Demo: <span class="hljs-subst">{project[<span class="hljs-string">'demo_link'</span>]}</span>

            Include technical details about implementation challenges and solutions. Format the response in markdown.
            """</span>
            <span class="hljs-keyword">return</span> self.get_response(prompt)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Project not found. Please check the project ID and try again."</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">answer_technical_question</span>(<span class="hljs-params">self, project_id, question</span>):</span>

        <span class="hljs-keyword">if</span> project_id <span class="hljs-keyword">in</span> self.projects:
            project = self.projects[project_id]
            prompt = <span class="hljs-string">f"""
            Answer the following technical question about this project:

            Project Name: <span class="hljs-subst">{project[<span class="hljs-string">'name'</span>]}</span>
            Tech Stack: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(project[<span class="hljs-string">'tech_stack'</span>])}</span>
            Description: <span class="hljs-subst">{project[<span class="hljs-string">'description'</span>]}</span>
            Highlights: <span class="hljs-subst">{<span class="hljs-string">', '</span>.join(project[<span class="hljs-string">'highlights'</span>])}</span>

            Question: <span class="hljs-subst">{question}</span>

            Provide a detailed technical answer with code examples if relevant.
            """</span>
            <span class="hljs-keyword">return</span> self.get_response(prompt)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> <span class="hljs-string">"Project not found. Please check the project ID and try again."</span>
</code></pre>
<p>This agent is designed to help users with project-related tasks such as:</p>
<ul>
<li><p>Providing an overview of all projects in a portfolio</p>
</li>
<li><p>Generating detailed descriptions of specific projects</p>
</li>
<li><p>Answering technical questions about implementation details</p>
</li>
</ul>
<p>The agent, like in the previous examples, uses the LLM capabilities of the base agent (using Groq's LLama 3.3 70B model) to generate technical, project-oriented content formatted in markdown. This is good for technical documentation, or when responding to inquiries about project implementations. We’re using mock data here as opposed to a database.</p>
<p>With that file completed, we have two left. The next is the <code>research_agent.py</code> file, so go ahead and add this code:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.base_agent <span class="hljs-keyword">import</span> BaseAgent
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">import</span> json


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ResearchAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            name=<span class="hljs-string">"ResearchAssistant"</span>,
            description=<span class="hljs-string">"I'm the research specialist. I can search the web for information about technologies, trends, and industry news."</span>,
            avatar=<span class="hljs-string">"research_avatar.png"</span>
        )
        self.api_key = os.getenv(<span class="hljs-string">"GROQ_API_KEY"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search_web</span>(<span class="hljs-params">self, query</span>):</span>

        headers = {
            <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">f"Bearer <span class="hljs-subst">{self.api_key}</span>"</span>,
            <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>
        }

        payload = {
            <span class="hljs-string">"model"</span>: <span class="hljs-string">"llama-3.3-70b-versatile"</span>,
            <span class="hljs-string">"messages"</span>: [
                {<span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">"You are a helpful research assistant."</span>},
                {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">f"Search the web for: <span class="hljs-subst">{query}</span>"</span>}
            ],
            <span class="hljs-string">"tools"</span>: [
                {
                    <span class="hljs-string">"type"</span>: <span class="hljs-string">"web_search"</span>
                }
            ]
        }

        <span class="hljs-keyword">try</span>:
            response = requests.post(
                <span class="hljs-string">"https://api.groq.com/openai/v1/chat/completions"</span>,
                headers=headers,
                json=payload
            )

            <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:
                result = response.json()
                <span class="hljs-keyword">return</span> result[<span class="hljs-string">"choices"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"message"</span>][<span class="hljs-string">"content"</span>]
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-string">f"Error searching the web: <span class="hljs-subst">{response.status_code}</span> - <span class="hljs-subst">{response.text}</span>"</span>
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            <span class="hljs-keyword">return</span> <span class="hljs-string">f"Error searching the web: <span class="hljs-subst">{str(e)}</span>"</span>

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">research_technology</span>(<span class="hljs-params">self, technology</span>):</span>

        query = <span class="hljs-string">f"latest developments and best practices for <span class="hljs-subst">{technology}</span> in software development"</span>
        search_results = self.search_web(query)

        prompt = <span class="hljs-string">f"""
        Based on the following search results about <span class="hljs-subst">{technology}</span>, provide a concise summary of:
        1. What it is
        2. Current state and popularity
        3. Key features and benefits
        4. Common use cases
        5. Future trends

        Search Results:
        <span class="hljs-subst">{search_results}</span>

        Format the response in markdown with appropriate sections.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compare_technologies</span>(<span class="hljs-params">self, tech1, tech2</span>):</span>

        query = <span class="hljs-string">f"comparison between <span class="hljs-subst">{tech1}</span> and <span class="hljs-subst">{tech2}</span> for software development"</span>
        search_results = self.search_web(query)

        prompt = <span class="hljs-string">f"""
        Based on the following search results comparing <span class="hljs-subst">{tech1}</span> and <span class="hljs-subst">{tech2}</span>, provide a detailed comparison including:
        6. Core differences
        7. Performance considerations
        8. Learning curve
        9. Community support
        10. Use case recommendations

        Search Results:
        <span class="hljs-subst">{search_results}</span>

        Format the response in markdown with a comparison table and explanatory text.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_industry_trends</span>(<span class="hljs-params">self</span>):</span>

        query = <span class="hljs-string">"latest trends in software development industry"</span>
        search_results = self.search_web(query)

        prompt = <span class="hljs-string">f"""
        Based on the following search results about software development trends, provide a summary of:
        11. Emerging technologies
        12. Industry shifts
        13. In-demand skills
        14. Future predictions

        Search Results:
        <span class="hljs-subst">{search_results}</span>

        Format the response in markdown with appropriate sections and highlights.
        """</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)
</code></pre>
<p>This agent is designed to help users with research-related tasks such as:</p>
<ul>
<li><p>Researching specific technologies to understand their features, benefits, and use cases</p>
</li>
<li><p>Comparing different technologies to make informed decisions</p>
</li>
<li><p>Staying updated on industry trends and emerging technologies</p>
</li>
</ul>
<p>What makes this agent unique compared to the other agents is that it actively fetches real-time information from the web using the Groq Toolhouse API's web search capability instead of relying solely on pre-defined data or the LLM's training data. This allows it to provide more current and comprehensive information about rapidly evolving technology topics.</p>
<p>Ok, now we have one last AI agent to create and it’s the <code>welcome_agent.py</code> file. Add this code to the file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> agents.base_agent <span class="hljs-keyword">import</span> BaseAgent


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WelcomeAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            name=<span class="hljs-string">"Greeter"</span>,
            description=<span class="hljs-string">"I'm the welcome agent for this portfolio. I can help guide you to the right section based on your interests."</span>,
            avatar=<span class="hljs-string">"welcome_avatar.png"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">self, visitor_type=None</span>):</span>

        <span class="hljs-keyword">if</span> visitor_type == <span class="hljs-string">"employer"</span>:
            <span class="hljs-keyword">return</span> self.get_response(
                <span class="hljs-string">"Generate a friendly, professional greeting for a potential employer visiting a programmer's portfolio website. "</span>
                <span class="hljs-string">"Mention that they can explore the Projects section to see technical skills and the Career section for professional experience."</span>
            )
        <span class="hljs-keyword">elif</span> visitor_type == <span class="hljs-string">"client"</span>:
            <span class="hljs-keyword">return</span> self.get_response(
                <span class="hljs-string">"Generate a friendly, business-oriented greeting for a potential client visiting a programmer's portfolio website. "</span>
                <span class="hljs-string">"Mention that they can check out the Projects section for examples of past work and the Client section for service details."</span>
            )
        <span class="hljs-keyword">elif</span> visitor_type == <span class="hljs-string">"fellow_programmer"</span>:
            <span class="hljs-keyword">return</span> self.get_response(
                <span class="hljs-string">"Generate a friendly, casual greeting for a fellow programmer visiting a portfolio website. "</span>
                <span class="hljs-string">"Mention that they can explore the Projects section for technical details and code samples."</span>
            )
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> self.get_response(
                <span class="hljs-string">"Generate a friendly, general greeting for a visitor to a programmer's portfolio website. "</span>
                <span class="hljs-string">"Ask if they are an employer, client, or fellow programmer to provide more tailored information."</span>
            )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">suggest_section</span>(<span class="hljs-params">self, interest</span>):</span>

        prompt = <span class="hljs-string">f"Based on a visitor expressing interest in '<span class="hljs-subst">{interest}</span>', suggest which section of a programmer's portfolio they should visit. Options include: Projects, Career, Client Work, About Me, Contact. Explain why in 1-2 sentences."</span>
        <span class="hljs-keyword">return</span> self.get_response(prompt)
</code></pre>
<p>This agent is designed to serve as the initial point of contact for visitors to a portfolio website, providing:</p>
<ul>
<li><p>Personalised greetings based on visitor type</p>
</li>
<li><p>Guidance to relevant sections based on specific interests</p>
</li>
<li><p>A friendly, conversational introduction to the portfolio</p>
</li>
</ul>
<p>The <code>WelcomeAgent</code> is simpler than some of the other agents we've looked at because it focuses on creating a positive first impression and helping visitors navigate to the content most relevant to their needs. It uses the LLM capabilities of the base agent to generate natural, contextually appropriate responses.</p>
<p>Ok good – your backend API is almost ready. You just have one last file to work on: the <code>main.py</code> file that completes your codebase. This file is quite big, so I will split it into three parts. You’ll need to copy and paste each section into the file. If you have not done so already, its worth installing the <a target="_blank" href="https://open-vsx.org/extension/ms-python/python">Python</a> extension for VS Code as this has debugging, linting, and formatting for Python files.</p>
<p>Alright, here is the first part of the codebase for our <code>main.py</code> file:</p>
<pre><code class="lang-python"><span class="hljs-keyword">from</span> flask <span class="hljs-keyword">import</span> Flask, request, jsonify
<span class="hljs-keyword">import</span> os
<span class="hljs-keyword">from</span> dotenv <span class="hljs-keyword">import</span> load_dotenv
<span class="hljs-keyword">import</span> json
<span class="hljs-keyword">import</span> requests
<span class="hljs-keyword">from</span> flask_cors <span class="hljs-keyword">import</span> CORS


load_dotenv()


app = Flask(__name__)
CORS(app)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BaseAgent</span>:</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, name, description</span>):</span>
        self.name = name
        self.description = description

        self.api_key = os.getenv(<span class="hljs-string">"GROQ_API_KEY"</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_response</span>(<span class="hljs-params">self, prompt</span>):</span>

        <span class="hljs-keyword">try</span>:
            headers = {
                <span class="hljs-string">"Authorization"</span>: <span class="hljs-string">f"Bearer <span class="hljs-subst">{self.api_key}</span>"</span>,
                <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>
            }

            data = {
                <span class="hljs-string">"model"</span>: <span class="hljs-string">"llama3-8b-8192"</span>,
                <span class="hljs-string">"messages"</span>: [
                    {<span class="hljs-string">"role"</span>: <span class="hljs-string">"system"</span>, <span class="hljs-string">"content"</span>: <span class="hljs-string">f"You are <span class="hljs-subst">{self.name}</span>, <span class="hljs-subst">{self.description}</span>. Respond in a helpful, concise, and professional manner."</span>},
                    {<span class="hljs-string">"role"</span>: <span class="hljs-string">"user"</span>, <span class="hljs-string">"content"</span>: prompt}
                ],
                <span class="hljs-string">"temperature"</span>: <span class="hljs-number">0.7</span>,
                <span class="hljs-string">"max_tokens"</span>: <span class="hljs-number">500</span>
            }

            response = requests.post(
                <span class="hljs-string">"https://api.groq.com/openai/v1/chat/completions"</span>,
                headers=headers,
                json=data
            )

            <span class="hljs-keyword">if</span> response.status_code == <span class="hljs-number">200</span>:
                <span class="hljs-keyword">return</span> response.json()[<span class="hljs-string">"choices"</span>][<span class="hljs-number">0</span>][<span class="hljs-string">"message"</span>][<span class="hljs-string">"content"</span>]
            <span class="hljs-keyword">else</span>:
                <span class="hljs-keyword">return</span> <span class="hljs-string">f"Error: <span class="hljs-subst">{response.status_code}</span> - <span class="hljs-subst">{response.text}</span>"</span>
        <span class="hljs-keyword">except</span> Exception <span class="hljs-keyword">as</span> e:
            <span class="hljs-keyword">return</span> <span class="hljs-string">f"An error occurred: <span class="hljs-subst">{str(e)}</span>"</span>


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">WelcomeAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            <span class="hljs-string">"WelcomeAgent"</span>,
            <span class="hljs-string">"a welcome specialist who greets visitors and helps them navigate the portfolio website"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">greet</span>(<span class="hljs-params">self, visitor_type=None</span>):</span>
        <span class="hljs-keyword">if</span> visitor_type == <span class="hljs-string">"employer"</span>:
            <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a warm welcome message for an employer visiting a programmer's portfolio website. Suggest they check out the Projects and Career sections."</span>)
        <span class="hljs-keyword">elif</span> visitor_type == <span class="hljs-string">"client"</span>:
            <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a warm welcome message for a potential client visiting a programmer's portfolio website. Suggest they check out the Services section."</span>)
        <span class="hljs-keyword">elif</span> visitor_type == <span class="hljs-string">"fellow_programmer"</span>:
            <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a warm welcome message for a fellow programmer visiting a programmer's portfolio website. Suggest they check out the Projects and Research sections."</span>)
        <span class="hljs-keyword">else</span>:
            <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a general welcome message for a visitor to a programmer's portfolio website. Ask if they are an employer, client, or fellow programmer."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">suggest_section</span>(<span class="hljs-params">self, interest</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"A visitor to my portfolio website has expressed interest in <span class="hljs-subst">{interest}</span>. Suggest which section(s) of the website they should visit based on this interest."</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProjectAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            <span class="hljs-string">"ProjectAgent"</span>,
            <span class="hljs-string">"a project specialist who provides detailed information about the programmer's projects"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_project_list</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a list of 3-5 impressive software development projects that could be in a programmer's portfolio. Include a brief description for each."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_project_details</span>(<span class="hljs-params">self, project_id</span>):</span>
        project_prompts = {
            <span class="hljs-string">"project1"</span>: <span class="hljs-string">"Describe in detail an e-commerce platform project for a programmer's portfolio. Include technologies used, challenges overcome, and key features."</span>,
            <span class="hljs-string">"project2"</span>: <span class="hljs-string">"Describe in detail a task management application project for a programmer's portfolio. Include technologies used, challenges overcome, and key features."</span>,
            <span class="hljs-string">"project3"</span>: <span class="hljs-string">"Describe in detail a data visualization dashboard project for a programmer's portfolio. Include technologies used, challenges overcome, and key features."</span>
        }

        prompt = project_prompts.get(
            project_id, <span class="hljs-string">f"Describe a project called <span class="hljs-subst">{project_id}</span> in detail."</span>)
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">answer_technical_question</span>(<span class="hljs-params">self, project_id, question</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"Answer this technical question about a project: '<span class="hljs-subst">{question}</span>'. The project is <span class="hljs-subst">{project_id}</span>."</span>)
</code></pre>
<p>This part of the code has your imports, set up, and some greetings for the AI agent.</p>
<p>Now for part two, add this code to the file underneath the first code you added:</p>
<pre><code class="lang-python">
<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CareerAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            <span class="hljs-string">"CareerAgent"</span>,
            <span class="hljs-string">"a career specialist who provides information about the programmer's skills and experience"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_skills_summary</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a comprehensive summary of technical and professional skills for a full-stack developer's portfolio."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_experience_summary</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate a summary of work experience for a full-stack developer with 5+ years of experience."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">assess_job_fit</span>(<span class="hljs-params">self, job_description</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"Assess how well a full-stack developer with 5+ years of experience would fit this job description: '<span class="hljs-subst">{job_description}</span>'. Highlight matching skills and experience."</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ClientAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            <span class="hljs-string">"ClientAgent"</span>,
            <span class="hljs-string">"a client specialist who provides information about services, pricing, and the client engagement process"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_services_overview</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Generate an overview of services that a freelance full-stack developer might offer to clients."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_service_details</span>(<span class="hljs-params">self, service_type</span>):</span>
        service_prompts = {
            <span class="hljs-string">"web_development"</span>: <span class="hljs-string">"Describe web development services offered by a freelance full-stack developer, including technologies, pricing range, and typical timeline."</span>,
            <span class="hljs-string">"mobile_development"</span>: <span class="hljs-string">"Describe mobile app development services offered by a freelance full-stack developer, including technologies, pricing range, and typical timeline."</span>,
            <span class="hljs-string">"consulting"</span>: <span class="hljs-string">"Describe technical consulting services offered by a freelance full-stack developer, including areas of expertise, hourly rate range, and engagement model."</span>
        }

        prompt = service_prompts.get(
            service_type, <span class="hljs-string">f"Describe <span class="hljs-subst">{service_type}</span> services in detail."</span>)
        <span class="hljs-keyword">return</span> self.get_response(prompt)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">explain_process</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Explain the client engagement process for a freelance full-stack developer, from initial consultation to project delivery."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">generate_proposal</span>(<span class="hljs-params">self, project_description</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"Generate a project proposal for this client request: '<span class="hljs-subst">{project_description}</span>'. Include estimated timeline, cost range, and approach."</span>)


<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ResearchAgent</span>(<span class="hljs-params">BaseAgent</span>):</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self</span>):</span>
        super().__init__(
            <span class="hljs-string">"ResearchAgent"</span>,
            <span class="hljs-string">"a research specialist who provides information about technologies, trends, and industry news"</span>
        )

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">search_web</span>(<span class="hljs-params">self, query</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"Provide information about '<span class="hljs-subst">{query}</span>' as if you've just searched the web for the latest information. Include key points and insights."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compare_technologies</span>(<span class="hljs-params">self, tech1, tech2</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">f"Compare <span class="hljs-subst">{tech1}</span> vs <span class="hljs-subst">{tech2}</span> in terms of features, performance, use cases, community support, and future prospects."</span>)

    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">get_industry_trends</span>(<span class="hljs-params">self</span>):</span>
        <span class="hljs-keyword">return</span> self.get_response(<span class="hljs-string">"Describe current trends in software development and technology that are important for developers to be aware of."</span>)


welcome_agent = WelcomeAgent()
project_agent = ProjectAgent()
career_agent = CareerAgent()
client_agent = ClientAgent()
research_agent = ResearchAgent()


<span class="hljs-meta">@app.route('/static/images/default_avatar.png')</span>
<span class="hljs-meta">@app.route('/static/images/default_project.jpg')</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">block_default_images</span>():</span>

    response = app.make_response(
        <span class="hljs-string">b'GIF89a\x01\x00\x01\x00\x80\x00\x00\xff\xff\xff\x00\x00\x00!\xf9\x04\x01\x00\x00\x00\x00,\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;'</span>)
    response.headers[<span class="hljs-string">'Content-Type'</span>] = <span class="hljs-string">'image/gif'</span>

    response.headers[<span class="hljs-string">'Cache-Control'</span>] = <span class="hljs-string">'public, max-age=31536000'</span>
    response.headers[<span class="hljs-string">'Expires'</span>] = <span class="hljs-string">'Thu, 31 Dec 2037 23:59:59 GMT'</span>
    <span class="hljs-keyword">return</span> response


<span class="hljs-meta">@app.route('/api/welcome', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">welcome_agent_endpoint</span>():</span>
    data = request.json
    message = data.get(<span class="hljs-string">'message'</span>, <span class="hljs-string">''</span>)

    visitor_type = <span class="hljs-literal">None</span>
    <span class="hljs-keyword">if</span> <span class="hljs-string">'employer'</span> <span class="hljs-keyword">in</span> message.lower():
        visitor_type = <span class="hljs-string">'employer'</span>
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'client'</span> <span class="hljs-keyword">in</span> message.lower():
        visitor_type = <span class="hljs-string">'client'</span>
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'programmer'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'developer'</span> <span class="hljs-keyword">in</span> message.lower():
        visitor_type = <span class="hljs-string">'fellow_programmer'</span>

    <span class="hljs-keyword">if</span> <span class="hljs-string">'interest'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'looking for'</span> <span class="hljs-keyword">in</span> message.lower():

        interest = message.replace(<span class="hljs-string">'interest'</span>, <span class="hljs-string">''</span>).replace(
            <span class="hljs-string">'looking for'</span>, <span class="hljs-string">''</span>).strip()
        response = welcome_agent.suggest_section(interest)
    <span class="hljs-keyword">else</span>:
        response = welcome_agent.greet(visitor_type)

    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'response'</span>: response})
</code></pre>
<p>In this part of your codebase, you have more AI responses and a welcome API route.</p>
<p>Lastly, complete the code by adding this final piece at the end:</p>
<pre><code class="lang-python">
<span class="hljs-meta">@app.route('/api/project', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">project_agent_endpoint</span>():</span>
    data = request.json
    message = data.get(<span class="hljs-string">'message'</span>, <span class="hljs-string">''</span>)

    project_id = <span class="hljs-literal">None</span>
    <span class="hljs-keyword">if</span> <span class="hljs-string">'e-commerce'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'ecommerce'</span> <span class="hljs-keyword">in</span> message.lower():
        project_id = <span class="hljs-string">'project1'</span>
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'task'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'management'</span> <span class="hljs-keyword">in</span> message.lower():
        project_id = <span class="hljs-string">'project2'</span>
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'data'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'visualization'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'dashboard'</span> <span class="hljs-keyword">in</span> message.lower():
        project_id = <span class="hljs-string">'project3'</span>

    <span class="hljs-keyword">if</span> project_id <span class="hljs-keyword">and</span> (<span class="hljs-string">'tell me more'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'details'</span> <span class="hljs-keyword">in</span> message.lower()):
        response = project_agent.get_project_details(project_id)
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'list'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'all projects'</span> <span class="hljs-keyword">in</span> message.lower():
        response = project_agent.get_project_list()
    <span class="hljs-keyword">elif</span> project_id:

        response = project_agent.answer_technical_question(project_id, message)
    <span class="hljs-keyword">else</span>:

        response = project_agent.get_response(
            <span class="hljs-string">f"The user asked: '<span class="hljs-subst">{message}</span>'. Respond as if you are a project specialist for a portfolio website. "</span>
            <span class="hljs-string">"If they're asking about a specific project, suggest they mention one of the projects: "</span>
            <span class="hljs-string">"E-commerce Platform, Task Management App, or Data Visualization Dashboard."</span>
        )

    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'response'</span>: response})


<span class="hljs-meta">@app.route('/api/career', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">career_agent_endpoint</span>():</span>
    data = request.json
    message = data.get(<span class="hljs-string">'message'</span>, <span class="hljs-string">''</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-string">'skills'</span> <span class="hljs-keyword">in</span> message.lower():
        response = career_agent.get_skills_summary()
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'experience'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'work history'</span> <span class="hljs-keyword">in</span> message.lower():
        response = career_agent.get_experience_summary()
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'job'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'position'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'role'</span> <span class="hljs-keyword">in</span> message.lower():

        response = career_agent.assess_job_fit(message)
    <span class="hljs-keyword">else</span>:

        response = career_agent.get_response(
            <span class="hljs-string">f"The user asked: '<span class="hljs-subst">{message}</span>'. Respond as if you are a career specialist for a portfolio website. "</span>
            <span class="hljs-string">"Suggest they ask about skills, experience, or job fit assessment."</span>
        )

    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'response'</span>: response})


<span class="hljs-meta">@app.route('/api/client', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">client_agent_endpoint</span>():</span>
    data = request.json
    message = data.get(<span class="hljs-string">'message'</span>, <span class="hljs-string">''</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-string">'services'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'offerings'</span> <span class="hljs-keyword">in</span> message.lower():
        response = client_agent.get_services_overview()
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'web'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">and</span> <span class="hljs-string">'development'</span> <span class="hljs-keyword">in</span> message.lower():
        response = client_agent.get_service_details(<span class="hljs-string">'web_development'</span>)
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'mobile'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">and</span> <span class="hljs-string">'development'</span> <span class="hljs-keyword">in</span> message.lower():
        response = client_agent.get_service_details(<span class="hljs-string">'mobile_development'</span>)
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'consulting'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'technical consulting'</span> <span class="hljs-keyword">in</span> message.lower():
        response = client_agent.get_service_details(<span class="hljs-string">'consulting'</span>)
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'process'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'how does it work'</span> <span class="hljs-keyword">in</span> message.lower():
        response = client_agent.explain_process()
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'proposal'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'quote'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'estimate'</span> <span class="hljs-keyword">in</span> message.lower():

        response = client_agent.generate_proposal(message)
    <span class="hljs-keyword">else</span>:

        response = client_agent.get_response(
            <span class="hljs-string">f"The user asked: '<span class="hljs-subst">{message}</span>'. Respond as if you are a client specialist for a portfolio website. "</span>
            <span class="hljs-string">"Suggest they ask about services, the client engagement process, or request a proposal."</span>
        )

    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'response'</span>: response})


<span class="hljs-meta">@app.route('/api/research', methods=['POST'])</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">research_agent_endpoint</span>():</span>
    data = request.json
    message = data.get(<span class="hljs-string">'message'</span>, <span class="hljs-string">''</span>)

    <span class="hljs-keyword">if</span> <span class="hljs-string">'compare'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">and</span> (<span class="hljs-string">'vs'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'versus'</span> <span class="hljs-keyword">in</span> message.lower()):

        tech_parts = message.lower().replace(<span class="hljs-string">'compare'</span>, <span class="hljs-string">''</span>).replace(
            <span class="hljs-string">'vs'</span>, <span class="hljs-string">' '</span>).replace(<span class="hljs-string">'versus'</span>, <span class="hljs-string">' '</span>).split()
        tech1 = tech_parts[<span class="hljs-number">0</span>] <span class="hljs-keyword">if</span> len(tech_parts) &gt; <span class="hljs-number">0</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
        tech2 = tech_parts[<span class="hljs-number">-1</span>] <span class="hljs-keyword">if</span> len(tech_parts) &gt; <span class="hljs-number">1</span> <span class="hljs-keyword">else</span> <span class="hljs-string">''</span>
        response = research_agent.compare_technologies(tech1, tech2)
    <span class="hljs-keyword">elif</span> <span class="hljs-string">'trends'</span> <span class="hljs-keyword">in</span> message.lower() <span class="hljs-keyword">or</span> <span class="hljs-string">'industry'</span> <span class="hljs-keyword">in</span> message.lower():
        response = research_agent.get_industry_trends()
    <span class="hljs-keyword">else</span>:
        response = research_agent.search_web(message)

    <span class="hljs-keyword">return</span> jsonify({<span class="hljs-string">'response'</span>: response})


<span class="hljs-keyword">if</span> __name__ == <span class="hljs-string">'__main__'</span>:

    app.config[<span class="hljs-string">'SEND_FILE_MAX_AGE_DEFAULT'</span>] = <span class="hljs-number">0</span>
    app.config[<span class="hljs-string">'TEMPLATES_AUTO_RELOAD'</span>] = <span class="hljs-literal">True</span>   <span class="hljs-comment"># Ensure templates reload</span>

<span class="hljs-meta">    @app.after_request</span>
    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">add_header</span>(<span class="hljs-params">response</span>):</span>
        response.headers[<span class="hljs-string">'Cache-Control'</span>] = <span class="hljs-string">'no-store, no-cache, must-revalidate, max-age=0'</span>
        response.headers[<span class="hljs-string">'Pragma'</span>] = <span class="hljs-string">'no-cache'</span>
        response.headers[<span class="hljs-string">'Expires'</span>] = <span class="hljs-string">'0'</span>
        <span class="hljs-keyword">return</span> response

    app.run(host=<span class="hljs-string">'0.0.0.0'</span>, port=<span class="hljs-number">5001</span>, debug=<span class="hljs-literal">True</span>,
            use_reloader=<span class="hljs-literal">False</span>, threaded=<span class="hljs-literal">True</span>)
</code></pre>
<p>Okay, if your file has errors, they're probably caused by the Python indentation. Hopefully, the formatting will not make them too difficult to fix.</p>
<p>The file is now complete, and you’ve created the rest of your AI API routes.</p>
<h3 id="heading-running-our-python-backend">Running Our Python Backend</h3>
<p>All that's left is to run your Flask server and get the backend up and running. You can do that with this run script inside the <code>venv</code> folder:</p>
<pre><code class="lang-shell">python3 main.py
</code></pre>
<p>Your backend should now be running on <a target="_blank" href="http://127.0.0.1:5001/">http://127.0.0.1:5001/</a>. If you go to the page you will see an error like this:</p>
<pre><code class="lang-markdown">Not Found

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.
</code></pre>
<p>This is expected, because if you have checked the codebase, you’ll realise that there are no GET routes, only POST routes. To see them working, you need to use an HTTP client like Postman. Another option is to create some <code>curl</code> commands that send a POST request, which you can run from your terminal. Let's use <code>curl</code> because there is less setup. You’ll need to copy and paste the commands.</p>
<p>Each POST request will use exactly one API call on Groq Cloud for your API Key which you can view here <a target="_blank" href="https://console.groq.com/keys">https://console.groq.com/keys</a>. Remember that it’s free to use but there are usage limits which you can read about in their documentation on <a target="_blank" href="https://console.groq.com/docs/rate-limits">Rate Limits</a>.</p>
<p>I have provided some sample curl commands below – just copy and paste them into your terminal and hit enter, and you should see the response message:</p>
<p><strong>1. Testing the Welcome Agent Endpoint</strong></p>
<pre><code class="lang-shell">curl -X POST http://localhost:5001/api/welcome \
  -H "Content-Type: application/json" \
  -d '{"message": "I am an employer looking for a skilled developer"}'
</code></pre>
<p><strong>2. Testing the Project Agent Endpoint</strong></p>
<pre><code class="lang-shell">curl -X POST http://localhost:5001/api/project \
  -H "Content-Type: application/json" \
  -d '{"message": "Tell me more about the e-commerce project"}'
</code></pre>
<p><strong>3. Testing the Career Agent Endpoint</strong></p>
<pre><code class="lang-shell">curl -X POST http://localhost:5001/api/career \
  -H "Content-Type: application/json" \
  -d '{"message": "What skills do you have?"}'
</code></pre>
<p><strong>4. Testing the Client Agent Endpoint</strong></p>
<pre><code class="lang-shell">curl -X POST http://localhost:5001/api/client \
  -H "Content-Type: application/json" \
  -d '{"message": "What services do you offer?"}'
</code></pre>
<p><strong>5. Testing the Research Agent Endpoint</strong></p>
<pre><code class="lang-shell">curl -X POST http://localhost:5001/api/research \
  -H "Content-Type: application/json" \
  -d '{"message": "What are the current trends in web development?"}'
</code></pre>
<h2 id="heading-building-our-react-frontend">Building Our React Frontend</h2>
<p>We have reached halfway point, and all that's left is to build your front end. We’ll build the front end using <a target="_blank" href="https://vite.dev/">Vite</a>, and the website will have six pages. Make sure that you are now inside the root folder for the <code>ai-agent-app</code> project. You can leave the Python server running because your front end is going to connect to the API routes you created.</p>
<p>Now, run the commands below to setup your React project using Vite, Tailwind CSS, react-router and Axios, which we need for page routing and fetch requests:</p>
<pre><code class="lang-shell">npm create vite@latest frontend -- --template react
cd frontend
npm install -D tailwindcss@3 postcss autoprefixer react-router axios
npx tailwindcss init -p
npm install
</code></pre>
<p>Great, now with those packages installed and our dependencies set up, we are almost ready to start on the codebase. But before that, we need to run one more script, which is going to create all of the files and folders for our project. It's much faster than doing them all manually.</p>
<p>Run this command inside the frontend folder:</p>
<pre><code class="lang-shell">mkdir -p src/components src/pages
touch src/style.css src/components/{Chat,Footer,Layout,Navbar}.jsx
touch src/pages/{Career,Contact,Home,Projects,Research,Services}.jsx
</code></pre>
<p>Our React frontend should now have a project structure like the example shown below:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977692485/9940901d-bd7a-49dd-a18b-ab3edf5e3714.png" alt="AI Agent App frontend project structure" class="image--center mx-auto" width="500" height="1548" loading="lazy"></p>
<p>We are now ready to start writing some code.</p>
<p>Up first is the <code>tailwind.config.js</code> file. This is the only configuration file you’ll need to work on, as the others already have the configuration we need. Replace all of the code in the file with the code below:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">/** <span class="hljs-doctag">@type <span class="hljs-type">{import('tailwindcss').Config}</span> </span>*/</span>
<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> {
  <span class="hljs-attr">content</span>: [<span class="hljs-string">'./index.html'</span>, <span class="hljs-string">'./src/**/*.{js,ts,jsx,tsx}'</span>],
  <span class="hljs-attr">theme</span>: {
    <span class="hljs-attr">extend</span>: {},
  },
  <span class="hljs-attr">plugins</span>: [],
};
</code></pre>
<p>All this code does is add the paths to all of your template files.</p>
<p>Ok, next, you are going to work on your styles and Tailwind CSS. There are three CSS files to work on: <code>App.css</code>, <code>index.css</code>, and <code>style.css</code>.</p>
<p>First up is the <code>App.css</code> file. Replace all of the code with this code here:</p>
<pre><code class="lang-css"><span class="hljs-selector-id">#root</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
  <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">text-align</span>: left;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
}
</code></pre>
<p>We just have some basic layout styles here for <code>root</code> and <code>main</code>.</p>
<p>Next is the <code>index.css</code> file. Below is the code you’ll need, so replace everything in the file with it:</p>
<pre><code class="lang-css"><span class="hljs-keyword">@tailwind</span> base;
<span class="hljs-keyword">@tailwind</span> components;
<span class="hljs-keyword">@tailwind</span> utilities;

<span class="hljs-selector-pseudo">:root</span> {
  <span class="hljs-attribute">font-family</span>: system-ui, Avenir, Helvetica, Arial, sans-serif;
  <span class="hljs-attribute">font-synthesis</span>: none;
  <span class="hljs-attribute">text-rendering</span>: optimizeLegibility;
  <span class="hljs-attribute">-webkit-font-smoothing</span>: antialiased;
  <span class="hljs-attribute">-moz-osx-font-smoothing</span>: grayscale;
}

<span class="hljs-keyword">@layer</span> components {
  <span class="hljs-selector-class">.chat-container</span> {
    @apply w-full h-96 flex flex-col;
  }

  <span class="hljs-selector-class">.chat-messages</span> {
    @apply flex-1 overflow-y-auto p-4;
  }

  <span class="hljs-selector-class">.message</span> {
    @apply flex mb-4;
  }

  <span class="hljs-selector-class">.user-message</span> {
    @apply justify-end;
  }

  <span class="hljs-selector-class">.agent-message</span> {
    @apply justify-start;
  }

  <span class="hljs-selector-class">.message-avatar</span> {
    @apply flex-shrink-0 mr-2;
  }

  <span class="hljs-selector-class">.avatar-placeholder</span> {
    @apply w-10 h-10 rounded-full bg-blue-500 text-white flex items-center justify-center font-bold;
  }

  <span class="hljs-selector-class">.message-content</span> {
    @apply p-3 rounded-lg max-w-xs <span class="hljs-attribute">sm</span>:max-w-sm md:max-w-md;
  }

  <span class="hljs-selector-class">.user-message</span> <span class="hljs-selector-class">.message-content</span> {
    @apply bg-blue-500 text-white;
  }

  <span class="hljs-selector-class">.agent-message</span> <span class="hljs-selector-class">.message-content</span> {
    @apply bg-gray-200 text-gray-800;
  }

  <span class="hljs-selector-class">.chat-input-container</span> {
    @apply p-4 border-t border-gray-200;
  }

  <span class="hljs-selector-class">.chat-input-group</span> {
    @apply flex;
  }

  <span class="hljs-selector-class">.chat-input</span> {
    @apply flex-1 border border-gray-300 rounded-l-lg p-2 <span class="hljs-attribute">focus</span>:outline-none focus:ring-<span class="hljs-number">2</span> focus:ring-blue-<span class="hljs-number">500</span>;
  }

  <span class="hljs-selector-class">.chat-send-button</span> {
    @apply bg-blue-500 text-white px-4 py-2 rounded-r-lg <span class="hljs-attribute">hover</span>:bg-blue-<span class="hljs-number">600</span> focus:outline-none focus:ring-<span class="hljs-number">2</span> focus:ring-blue-<span class="hljs-number">500</span>;
  }

  <span class="hljs-selector-class">.loading-dots</span><span class="hljs-selector-pseudo">:after</span> {
    @apply content-['...'] animate-pulse;
  }

  <span class="hljs-selector-class">.project-image-placeholder</span> {
    @apply h-48 bg-gray-300 flex items-center justify-center text-gray-600 font-semibold;
  }

  <span class="hljs-selector-class">.agent-avatar-placeholder</span> {
    @apply w-16 h-16 rounded-full bg-blue-500 text-white flex items-center justify-center font-bold mx-auto;
  }
}
</code></pre>
<p>All of these styles relate to your Tailwind CSS setup throughout your project.</p>
<p>Just one file remains for the CSS and it’s the <code>style.css</code> file. This is a big file, so I will split the code into two parts – just copy and paste them into the file.</p>
<p>Here is the first part:</p>
<pre><code class="lang-css"><span class="hljs-comment">/* Main Styles */</span>
<span class="hljs-selector-tag">body</span> {
  <span class="hljs-attribute">font-family</span>: <span class="hljs-string">'Inter'</span>, -apple-system, BlinkMacSystemFont, <span class="hljs-string">'Segoe UI'</span>, Roboto, Oxygen,
    Ubuntu, Cantarell, <span class="hljs-string">'Open Sans'</span>, <span class="hljs-string">'Helvetica Neue'</span>, sans-serif;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#333</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f8f9fa</span>;
}

<span class="hljs-comment">/* Layout Styles */</span>
<span class="hljs-selector-id">#root</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">100%</span>;
  <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">text-align</span>: left;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">min-height</span>: <span class="hljs-number">100vh</span>;
}

<span class="hljs-selector-tag">main</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
}

<span class="hljs-selector-tag">h1</span>,
<span class="hljs-selector-tag">h2</span>,
<span class="hljs-selector-tag">h3</span>,
<span class="hljs-selector-tag">h4</span>,
<span class="hljs-selector-tag">h5</span>,
<span class="hljs-selector-tag">h6</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">600</span>;
}

<span class="hljs-selector-tag">footer</span> {
  <span class="hljs-attribute">margin-top</span>: auto;
}

<span class="hljs-comment">/* Navbar Styles */</span>
<span class="hljs-selector-class">.navbar</span> {
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</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-selector-class">.navbar-brand</span> {
  <span class="hljs-attribute">font-weight</span>: <span class="hljs-number">700</span>;
}

<span class="hljs-selector-class">.navbar</span> <span class="hljs-selector-class">.container</span> {
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">1320px</span>;
}

<span class="hljs-comment">/* Card Styles */</span>
<span class="hljs-selector-class">.card</span> {
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">transition</span>: transform <span class="hljs-number">0.3s</span> ease, box-shadow <span class="hljs-number">0.3s</span> ease;
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">2em</span>;
}

<span class="hljs-selector-class">.card</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">transform</span>: <span class="hljs-built_in">translateY</span>(-<span class="hljs-number">5px</span>);
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">10px</span> <span class="hljs-number">20px</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-comment">/* Agent Styles */</span>
<span class="hljs-selector-class">.agent-avatar-placeholder</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">80px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#6c757d</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">24px</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
  <span class="hljs-attribute">margin</span>: <span class="hljs-number">0</span> auto;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">3px</span> solid <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">box-shadow</span>: <span class="hljs-number">0</span> <span class="hljs-number">2px</span> <span class="hljs-number">4px</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-selector-class">.avatar-placeholder</span> {
  <span class="hljs-attribute">width</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">40px</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">50%</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#6c757d</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: center;
  <span class="hljs-attribute">justify-content</span>: center;
  <span class="hljs-attribute">font-size</span>: <span class="hljs-number">16px</span>;
  <span class="hljs-attribute">font-weight</span>: bold;
}

<span class="hljs-comment">/* Chat Container Styles */</span>
<span class="hljs-selector-class">.chat-container</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">flex-direction</span>: column;
  <span class="hljs-attribute">height</span>: <span class="hljs-number">400px</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dee2e6</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attribute">overflow</span>: hidden;
}

<span class="hljs-selector-class">.chat-messages</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">1rem</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#f8f9fa</span>;
}
</code></pre>
<p>And here is the second part:</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.chat-input-container</span> {
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">border-top</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dee2e6</span>;
}

<span class="hljs-selector-class">.chat-input-group</span> {
  <span class="hljs-attribute">display</span>: flex;
}

<span class="hljs-selector-class">.chat-input</span> {
  <span class="hljs-attribute">flex</span>: <span class="hljs-number">1</span>;
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0.5rem</span>;
  <span class="hljs-attribute">border</span>: <span class="hljs-number">1px</span> solid <span class="hljs-number">#dee2e6</span>;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span>;
}

<span class="hljs-selector-class">.chat-send-button</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attribute">color</span>: white;
  <span class="hljs-attribute">border</span>: none;
  <span class="hljs-attribute">border-radius</span>: <span class="hljs-number">0.25rem</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.5rem</span> <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">cursor</span>: pointer;
}

<span class="hljs-selector-class">.chat-send-button</span><span class="hljs-selector-pseudo">:hover</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#0069d9</span>;
}

<span class="hljs-comment">/* Message Styles */</span>
<span class="hljs-selector-class">.message</span> {
  <span class="hljs-attribute">margin-bottom</span>: <span class="hljs-number">1rem</span>;
  <span class="hljs-attribute">max-width</span>: <span class="hljs-number">80%</span>;
}

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

<span class="hljs-selector-class">.agent-message</span> {
  <span class="hljs-attribute">display</span>: flex;
  <span class="hljs-attribute">align-items</span>: flex-start;
}

<span class="hljs-selector-class">.message-avatar</span> {
  <span class="hljs-attribute">margin-right</span>: <span class="hljs-number">0.5rem</span>;
}

<span class="hljs-selector-class">.message-content</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
  <span class="hljs-attribute">padding</span>: <span class="hljs-number">0.75rem</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">1px</span> <span class="hljs-number">2px</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.05</span>);
}

<span class="hljs-selector-class">.user-message</span> <span class="hljs-selector-class">.message-content</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#007bff</span>;
  <span class="hljs-attribute">color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-selector-class">.agent-message</span> <span class="hljs-selector-class">.message-content</span> {
  <span class="hljs-attribute">background-color</span>: <span class="hljs-number">#fff</span>;
}

<span class="hljs-comment">/* Loading Animation */</span>
<span class="hljs-selector-class">.loading-dots</span><span class="hljs-selector-pseudo">:after</span> {
  <span class="hljs-attribute">content</span>: <span class="hljs-string">'.'</span>;
  <span class="hljs-attribute">animation</span>: dots <span class="hljs-number">1.5s</span> <span class="hljs-built_in">steps</span>(<span class="hljs-number">5</span>, end) infinite;
}

<span class="hljs-keyword">@keyframes</span> dots {
  0%,
  20% {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">'.'</span>;
  }
  40% {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">'..'</span>;
  }
  60% {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">'...'</span>;
  }
  80%,
  100% {
    <span class="hljs-attribute">content</span>: <span class="hljs-string">''</span>;
  }
}
</code></pre>
<p>This code has the main styles for the layout of the website’s content. That takes care of the styling. We just have the components and pages left, and then you can run your app. Before we start on those folders, let’s quickly do the <code>App.jsx</code> and <code>main.jsx</code> files in the <code>src</code> folder.</p>
<p>So, add this code to the <code>App.jsx</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { BrowserRouter <span class="hljs-keyword">as</span> Router, Routes, Route } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router'</span>;
<span class="hljs-keyword">import</span> Layout <span class="hljs-keyword">from</span> <span class="hljs-string">'./components/Layout'</span>;
<span class="hljs-keyword">import</span> Home <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Home'</span>;
<span class="hljs-keyword">import</span> Projects <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Projects'</span>;
<span class="hljs-keyword">import</span> Career <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Career'</span>;
<span class="hljs-keyword">import</span> Services <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Services'</span>;
<span class="hljs-keyword">import</span> Research <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Research'</span>;
<span class="hljs-keyword">import</span> Contact <span class="hljs-keyword">from</span> <span class="hljs-string">'./pages/Contact'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./App.css'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">App</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">Router</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">Layout</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Routes</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Home</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/projects"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Projects</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/career"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Career</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/services"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Services</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/research"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Research</span> /&gt;</span>} /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">Route</span> <span class="hljs-attr">path</span>=<span class="hljs-string">"/contact"</span> <span class="hljs-attr">element</span>=<span class="hljs-string">{</span>&lt;<span class="hljs-attr">Contact</span> /&gt;</span>} /&gt;
        <span class="hljs-tag">&lt;/<span class="hljs-name">Routes</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">Layout</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">Router</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> App;
</code></pre>
<p>In this file, you have all of your routes. This is how you’ll navigate between pages using <code>BrowserRouter</code>.</p>
<p>Finally, replace and update all of the code inside of <code>main.jsx</code> with this:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { StrictMode } <span class="hljs-keyword">from</span> <span class="hljs-string">'react'</span>;
<span class="hljs-keyword">import</span> { createRoot } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-dom/client'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./index.css'</span>;
<span class="hljs-keyword">import</span> <span class="hljs-string">'./style.css'</span>;
<span class="hljs-keyword">import</span> App <span class="hljs-keyword">from</span> <span class="hljs-string">'./App.jsx'</span>;

createRoot(<span class="hljs-built_in">document</span>.getElementById(<span class="hljs-string">'root'</span>)).render(
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">StrictMode</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">App</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">StrictMode</span>&gt;</span></span>
);
</code></pre>
<p>The only update we did here was add an import for <code>import './style.css'</code> so now you can access the styles from this file across your application.</p>
<p>Time to work on your component files, starting with the <code>Chat.jsx</code> file. I split the codebase because it’s a big file, so make sure you add it all together.</p>
<p>Like before, here is the first part:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState, useEffect, useRef, useCallback } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Chat</span>(<span class="hljs-params">{ agentType, initialMessage, agentInitials, directQuestion }</span>) </span>{
  <span class="hljs-keyword">const</span> [messages, setMessages] = useState([]);
  <span class="hljs-keyword">const</span> [input, setInput] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [isLoading, setIsLoading] = useState(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">const</span> messagesEndRef = useRef(<span class="hljs-literal">null</span>);
  <span class="hljs-keyword">const</span> [processedQuestions, setProcessedQuestions] = useState([]);

  <span class="hljs-keyword">const</span> API_BASE_URL = <span class="hljs-string">"http://127.0.0.1:5001"</span>;

  <span class="hljs-keyword">const</span> scrollToBottom = <span class="hljs-function">() =&gt;</span> {
    messagesEndRef.current?.scrollIntoView({ <span class="hljs-attr">behavior</span>: <span class="hljs-string">"smooth"</span> });
  };

  <span class="hljs-keyword">const</span> handleSendMessage = useCallback(
    <span class="hljs-keyword">async</span> (questionOverride = <span class="hljs-literal">null</span>) =&gt; {
      <span class="hljs-keyword">const</span> messageToSend = questionOverride || input;

      <span class="hljs-keyword">if</span> (!messageToSend.trim()) <span class="hljs-keyword">return</span>;

      <span class="hljs-keyword">const</span> userMessage = {
        <span class="hljs-attr">content</span>: messageToSend,
        <span class="hljs-attr">isUser</span>: <span class="hljs-literal">true</span>,
      };

      setMessages(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [...prev, userMessage]);

      <span class="hljs-keyword">if</span> (!questionOverride) {
        setInput(<span class="hljs-string">""</span>);
      }

      setIsLoading(<span class="hljs-literal">true</span>);

      <span class="hljs-keyword">try</span> {
        <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(
          <span class="hljs-string">`<span class="hljs-subst">${API_BASE_URL}</span>/api/<span class="hljs-subst">${agentType}</span>`</span>,
          {
            <span class="hljs-attr">message</span>: messageToSend,
          },
          {
            <span class="hljs-attr">headers</span>: {
              <span class="hljs-string">"Content-Type"</span>: <span class="hljs-string">"application/json"</span>,
              <span class="hljs-string">"Access-Control-Allow-Origin"</span>: <span class="hljs-string">"*"</span>,
            },
          }
        );

        <span class="hljs-keyword">if</span> (response.data &amp;&amp; response.data.response) {
          setMessages(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [
            ...prev,
            {
              <span class="hljs-attr">content</span>: response.data.response,
              <span class="hljs-attr">isUser</span>: <span class="hljs-literal">false</span>,
            },
          ]);
        }
      } <span class="hljs-keyword">catch</span> (error) {
        <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error sending message:"</span>, error);
        setMessages(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [
          ...prev,
          {
            <span class="hljs-attr">content</span>:
              <span class="hljs-string">"Sorry, there was an error connecting to the AI agent. Please make sure the Flask server is running at http://127.0.0.1:5001/"</span>,
            <span class="hljs-attr">isUser</span>: <span class="hljs-literal">false</span>,
          },
        ]);
      } <span class="hljs-keyword">finally</span> {
        setIsLoading(<span class="hljs-literal">false</span>);
      }
    },
    [input, agentType, API_BASE_URL]
  );

  <span class="hljs-keyword">const</span> handleKeyPress = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">if</span> (e.key === <span class="hljs-string">"Enter"</span>) {
      handleSendMessage();
    }
  };

  <span class="hljs-keyword">const</span> cleanQuestion = <span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
    <span class="hljs-keyword">return</span> question.replace(<span class="hljs-regexp">/\s*\[\d+\]\s*$/</span>, <span class="hljs-string">""</span>);
  };

  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (initialMessage) {
      setMessages([
        {
          <span class="hljs-attr">content</span>: initialMessage,
          <span class="hljs-attr">isUser</span>: <span class="hljs-literal">false</span>,
        },
      ]);
    }
  }, [initialMessage]);

  useEffect(<span class="hljs-function">() =&gt;</span> {
    scrollToBottom();
  }, [messages]);
</code></pre>
<p>The first part of this code has your imports, base URL to connect to the backend, and the functions.</p>
<p>Now let’s add the second part of the codebase:</p>
<pre><code class="lang-javascript">  useEffect(<span class="hljs-function">() =&gt;</span> {
    <span class="hljs-keyword">if</span> (
      directQuestion &amp;&amp;
      directQuestion.trim() !== <span class="hljs-string">""</span> &amp;&amp;
      !processedQuestions.includes(directQuestion)
    ) {
      <span class="hljs-keyword">const</span> cleanedQuestion = cleanQuestion(directQuestion);
      setInput(cleanedQuestion);
      handleSendMessage(cleanedQuestion);
      setProcessedQuestions(<span class="hljs-function">(<span class="hljs-params">prev</span>) =&gt;</span> [...prev, directQuestion]);
    }
  }, [directQuestion, processedQuestions, handleSendMessage]);

  <span class="hljs-keyword">const</span> renderContent = <span class="hljs-function">(<span class="hljs-params">content</span>) =&gt;</span> {
    <span class="hljs-keyword">let</span> formattedContent = content;

    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{6}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h6&gt;$1&lt;/h6&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{5}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h5&gt;$1&lt;/h5&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{4}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h4&gt;$1&lt;/h4&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{3}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h3&gt;$1&lt;/h3&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{2}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h2&gt;$1&lt;/h2&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/#{1}\s+(.*?)(?=\n|$)/g</span>,
      <span class="hljs-string">"&lt;h1&gt;$1&lt;/h1&gt;"</span>
    );

    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/\*\*(.*?)\*\*/g</span>,
      <span class="hljs-string">"&lt;strong&gt;$1&lt;/strong&gt;"</span>
    );

    formattedContent = formattedContent.replace(<span class="hljs-regexp">/\*(.*?)\*/g</span>, <span class="hljs-string">"&lt;em&gt;$1&lt;/em&gt;"</span>);

    formattedContent = formattedContent.replace(<span class="hljs-regexp">/`(.*?)`/g</span>, <span class="hljs-string">"&lt;code&gt;$1&lt;/code&gt;"</span>);

    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/\[(.*?)\]\((.*?)\)/g</span>,
      <span class="hljs-string">'&lt;a href="$2" target="_blank"&gt;$1&lt;/a&gt;'</span>
    );

    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/^\s*\*\s+(.*?)(?=\n|$)/gm</span>,
      <span class="hljs-string">"&lt;li&gt;$1&lt;/li&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/&lt;li&gt;(.*?)&lt;\/li&gt;(?:\s*&lt;li&gt;.*?&lt;\/li&gt;)*/g</span>,
      <span class="hljs-string">"&lt;ul&gt;$&amp;&lt;/ul&gt;"</span>
    );

    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/^\s*\d+\.\s+(.*?)(?=\n|$)/gm</span>,
      <span class="hljs-string">"&lt;li&gt;$1&lt;/li&gt;"</span>
    );
    formattedContent = formattedContent.replace(
      <span class="hljs-regexp">/&lt;li&gt;(.*?)&lt;\/li&gt;(?:\s*&lt;li&gt;.*?&lt;\/li&gt;)*/g</span>,
      <span class="hljs-string">"&lt;ol&gt;$&amp;&lt;/ol&gt;"</span>
    );

    <span class="hljs-keyword">return</span> { <span class="hljs-attr">__html</span>: formattedContent };
  };

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-container"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-messages"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">agentType</span>}<span class="hljs-attr">-messages</span>`}&gt;</span>
        {messages.map((message, index) =&gt; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
            <span class="hljs-attr">key</span>=<span class="hljs-string">{index}</span>
            <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">message</span> ${
              <span class="hljs-attr">message.isUser</span> ? "<span class="hljs-attr">user-message</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">agent-message</span>"
            }`}
          &gt;</span>
            {!message.isUser &amp;&amp; (
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-avatar"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar-placeholder"</span>&gt;</span>
                  {agentInitials || "AI"}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-content"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">dangerouslySetInnerHTML</span>=<span class="hljs-string">{renderContent(message.content)}</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">div</span>&gt;</span>
        ))}
        {isLoading &amp;&amp; (
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message agent-message"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-avatar"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"avatar-placeholder"</span>&gt;</span>{agentInitials || "AI"}<span class="hljs-tag">&lt;/<span class="hljs-name">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"message-content"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"loading-dots"</span>&gt;</span>Thinking<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
        )}
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">ref</span>=<span class="hljs-string">{messagesEndRef}</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-input-container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-input-group"</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">{</span>`${<span class="hljs-attr">agentType</span>}<span class="hljs-attr">-input</span>`}
            <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-input"</span>
            <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Type your message..."</span>
            <span class="hljs-attr">value</span>=<span class="hljs-string">{input}</span>
            <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setInput(e.target.value)}
            onKeyPress={handleKeyPress}
          /&gt;
          <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
            <span class="hljs-attr">id</span>=<span class="hljs-string">{</span>`${<span class="hljs-attr">agentType</span>}<span class="hljs-attr">-send</span>`}
            <span class="hljs-attr">className</span>=<span class="hljs-string">"chat-send-button"</span>
            <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> handleSendMessage()}
          &gt;
            <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"fa-solid fa-paper-plane mr-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</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">div</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">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Chat;
</code></pre>
<p>The second part of the code mostly has the JSX for the components.</p>
<p>Right, next let’s do the <code>Footer.jsx</code> file by adding this code to the file:</p>
<pre><code class="lang-javascript"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Footer</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-dark text-white py-4"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>Showcasing my work with the help of AI agents<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-md-6 text-md-end"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span>&gt;</span>Connect<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"social-links"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-white me-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-white me-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-white me-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">a</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">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"row mt-3"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"col-12 text-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-0"</span>&gt;</span>
              <span class="hljs-symbol">&amp;copy;</span> {new Date().getFullYear()} Portfolio. All rights reserved.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</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">footer</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Footer;
</code></pre>
<p>The code is pretty much self-explanatory – it has some contact details which will show up at the bottom of your page in the footer section.</p>
<p>Now we can work on the <code>Layout.jsx</code>. I have also split it into two parts.</p>
<p>Add the first part of the codebase here:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Link, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">"react-router"</span>;
<span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Layout</span>(<span class="hljs-params">{ children }</span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();
  <span class="hljs-keyword">const</span> [isMenuOpen, setIsMenuOpen] = useState(<span class="hljs-literal">false</span>);

  <span class="hljs-keyword">return</span> (
    &lt;div className="flex flex-col min-h-screen"&gt;
      &lt;nav className="bg-gray-800 text-white"&gt;
        &lt;div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"&gt;
          &lt;div className="flex justify-between h-16"&gt;
            &lt;div className="flex items-center"&gt;
              &lt;Link className="text-xl font-bold" to="/"&gt;
                Portfolio
              &lt;/Link&gt;
            &lt;/div&gt;
            &lt;div className="hidden md:block"&gt;
              &lt;div className="ml-10 flex items-center space-x-4"&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/"
                &gt;
                  Home
                &lt;/Link&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/projects"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/projects"
                &gt;
                  Projects
                &lt;/Link&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/career"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/career"
                &gt;
                  Career
                &lt;/Link&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/services"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/services"
                &gt;
                  Services
                &lt;/Link&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/research"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/research"
                &gt;
                  Research
                &lt;/Link&gt;
                &lt;Link
                  className={`px-3 py-2 rounded-md text-sm font-medium ${
                    location.pathname === "/contact"
                      ? "bg-gray-900 text-white"
                      : "text-gray-300 hover:bg-gray-700 hover:text-white"
                  }`}
                  to="/contact"
                &gt;
                  Contact
                &lt;/Link&gt;
              &lt;/div&gt;
            &lt;/div&gt;
            &lt;div className="md:hidden flex items-center"&gt;
              &lt;button
                onClick={() =&gt; setIsMenuOpen(!isMenuOpen)}
                className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
              &gt;
                &lt;span className="sr-only"&gt;Open main menu&lt;/span&gt;
                {isMenuOpen ? (
                  &lt;svg
                    className="block h-6 w-6"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke="currentColor"
                    aria-hidden="true"
                  &gt;
                    &lt;path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth="2"
                      d="M6 18L18 6M6 6l12 12"
                    /&gt;
                  &lt;/svg&gt;
                ) : (
                  &lt;svg
                    className="block h-6 w-6"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                    stroke="currentColor"
                    aria-hidden="true"
                  &gt;
                    &lt;path
                      strokeLinecap="round"
                      strokeLinejoin="round"
                      strokeWidth="2"
                      d="M4 6h16M4 12h16M4 18h16"
                    /&gt;
                  &lt;/svg&gt;
                )}
              &lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
</code></pre>
<p>This part of the code has a lot of components, as expected for the layout.</p>
<p>Here is the second part of the code to be added to the file:</p>
<pre><code class="lang-javascript">        {<span class="hljs-comment">/* Mobile menu, show/hide based on menu state */</span>}
        {isMenuOpen &amp;&amp; (
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2 pt-2 pb-3 space-y-1 sm:px-3"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Home
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/projects"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/career"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/career"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Career
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/services"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/services"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Services
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/research"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/research"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Research
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">block</span> <span class="hljs-attr">px-3</span> <span class="hljs-attr">py-2</span> <span class="hljs-attr">rounded-md</span> <span class="hljs-attr">text-base</span> <span class="hljs-attr">font-medium</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">"/contact"</span>
                    ? "<span class="hljs-attr">bg-gray-900</span> <span class="hljs-attr">text-white</span>"
                    <span class="hljs-attr">:</span> "<span class="hljs-attr">text-gray-300</span> <span class="hljs-attr">hover:bg-gray-700</span> <span class="hljs-attr">hover:text-white</span>"
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/contact"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span> setIsMenuOpen(false)}
              &gt;
                Contact
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</span>&gt;</span></span>
        )}
      &lt;/nav&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">main</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex-grow max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-8"</span>&gt;</span>
        {children}
      <span class="hljs-tag">&lt;/<span class="hljs-name">main</span>&gt;</span></span>

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">footer</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-gray-800 text-white py-8"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"max-w-7xl mx-auto px-4 sm:px-6 lg:px-8"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:flex md:justify-between"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-8 md:mb-0"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold mb-2"</span>&gt;</span>Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-300"</span>&gt;</span>
                Showcasing my work with the help of AI agents
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-8 border-t border-gray-700 pt-8 text-center"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-300"</span>&gt;</span>
              <span class="hljs-symbol">&amp;copy;</span> 2025 Portfolio. All rights reserved.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">footer</span>&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Layout;
</code></pre>
<p>This code has more components, which completes the Layout component.</p>
<p>We’re almost done. Now for the last component, <code>Navbar.jsx</code>, before we move on to the pages.</p>
<p>This is the code you need for the file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Link, useLocation } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Navbar</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> location = useLocation();

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">nav</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar navbar-expand-lg navbar-dark bg-dark"</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"container"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">Link</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar-brand"</span> <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>&gt;</span>
          Portfolio
        <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
          <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar-toggler"</span>
          <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
          <span class="hljs-attr">data-bs-toggle</span>=<span class="hljs-string">"collapse"</span>
          <span class="hljs-attr">data-bs-target</span>=<span class="hljs-string">"#navbarNav"</span>
        &gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar-toggler-icon"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"collapse navbar-collapse"</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"navbarNav"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"navbar-nav ms-auto"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/"</span>
              &gt;</span>
                Home
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/projects'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>
              &gt;</span>
                Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/career'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/career"</span>
              &gt;</span>
                Career
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/services'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/services"</span>
              &gt;</span>
                Services
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/research'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/research"</span>
              &gt;</span>
                Research
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"nav-item"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">nav-link</span> ${
                  <span class="hljs-attr">location.pathname</span> === <span class="hljs-string">'/contact'</span> ? '<span class="hljs-attr">active</span>' <span class="hljs-attr">:</span> ''
                }`}
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/contact"</span>
              &gt;</span>
                Contact
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">nav</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Navbar;
</code></pre>
<p>The navbar component has your navigation links, which lets you navigate between pages using <code>react-router</code>.</p>
<p>Alright, the component codebase is ready! All that remains is the six page routes in our pages folder.</p>
<p>The first file we’ll work on will be the <code>Career.jsx</code> file. I will split the codebase for readability like before, so copy the different sections starting with the first part here:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Chat"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Career</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialMessage =
    <span class="hljs-string">"Hello! I'm CareerAgent, the career specialist. I can provide information about skills, experience, and professional background. What would you like to know?"</span>;

  <span class="hljs-keyword">const</span> [currentQuestion, setCurrentQuestion] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> askCareerQuestion = <span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
    setCurrentQuestion(<span class="hljs-string">`<span class="hljs-subst">${question}</span> [<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>]`</span>);

    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      setCurrentQuestion(<span class="hljs-string">""</span>);
    }, <span class="hljs-number">500</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div className="flex flex-col md:flex-row gap-8 mb-12"&gt;
        &lt;div className="md:w-1/3"&gt;
          &lt;h1 className="text-3xl font-bold mb-4"&gt;Career&lt;/h1&gt;
          &lt;p className="text-lg mb-4"&gt;
            Here you can find information about my professional background,
            skills, and experience. Feel free to ask CareerAgent for more
            details.
          &lt;/p&gt;
        &lt;/div&gt;
        &lt;div className="md:w-2/3"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                Chat with CareerAgent
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                Our career specialist can provide information about skills,
                experience, and professional background.
              &lt;/p&gt;
              &lt;Chat
                agentType="career"
                initialMessage={initialMessage}
                agentInitials="CA"
                directQuestion={currentQuestion}
              /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div className="mb-12"&gt;
        &lt;div className="mb-6"&gt;
          &lt;h2 className="text-2xl font-bold mb-4"&gt;Skills&lt;/h2&gt;
        &lt;/div&gt;
        &lt;div className="grid grid-cols-1 md:grid-cols-3 gap-6"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden h-full"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-4"&gt;
                Frontend Development
              &lt;/h5&gt;
              &lt;ul className="divide-y divide-gray-200"&gt;
                &lt;li className="py-3 flex justify-between items-center"&gt;
                  React
                  &lt;span className="px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"&gt;
                    Expert
                  &lt;/span&gt;
                &lt;/li&gt;
                &lt;li className="py-3 flex justify-between items-center"&gt;
                  Vue.js
                  &lt;span className="px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"&gt;
                    Advanced
                  &lt;/span&gt;
                &lt;/li&gt;
                &lt;li className="py-3 flex justify-between items-center"&gt;
                  Angular
                  &lt;span className="px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"&gt;
                    Intermediate
                  &lt;/span&gt;
                &lt;/li&gt;
                &lt;li className="py-3 flex justify-between items-center"&gt;
                  TypeScript
                  &lt;span className="px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"&gt;
                    Advanced
                  &lt;/span&gt;
                &lt;/li&gt;
                &lt;li className="py-3 flex justify-between items-center"&gt;
                  CSS/SASS
                  &lt;span className="px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"&gt;
                    Expert
                  &lt;/span&gt;
                &lt;/li&gt;
              &lt;/ul&gt;
              &lt;button
                className="mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"
                onClick={() =&gt;
                  askCareerQuestion(
                    "Tell me more about your frontend development skills"
                  )
                }
              &gt;
                Ask About Frontend Skills
              &lt;/button&gt;
</code></pre>
<p>Like before, we have imports, states, and some components. Now for the second part, which is here:</p>
<pre><code class="lang-javascript"> &lt;/div&gt;
          &lt;/div&gt;
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-4"</span>&gt;</span>
                Backend Development
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"divide-y divide-gray-200"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Node.js
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Expert
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Python
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Advanced
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Django
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Intermediate
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Flask
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Advanced
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  SQL/NoSQL
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Advanced
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askCareerQuestion(
                    "Tell me more about your backend development skills"
                  )
                }
              &gt;
                Ask About Backend Skills
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span></span>
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-4"</span>&gt;</span>Other Skills<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"divide-y divide-gray-200"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  DevOps
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Intermediate
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  UI/UX Design
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Advanced
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Project Management
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Advanced
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Agile Methodologies
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Expert
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                  Technical Writing
                  <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"px-2.5 py-0.5 bg-blue-500 text-white text-xs font-medium rounded-full"</span>&gt;</span>
                    Intermediate
                  <span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askCareerQuestion("What other skills do you have?")
                }
              &gt;
                Ask About Other Skills
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span></span>
        &lt;/div&gt;
      &lt;/div&gt;
</code></pre>
<p>There is a lot more component code here for the career page. Lastly, lets add the last part of the code for this page:</p>
<pre><code class="lang-javascript">&lt;div className=<span class="hljs-string">"mb-12"</span>&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold mb-4"</span>&gt;</span>Experience<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-start mb-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold"</span>&gt;</span>
                  Senior Full-Stack Developer
                <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2020 - Present<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-3"</span>&gt;</span>Tech Innovations Inc.<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700 mb-4"</span>&gt;</span>
                Lead developer for multiple web and mobile applications,
                managing a team of 5 developers. Implemented CI/CD pipelines and
                improved development workflow efficiency by 30%.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askCareerQuestion(
                    "Tell me more about your experience at Tech Innovations Inc."
                  )
                }
              &gt;
                More Details
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-start mb-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold"</span>&gt;</span>Full-Stack Developer<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2017 - 2020<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-3"</span>&gt;</span>WebSolutions Co.<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700 mb-4"</span>&gt;</span>
                Developed and maintained multiple client websites and web
                applications. Specialized in React frontend development and
                Node.js backend services.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askCareerQuestion(
                    "Tell me more about your experience at WebSolutions Co."
                  )
                }
              &gt;
                More Details
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-start mb-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold"</span>&gt;</span>Junior Web Developer<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2015 - 2017<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-3"</span>&gt;</span>Digital Creations Ltd.<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700 mb-4"</span>&gt;</span>
                Worked on frontend development for e-commerce websites. Gained
                experience with JavaScript, CSS, and responsive design
                principles.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askCareerQuestion(
                    "Tell me more about your experience at Digital Creations Ltd."
                  )
                }
              &gt;
                More Details
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
      &lt;/div&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 gap-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-4"</span>&gt;</span>Education<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-start mb-1"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-medium"</span>&gt;</span>
                  Master of Science in Computer Science
                <span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2013 - 2015<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>University of Technology<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-start mb-1"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-medium"</span>&gt;</span>
                  Bachelor of Science in Software Engineering
                <span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2009 - 2013<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600"</span>&gt;</span>State University<span class="hljs-tag">&lt;/<span class="hljs-name">p</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">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                askCareerQuestion(
                  "Tell me more about your educational background"
                )
              }
            &gt;
              Ask About Education
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-4"</span>&gt;</span>Certifications<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"divide-y divide-gray-200"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                AWS Certified Solutions Architect
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2022<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                Google Cloud Professional Developer
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2021<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                Microsoft Certified: Azure Developer Associate
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2020<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 flex justify-between items-center"</span>&gt;</span>
                Certified Scrum Master
                <span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-500 text-sm"</span>&gt;</span>2019<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                askCareerQuestion("Tell me more about your certifications")
              }
            &gt;
              Ask About Certifications
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Career;
</code></pre>
<p>And this completes our <code>Career.jsx</code> page: we have forms and more components in this part of the code.</p>
<p>Next is our <code>Contact.jsx</code> page. Like before, I will split the codebase for readability, so add the first part of this code to it:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Contact</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> [formData, setFormData] = useState({
    <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">subject</span>: <span class="hljs-string">""</span>,
    <span class="hljs-attr">message</span>: <span class="hljs-string">""</span>,
  });
  <span class="hljs-keyword">const</span> [formResponse, setFormResponse] = useState(<span class="hljs-literal">null</span>);

  <span class="hljs-keyword">const</span> handleChange = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    <span class="hljs-keyword">const</span> { id, value } = e.target;
    setFormData(<span class="hljs-function">(<span class="hljs-params">prevData</span>) =&gt;</span> ({
      ...prevData,
      [id]: value,
    }));
  };

  <span class="hljs-keyword">const</span> handleSubmit = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();

    setFormResponse({
      <span class="hljs-attr">type</span>: <span class="hljs-string">"success"</span>,
      <span class="hljs-attr">message</span>:
        <span class="hljs-string">"Thank you for your message! I'll get back to you as soon as possible."</span>,
    });

    setFormData({
      <span class="hljs-attr">name</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">email</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">subject</span>: <span class="hljs-string">""</span>,
      <span class="hljs-attr">message</span>: <span class="hljs-string">""</span>,
    });

    <span class="hljs-built_in">document</span>
      .getElementById(<span class="hljs-string">"form-response"</span>)
      .scrollIntoView({ <span class="hljs-attr">behavior</span>: <span class="hljs-string">"smooth"</span> });
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div className="flex flex-col md:flex-row gap-8 mb-12"&gt;
        &lt;div className="md:w-2/3"&gt;
          &lt;h1 className="text-3xl font-bold mb-4"&gt;Contact Me&lt;/h1&gt;
          &lt;p className="text-lg mb-4"&gt;
            Have a question or want to discuss a potential project? Feel free to
            reach out using the form below or through any of my social media
            channels.
          &lt;/p&gt;
        &lt;/div&gt;
        &lt;div className="md:w-1/3"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-4"&gt;Quick Links&lt;/h5&gt;
              &lt;div className="flex flex-col gap-2"&gt;
                &lt;a
                  href="/projects"
                  className="py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 text-center transition-colors"
                &gt;
                  View Projects
                &lt;/a&gt;
                &lt;a
                  href="/services"
                  className="py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 text-center transition-colors"
                &gt;
                  Services &amp; Pricing
                &lt;/a&gt;
                &lt;a
                  href="/research"
                  className="py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 text-center transition-colors"
                &gt;
                  Research &amp; Resources
                &lt;/a&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-12"&gt;
        &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
          &lt;div className="p-6"&gt;
            &lt;h5 className="text-xl font-semibold mb-4"&gt;Contact Form&lt;/h5&gt;
            &lt;form id="contact-form" onSubmit={handleSubmit}&gt;
              &lt;div className="mb-4"&gt;
                &lt;label
                  htmlFor="name"
                  className="block text-sm font-medium text-gray-700 mb-1"
                &gt;
                  Name
                &lt;/label&gt;
                &lt;input
                  type="text"
                  className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                  id="name"
                  placeholder="Your Name"
                  required
                  value={formData.name}
                  onChange={handleChange}
                /&gt;
              &lt;/div&gt;
</code></pre>
<p>We have our imports, functions, and part of the components here. Lastly, add the second part to complete this page:</p>
<pre><code class="lang-javascript">&lt;div className=<span class="hljs-string">"mb-4"</span>&gt;
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                  <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"email"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>
                &gt;</span>
                  Email
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span></span>
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">input</span>
                  <span class="hljs-attr">type</span>=<span class="hljs-string">"email"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"</span>
                  <span class="hljs-attr">id</span>=<span class="hljs-string">"email"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"your.email@example.com"</span>
                  <span class="hljs-attr">required</span>
                  <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.email}</span>
                  <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                /&gt;</span></span>
              &lt;/div&gt;
              <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                  <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"subject"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>
                &gt;</span>
                  Subject
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</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">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"</span>
                  <span class="hljs-attr">id</span>=<span class="hljs-string">"subject"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Subject"</span>
                  <span class="hljs-attr">required</span>
                  <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.subject}</span>
                  <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                /&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
              <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                  <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"message"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>
                &gt;</span>
                  Message
                <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"</span>
                  <span class="hljs-attr">id</span>=<span class="hljs-string">"message"</span>
                  <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span>
                  <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Your message..."</span>
                  <span class="hljs-attr">required</span>
                  <span class="hljs-attr">value</span>=<span class="hljs-string">{formData.message}</span>
                  <span class="hljs-attr">onChange</span>=<span class="hljs-string">{handleChange}</span>
                &gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">textarea</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
              <span class="xml"><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">className</span>=<span class="hljs-string">"px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors"</span>
              &gt;</span>
                Send Message
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
            &lt;/form&gt;
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>
              <span class="hljs-attr">id</span>=<span class="hljs-string">"form-response"</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>
              <span class="hljs-attr">style</span>=<span class="hljs-string">{{</span> <span class="hljs-attr">display:</span> <span class="hljs-attr">formResponse</span> ? "<span class="hljs-attr">block</span>" <span class="hljs-attr">:</span> "<span class="hljs-attr">none</span>" }}
            &gt;</span>
              {formResponse &amp;&amp; (
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">{</span>`<span class="hljs-attr">p-4</span> ${
                    <span class="hljs-attr">formResponse.type</span> === <span class="hljs-string">"success"</span>
                      ? "<span class="hljs-attr">bg-green-100</span> <span class="hljs-attr">text-green-700</span>"
                      <span class="hljs-attr">:</span> "<span class="hljs-attr">bg-red-100</span> <span class="hljs-attr">text-red-700</span>"
                  } <span class="hljs-attr">rounded-md</span>`}
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-check-circle-fill mr-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
                  {formResponse.message}
                <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              )}
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
          &lt;/div&gt;
        &lt;/div&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-4"</span>&gt;</span>
                Contact Information
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-3"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-envelope mr-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                    <span class="hljs-attr">href</span>=<span class="hljs-string">"mailto:contact@example.com"</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"text-blue-500 hover:underline"</span>
                  &gt;</span>
                    contact@example.com
                  <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex items-center"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-geo-alt mr-2"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span>
                  UK
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mt-6 mb-3"</span>&gt;</span>
                Connect on Social Media
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-wrap gap-2"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"px-3 py-1.5 border border-gray-800 text-gray-800 rounded-md hover:bg-gray-100 flex items-center transition-colors"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-github mr-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span> GitHub
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"px-3 py-1.5 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 flex items-center transition-colors"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-linkedin mr-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span> LinkedIn
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">a</span>
                  <span class="hljs-attr">href</span>=<span class="hljs-string">"#"</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"px-3 py-1.5 border border-gray-800 text-gray-800 rounded-md hover:bg-gray-100 flex items-center transition-colors"</span>
                &gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">i</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bi bi-twitter mr-1"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">i</span>&gt;</span> X
                <span class="hljs-tag">&lt;/<span class="hljs-name">a</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">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-3"</span>&gt;</span>Availability<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700 mb-3"</span>&gt;</span>
                I'm currently available for freelance work and consulting. My
                typical response time is within 24 hours.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700"</span>&gt;</span>
                For urgent inquiries, please call the phone number listed above.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
      &lt;/div&gt;
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Contact;
</code></pre>
<p>With that, this page is now done, and we have the rest of the components and form.</p>
<p>Ok just four pages left: let’s work on the home page first. The code is not that big so we can do it all at once.</p>
<p>This is the code to add to the <code>Home.jsx</code> page file:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { Link } <span class="hljs-keyword">from</span> <span class="hljs-string">'react-router'</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">'../components/Chat'</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Home</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialMessage =
    <span class="hljs-string">"Hello! I'm WelcomeAgent, the welcome specialist. I can help you navigate this portfolio website. Are you an employer, client, or fellow programmer?"</span>;

  <span class="hljs-keyword">return</span> (
    <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>
      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col md:flex-row gap-8 mb-12"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:w-1/3"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h1</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-3xl font-bold mb-4"</span>&gt;</span>Welcome to my Portfolio<span class="hljs-tag">&lt;/<span class="hljs-name">h1</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg mb-4"</span>&gt;</span>
            This portfolio showcases my work and skills with the help of
            specialized AI agents. Each agent is designed to assist you with
            different aspects of my portfolio.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-700"</span>&gt;</span>
            Feel free to interact with the WelcomeAgent to get personalized
            recommendations on which sections of the portfolio to explore based
            on your interests.
          <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"md:w-2/3"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>
                Chat with WelcomeAgent
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
                Our welcome specialist can help you navigate this portfolio
                website.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Chat</span>
                <span class="hljs-attr">agentType</span>=<span class="hljs-string">"welcome"</span>
                <span class="hljs-attr">initialMessage</span>=<span class="hljs-string">{initialMessage}</span>
                <span class="hljs-attr">agentInitials</span>=<span class="hljs-string">"WA"</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">div</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">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-12"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold mb-4"</span>&gt;</span>Meet the Agents<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-3 gap-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"agent-avatar-placeholder mb-4"</span>&gt;</span>PA<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>ProjectAgent<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 text-center"</span>&gt;</span>
                Provides detailed information about my projects, technologies
                used, and challenges overcome.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-auto py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              &gt;</span>
                View Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"agent-avatar-placeholder mb-4"</span>&gt;</span>CA<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>CareerAgent<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 text-center"</span>&gt;</span>
                Shares information about my skills, experience, and professional
                background.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/career"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-auto py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              &gt;</span>
                View Career
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col items-center"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"agent-avatar-placeholder mb-4"</span>&gt;</span>BA<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>BusinessAdvisor<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 text-center"</span>&gt;</span>
                Provides information about services, pricing, and client
                engagement process.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/services"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-auto py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              &gt;</span>
                View Services
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</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">div</span>&gt;</span>

      <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 gap-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>Featured Projects<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              Check out some of my recent work:
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"divide-y divide-gray-200"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>E-commerce Platform<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>Task Management Application<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>Data Visualization Dashboard<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/projects"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-block py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              &gt;</span>
                View All Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>Research &amp; Insights<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              Explore my research on emerging technologies and industry trends:
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"divide-y divide-gray-200"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>AI in Web Development<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>Modern Frontend Frameworks<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">li</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"py-3 px-2"</span>&gt;</span>Cloud Architecture Patterns<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">Link</span>
                <span class="hljs-attr">to</span>=<span class="hljs-string">"/research"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"inline-block py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              &gt;</span>
                View Research
              <span class="hljs-tag">&lt;/<span class="hljs-name">Link</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">div</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">div</span>&gt;</span>
    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Home;
</code></pre>
<p>This has the code for our home page and WelcomeAgent.</p>
<p>Alright, now let's work on the <code>Projects.jsx</code> page. For readability it's easier to split the code in half again. So here is the first part:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Chat"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Projects</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialMessage =
    <span class="hljs-string">"Hello! I'm ProjectAgent, the project specialist. I can provide detailed information about projects, technologies used, and challenges overcome. What would you like to know?"</span>;

  <span class="hljs-keyword">const</span> [currentQuestion, setCurrentQuestion] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> askProjectQuestion = <span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
    setCurrentQuestion(<span class="hljs-string">`<span class="hljs-subst">${question}</span> [<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>]`</span>);

    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      setCurrentQuestion(<span class="hljs-string">""</span>);
    }, <span class="hljs-number">500</span>);
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div className="flex flex-col md:flex-row gap-8 mb-12"&gt;
        &lt;div className="md:w-1/3"&gt;
          &lt;h1 className="text-3xl font-bold mb-4"&gt;Projects&lt;/h1&gt;
          &lt;p className="text-lg mb-4"&gt;
            Here you can explore my portfolio of projects. Feel free to ask
            ProjectAgent for more details about any project.
          &lt;/p&gt;
        &lt;/div&gt;
        &lt;div className="md:w-2/3"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                Chat with ProjectAgent
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                Our project specialist can provide detailed information about
                projects, technologies, and challenges.
              &lt;/p&gt;
              &lt;Chat
                agentType="project"
                initialMessage={initialMessage}
                agentInitials="PA"
                directQuestion={currentQuestion}
              /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div className="mb-12"&gt;
        &lt;div className="mb-6"&gt;
          &lt;h2 className="text-2xl font-bold mb-4"&gt;Featured Projects&lt;/h2&gt;
        &lt;/div&gt;
        &lt;div className="grid grid-cols-1 md:grid-cols-3 gap-6"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="project-image-placeholder"&gt;E-commerce Platform&lt;/div&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                E-commerce Platform
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                A full-featured e-commerce platform with product management,
                shopping cart, and payment processing.
              &lt;/p&gt;
              &lt;div className="flex justify-between items-center"&gt;
                &lt;div className="flex space-x-2"&gt;
                  &lt;button
                    type="button"
                    className="py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"
                    onClick={() =&gt;
                      askProjectQuestion(
                        "Tell me more about the E-commerce Platform project"
                      )
                    }
                  &gt;
                    View Details
                  &lt;/button&gt;
                  &lt;button
                    type="button"
                    className="py-1.5 px-3 text-sm border border-gray-500 text-gray-500 rounded-md hover:bg-gray-50 transition-colors"
                    onClick={() =&gt;
                      askProjectQuestion(
                        "What technologies were used in the E-commerce Platform project?"
                      )
                    }
                  &gt;
                    Technologies
                  &lt;/button&gt;
                &lt;/div&gt;
                &lt;span className="text-sm text-gray-500"&gt;2023&lt;/span&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="project-image-placeholder"&gt;Task Management App&lt;/div&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                Task Management Application
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                A collaborative task management application with real-time
                updates and team collaboration features.
              &lt;/p&gt;
              &lt;div className="flex justify-between items-center"&gt;
                &lt;div className="flex space-x-2"&gt;
                  &lt;button
                    type="button"
                    className="py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"
                    onClick={() =&gt;
                      askProjectQuestion(
                        "Tell me more about the Task Management Application project"
                      )
                    }
                  &gt;
                    View Details
                  &lt;/button&gt;
</code></pre>
<p>As previously mentioned, we have our imports, functions, and some components. Complete the page with the second part of the code here:</p>
<pre><code class="lang-javascript"> &lt;button
                    type=<span class="hljs-string">"button"</span>
                    className=<span class="hljs-string">"py-1.5 px-3 text-sm border border-gray-500 text-gray-500 rounded-md hover:bg-gray-50 transition-colors"</span>
                    onClick={<span class="hljs-function">() =&gt;</span>
                      askProjectQuestion(
                        <span class="hljs-string">"What technologies were used in the Task Management Application project?"</span>
                      )
                    }
                  &gt;
                    Technologies
                  &lt;/button&gt;
                &lt;/div&gt;
                <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>2022<span class="hljs-tag">&lt;/<span class="hljs-name">span</span>&gt;</span></span>
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"project-image-placeholder"</span>&gt;</span>Data Visualization<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>
                Data Visualization Dashboard
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
                An interactive dashboard for visualizing complex datasets with
                customizable charts and filters.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-between items-center"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex space-x-2"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                      askProjectQuestion(
                        "Tell me more about the Data Visualization Dashboard project"
                      )
                    }
                  &gt;
                    View Details
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                    <span class="hljs-attr">type</span>=<span class="hljs-string">"button"</span>
                    <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-gray-500 text-gray-500 rounded-md hover:bg-gray-50 transition-colors"</span>
                    <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                      askProjectQuestion(
                        "What technologies were used in the Data Visualization Dashboard project?"
                      )
                    }
                  &gt;
                    Technologies
                  <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">span</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-sm text-gray-500"</span>&gt;</span>2021<span class="hljs-tag">&lt;/<span class="hljs-name">span</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
        &lt;/div&gt;
      &lt;/div&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 gap-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>
              Technical Skills Showcase
            <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              These projects demonstrate proficiency in the following
              technologies:
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-2 gap-4"</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">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Frontend<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-disc pl-5 space-y-1"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>React<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Vue.js<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Angular<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>TypeScript<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>CSS/SASS<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Backend<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-disc pl-5 space-y-1"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Node.js<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Python<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Django<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Flask<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>MongoDB<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;/<span class="hljs-name">ul</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">div</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-4 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                askProjectQuestion(
                  "What other technologies are you proficient in?"
                )
              }
            &gt;
              Ask About Other Skills
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>Project Inquiry<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              Interested in a specific type of project or technology? Ask
              ProjectAgent for more information.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col space-y-3"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askProjectQuestion(
                    "Do you have any projects involving machine learning or AI?"
                  )
                }
              &gt;
                Ask About AI Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askProjectQuestion("What are your most challenging projects?")
                }
              &gt;
                Ask About Challenging Projects
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askProjectQuestion(
                    "Can you show me examples of your UI/UX work?"
                  )
                }
              &gt;
                Ask About UI/UX Work
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</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">div</span>&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Projects;
</code></pre>
<p>With the remaining components added, this page is now complete.</p>
<p>Its time to do the <code>Research.jsx</code> page, starting with the first half of the codebase:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Chat"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Research</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialMessage =
    <span class="hljs-string">"Hello! I'm ResearchAgent, the research specialist. I can provide information about technologies, trends, and industry news. What would you like to know?"</span>;
  <span class="hljs-keyword">const</span> [searchQuery, setSearchQuery] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [tech1, setTech1] = useState(<span class="hljs-string">""</span>);
  <span class="hljs-keyword">const</span> [tech2, setTech2] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [currentQuestion, setCurrentQuestion] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> askResearchQuestion = <span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
    setCurrentQuestion(<span class="hljs-string">`<span class="hljs-subst">${question}</span> [<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>]`</span>);

    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      setCurrentQuestion(<span class="hljs-string">""</span>);
    }, <span class="hljs-number">500</span>);
  };

  <span class="hljs-keyword">const</span> handleSearch = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-keyword">if</span> (searchQuery.trim()) {
      askResearchQuestion(<span class="hljs-string">`Search for information about: <span class="hljs-subst">${searchQuery}</span>`</span>);
      setSearchQuery(<span class="hljs-string">""</span>);
    }
  };

  <span class="hljs-keyword">const</span> handleCompare = <span class="hljs-function">(<span class="hljs-params">e</span>) =&gt;</span> {
    e.preventDefault();
    <span class="hljs-keyword">if</span> (tech1.trim() &amp;&amp; tech2.trim()) {
      askResearchQuestion(<span class="hljs-string">`Compare <span class="hljs-subst">${tech1}</span> vs <span class="hljs-subst">${tech2}</span>`</span>);
      setTech1(<span class="hljs-string">""</span>);
      setTech2(<span class="hljs-string">""</span>);
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div className="flex flex-col md:flex-row gap-8 mb-12"&gt;
        &lt;div className="md:w-1/3"&gt;
          &lt;h1 className="text-3xl font-bold mb-4"&gt;Research &amp; Insights&lt;/h1&gt;
          &lt;p className="text-lg mb-4"&gt;
            Here you can explore research on technologies, trends, and industry
            news. Feel free to ask ResearchAgent for more information.
          &lt;/p&gt;
        &lt;/div&gt;
        &lt;div className="md:w-2/3"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                Chat with ResearchAgent
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                Our research specialist can provide information about
                technologies, trends, and industry news.
              &lt;/p&gt;
              &lt;Chat
                agentType="research"
                initialMessage={initialMessage}
                agentInitials="RA"
                directQuestion={currentQuestion}
              /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-12"&gt;
        &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
          &lt;div className="p-6"&gt;
            &lt;h5 className="text-xl font-semibold mb-3"&gt;
              Search for Information
            &lt;/h5&gt;
            &lt;p className="text-gray-600 mb-4"&gt;
              Enter a topic to search for the latest information and insights.
            &lt;/p&gt;
            &lt;form onSubmit={handleSearch}&gt;
              &lt;div className="flex mb-4"&gt;
                &lt;input
                  type="text"
                  className="flex-grow px-3 py-2 border border-gray-300 rounded-l-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                  placeholder="e.g., WebAssembly, Edge Computing, etc."
                  value={searchQuery}
                  onChange={(e) =&gt; setSearchQuery(e.target.value)}
                /&gt;
                &lt;button
                  className="px-4 py-2 bg-blue-500 text-white rounded-r-md hover:bg-blue-600 transition-colors"
                  type="submit"
                &gt;
                  Search
                &lt;/button&gt;
              &lt;/div&gt;
            &lt;/form&gt;
          &lt;/div&gt;
        &lt;/div&gt;
        &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
          &lt;div className="p-6"&gt;
            &lt;h5 className="text-xl font-semibold mb-3"&gt;Compare Technologies&lt;/h5&gt;
            &lt;p className="text-gray-600 mb-4"&gt;
              Compare two technologies to understand their pros, cons, and use
              cases.
            &lt;/p&gt;
            &lt;form onSubmit={handleCompare}&gt;
              &lt;div className="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4"&gt;
                &lt;div&gt;
                  &lt;input
                    type="text"
                    className="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
                    placeholder="First technology"
                    value={tech1}
                    onChange={(e) =&gt; setTech1(e.target.value)}
                  /&gt;
                &lt;/div&gt;
</code></pre>
<p>We have our imports, state, functions, and some components for the ResearchAgent, so it's pretty straightforward. Now, we can complete the page by finishing it with the rest of the code:</p>
<pre><code class="lang-javascript">&lt;div&gt;
                  <span class="xml"><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">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"</span>
                    <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Second technology"</span>
                    <span class="hljs-attr">value</span>=<span class="hljs-string">{tech2}</span>
                    <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setTech2(e.target.value)}
                  /&gt;</span>
                &lt;/div&gt;
              &lt;/div&gt;
              <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors"</span>
                <span class="hljs-attr">type</span>=<span class="hljs-string">"submit"</span>
              &gt;</span>
                Compare
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span></span>
            &lt;/form&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-12"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold mb-4"</span>&gt;</span>Current Tech Trends<span class="hljs-tag">&lt;/<span class="hljs-name">h2</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-3 gap-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col h-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-3"</span>&gt;</span>
                AI in Web Development
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 flex-grow"</span>&gt;</span>
                Exploring how artificial intelligence is transforming web
                development practices and tools.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors self-start"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askResearchQuestion("Tell me about AI in web development")
                }
              &gt;
                Learn More
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col h-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-3"</span>&gt;</span>
                Modern Frontend Frameworks
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 flex-grow"</span>&gt;</span>
                Analysis of current frontend frameworks, their strengths, and
                ideal use cases.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors self-start"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askResearchQuestion("Compare modern frontend frameworks")
                }
              &gt;
                Learn More
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6 flex flex-col h-full"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-3"</span>&gt;</span>
                Cloud Architecture Patterns
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4 flex-grow"</span>&gt;</span>
                Best practices and patterns for designing scalable cloud-based
                applications.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors self-start"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askResearchQuestion("Explain cloud architecture patterns")
                }
              &gt;
                Learn More
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</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">div</span>&gt;</span></span>

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-3"</span>&gt;</span>Industry Trends<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              Stay updated on the latest trends in software development and
              technology.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                askResearchQuestion(
                  "What are the current trends in software development and technology?"
                )
              }
            &gt;
              Get Industry Trends
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Research;
</code></pre>
<p>The second half of the code has the remaining components, which complete the page.</p>
<p>Now for the final page which is for <code>Services.jsx</code>. The codebase is quite large so we will break it down.</p>
<p>And here's the first part of the codebase to add:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">import</span> { useState } <span class="hljs-keyword">from</span> <span class="hljs-string">"react"</span>;
<span class="hljs-keyword">import</span> axios <span class="hljs-keyword">from</span> <span class="hljs-string">"axios"</span>;
<span class="hljs-keyword">import</span> Chat <span class="hljs-keyword">from</span> <span class="hljs-string">"../components/Chat"</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">Services</span>(<span class="hljs-params"></span>) </span>{
  <span class="hljs-keyword">const</span> initialMessage =
    <span class="hljs-string">"Hello! I'm BusinessAdvisor, the client specialist. I can provide information about services, pricing, and project details. What would you like to know?"</span>;
  <span class="hljs-keyword">const</span> [projectDescription, setProjectDescription] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> [currentQuestion, setCurrentQuestion] = useState(<span class="hljs-string">""</span>);

  <span class="hljs-keyword">const</span> askClientQuestion = <span class="hljs-function">(<span class="hljs-params">question</span>) =&gt;</span> {
    setCurrentQuestion(<span class="hljs-string">`<span class="hljs-subst">${question}</span> [<span class="hljs-subst">${<span class="hljs-built_in">Date</span>.now()}</span>]`</span>);

    <span class="hljs-built_in">setTimeout</span>(<span class="hljs-function">() =&gt;</span> {
      setCurrentQuestion(<span class="hljs-string">""</span>);
    }, <span class="hljs-number">500</span>);
  };

  <span class="hljs-keyword">const</span> generateProposal = <span class="hljs-keyword">async</span> () =&gt; {
    <span class="hljs-keyword">if</span> (!projectDescription.trim()) <span class="hljs-keyword">return</span>;

    <span class="hljs-keyword">try</span> {
      <span class="hljs-keyword">const</span> response = <span class="hljs-keyword">await</span> axios.post(<span class="hljs-string">"/api/client/proposal"</span>, {
        <span class="hljs-attr">project_description</span>: projectDescription,
      });

      <span class="hljs-keyword">if</span> (response.data &amp;&amp; response.data.proposal) {
        askClientQuestion(
          <span class="hljs-string">`Can you provide a proposal for this project: <span class="hljs-subst">${projectDescription}</span>`</span>
        );
      }
    } <span class="hljs-keyword">catch</span> (error) {
      <span class="hljs-built_in">console</span>.error(<span class="hljs-string">"Error generating proposal:"</span>, error);
    }
  };

  <span class="hljs-keyword">return</span> (
    &lt;div&gt;
      &lt;div className="flex flex-col md:flex-row gap-8 mb-12"&gt;
        &lt;div className="md:w-1/3"&gt;
          &lt;h1 className="text-3xl font-bold mb-4"&gt;Services&lt;/h1&gt;
          &lt;p className="text-lg mb-4"&gt;
            Here you can find information about the services I offer. Feel free
            to ask BusinessAdvisor for more details about pricing, timelines,
            and project specifics.
          &lt;/p&gt;
        &lt;/div&gt;
        &lt;div className="md:w-2/3"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;
                Chat with BusinessAdvisor
              &lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                Our client specialist can provide information about services,
                pricing, and project details.
              &lt;/p&gt;
              &lt;Chat
                agentType="client"
                initialMessage={initialMessage}
                agentInitials="BA"
                directQuestion={currentQuestion}
              /&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div className="mb-12"&gt;
        &lt;div className="mb-6"&gt;
          &lt;h2 className="text-2xl font-bold mb-4"&gt;Services Offered&lt;/h2&gt;
        &lt;/div&gt;
        &lt;div className="grid grid-cols-1 md:grid-cols-3 gap-6"&gt;
          &lt;div className="bg-white rounded-lg shadow-md overflow-hidden h-full"&gt;
            &lt;div className="p-6"&gt;
              &lt;h5 className="text-xl font-semibold mb-2"&gt;Web Development&lt;/h5&gt;
              &lt;p className="text-gray-600 mb-4"&gt;
                Custom web application development using modern frameworks and
                best practices.
              &lt;/p&gt;
              &lt;h6 className="font-semibold mb-2"&gt;Technologies&lt;/h6&gt;
              &lt;ul className="list-disc pl-5 space-y-1 mb-4"&gt;
                &lt;li&gt;React&lt;/li&gt;
                &lt;li&gt;Vue.js&lt;/li&gt;
                &lt;li&gt;Node.js&lt;/li&gt;
                &lt;li&gt;Django&lt;/li&gt;
                &lt;li&gt;Flask&lt;/li&gt;
              &lt;/ul&gt;
              &lt;h6 className="font-semibold mb-2"&gt;Details&lt;/h6&gt;
              &lt;ul className="space-y-2 mb-4"&gt;
                &lt;li&gt;
                  &lt;strong&gt;Pricing Model:&lt;/strong&gt; Project-based or hourly
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;strong&gt;Price Range:&lt;/strong&gt; $5,000 - $50,000 depending on
                  complexity
                &lt;/li&gt;
                &lt;li&gt;
                  &lt;strong&gt;Timeline:&lt;/strong&gt; 4-12 weeks depending on scope
                &lt;/li&gt;
              &lt;/ul&gt;
              &lt;button
                className="mt-2 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"
                onClick={() =&gt;
                  askClientQuestion(
                    "Tell me more about your web development services"
                  )
                }
              &gt;
                Ask about Web Development
              &lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
</code></pre>
<p>We have more import statements, state, and components for our BusinessAdvisor AI agent. Onto the next part of this codebase here:</p>
<pre><code class="lang-javascript"> &lt;div className=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;
            <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>
                Mobile App Development
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
                Native and cross-platform mobile application development for iOS
                and Android.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Technologies<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-disc pl-5 space-y-1 mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>React Native<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Flutter<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Swift<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Kotlin<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Details<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-2 mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Pricing Model:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Project-based
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Price Range:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> $8,000 - $60,000 depending on
                  complexity
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Timeline:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> 6-16 weeks depending on scope
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-2 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askClientQuestion(
                    "Tell me more about your mobile app development services"
                  )
                }
              &gt;
                Ask about Mobile Development
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>
            <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
          &lt;/div&gt;
          <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden h-full"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>
                Technical Consulting
              <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
                Expert advice on architecture, technology stack, and development
                practices.
              <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Areas of Expertise<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"list-disc pl-5 space-y-1 mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>System Architecture<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Database Design<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Performance Optimization<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>Security Best Practices<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>DevOps Implementation<span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">h6</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"font-semibold mb-2"</span>&gt;</span>Details<span class="hljs-tag">&lt;/<span class="hljs-name">h6</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">ul</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"space-y-2 mb-4"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Pricing Model:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Hourly
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Price Range:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> $150 - $250 per hour
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">li</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Timeline:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> Ongoing or as needed
                <span class="hljs-tag">&lt;/<span class="hljs-name">li</span>&gt;</span>
              <span class="hljs-tag">&lt;/<span class="hljs-name">ul</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"mt-2 py-1.5 px-3 text-sm border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                  askClientQuestion(
                    "Tell me more about your technical consulting services"
                  )
                }
              &gt;
                Ask about Consulting
              <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span></span>
        &lt;/div&gt;
      &lt;/div&gt;
</code></pre>
<p>We can expect to see lots of component code here for the page, so lets finish it off with the final part now:</p>
<pre><code class="lang-javascript"> &lt;div className=<span class="hljs-string">"mb-12"</span>&gt;
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">h2</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-2xl font-bold mb-4"</span>&gt;</span>Client Engagement Process<span class="hljs-tag">&lt;/<span class="hljs-name">h2</span>&gt;</span>
        <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
        <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"grid grid-cols-1 md:grid-cols-4 gap-6"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 md:mb-0"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center text-xl font-bold mb-4"</span>&gt;</span>
                      1
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold mt-2 mb-1"</span>&gt;</span>
                      Initial Consultation
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-center"</span>&gt;</span>
                      Understanding your requirements and project goals
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 md:mb-0"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center text-xl font-bold mb-4"</span>&gt;</span>
                      2
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold mt-2 mb-1"</span>&gt;</span>
                      Proposal
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-center"</span>&gt;</span>
                      Detailed quote and project plan preparation
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 md:mb-0"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center text-xl font-bold mb-4"</span>&gt;</span>
                      3
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold mt-2 mb-1"</span>&gt;</span>
                      Development
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-center"</span>&gt;</span>
                      Regular sprints with client feedback
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-6 md:mb-0"</span>&gt;</span>
                  <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex flex-col items-center"</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-12 h-12 rounded-full bg-blue-500 text-white flex items-center justify-center text-xl font-bold mb-4"</span>&gt;</span>
                      4
                    <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-lg font-semibold mt-2 mb-1"</span>&gt;</span>
                      Delivery
                    <span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
                    <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 text-center"</span>&gt;</span>
                      Testing, deployment, and ongoing support
                    <span class="hljs-tag">&lt;/<span class="hljs-name">p</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">div</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">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"flex justify-center mt-8"</span>&gt;</span>
                <span class="hljs-tag">&lt;<span class="hljs-name">button</span>
                  <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 border border-blue-500 text-blue-500 rounded-md hover:bg-blue-50 transition-colors"</span>
                  <span class="hljs-attr">onClick</span>=<span class="hljs-string">{()</span> =&gt;</span>
                    askClientQuestion(
                      "Explain your client engagement process in detail"
                    )
                  }
                &gt;
                  Learn More About the Process
                <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</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">div</span>&gt;</span></span>
      &lt;/div&gt;

      <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full"</span>&gt;</span>
        <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"bg-white rounded-lg shadow-md overflow-hidden"</span>&gt;</span>
          <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"p-6"</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">h5</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-xl font-semibold mb-2"</span>&gt;</span>Request a Proposal<span class="hljs-tag">&lt;/<span class="hljs-name">h5</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"text-gray-600 mb-4"</span>&gt;</span>
              Interested in working together? Describe your project below and
              BusinessAdvisor will generate a custom proposal for you.
            <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
            <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">className</span>=<span class="hljs-string">"mb-4"</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">label</span>
                <span class="hljs-attr">htmlFor</span>=<span class="hljs-string">"project-description"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"block text-sm font-medium text-gray-700 mb-1"</span>
              &gt;</span>
                Describe your project:
              <span class="hljs-tag">&lt;/<span class="hljs-name">label</span>&gt;</span>
              <span class="hljs-tag">&lt;<span class="hljs-name">textarea</span>
                <span class="hljs-attr">id</span>=<span class="hljs-string">"project-description"</span>
                <span class="hljs-attr">className</span>=<span class="hljs-string">"w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"</span>
                <span class="hljs-attr">rows</span>=<span class="hljs-string">"5"</span>
                <span class="hljs-attr">placeholder</span>=<span class="hljs-string">"Enter project description..."</span>
                <span class="hljs-attr">value</span>=<span class="hljs-string">{projectDescription}</span>
                <span class="hljs-attr">onChange</span>=<span class="hljs-string">{(e)</span> =&gt;</span> setProjectDescription(e.target.value)}
              &gt;<span class="hljs-tag">&lt;/<span class="hljs-name">textarea</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">button</span>
              <span class="hljs-attr">className</span>=<span class="hljs-string">"py-2 px-4 bg-blue-500 text-white rounded-md hover:bg-blue-600 transition-colors"</span>
              <span class="hljs-attr">onClick</span>=<span class="hljs-string">{generateProposal}</span>
            &gt;</span>
              Generate Proposal
            <span class="hljs-tag">&lt;/<span class="hljs-name">button</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">div</span>&gt;</span>
      <span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
    &lt;/div&gt;
  );
}

<span class="hljs-keyword">export</span> <span class="hljs-keyword">default</span> Services;
</code></pre>
<p>Our services page is complete, and so is the application!</p>
<p>Make sure that the Python backend server is running, and then start your React frontend with the usual Vite run script here inside the <code>frontend</code> folder:</p>
<pre><code class="lang-shell">npm run dev
</code></pre>
<p>You should see the website up and running on <a target="_blank" href="http://localhost:5173/">http://localhost:5173/</a> with working AI agents on all pages (apart from the contact page, which does not have one). Remember that every time you use one of the AI agents to ask a question, it will use 1 API call on Groq Cloud, so check the <a target="_blank" href="https://console.groq.com/docs/rate-limits">Rate Limits</a> for the different LLMs.</p>
<h2 id="heading-conclusion">Conclusion</h2>
<p>Building a squad of AI agents for your website using platforms like Agno and Groq is a powerful way to showcase how innovative automated workflows can enhance user experience without spending a lot of money.</p>
<p>The combination of Agno and Groq provides a free route for exploring AI agents, which can be very beneficial. With Agno's no-code agent orchestration and Groq's super-fast inference, you can deploy AI-powered features that engage with visitors and make interactions easier.</p>
<p>So, whether it's a chatbot, content generator, or intelligent assistant, these tools are making it easier than ever to integrate AI into your brand. With the advancements that AI technology is making, being able to try out these free solutions will definitely keep you ahead and make your website truly shine as you continue to modernise your brand.</p>
<h3 id="heading-stay-up-to-date-with-tech-programming-productivity-and-ai">Stay up to date with tech, programming, productivity, and AI</h3>
<p>If you enjoyed these articles, connect and follow me across <a target="_blank" href="https://limey.io/andrewbaisden">social media</a>, where I share content related to all of these topics 🔥</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1741977770238/3766c236-f276-4939-996e-61ab1306cc26.png" alt="Andrew Baisden Software Developer and Technical Writer Social Media Banner" class="image--center mx-auto" width="1500" height="500" loading="lazy"></p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
