progress
BROWSE CHAPTERS
Exploring the Code
In this chapter, we will be exploring the code of the project and discussing the architecture of the chatbot. We will also be looking into the most important files of the project.
Project Structure
The project is structured as follows:
The most important files and directories are:
credential.js
: Contains the OpenAI API key and assistant ID. We have created this file in the previous chapter.deploy-local-ledger.sh
: A shell script for deploying the canisters to the local network.dfx.json
: The configuration file for DFX. It contains the configuration for the canisters and the local network.dfinity_js_backend
: The directory containing the source code of the backend canister.dfinity_js_frontend
: The directory containing the source code of the frontend canister.
Backend Canister
The backend canister is responsible for communicating with the OpenAI API and providing the frontend canister with the response. It is written in TypeScript and uses the DFINITY Canister SDK to communicate with the Internet Computer Protocol. The backend canister is located in the dfinity_js_backend
directory.
The structure of the backend canister is as follows:
assistant.ts
We are looking at the assistant.ts
file located in the dfinity_js_backend
directory. This file contains the code for the Assistant
class, which is responsible for managing the assistant and its interactions with the user. The class contains methods for retrieving the assistant's ID, saving a thread, retrieving a thread, and deleting a thread. It also contains methods for checking if a thread exists for a given user identity.
The file starts by importing necessary functions and types from azle
, a library for building decentralized applications on the Internet Computer Protocol
in TypeScript. It also imports models such as ErrorResponse
and thread-related structures (CreateThead
, Thread
) for data handling.
Next, the file initializes threadStorage
as a StableBTreeMap
, a data structure used for storing threads. The map is keyed by text
and contains CreateThead
values. The map is initialized with a capacity of 4.
The Assistant
class encapsulates various methods for managing threads and interactions with the assistant. The getAssistant
method retrieves an assistant's ID. It uses a query
function, indicating that it fetches data without modifying the state.
The saveThread
method is responsible for saving a thread.
It checks whether a saved thread exists for the given userIdentity
by calling the this.hasASavedThread_
method. If a saved thread is found, it retrieves and returns the thread.If no saved thread is found, the code prepares a threadToSave
object of type CreateThead, wraps it in an object, and inserts it into threadStorage
using threadStorage.insert(userIdentity, threadToSave)
.
There are additional methods for retrieving, and deleting threads, we will not be going over them in this tutorial.
index.did
This file contains the interface for the backend canister. It defines the service provided by the canister and the methods it exposes. The file is written in Candid, an interface description language for the Internet Computer Protocol. This file automatically generated by DFX when you deploy the canister. If you want to learn more follow the Typescript Smart Contract 101 tutorial here.
index.ts
The index.ts
file contains the code for the backend canister.
This file is responsible for initializing the canister and exposing the service defined in the index.did
file.
user.ts
The user.ts
file contains the code for the User
class, which is responsible for managing user identities. The class contains methods for retrieving a username and updating a username. It also contains a method for checking if a username exists for a given user identity.
models/assistant.ts
The assistant.ts
file contains models for data handling. The file contains models for saving an assistant, a thread, and creating a thread. These models are used by the Assistant
class.
models/error.ts
The error.ts
file contains the ErrorResponse
model, which is used for returning error messages. The model is used by the Assistant
class.
Frontend Canister
The frontend canister is responsible for providing the user interface for the chatbot. It is written in TypeScript and uses the DFINITY Canister SDK to communicate with the Internet Computer Protocol. The frontend canister is located in the dfinity_js_frontend
directory.
The structure of the frontend canister is as follows:
The most important files and directories are:
src/App.js
: The main file of the frontend canister. It contains the code for the chatbot's user interface.src/index.js
: The entry point of the frontend canister. It contains the code for initializing the canister and rendering the chatbot's user interface.src/components
: The directory containing the React components of the chatbot. We will not be going over them here, they should be pretty straightforward.src/context
: The directory containing the React contexts of the chatbot. We will be going over them in the next section.src/utils
: The directory containing utility functions for the chatbot. We will be going over them in a later section.
context/assistantProvider.js
The assistantProvider.js
file contains the code for the AssistantProvider
component, which is responsible for managing the assistant and its interactions with the user. It uses the AssistantContext
context to provide the assistant and thread to its children. It also uses the UserContext
context to retrieve the user identity.
context/userProvider.js
The userProvider.js
file contains the code for the UserProvider
component, which is responsible for managing the user identity and its interactions with the assistant. It uses the UserContext
context to provide the user identity to its children.
utils/assistantCanister.js
The assistantCanister.js
file contains functions for communicating with the backend canister. It uses the window.canister
object to access the backend canister. The file contains functions for retrieving the assistant, saving a thread, retrieving a thread, deleting a thread, and checking if a thread exists for a given user identity.
utils/auth.js
The auth.js
file contains functions for managing the user's authentication. It uses the @dfinity/auth-client
library to handle authentication. The file contains functions for logging in and logging out.
utils/canisterFactory.js
The canisterFactory.js
file contains functions for creating canister actors. It uses the @dfinity/agent
library to create canister actors. The file contains a function for creating a canister actor for the chatbot canister. A canister actor is an object that allows you to call methods on a canister.
utils/chat.js
The chat.js
file contains functions for communicating with the OpenAI API. It uses the openai
library to communicate with the OpenAI API. The file contains functions for creating a thread, saving a thread, retrieving a thread, creating a message, retrieving all messages, and analyzing runs steps.
We are using the openai
library to communicate with the OpenAI API. The library is initialized with the OpenAI API key and the dangerouslyAllowBrowser
flag set to true
. This flag allows the library to be used in the browser, which is not recommended in a production environment.
The runTheAssistantOnTheThread
function runs the assistant on a given thread. It takes a thread ID and an assistant ID as inputs. It uses the openai.beta.threads.runs.create
function to run the assistant on the thread. It then returns the run ID. Which is needed to retrieve the assistant's response.
We then have functions for creating a thread, saving a thread, retrieving a thread, creating a message, retrieving all messages, and analyzing runs steps.
The analyseRunsStepsDone
function analyzes the steps of a run. It takes a thread ID and a run ID as inputs. It uses the openai.beta.threads.runs.steps.list
function to retrieve the steps of the run. It then checks if the run is completed. If it is, it returns true
. If not, it waits for 3 seconds and calls itself again.
The retreiveAssistantFromOpenai
function retrieves an assistant from the OpenAI API. It takes an assistant ID as input. It uses the openai.beta.assistants.retrieve
function to retrieve the assistant. It then returns the assistant.
utils/icp.js
The icp.js
file contains functions for initializing the canister and the authentication client. It uses the @dfinity/agent
library to create canister actors. The file contains a function for creating a canister actor for the chatbot canister. A canister actor is an object that allows you to call methods on a canister.
utils/localStorageController.js
The localStorageController.js
file contains functions for managing the local storage. It contains a function for retrieving data from the local storage and a function for saving data to the local storage.
Next Chapter
Conclusion