Building Conversio v2

Conversio is a AI chatbot. How did I build Conversio v2?

Building Conversio v2

Conversio v2 was built in 10 days.

This is Conversio v1. It is built with raw HTML, CSS & JavaScript on the frontend and messy spegetti code with Node.js on the backend, which wasn't a very good stack. It was very hard to iterate on, and very hard to build new features.

Then, t3.chat was released. It was a fantastic SPA (Single Page App) which also inspired me to build this.

Introducing Conversio v2

First, what stack should I choose? I went with the most familiar one for me, which is Next.js for frontend & Hono with Bun for backend.

That worked for a while and I managed to create a similar layout to the one before.

Massive Layout Changes

That might look cool, but it wastes a lot of space which can be really useful. I was also aiming for Chat Threads to persist so I changed it. It was now fullscreen & had a sidebar. (Thanks shadcn for the clean sidebar)

Enter Vite

To be honest, Next.js does not really work that well for SPAs.

So, I tried a new frontend stack: Vite & React Router. I spent quite a bit of time migrating to it, but it was worth it.

Making the website work

Vercel's AI SDK really glued the project together.

I made a React Context which wrapped around to extend it to provide support for Model Switching, Persisting Chat, etc.

I also Dexie, a wrapper for IndexedDB to persist chat data.

Combining these with a PWA, this makes it so that users can view pervious chats even without internet.

Auto-scrolling is done with useState and useEffect hooks, which are very useful.

Problem #1: Offline Access

Vite also have a plugin called vite-pwa, which help developer setup PWAs (Progress Web Apps) easily.
It enabled me to make the website work offline when installed as a PWA, which was really cool.

However, one problem with it is that React Router's manifest is not cached, which made it so the website couldn't load.

The workaround? I had to change its name from manifest-[hash].js to manifest.js which involved patching dependencies in order to cache it.

Problem #2: Creating Chats

Another problem I faced is creating new chats.

On the Home Page, there is a Text Box which on submit, will redirect you from / to /chat/[id] where the ID is randomly generated.

How could you pass the Initial Message from the home page to the new chat?

This solution took me ages to find. There is a hook called useNavigate, which returns the navigate() function where I can pass state to the new page.

However, this raised another problem too. When I refreshed on the new page, the state will still be there! This made it so that every time I refreshed, the AI would run again.

How did I fix it? I had to empty the states after reading them.

Problem #3: Generating Titles

Titles for chats are generated from the first message of the chat. For this, I used Gemini 2.0 Flash-Lite which is cheap & excellent for these tasks.

The system prompt I used is below, which guided the AI on how and what to generate.

Authentication

Some people would make their own authentication solution, some would use a hosted solution like Clerk, and some would use an open source one.

What did I pick? A few months ago, a new Framework Agnostic solution called better-auth released, which is now my go-to for authentication. It is pretty simple to setup and lets you use a lot of different databases, such as SQLite, PostgreSQL and MongoDB.

The only thing it lack is server sided APIs, but that is not such a big issue and is often a great product to use.

Premade Sign In and Sign Up Components

The Logged Out Experience

How do you handle logged out users? Give them a free all-you-can-eat buffet? (AKA Unlimited Messages)

Nope. So how do we limit people who aren't logged in? CAPTCHAs.

CAPTCHAs stand for Completely Automated Public Turing Test To Tell Computers and Humans Apart, which can help us verify that it is a real user that is interacting with your site.

In this case, when a logged out user tries to send their first message, we used Cloudflare Turnstile which is similar to a CAPTCHA.

We verify that they are a human (like they claimed), assign them a temporary User ID (stored in cookies), and give them 20 messages for free. After that, they'll have to login!

The Result

What's the result? A fully-fledged AI chatbot with all the basic features!

There's still a lot of new features that could be made such as:

  • Authentication
  • Chat Limits
  • Search
  • Sharing Chats
  • etc...

The possibilities are endless!

Head over to chat.iamevan.dev to test it out!

If you don't understand React yet, go and try it out!
It can be very useful in your programming career.

Thanks for reading!
- Evan