Kutluhan Aktar
Published © CC BY

AI-driven IoT Shopping Assistant w/ ChatGPT

Activate your cart with QR code sent via email by the web app, update product info by scanning barcodes, and get shopping tips from ChatGPT.

ExpertFull instructions provided3,166

Things used in this project

Hardware components

WIZnet W5300 TOE SHIELD
×1
NUCLEO-F439ZI
STMicroelectronics NUCLEO-F439ZI
×1
DFRobot GM77 Barcode and QR Code Scanning Module
×1
DFRobot Fermion: 1.51” OLED Transparent Display
×1
DFRobot Tiny (Embedded) Thermal Printer
×1
LattePanda 3 Delta 864
×1
DFRobot 8.9” 1920x1200 IPS Touch Display
×1
Anycubic Kobra 2
×1
Keyes 10mm RGB LED Module (140C05)
×1
SparkFun Button (6x6)
×3
Xiaomi 20000 mAh 3 Pro Type-C Power Bank
×1
USB Buck-Boost Converter Board
×2
Breadboard (generic)
Breadboard (generic)
×1
Ethernet Cable
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Thonny
STM32CUBEPROG
STMicroelectronics STM32CUBEPROG
Fusion
Autodesk Fusion
Ultimaker Cura
XAMPP
OpenAI API (ChatGPT)
Brevo
Visual Studio 2017
Microsoft Visual Studio 2017

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Hot glue gun (generic)
Hot glue gun (generic)
3D Printer (generic)
3D Printer (generic)

Story

Read more

Custom parts and enclosures

firmware_updated.hex

assets.zip

AIoT_Shopping_Assistant_main_case_bottom.stl

AIoT_Shopping_Assistant_main_case_top.stl

Schematics

W5300

Code

class.php

PHP
<?php

session_start();

// Define the user class and its functions:
class user {
	public $conn;
	
	private $Brevo_API_URL = "https://api.brevo.com/v3/smtp/email";
	private $Brevo_API_Key = '<_API_Key_>';
	private $Brevo_email = 'freelance@theamplituhedron.com';
	private $Brevo_email_name = 'AIoT Shopping Assistant';
	
	public function __init__($conn){
		$this->conn = $conn;
	}
	
	// Database -> Add new account information
	public function add_new_account($firstname, $lastname, $email, $username, $password, $c_password){
		// Check for existing users.
		$existing_sql = "SELECT * FROM `users` WHERE `username`='$username' OR `email`='$email'";
		$existing_sql_result = mysqli_query($this->conn, $existing_sql);
		$existing_sql_check = mysqli_num_rows($existing_sql_result);
		if($existing_sql_check > 0){
			header('Location: ../?userAlreadyExists');
			exit();
		}
		// Confirm the given account password.
		if($password != $c_password){
			header('Location: ../?wrongPassword');
			exit();
		}
		
		// Obtain the unique user token  12 digits.
		$user_token = $this->generate_token(12, $username);

		// Create a QR code from the given username and the generated user token.
		$qr_code = "https://chart.googleapis.com/chart?cht=qr&chs=450x450&chl=user%".$user_token."&choe=UTF-8";
		
		// Insert new user information into the users MySQL database table.
		$insert_sql = "INSERT INTO `users` (`firstname`, `lastname`, `username`, `password`, `email`, `token`, `qr_code`, `successful_order`)
		               VALUES ('$firstname', '$lastname', '$username', '$password', '$email', '$user_token', '$qr_code', 1)";
		mysqli_query($this->conn, $insert_sql);
		
		// Create a unique MySQL database table for the registered account.
		$new_table = $this->create_products_table($user_token);
		if(!$new_table){ header('Location: ../?mysqlServerFailed'); exit(); }
		
		// Send a confirmation email to the user, including the verification QR code.
		$this->send_confirmation_email($email, "Verify Your Account", $firstname.' '.$lastname, $qr_code);
		
		// Set the required session variables.
		$_SESSION["name"] = $firstname.' '.$lastname;
		$_SESSION["username"] = $username;
		$_SESSION["email"] = $email;
		$_SESSION["user_token"] = $user_token;
		$_SESSION["qr_code"] = $qr_code;
		
		// If there is no error, go to the user interface (dashboard).
		header('Location: ../dashboard.php');
		exit();
	}
	
	// If the user requests to log into an existing account:
	public function user_login_request($u_username, $u_password){
		// Check whether the given account information is accurate.
	    $account_sql = "SELECT * FROM `users` WHERE `username`='$u_username' AND `password`='$u_password'";
		$account_sql_result = mysqli_query($this->conn, $account_sql);
		$account_sql_check = mysqli_num_rows($account_sql_result);
		if($account_sql_check > 0){
			if($row = mysqli_fetch_assoc($account_sql_result)){				
			    // Set the required session variables.
				$_SESSION["name"] = $row['firstname'].' '.$row['lastname'];
				$_SESSION["username"] = $row['username'];
				$_SESSION["email"] = $row['email'];
				$_SESSION["user_token"] = $row['token'];
				$_SESSION["qr_code"] = $row['qr_code'];
				// If there is no error, go to the user interface (dashboard).
				header('Location: ../dashboard.php');
				exit();
			}
		}else{
			header('Location: ../login.php?noAccountFound');
			exit();
		}
	}
	
	// Generate a unique user token.
	private function generate_token($len, $username){
		// Define the main string.
		$lowercase = "abcdefghijklmnopqrstuvwxyz"; $uppercase = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; $number = "0123456789"; $symbol = "*()[]{}#$?!";
		$main = $lowercase.$uppercase.$number.$symbol;
		// Derive the user token from the main string.
		$token = "";
		for ($i=0; $i<$len; $i++){ $token .= $main[random_int(0, (strlen($main)-1))]; }
        return $username."_".$token;
	}
	
