Hello everyone!
I am trying to add SSE (server sent events) in my Laravel project, but I am faced with the constant problem that an api request is sent, but SSE does not work. Here’s the whole code:
If you explained something wrong, then let me know about it and I will definitely fix it
Any help will be very useful for me in this situation
chat.blade.php:
@extends('layouts.app')
@section('main')
<section>
<div class="container py-5">
<h3 class="text-center">Привет , {{ auth()->user()->name ?? null}}!</h3>
<div class="row d-flex justify-content-center">
<div class="col-md-15">
<div class="card mt-2" style="border-radius: 15px;">
<div class="card-header d-flex justify-content-between align-items-center p-3 text-white border-bottom-0" style="border-top-left-radius: 15px; border-top-right-radius: 15px; background-color:#47b2e4">
<h3 class="text-center">DOCUMENTATOR</h3>
</div>
<div class="p-3">
<div class="row">
<div class="col">
<h6>Язык Программирования: </h6>
<select class="form-select " aria-label="Default select example" name="proglang" id="prolang">
<option value="Автоопределение">Автоопределение</option>
<option value="PHP">PHP</option>
<option value="Golang">Golang</option>
<option value="Python">Python</option>
<option value="Java">Java</option>
<option value="Golang">Golang</option>
</select>
</div>
<div class="col">
<h6>Фреймворк :</h6>
<select class="form-select" aria-label="Default select example" name="framework" id="framework">
<option value="Автоопределение">Автоопределение</option>
<option value="Отсутствует">Отсутствует</option>
<option value="Laravel">Laravel</option>
<option value="Gin">Gin</option>
</select>
</div>
<div class="col">
<h6>Размер документации :</h6>
<select class="form-select" aria-label="Default select example" name="size" id="size">
<option value="Автоопределение">Автоопределение</option>
<option value="Краткий: -Описание краткое и лаконичное. -В основном описываются ключевые функции и методы. -Примеры кода ограничены и включают только базовый функционал. -Могут использоваться краткие пояснения и комментарии.">Краткий</option>
<option value="Средний: -Описание более подробное и полное. -Подробно описываются функции и методы. -Включаются примеры кода с пояснениями и комментариями. -Могут быть добавлены схемы, диаграммы и графики, чтобы облегчить понимание. -Могут включать ссылки на дополнительные ресурсы и документацию по API.">Средний</option>
<option value="Подробный: -Документация включает в себя все детали и особенности кода или проекта. -Подробно описываются каждая функция, класс и метод -Включаются подробные примеры кода с подробными пояснениями и комментариями. -Используются дополнительные материалы, такие как видеоуроки или интерактивные демонстрации. -Могут включать в себя разделы о структуре проекта, архитектурных решениях и лучших практиках.">Подробный</option>
</select>
</div>
<div class="col">
<h6>Язык документации :</h6>
<select class="form-select" aria-label="Default select example" name="lang" id="lang">
<option value="Автоопределение">Автоопределение</option>
<option value="Русский">Русский</option>
<option value="Англиский">Англиский</option>
<option value="Армянский">Армянский</option>
</select>
</div>
</div>
</div>
<div class="card-body">
<div id="chat-box" style="height: 280px" class="overflow-auto p-3"></div>
<div class="form-outline">
<form id="ask-chatgpt-form" method="POST">
@csrf
<div class="form-group" style="position: relative;">
<textarea class="form-control" name="prompt" placeholder="Введите свой код..."></textarea>
<button type="submit" id="submit-btn" style="background-color:#47b2e4; position: absolute; right: 10px; top: 50%; transform: translateY(-50%);" class="btn text-white"><i class="bi bi-send-fill"></i></button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
<template id="user-message-box-template">
<div class="d-flex flex-row justify-content-end mb-4">
<div class="p-3 me-3 border" style="border-radius: 15px; background-color: #fbfbfb;">
<p class="small mb-0" id="message-box-text"></p>
</div>
</div>
</template>
<template id="chatgpt-message-box-template">
<div class="d-flex flex-row justify-content-start mb-4">
<div class="p-3 ms-3 " style="border-radius: 15px; background-color: rgba(0, 166, 255, 0.289);">
<p class="small mb-0" id="message-box-text"></p>
</div>
</div>
</template>
<script>
$(document).on("click", "#submit-btn", function (e) {
e.preventDefault();
var source = new EventSource("/sse");
var form = $("#ask-chatgpt-form");
var textarea = form.find('textarea[name="prompt"]');
var selectedproglang = $('select[name="proglang"]').val();
var selectedframework = $('select[name="framework"]').val();
var selectedsize = $('select[name="size"]').val();
var selectedlang = $('select[name="lang"]').val();
var formData = {
_token: "{{ csrf_token() }}",
prompt: textarea.val(),
proglang: selectedproglang,
framework: selectedframework,
size: selectedsize,
lang: selectedlang
};
generateChatBoxMessage(false, textarea.val());
textarea.val('');
source.onmessage = function (event) {
generateChatBoxMessage(true, event.data);
};
source.onerror = function (error) {
console.error("Ошибка EventSource:", error);
source.close();
};
$.ajax({
type: "POST",
url: "{{ route('messeges') }}",
data: formData,
success: function (answer) {
generateChatBoxMessage(true, answer);
source.close();
},
});
});
$('select').change(function() {
var selectedValue = $(this).val();
$(this).siblings('input[type="hidden"]').val(selectedValue);
});
function generateChatBoxMessage(isChatGPTMessage, messageText) {
var template = isChatGPTMessage ? $("#chatgpt-message-box-template").html() : $("#user-message-box-template").html();
var messageBox = $(template);
messageBox.find('#message-box-text').text(messageText);
$('#chat-box').append(messageBox);
}
</script>
@endsection
chatcontroller.php:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\MessageRequest;
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Request;
use App\Models\message;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Illuminate\Support\Facades\Auth;
class ChatController extends Controller
{
private $openAIRequest;
public function __construct()
{
$this->openAIRequest = Http::withoutVerifying()
->withOptions(['timeout' => 120])
->withHeaders([
'Authorization' => 'Bearer ' . config('openai.api_key'),
'Content-Type' => 'application/json',
]);
}
public function messeges(Request $request, MessageRequest $messageRequest)
{
$prompt = $messageRequest->input('prompt');
$proglang = $messageRequest->input('proglang');
$framework = $messageRequest->input('framework');
$size = $messageRequest->input('size');
$lang = $messageRequest->input('lang');
$message = 'Задокументируйте код на языке программирования: ' . $proglang . ' с использованием фреймворка: ' . $framework .
' Документация должна быть в формате: ' . $size . ' Объект - предназначение' .' и написана на ' . $lang . ' языке.' .
' Код, который необходимо документировать: ' . $prompt . ' Если в поле для кода будет короткий код, то мы его всё равно описываем, а если код отсутствует, то сообщи об этом';
Message::create([
'user_id' => Auth::user()->id,
'prompt' => $prompt,
'proglang' => $proglang,
'framework' => $framework,
'size' => $size,
'lang' => $lang,
]);
return $this->askToChatGPT($message);
}
private function askToChatGPT($message)
{
$response = $this->openAIRequest->post('https://api.openai.com/v1/chat/completions', [
"model" => "gpt-3.5-turbo-16k",
"messages" => [
[
"role" => "user",
"content" => $message
]
],
"max_tokens" => 5000,
]);
return $response->json()['choices'][0]['message']['content'];
}
public function serverSentEvents()
{
$response = new StreamedResponse(function () {
while (true) {
$messages = Message::orderBy('created_at', 'desc')->limit(5)->get();
foreach ($messages as $message) {
echo "data: " . $message->prompt . "\n\n";
ob_flush();
flush();
}
sleep(1);
}
}, 200, [
'Content-Type' => 'text/event-stream',
'Cache-Control' => 'no-cache',
'Connection' => 'keep-alive',
'X-Accel-Buffering' => 'no',
]);
return $response;
}
}
web.php:
<?php
use App\Http\Controllers\chatController;
use App\Http\Controllers\FeedbackController;
use App\Http\Controllers\mailnewController;
use App\Http\Controllers\PagesController;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\AuthController;
use App\Http\Controllers\RegisterController;
Route::controller(PagesController::class)->group(function(){
Route::get('/' , 'main')->name('main');
Route::get('/chat' , 'chat')->name('chat')->middleware('auth');
Route::get('/about' , 'about')->name('about');
});
Route::controller(chatController::class)->group(function(){
Route::post('/chatgpt/ask' , 'messeges' )->name('messeges');
Route::post('/sse' , 'serverSentEvents' )->name('sse');
});
Route::controller(mailnewController::class)->group(function () {
Route::post('/news/send', 'news')->name('mail.news');
});
Route::controller(RegisterController::class)->middleware('guest')->group(function(){
Route::get('/registration' , 'regpage')->name('reg.page');
Route::post('/registration/action' , 'regaction')->name('reg.action');
});
Route::controller(AuthController::class)->middleware('guest')->group(function(){
Route::get('/authorization' , 'authpage')->name('auth.page');
Route::post('/authorization/action' , 'authaction')->name('auth.action');
Route::post('/logout' , 'logout')->name('logout')->withoutMiddleware('guest');
});
Route::controller(FeedbackController::class)->group(function(){
Route::post('/feedback', 'storeFeedback')->name('feedback');
});