I don't understand what the problem is in the code (Laravel , SSE)

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 :heart:

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');
});

1 Like