	// Create a unique MySQL database table for the new user.
	private function create_products_table($table){
		// Create a new database table.
		$sql_create = "CREATE TABLE `$table`(		
							id int AUTO_INCREMENT PRIMARY KEY NOT NULL,
							product_barcode varchar(255) NOT NULL,
							product_name varchar(255) NOT NULL,
							product_ingredients varchar(255) NOT NULL,
							product_price int NOT NULL,
							cart_number int NOT NULL,
							order_number int NOT NULL
					   );";
		if(mysqli_query($this->conn, $sql_create)){ return true; } else{ return false; }		
	}
	
	// Via Brevo's Email API, send an HTML email to the user.
	public function send_Brevo_email($to_email, $subject, $name, $html_content){
		// Define POST data parameters in the JSON format. 
		$data = '{  
					"sender":{  
								"name":"'.$this->Brevo_email_name.'",
								"email":"'.$this->Brevo_email.'"
							 },
					"to":[  
							 {  
								"email":"'.$to_email.'",
								"name":"'.$name.'"
							 }
						 ],
					"subject":"'.$subject.'",
					"htmlContent":"'.$html_content.'"
				 }';
		// Define the required HTML headers.
		$headers = array('accept: application/json', 'api-key:'.$this->Brevo_API_Key, 'content-type: application/json');
		// Send an HTML email via Brevo's Email API by making a cURL call.
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
		curl_setopt($curl, CURLOPT_URL, $this->Brevo_API_URL);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		// Execute the defined cURL call.
		$result = curl_exec($curl);
		if(!$result){ header('Location: ../?emailServerFailed'); exit(); }
        curl_close($curl);
	}
	
	// Send an account confirmation email to the new user, including the unique account verification QR code.
	private function send_confirmation_email($to_email, $subject, $name, $qr_code){
		// Define the HTML message (content) of the email.
		$html_content = '<html><head><style>h1{text-align:center;font-weight:bold;color:#505F4E;font-size:40px;}a{text-decoration:none;color:#9BB5CE;font-size:18px;font-weight:bold;}div{display:block;background-color:#F9E5C9;text-align:center;border:50px solid #5C5B57;}div p{font-size:25px;color:#505F4E;font-weight:bold;}@media only screen and (max-width: 600px){h1{font-size:20px;}a{font-size:9px;}div{border:10px solid #5C5B57;}div p{font-size:12px;}}</style></head><body><div><h1>Thanks for trying AIoT Shopping Assistant </h1><img src=\"'.$qr_code.'\" alt=\"QR_CODE\" /><p>Please scan the account QR code with the shopping assistant to activate your cart </p><a href=\"http://192.168.1.22/AIoT_Shopping_Assistant/\"> Go to your Dashboard<br><br></a></div></body></html>';
		// Transfer the HTML email.
		$this->send_Brevo_email($to_email, $subject, $name, $html_content);
	}
	

}

// Define the product class and its functions:
class product extends user {
	private $OPENAI_API_KEY = "<_OPENAI_API_KEY_>";
	private $OPENAI_ENDPOINT = "https://api.openai.com/v1/chat/completions";
	
	// Obtain and decrypt the product information from the Open Food Facts JSON API by barcode.
	public function get_product_info($barcode){
		// Make an HTTP GET request to the Open Food Facts JSON API.
		// Then, decode the received JSON object.
		$data = json_decode(file_get_contents("https://world.openfoodfacts.org/api/v0/product/".$barcode.".json", TRUE));
		$product_info = array(
								"name" => $data->product->product_name,
								"ingredients" => (is_null($data->product->ingredients_text_en) || $data->product->ingredients_text_en == "") ? "Not Found" : $data->product->ingredients_text_en,
								"price" => (int)$data->product->product_quantity / 100
							 );
		return $product_info;
	}
	
	// Retrieve the current product list created by the customer.
	public function get_current_products($table){
		$total_price = 0;
		// Obtain the current order tag (number).
		$order_number = $this->get_order_number($table);
		// Obtain all registered product information of the current cart as a list.
		$p_barcode = []; $p_name = []; $p_ingredients = []; $p_price = []; $p_number = [];
		$sql_list = "SELECT * FROM `$table` WHERE `order_number`='$order_number' ORDER BY `id` ASC";
		$result = mysqli_query($this->conn, $sql_list);
		$check = mysqli_num_rows($result);
		if($check > 0){
			while($row = mysqli_fetch_assoc($result)){
				// Store the fetched product information as arrays.
				array_push($p_barcode, $row["product_barcode"]);
				array_push($p_name, $row["product_name"]);
				array_push($p_ingredients, $row["product_ingredients"]);
				array_push($p_price, $row["product_price"]);
				array_push($p_number, $row["cart_number"]);
				// Calculate the total cart price (amount).
				$price = $row["product_price"] * $row["cart_number"];
				$total_price+=$price;
			}
			return array($p_barcode, $p_name, $p_ingredients, $p_price, $p_number, array("total_price" => $total_price));
		}else{
			return array(["Not Found!"], ["Not Found!"], ["Not Found!"], ["Not Found!"], ["Not Found!"], array("total_price" => 0));
		}
	}
	
	// Retrieve and print the previous order lists.  
	public function get_previous_orders($table){
		// Obtain the current order tag (number).
		$order_number = $this->get_order_number($table);
		// If there are any previous orders, return the purchased products as an HTML list for each order.
		if($order_number == 1){
			echo '<h1><i class="fa-solid fa-circle-xmark"></i> No previous order was found!</h1>';
		}else{
			$list = "";
			for($i=1;$i<$order_number;$i++){
				$sql = "SELECT * FROM `$table` WHERE `order_number`='$i' ORDER BY `id` ASC";
				$result = mysqli_query($this->conn, $sql);
				$check = mysqli_num_rows($result);
				if($check > 0){
					while($row = mysqli_fetch_assoc($result)){
						$line = '<li>'.$row["product_name"].' ['.$row["product_barcode"].'] <span><i class="fa-solid fa-xmark"></i></span>'.$row["cart_number"].'</li>';
						$list.=$line;
					}
				}
				echo '<div class="orders"><h2><i class="fa-solid fa-cash-register"></i> Order ['.$i.']</h2><ul>'.$list.'</ul></div>';
				$list = "";			
			}
		}
	}
	
	// Generate the unique payment QR code and notify the user of the placed order via an HTML email.
	public function user_checkout($table, $email, $name){
		// Create a QR code from the user token and the given command.
		$qr_text = 'finished%'.$table;
		$qr_code = "https://chart.googleapis.com/chart?cht=qr&chs=450x450&chl=".$qr_text."&choe=UTF-8";
		
		// Update the successful order number after the checkout process.
		$sql = "UPDATE `users` SET `successful_order`=`successful_order`+1 WHERE `token` = '$table'";
		mysqli_query($this->conn, $sql);
		
		// Send a notification email to the user, including the unique payment QR code.
		$this->send_payment_email($email, "Order Successful", $name, $qr_code);
		
		// If there is no error, go to the user interface (dashboard).
		header('Location: ./dashboard.php?paymentCompleted');
		exit();	
	}
	
