The source material provides a comprehensive guide to constructing a full-stack AI-powered chat application. It details the technologies employed, including Vue.js and Node.js, TypeScript, OpenAI’s API, Stream Chat, and a Neon Postgres database. The text outlines the development process, from setting up the backend API and frontend UI to implementing real-time chat, AI interactions with context, and database integration for persistent data. Deployment to Render for the backend and Vercel for the frontend is also covered, creating a complete development-to-deployment workflow.
Study Guide: AI-Powered Chat Application
Quiz
Instructions: Answer the following questions in 2-3 sentences each.
- What are the primary front-end and back-end technologies used in this chat application project? The front end utilizes Vue.js with Pinia for state management, while the back end is built with Node.js and Express. Both the front end and back end are developed using TypeScript for type safety and enhanced development experience.
- Explain the role of the OpenAI API in the Chat AI application. The OpenAI API is crucial for the artificial intelligence capabilities of the application. Specifically, it uses the completions API with the GPT-4 model to process user messages and generate intelligent and context-aware responses, providing the AI-powered chat functionality.
- What is Stream Chat, and what aspects of the application does it handle? Stream Chat, provided by getstream.io, is a service used for implementing the real-time chat features of the application. It handles aspects such as messaging, user management, and channels, abstracting away the complexities of building a real-time communication system.
- Why is a PostgreSQL database with Neon used in addition to Stream Chat’s features? While Stream Chat stores chat logs, the project sets up its own PostgreSQL database with Neon for persistent storage of users and chat history. Neon offers a serverless, scalable PostgreSQL solution with features like branching, giving the developers more control over their data.
- Describe the purpose of Drizzle ORM in this project. Drizzle ORM (Object-Relational Mapper) is used to interact with the PostgreSQL database provided by Neon. It simplifies database operations by allowing developers to work with JavaScript/TypeScript objects instead of writing raw SQL queries, and it’s also used for defining database schemas and running migrations.
- What are the key steps involved in setting up the back-end project using Node.js and TypeScript? Setting up the back end involves initializing a Node.js project with npm init, installing necessary dependencies like Express and TypeScript, configuring TypeScript with a tsconfig.json file, and defining scripts in package.json for development, building, and starting the server.
- Explain the purpose of environment variables and how they are used in this project. Environment variables are used to store configuration settings such as API keys (for OpenAI, Stream, and Neon) and the database URL, keeping sensitive information separate from the codebase. The dotenv package is used to load these variables from a .env file into the application’s process environment.
- Outline the process of registering a new user with Stream Chat in the back end. Registering a user involves creating an instance of the Stream Chat client using API keys, receiving the user’s name and email from the front end, generating a unique user ID (often derived from the email), checking if the user exists in Stream Chat, and if not, using the upsertUser method to create a new user with the provided details.
- Describe the flow of a user sending a message and receiving a response from the AI. When a user sends a message, the front end sends it to the back end’s /chat endpoint along with the user ID. The back end retrieves the user’s past messages for context, sends the conversation to the OpenAI API, receives the AI’s response, saves the interaction in the Neon database, and finally sends the AI’s reply back to the front end.
- What is the role of Pinia and the pinia-plugin-persistedstate in the front-end application? Pinia is a state management library for Vue.js that helps manage the application’s data in a centralized and reactive way. The pinia-plugin-persistedstate is used to automatically save and reload Pinia stores across page reloads, ensuring that user sessions and other relevant data persist.
Essay Format Questions
- Discuss the advantages of using a full-stack approach with technologies like Vue.js, Node.js, TypeScript, and cloud services like OpenAI, Stream, and Neon for building a real-time AI-powered chat application. Consider aspects such as development efficiency, scalability, and maintainability.
- Analyze the architectural design of the Chat AI application, focusing on the separation of concerns between the front end, back end, and the various third-party services integrated. Explain how these components interact to deliver the overall functionality.
- Evaluate the choice of using Stream Chat for the real-time messaging features versus building a custom solution. Consider the trade-offs in terms of development time, complexity, scalability, and the features provided by Stream Chat.
- Explore the process of integrating artificial intelligence into a web application using the OpenAI API. Discuss the steps involved, the role of the API key, the structure of the API requests and responses, and the importance of managing API costs and usage.
- Compare and contrast the use of a serverless PostgreSQL database like Neon with a traditional relational database setup. Discuss the benefits and potential drawbacks in the context of a modern web application like the AI-powered chat app, considering factors like scalability, cost, and operational overhead.
Glossary of Key Terms
- Full-Stack: Refers to the development of both the front-end (client-side) and the back-end (server-side) components of an application.
- AI-Powered Chat App: An application that uses artificial intelligence to understand and respond to user messages in a conversational manner.
- Vue.js: A progressive JavaScript framework used for building user interfaces and single-page applications.
- Node.js: A JavaScript runtime environment that allows JavaScript to be executed on the server-side.
- TypeScript: A statically typed superset of JavaScript that adds optional types, classes, and interfaces to JavaScript.
- OpenAI API: A service that provides access to advanced AI models, such as GPT-4, for various tasks including natural language processing and generation.
- Stream Chat: A platform that offers SDKs and APIs for building real-time chat, video, and audio functionalities into applications.
- Neon Database: A serverless PostgreSQL database platform designed for scalability and developer convenience.
- Pinia: A state management library for Vue.js, providing a reactive store for application data.
- State Management: The process of managing and organizing the data that drives an application’s user interface.
- Express: A minimal and flexible Node.js web application framework, providing a robust set of features for building web and mobile applications.
- API Key: A unique identifier used to authenticate and authorize access to an API service, such as OpenAI or Stream.
- Completions API (OpenAI): An endpoint in the OpenAI API that generates text based on a given prompt.
- GPT-4: A powerful large language model developed by OpenAI, capable of understanding and generating human-like text.
- SDK (Software Development Kit): A collection of tools, libraries, documentation, code samples, and processes that allow developers to create software for a specific platform or service.
- ORM (Object-Relational Mapper): A programming technique that converts data between incompatible type systems using object-oriented programming languages, simplifying database interactions.
- Drizzle ORM: A lightweight and type-safe ORM for TypeScript and JavaScript, used for interacting with SQL databases.
- Schema: A blueprint or structure that defines how data is organized within a database, including tables, columns, and their properties.
- Migrations: Scripts used to manage changes to a database schema over time, such as creating or altering tables.
- Serverless: A cloud computing execution model in which the cloud provider dynamically manages the allocation and provisioning of servers, allowing developers to focus on writing code without worrying about server infrastructure.
- Render: A cloud hosting platform used to deploy and host web applications and back-end services.
- Vercel: A platform for deploying and hosting front-end web applications and static sites.
- vite: A build tool and development server for modern web projects, known for its speed and efficiency.
- dotenv: A zero-dependency module that loads environment variables from a .env file into process.env.
- CORS (Cross-Origin Resource Sharing): A mechanism that allows restricted resources (e.g., fonts, JavaScript, etc.) on a web page to be requested from another domain outside the domain from which the first resource served.
- Middleware: Functions that have access to the request object (req), the response object (res), and the next middleware function in the application’s request-response cycle.
- Asynchronous Function: A function that can pause its execution while waiting for an operation to complete (like an API call) without blocking the main thread.
- Promise: An object representing the eventual completion (or failure) of an asynchronous operation and its resulting value.
- JSON (JavaScript Object Notation): A lightweight data-interchange format that is easy for humans to read and write and easy for machines to parse and generate.
- Postman: An API client used to test and interact with HTTP APIs.
- Regular Expression: A sequence of characters that define a search pattern, used for matching and manipulating text.
- State (Front-end): The data that represents the current condition or mode of the user interface.
- Action (State Management): Functions that modify the state in a state management system like Pinia.
- Mutation (Implicit in Pinia with Actions): The actual modification of the state in response to an action.
- Getter (State Management): Functions that derive computed values from the state without modifying it.
- Ref (Vue.js Composition API): A reactive and mutable reference that holds a value, used to track changes in data.
- Reactive Variable: A variable whose changes trigger updates in the user interface or other parts of the application.
- Component (Front-end): A reusable and self-contained building block of a user interface.
- Route (Front-end Routing): A mapping between a URL path and a specific view or component in a single-page application.
- Router (Vue Router): The official router for Vue.js, used for navigating between different views or components.
- Composition API (Vue.js): A set of additive, function-based APIs that allow flexible composition of component logic.
- Options API (Vue.js): The traditional way of structuring Vue.js components using options like data, methods, and computed.
- Emit (Component Communication): A mechanism for a child component to send events up to its parent component.
- Props (Component Communication): Data passed from a parent component down to its child component.
- HTTP Request: A message sent by the client (e.g., a web browser or application) to a server to request a resource or trigger an action.
- HTTP Response: A message sent by the server back to the client in response to an HTTP request.
- API Endpoint: A specific URL that represents an entry point for accessing resources or functionalities provided by an API.
- Context (in AI): The history of previous interactions or information that an AI model uses to understand and respond to the current input more effectively.
- Chat History: A record of past messages exchanged between the user and the AI.
Briefing Document: AI-Powered Chat App Development
This document provides a detailed review of the main themes and important ideas presented in the provided source, which outlines the development of a full-stack AI-powered chat application named “Chat AI.” The application utilizes Vue.js and Pinia for the frontend, Node.js and Express for the backend, TypeScript for both, OpenAI’s API (GPT-4) for AI capabilities, Stream Chat for real-time messaging, and Neon Database for a serverless PostgreSQL database. The document includes relevant quotes from the source.
Main Themes
- Full-Stack Development: The project encompasses the entire development lifecycle, from setting up the frontend and backend to database integration and deployment.
- “hey what’s going on guys so I got a really cool project for you today we’re going to be building a full stack AI powered chat app called chat Ai”
- Integration of Multiple Technologies: The application leverages a diverse set of modern technologies for different aspects of its functionality.
- Frontend: Vue.js (framework), Pinia (state management), TypeScript (language).
- Backend: Node.js and Express (framework), TypeScript (language).
- AI: OpenAI API (GPT-4 completions).
- Chat: Stream Chat (real-time messaging SDK).
- Database: Neon Database (serverless PostgreSQL), Drizzle ORM.
- Deployment: Render (backend), Vercel (frontend).
- AI-Powered Chat: The core functionality revolves around enabling users to interact with an AI for information and conversation.
- “we’re going to be building a full stack AI powered chat app called chat Ai”
- “for the whole artificial intelligence aspect we’re using the open AI API uh the completions API using gp4”
- Real-time Messaging: Stream Chat is employed to handle the real-time aspects of the chat application, including users, channels, and messaging.
- “for the whole chat aspect we’re using stream chat at getstream.io so stream offers sdks for powerful applications that Implement real-time chat as well as video and audio”
- Serverless Database: Neon Database provides a scalable and easy-to-set-up serverless PostgreSQL solution for storing user data and chat logs.
- “we’re going to set up our own database our postgres database with neon so neon offers serverless postgres databases that you can literally set up in like 10 seconds”
- DevOps and Deployment: The project covers the deployment process to platform-as-a-service providers.
- “at the very end we’re going to deploy the back end is going to go to render … and then the front end The View application will go to versel”
- Learning by Doing: The presenter encourages viewers to follow along with the tutorial as the best way to learn.
- “I would suggest you follow along with me I think that’s the best way to learn”
Most Important Ideas and Facts
- Application Demo: The presenter provides a quick demo showcasing user login (name and email), sending questions to the AI, maintaining conversation context, and saving chat history upon logout and return.
- “if I just say simply who was the 12th it’s going to know what I’m talking about”
- “if I were to log out or leave the chat and then come back with the same email my chat will be saved”
- Technology Stack Breakdown: A detailed list of technologies used on both the frontend and backend is provided.
- Frontend: Vue.js, Pinia, TypeScript.
- Backend: Node.js, Express, TypeScript.
- AI: OpenAI API (GPT-4 Completions API).
- Chat: Stream Chat (getstream.io).
- Database: Neon (serverless PostgreSQL), Drizzle ORM (for database interaction).
- Deployment: Render (backend), Vercel (frontend).
- External API Documentation: The presenter highlights the websites where documentation for the key technologies can be found:
- Stream Chat: getstream.io (Developers -> Chat Messaging -> Node.js).
- Neon Database: neon.pdf (implied to be accessible).
- OpenAI: platform.openai.com.
- API Key Management: The project requires generating and managing API keys for OpenAI, Neon, and Stream Chat.
- “we are going to have to generate API keys for open AI for neon and for stream so you might want to just just keep these websites open”
- Backend Setup:Project structure involves separate folders for the backend (chat-AI-API) and frontend (chat-AI-UI).
- npm init is used to initialize the Node.js backend.
- ES Modules (“type”: “module” in package.json) are used.
- Key backend dependencies include: express, cors, dotenv, stream-chat, openai, typescript, tsx, drizzle-orm, drizzle-kit, @types/node, @types/express, @types/cors.
- tsx is used to execute TypeScript on the backend.
- drizzle is the ORM for PostgreSQL, and drizzle-kit is its CLI.
- A tsconfig.json file is configured to specify TypeScript compilation options (ES Modules, target, output directory, source directory, strict mode).
- npm scripts are defined for development (dev: tsc –noEmit && tsx watch ./src/server.ts), build (build: tsc), and production start (start: node ./dist/server.js).
- A basic Express server is set up in server.ts with middleware for CORS, JSON parsing, and URL-encoded data.
- .env file is used to manage environment variables (e.g., PORT).
- Initial Git setup with .gitignore (excluding node_modules and .env).
- Register User Route (/register-user – POST):Registers a user with Stream Chat.
- Expects name and email in the request body.
- Uses the Stream Chat client (stream-chat library) initialized with API key and secret from environment variables.
- Generates a unique user ID from the email (replacing non-alphanumeric characters with underscores).
- Checks if the user exists in Stream Chat using chatClient.queryUsers.
- If the user doesn’t exist, it adds the user to Stream Chat using chatClient.upsertUser with the generated ID, name, email, and role (‘user’).
- Returns the user ID, name, and email.
- Send Message to AI Route (/chat – POST):Handles sending a message to the AI (OpenAI).
- Expects message and user ID in the request body.
- Initializes the OpenAI client (openai library) with the API key from environment variables.
- Verifies if the provided user ID exists in Stream Chat.
- Uses the OpenAI Chat Completions API (openai.chat.completions.create) with the gpt-4 model.
- Sends an array of messages to OpenAI, including the user’s message with the role ‘user’.
- Extracts the AI’s reply from the response (response.choices[0].message.content).
- Returns a JSON response with the AI’s reply.
- Database Integration (Neon and Drizzle):Installation of drizzle-orm, @neon-database/serverless, and drizzle-kit.
- Database configuration in src/config/database.ts using Neon and drizzle, connecting to the database URL from .env.
- Schema definition in src/db/schema.ts using pgTable, defining chats and users tables with their respective columns (ID, user ID, message, reply, created at for chats; user ID, name, email, created at for users).
- Type inference for insert and select operations using Drizzle.
- Drizzle configuration file (drizzle.config.ts) in the root directory, specifying the schema location, migrations folder (./migrations), dialect (‘postgres’), and database URL.
- Generating and running migrations using npx drizzle-kit generate and npx drizzle-kit migrate.
- Integrating database operations into the /register-user route to save user information in the Neon database after successful Stream Chat registration.
- Integrating database operations into the /chat route to save the chat message and AI reply in the Neon database.
- Get Messages Route (/get-messages – POST):Retrieves chat history for a specific user from the Neon database.
- Expects user ID in the request body.
- Uses Drizzle’s db.select().from(chats).where(eq(chats.user_id, userId)) to fetch messages for the given user ID.
- Returns an array of messages in the JSON response.
- Contextual Conversations: Implementation on the backend to fetch the last 10 messages for a user and include them in the prompt sent to OpenAI, enabling contextual conversations. The chat history is formatted for OpenAI, and the latest user message is added. The role for the AI in the conversation is specified as ‘assistant’.
- Frontend Development (Vue.js):Project creation using npx create-vue.
- Installation of frontend dependencies: vue, vue-router, pinia, pinia-plugin-persistedstate, axios, tailwindcss, @tailwindcss/aspect-ratio.
- Tailwind CSS setup involving importing tailwindcss in vite.config.js and @tailwind base, @tailwind components, and @tailwind utilities in src/style.css.
- Router setup in src/router/index.ts with routes for home (/) and chat (/chat) views.
- Pinia store setup in src/stores/user.ts for managing user ID and name with actions to set and clear the user, and persistence enabled.
- Home view (src/views/HomeView.vue) with a form for name and email, connected to the backend’s /register-user endpoint using Axios and updating the user store upon success, then redirecting to the chat view.
- Header component (src/components/Header.vue) with a logout button that clears the user store and redirects to the homepage.
- Chat store (src/stores/chat.ts) using the Composition API to manage chat messages, loading state, and functions to load previous chat history (/get-messages) and send new messages (/chat).
- Chat view (src/views/ChatView.vue) displaying messages, handling scrolling, and using a ChatInput component.
- Chat input component (src/components/ChatInput.vue) with an input field and a send button, emitting the message to the parent component.
- Formatting AI messages in the frontend (formatMessage function using regular expressions) to improve display of lists, bold text, etc., using v-html.
- Deployment:Backend deployment to Render: Configuring the build command (npm install && npm run build), start command (node dist/server.js), and environment variables from .env.
- Frontend deployment to Vercel: Selecting the Git repository, with automatic build settings (using Vite), and configuring the environment variable VITE_API_URL with the Render backend URL.
This detailed overview captures the comprehensive nature of the project, highlighting the interconnectedness of various technologies to build a modern AI-powered chat application.
Chat AI Application: Overview and Functionality
General App Overview
- What is Chat AI? Chat AI is a full-stack AI-powered chat application built to demonstrate how various technologies can be integrated to create a real-time conversational experience with an AI. Users can log in by providing their name and email, engage in chats with an AI, and their chat history is saved and persists across sessions using the same email.
- What are the main technologies used in Chat AI? The application utilizes a range of modern web development and AI technologies. On the front end, it employs Vue.js for the user interface and Pinia for state management, both written in TypeScript. The back end is built with Node.js and Express, also using TypeScript. For the AI aspect, it leverages the OpenAI API, specifically the gpt-4 model via the Completions API. Real-time chat functionality is provided by Stream Chat (getstream.io). The application also uses a Neon serverless PostgreSQL database to store user information and chat logs, interacting with it through the Drizzle ORM. Deployment is handled by Render for the back end and Vercel for the front end.
Core Functionality and Features
- How does user registration work in Chat AI? User registration in Chat AI is a straightforward process. Users provide their name and email through a form on the front end. This information is sent to the back end, which then registers the user with Stream Chat, assigning them a unique ID derived from their email. Additionally, the user’s ID, name, and email are stored in the Neon PostgreSQL database. No traditional password-based authentication is implemented in this demonstration.
- How does Chat AI handle the conversation with the AI? When a user sends a message, the front end transmits the message and the user’s ID to the back end’s /chat endpoint. The back end then retrieves the recent chat history for that user from the Neon database to provide context to the AI. It sends this context, along with the new user message, to the OpenAI API (using the gpt-4 model). The AI’s response is then sent back to the front end and also saved in the Neon database, associated with the user’s ID.
- Does Chat AI remember previous messages in a conversation? Yes, Chat AI is designed to maintain context within a conversation. Before sending a new user message to the OpenAI API, the back end fetches the recent chat history for that user from the Neon database. This history, along with the current message, is sent to OpenAI, allowing the AI to consider previous turns in the conversation when generating its response.
- How is chat data and user information stored in Chat AI? Chat AI uses a Neon serverless PostgreSQL database to persist data. When a user registers, their user ID (derived from their email), name, and email are stored in a users table. Every message sent by a user and the corresponding AI reply are stored as a record in a chats table, linked to the user by their ID. This ensures that chat history is saved and can be retrieved for ongoing conversations and across user sessions.
Development and Deployment
- How are the front end and back end of Chat AI structured? The Chat AI project is structured with a clear separation between the front end and back end. The front end UI, built with Vue.js, resides in a chat-ai-ui folder, while the back end API, using Node.js and Express, is located in a chat-ai-api folder. This separation allows for independent development, testing, and deployment of each part of the application.
- How is Chat AI deployed? The back end of Chat AI is deployed using Render. The Render configuration specifies the build command (npm install && npm run build) to compile the TypeScript and the start command (node dist/server.js) to run the server. Environment variables, such as API keys for OpenAI, Stream Chat, and the Neon database URL, are configured in Render. The front end, built with Vue.js, is deployed using Vercel. Vercel automatically handles the build process (vite build) and serves the static assets. The API URL for the back end (the Render-provided URL) is set as an environment variable in Vercel.
Chat AI: Development and Deployment of an AI Chat App
The sources detail the development and deployment of an AI-Powered Chat App called Chat AI. This full-stack application allows users to log in by providing their name and email, and then engage in conversations with an AI. The AI can answer questions and maintain context within a single chat session. User chats are saved, so if a user logs out and returns with the same email, their previous chat history is retained.
Here’s a breakdown of the technologies and functionalities involved:
Functionality:
- User Interaction: Users can input text-based questions or statements.
- AI Response: The app uses the OpenAI API, specifically the completions API with the GPT-4 model, to generate responses to user input.
- Context Management: The backend is designed to retain conversation history within a user’s session, allowing the AI to understand follow-up questions. This is achieved by fetching past messages and including them in the prompt sent to OpenAI.
- Chat Interface: The app utilizes Stream Chat from getstream.io to handle the messaging aspect, including users and channels.
- Data Persistence: User information and chat logs are stored in a PostgreSQL database hosted on Neon, a serverless platform. The Drizzle ORM is used to interact with this database, manage schemas, and run migrations.
- User Registration: When a user enters their name and email, the backend registers this user with Stream Chat and also saves their information in the Neon database. A unique user ID is generated based on the user’s email.
- Chat History Retrieval: The backend provides an endpoint to retrieve the chat history for a specific user from the Neon database.
- Deployment: The backend, built with Node.js and Express, is deployed to Render. The frontend, built with Vue.js, is deployed to Vercel.
Technologies Used:
- Frontend:
- Vue.js: A JavaScript framework for building the user interface.
- Pinia: For state management on the frontend, allowing for a global store to manage user and chat data. Pinia Persisted State is used to persist the user’s login status across page loads.
- TypeScript: Used for type checking on the frontend.
- Vite: A build tool and development server for the Vue.js application.
- Vue Router: For handling navigation between different views (homepage and chat page).
- Axios: An HTTP client for making API requests to the backend.
- Tailwind CSS: A utility-first CSS framework for styling the application.
- Backend:
- Node.js: A JavaScript runtime environment for the backend.
- Express: A web application framework for Node.js used to build the API.
- TypeScript: Used for type checking on the backend. TSX is used to execute TypeScript code.
- CORS: Middleware to enable cross-origin requests between the frontend and backend.
- dotenv: To load environment variables from a .env file.
- Stream Chat (getstream.io): A platform providing SDKs for implementing real-time chat features. The Node.js client library (stream-chat) is used to interact with Stream Chat’s API for user management and channel creation.
- OpenAI API: For the artificial intelligence capabilities, using the openai Node.js client to interact with the completions API and the GPT-4 model.
- Neon Database: A serverless PostgreSQL database used for storing user data and chat logs.
- Drizzle ORM: A TypeScript ORM used to interact with the PostgreSQL database, define schemas, and perform database operations. Drizzle Kit is used as a CLI for Drizzle to generate migrations.
AI Implementation:
- The backend receives user messages and sends them to the OpenAI API using the gpt-4 model.
- Previous chat messages for a user are fetched from the database and included in the prompt sent to OpenAI to maintain context. The conversation history is formatted according to the OpenAI API’s requirements, with roles specified as “user” and “assistant”.
- The AI’s response is then sent back to the frontend and also stored in the Neon database along with the user’s message.
Chat Implementation:
- Stream Chat is used to manage users and create channels for conversations.
- When a user registers, they are also registered as a user in Stream Chat.
- When a user sends a message, a unique channel is created or retrieved for that user (identified by chat- and their user ID).
- Both the user’s message and the AI’s response are sent as messages within this Stream Chat channel.
This project demonstrates a comprehensive approach to building an AI-powered chat application, covering frontend development with Vue.js, backend development with Node.js and Express, integration with AI and chat service providers, database management, and deployment.
Chat AI Application: A Full-Stack Development Example
Based on the sources and our previous discussion about the Chat AI application, full-stack development refers to the process of building a complete web application that encompasses both the frontend (client-side) and the backend (server-side), as well as the database that supports them. A full-stack developer is proficient in working with all these layers of the application.
The development of the Chat AI application serves as a practical example of full-stack development. The project involved building:
- The Frontend (Chat AI UI): This is the user interface that users interact with directly in their web browsers. It was built using Vue.js, a JavaScript framework for building user interfaces. Key aspects of the frontend development included:
- Creating the user interface with components for the homepage (login/registration) and the chat page.
- Managing the application’s state using Pinia. This included managing user information (user ID, name) and chat messages. Pinia Persisted State was used to ensure user login status persists across page reloads.
- Handling routing between different pages (homepage and chat) using Vue Router.
- Making API calls to the backend using Axios to register users, send messages, and retrieve chat history.
- Styling the application using Tailwind CSS, a utility-first CSS framework.
- Using TypeScript for type checking to improve code quality and maintainability.
- Using Vite as a build tool and development server.
- The Backend (Chat AI API): This is the server-side logic that handles requests from the frontend, interacts with the database and external APIs (OpenAI, Stream Chat), and sends responses back to the frontend. It was built using Node.js and Express. Key aspects of the backend development included:
- Setting up API endpoints using Express to handle user registration (/register-user), sending chat messages (/chat), and retrieving chat history (/get-messages).
- Handling cross-origin requests using CORS to allow communication between the frontend and backend running on different domains.
- Loading environment variables using dotenv to manage API keys and database connection strings securely.
- Integrating with Stream Chat to manage users and channels for the chat functionality. This involved registering users with Stream Chat and creating unique channels for each user’s AI conversations.
- Integrating with the OpenAI API to generate AI responses to user messages using the GPT-4 model. This involved sending user prompts along with conversation history to maintain context.
- Interacting with the Neon PostgreSQL database using the Drizzle ORM to store and retrieve user data and chat logs. This included defining database schemas, running migrations using Drizzle Kit, and performing database queries.
- Using TypeScript for type checking on the backend, along with TSX for executing TypeScript code.
- The Database (Neon PostgreSQL): This is where the application’s data is stored and managed. In the Chat AI project, Neon, a serverless PostgreSQL platform, was used. The database stored user information and the history of conversations between users and the AI. The backend interacted with this database to persist and retrieve data.
Finally, full-stack development also includes deployment, making the application accessible to users over the internet. In the Chat AI project, the frontend was deployed to Vercel, and the backend was deployed to Render.
Therefore, the Chat AI application is a clear example of full-stack development, requiring the integration of various frontend and backend technologies along with a database to deliver a complete and functional user experience.
Chat AI Application: Real-Time Features via Stream Chat
Based on the sources and our conversation history, the Chat AI application incorporates real-time chat features through the use of Stream Chat from getstream.io. The source explicitly states that Stream Chat offers SDKs for powerful applications that implement real-time chat.
Here’s a breakdown of how real-time chat features are relevant to the Chat AI application based on the provided information:
- Stream Chat as the Foundation: The application uses Stream Chat to handle the entire messaging aspect. This includes managing users and channels, which are fundamental components of a chat system.
- Real-time Capabilities: Stream Chat is designed to provide real-time communication. While the current implementation described in the source focuses on a turn-based interaction with the AI (user sends a message, AI responds), the underlying technology of Stream Chat is capable of supporting more interactive and real-time scenarios if needed.
- Abstraction of Complexity: By using Stream Chat, the developers of Chat AI likely leveraged Stream’s SDKs to abstract away the complexities of building a real-time messaging infrastructure from scratch. This includes handling things like message delivery, user presence (if implemented), and channel management.
- Backend Integration: The backend of the Chat AI application (built with Node.js and Express) integrates with Stream Chat using Stream’s JavaScript client library (stream-chat). This allows the backend to register users with Stream Chat and create channels for the conversations.
- Potential for Expansion: Although the initial version focuses on AI interaction, the use of Stream Chat provides a foundation for potentially adding features like multi-user chat or other real-time communication elements in the future, as Stream Chat also offers video and audio capabilities.
In summary, Stream Chat is the key technology chosen for the Chat AI application to provide robust and scalable real-time chat features, even though the current implementation primarily showcases a single-user interaction with an AI. The use of Stream Chat simplifies the development of the messaging aspects of the application by providing pre-built SDKs and handling the underlying complexities of real-time communication.
Chat AI: Serverless PostgreSQL with Neon
Based on the sources and our conversation history regarding the Chat AI application, a serverless PostgreSQL database is a fully managed database service hosted in the cloud that offers on-demand scaling, automated management, and billing based on actual usage. The Chat AI application utilizes Neon as its serverless PostgreSQL database.
Here’s a breakdown of the discussion around Neon and its role as a serverless Postgres database within the context of the Chat AI project:
- Neon as the Chosen Database: The project explicitly states that it uses Neon for its cloud PostgreSQL database. It’s described as offering serverless PostgreSQL databases that can be set up very quickly, “literally in like 10 seconds”.
- Key Features and Benefits of Neon (as mentioned in the source):
- Easy Setup: Neon allows for a very rapid setup of a PostgreSQL database.
- Branching: Neon offers features like database branching, similar to code branching with Git, which is useful for development and testing new features without affecting the main database.
- Scalability: It is highlighted as being extremely scalable, implying that it can handle varying workloads automatically without requiring manual intervention.
- Data Persistence: The Chat AI application is configured to save user information and chat logs directly in the Neon database.
- Cloud-Based: Neon is a cloud postgres database, offering the benefits of cloud infrastructure such as reliability and accessibility.
- User-Friendly Interface: Neon provides an easy-to-use interface for setting up and managing databases. This includes the ability to run straight SQL queries directly through the interface.
- Integration with the Chat AI Application:
- The backend of the Chat AI application connects to the Neon database using a connection string. This connection string, including the database URL and password, is stored as an environment variable (DATABASE_URL) for security and configuration.
- The Drizzle ORM is employed to interact with the Neon PostgreSQL database. Drizzle is a TypeScript-based ORM that simplifies database operations.
- Drizzle Kit is used as a command-line interface (CLI) for Drizzle to create database schemas and run migrations. The schema, defining the structure of the chats and users tables, is created in TypeScript, and Drizzle Kit uses this schema to generate and apply the necessary SQL to the Neon database.
- The backend API includes endpoints to save user data into the users table and store chat logs (user messages and AI replies) in the chats table within the Neon database.
- Another API endpoint (/get-messages) retrieves the chat history for a specific user from the Neon database by querying the chats table.
In essence, Neon serves as the persistent data storage layer for the Chat AI application, providing a scalable, easily manageable, and feature-rich PostgreSQL database in a serverless environment. This allows the developers to focus on the application logic rather than managing the underlying database infrastructure. The integration with Drizzle ORM further streamlines database interactions within the TypeScript-based backend.
Cloud Deployment of a Chat AI Application
Based on the sources and our conversation history, the Chat AI application was deployed to the cloud using two separate platforms for the frontend and the backend.
Here’s a breakdown of the deployment process discussed in the source:
- Backend Deployment to Render:
- The backend, built with Node.js and Express, was deployed to Render (render.com).
- The deployment process on Render involved connecting the Render service to the GitHub repository containing the backend code (chat AI API).
- Specific build and start commands were configured for the Render deployment:
- Build Command: npm install && npm run build. This ensures that the dependencies are installed and the TypeScript code is compiled into JavaScript before running the server.
- Start Command: node dist/server.js. This specifies how to start the backend server, pointing to the compiled JavaScript file located in the dist folder.
- Environment variables crucial for the backend’s operation were configured in Render. This included the Stream API key and secret, the OpenAI API key, and the Neon database connection URL (DATABASE_URL). These environment variables allow the deployed backend to securely access necessary services and the database.
- After configuring these settings, the backend was deployed as a web service on Render. The source mentions that the deployment process can take a few minutes.
- Once deployed, Render provides a live URL (domain) for the backend API, which can then be accessed by the frontend. This was verified by making a request to the /get-messages endpoint using Postman and successfully retrieving data from the deployed API.
- Frontend Deployment to Vercel:
- The frontend, built with Vue.js, was deployed to Vercel.
- Similar to the backend, the deployment on Vercel involved connecting the Vercel platform to the GitHub repository containing the frontend code (chat AI UI).
- Vercel automatically handles the build process for Vue.js applications, typically using vite build as the build command, although the source indicates that the default settings were largely kept.
- An environment variable specific to the frontend, VITE_API_URL, was configured in Vercel. This variable was set to the live URL of the backend API deployed on Render, ensuring that the frontend communicates with the correct backend endpoint in the cloud. The VITE_ prefix is convention for Vite to expose environment variables to the frontend code.
- After configuring the API URL, the frontend application was deployed to Vercel. The source notes that the frontend deployment can also take a short amount of time.
- Upon successful deployment, Vercel provides a live URL for the frontend application, making it accessible to users via a web browser. The deployed frontend was tested by logging in, initiating a chat, and verifying that it could communicate with the backend and display responses.
In summary, the Chat AI application utilized a microservices-like deployment strategy, with the frontend and backend deployed independently to platforms optimized for their respective technologies. Render was chosen for the Node.js backend, providing a platform for running server-side applications with support for environment variables and custom build/start commands. Vercel was chosen for the Vue.js frontend, offering streamlined deployment for modern web applications with easy configuration of environment variables for API integration. This approach allows for independent scaling and management of the different parts of the full-stack application in the cloud.
The Original Text
hey what’s going on guys so I got a really cool project for you today we’re going to be building a full stack AI powered chat app called chat Ai and I’m just going to give you a quick demo before I explain anything so we just log in and and you just have to put your name and email and then we can go ahead and say something we’ll say like um we’ll say who we’ll say who was the 10th president of the US okay so it says AI is thinking and get back the 10th president of the US was John Tyler now it’s going to keep the context so if I just say simply who was the 12th it’s going to know what I’m talking about so the 12th President uh was Zachary Taylor all right and if I were to log out or leave the chat and then come back with the same email my chat will be saved all right now to achieve this we’re going to be using VJs and pinea for State Management on the front end and no. JS and Express on the back end and we’re using typescript on both the front end and backend now there’s a bunch of technologies that we need to incorporate to achieve this for the whole artificial intelligence aspect we’re using the open AI API uh the completions API using gp4 and then for the whole chat aspect we’re using stream chat at getstream.io so stream offers sdks for powerful applications that Implement real-time chat as well as video and audio and and this is just one of the many ways to use stream chat so like I said it’s going to handle the whole messaging aspect the users the channels now even though stream does store your chat logs and stuff we’re going to set up our own database our postgres database with neon so neon offers serverless postgres databases that you can literally set up in like 10 seconds and there’s features like branching it’s extremely scalable and we’re going to set it up so that our our project saves the users and the chats in the neon database and then we’ll be using the drizzle orm to interact with the database uh as well as create schemas run migrations and so on and then at the very end we’re going to deploy the back end is going to go to render so render doc um and then the front end The View application will go to versel all right so this is just an all-in-one Dev to deployment project I have the repositories for both the front end UI and the back backend API in the description so I would suggest you follow along with me I think that’s the best way to learn so let’s jump into it all right so I just want to quickly go over some of the websites where you can find the documentation for different parts of this project so first off we have stream chat which we’ll be using for all the chat aspects and you can find the docs at getstream.io if you go to Developers and we’re using the chat messaging there’s also video and audio capabilities if you want to check that out but if we go to chat messaging there’s all these platforms that we can choose from and we’re using it on the back end so you want to choose the the node.js option and then from here you have all different topics like users tokens permissions um creating channels and all that good stuff so that’s for stream chat and then for neon which is our Cloud postgres database you can go to neon.pdf here and then finally we have openai which is at platform. open.com and this is what we’re using for the whole AI aspect of it and we are going to have to generate API keys for open AI for neon and for stream so you might want to just just keep these websites open so let’s go ahead and just open up a terminal and just navigate to wherever you want to create this project and we’re going to have two separate folders for the back end and front end the back end will be chat AI API and the front end will be chat AI UI that’ll be the vue.js back end will be the node and expr Express so I’m going to put both in a parent folder so let’s create that so I’m going to say make directory and chat Ai and then CD into that chat AI folder and make another directory called chat AI uh- API and that will be our back end and I want to open that up in in vs code so I’m going to say code and then chat AI API and of course if you want to use a a different text editor that’s absolutely fine okay I’m going to be using my integrated terminal so I’ll go ahead and open that up and we just want to run npm in nit of course you need to have no JS installed and let’s go through this so package name version that’s good description let’s say this is going to be a backend for uh we say for an AI chat application and then s uh entry point I’m going to call server say server.js and then author you can put your own name if you want and MIT for the license so type I’m going to be using ES module so we want to put module instead of commonjs I mean if you want to use commonjs you can but um we’ll be using import all right so now that we’ve done that let’s install our dependencies and I just want to quickly go over what our backend dependencies are going to be so we have Express of course which is our backend web framework cores which which allows access to resources from a different origin that’s because our front end and back end will be on different domains EnV allows us to use environment variables from a EnV file stream chat is the official JavaScript client to work with stream chat in nodejs or in JavaScript and then open AI is the client to work with the open AI API typescript we’re going to be using on both the back end and front end a little bit more to the setup in the the back end but it’s not too bad we’re going to be using something called TSX to execute our typescript because even though with node.js version I think 23 um typescript is supported but all it really does is is strip your types it doesn’t actually compile it doesn’t execute it so that’s where TSX comes in if you want to use TS node or something else you can and then drizzle is the OM to interact with our postgis database and then drizzle kit is a CLI for drizzle and we’ll install the drizzle stuff a little later but let’s install some of these dependencies now so let’s say npm install Express we want what else cores we want EnV um stream chat so stream Das chat and also open AI I think that’s I think that’s all I want right now as far as regular dependencies now for for Dev dependencies let’s say npm install D- uppercase D and we want typescript and I’m also going to install TSX to execute the typescript and then for types we’ll do types SL node let’s say at types SL Express and also types slash cores now as far as uh as our typescript config goes we’re going to create our TS conf fig with npx and let’s say TSC D- init and I’m going to open that up and there’s I have a configuration that I’m going to use if you want to use the same one you can just get it from the link in the description the the GitHub repo but I’m going to paste this in so it’s pretty simple we’re going to I want to use es modules and all that all the latest features so using node next for module and module resolution and Es next for the Target our output directory when we compile our typescript is going to be slash and then our root directory where we write our code is going to be SL Source okay we’re using strict mode or strict type checking U and then we’re allowing importing commonjs modules we’re allowing importing of Json files as modules and we’re skipping the Declaration files in the node modules folder to speed up compilation so pretty simple setup we’ll go ahead and save that file and and then we want to create our scripts in package.json so we want a Dev script and of course with our Dev script we want to compile our typescript so we’re going to use TSC so the typescript compiler and then we’re going to add– no emit because we don’t actually want to produce JavaScript files when we run this we’re just running our Dev server and we just want to compile our typescript and we also need to run TSX as well and we’re going to run that in watch mode okay so no need for like node Monon or anything like that and then that’s going to be source and then server. TS will be the entry point so that’s what we want to run okay and then to build our project out to just compile we want to run just TSC and then the start script so to run in production is just going to be node and then it’ll be in a disc folder and it’ll be called server.js so that’s all we need for uh for our npm scripts all right so now let’s create a folder in the rout called Source that’s where we will write all of our code and let’s create our entry point which is going to be server. TS I mean if you don’t want to use typescript that’s fine we’re not doing too much as far as typescript goes so even if you’re not familiar with it you should be all right Honestly though it’s really becoming the standard so I mean you’re going to be creating TS files and TSX files all the time so I mean I would suggest learning the basics of typescript if you don’t know it so let’s just create a basic Express server so we want to import Express from Express and we want to import uh let’s see we want to import cores as well and we also want to import EnV and then we want to call env. config and then we’ll initialize our Express app so set that to express okay we need have some middleware to add so cores requires us to add an app.use and we’re also going to do app.use express. Json because we want to be able to um when we send a request we want to be able to send Json in the body we also want to be able to send form data so let’s also do app.use and say Express and then URL encoded and then just pass in an object with extended and set that to false all right and then we want to create our Port variable and I’m going to set the port in the EnV so I’ll say process. env. port or then use 5000 and then let’s just uh take our app and let’s listen on that Port whoops listen on Port and then when that happens we’ll just run a console.log and put in some btics here and we’ll say the server server running on and then output that Port variable all right so let’s um let’s create ourv so that’s going to go in the rout not in the source folder and from here we’ll say port and for now I’m just going to set it to 8,000 because I want to make sure that it’s actually reading this value so down at the bottom here at the terminal or wherever your terminal is let’s run npm run Dev okay so server running on 8,000 and it’ll compile any typescript we have obviously we don’t have any right now and before we start to add our route I just want to make my my first commit so I’m going to open up a new terminal here and let’s run and get a knit and then we’ll create our do get ignore uh CU you definitely don’t want to push thatv so let’s add not node modules and Dot EnV all right so I’ll say get add all get commit oh what’s this don’t care get commit and we’ll just say initial Express setup set up our initial Express and TS setup all right so now what we want to do is have make our first route and what this is going to do is it’s going to reach out to to stream chat and it’s going to register a user with stream okay because you can actually log into to your stream dashboard and you can see the users that were registered for um what is this doing here for your for your application and it when I say register it’s not traditional authentication where you’re going to have a password and stuff basically you come to the the app and you put in your name and email and then from there you get sent to the you know the the form to interact with the AI so let’s start by just creating a route now since we’re using typescript we’re also going to bring in from Express we want to bring in uh request and response uppercase R and let’s create our first route we’ll go down here let’s say I’ll put a comment let’s say register user with stream chat and it’s going to be a post request so app post and for the endpoint we’ll call this excuse me we’ll say SL register D user and then we’re going to have an async function here okay and then as far as what this returns will be a promise and we’re just going to add any to this and then it’s going to take in the request and response and we want to set those to those types so request and then res which will be response and then just to test it I’ll do a res. send and we’ll just say test okay so now we have our first endpoint now as far as how you test your endpoints it’s it’s really up to you I I like to use Postman and I have the postman extension for vs code so if I click on this icon right here I can make a a new HTTP request and it just opens up in a new tab which is nice so I’m going to make a post request to http and we want Local Host and I have it running on 8,000 and we want to do register Das user and you’ll see I get a 200 response and I get test so we know that that that route is working we also want to send an a name and email so why don’t we do a little bit of validation here we’ll say if or first of all let’s get the name and email so that’ll be in the request body so let’s say cons and then we’ll destructure the name and email from requestbody and then we’ll say if not name or not email then we want to send back an error so so we’ll return res Dot and let’s do a status of 400 which is a user error and then we’ll attach the Json uh let’s just put an error here and we’ll say name name and email are required and then after the if I’ll just do a res. status say 200 and Json message success all right so let’s try that out so if I just send as is I get the error but if I send a name and email in the body I can either do Json data or I can use the form URL encoded so I’m just going to add name and email and then send and I get success all right so now we want to start to work with stream we installed that you should have the stream client so if you just look in your dependencies you should have stream chat that’s what we’re going to use now in order to create an instance we have to we we need our API key so we’re going to have to go to the getstream.io and just you can log in with with either GitHub or Google so I’m already logged in I’m going to go to my dashboard and you don’t have to pay anything or enter any credit card info for this we want to create a new app and this has to be unique so I’m just going to say chat Dash uh we’ll say chat Ai and I’ll just do das Brad you could put your own name whatever it just it has to be unique and then just choose the locations for the the chat and video storage and feed storage that’s closest to you and click create app and then you’ll have your keys right here we have a key and a secret we need both of these so I’m going to copy the key I’m going to go into myv and we’re going to add stream API key and set that to the key and then we also want the stream API secret which we can get from right here just going to copy that okay so I’ll paste that in now that we have that we should be able to create an instance so let’s bring in the library so import or the client and that’s called stream chat and then we’re going to create it or initialize it right above our row let’s say initialize initialize the stream stream chat or stream client so we’ll say const we’ll call this chat client and I’m going to set that to the the stream chat stream chat Dot and then it’s get instance and then that’s going to take in your API key and your API secret so let’s say process Dov Dot and then stream API key and I’m going to put a bang on the end of this which is a nonnull assertion so I’m basically telling typescript that this is it’s not going to be null or undefined it’s definitely there and then we’ll do the same with the secret that gets passed in as well okay so now we should have our chat client initialize now we can use it in our route and the first thing I want to do is is create an ID because when you create a user it needs to have a unique ID and it’s up to you on what you want that ID to be I mean you could install a package like uuid but what I want to do is take the email you don’t have to type this out but let’s say that the email is Brad gmail.com then I want the ID to be brador gmailcom so that way we have a unique ID but it’s also readable it’s understandable all right so let’s um let’s do that so I actually want to after we do the if here let’s wrap this in a TR catch and I’ll move this this success I’m going to move that into the try and then let’s copy it and then in the catch if something goes wrong then I’m going to send a 500 error so let’s change the status to 500 and for the message we’ll just say or it’s actually going to be error so error we’ll say internal server error all right now in the try let’s generate the ID so we want to say user ID and we have access to the email that they enter so we’re going to use replace and replace takes in it’ll take in what we want to replace and what we want to replace it with so and we pass in a regular expression I know a lot of you guys and including myself hate regular Expressions but this is pretty simple so in Brackets we’re going to use the uh the carrot so basically we’re saying if not if it doesn’t match whatever I type here which is going to be a lowercase A to Z so a low lowercase letter or an uppercase A to Z or 0 to9 or an underscore or a dash if it’s anything other than that I want to replace it with an underscore and I want this I want it to be Global so I’m going to put SLG so the second argument you pass in is what you want to replace it with which in our case is going to be an underscore okay so that’ll generate the user ID in fact we can go ahead and do a console log of user ID just to check and then if I make a request again with this Brad at Gmail and I send if we look down in the console brador gmailcom and again if you want to do something different for IDs you can so yeah let’s get rid of the console log and now I want to check to see if the user exists in stream chat so let’s say check if user exists and we can do that let’s put this in user response and this is a synchronous so we want to do await and then chat client and then there’s a method called query users so we want to use that and then what we can do is pass in an object where we want to match the ID and we set that to an object with this money sign EQ so we’re saying if it equals the user ID and we can do a console log of that as well and then just go ahead and send and if we look down here you see it gives us an object with a duration and the user’s array which is empty because that the user doesn’t exist that um in my case it would be the Brad gmailcom doesn’t exist so what we can do after that after we check if the user exists or after we set that variable we’ll say if not user response. users. length so we’re saying if that array is empty then we want to add new user to stream so we can do that with the uh there’s a few different methods we can use I’m going to use upsert user which will create or update a user so let’s say chat client. upsert we want to do it’s just a single user so upsert user and then we’re going to pass in an object I’m going to assign the ID to the user ID which will be that formatted email the name set that to name and the email and then I’m also going to add the role of user because there’s there’s different roles there’s an admin user as well in fact if we look at the the docs here if I search for roll permissions let’s see yeah so right here buil-in roles so user is a default user role you have guest um you have admin which is a role for users that can perform administrative tasks with elevated permissions so we just want a a regular user now I should also mention that this is where you you can also generate a token so let’s see um we could call right here create token however we’re we’re using this on the server side with an API key so we don’t need to do this but if you were using this from you know react or view or some kind of front end then you would want to create a token and you’d want to save that and then send that with your um you know the rest of your requests so but we don’t have to do that so yeah I just want to return now basically just return the user ID the name and the email so let’s go right under that if actually we already have this we might as well just use that um yeah we’ll get rid of the message and let’s send the user ID the name and email and I think that should do it so we can try it out now so I’m going to come back here I’m going to register the user Brad gmail.com let’s click Send and I get back a 200 I get back my that’s my user id formatted from my email my name and the actual email now you should be able to actually log into your dashboard so if I go to my chat AI app here and under chat messaging if I go to Explorer you can see I have my chat AI Brad app has an app ID app name if I click users I got Brad 90 not sure where that came from but right here is the the user that I just created and it has all these fields it has the ID the name language role created at updated that if the user banned if they’re online if they’re invisible so lots of information uh and you can delete users too in fact I’ll delete that Brad 90 user oh it’s an original dashboard user okay so I can’t delete that all right so we’re able to to register users now for the chat and later on we’re also going to implement our neon postgres database so that it saves users there as well and it also saves all the chats all the logs but before we do that let’s create our chat route chat route so that we can send a question or or whatever it is we want to send to the AI and use the open AI API to respond to that so let’s first of all bring in the open AI client so up at the top here we’ll say import and it’s going to be open AI from open Ai and then we need to initialize open AI here as well just like we did with stream so right here I’ll say initialize open AI now we are going to need an API key so why don’t we do that real quick I’m going to jump over to platform. openai and log in so from here if we click on settings go to API Keys you should see them here um I’ll just create a new one let’s say chat and for project I’ll just use um project one okay so I’m going to copy that and then I’m going to go ahead and add that to myv so here let’s say opencore AI uh actually no let’s do open AI underscore and then API uncore key and then set that okay so now what we can do is initialize here let’s say const open a excuse me open AI set that to new uppercase o Open Ai and then pass in our API key which is going to be process.env do open aore API key okay so that’ll initialize that now let’s create our our chat route so I’m going to go under the register user and let’s say um what should I say here let’s say send message to Ai and this is going to be a post request as well so app post and the route is going to be just slash chat and then let’s say async okay I’m going to return say promise and any and then we’re going to pass in the request and res response all right so the first thing I want to do is get from the body there should be a message and there should be the user ID because when you register a user you get the ID and then you’re going to send that along to the chat route so let’s say const and let’s get the message and the user ID from the request. body and then we want to just make sure that that exists so we’ll say if not message or not user ID then we’re going to want to return let’s say status 400 and Json we’ll say message and user are required all right then we’re going to go under that if statement and let’s open up a TR catch and in the catch we’re going to I’ll just copy this response here except we’re going to change this to a 500 and then for the error for the error we’ll just say internal server error and in the try first thing we’re going to do is let’s say verify user exists so we’ll say const user response we want to set that to a wait on the chat client and then we’re going to use Query query users pass in an object we want the ID to match the user ID okay after we do that let’s check that response we’ll say if not user response remember it has an array called users so we’re going to check that we’re going to check the length and basically if it’s an empty array then we know the user isn’t hasn’t been found it doesn’t exist so let’s return res. status and four we’ll do 404 because it’s a not the user’s not found and then we’ll we’ll do Json and let’s pass in an error and for the error we’ll say user not found and we’ll say please register first all right now before we do anything else let’s just let’s just check if that works so we’ll just do a simple res. send and just say success okay so when we make our request now to slash chat it should reach out to stream and uh in the body I don’t have uh I don’t have anything so I should get this message and user are required so let’s add in the message I’m going to say what is the capital of Massachusetts and then for the user ID for the user ID I’m going to put a user that doesn’t exist I’ll just do one two three and if I send that I get user not found please register first now we know that the user ID for me brador gmailcom we know that that exists so let’s try that out and we get success so so far so good now what we want to do is start to work with open Ai and we’re going to use the chat completions API which will work like chat GPT you send it a prompt and it sends you a response so let’s go right here where I have the res. send and delete that and let’s send the message to open Ai and we’re going to be using the gp4 model so we’ll say con response and set that to await open AI and it’s going to be chat dot completions Dot and then create and then we want to pass in an object that has the model that we want to use which in this case is going to be GPT you have all these different options we’re going to do gp-4 so that’s the model we want and then we send messages which is going to be an array and we’re going to pass in an object here with a rle of the user and then the content is going to be the message all right so whatever we add in the message which in my request is just what’s the capital of Massachusetts now I want to show you what that gives us so why don’t we just do a console log of the response and then as far as what we return I’ll just let’s just do uh yeah we’ll just say res. send success okay I just want to see what what this gives us so let’s come back over here and I’m going to send the same response with the message and the correct user ID we get success but let’s take a look in the in the console here and we get this object has an ID blah blah blah what we care about is this right here this a choices array and there’s an one object in there with a message and we can’t see it here we just see object um yeah I don’t think we can see that so why don’t we log that so we got console log response and then it’s going to be dot choices which is an array we want the first and only item in that array and we want the message okay let’s send it again and there we go so we get an object with the role is assistant okay so it’s the the AI That’s responding has a role of assistant and then content is what we’re looking for the capital of Massachusetts is Boston all right so it’s as easy as that to to create a prompt and get back a response so now obviously we want to return that response from the endpoint so let’s come back in here we know how to access it now right with this it’s actually message. content that will give us the exact you you know what we’re looking for so let’s get rid of the console log here around this and let’s put this into a variable we’ll say const AI message and um let’s type that it’s going to be a string and set it to that so response choices message content now I am going to use um optional chaining here for for uh message so just add a question mark there and then we also want to use a nullish coalescing operator because if that happens to be null or whatever then we’re just going to make it no response from AI that’ll get rid of any typescript errors now before we actually send this AI message back from this endpoint we need to create a channel which is used for managing conversations in fact if we go to the docs here and we search for Channel and then creating channels so it shows us how to do that we store a reference in a variable using our client and then. channel pass in the type which is going to be messaging okay there’s different types if we come down here and look at type you have um live stream messaging team gaming Commerce messaging is is for like you know one-on-one conversations or group chats um that’s uh typical type for things like that and we’re having a one-on-one chat with it’s just not with a user it’s with the AI so that’s what we’re going to use and then once we store the reference we can then call channel. create and then we can actually do channel. send message as well which will send the message through through the channel it’ll get stored and so on so let’s um let’s do that let’s go right below the AI message and let’s say actually I’m going to just put a comment here let’s say create channel or it’s actually create or get channel and we’re going to create the reference with our chat client. channel the type is going to be messaging and we can also pass in a unique ID which I’m going to use back ticks and then just say chat Dash and then the um the user ID so that’ll be a unique identifier and then we want to pass in an object with the name of the channel which I’m going to call we’ll call it AI chat and then we also need to add this created uncore byor ID which if you were chatting with another user then it would be that user but since we’re using an AI we’re going to call it AI bot all right so that will will create the reference now we need to call channel. create like I just showed you in the docs and then after that we can do uh sorry this needs a wait and then after that we can do await channel. send message and pass in an object with the text which will be the AI message so AI message and then the user ID and make sure you do user uncore ID that’s what the key is it’s not camel case it’s underscore and then that’s going to be the AI bot that sends this message okay now as far as what we want to respond with let’s do res. J actually we’ll do status 200. Json and then pass in um an object oops passing an object with a reply and that reply will be the AI AI message oops not Al message AI okay so yeah that should do it and then I just want to do a console log here as well if there is an error let’s put um error generating AI response and then also the error all right cool so let’s try that out I’m going to come over here and I have I have my message I have my user id let’s go ahead and send and we get an object with the reply the capital of Massachusetts is Boston and what’s cool is now if we go back to the stream dashboard and if we go to you know chat messaging Explorer we have the AI bot user here and you can see under channels we have messaging so it’s that’s the type and then we have the unique identifier which is chat D Brad Gmail com because I set that right here right that’s the unique identifier and then we should be able to see any messages that are in through that channel so we have one message here and it shows the text which is the capital of Massachusetts is Boston so whatever the AI sent us back so pretty cool now what I’d like to do is Implement our own database I mean we do have the the you know you can see the chats and using stuff through stream but a lot of times you want to do more with it so you’ll want to store the chat logs in your own database so I want to expand this to to do that and also store our users so you want to create uh a postgres database through neon so I’m going to go ahead and log in here all right and then we’re going to go to well yeah I guess we’ll create a new project so once you log in and this interface is is so easy to use and it’s so easy to set up a database it’s basically just a couple clicks so I do want to create a new project I’ll call this uh tutorial and you can choose your postr G version I’m going to stick with 17 your database name I’m going to call this chat chat Aid DB and I’ll just choose AWS and then create and you can do a lot from this interface I mean you can run straight SQL queries there’s branching so just like you have branching with GitHub with your code you have branching with your databases so if you want to whatever add a new feature and you don’t want to affect the main branch you can just create a new Branch work with that once that’s all set and you know that’s what you want to use then you can merge the branches so really cool and what we want to do now is just click connect and that will give us our connection string so right here we want to copy this and actually let’s click show password too and then copy and we want to store that that uh reference to the the database the database string in ourv so let’s go in there and let’s call this database uncore URL and go ahead and paste that in all right right so now that we have that we need a way to interact with our database and that’s where drizzle comes in drizzle is an OM it’s typescript base it’s really easy to use um but one thing we do have to do since we’re using neon is use the neon database serverless adapter so we do have to install that as well so let’s come down to the terminal here and let’s run npm install and we want drizzle Das omm and then we also want to install at neon database SL serverless okay so it just allows us to to use um drizzle and to use this with with uh neon’s infrastructure and then we also want to install drizzle kit as a a Dev dependency so let’s say npm install Das uppercase D and then drizzle dkit and this is a CLI and we can run migrations from it and stuff okay so now that those are installed a couple things we have to do a few files we need to create so one is going to be our database config file which I’m going to put in the source folder I’ll create a new folder called config and then in that config we’ll have a database. TS file and this is where we configure That Neon database adapter so let’s go ahead and import a couple things here first one is going to be Neon and that’s going to be from this right here neon database SLS serverless then we want drizzle so import drizzle and let’s see we’re going to bring that in from drizzle omm and then it’s going to be slash neon HTTP and then we want to bring in from the dotv package we want to bring in the config function because we’re going to be using environment variables so let’s go ahead and load environment variables and we do that by calling config and then since I have this in you know in the source folder than in the config folder I’m just going to specify the path to the EnV file you can do that by passing in an object like this just say the path and it’s justv because it’s in the root okay cuz that’s going to start in the root all right then we just want to check for the database URL so if not process. env. database uncore URL then let’s throw a new error and we’ll say database uncore URL is undefined okay so we got that um next thing we want to initialize the neon client so actually going to put a comment here so init the neon client and we’re going to put that in a variable called SQL so we set that to Neon and that’s going to get passed in the database URL so process. EnV do database URL and then we need to initialize drizzle and that’s going to be exported because we’re going to be using this in other files so we’re going to call this uh variable of DB and then we set that to drizzle and that gets passed in the SQL variable which is the neon client so we can close that file up and now we want to create our schema and if you’ve used like Mongoose or SQL eyes or Prisma we create a a model or a schema of our data and then we can use drizzle kit to run the migration looking at that schema and it will create the tables for us so I’m going to put this um in let’s see we’ll have in the source folder I’ll have a folder called DB and then in DB will have a schema. TS file all right so let’s start off by importing what we need from drizzle so we need PG table which is going to create post postres tables for us and that’s going to come in from drizzle o/ PG core so in addition to that any Fields any field types that you want to use you bring in here so for instance serial which is what our primary key IDs are going to be and then text and then timestamp I believe those are the only ones we need so what we do now is export for any any table we want to create we export uh uh PG table function that takes in the name of the table and then all the fields we want to use so for instance for the chats let’s say const chats and we want to set that to PG table and the name of the table will be chats and then we pass in an object with all the fields that we want so for instance the ID is Going to Be A Serial type serial field and that’s going to be named ID and then I want that to be the primary key so we can tack on do primary key next thing we want is the user ID so that’s going to be text and user undor ID uh and then let’s see we’re that’s going to also be not null so we’ll tack that on then we have the message so let’s say message of the chat and this will be message as well then we want the reply which will be the you know the message that’s sent back from um from the the AI so that’ll be text as well and reply and not null all right and then the last thing I want here is created at so created at is going to be a Tim stamp and that’s going to also be called Crea underscore uh at and let’s add on to that I’m going to use default now which will do the current time stamp and that should also be any parenthesis there that should also be not null all right so that’s our our chats now let’s do the users because I want to store users as well so we’ll say con users not exports so cons user set that to um PG table and the name of the table will also be users and then we want to pass in all of our Fields so first thing is going to be the user ID which will be text and user ID for the column name and this is going to be the primary key so we want to add that all right then we get the name so name will be text as well name for the column name and not null all right then we got email so let’s change this and this to email and then we want a created at so I’m just going to copy this one because it’s the same thing okay so that those are the two schemas and the two tables we want to create now drizzle is is really great when it comes to typescript we can have our type inference in inference for drizzle queries so basically when we insert a chat for instance it’s going to be structured in a specific way with a specific type and we can add that here the type inference for the chat insert for the chat select for the user insert and for the user select so we want to export the so we can use them outside of this file and we’re going to say type and then chat insert and we want to set that to type of and then chats and we want this infer insert okay money sign infer insert and then we want to do the same for the chat select which is going to be infer select and change this to chat select okay and then we want to do the same thing for users so what I’ll do is just uh whoops what I’ll do is just grab both of these and copy those down and then we’re going to change this first one here to user insert and make sure we change this to users and then this one here change that to users and this one is going to be users select like that okay so that takes care of the type inference for those types for insert and selects now we want to create a config file for for drizzle or for drizzle kit because it needs to know where the scheme is are it needs to know um where the migrations will go things like that so that this is going to go in the root because that’s where it looks so in the root not in the source but in the root we’re going to create a drizzle. config dots all right and we want to import let’s see we’re going to be using EnV so we want to bring in the config from that so that’s going to be from EnV and then we’re going to import Define config and that’s going to come from drizzle kit and then let’s just run uh let’s say config because we’re going to be using the environment variables to get the database URL and again I’m just going to specify path and it’s just in the root. the EnV okay and then we want to export as default Define config and then that’s going to get passed in a couple things so first is going to be schema and that’s going to point to what we just created which is going to be from the root in the source folder and then in the DB and then schema schema. TS okay so that’s our schema um then we have out so this is going to be the migrations folder so just uh it’s going to be slash migrations all right then we have the dialect so dialect I mean you can use drizzle with different databases MySQL Etc we’re using postgres in fact you can see the options here so we’re going to use postgres and then the for the DB credentials that that’s going to be an object and we just need to provide the URL which is going to be our process uh process. env. database URL and let’s just add a bang on the end of that all right so that’s our config so we can close that up now since that drizzle config is in the root directory we are probably going to have an issue with typescript because it’s compiling the The Source folder right so we can run into an issue there so what we can do is exclude that file so under compiler options right so it ends right here so under compile options we’re going to add exclude and it’s going to be an array and we just want to add in that file so we want uh drizzle what is it drizzle. config dotx yes and that just cleared up that error that was there okay so now we have our schema created so that means that we’re ready to create our migration and when we create our migration we first generate it and then we we do drizzle kit generate and then drizzle kit migrate and that should actually create our tables for US based on this based on the schema so let’s try that let’s come down here and let’s run or we need npx and drizzle dkit and then we want to do generate first okay so your your SQL migration file so it created that here and then and you’ll see there’s a migrations folder here now then to actually migrate we want to do npx drizzle kit migrate all right so let’s see you can only connect to remote super B instances through web socket not exactly sure why it’s saying that it is a warning so let’s go to our neon dashboard and let’s check it out so if we go to tables and we have our chats yep chats table you can see the fields here ID user ID message and we have our users table okay so that worked I’m not exactly sure can only connect to remote neon versel postgress through a web socket um I guess I’m just not going to worry about that right now because it did work it created our tables from our schema which is what should have happened so now let’s integrate the database into our endpoints into the register user and into the chats because again we want to save the users we want to save the chats actually let’s bring in up top what we need to First okay so we’re going to import we want our DB right so DB which is going to come from our database now this is something that I want to mention when you’re using typescript with node with with TSX and you have the configuration that we do when you import a file because this is the first file that we’ve imported the rest have just been you know package modules so you it says JS even though it’s a TS file okay you can’t do import TS that’s not going to work it’s going to give you an error so even though it says JS everything to do with typescript compilation everything is just it still works fine this is just the syntax we have to use so in addition to that we want to bring in our schemas so chats and users and that’s going to come in from slash DB and then slash schema and again we’re going to do schema JS even though it’s a TS file and then let’s see what else do we need um there’s a utility called EQ to to basically compare values to compare the users and so on so that’s going to be EQ from drizzle omm and then what else do we have here uh the oh the chat completion message pram type so we’re going to bring that in as well so chat completion I don’t see it here completion message right here so that’s going to come from openai resources MJS actually we don’t need the MJS I don’t think yeah that should work okay so now that we we have our Imports let’s figure out where we actually want to use the database so we have our register user right so that creates a user with stream but again we want to also save the users in our own database so I’m going to go down right above the the response okay after we deal with all the stream stuff and let’s check for existing user in the database I know we checked for if it’s in stream but we also want to check in our own database so let’s say const existing user and I’m just going to close that up and we want to set that to a wait and this is where use the DB right so DB from our config file database config and then I’m going to call a few different methods on this one is Select so I want to select from the users table where so do where this is just the syntax of drizzle which I I like pretty clean so where now this is where we use that EQ utility so we want to pass in EQ and we want to see where users do user ID is equal to the user ID okay and that the user ID would be you know what we create from the email when a user is registered so it’s going to check for that and well it’s going to put it in this variable now let’s come down under it and let’s say if not existing user uh we’ll say if not existing user. length then let’s just um we’ll first off we’ll just do a console log and I’ll put some back ticks in here and we’ll say user and then the user ID uh we’ll say does not exist in the database and we’ll say adding them because that’s what we’re going to do all right so under that line let’s await DB and then we’re going to call insert and we want to insert into users where values okay so the values we want to add pass in an object here with the user ID the name and the email all right and that should be it so let’s save it now and I’m going to come back to uh to postman so let’s send a request so I’m going to make a post request to http we want to do register user and in the body for form data let’s add a name and an email okay so I’m going to go ahead and send that all right so I get back what I’m supposed to to now we want to check the database so let’s go to uh to Neon just going to reload this and there’s the user so user ID which is also the primary key the name email and the created ad so now not only are we do we have the users in the chat Explorer and stream we have it in our own database which we can do whatever we want with right and I had deleted the the user before so there it is again all right so in addition to the users in the database we also want to store the chats so let’s go back to server TS and let’s go down to the chat endpoint and figure out where we want to use the database here so let’s see we’re getting the user response here right then we check the user response so let’s go right under that and we’ll say check check user in database so again we’re going to do const actually I can just copy the the line of code I just put here okay so we’ll add that here and then um actually we can take what we put after that too which is this except we’re not going to create the user so we do have to change that so right under where we check the user let’s paste that and uh we’re going to get rid of this insert we don’t want to do that and then for the actually we’re not even going to do a console log we want to return an error if the user isn’t there so let’s say return and then res. status and we’ll do uh 404 and let’s do Json error and we’ll set the error we’ll say user not found in database please register first okay so we’re making it so that if the user isn’t in our postres database our neon database then it’s still it’s not going to let it happen right it has the user has to exist in stream and it has to exist in our database so now let’s go under where we get the AI message message and store that and let’s say save we’ll say save chat to database so to do that we can just say await db. insert we want to insert into the chats or the chats U table and then for values we’re going to add the user ID we want the message the reply uh actually reply we’re going to set that to AI message okay so we’re just taking whatever this is right and we’re just storing it as reply and that’s it so now we can try that out so I’m going to come over here and let’s go let’s make a request to slash chat and we’re going to change the stuff here so let’s say message and let’s do something different um Let’s do let’s do something a little more difficult like create a simple let’s see what should we do we’ll say create a simple rest API with python so that’s our message and then for the user ID I’m going to put my user which is going to be brador gmailcom so let’s try that out and it might take a couple seconds obviously the the more difficult the the answer the longer it’s going to take okay so we got our reply and it has a bunch of you know new line characters and stuff for formatting and we’ll we’ll when we create our UI with view we’ll have this displaying nicely so here’s a simple example on how to create a rest API using flask a microweb web framework in Python and it goes through and gives us the steps all right so we know that’s working now let’s make sure that that got saved to the database so we’ll go to Neon and I’m going to go to chats and there it is message create a simple rest API reply there’s the reply now since we implemented a database I’d like to add one more route to to get the messages of a specific user okay and we’re going to need that for our UI because obviously when you’re you know sending messages as a user you only want your messages so let’s create a new route we’re going to come down here and let’s say we want to get chat history for a user so app. poost and let’s see the the endpoint is going to be SLG get- messages and we want to do a sync return promise any okay I’ll pass in here our request so request Andre which will be response all right so what I’m going to do first is get it’s going to take a user ID so we’ll destructure the user ID from request. body because that needs to be sent with the body and then let’s check for the user ID or check if not you user ID and if not then we’re going to return res. status and we’ll do 400 and we’ll pass in an error and say user ID is required all right so if the user ID is there then let’s open up a try catch and let’s create a variable here we’ll call it chat history so chat history and then we want to await DB and then we’re going to select I’m going to go on the next line here so db. select and from okay we want to select from chats and let’s say where so where and we’re going to use EQ here CU we’re comparing so we want to to say where the chats. user ID is equal to the user ID and then we’re going to return actually we can just do res res. status 200. Json and let’s pass in we’ll do messages messages and set that to the chat history okay and then if there’s an error then we’re going to res. status 500 and let’s uh we’ll pass in an error and we’ll say internal server error and then I do want to just do a a console log as well so we’ll say um actually let’s do quotes and say error fetching chat history and we’ll output the error okay so that’s our get messages so let’s try that out I’m going to come over here post request to SLG get- messages and then we just want the user ID in the body so I’m going to go ahead and send and now it gives me back an array and you see we have id1 user ID message and then the apply I should have my other one here actually no I deleted the other one so let’s make another um let’s do another chat and then for the message make sure we check that let’s say what is the most popular JS framework send as of 20 okay so the 2021 is the cut off for this um it says the most popular JavaScript framework is react all right so now if I were to go back to get Dash messages with the user ID I should have both so create a simple rest API and what is the most popular JS framework okay so we have three routes we can we register a user we use that user to to chat to ask a question to the AI and then we have a an endpoint to to get all the messages of a specific user so that’s pretty much it as far as the back end there there’s a couple things later on while we’re doing the front end that I want to add to the back end but I think that I’ll be able to explain it better once we have the UI and I know that backend development like this can be a little tricky and can be a little weird because you don’t you’re not looking at like a user interface for your are the results of what you’re doing you’re just seeing a bunch of data so it can be can be tough for for some people so um if you if you’ve been confused through this don’t worry about it I mean it happens as you do more of it it’ll kind of Click but now what I’d like to do is jump into the front end create a whole new folder for our our chat AI UI and start to use vuejs okay so now we’re going to get into our front end and like I said we’re going to be using vue.js version three um we’re going to be using a couple other dependencies so let me just show you those real quick so view we’re using vit for our Dev server and environment we’re using pinf for our state management Library so we’ll be able to create a store for our users for our chats uh we’ll be able to have our actions and our state in those stores axios I’m using for my HTP Library although if you want to use fetch that’s fine too really doesn’t matter it’s just preference and then Tailwind CSS I’m using for The Styling so we will be be adding quite a bit of Tailwind classes to make it look nice view router we’re using the official router for view uh and we’re just going to have two routes two pages one is going to be the homepage with the form that has the email and the name so that you can you know enter your name to start chatting and then of course the chat route chat page where you interact with the AI and then typescript which we don’t have to set up at all it just works out of the box with vit so those are our frontend dependencies now I have the backend running so you definitely want to have that um this is just something I was testing out but you can see it’s mine’s running on Port 8000 and then I’m going to go into the chat AI folder and you can see I have the the back end that’s what’s running over here I want to create a folder alongside of this in my chat AI folder not inside the API folder that’s the back end this is completely separ separate so alongside that let’s go ahead and run npx and then I’m going to use create V and let’s call this chat D ai- UI okay this is the user interface part of our application and then we’re going to choose view I’m going to choose typescript although if you you want to use JavaScript that’s fine too and I mean even if you don’t know typescript it’s we’re not doing that much so you should be fine and and we already used it in the back end um and it’s much easier to set up I mean there really is no setup in the front end it just works so now let’s go ahead and CD into chat ai- UI and then let’s run our npm npm install to install our initial dependencies that come with v and then we’ll install a couple other dependencies as well all right so let’s go npm install and view- router we want pinf for our state management and there’s also a plugin called uh persisted State and we want to use this because we want our state our user to persist across page loads so we’re going to install pinea Das plugin Das persisted State and then also axios so those are our front end those are our regular dependencies and then for Dev dependencies it’s just tailwind and the plug-in for V for Tailwind so let’s do Dash uppercase D and then Tailwind CSS and then also at uh what is it at Tailwind CSS SLV and Tailwind version 4 is super easy to get set up with v okay so now that we have our dependency set up I’m going to actually just open this folder up in vs code and I’m going to run the dev server from the integrated terminal so from here let’s say NP say npm run Dev and it’s going to be 5173 for the port by default and I’m just going to make this going to just bring this over here make this a little smaller okay so this is just a landing page we’re going to get rid of the the boiler plate um what I do want to do is set up Tailwind which is really easy we just need to go into our V config first and we’re going to import uh Tailwind CSS from and then it’s going to be this at tailwind cssv and then we just need to add the plugin to the array here so Tailwind CSS parentheses and then the only other thing we need to do is go into our main stylesheet so in the source folder I want to go into style CSS and we can get rid of all this other stuff and just simply do at import and then in quotes take Tailwind CSS and that’s it and you can see Tailwinds working because there’s it’s all the same font size there’s no padding or or margin on the body so Tailwind is working all right now let’s just clear this up a little bit I don’t want the hello world component so we can completely delete that okay and then in the app. view we don’t want that I’ll leave the script tag there and then in the template uh actually we can get rid of this the scope style and then in the template for now let’s just have oops let’s just have an H1 and we’ll just say my app okay so just kind of clear everything out and in the assets we don’t need the view SVG you can get rid of that now I do have a little robot icon and logo that I want to use so let me just find that real quick you guys can get this from the the GitHub repository that that’s in the description let me just find it real quick uh let’s see Dev I’m just trying to find it off screen where we chat AI UI all right so it’s going to be in you have the fabicon which is in the root so just bring that over to your root and then you have um in the source assets folder there’s a robot PNG you’re going to bring that into your assets folder so it’s just this little robot guy all right now to add the fabcon we can go into the index HTML in our um in the root and I’m just going to change the page title to let’s do chat Ai and then for the fabicon we’ll just add a link and let’s change the real to Icon We’ll add a type of image slash it’s an Ico and then slash favicon Ico and then you should see the little robot in the tab all right so right off the bat I just want to set up routing okay because we’re using view router we’re going to have the home route we’re going to have a chat route so let’s start by creating those pages or those views so in the source we’re going to create a folder called views and then in there we’re going to create a file file called home let’s call it home view. viw Vue and then let’s create another file called chat view. viw okay and then I’m just going to have a script tag and then we’re going to add our setup so as far as vuejs goes this is not an intro to view I’m not going to explain the the basics um I have a view course A View crash course on YouTube that I just did it like a couple months ago so it’s really up to date if you don’t know anything or you know very little about VJs I would suggest watching that I mean you can watch it after if you want so you can kind of understand what you did but I would suggest watching it before but basically with the composition API which is a kind of a more Modern Way of of building view components you basically have to have in your script you would export uh a setup function right and then you do all your JavaScript all your state stuff you would do in here but you can do a shortcut by just adding setup here that’s why I’m doing that and then I’m also just going to add Lang and since I’m using typescript I’m going to add Lang TS and then I’m not even going to put anything in there for now then we have our template so basically the HTML we want to show on this in this component or in this page which right now I don’t really care we’ll just do an H1 and we’ll just say chat or chat page all right and then for the home view I’m just going to grab that and we’ll just change this to homepage all right because I I just want to get these created so that we can create set up our router so we can close those up for now and then for the router we’re going to have a folder in the source folder called router and then in that will have a file called index.ts and this is where we set up our routes now to do that we need to import a couple things so first off we need create router from view router and then we also want a function called create web history which allows us to use the the HTML 5 history API to to do routing instead of you know actual page loads and then we also want to bring in any views or any components that we want to load so that would be the home View and that would be the chat view okay then what then what we do is create an array for our routes so we’ll set that to an array and each route will have an object with a a path so in this case I want this to be just slash for the homepage and then we can load a component which our views are our components so let’s set that to the home View all right and then we’ll do the same thing for the chat view so let’s make this slash chat and this will be for the component chat view then what we want to do is export const router so this is what we bring into other files and this is where we want to set this to create router which is going to take in an object with history and we want to set that to the create web history again that’s going to use the the HTML 5 history API and that’s a function so you want your parenthesis and then you just want to pass in your routes as well all right and that’s it for that file now couple other things we need to do before we can actually use our router we need to initialize it in the main.ts file which is basically our entry point so in this file uh let’s see we’re going to bring in let’s bring in in and we want create router uh I’m sorry not create router just router we already used that in our router file that we just created and that’s what we’re bringing in here so router from. SL router now we have to use that so where we have this create app which bootstraps the entire application it mounts it to this this element with app um I’m going to just put this in a variable and then we’ll mount it down below so we’ll take this and we’ll do app. Mount here instead and that way we can take that app that app object and we can call use and then we can use the router okay so we got that done now the last thing to be able to see the routes on the page in the main app. view where we have this H1 we want to replace that with router View save that and now we see homepage because we’re on the the Home Route if I go to SL chat then we’re on the chat page and if you want to create just a quick navigation we can do nav and then we can use router link okay so router link we can add a two attribute here to slash and then we’ll have one to chat slash chat and then we should be able to click on chat takes us to the chat page home takes us to the the homepage now we do need to set up our store but before we do that let’s just get the form displayed on the hom page uh and we can get rid of this nav we don’t need that okay so let’s go into Let’s see we want to go into the home View and I’m going to bring in the that robot image because that’s going to be our logo so let’s import robot image from and then it’s going to be dot dot slass assets slash and then robot.png okay so we’ll bring that in and then let’s just start to add some of the the elements down here and use our Tailwind classes so we’re going to have a div that wraps everything get rid of this um div and then for classes here we’re going to do h- screen let’s make this a flex box and align everything to the center so items Das Center and justify Center I’m not going to explain what every Tailwind class does I have Tailwind crash courses I have a premium course if you want that but it’s pretty obvious what most of these classes do background we’re going to make gray let’s do 900 for the shade and then we’re going to do text white okay so that just gives us this dark background then inside that I’m going to have another div with a class of pad let’s do padding 8 and I’m going to do BG gray 800 make get a little lighter and rounded large let’s do shadow shadow large and let’s make it width Dash full and a Max width of medium all right whoops I don’t know what what happened oh need to do this all right so there’s our container for the form so in that div let’s have an H1 we’ll do text Dash let’s do 2XL for the sizing we’ll say font Das semibold let’s do uh margin bottom four and text Center and in that we’ll say welcome to chat AI all right oh I forgot the robot so let’s actually put above the the H1 I’m gonna have my image now since the source is going to be pointed to a variable right it’s Dynamic we need to bind it so we could either do a v-h on or we can just put a colon here and then set it to something Dynamic such as the robot image variable and then I’m just going to add a couple classes on this as well so let’s do MX so margin on the X Access Auto width 24 height 24 and then let’s do a margin bottom four and there we go so now I have the little robot guy and then let’s go under the H1 and we want to have our inputs so for the classes here we’re going to do Dash uh with Dash full let’s do padding two for margin bottom two and then I’m going to do a BG gray 700 so make it a little lighter the text will be white um let’s say round rounded Das large and then I’m also going to add a focus style so on Focus I want outline Das none okay uh yeah and then let’s add a couple other things so in addition to whoops what did I do here that should be there so I want to add a placeholder and it’s going to say name and then we want to buy this name to uh a reactive variable we want to we want to have a a piece of component State called name and we do that with v- model and we we’ll set that to name and we want to create that name variable up top here in the script so let’s say con name and we set that to ref okay we’re creating a reactive value so ref and then whatever the default is will go in here which is going to be an empty string now that ref we do have to import that from view so let’s bring that in that should be lowercase R okay there we go so now that gets bound to that if I put in you know hello here it’s going to show here because that is bound to that input okay and then we’ll have some other values here as well like the the uh email and let’s see do I want to add the rest of the stuff now um yeah uh might as well just copy this down so we’re going to have a loading state so basically when we reach out to our API we’re going to set loading to true and then when we get the result it’ll be set to back to false so let’s set this to ref default value will be false um and then I also want for ER if we have an error I want to have that in our state as well that’ll just be an empty string by default as well and then let’s come back down let’s create our email input so I’m going to take this copy it down let’s change the type to email and let’s see we’ll change placeholder to email and the V model to email so now this input is going to pertain or is going to be bound to this variable if I save it we see the email and then let’s create the button okay so right here let’s say say button and as far as classes go let’s do with- full let’s do padding to we’ll do BG blue Das 500 and rounded large all right and inside that I want it to say start chat but if it’s loading then I want it to show logging in okay and it’s not actually a login but you know what I mean creating the user or just getting the user so if you want to show something Dynamic uh within your view template you use double curly braces so here I can put a JavaScript expression like if it’s loading then show logging in dot dot dot else then show start chat so now we have our start chat button and then I also want to make this button disabled if loading is true so it’s going to be um Dynamic so I’m going to do colon disabled because what I’m setting this to is a is a variable right it’s loading so if I were to set loading up here I know a lot of you guys know this stuff but for those of you that are kind of new to view if I set that now it’s disabled and it says logging in so I’ll set that back to false all right now let’s see um for the error I want to show that down here in a paragraph So in the paragraph we can use a v if directive which is just like an if statement whatever I put in here in here will only show if this is true so for V if we just want to set that to error so if error is true then I just want to show the actual error and we’ll just add a class uh let’s add a class of text Dash red we’ll do red 400 and text Center and let’s do margin top two okay so if I have an error which we can test out by just putting something in here then it will show like that all right cool now that button is going to call a function so let’s go to the button here we’ll say at click so when we click this we’re going to call call a function called create user which doesn’t exist yet so we’re going to go up here and we want to create we want to create the create user function so here let’s say const create user we’ll set that to async an async function and let’s let’s check for the the name and email so we’ll say if not name and we can access the value with DOT value or if not email. value okay so if either one of those are not you know not added then I want to set an error so we’ll say error. value and we’ll set that to let’s say name and email are required and then we’ll just return okay and then I think you know what what I think that’s as far as I want to go because we don’t have our store yet cuz what we’re going to do is send a request to well we could you know what we’ll send the request I’m trying to think of how I want how the order I want to do this in do we want to do the store first yeah you know what before we do the request let’s do the store I mean we can test out this little validation if I were to click Start chat without putting anything then it’s going to give us an error but yeah let’s create our store so so basically when the data comes back from SL register user from our back end it’s going to be stored in our user store which we have yet to create so we’re using pinea which means we have to initialize it so we’re going to go into our main.ts which is right here and couple things we need to do um yeah we’ll go right here and let’s import here create pinea from pinea and then we also need that plugin which is pinea plugin persisted State that’s going to come from oops it’s going to come from uh this right here okay so we want to bring those in and then let’s go above this app let’s say const pinea set that to the create pinea function and then we should be able to take that pinea object and say do use and we can use the plugin so pinea plugin persisted State we want to pass that in and then the only other thing we need to do is use it just like we did the router so copy that down and pass in pinea okay I don’t have the code right in front of me but I’m pretty sure that’s that’s right all right so we’ll close that up now to create our store let’s go into the source folder create a folder called stores and for each resource we’ll have a file so I want to create a file called user. TS so this is where our Global State goes as well as any actions which are going to be functions that mutate the state in some way um so what we’re going to do is import Define store and that’s going to be from pinea all right and then we’re going to export let’s export const and we’re going to call this use user store and we want to set that to that defined store and then that’s going to take in a name of our of our store so user and then we pass in an object and this is where we can Define our state which is going to be set to an arrow function and some and it’s going to be set to an OB it’s going to return an object in that object we’re going to have our user ID and we’re using typescript so I’m going to say null as string or null so what we’re doing is using a type assertion and we’re defining it as null to begin with but we’re saying it can be null or string and then we’re going to do the same thing with the name okay so if you remember when we hit that register user route it sends back the user ID the name and the email we don’t need the email um in the the the project so I’m not going to store it in the in the store if you want to you can but I’m just going to leave it out for now so in addition to our state we want to have our actions so let’s put a comma here and then actions and actions is an object with functions in it to manipulate the state in some way so let’s create a function called set user and set user is going to take in a data object so for the type it’s going to be an object that has a user ID which will be a string and also name which will be a string and we can a access this right these values in our state we can access with this keyword so we can say this. user ID is going to be set to the user ID that’s passed in here uh I’m sorry it’s going to be be data. user ID okay and then we’ll do the same thing with the name so this set that so this.name is going to equal data. name then let’s go under set user because we also want to have a log out because we need we need a way to clear this state so here we’ll say this. user ID is equal to null and then this do name is equal to null and then the last thing we’re going to do is persist the state meaning that it’s going to the user will stay even if the page refreshes or reloads so we’re going to go right here put a comma and we can add in here persist and we’re just going to set that to true and I’ll put a little comment here and just say keep user logged in across um across page reloads and that yeah that should do it so that’s our user store and we’ll have a chat store later on so now let’s go back to our home View and we’re going to import the we want to import the use user store that we just created that’s going to be from and then dot dot slash stores sluser okay and then we’re going to be redirecting the user as well so we’re also going to import use router from view router now we have to initialize these two things so right here let’s say const user so user store set that to uh use user store um why is that oh it’s just I just haven’t used it right yeah okay so then also the router so let’s say cons router set that to use router all right now we have access to the user store so let’s make our request down here in the create user so after this if statement let’s first off set the loading value and set that to true because we’re now loading because we’re we’re making a request and let’s just make sure the error value is clear and then I’m going to use a tri catch for the request now for as far as the URL that we make the request to for me it’s going to be HTTP Local Host 8000 but when you go into production obviously that’s going to change so we should put that in an environment variable so let’s go into the root not the source but in the root and let’s create a EnV and here we’re going to say vit under so these are going to be prefixed with vit and then API URL and we’ll set that to http Local Host 8000 if you ran it on a different port make sure you put that all right so that way we can just have one central place for that URL now let’s make the request and I’m using axios by the way so I have to import that as well uh let’s see so import axios and then let’s say const I’m going to destructure the data if you’re using fetch then you would do that here but I’m going to await on axios.com API URL okay so that’s where we want to go and then slash so after the the closing curly brace SL register Das ususer so we’re making a request to our backend now we also want to pass in after that backtick uh a comma and then we want to pass in the data that we’re sending which is going to be our name and we remember we access that with name. value and then email so this will be email email. value and then once we do that we can then set the this the user data in our store to the data that we get back okay so let’s do that we’re going to say user store and then we’re going to call our set user action we’re going to pass in the user ID set that to the data. userid and then we want to do the same thing with the name so this will be name oops name and then it’ll be data. name okay so we’re setting it to our store and then the last thing we want to do in the try is just redirect so router. push and we want to go to slash chat and then in the catch let’s do uh we’ll say error. value and set that to we’ll just say something went wrong and we’ll say please try again okay uh let’s see did I set this oh you know what this let’s make this e r r because we can’t have that being error and the state being error error all right and then we want to set the loading to false no matter what whether it’s an error or not so we can add a finally so right here finally and then we’ll set the loading do value to false okay so that should do it right so again just to kind of reiterate we click the button it calls create user and checks the name and value inputs sets loading to true then we make our request to our backend which we already created send the name and email we get back the user ID the name and email and we’re storing the user ID and the name in our state right in our frontend UI State then we’re just redirecting to chat and we’re setting loading back to false so let’s try this out uh I’m going to come over here I’m just going to refresh the page here and then let’s do like I’ll say John Doe or just John and John gmail.com start chat says logging in redirects me to the chat page right now I should be able to check I can check this in a few places I can check stream or I can check um uh neon so we’ll do both going to go back here to my Explorer and stream and if we look look at users you’ll see right here John gmailcom so that’s what that’s who I just registered as right and then if we go to our neon console and go to users John gmailcom so now our front end is connecting to our backend sending a request signing up with both you know setting it in stream sending it to our own database so that we have our own uh store of users for what whatever you want to do with them um sets a channel and that’s it now what we need to do is create this chat page so that we can interact with the AI however before we do that I’d like to have a header at the top because we do need um we do need a way to log out I say log out but it’s not actual authentication but you know what I mean just make the user know right the user ID and the email so let’s create a component we’re we going to go into the components folder and let’s create a header. viw file okay and we’re going to add our script let’s add our setup so setup and for the Lang set that to TS and then we’ll have our template okay so in our template I’m going to have a div with padding y let’s do py4 px-6 BG Das gray 800 let’s do Shadow DMD make this a flex box we want to justify uh justify between and let’s do items Das Center all right so within that div I’m going to have the robot image which I need to bring in so up here just close that up so up here let’s import that so import robot image and that’s going to be from dot dot SL assets SL robot.png all right so for the source I’m going to just add a colon here since this is a dynamic variable it’s a robot image and let’s see just a couple classes on this so so class is going to be W so width d8 and height -8 and we’ll just say for the alt chat AI now we want to bring this header in uh it’s not finished yet but I just want to be able to see it so it’s only going to be on the chat page it doesn’t have to be on the homepage so we’re not going to put it in you know the main app file we’ll put it right in chat so in the chat view let’s go ahead and import header and let’s see we’ll just get rid of this uh H1 here I do want to have a div though with just a couple classes so let’s do Flex I’m going to do flex-all h- screen BG let’s do gray 900 and text- white and then in that we’ll put our header and there we go so looks pretty good so back to let’s see home view we can close up but back in the header let’s finish this up I’m going to put under the image here an H1 with a class of text large and font semibold and we’ll say AI or chat AI now it’s way it’s way over on the right because I have justify between so all the spaces in between but I’m going to put a log out button so this will be pushed over into the middle and the log out button will be on the end so let’s add button and I’m going to do text Gray 400 and also on Hover so hover will make text- white and inside of it will’ll say log out okay so there’s that now when we click it let’s go ahead and add an event handler so we want to click so when we click it’s going to call a function called logout now the log out function is the action in the store right if I go to my user store we have this log out action so we can bring this into to our our header and use it so up at the top here let’s let’s import and whenever you want to use the user store you need to bring in use user store all right so we’re bringing that in um I’m also going to bring the the user use router in so use router from view router and then we need to initialize both of those so let’s say const use or user store set that to use use user store and then let’s say cons router set that to use router and then for the log out uh what we’re going to do is if it first calls a logout function here so we’ll create that and then from there we want to then take the user store and we want to call the logout action and we can do that just simply by doing Dot user store. logout then we just want to redirect so router. push and we want to redirect to the homepage the home view okay so when we call that log out it’s going to clear the state because again in our user store it’s going to set the user ID and the name to nulls so when we log in we hit our backend we get the data back it sets it when we log out it clears it so let’s do it let’s say log out and now there we go so now we want to do the the chat right we want to be able to actually interact with the AI so I’m going to log back in as John so I should be able to just do John on at gmail we want to work on getting the the messages which right now John is a new account so he doesn’t have any so I’m just going to add some so I’m going to go to my to postman or open whatever HTTP client you want let’s make a post request to chat and then in the body you want to include your user ID which for me is going to be johore gmailcom that should be lowercase ID and then we want to send a message and for the message I’ll just say what is the capital of um say Maine and let’s send okay so capital of main is Augusta let’s send another another message here what do I want to ask it um say what is the what is the most popular programming language curious to see what it says oh most popular language is Javascript however it’s very it it may vary based on the specific industry or use case Python and Java are also widely used all right so we have uh some chats now so we want to get these and we want those to display here so what I’m going to do is create a new store for chats so in stores let’s create a file called chat. TS now you can set your store up in different ways in the user store we use the object style where we have a state you know State we have an object with State action and uh just any other options but we can also use the composition API and we can use reactive variables with ref like we did in our components so that’s what I’m going to do with chat the chat store because it’s a little more complicated so let’s start off by importing Define store okay so we want to bring that in from paa and then let’s also import ref because I’m going to be using reactive variables that’ll be from View and then I’m going to bring in axios because I’m also going to do the the fetch from here or the HTTP request and then let’s do what else we also want the user store okay because we’re going to need the user ID the the user that’s logged in so let’s say use user store bring that in from do/ user all right now we’re going to be formatting our chat messages a certain way so meaning the message that we send as well as the message we get back and I’m going to use an interface for that okay so this is a typescript interface and it’s basically just like a type where we Define certain fields that it has to match so let’s call this chat message and chat message has to have a message which is going to be a stream Str and has to have a reply which will be a string so that’s our chat message let’s do another interface of formatted message and formatted message is going to have a role because when we get our messages back we need to know which which one is the the user and which one is the AI so the role is going to be a string of either user or AI okay it has to be one of those and then we’ll have the content which will be either the message or the reply so that’s going to be a string so those are our interfaces and you could put those in separate files if you want but there’s only two Fields so I’ll just keep them here and then let’s export const and let’s say use chat store just like we did use user store set that to our Define store which is going to take in the name which which we’ll call chat and then we’ll have our function yeah actually this yeah we don’t want an object here you can use an object like we did in the use uh user the user store but I’m going to have a function and we can use the composition API here so let’s create a variable for messages and set that to ref so it’s going to be a reactive variable and I’m going to use typescript generics here to Define what a message should be which is going to have a roll which will be a string and content which will be a string and it’s going to be an array messages so we also want to have after the curly brace here our brackets and uh ref is a function so we want to have our parentheses and the default value goes in here which is an empty array okay and then the other thing that I want to have is is loading and and set that to ref which is going to be false by default then we want to initialize our user store because we need that user ID so let’s say const user store and set that to use use user store right and then we need to have a function that will load previous chat messages so let’s say load previous chat messages and we’ll call this load chat history and this is going to be asynchronous okay and first thing I’m going to do here is check for the the user the user ID so we’ll say if the user store do user ID or rather we want to say if not the user ID then we just want to return okay then we’re going to open up a try catch and we want to make our request and the the end point we’re making the request to is get messages right because we want to get our messages so let’s say const and we’re going to destructure the data from axios so let’s say await axios Dot and it’s going to be a post request and then we have our API URL which is in the the EnV file so let’s use some back ticks here and we’ll say um to access that we can do import. meta Dov and then Vore apiurl and then outside of the curly brace we want to do SLG get- messages okay so we’re going to hit that endpoint and then we want to pass in an object because we need to send the user ID with it to get the user’s messages so it’s a user ID and then user store. user ID all right and then uh let’s see so the way that the messages come back right in fact we can just we can just check this out so if I say new new request and I want to hit I want post and then the get messages and in the body I’m going to add my user id which is johore gmailcom if I do that I get back my messages the me the two that I just sent right so it comes back in an array called messages and then an object that has ID user ID message reply created at where message is what I sent reply is what the a sent now I want to I want to manipulate this data into basically into an array that has the role which will be either the AI or the user and the content which will be either the message or the reply based on if it’s the AI or the user right we want to match this right here so this this interface so we have to uh basically map through and and return an array with those two Fields um and we also have to flatten it because what we what we can do by using map right if we map through we can get like an array with the the roll so it would be like user and then content would be just whatever right and then we’d have another array like that and we don’t want that we want we want an array that has objects in it like this so we want to flatten it so the the method we can use to do that is called flat map okay which is just a JavaScript method so that’s what we’re going to do we’re going to come down here and we’re going to take messages which is our reactive variable that we set up above and I want to set the value of it it right so value and I want to set it to the data. messages which comes back which looks like this initially it’s going to look like this an array of of those objects so on this we want to run our DOT our flat map just going to go on the next line here so let’s say um flat map and then that takes in a function and for this we’re going to say MSG so for each message which is going to be formatted as the chat message interface and then what that’ll return so right here we want to put a colon and what that’ll return is a formatted message array okay that has that matches this right here the U the role and the content okay so it gets passed in the chat message we want it to return the formatted message and the way we do that um actually we just want to set this right to an array and pass in an object and say roll so roll user and then the content will be the MSG Dot and then message because we the me remember what we’re getting back here the message field is the user what the user says the reply is what the AI says so we want to do that and then let’s copy that down and then the rooll for AI will be the reply so MSG do reply and then I want to just filter filter it because all I want is the content that’s what we want to show right is the message and the replies which is now going to be in content we don’t want to show the ruler so the ruler the role so I’m going to filter that out so let’s go on the next line and say filter and pass in uh let’s say MSG so MSG which will now be the formatted message okay no brackets because it’s not an array we’re we’re going through each one so each one will be a formatted message and we just want to return from that we want to filter out just the content which will be the reply or the me and the message and then for the error so in the catch here let’s just do a console do error and we’ll say error loading chat history and then show show the error Okay cool so we have our chat store and we have our load chat history so now we want to call this right we want to call this within our um chat view so let’s go to chat View and we want to bring in couple things here so up at the top let’s import now we want this to happen when the component mounts and we can do that by using on mounted so I’m going to bring in on mounted I’m also going to bring in a function called Next tick and what that does is it allows us to wait until the Dom finishes loading before it does something so we’re going to do that and that’s going to both of those are going to be from View and then we want to bring in both stores so let’s say use user store and then we also want to import the use chat store and while we’re at it let’s bring in use router from view router and I think that should do it for now now we need to initialize a couple things so the user store set that to use user store then we have the chat store set that to use chat store and then the router so const uh router set that to use router and then I want to make sure that the user is logged in so uh let’s just say Ure user is logged in and again I know I’ve said this but if you want to incorporate actual authentication with a password you can do that but I didn’t really want to focus on authentication because that’s you know that’s such a huge thing I wanted to focus on the whole AI aspect of it so yeah let’s just check if not so if not user store. userid then we’re just going to take the router and we’re going to push to slash and then I also want to scroll to the bottom right so because we’re going to be able to scroll through the chats I want it to to scroll to the bottom so let’s say autoc scroll to bottom so I’m going to create a function here called scroll to bottom all right and then in that um this is where we’re going to we’re going to use next tick which again we’ll wait until the Dom has been updated and that takes in a function and then to scroll to the bottom let’s get the chat container which we haven’t created yet we don’t have that you know down in the output but we will so we’ll say chat container and we’re going to set that to document. getet element by D and it’s going to have an ID of chat Dash container okay so then under that I’m going to just check for chat container and then we’ll take chat container and we’re going to set the scroll Top Value to the scroll height so chat container. scroll height okay now like I said when when we the component mounts right we come to the page the component mounts that’s when we want to call the load chat history that we just created in the store so let’s go under that scroll to bottom and let’s say on mounted okay so this is how we use this we just pass in a function and then we’re going to call chat store and then load chat history which returns a promise so I’ll just use a DOT then um and then we want to scroll to the bottom so scroll to bottom like that all right and let’s see why is this does not exist on type store did I not save it um oh I didn’t return this oh so at the bottom here we want want to return an object and we’re going to return the messages the is loading the load chat history and that’s it for now okay good so now that error should go away now we want to add the output so let’s go right under the header and I’ll say chat messages so we’re going to have an ID of chat Dash container and let’s add a couple classes here as well so for classes we’re going to do Flex das1 let’s say overflow on the Y AIS Auto let’s do padding so P4 and space- y-4 now in here we’re going to have a div with a V4 so the V4 attribute will allow you to Loop over something in our case the the chat messages and output um elements based on you know on those messages so let’s have um let’s do a div I’m just going to add a class of flex onto this and then items Dash start okay so on this div I’m going to add a v-4 directive and set that to the way we do this is open up some parentheses and say MSG so MSG we can also get the index in and then whatever we want to Loop over which is going to be this the chat store. messages so we Loop over those we also need to add a unique key so let’s bind so colon key and we’re going to use the index as the key and then uh let’s see we’re going to add we’re going to have some we’re going to have a a conditional class because if it’s a user I want to align it a certain way and if it’s a AI I want to align it a certain way so the way we do that is in addition to class we can do colon class to make this Dynamic and then we can put basically a JavaScript expression in here I’m going to say if the message. roll if that is equal to user then I want to add add the class of justify Das end else I want to add the class of justify Dash start okay so that’ll add some conditional styling and then inside that div we’re going to have another div and let’s do a class of we’ll say Max let’s do Max with uh extra small so Xs and I’m going to do p padding on the xaxis 4 padding on the Y I 2 and let’s do rounded large and then I also just want to add on medium screens and up then let’s do a Max width of medium okay and then I want this to have a conditional class as well because I want to have a different color based on if it’s the user or the AI so just like we did above we’re going to do colon class for conditional uh styling and let’s say If the message. roll is equal to user then I’m going to have the class BG Das blue- 600 with text- white else then I’m going to have the class of BG Das gray- 700 and text- white and then let’s put in here we want the content so MSG do content which will be either the reply if it’s the ai’s message or message if it’s the user’s message okay so hopefully that makes sense um yeah let’s go ahead and try that there we go so looks pretty good what’s the capital main capital main is Augusta it’s the most popular programming language gives us the answer cool now the next step is to be able to actually ask something because right now we’re just seeing the messages that are there so let’s go back to our chat store and we’re going to have a new function to do this so let’s see we’re going to go under this one and let’s say send new message to Ai and we’re going to create a function called send message set that to async and it’s going to take in a message which is going to be a string okay then in our function I’m going to check for let’s say if we’ll say if not message and I’m just going to add trim onto that to trim the whites space or not user store. userid then we want to return okay so if there’s no message or if there’s no user then we just want to return then we’re going to take our messages right so messages is our reactive value up here right so our messages and I want to push onto that so let’s say messages. value. push I want to add to that an array not an array an object with a rle of user because it’s coming from the user and then the content of message okay okay and then this is where we’re going to use that is loading so I’m going to set is loading to True okay because uh actually that needs to be is is loading. value set that to true because we’re about to make our request all right so let’s add a try catch and in the try we’re going to make our request so we’ll destructure the data from await axios dopost and the endpoint we’re hitting is the chat endpoint so let’s do our back ticks and then we’re going to add the import. meta Dov we want the Vore API URL and then slash chat so that’s the end point and then we want to pass in the data that we want to send which is going to be the message and the user ID which is going to be set from the user store. userid okay now let’s come down here and let’s take the messages value and push on to that and this time it’s going to be the role of AI because this is the response right so role is going to be Ai and then content is going to be the data dot in the rep reply CU again the it’s going to look like well this is get messages but when we send a chat it it’s formatted the same way basically all right so we do that and then in the error let’s let’s just return a message we’ll have a message but it’ll just say like unable to process so let’s take our messages and let’s well first off you know what let’s let’s just console. error and we’ll say error Sending message and we’ll put the error okay and then as far as the messages go let’s say value. push and we’re going to pass in an object with the role which is going to be Ai and then the content which will say error unable to process request okay and we want to set the is loading to false so for that we can add a finally and then we’ll set is loading the dot value set that to false and then we want to make sure that we return the um send message okay so now ready to use that so let’s go back to our chat View and let’s see we’re going to go so we got our message content and we want to go under under the second closing div here and we’re going to have uh a div let’s do Flex so flex and justify Dash start and then this is going to have an if because I want to check for that loading state so let’s say a vif and set that to chat store Dot and then is loading okay so if it’s loading then I just want it to say AI the AI is thinking so let’s actually put a div with a a background we’ll do gray 700 and text- white PX4 py 2 and let’s do rounded large okay and then in that div we’ll have a span and I’m going to use the animate Das pulse class and we’ll say ai ai is thinking dot dot dot okay so that’s if it’s loading and then we want to put the input the chat input uh under Let’s see we got one two 2 three so just above the last div is where I want to put the chat input now I want this to be in its own component so let’s uh let’s do that let’s create a new component in the components folder and we’ll call this chat input. view okay and then we’re going to add our script and our setup and our Lang of TS okay and we’re going to import we’re going to import ref from View and I want to set a message variable here so let’s say cons message set that to ref it’s going to be empty by default and then we have to send this up a level right because we’re embedding the chat input component into the chat View and we need the message to be sent up so we need to emit it so we’re going to say const Emit and the way we do this is we can use Define emits and then we’re going to pass in an array and it’s going to be called send Okay um now here we want to have our send message and set that to an arrow function okay and then that’s what we’re going to call when we submit the input put so before we do that let’s create our output our template so in our template we’ll have a class of padding padding four let’s do BG Das gray 800 and flex and then in that div we’re going to have our input add a couple classes here Flex one padding to rounded large uh BG gray 700 text white and then I want to have a focus class as well so at the end here we’ll say Focus colon and I just don’t want to have an outline so outline none all right and then in this input we’re going to bind it to that message variable so we use V model for that so V model to message and then we’ll add a placeholder as well so say send a message make that lowercase so send a message and then I want to be able to call the send message function when we hit enter with we’re going to have a button too but I also want to be able to hit enter so I’m going to add here let’s say at and then we can do key up and the key that I want is enter so we can just say do enter and then set that to send message all right and then underneath the input just going to put a slash there so underneath the input we’ll have the button so here let’s say button and give it some classes margin left we’ll do margin left two PX -4 py2 I’m going to do a color of BG blue 500 and rounded large okay and the button will just say send and of course when we click this we want it to call send message so let’s say at click set that to send message all right and that should do it now we just have to add our send message here and all we really need to do is emit the the message up to the to the chat view so let’s first off check we’ll say if not if not message. value and then we’ll just trim it so if not message then we want to return okay and then we want to use that emit and we want to emit send and we want to send along with it the message. value and then we’ll just clear the value so message. value set that to an empty string all right now we need to embed the chat uh the the chat input into the chat view so let’s import it so right here we’re going to import chat input and we’re going to come down here and go right above the last div and let’s embed it so chat input and then we want to pass here we want to say at send because remember we from the chat input we emitted a custom event called send so when that’s called basically when we hit the button or we hit enter then that event is going to get called so we need to add a Handler to it and the Handler is simply going to be the chat store. send message whoops chat store. send message and that’s it so now we have our input down at the bottom here so let’s try it out we’ll say who who was the who is the 10th president of the us so AI is thinking and then it comes back 10th president was John Tyler so yeah I mean this is working now one thing that I’d like to add and we’re going to have to do this in the back end is context because you’ll see if I say now uh we’ll say what year what years was he president okay so I’m going to send that a i is thinking to respond to your query I need to know the specific person so it doesn’t have context right it doesn’t know it doesn’t look back and and see that I just asked about John Tyler so we have to add that functionality in the back end I’m actually going to go let’s see so this is the back end here I’m going to open up vs code in the back end okay so this is now my my Express API and we’re going to go to the uh let’s see the server TS and the where we want to do this is going to be the chat endpoint and if you want to break these up into separate files you can I know that this is kind of a long file um but yeah so this is the chat endpoint and let me just figure out where where I want to put this um so we we check for the message the user ID we query users check make sure the user’s there check the user in the database and let’s see then we set our response so let’s go after we check the user in the database and before we send the response so we’re going to go right here and we what we want to do is fetch users past um p pass messages for context and what we want to do here is essentially instead of sending back because right now when we hit slash chat it sends back this it sends the the an object with the role the user rle and then whatever the message is all right uh I’m sorry that’s not what it sends back that’s what we’re sending it and then it sends back down here it sends back the reply but what we want to do is instead of of us sending it only the current message we want to send it we want it to also have context of the last whatever 10 20 messages however however many you want to set it you want to input that into open AI as well as the current message so that way it has context and it can look back and when we say you know what years did he serve then they can look back at the last few messages and respond with that context so to fetch the users um not fetch the users fetch the the users messages we can come down to get messages and right here the chat history we can just copy this this block of code okay and then we’ll put that here so right before we send the the request to open Ai and we’re just selecting from the chats where the user is the user ID I’m going to get rid of this semicolon because I also want to just add order by and we want to order by chats Dot and then create at and then I’m also going to limit it to the last 10 messages if you want to put more that’s fine but just remember the more you put the longer the request is going to take all right so we have that now like I said we need to send not just the current message but but the last the chat history so what I’m going to do is create a variable for actually let’s put a comment here let’s say format the chat history for open AI okay because it has to be formatted in a certain way so I’m going to call this conversation because that’s what it is a bunch of messages in context is a conversation and for the type we’re going to use this uh chat what is it chat completion message param so we want to use that and it’s an array so put some brackets on there and uh I believe we have to bring that in so up at the top oh it was brought in okay so this comes in from open AI resources all right so back to where we were so we’re going to set that and we’re going to use flat map because it needs to be a flattened array so let’s say chat history and then flatmap pass in our function and say for each chat we want to return an array so actually this can be just brackets so we want to return an array that has uh it should look like this right so it should have the role so the user R will have the content of chat. message and the AI role will have the chat reply because we need both we need our messages and the ai’s messages in the conversation in order to have context so now let’s go under that and let’s say uh we’ll put a comment here we’ll say add latest user messages to the conversation okay so we can do that by saying conversation. push and we’re going to push onto it the latest which is this right normally or or what we were doing is just passing this in we still want to pass that in along with this stuff so we’re pushing this onto this so we’ll just put that in there like that all right now we should be able to come down here and instead of for messages instead of doing this we’ll say conversation as and then the chat completion message param array uh let’s see content oh so this right here this this shouldn’t be AI this should be assistant because when you’re dealing with open AI there’s a couple different types that you can use for role there’s user um we’re dealing with assistant here the AI is is the assistant so that should clear up that error all right so now that we’ve done that it should have the context we shouldn’t have to change anything in the front end because it’s still returning the same thing you know that’s still returning the AI response but it should have context now so let’s go ahead and run the back end because I did I stopped it so I’m going to do npm runev all right so now I’m going to come back over here and I’m going to say who was the who was the 11th president of the US okay James K pul now let’s say what years did he serve there we go James K poke served as the president March 4th in 1845 1849 cool so now we have context and I think that’s something that’s you know really important you don’t want to just ask one question and that’s it you want to be able to conversate all right so we’re we’re just about done this one other thing I want to do so let’s say I I was to do like um give me give me a list of the the top five cities in the US when it comes to crime rate and you could take I guess I could interpret that as low lowest crime or best or you know least crime it answers but it’s not formatted very nicely we have number one here Albuquerque number two Baton Rouge so I want this to actually show in a nice list so what we can do is just add a simple format message function in our chat view so let’s go to our chat View and we can use regular Expressions to replace certain um certain tags and so on so let’s uh let’s see where do I want to put this we’ll put it right above the scroll to bottom and let’s say format format AI messages for better display so we’ll call this format message and that’s going to take in text which is going to be a string okay and then we just want to check if there’s no text if there’s no text then we’re just going to return an empty string all right and then we’re going to return a bunch of replace methods with some regular expression and I’m not going to type this out I’m going to paste it in and you guys can get it from the repo if you don’t want to type this stuff in but basically we’re going to preserve line breaks we’re going to bold text um so we’re looking for like new lines and replacing it with a a line break HTML tag bold text inline code um bullet points Etc so the way that we use this is down here where we output the content instead of outputting it in the div inside of these curly braces we’re going to use the the V HTML directive on the div right so this div right here let’s add v- HTML and then we can just set that to the the format message function and then pass in our MSG do content and now as you can see the list is nice and clear all right all right so that’s yeah that’s pretty much it guys um if I were to log out and log in as I think I have some messages with this with uh what was it Brad at Gmail and you can see the code when I asked for a rest API I mean it’s not the best if I make it a little bigger you can see it better it’s not formatted the best but it’s readable you know um but yeah so that’s it we now have a an AI a AI chat bot that works pretty well and will give you you know gp4 powered data now the last thing I’d like to do is actually deploy this and since we have our back end and front end completely separate we’re going to be hosting our back end with render and we’re going to host our front end with versel all right so let’s get into that all right guys so we’re going to go ahead and deploy this project and we have the back end which we’re going to be deploying to render.png all right so I’m going to go to render.jpg sub repos I’m going to choose chat AI API and then there’s just some options that we need to add here so for one um the build Command right so if we look at our package.json we’re using typescript and we need to compile that typescript so we’re going to do that on the server so we need it to run this npm run build in addition to npm install so right here we’re going to say and run npm run build and then the other thing is the the start it’s the server.js is going to be in the disc folder so here instead of node server JS we’re going to say node disc SL server JS all right then we just have some environment variables so in ourv copy everything but the port and then we can say add from. EnV paste that in add those variables and that’s it now we’ll click deploy web service and this can take like a minute or two all right so it says your uh build successful your server is live this is the domain here and we can test this real quick so I can go into Postman and make a new request post request to this that’s not it it didn’t copy there we go all right so we want to do this domain right and then we’re going to do slash and let’s do get Dash messages and then in the body we’re going to add user ID and let’s do johore gmailcom and send and there we go so we’re getting the messages so we know that that the API is now live so now we want to do the front end so I’m going to go to verel and log in with GitHub okay and then we’re going to click add new project we’re going to select chat AI UI this time and let’s see so V build and output settings I believe leave everything we can just leave as is um for environment variables though we want to add the Vore aior key not key what am I doing API underscore URL right because this is going to be our endpoint and we don’t want to use Local Host 8000 or whatever we want to paste in the the render endpoint or the render URL and yeah I think that’s it so let’s click deploy again this can take like a minute or two all right so that took like 10 seconds and then we’re going to continue and let’s check it out if we just click on that and you can see we’re at the live site now and I’m going to log in as let’s say John and John at Gmail start chat and I should see my chats because remember we’re using the same database and let’s try it out I’ll say what is the capital of Texas AI is thinking the capital of Texas is Austin so we have this fully deployed and you can see just how easy that that was all right but that’s it hopefully you guys enjoyed this I may do another video where we create a react front end uh or I might save it for my react course I’m really not sure yet um and I may add on to this we may add actual authentication with you know protect um protection of the actual messages and adding password authentication and so on but I think that this is a really good start and hopefully you guys learned quite a bit from this and thanks for watching if you liked it leave a like and I’ll see you next time

By Amjad Izhar
Contact: amjad.izhar@gmail.com
https://amjadizhar.blog
Affiliate Disclosure: This blog may contain affiliate links, which means I may earn a small commission if you click on the link and make a purchase. This comes at no additional cost to you. I only recommend products or services that I believe will add value to my readers. Your support helps keep this blog running and allows me to continue providing you with quality content. Thank you for your support!

Leave a comment