How to create and integrate a ChatGPT AI bot into Laravel?
Discover how to create and integrate a ChatGPT AI bot into your Laravel application with this comprehensive guide. It covers all the essential steps to enhance user interaction with AI-driven conversational capabilities. First, you'll need to obtain your API keys. To generate them, log in or create an account on platform.openai.com. Once logged in, locate the API keys option on the left sidebar, click on it, and generate your API keys there.
Preview :
We'll need a database to save our chat with the bot. Let's create the model, migration, and controller. Use the following command to create all three components at once.
php artisan make:model ChatGpt -mcr
At this point, a migration file, model, and controller should have been created. Navigate to 'database/migrations', where you'll find a file named '_create_chat_gpt_table.php'. Open that file and add the following fields.
Schema::create('chat_gpt', function (Blueprint $table) {
$table->id();
$table->integer('send_by');
$table->integer('send_to');
$table->longText('message');
$table->tinyInteger('status')->default(0);
$table->tinyInteger('deleted')->default(0);
$table->timestamps();
});
Execute the following command to apply the migration to the database.
php artisan migrate
The '-mcr' command creates a resource route that we do not need. Therefore, we will add the necessary routes and delete all pre-written functions in the 'ChatGptController'.
use App\Http\Controllers\ChatGptController;
// ChatGpt AI Bot Routes
Route::get('chat-gpt', [ChatGptController::class, 'index'])->name('chat-gpt.index');
Route::post('ajax/send-message', [ChatGptController::class, 'sendMessage'])->name('send.message');
Route::get('ajax/load-messages', [ChatGptController::class, 'loadMessages'])->name('load.messages');
Route::post('ajax/receive-reply', [ChatGptController::class, 'receiveReply'])->name('receive.reply');
Route::delete('delete-chat/{id}', [ChatGptController::class, 'destroy'])->name('chat.destroy');
Now, let's navigate to 'ChatGptController', work on the 'index' function, and create its corresponding file.
public function index()
{
return view('chat-gpt.index');
}
Let's create a basic chat design. Start by creating a blade file in 'resources/views/chat-gpt/index.blade.php'.
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">{{ __('Chat with AI Bot') }}</div>
<div class="card-body" id="chat-body"></div>
<div class="card-footer text-end">
<div class="input-group">
<input type="text" id="message-inp" class="form-control" placeholder="Type your message here..." aria-label="Message" aria-describedby="send-btn">
<div class="input-group-append">
<span class="input-group-text cursor-pointer" onclick="sendMessage()">Send</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@endsection
We will break the code into sections to ensure clarity and avoid any confusion, The above code is for base design, Now we can add CSS on top and Javascript on bottom
<style>
.cursor-pointer
{
cursor: pointer;
}
.bot-message
{
background-color: #e5e4e4;
color: black;
padding: 10px;
border-radius: 10px;
margin-bottom: 20px;
width: 50%;
}
.my-message
{
background-color: #657be4;
color: white;
padding: 10px;
border-radius: 10px;
margin-bottom: 20px;
width: 50%;
margin-left: auto;
}
.message-date
{
text-align: center;
padding-bottom: 30px;
}
ul
{
list-style: none;
padding-left: 0;
}
#chat-body
{
height: 600px;
overflow: auto;
}
#message-typing
{
width: 15%;
}
</style>
Before we dive into JavaScript, we need to create a few functions and a file to load messages without refreshing the page. Let's start by creating a function named 'loadMessages' in the 'ChatGptController'.
use App\Models\ChatGpt;
public function loadMessages()
{
$auth_id = auth()->id();
$chats = ChatGpt::where('deleted',0)
->where('send_by',$auth_id)
->orWhere('send_to',$auth_id)
->orderBy('created_at')
->get()->groupBy(function($data) {
return $data->created_at->format('d M Y');
})->toArray();
$output = view('chat-gpt.ajax.messages',compact('auth_id','chats'))->render();
return $output;
}
Now, let's create a blade file for rendering in 'resources/views/chat-gpt/ajax/messages.blade.php'.
<ul>
@if(count($chats) > 0)
@foreach($chats as $date => $chat)
// message group by date
<li class="message-date">
<span class="badge bg-secondary">{{ \Carbon\Carbon::parse($date)->isToday() ? 'Today' : $date }}</span>
</li>
@foreach($chat as $ch)
@if($ch['send_by'] == $auth_id)
// message you sent
<li class="my-message">
{!! nl2br($ch['message']) !!}
</li>
@else
// response message from bot
<li class="bot-message">
{!! nl2br($ch['message']) !!}
</li>
@endif
@endforeach
@endforeach
@else
// no chat message
<li class="message-date">
<span class="badge bg-secondary">No Chats</span>
</li>
@endif
// waiting animation
<li class="bot-message d-none" id="message-typing">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin: auto;display: block;shape-rendering: auto;width: 43px;height: 20px;" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<circle cx="0" cy="44.1678" r="15" fill="#ffffff">
<animate attributeName="cy" calcMode="spline" keySplines="0 0.5 0.5 1;0.5 0 1 0.5;0.5 0.5 0.5 0.5" repeatCount="indefinite" values="57.5;42.5;57.5;57.5" keyTimes="0;0.3;0.6;1" dur="1s" begin="-0.6s"></animate>
</circle> <circle cx="45" cy="43.0965" r="15" fill="#ffffff">
<animate attributeName="cy" calcMode="spline" keySplines="0 0.5 0.5 1;0.5 0 1 0.5;0.5 0.5 0.5 0.5" repeatCount="indefinite" values="57.5;42.5;57.5;57.5" keyTimes="0;0.3;0.6;1" dur="1s" begin="-0.39999999999999997s"></animate>
</circle> <circle cx="90" cy="52.0442" r="15" fill="#ffffff">
<animate attributeName="cy" calcMode="spline" keySplines="0 0.5 0.5 1;0.5 0 1 0.5;0.5 0.5 0.5 0.5" repeatCount="indefinite" values="57.5;42.5;57.5;57.5" keyTimes="0;0.3;0.6;1" dur="1s" begin="-0.19999999999999998s"></animate>
</circle>
</svg>
</li>
</ul>
Include the jQuery CDN , 'scrollDown' and 'loadMessages' functions in 'index.blade.php'.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<script>
$(document).ready(function () {
loadMessages();
});
function loadMessages()
{
$('#chat-body').load('{{ route('load.messages') }}');
}
function scrollDown(time = 1500)
{
var content = $('#chat-body');
content.finish().animate({
scrollTop: content.prop("scrollHeight")
}, time);
}
</script>
Return to 'ChatGptController' and create a function called 'sendMessage'.
public function sendMessage(Request $request)
{
$auth_id = auth()->id();
$message = $request->message;
if(!empty($message))
{
// SAVE USER MESSAGE
$newMessage = new ChatGpt();
$newMessage->send_by = $auth_id;
$newMessage->send_to = 0;
$newMessage->message = $message;
$newMessage->status = 1;
$newMessage->save();
$chats = ChatGpt::where('deleted',0)
->where('send_by',$auth_id)
->orWhere('send_to',$auth_id)
->orderBy('created_at')
->get()->groupBy(function($data) {
return $data->created_at->format('d M Y');
})->toArray();
$output = view('chat-gpt.ajax.messages',compact('auth_id','chats'))->render();
return [
'status' => 'success',
'output' => $output
];
}
else
{
return [
'status' => 'error',
'message' => 'Message is required.'
];
}
}
Now add it's script in 'index.blade.php'
function sendMessage()
{
var messageElm = $('#message-inp');
messageElm.prop('readonly',true);
var message = messageElm.val();
if(message != '')
{
$.ajax({
type: 'POST',
url: '{{ route('send.message') }}',
data: {
message: message
},
success: function (response)
{
if (response.status == 'success')
{
messageElm.val('');
$("#chat-body").html('');
$("#chat-body").html(response.output);
receiveReply(message)
scrollDown();
}
else
{
console.log('Error : ' + response.message);
}
},
error: function (response)
{
console.log('Error : Something went wrong!');
}
});
}
}
Before we start working on the 'receiveReply' function, we need to bypass the 'ajax' routes from CSRF verification. This step is not mandatory, but I prefer to bypass CSRF verification for ajax calls. To do this, open 'app/Http/Middleware/VerifyCsrfToken.php' and add the following code.
protected $except = [
'*/ajax/*'
];
Now, let's navigate to 'ChatGptController' and create two functions named 'receiveReply' and 'generateReply'.
public function receiveReply(Request $request)
{
$auth_id = auth()->id();
$message = $request->message;
// GENERATE MESSAGE FROM AI
$aiMessage = self::generateReply($message);
// SAVE AI RESPONSE
$newMessage = new ChatGpt();
$newMessage->send_by = 0;
$newMessage->send_to = $auth_id;
$newMessage->message = $aiMessage;
$newMessage->status = 1;
$newMessage->save();
$chats = ChatGpt::where('deleted',0)
->where('send_by',$auth_id)
->orWhere('send_to',$auth_id)
->orderBy('created_at')
->get()->groupBy(function($data) {
return $data->created_at->format('d M Y');
})->toArray();
$output = view('chat-gpt.ajax.messages',compact('auth_id','chats'))->render();
return [
'status' => 'success',
'output' => $output
];
}
The 'generateReply' function will invoke the API and generate a response based on the message sent.
use GuzzleHttp\Client as GuzzleClient;
public static function generateReply($message)
{
// URL for the OpenAI API endpoint for chat completions
$apiUrl = 'https://api.openai.com/v1/chat/completions';
// Your API key for accessing OpenAI services
$apiKey = 'SECRET_KEY';
// The version of the model you want to use (e.g., GPT-3.5 or GPT-4)
$modelVersion = 'gpt-4o'; // gpt-3.5-turbo || gpt-4o-mini || gpt-4o
// Initialize a new Guzzle HTTP client
$client = new GuzzleClient();
// Data to be sent to the API, including the model version and messages
$data = [
'model' => $modelVersion,
'messages' => [
[
'role' => 'user',
'content' => $message,
],
],
];
// Headers for the HTTP request, including content type and authorization
$headers = [
'Content-Type' => 'application/json',
'Authorization' => 'Bearer ' . $apiKey,
];
try {
// Send the POST request to the API with the headers and data
$response = $client->post($apiUrl, [
'headers' => $headers,
'json' => $data,
]);
// Decode the JSON response from the API
$result = json_decode($response->getBody(), true);
// Check if the API returned a valid response and extract the content
if (isset($result['choices'][0]['message']['content']))
{
$content = $result['choices'][0]['message']['content'];
return $content;
}
else
{
// Return an error message if no content is received from the AI
return 'Error: No content received from AI.';
}
}
catch (\Exception $e)
{
// Return the error message in case of an exception
return 'Error: ' . $e->getMessage();
}
}
At last, go to 'index.blade.php' and add the script for the 'receiveReply' function.
function receiveReply(message)
{
$('#message-typing').removeClass('d-none');
$.ajax({
type: 'POST',
url: '{{ route('receive.reply') }}',
data: {
message: message
},
success: function (response)
{
if (response.status == 'success')
{
var messageElm = $('#message-inp');
messageElm.prop('readonly',false);
$("#chat-body").html('');
$("#chat-body").html(response.output);
scrollDown();
}
else
{
console.log('Error : ' + response.message);
}
},
error: function (response)
{
console.log('Error : Something went wrong!');
}
});
}
Related Posts
How to us factory in laravel?
How to create a common dynamic modal in Laravel?
How to edit env dynamically in laravel?
How to solve CORS error in laravel?
How to integrate ChatGPT into Laravel?
How to use seeder in laravel?
How to create multi auth in laravel with 2 different login page?
Most Useful Laravel Commands
How to save image from a url in laravel?
How to run laravel 10 project without artisan serve?