	// Send a notification email to the user after completing the checkout process, including the unique payment QR code.
	private function send_payment_email($to_email, $subject, $name, $qr_code){
		// Define the HTML message (content) of the email.
		$html_content = '<html><head><style>h1{text-align:center;font-weight:bold;color:#505F4E;font-size:40px;}a{text-decoration:none;color:#9BB5CE;font-size:18px;font-weight:bold;}div{display:block;background-color:#F9E5C9;text-align:center;border:50px solid #5C5B57;}div p{font-size:25px;color:#505F4E;font-weight:bold;}@media only screen and (max-width: 600px){h1{font-size:20px;}a{font-size:9px;}div{border:10px solid #5C5B57;}div p{font-size:12px;}}</style></head><body><div><h1>Thanks for your order </h1><img src=\"'.$qr_code.'\" alt=\"QR_CODE\" /><p>Please scan your payment QR code with the shopping assistant to complete your order </p><a href=\"http://192.168.1.22/AIoT_Shopping_Assistant/\"> Go to your Dashboard<br><br></a></div></body></html>';
		// Transfer the HTML email.
		$this->send_Brevo_email($to_email, $subject, $name, $html_content);
	}
	
	// Make a cURL call (request) to the OpenAI API in order to get suggestions regarding the given product from ChatGPT.
	public function chatgpt_get_suggestion($product){
		// Define the questions related to the given product.
		$questions = array(
							"What is the nutritional value of ".$product."?",
							"What should I purchase with ".$product."?",
							"Can you teach me a recipe with ".$product."?",
							"How should I serve ".$product."?",
							"Is there a more affordable and healthy option than ".$product."?"
		                  );
		// Define POST data parameters in the JSON format. 
		$data = '{  
					"model": "gpt-3.5-turbo",
					"messages": [
									{"role": "user", "content": "'.$questions[0].'"},
									{"role": "user", "content": "'.$questions[1].'"},
									{"role": "user", "content": "'.$questions[2].'"},
									{"role": "user", "content": "'.$questions[3].'"},
									{"role": "user", "content": "'.$questions[4].'"},
									{"role": "user", "content": "Please add the exact question at the beginning of the answer with the question number."}
								],
					"temperature": 0.7
				 }';
		// Define the required HTML headers.
		$headers = array('Authorization: Bearer '.$this->OPENAI_API_KEY, 'Content-Type: application/json');
		// Obtain product suggestions from ChatGPT by making a cURL call to the OpenAI API.
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_POST, 1);
		curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
		curl_setopt($curl, CURLOPT_URL, $this->OPENAI_ENDPOINT);
		curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		// Execute the defined cURL call.
		$result = curl_exec($curl);
		if(!$result){ header('Location: ../?ChatGPTServerFailed'); exit(); }
        curl_close($curl);
        // Decode the received JSON object to obtain suggestions generated by ChatGPT.
		$res = json_decode($result);
		$suggestions = $res->choices[0]->message->content;
		// Modify the obtained suggestions to add line breaks.
		$modified_suggestions = $suggestions;
		$modified_suggestions = str_replace('1. '.$questions[0], "<h2>Suggestions</h2>", $modified_suggestions);
		for($i=1;$i<count($questions);$i++){
			$modified_suggestions = str_replace(strval($i+1).'. '.$questions[$i], "<br><br>", $modified_suggestions);
		} 
		// Return the modified suggestions and the defined product questions.
		return array($modified_suggestions, $questions);
	}
	
    // Database -> Insert product data
	public function insert_product($table, $barcode, $name, $ingredients, $price){
		// Obtain the current order tag (number).
		$order_number = $this->get_order_number($table);
		// Check whether the given product is in the user's database table or not.
		if($this->check_product($table, $barcode, $order_number)){
			// If the given product is already in the cart (table), update the product amount (cart number).
			$sql_update = "UPDATE `$table` SET `cart_number`=cart_number+1 WHERE `product_barcode` = '$barcode'";
			if(mysqli_query($this->conn, $sql_update)){ return true; } else{ return false; }
		}else{
			// If not, insert the new product information into the user's database table.
			$sql_insert = "INSERT INTO `$table` (`product_barcode`, `product_name`, `product_ingredients`, `product_price`, `cart_number`, `order_number`)
		                   VALUES('$barcode', '$name', '$ingredients', '$price', 1, '$order_number');
					      ";
		    if(mysqli_query($this->conn, $sql_insert)){ return true; } else{ return false; }
		}
	}

    // Database -> Delete product data
	public function delete_product($table, $barcode){
		// Obtain the current order tag (number).
		$order_number = $this->get_order_number($table);
		// Check whether the given product is in the user's database table or not.
		if($this->check_product($table, $barcode, $order_number)){
			// Remove the given product from the cart (table).
			$sql_delete = "DELETE FROM `$table` WHERE `product_barcode`='$barcode' AND `order_number` = '$order_number'";
			if(mysqli_query($this->conn, $sql_delete)){ return true; } else{ return false; }
		}
	}
	
	// Database -> Check database table
	public function check_table($table){
		$sql = "SELECT * FROM `information_schema`.`TABLES` WHERE `table_name` = '$table' limit 1";
		$sql_result = mysqli_query($this->conn, $sql);
		$sql_check = mysqli_num_rows($sql_result);
		if($sql_check > 0){ return true; } else{ return false; }
	}
	
	// Database -> Check product
	private function check_product($table, $barcode, $order_number){
		$sql = "SELECT * FROM `$table` WHERE `product_barcode` = '$barcode' AND `order_number` = '$order_number'";
		$sql_result = mysqli_query($this->conn, $sql);
		$sql_check = mysqli_num_rows($sql_result);
		if($sql_check > 0){ return true; } else{ return false; }
	}
	
    // Database -> Get order number 
	private function get_order_number($token){
		$order_number = 0;
		$sql = "SELECT * FROM `users` WHERE `token` = '$token'";
		$sql_result = mysqli_query($this->conn, $sql);
		$sql_check = mysqli_num_rows($sql_result);
		if($sql_check > 0){
			if($row = mysqli_fetch_assoc($sql_result)){
				$order_number = $row["successful_order"];
			}
			return $order_number;
		}
	}
}

// Define database and server settings:
$server = array(
	"name" => "localhost",
	"username" => "root",
	"password" => "",
	"database" => "shopping_assistant_users"
);

$conn = mysqli_connect($server["name"], $server["username"], $server["password"], $server["database"]);

?>

barcode.php

PHP
<?php

include_once "class.php";

// Define the new '_product' object:
$_product = new product();
$_product->__init__($conn);

if(isset($_GET["table"]) && isset($_GET["barcode"]) && isset($_GET["com"])){	
	// Check whether the given table is in the MySQL database.
	if($_product->check_table($_GET["table"])){
		// Make an HTTP GET request to the Open Food Facts JSON API to obtain the product information with the given barcode.
		$product_info = $_product->get_product_info($_GET["barcode"]);
		// According to the selected command by the user, add or remove the given product to/from the user's database table.
		if($_GET["com"] == "add"){
			$_product->insert_product($_GET["table"], $_GET["barcode"], $product_info["name"], $product_info["ingredients"], $product_info["price"]);
			echo "Given Product Added to the Cart Successfully!";
		}else if($_GET["com"] == "remove"){
			$_product->delete_product($_GET["table"], $_GET["barcode"]);
			echo "Given Product Removed from the Cart Successfully!";
		}
	}else{
		echo "No Table Found!";
	}
}

