After our classes are defined, itβs time to:
1. Create the botβs basis
2. Plan the folder and file structure of the project
100 fires π₯ on this post, and weβll continue.
1. Create the botβs basis
2. Plan the folder and file structure of the project
100 fires π₯ on this post, and weβll continue.
π₯109
Since the process and results of the work of each of our classes depend on the project folder, we see that all our classes have a common element β the project working directory.
In addition to this, different classes may have other common functionality, such as reading or writing data to CSV files or a database.
To avoid code duplication (the DRY principle) and to facilitate project maintenance, let's use inheritance to extract the common elements of our child classes into a separate parent class (base class).
Thus, we introduce an additional class, which we will call BaseGenerator.
We will inherit our classes from this base class, allowing us to access its attributes and methods from the child classes.
Therefore, our inheritance hierarchy looks like this.
In addition to this, different classes may have other common functionality, such as reading or writing data to CSV files or a database.
To avoid code duplication (the DRY principle) and to facilitate project maintenance, let's use inheritance to extract the common elements of our child classes into a separate parent class (base class).
Thus, we introduce an additional class, which we will call BaseGenerator.
We will inherit our classes from this base class, allowing us to access its attributes and methods from the child classes.
Therefore, our inheritance hierarchy looks like this.
β€βπ₯38β€1
β¬οΈ This architecture will be sufficient for our project.
We could also build the architecture using interfaces, abstract classes, and contracts, but I don't want to overcomplicate things or overload you with information right now.
I can explain this separately in the future, but for now, this will be enough.
We could also build the architecture using interfaces, abstract classes, and contracts, but I don't want to overcomplicate things or overload you with information right now.
I can explain this separately in the future, but for now, this will be enough.
β€24π8π₯4
Where will we store our classes? We'll create a package called modules, and inside it, weβll create a .py file for each class.
Additionally, weβll create a main.py file in the root of the project. This file will serve as the entry point to the application and will contain the logic for launching the different modes of the bot.
Weβll also need a data folder in the bot, where various global project files can be stored, such as the keyfile.json file for integrating the bot with Google Sheets.
Thus, our project structure will look like this.
We created a similar bot structure in lesson 4 of the Pinterest Money course. In that lesson, youβll also learn how to build a prompt builder, and connect the bot to Google Sheets.
Additionally, weβll create a main.py file in the root of the project. This file will serve as the entry point to the application and will contain the logic for launching the different modes of the bot.
Weβll also need a data folder in the bot, where various global project files can be stored, such as the keyfile.json file for integrating the bot with Google Sheets.
Thus, our project structure will look like this.
We created a similar bot structure in lesson 4 of the Pinterest Money course. In that lesson, youβll also learn how to build a prompt builder, and connect the bot to Google Sheets.
β€βπ₯21π₯9π2β€1
Take note of the module structure above.
For each class corresponding to a separate task, we have created a separate .py file (module).
Donβt think that only one class can be created in a single .py file.
You can also create additional classes in the same file if they are closely related to the task of the main class.
So, the recommendation is:
One file β one task.
This makes the code easier to read and maintain.
For each class corresponding to a separate task, we have created a separate .py file (module).
Donβt think that only one class can be created in a single .py file.
You can also create additional classes in the same file if they are closely related to the task of the main class.
So, the recommendation is:
One file β one task.
This makes the code easier to read and maintain.
π₯23π1
At this stage, we have created the structure of our bot and the class hierarchy.
The next step is to create the skeleton of our classes and the bot's launch logic.
The next step is to create the skeleton of our classes and the bot's launch logic.
β€βπ₯22π1
Let's start with the base class. In the file base_generator.py, we'll declare the BaseGenerator class and then create the class constructor (the init method).
Earlier, we determined that a common element among our child classes will be the project working folder.
Therefore, in the constructor of the base class, we need to accept a variable containing the project folder name (project_folder) as an argument.
Then, we'll create an instance attribute (self.project_folder) and assign it the path to the project folder, formed using the os module.
Additionally, it would be a good idea to create attributes for the paths to other project folders in the base class and ensure their automatic creation (self.generated_images, self.generated_video).
In this class, we will also create methods for reading and writing CSV files, which will be needed for our child classes.
An example implementation of this class might look like this (image).
Earlier, we determined that a common element among our child classes will be the project working folder.
Therefore, in the constructor of the base class, we need to accept a variable containing the project folder name (project_folder) as an argument.
Then, we'll create an instance attribute (self.project_folder) and assign it the path to the project folder, formed using the os module.
Additionally, it would be a good idea to create attributes for the paths to other project folders in the base class and ensure their automatic creation (self.generated_images, self.generated_video).
In this class, we will also create methods for reading and writing CSV files, which will be needed for our child classes.
An example implementation of this class might look like this (image).
β€22π5
Now let's move on to the child classes.
We'll create a skeleton for ScriptWriter. The structure for the other child classes will be created following the same principle.
In the script_writer.py file, declare the ScriptWriter class and inherit it from the base class BaseGenerator.
Create the class constructor. Since we need to pass the project_folder argument to the BaseGenerator parent class constructor, we must first accept it in the ScriptWriter child class constructor. Let's do that.
To pass project_folder to the parent class, we need to call the parent class constructor. This is done using the super() function.
Call the parent class constructor using super() and pass the project_folder parameter.
* I will provide the code a bit later
We'll create a skeleton for ScriptWriter. The structure for the other child classes will be created following the same principle.
In the script_writer.py file, declare the ScriptWriter class and inherit it from the base class BaseGenerator.
Create the class constructor. Since we need to pass the project_folder argument to the BaseGenerator parent class constructor, we must first accept it in the ScriptWriter child class constructor. Let's do that.
To pass project_folder to the parent class, we need to call the parent class constructor. This is done using the super() function.
Call the parent class constructor using super() and pass the project_folder parameter.
* I will provide the code a bit later
β€18π1
Note that instance attributes of the child class ScriptWriter should be created after calling the super() function, as this is related to the initialization order of the base and child classes.
When your child class inherits functionality from a base class, the base class attributes need to be initialized before adding attributes in the child class.
When creating an object (instance) of ScriptWriter, the initialization order will be as follows:
1. The constructor of the ScriptWriter child class is called first.
2. Then, the constructor of the BaseGenerator parent class is called via super(). At this point, all parent class attributes are initialized.
3. Then, the constructor of the child class continues, where the child class attributes are initialized.
When your child class inherits functionality from a base class, the base class attributes need to be initialized before adding attributes in the child class.
When creating an object (instance) of ScriptWriter, the initialization order will be as follows:
1. The constructor of the ScriptWriter child class is called first.
2. Then, the constructor of the BaseGenerator parent class is called via super(). At this point, all parent class attributes are initialized.
3. Then, the constructor of the child class continues, where the child class attributes are initialized.
β€14π₯4
Next, after the class constructor, we will declare a method that will trigger the execution of the main task of the class. Let's name it execute and leave it empty for now.
Each of the child classes will have a method with this name, but it will have its own unique implementation for each class.
Each of the child classes will have a method with this name, but it will have its own unique implementation for each class.
π₯14π1
In the main.py file, we will implement the management of different operation modes for the bot.
Here's what we'll do:
1. Import our classes.
2. Add functions to run individual steps, each of which will create an instance of the corresponding class and call its execute method.
3. Add a function to run the full pipeline, which will sequentially execute all the steps.
4. Create a menu to select the bot's operation mode.
Here's what we'll do:
1. Import our classes.
2. Add functions to run individual steps, each of which will create an instance of the corresponding class and call its execute method.
3. Add a function to run the full pipeline, which will sequentially execute all the steps.
4. Create a menu to select the bot's operation mode.
π₯11
Letβs implement this.
First, we'll import the classes. Then, for each class, weβll create a function that accepts the project_folder argument.
In the function, we will create an instance of the class and pass the project_folder parameter to the class constructor. After that, we will call the execute method on this object.
* I will provide the code a bit later
First, we'll import the classes. Then, for each class, weβll create a function that accepts the project_folder argument.
In the function, we will create an instance of the class and pass the project_folder parameter to the class constructor. After that, we will call the execute method on this object.
* I will provide the code a bit later
π₯15π1
Note that instead of importing all classes globally, we can move the imports inside their respective functions.
This will speed up the botβs startup and reduce memory usage in situations where not all classes are needed.
For example, if we only need to run one mode, the bot wonβt import all other classes.
This will speed up the botβs startup and reduce memory usage in situations where not all classes are needed.
For example, if we only need to run one mode, the bot wonβt import all other classes.
π₯14
Next, we'll declare the main function.
In this function, we'll declare a variable project_folder and assign it the project folder name.
We'll also create a menu here to choose the bot's operation mode.
We can implement this in two ways:
1. By parsing command-line arguments (argparse), allowing the bot to be launched from the command line.
2. By using a simple numeric input in the console.
We'll go with the simpler second option for now. I'll demonstrate the first option separately later.
In this function, we'll declare a variable project_folder and assign it the project folder name.
We'll also create a menu here to choose the bot's operation mode.
We can implement this in two ways:
1. By parsing command-line arguments (argparse), allowing the bot to be launched from the command line.
2. By using a simple numeric input in the console.
We'll go with the simpler second option for now. I'll demonstrate the first option separately later.
π₯10π1