Laravel Chatgpt implementation for Doctor appointment
//AppointmentController.php code
public function check(Request $request)
{
$request->validate([
'user_id' => 'required|integer|exists:users,id',
'service_id' => 'required|integer|exists:services,id',
'admin_id' => 'required|integer|exists:admins,id',
'appointment_date' => 'required|date'
]);
$doctor = Admin::where('id', $request->admin_id)
->whereHas('role', fn($q) => $q->where('name', 'Doctor'))
->firstOrFail();
$service = Service::findOrFail($request->service_id);
$date = $request->appointment_date;
$dayOfWeek = date('l', strtotime($date));
$schedule = DoctorSchedule::where('admin_id', $doctor->id)
->whereHas('day', fn($q) => $q->where('name', $dayOfWeek))
->first();
$scheduleText = $schedule
? "{$schedule->day_id}: {$schedule->start_time} - {$schedule->end_time}"
: "Doctor not available on {$dayOfWeek}";
$prompt = "A patient named {$request->name} wants to book a {$service->title} with Dr. {$doctor->name} on {$date}.
The doctor's schedule for {$dayOfWeek} is {$scheduleText}.
Suggest 2-3 available appointment time slots during working hours.
If the doctor is unavailable on that day, suggest the next available day.";
$apiKey = gs()->open_ai_key;
$payload = [
'model' => 'gpt-4o-mini',
'messages' => [
['role' => 'system', 'content' => 'You are an AI scheduling assistant for a dental clinic.'],
['role' => 'user', 'content' => $prompt],
],
'temperature' => 0.5,
];
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . $apiKey,
'Content-Type' => 'application/json',
])->post('https://api.openai.com/v1/chat/completions', $payload);
$data = $response->json();
$aiMessage = $data['choices'][0]['message']['content'] ?? 'No suggestion generated.';
return response()->json([
'success' => true,
'ai_message' => nl2br(e($aiMessage)),
]);
}
public function book(Request $request)
{
$request->validate([
'user_id' => 'required|integer|exists:users,id',
'service_id' => 'required|integer|exists:services,id',
'admin_id' => 'required|integer|exists:admins,id',
'doctor_schedule_id' => 'required|integer|exists:doctor_schedules,id',
'appointment_date' => 'required|date'
]);
$appointment = new Appointment();
$appointment->user_id = $request->user_id;
$appointment->service_id = $request->service_id;
$appointment->admin_id = $request->admin_id;
$appointment->appointment_date = $request->appointment_date;
$appointment->doctor_schedule_id = $request->doctor_schedule_id;
$appointment->save();
$user = User::find($request->user_id);
$userNotification = new UserNotification();
$userNotification->user_id = $user->id;
$userNotification->title = 'Appointment Booked Successfully';
$userNotification->click_url = urlPath('user.appointment.details', $appointment->id);
$userNotification->save();
return response()->json([
'success' => true,
'message' => 'Appointment booked successfully!',
]);
}
//appointment.blade.php code
@extends($activeTemplate . 'layouts.frontend')
@section('content')
@php
$appointmentContent = getContent('appointment.content', true);
$services = \App\Models\Service::where('status', 1)->get();
$doctors = \App\Models\Admin::whereHas('role', function ($q) {
$q->where('name', 'Doctor');
})->get();
use App\Models\DoctorSchedule;
$openingHours = DoctorSchedule::with('day')
->select('day_id', 'start_time', 'end_time')
->distinct('day_id')
->where('status', 1)
->get()
->sortBy(function ($schedule) {
$customOrder = [
'Sunday' => 1,
'Monday' => 2,
'Tuesday' => 3,
'Wednesday' => 4,
'Thursday' => 5,
'Friday' => 6,
'Saturday' => 7,
];
return $customOrder[$schedule->day->name] ?? 8;
});
$doctorSchedules = \App\Models\DoctorSchedule::with('day')
->select('id', 'day_id', 'start_time', 'end_time')
->distinct('day_id')
->orderBy('day_id')
->get();
@endphp
<section class="booking mt-120">
<div class="container">
<div class="booking__wrapper">
<div class="row">
<div class="col-lg-12">
<div class="booking__wrap">
<div class="opening__hours bg--img"
data-background-image="{{ asset($activeTemplateTrue . 'images/our-services-shape.png') }}">
<h4 class="opening__hours-title">{{ __($appointmentContent->data_values->hours_heading) }}
</h4>
@foreach ($openingHours as $schedule)
<div class="opening__hours-wrap">
<span>{{ $schedule->day->name ?? '' }}:</span>
<p>
{{ \Carbon\Carbon::createFromFormat('H:i:s', $schedule->start_time)->format('h:i A') }}
-
{{ \Carbon\Carbon::createFromFormat('H:i:s', $schedule->end_time)->format('h:i A') }}
</p>
</div>
@endforeach
</div>
<div class="appointment">
<h3 class="appointment__title">{{ __($appointmentContent->data_values->book_heading) }}</h3>
<form id="appointmentForm">
@csrf
<input type="hidden" name="user_id" value="{{ auth()->id() }}">
<div class="auth__form">
<input type="text" name="name" class="form-control"
value="{{ auth()->user()->firstname ?? '' }}" placeholder="@lang('Your Name')"
required>
</div>
<div class="auth__form">
<input type="text" name="phone" class="form-control"
value="{{ auth()->user()->mobile ?? '' }}" placeholder="@lang('Your Number')"
required>
</div>
<div class="auth__form">
<input type="email" name="email" class="form-control"
value="{{ auth()->user()->email ?? '' }}" placeholder="@lang('Your Email')"
required>
</div>
<div class="auth__form">
<select class="form-select" name="service_id" required>
<option value="" selected disabled>@lang('Type Of Service')</option>
@foreach ($services as $service)
<option value="{{ $service->id }}">{{ __($service->title) }}</option>
@endforeach
</select>
</div>
<div class="auth__form">
<select class="form-select" name="admin_id" required>
<option value="" selected>@lang('Doctor')</option>
@foreach ($doctors as $doctor)
<option value="{{ $doctor->id }}">{{ __($doctor->name) }}</option>
@endforeach
</select>
</div>
<div class="auth__form">
<input type="date" name="appointment_date" id="appointment_date"
class="form-control" required>
</div>
<div class="auth__form">
<select class="form-select" name="doctor_schedule_id" required>
<option value="" selected>@lang('Select Time Slot')</option>
@foreach ($doctorSchedules as $schedule)
<option value="{{ $schedule->id }}">
{{ \Carbon\Carbon::createFromFormat('H:i:s', $schedule->start_time)->format('h:i A') }}
@lang('to')
{{ \Carbon\Carbon::createFromFormat('H:i:s', $schedule->end_time)->format('h:i A') }}
</option>
@endforeach
</select>
</div>
<div class="booking__button d-flex gap-2">
<button type="button" id="checkBtn" class="btn btn--base-two"
disabled>@lang('Check Availability')</button>
<button type="button" id="bookBtn" class="btn btn--success"
style="display:none;">@lang('Book an Appointment')</button>
</div>
</form>
<div id="aiSuggestionBox" class="ai_suggestionbox" style="display:none;">
<strong>@lang('Suggested Time Slots')</strong>
<div id="aiResponse"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
@if ($sections->secs != null)
@foreach (json_decode($sections->secs) as $sec)
@include($activeTemplate . 'sections.' . $sec)
@endforeach
@endif
@endsection
@push('style')
<style>
.ai_suggestionbox {
margin-top: 15px;
display: none;
border: 1px solid #ddd;
padding: 10px;
border-radius: 5px;
color: #fff;
}
</style>
@endpush
@push('script')
<script>
(function($) {
"use strict";
$(document).ready(function() {
const $form = $('#appointmentForm');
const $checkBtn = $('#checkBtn');
const $bookBtn = $('#bookBtn');
const $requiredInputs = $form.find('[required]').not('[type="hidden"]');
function checkFormValidity() {
let allValid = true;
$requiredInputs.each(function() {
if (!$(this).val() || $(this).val().trim() === '') {
allValid = false;
return false;
}
});
$checkBtn.prop('disabled', !allValid);
if (!allValid) {
$bookBtn.hide();
$('#aiSuggestionBox').hide();
}
}
$requiredInputs.on('input change', checkFormValidity);
checkFormValidity();
$('#checkBtn').on('click', function(e) {
e.preventDefault();
if ($checkBtn.prop('disabled')) {
return;
}
let formData = $form.serialize();
$.ajax({
url: "{{ route('appointment.check') }}",
method: "POST",
data: formData,
beforeSend: function() {
$('#aiResponse').html('Checking availability...');
$('#aiSuggestionBox').show();
$bookBtn.hide();
},
success: function(response) {
$('#aiResponse').html(response.ai_message);
$bookBtn.show();
},
error: function() {
$('#aiResponse').html('Error: Could not check availability.');
$bookBtn.hide();
}
});
});
$('#bookBtn').on('click', function(e) {
e.preventDefault();
let formData = $form.serialize();
$.ajax({
url: "{{ route('appointment.book') }}",
method: "POST",
data: formData,
beforeSend: function() {
$bookBtn.text('Booking...');
},
success: function(response) {
$bookBtn.text('Book an Appointment');
if (response.success) {
notify('success', 'Appointmented Successfully');
$bookBtn.hide();
$checkBtn.prop('disabled',
true);
$('#aiResponse').append(
'<br><strong> Appointment Confirmed!</strong>');
}
},
error: function() {
$bookBtn.text('Book an Appointment');
notify('error', 'Error: Could not book appointment.');
}
});
});
});
// previous date disable
const dateInput = document.getElementById('appointment_date');
const today = new Date().toISOString().split('T')[0];
dateInput.min = today;
})(jQuery);
</script>
@endpush
No comments