?>

dashboard_updates.php

PHP
<?php

include_once "class.php";

if(!isset($_SESSION["username"]) && !isset($_SESSION["email"])){
	header('Location: ./');
	exit();
}

// Define the new '_product' object:
$_product = new product();
$_product->__init__($conn);

// Retrieve and print the current product list generated by the customer.
if(isset($_GET["update"])){
	$p_barcode = []; $p_name = []; $p_ingredients = []; $p_price = []; $p_number = []; $total_price = [];
	list($p_barcode, $p_name, $p_ingredients, $p_price, $p_number, $total_price) = $_product->get_current_products($_SESSION["user_token"]);
	$list = "<tr><th>Product</th><th>Barcode</th><th>Ingredients</th><th>Price($)</th><th>Unit</th><th>Counsel</th></tr>";
	for($i=0; $i<count($p_barcode); $i++){
		$list .= '<tr>
					<td>'.$p_name[$i].'</td>
					<td>'.$p_barcode[$i].'</td>
					<td>'.$p_ingredients[$i].'</td>
					<td>'.$p_price[$i].'</td>
					<td>'.$p_number[$i].'</td>
					<td><a href="ChatGPT/?product='.$p_name[$i].'" target="_blank"><button><i class="fa-solid fa-comment-dots"></i> Ask ChatGPT</button></a></td>
				  </tr>
				 ';   
	}
	
	// Create a JSON object from the generated HTML table rows consisting of the product information and the evaluated total cart price.
	$data = array("list" => $list, "total_price" => "$".$total_price["total_price"]);
	$j_data = json_encode($data);
    
	// Return the recently generated JSON object.
	echo($j_data);
}
?>

index.js

JavaScript
// Every 5 seconds, retrieve the HTML table rows generated from the user's database table rows to showcase current products added to the cart
// and inform the user of the calculated total cart price (amount).
setInterval(function(){
	$.ajax({
		url: "./assets/dashboard_updates.php?update",
		type: "GET",
		success: (response) => {
			// Decode the obtained JSON object.
			const data = JSON.parse(response);
			// Assign the HTML table rows as the current product list in the cart. 
			$(".products table").html(data.list);
			// Assign the evaluated total cart price (amount).
			$("#total_price").html(data.total_price);
		}
	});
}, 5000);

// When the user clicks the checkout button, open the checkout page and transfer the evaluated total cart price via the hidden HTML form.
$(".info").on("click", "#checkout", () => {
	var total_price = $("#total_price").text();
	$("#checkout_price").val(total_price);
	$("#hidden_checkout").submit();
});

index.css

CSS
html{background-image:url('background.jpg');background-repeat:no-repeat;background-attachment:fixed;background-size:100% 100%;font-family: 'Kanit', sans-serif;}
h1{text-align:center;font-weight:bold;user-select:none;background:-webkit-linear-gradient(#9BB5CE, #F9E5C9);-webkit-background-clip:text;-webkit-text-fill-color:transparent;}
input{background-image:linear-gradient(45deg, #F9E5C9, #5C5B57);color:#9BB5CE;font-size:18px;font-weight:bold;margin-right:20px;}
label{user-select:none;color:#9BB5CE;font-size:18px;font-weight:bold;padding-left:20px;}

.container{position:relative;background-image:linear-gradient(45deg, #505F4E, #F5F5F0);width:30%;height:30%;margin:auto;margin-top:10%;border:20px solid #5C5B57;border-radius:20px;padding:5px;}
.container div{position:relative;background-color:none;width:100%;height:100%;margin-top:20px;margin-bottom:20px;}
.container div input{position:absolute;right:0;width:35%;}
.container button{display:block;background-image:linear-gradient(45deg, #9BB5CE, #F9E5C9);width:75%;height:auto;margin:auto;margin-top:50px;margin-bottom:25px;font-size:25px;color:#5C5B57;font-weight:bold;border:5px solid #5C5B57;border-radius:15px;}
.container button:hover{cursor:pointer;background-image:linear-gradient(45deg, #9BB5CE, #9BB5CE);}
.container a{user-select:none;font-size:18px;background:-webkit-linear-gradient(#9BB5CE, #9BB5CE);-webkit-background-clip:text;-webkit-text-fill-color:transparent;}
.container a:hover{background:-webkit-linear-gradient(#9BB5CE, #F9E5C9);-webkit-background-clip:text;-webkit-text-fill-color:transparent;}

.products{position:fixed;bottom:5%;left:20px;width:60%;height:75%;background-color:rgba(80, 95, 78, 0.65);overflow-y:auto;border:15px solid rgba(92, 91, 87, 0.85);border-radius:20px;padding:5px;}
.products table{position:relative;width:95%;color:white;margin:auto;margin-top:20px;margin-bottom:20px;border:3px solid #F9E5C9;user-select:none;}
.products th, .products td{border:3px solid #F9E5C9;color:#5C5B57;}
.products th{background-color:#F9E5C9}
.products td{color:white;padding:10px;}
.products button{display:block;width:160px;height:auto;margin:auto;padding:5px;background-image:linear-gradient(45deg, #9BB5CE, #F9E5C9);font-size:15px;color:#5C5B57;font-weight:bold;border:5px solid #5C5B57;border-radius:10px;}
.products button:hover{cursor:pointer;background-image:linear-gradient(45deg, #9BB5CE, #9BB5CE);}
.products a, .products a:hover{text-decoration:none;}

.info{position:fixed;bottom:5%;right:20px;width:30%;height:75%;background-color:rgba(80, 95, 78, 0.65);overflow-y:auto;border:15px solid rgba(92, 91, 87, 0.85);border-radius:20px;padding:5px;}
.info section:nth-of-type(1){position:relative;width:95%;height:50%;margin:auto;background-color:transparent;}
.info section:nth-of-type(1) div{position:relative;top:0;left:0;width:50%;height:100%;background-color:#505F4E;border:10px solid #F9E5C9;border-radius:15px;}
.info section:nth-of-type(1) div button{display:block;position:absolute;left:7%;bottom:10px;width:85%;height:60px;padding:5px;background-image:linear-gradient(45deg, #9BB5CE, #F9E5C9);font-size:25px;color:#F5F5F0;font-weight:bold;border:10px solid #F5F5F0;border-radius:15px;}
.info section:nth-of-type(1) div button:hover{cursor:pointer;background-image:linear-gradient(45deg, #9BB5CE, #9BB5CE);}
.info section:nth-of-type(1) p{user-select:none;color:#F9E5C9;font-size:20px;font-weight:bold;padding-left:5px;}
.info section:nth-of-type(1) span{display:block;text-align:center;color:#9BB5CE;font-size:100px;font-weight:bold;padding-top:15%;}
.info section img{display:inline-block;position:absolute;top:0;right:0;width:250px;height:250px;border:3px solid #F9E5C9;border-radius:5px;padding:5px;transition:1s;}
.info section img:hover{cursor:crosshair;border:3px solid #9BB5CE;padding:8px;transition:1s;}
.info section:nth-of-type(2){position:relative;width:95%;height:35%;margin:auto;background-color:#505F4E;border:10px solid #F9E5C9;border-radius:15px;}
.info section:nth-of-type(2) h2{color:#F9E5C9;padding-left:10px;}
.info section:nth-of-type(2) p{color:#F5F5F0;padding-left:10px;font-weight:bold;}
.info section:nth-of-type(2) span{position:absolute;right:0;padding-right:10px;color:#9BB5CE;}
.info section:nth-of-type(2) button{display:block;position:absolute;left:7%;bottom:20px;width:85%;height:60px;padding:5px;background-image:linear-gradient(45deg, #9BB5CE, #F9E5C9);font-size:25px;color:#F5F5F0;font-weight:bold;border:8px solid #F5F5F0;border-radius:15px;}
.info section:nth-of-type(2) button:hover{cursor:pointer;background-image:linear-gradient(45deg, #9BB5CE, #9BB5CE);}
.info a, .info a:hover{text-decoration:none;}
.logout{display:block;position:absolute;right:5px;top:280px;width:250px;height:60px;padding:5px;background-image:linear-gradient(45deg, #9BB5CE, #F9E5C9);font-size:25px;color:#F5F5F0;font-weight:bold;border:10px solid #F5F5F0;border-radius:15px;}
.logout:hover{cursor:pointer;background-image:linear-gradient(45deg, #9BB5CE, #9BB5CE);}

.orders{display:block;width:55%;height:auto;margin:auto;background-image:linear-gradient(45deg, #505F4E, #F5F5F0);margin-top:35px;border:20px solid #5C5B57;border-radius:20px;padding:10px;}
.orders li{font-weight:bold;font-size:18px;color:#F9E5C9;}
.orders h2{font-weight:bold;color:#9BB5CE;user-select:none;}
.orders span{color:#9BB5CE;padding-left:10px;padding-right:10px;}

#checkout_form fieldset{border:2px solid #F9E5C9;}
#checkout_form legend{background-color:#9BB5CE;color:white;}
#checkout_form img{width:100px;height:auto;}
#checkout_form span{position:absolute;font-weight:bold;font-size:60px;color:#F9E5C9;bottom:25px;right:20px;user-select:none;}


/* Width */
::-webkit-scrollbar {width:5px;height:5px;}
/* Track */
::-webkit-scrollbar-track {background-color:#9BB5CE;}
/* Button */
::-webkit-scrollbar-button{background-color:#F9E5C9;height:5px;width:5px;}
::-webkit-scrollbar-button:hover{background-color:#F5F5F0;}
/* Handle */
::-webkit-scrollbar-thumb {background-color:#F9E5C9;}
::-webkit-scrollbar-thumb:hover {background-color:#F5F5F0;}
/* Corner */
::-webkit-scrollbar-corner{background-color:#F5F5F0;}

index.php

PHP
<?php

session_start();

// If the user has already signed in, go to the user interface (dashboard).
if(isset($_SESSION["username"]) && isset($_SESSION["email"])){
	header('Location: ./dashboard.php');
	exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<title>AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="assets/index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="assets/icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

</head>
<body>
<?php ini_set('display_errors',1);?> 
<h1><i class="fa-sharp fa-solid fa-network-wired"></i> <i class="fa-sharp fa-solid fa-wifi"></i> Please create an account to experience AIoT shopping <i class="fa-regular fa-face-smile"></i></h1>

<div class="container">
<form method="get" action="assets/new_account.php">
<div><label for="firstname">First name:</label><input name="firstname" placeholder="John" id="firstname"></input></div>
<div><label for="lastname">Last name:</label><input name="lastname" placeholder="Doe" id="lastname"></input></div>
<div><label for="email">Email:</label><input name="email" placeholder="johndoe@gmail.com" id="email"></input></div>
<div><label for="username">Username:</label><input name="username" placeholder="John_123" id="username"></input></div>
<div><label for="password">Password:</label><input type="password" name="password" placeholder="000_abc" id="password"></input></div>
<div><label for="c_password">Confirm Password:</label><input type="password" name="c_password" placeholder="000_abc" id="c_password"></input></div>
<button type="submit"><i class="fa-solid fa-user-check"></i> Create New Account</button>
<p style="text-align:center;"><a href="./login.php">Already have an account?</a></p>
</form>
</div>
</body>
</html>

login.php

PHP
<?php

session_start();

// If the user has already signed in, go to the user interface (dashboard).
if(isset($_SESSION["username"]) && isset($_SESSION["email"])){
	header('Location: ./dashboard.php');
	exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Login / AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="assets/index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="assets/icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

</head>
<body>
<?php ini_set('display_errors',1);?> 
<h1><i class="fa-sharp fa-solid fa-network-wired"></i> <i class="fa-sharp fa-solid fa-wifi"></i> Please sign in to experience AIoT shopping <i class="fa-regular fa-face-smile"></i></h1>

<div class="container">
<form method="get" action="assets/new_account.php">
<div><label for="u_username">Username:</label><input name="u_username" placeholder="John_123" id="u_username"></input></div>
<div><label for="u_password">Password:</label><input type="password" name="u_password" placeholder="000_abc" id="u_password"></input></div>
<button type="submit"><i class="fa-solid fa-house-circle-check"></i> Sign In</button>
</form>
</div>
</body>
</html>

main.py

Python
# AI-driven IoT Shopping Assistant w/ ChatGPT
#
# STM32 Nucleo-144 NUCLEO-F439ZI
#
# By Kutluhan Aktar
#
# Activate your cart with a QR code sent via email by the web app, update product info by scanning barcodes,
# and get shopping tips from ChatGPT. 
# 
#
# For more information:
# https://www.theamplituhedron.com/projects/AI_assisted_IoT_Shopping_Assistant_w_ChatGPT

from usocket import socket
from wiznet_conf import wiznet5k_w5300
import urequests
import network
from pyb import Pin, UART, SPI
from ssd1309 import Display
from xglcd_font import XglcdFont
from Adafruit_Thermal import *
from time import sleep

# Create the shopping_assistant class and define its functions. 
class shopping_assistant:
    def __init__(self):
        # Define the W5300 object and the static IP address settings.
        self.w5300 = wiznet5k_w5300()
        self.w5300.w5300_set_ip('0.0.0.0','0.0.0.0','0.0.0.0','0.0.0.0')
        # Define the required print and hardware serial port settings for the tiny (embedded) thermal printer.
        self.printer = Adafruit_Thermal(bus=6, heattime=120, heatdots=5, heatinterval=40)
        # Define the required hardware serial port settings for the GM77 barcode and QR code scanner.
        self.scanner = UART(2, 9600, bits=8, parity=None, stop=1)
        self.user_token = ""
        self.new_product_barcode = ""
        # Define the required settings for the SSD1309 OLED transparent display. (SCK: PA5, MOSI: PA7)
        spi = SPI(1, SPI.MASTER, baudrate=10000000)
        self.display = Display(spi, dc=Pin("A4"), cs=Pin("C6"), rst=Pin("C7"))
        # Define the given fonts.
        self.bold = XglcdFont('assets/Unispace12x24.c', 12, 24)
        self.light = XglcdFont('assets/Bally5x8.c', 5, 8)
        # Define the control button pins.
        self.button_A = Pin("C0", Pin.IN, Pin.PULL_UP)
        self.button_B = Pin("C3", Pin.IN, Pin.PULL_UP)
        self.button_C = Pin("C2", Pin.IN, Pin.PULL_UP)
        # Define the RGB LED pins.
        self.red = Pin("A1", Pin.OUT_PP)
        self.blue = Pin("A0", Pin.OUT_PP)
        self.green = Pin("F9", Pin.OUT_PP)
        self.adjust_color([0,0,0])
        sleep(2)
        # Initialize the SSD1309 OLED transparent display.
        self.product_menu_activate = False
        self.change_layout("home")

    # If the scanner module reads a barcode or QR code successfully, decode the scanned data.
    def read_QR_barcode(self):
        scanned_data = self.scanner.readline()
        # Decode and modify the received data packet to obtain the user (account) token with the given command or the new product barcode.
        if(type(scanned_data) is not type(None)):
            decoded_data = scanned_data.decode("utf_8")
            decoded_data = decoded_data.replace("\r", "")
            print("\nScanned: " + decoded_data)
            # Get the user token.
            if(decoded_data.find("user%") >= 0):
                self.user_token = decoded_data.split("%")[1]
                print("\nYour cart registered successfully!")
                print("Registered Token: " + self.user_token)
                self.change_layout("register")
                sleep(10)
                self.change_layout("scan")
            # After getting the finished command, discard the registered user token to deactivate the cart.
            elif(decoded_data.find("finished%") >= 0):
                given_token = decoded_data.split("%")[1]
                if(given_token == self.user_token):
                    print("\nPayment Received Successfully!")
                    print("Your cart discarded successfully!")
                    self.change_layout("payment")
                    sleep(2)
                    # Notify the customer via the thermal printer.
                    self.print_status(True)
                    self.change_layout("home")
                    self.user_token = ""
            # Get the product barcode.
            else:
                if(self.user_token != ""):
                    self.new_product_barcode = decoded_data
                    print("New Product Barcode: " + self.new_product_barcode)
                    self.product_menu_activate = True
                    if(self.product_menu_activate == True):
                        self.change_layout("barcode")
                        while(self.product_menu_activate == True):
                            self.product_menu()
                else:
                    print("\nPlease scan your unique account QR code to register your cart.") 
        sleep(1)
        
    # Make an HTTP GET request to the AIoT Shopping Assistant web application with the obtained barcode.
    def make_get_request(self, barcode, com="add"):
        path = "http://192.168.1.22/AIoT_Shopping_Assistant/assets/barcode.php?table={}&barcode={}&com={}".format(self.user_token, barcode, com)
        # Make an HTTP GET request.
        request = urequests.get(path)
        print("\nURL => "+path)
        print("App Response => ")
        print(request.text)
        sleep(1)
    
    # Display the product menu (interface) when the scanner detects a new product barcode.
    def product_menu(self):
        print("Press: Button (A) -> Add | Button (B) -> Remove")
        sleep(1)
        if(self.button_A.value() == False):
            self.make_get_request(self.new_product_barcode, "add")
            self.change_layout("add")
            sleep(10)
            self.change_layout("scan")
            self.product_menu_activate = False
        if(self.button_B.value() == False):
            self.make_get_request(self.new_product_barcode, "remove")
            self.change_layout("remove")
            sleep(10)
            self.change_layout("scan")
            self.product_menu_activate = False
            
    # If requested, print the current device status via the tiny (embedded) thermal printer.
    def print_status(self, payment=False):
        if(self.button_C.value() == False):
            print("\nPrinting the device status...")
            # Change the thermal printer hardware settings to obtain smoother prints depending on the targeted feature.
            if(self.user_token == ""):
                self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
                self.printer.printBMPImage('assets/printer_chatgpt.bmp')
                self.printer = Adafruit_Thermal(bus=6, heattime=120, heatdots=5, heatinterval=40)
                self.printer.justify('C')
                self.printer.setSize('L')
                self.printer.println("AIoT")
                self.printer.println("Shopping")
                self.printer.println("Assistant")
                self.printer.println("Status\n\n")
                self.printer.justify('L')
                self.printer.setSize('S')
                self.printer.boldOn()
                self.printer.println("Please scan")
                self.printer.println("your unique")
                self.printer.println("account QR code")
                self.printer.println("to activate your")
                self.printer.println("cart and start")
                self.printer.println("shopping!\n\n")
                self.printer.boldOff()
                self.printer.justify('R')
                self.printer.setSize('M')
                self.printer.inverseOn()
                self.printer.println(" Have a ")
                self.printer.println(" Great ")
                self.printer.println(" Day :) \n")
                self.printer.inverseOff()
                self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
                self.printer.printBMPImage('assets/printer_scan.bmp')
                self.printer.feed(5)
            elif(self.user_token != ""):
                self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
                self.printer.printBMPImage('assets/printer_chatgpt.bmp')
                self.printer = Adafruit_Thermal(bus=6, heattime=120, heatdots=5, heatinterval=40)
                self.printer.justify('C')
                self.printer.setSize('L')
                self.printer.println("AIoT")
                self.printer.println("Shopping")
                self.printer.println("Assistant")
                self.printer.println("Status\n\n")
                self.printer.justify('L')
                self.printer.setSize('S')
                self.printer.boldOn()
                self.printer.println("Your cart is")
                self.printer.println("registered and")
                self.printer.println("initialized")
                self.printer.println("successfully.")
                self.printer.println("Please scan a")
                self.printer.println("product barcode")
                self.printer.println("to change")
                self.printer.println("the cart")
                self.printer.println("items!\n\n")
                self.printer.println("Registered Token:")
                self.printer.doubleHeightOn()
                self.printer.println(self.user_token)
                self.printer.println("\n")
                self.printer.doubleHeightOff()
                self.printer.boldOff()
                self.printer.justify('R')
                self.printer.setSize('M')
                self.printer.inverseOn()
                self.printer.println(" Have a ")
                self.printer.println(" Great ")
                self.printer.println(" Day :) \n")
                self.printer.inverseOff()
                self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
                self.printer.printBMPImage('assets/printer_cart.bmp')
                self.printer.feed(5)
        # If the customer places an order successfully:
        if(payment == True):
            self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
            self.printer.printBMPImage('assets/printer_chatgpt.bmp')
            self.printer = Adafruit_Thermal(bus=6, heattime=120, heatdots=5, heatinterval=40)
            self.printer.justify('C')
            self.printer.setSize('L')
            self.printer.println("AIoT")
            self.printer.println("Shopping")
            self.printer.println("Assistant")
            self.printer.println("Status\n\n")
            self.printer.justify('L')
            self.printer.setSize('S')
            self.printer.boldOn()
            self.printer.println("Payment for")
            self.printer.println("your latest")
            self.printer.println("order is received")
            self.printer.println("successfully via")
            self.printer.println("your dashboard")
            self.printer.println("on the web")
            self.printer.println("application.")
            self.printer.println("Please scan")
            self.printer.println("your account")
            self.printer.println("QR code to")
            self.printer.println("activate your")
            self.printer.println("cart for")
            self.printer.println("your next")
            self.printer.println("order!\n\n")
            self.printer.println("Removed Token:")
            self.printer.doubleHeightOn()
            self.printer.println(self.user_token)
            self.printer.println("\n")
            self.printer.doubleHeightOff()
            self.printer.boldOff()
            self.printer.justify('R')
            self.printer.setSize('M')
            self.printer.inverseOn()
            self.printer.println(" Have a ")
            self.printer.println(" Great ")
            self.printer.println(" Day :) \n")
            self.printer.inverseOff()
            self.printer = Adafruit_Thermal(bus=6, heattime=155, heatdots=1, heatinterval=1)
            self.printer.printBMPImage('assets/printer_payment.bmp')
            self.printer.feed(5)
                           
    # Change the layout on the SSD1309 OLED transparent display depending on the given command.
    def change_layout(self, activated):
        self.display.clear_buffers()
        if(activated == "home"):
            self.adjust_color([0,1,0])
            self.display.draw_bitmap("assets/cart.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Please scan", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "your unique", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "account QR ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "code to    ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "activate   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "your cart! ", self.light, invert=True)
        elif(activated == "scan"):
            self.adjust_color([0,1,1])
            self.display.draw_bitmap("assets/chatgpt.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Please scan", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "a product  ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "barcode to ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "change     ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "the cart   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "items!     ", self.light, invert=True)
        elif(activated == "register"):
            self.adjust_color([0,0,1])
            self.display.draw_bitmap("assets/registered.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Account QR ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "code       ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "registered ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "and your   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "cart       ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "is ready!  ", self.light, invert=True)        
        elif(activated == "barcode"):
            self.adjust_color([1,0,1])
            self.display.draw_bitmap("assets/barcode.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Press:     ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "           ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "Button (A) ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "-> Add     ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "Button (B) ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "-> Remove  ", self.light, invert=True)
        elif(activated == "add"):
            self.adjust_color([0,0,1])
            self.display.draw_bitmap("assets/add.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Given      ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "product    ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "added to   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "your       ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "registered ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "cart!      ", self.light, invert=True)
        elif(activated == "remove"):
            self.adjust_color([1,0,0])
            self.display.draw_bitmap("assets/remove.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Given      ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "product    ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "removed    ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "from your  ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "registered ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "cart!      ", self.light, invert=True)
        elif(activated == "payment"):
            self.adjust_color([1,1,1])
            self.display.draw_bitmap("assets/payment.mono", 5, (self.display.height-48) // 2, 48, 48, invert=True)
            self.display.draw_text(48+10, (self.display.height-48) // 2, "Order      ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*1), "payment    ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*2), "received   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*3), "and your   ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*4), "cart       ", self.light, invert=True)
            self.display.draw_text(48+10, ((self.display.height-48) // 2) + (self.light.height*5), "deactivated", self.light, invert=True)            
        self.display.present()
        sleep(1)
            
    def adjust_color(self, color):
        self.red.value(1-color[0])
        self.blue.value(1-color[1])
        self.green.value(1-color[2])
    
    def start(self):
        self.read_QR_barcode()
        self.print_status()
            

# Define the assistant object.
assistant = shopping_assistant()

while True:
    assistant.start()

dashboard.php

PHP
<?php

session_start();

// If the user signed in successfully, proceed.
if(!isset($_SESSION["username"]) && !isset($_SESSION["email"])){
	header('Location: ./');
	exit();
}

// If the user requests to log out:
if(isset($_GET["logout"])){
	// Remove and destroy all session variables.
	session_unset();
	session_destroy();
	// Go to the home page.
	header('Location: ./');
	exit();
}
?>

<!DOCTYPE html>
<html>
<head>
<title>Dashboard / AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="assets/index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="assets/icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

<!--link to jQuery script-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

</head>
<body>
<?php ini_set('display_errors',1);?> 
<h1 style="text-align:left;padding-left:20px;margin-top:60px;"><i class="fa-solid fa-keyboard"></i> Welcome to your Dashboard</h1>
<div class="products">
<table>
<tr><th>Product</th><th>Barcode</th><th>Ingredients</th><th>Price($)</th><th>Unit</th><th>Counsel</th></tr>
<tr><td>X</td><td>X</td><td>X</td><td>X</td><td>X</td><td><a href="ChatGPT/?product=Not Found!" target="_blank"><button><i class="fa-solid fa-comment-dots"></i> Ask ChatGPT</button></a></td></tr>
</table>
</div>

<div class="info">
<br>
<section>
<div>
<p><i class="fa-solid fa-money-check-dollar"></i> Total Price:</p>
<span id="total_price">$0</span>
<form><button id="checkout"><i class="fa-solid fa-cart-shopping"></i> Checkout</button></form>
</div>
<img src="<?php echo $_SESSION["qr_code"] ?>" alt="QR_CODE" />
<a href="?logout=OK"><button class="logout"><i class="fa-solid fa-door-open"></i> Logout</button></a>
</section>
<br>
<section>
<h2><i class="fa-solid fa-address-card"></i> Account Information</h2>
<p>Name: <span><?php echo $_SESSION["name"]; ?></span></p>
<p>Email: <span><?php echo $_SESSION["email"]; ?></span></p>
<p>Username: <span><?php echo $_SESSION["username"]; ?></span></p>
<a href="previous_orders.php" target="_blank"><button><i class="fa-solid fa-backward"> </i> Previous Orders</button></a>
</section>
</div>

<form id="hidden_checkout" action="checkout.php" method="post" target="_blank" style="display:none;">
<input id="checkout_price" name="checkout_price" type="hidden" value="$0">
</form>

<!--Add the index.js file-->
<script type="text/javascript" src="assets/index.js"></script>

</body>
</html>

checkout.php

PHP
<?php

include_once "assets/class.php";

// Define the new '_product' object:
$_product = new product();
$_product->__init__($conn);

// If the user signed in successfully, proceed.
if(!isset($_SESSION["username"]) && !isset($_SESSION["email"])){
	header('Location: ./');
	exit();
}

// If the user places an order by entering the requested credit/debit card information:
if(isset($_GET["c_number"]) && isset($_GET["c_name"]) && isset($_GET["c_date"]) && isset($_GET["c_verify"])){
	$_product->user_checkout($_SESSION["user_token"], $_SESSION["email"], $_SESSION["name"]);
}

?>

<!DOCTYPE html>
<html>
<head>
<title>Checkout / AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="assets/index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="assets/icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

</head>
<body>
<?php ini_set('display_errors',1);?> 
<h1 style="text-align:left;padding-left:20px;margin-top:60px;"><i class="fa-solid fa-cart-shopping"></i> Checkout</h1>

<div class="container">
<form method="get" action="" id="checkout_form">
<br>
<fieldset>
<legend> Credit or Debit Card </legend>
<div><label for="c_number">Card Number:</label><input name="c_number" placeholder="4111 1111 1111 1111" id="c_number"></input></div>
<div><label for="c_name">Name:</label><input name="c_name" placeholder="John Doe" id="c_name"></input></div>
<div><label for="c_date">Expiration Date:</label><input name="c_date" placeholder="12/2023" id="c_date"></input></div>
<div><label for="c_verify">Card Verification Number:</label><input name="c_verify" placeholder="123" id="c_verify"></input></div>
<button type="submit"><i class="fa-solid fa-money-check-dollar"></i> Pay</button>
<img src="assets/credit.jpg" alt="credit" />
<span>
<?php
// Check whether the total price variable is received.
if(isset($_POST["checkout_price"])){
	echo $_POST["checkout_price"];
}else{
	echo "$0";
}
?>
</span>
</fieldset>
<br>
</form>
</div>
</body>
</html>

previous_orders.php

PHP
<?php

include_once "assets/class.php";

// Define the new '_product' object:
$_product = new product();
$_product->__init__($conn);

// If the user signed in successfully, proceed.
if(!isset($_SESSION["username"]) && !isset($_SESSION["email"])){
	header('Location: ./');
	exit();
}

?>

<!DOCTYPE html>
<html>
<head>
<title>Orders / AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="assets/index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="assets/icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

</head>
<body>
<?php ini_set('display_errors',1);?> 

<?php

$_product->get_previous_orders($_SESSION["user_token"]);

?>

</body>
</html>

index.php (ChatGPT)

PHP
<?php

include_once "../assets/class.php";

// Define the new '_product' object:
$_product = new product();
$_product->__init__($conn);

if(!isset($_SESSION["username"]) && !isset($_SESSION["email"])){
	header('Location: ./');
	exit();
}

// Make a cURL call (request) to the OpenAI API in order to get suggestions regarding the given product from ChatGPT.
$suggestions = "<h2>Please enter a product name.</h2>";
$questions = ["Please enter a product name."];
if(isset($_GET["product"]) && $_GET["product"] != "Not Found!"){
	list($suggestions, $questions) = $_product->chatgpt_get_suggestion($_GET["product"]);
}


?>

<!DOCTYPE html>
<html>
<head>
<title>ChatGPT / AIoT Shopping Assistant</title>

<!--link to index.css-->
<link rel="stylesheet" type="text/css" href="index.css"></link>

<!--link to favicon-->
<link rel="icon" type="image/png" sizes="36x36" href="icon.png">

<!-- link to FontAwesome-->
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v6.2.1/css/all.css">
 
<!-- link to font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Kanit&display=swap" rel="stylesheet">

</head>
<body>
<?php ini_set('display_errors',1);?> 
<h1><i class="fa-solid fa-network-wired"></i> Powered by ChatGPT</h1>
<div class="question">
<?php

for($i=0;$i<count($questions);$i++){
	echo '<h2><i class="fa-regular fa-comment-dots"></i> '.$questions[$i].'</h2>';
}

?>
</div>
<br>
<div class="reply">
<p><img src="icon.png" alt="ChatGPT" />
<?php

echo $suggestions;

?>
</p>
</div>

</body>
</html>

index.css (ChatGPT)

CSS
html{background-color:#00A67E;font-family: 'Kanit', sans-serif;}
h1{text-align:left;font-weight:bold;user-select:none;background:-webkit-linear-gradient(#5C5B57, #505F4E);-webkit-background-clip:text;-webkit-text-fill-color:transparent;padding-left:2%;}

.question{background-image:linear-gradient(45deg, #5C5B57, #505F4E);margin-left:2%;width:40%;height:auto;min-height:200px;border:12px solid #9BB5CE;border-radius:20px;padding-left:30px;padding-right:30px;}
.question h2{color:#9BB5CE;padding-left:5px;}

.reply{background-image:linear-gradient(45deg, #5C5B57, #505F4E);margin-left:20%;width:60%;height:auto;min-height:200px;border:12px solid #F9E5C9;border-radius:20px;padding-left:30px;padding-right:30px;color:#F5F5F0;font-weight:bold;}
.reply img{float:left;width:150px;height:150px;border-radius:50%;margin-right:20px;}
.reply h2{color:#F9E5C9;font-weight:bold;}


/* Width */
::-webkit-scrollbar {width:5px;height:5px;}
/* Track */
::-webkit-scrollbar-track {background-color:#9BB5CE;}
/* Button */
::-webkit-scrollbar-button{background-color:#F9E5C9;height:5px;width:5px;}
::-webkit-scrollbar-button:hover{background-color:#F5F5F0;}
/* Handle */
::-webkit-scrollbar-thumb {background-color:#F9E5C9;}
::-webkit-scrollbar-thumb:hover {background-color:#F5F5F0;}
/* Corner */
::-webkit-scrollbar-corner{background-color:#F5F5F0;}

Credits

Kutluhan Aktar

Kutluhan Aktar

81 projects • 307 followers
AI & Full-Stack Developer | @EdgeImpulse | @Particle | Maker | Independent Researcher

Comments