Your IP : 216.73.217.77


Current Path : /home/users/unlimited/www/ultimate-ai.codeskitter.site/app/Services/Stream/
Upload File :
Current File : /home/users/unlimited/www/ultimate-ai.codeskitter.site/app/Services/Stream/StreamService.php

<?php

namespace App\Services\Stream;

use App\Domains\Engine\Enums\EngineEnum;
use App\Domains\Engine\Services\AnthropicService;
use App\Domains\Engine\Services\GeminiService;
use App\Domains\Entity\BaseDriver;
use App\Domains\Entity\Enums\EntityEnum;
use App\Domains\Entity\Facades\Entity;
use App\Enums\BedrockEngine;
use App\Extensions\OpenRouter\System\Services\RouterAiService;
use App\Helpers\Classes\ApiHelper;
use App\Helpers\Classes\Helper;
use App\Helpers\Classes\MarketplaceHelper;
use App\Models\Setting;
use App\Models\SettingTwo;
use App\Models\Usage;
use App\Models\UserOpenai;
use App\Models\UserOpenaiChat;
use App\Models\UserOpenaiChatMessage;
use App\Services\Ai\OpenAI\FileSearchService;
use App\Services\Assistant\AssistantService;
use App\Services\Bedrock\BedrockRuntimeService;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use JsonException;
use OpenAI as OpenAIMain;
use OpenAI\Laravel\Facades\OpenAI;
use Symfony\Component\HttpFoundation\StreamedResponse;
use Throwable;

class StreamService
{
    public bool $guest = false;

    public function __construct(
        Setting $setting,
        SettingTwo $settingTwo,
    ) {
        match (setting('default_ai_engine', EngineEnum::OPEN_AI->value)) {
            EngineEnum::ANTHROPIC->value => ApiHelper::setAnthropicKey($setting),
            EngineEnum::GEMINI->value    => ApiHelper::setGeminiKey($setting),
            EngineEnum::X_AI->value 	    => ApiHelper::setXAiKey($setting),
            default                      => ApiHelper::setOpenAiKey($setting),
        };
    }

    /**
     * @throws Exception
     * @throws GuzzleException
     */
    public function ChatStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images, $ai_engine = null, $assistant = null, $openRouter = null, $responsesApi = false): ?StreamedResponse
    {
        if ($chat_type === 'chatPro' && MarketplaceHelper::isRegistered('ai-chat-pro') && ! auth()->check()) {
            $this->guest = true;
        }

        if ($responsesApi) {
            return $this->responsesApiStream($chat_bot, $history, $main_message, $chat_type, $contain_images);
        }

        if (! $ai_engine) {
            $ai_engine = setting('default_ai_engine', EngineEnum::OPEN_AI->value);
        }

        if (! is_null($assistant)) {
            return $this->assistantStream($chat_bot, $history, $main_message, $assistant);
        }

        if (! is_null($openRouter) && setting('open_router_status') == 1) {
            return $this->openRouterChatStream($chat_bot, $history, $main_message, $contain_images, $openRouter);
        }

        return match ($ai_engine) {
            EngineEnum::OPEN_AI->value   => $this->openaiChatStream($chat_bot, $history, $main_message, $chat_type, $contain_images),
            EngineEnum::ANTHROPIC->value => $this->anthropicChatStream($chat_bot, $history, $main_message, $chat_type, $contain_images),
            EngineEnum::GEMINI->value    => $this->geminiChatStream($chat_bot, $history, $main_message, $chat_type, $contain_images),
            EngineEnum::DEEP_SEEK->value => $this->deepseekChatStream($chat_bot, $history, $main_message, $contain_images),
            EngineEnum::X_AI->value      => $this->xAiChatStream($chat_bot, $history, $main_message, $chat_type, $contain_images),
            default                      => throw new Exception('Invalid AI Engine'),
        };
    }

    private function createDriver(EntityEnum $model): ?BaseDriver
    {
        if ($this->guest) {
            return Entity::driverForGuest($model);
        }

        return Entity::driver($model);
    }

    private function openRouterChatStream($chat_bot, $history, $main_message, $contain_images, $openRouter)
    {
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        if ($contain_images) {
            $driver = $this->createDriver(EntityEnum::GPT_4_O);
        } else {
            $driver = $this->createDriver(EntityEnum::fromSlug($openRouter));
        }

        return response()->stream(function () use ($openRouter, $driver, $chat_bot, $history, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {

            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();

            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            if (! $contain_images) {
                $historyMessages = array_filter($history, function ($item) {
                    return $item['role'] != 'system';
                });

                $service = new RouterAiService;
                $response = $service->response(last($historyMessages)['content'], $openRouter);

                foreach (explode("\n", $response) as $line) {
                    if (str_starts_with($line, 'data:')) {
                        $data = trim(substr($line, 5));
                        if ($data === '[DONE]') {
                            break;
                        }

                        $json = json_decode($data, true);

                        if (isset($json['choices'][0]['delta']['content'])) {
                            $content = $json['choices'][0]['delta']['content'];

                            if (! empty($content)) {
                                $output .= $content;
                                $responsedText .= $content;
                                $total_used_tokens += str_word_count($content);

                                $content = str_replace(["\r\n", "\r", "\n"], '<br/>', $content);

                                echo PHP_EOL;
                                echo "event: data\n";
                                echo 'data: ' . $content;
                                echo "\n\n";
                                flush();

                                if (connection_aborted()) {
                                    break;
                                }
                            }
                        }
                    }
                }
            } else {
                ApiHelper::setOpenAiKey();
                $chat_bot = 'gpt-4o';
                $stream = OpenAI::chat()->createStreamed([
                    'model'             => $chat_bot,
                    'messages'          => $history,
                    'max_tokens'        => 2000,
                    'temperature'       => 1.0,
                    'frequency_penalty' => 0,
                    'presence_penalty'  => 0,
                    'stream'            => true,
                ]);
                foreach ($stream as $response) {
                    if (isset($response->choices[0]->delta->content)) {
                        $text = $response->choices[0]->delta->content;
                        $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                        $output .= $messageFix;
                        $responsedText .= $text;
                        $total_used_tokens += countWords($text);
                        if (connection_aborted()) {
                            break;
                        }
                        echo PHP_EOL;
                        echo "event: data\n";
                        echo 'data: ' . $messageFix;
                        echo "\n\n";
                        flush();
                    }
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();

            $chat->total_credits += $total_used_tokens;
            $chat->save();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    public function fixMessageHistory(array $history): array
    {
        $fixedHistory = [];
        $firstMessage = null;
        foreach ($history as $message) {
            if ($firstMessage === null) {
                $firstMessage = $message;
            } else {
                if ($firstMessage['role'] === $message['role']) {
                    if (is_array($message['content'])) {
                        $firstMessage['content'] = $message['content'];
                    } else {
                        $firstMessage['content'] .= ' ' . $message['content'];
                    }
                } else {
                    // Add the current message to the fixed history
                    $fixedHistory[] = $firstMessage;
                    // Start a new message
                    $firstMessage = $message;
                }
            }
        }
        if ($firstMessage !== null) {
            $fixedHistory[] = $firstMessage;
        }

        return $fixedHistory;
    }

    private function deepseekChatStream($chat_bot, $history, $main_message, $contain_images): StreamedResponse
    {
        ini_set('max_execution_time', 440);
        set_time_limit(0);

        $history = $this->fixMessageHistory($history);
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        if ($contain_images) {
            $driver = $this->createDriver(EntityEnum::GPT_4_O);
        } else {
            $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        }

        return response()->stream(
            function () use ($driver, $chat_bot, $history, $main_message, $contain_images, &$total_used_tokens, &$output, &$responsedText) {
                $chat_id = $main_message->user_openai_chat_id;
                $chat = UserOpenaiChat::whereId($chat_id)->first();
                echo "event: message\n";
                echo 'data: ' . $main_message->id . "\n\n";
                if (! $driver->hasCreditBalance()) {
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                    echo "\n\n";
                    flush();
                    echo "event: stop\n";
                    echo 'data: [DONE]';
                    echo "\n\n";
                    flush();

                    return null;
                }
                if (! $contain_images) {
                    ini_set('max_execution_time', 3000);
                    set_time_limit(3000);
                    $client = new Client;
                    ApiHelper::setDeepseekKey();
                    $url = 'https://api.deepseek.com/chat/completions';
                    $apikey = config('deepseek.api_key');
                    $headers = [
                        'Content-Type'  => 'application/json',
                        'Accept'        => 'application/json',
                        'Authorization' => "Bearer $apikey",
                    ];

                    $body = [
                        'messages'          => $history,
                        'model'             => $chat_bot,
                        'frequency_penalty' => 0,
                        'max_tokens'        => (int) setting('deepseek_max_output_length', 200),
                        'presence_penalty'  => 0,
                        'response_format'   => [
                            'type' => 'text',
                        ],
                        'stop'           => null,
                        'stream'         => true,
                        'stream_options' => null,
                        'temperature'    => 1,
                        'top_p'          => 1,
                        'tools'          => null,
                        'tool_choice'    => 'none',
                        'logprobs'       => false,
                        'top_logprobs'   => null,
                    ];
                    $response = $client->post($url, [
                        'headers' => $headers,
                        'json'    => $body,
                    ]);
                    $bodyStream = $response->getBody();
                    $buffer = '';
                    $emptyLinesAdded = false;
                    while (! $bodyStream->eof()) {
                        $chunk = $bodyStream->read(1024);
                        $buffer .= $chunk;

                        while (($pos = strpos($buffer, "\n")) !== false) {
                            $line = substr($buffer, 0, $pos);
                            $buffer = substr($buffer, $pos + 1);

                            if (str_starts_with(trim($line), 'data: ')) {
                                $json = trim(substr($line, 5)); // Remove "data: "
                                if (! empty($json)) {
                                    $decoded = json_decode($json, true);
                                    if (json_last_error() === JSON_ERROR_NONE) {
                                        $delta = $decoded['choices'][0]['delta'] ?? [];

                                        // Handle reasoning content
                                        if (isset($delta['reasoning_content']) && $delta['reasoning_content'] !== null) {
                                            // Add start signal if this is the first reasoning content
                                            if (! isset($reasoningStarted)) {
                                                $reasoningStarted = true;
                                                $startSignal = '[START_REASONING]';
                                                $output .= $startSignal;
                                                $responsedText .= '[START_REASONING]';

                                                echo PHP_EOL;
                                                echo "event: data\n";
                                                echo 'data: ' . $startSignal;
                                                echo "\n\n";
                                                flush();
                                            }

                                            $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $delta['reasoning_content']);
                                            $output .= $messageFix;
                                            $responsedText .= $messageFix;
                                            // $total_used_tokens += countWords($messageFix); do we calculate reasoning content?

                                            echo PHP_EOL;
                                            echo "event: data\n";
                                            echo 'data: ' . $messageFix;
                                            echo "\n\n";
                                            flush();
                                        }

                                        // Handle regular content
                                        if (isset($delta['content']) && $delta['content'] !== null) {
                                            // Add end signal if we were in reasoning mode
                                            if (isset($reasoningStarted)) {
                                                $endSignal = '[END_REASONING]<br/><br/>';
                                                $output .= $endSignal;
                                                $responsedText .= "[END_REASONING]\n\n";

                                                echo PHP_EOL;
                                                echo "event: data\n";
                                                echo 'data: ' . $endSignal;
                                                echo "\n\n";
                                                flush();

                                                unset($reasoningStarted);
                                            }

                                            if (! $emptyLinesAdded) {
                                                echo "event: data\n";
                                                echo 'data: <br/><br/><br/>';
                                                echo "\n\n";
                                                flush();
                                                $emptyLinesAdded = true;
                                            }

                                            $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $delta['content']);
                                            $output .= $messageFix;
                                            $responsedText .= $messageFix;
                                            $total_used_tokens += countWords($messageFix);

                                            echo "event: data\n";
                                            echo 'data: ' . $messageFix;
                                            echo "\n\n";
                                            flush();
                                        }
                                    }
                                }
                            }
                        }

                        if (connection_aborted()) {
                            break;
                        }
                    }

                } else {
                    ApiHelper::setOpenAiKey();
                    $chat_bot = 'gpt-4o';
                    $stream = OpenAI::chat()->createStreamed([
                        'model'             => $chat_bot,
                        'messages'          => $history,
                        'max_tokens'        => 2000,
                        'temperature'       => 1.0,
                        'frequency_penalty' => 0,
                        'presence_penalty'  => 0,
                        'stream'            => true,
                    ]);
                    foreach ($stream as $response) {
                        if (isset($response->choices[0]->delta->content)) {
                            $text = $response->choices[0]->delta->content;
                            $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                            $output .= $messageFix;
                            $responsedText .= $text;
                            $total_used_tokens += countWords($text);
                            if (connection_aborted()) {
                                break;
                            }
                            echo PHP_EOL;
                            echo "event: data\n";
                            echo 'data: ' . $messageFix;
                            echo "\n\n";
                            flush();
                        }
                    }
                }
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                $main_message->response = $responsedText;
                $main_message->output = $output;
                $main_message->credits = $total_used_tokens;
                $main_message->words = $total_used_tokens;
                $main_message->save();

                $chat->total_credits += $total_used_tokens;
                $chat->save();

                $driver->input($responsedText)->calculateCredit()->decreaseCredit();
                Usage::getSingle()->updateWordCounts($driver->calculate());

            },
            200,
            [
                'Cache-Control'     => 'no-cache',
                'X-Accel-Buffering' => 'no',
                'Content-Type'      => 'text/event-stream',
            ]
        );
    }

    private function deepseekOtherStream(Request $request, $chat_bot)
    {
        ini_set('max_execution_time', 440);
        set_time_limit(0);

        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');

        $history[] = ['role' => 'user', 'content' => $prompt];

        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        return response()->stream(function () use (&$total_used_tokens, &$output, &$responsedText, $driver, $message_id, $title, $openai_id, $prompt, $history, $chat_bot) {

            $user = Auth::user();
            $entry = UserOpenai::firstOrCreate(
                [
                    'id' => $message_id,
                ],
                [
                    'user_id'   => $user->id,
                    'input'     => $prompt,
                    'hash'      => str()->random(256),
                    'team_id'   => $user->team_id,
                    'slug'      => str()->random(7) . str($user?->fullName())->slug() . '-workbook',
                    'openai_id' => $openai_id ?? 1,
                ]);

            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $client = new Client;

            ApiHelper::setDeepseekKey();

            $url = 'https://api.deepseek.com/chat/completions';
            $apikey = config('deepseek.api_key');
            $headers = [
                'Content-Type'  => 'application/json',
                'Accept'        => 'application/json',
                'Authorization' => "Bearer $apikey",
            ];

            $body = [
                'messages'          => $history,
                'model'             => $chat_bot,
                'frequency_penalty' => 0,
                'max_tokens'        => (int) setting('deepseek_max_output_length', 200),
                'presence_penalty'  => 0,
                'response_format'   => [
                    'type' => 'text',
                ],
                'stop'           => null,
                'stream'         => true,
                'stream_options' => null,
                'temperature'    => 1,
                'top_p'          => 1,
                'tools'          => null,
                'tool_choice'    => 'none',
                'logprobs'       => false,
                'top_logprobs'   => null,
            ];

            $response = $client->post($url, [
                'headers' => $headers,
                'json'    => $body,
            ]);

            $bodyStream = $response->getBody();
            $buffer = '';
            $emptyLinesAdded = false;
            while (! $bodyStream->eof()) {
                $chunk = $bodyStream->read(1024);
                $buffer .= $chunk;

                while (($pos = strpos($buffer, "\n")) !== false) {
                    $line = substr($buffer, 0, $pos);
                    $buffer = substr($buffer, $pos + 1);

                    if (str_starts_with(trim($line), 'data: ')) {
                        $json = trim(substr($line, 5)); // Remove "data: "
                        if (! empty($json)) {
                            $decoded = json_decode($json, true);
                            if (json_last_error() === JSON_ERROR_NONE) {
                                $delta = $decoded['choices'][0]['delta'] ?? [];
                                if (isset($delta['reasoning_content']) && $delta['reasoning_content'] !== null) {
                                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $delta['reasoning_content']);
                                    $output .= $messageFix;
                                    $responsedText .= $messageFix;
                                    // $total_used_tokens += countWords($messageFix); do we calculate reasoning content?
                                    echo PHP_EOL;
                                    echo "event: data\n";
                                    echo 'data: ' . $messageFix;
                                    echo "\n\n";
                                    flush();
                                }

                                if (isset($delta['content']) && $delta['content'] !== null) {
                                    if (! $emptyLinesAdded) {
                                        echo "event: data\n";
                                        echo 'data: <br/><br/><br/>';
                                        echo "\n\n";
                                        flush();
                                        $emptyLinesAdded = true;
                                    }
                                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $delta['content']);

                                    $output .= $messageFix;
                                    $responsedText .= $messageFix;
                                    $total_used_tokens += countWords($messageFix);

                                    echo "event: data\n";
                                    echo 'data: ' . $messageFix;
                                    echo "\n\n";
                                    flush();
                                }
                            }
                        }
                    }
                }

                if (connection_aborted()) {
                    break;
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $entry->update([
                'title'    => $title ?: null,
                'credits'  => $total_used_tokens,
                'words'    => $total_used_tokens,
                'response' => $responsedText,
                'output'   => $output,
            ]);

            $driver->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());

        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    /**
     * @throws GuzzleException
     * @throws JsonException
     * @throws Exception
     */
    public function assistantStream(string $chat_bot, $history, $main_message, $assistant): ?StreamedResponse
    {
        $chat = UserOpenaiChat::query()->where('id', $main_message->user_openai_chat_id)->first();
        $threadId = $chat?->thread_id;
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        $assistantService = new AssistantService;

        $tmp = $assistantService->createMessage($threadId, $history);

        return $assistantService->createRun($chat_bot, $assistant, $threadId, $main_message, $driver);
    }

    public function OtherStream(Request $request, string $chat_bot, $ai_engine = null): StreamedResponse
    {
        if (! $ai_engine) {
            $ai_engine = setting('default_ai_engine', EngineEnum::OPEN_AI->value);
        }

        if (setting('open_router_status') == 1 && $request->open_router_model !== 'undefined' && ! empty($request->open_router_model)) {
            return $this->openRouterStream($request);
        }

        return match ($ai_engine) {
            EngineEnum::ANTHROPIC->value => $this->anthropicOtherStream($request, $chat_bot),
            EngineEnum::GEMINI->value    => $this->geminiOtherStream($request, $chat_bot),
            EngineEnum::DEEP_SEEK->value => $this->deepseekOtherStream($request, $chat_bot),
            EngineEnum::X_AI->value 	    => $this->xAiOtherStream($request, $chat_bot),
            default                      => $this->openaiOtherStream($request, $chat_bot),
        };
    }

    private function openRouterStream(Request $request)
    {
        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');
        $open_router_model = $request->get('open_router_model');
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';
        $driver = $this->createDriver(EntityEnum::fromSlug($open_router_model));

        return response()->stream(function () use ($driver, &$total_used_tokens, &$output, &$responsedText, $message_id, $title, $openai_id, $prompt, $open_router_model) {
            $user = Auth::user();
            $entry = UserOpenai::find($message_id);
            if (! $entry) {
                $entry = new UserOpenai;
                $entry->user_id = $user?->id;
                $entry->input = $prompt;
                $entry->hash = str()->random(256);
                $entry->team_id = $user?->team_id;
                $entry->slug = str()->random(7) . str($user?->fullName())->slug() . '-workbook';
                $entry->openai_id = $openai_id ?? 1;
            }
            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $service = new RouterAiService;
            $response = $service->response($entry->input, $open_router_model);

            foreach (explode("\n", $response) as $line) {
                if (str_starts_with($line, 'data:')) {
                    $data = trim(substr($line, 5));
                    if ($data === '[DONE]') {
                        break;
                    }

                    $json = json_decode($data, true);

                    if (isset($json['choices'][0]['delta']['content'])) {
                        $content = $json['choices'][0]['delta']['content'];

                        // Boş içerik varsa atla
                        if (! empty($content)) {
                            $output .= $content;
                            $responsedText .= $content;
                            $total_used_tokens += str_word_count($content);

                            $content = str_replace(["\r\n", "\r", "\n"], '<br/>', $content);

                            echo PHP_EOL;
                            echo "event: data\n";
                            echo 'data: ' . $content;
                            echo "\n\n";
                            flush();

                            if (connection_aborted()) {
                                break;
                            }
                        }
                    }
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());

            $entry->title = $title ?: null;
            $entry->credits = $total_used_tokens;
            $entry->words = $total_used_tokens;
            $entry->response = $responsedText;
            $entry->output = $output;
            $entry->save();
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    public function reduceTokensWhenIntterruptStream(Request $request, $type): void
    {
        $model = Helper::setting('openai_default_model') ?: EntityEnum::GPT_3_5_TURBO_16K->value;
        $streamed_text = $request->get('streamed_text');
        $message_id = $request->get('streamed_message_id');
        if ($streamed_text) {
            $total_used_tokens = countWords($streamed_text);
            $this->createDriver(EntityEnum::fromSlug($model))->input($streamed_text)->calculateCredit()->decreaseCredit();
            if (! empty($message_id)) {
                if ($type === 'writer') {
                    $entry = UserOpenai::find($message_id);
                    if ($entry) {
                        $entry->title = null;
                        $entry->credits = $total_used_tokens;
                        $entry->words = $total_used_tokens;
                        $entry->response = $streamed_text;
                        $entry->output = $streamed_text;
                        $entry->save();
                    }
                } else { // chat
                    $main_message = UserOpenaiChatMessage::find($message_id);
                    if ($main_message) {
                        $chat = UserOpenaiChat::find($main_message->user_openai_chat_id);
                        $main_message->response = $streamed_text;
                        $main_message->output = $streamed_text;
                        $main_message->credits = $total_used_tokens;
                        $main_message->words = $total_used_tokens;
                        $main_message->save();

                        if ($chat) {
                            $chat->total_credits += $total_used_tokens;
                            $chat->save();
                        }
                    }
                }
            }
        }
    }

    // X-AI Stream
    /**
     * @throws Exception
     */
    private function xAiChatStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images): ?StreamedResponse
    {
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        if ($contain_images) {
            $driver = $this->createDriver(EntityEnum::GPT_4_O);
        } else {
            $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        }

        return response()->stream(static function () use ($driver, $history, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {
            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();

            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";
            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $model = $driver->enum()->value;
            if ($contain_images) {
                $options = [
                    'model'             => EntityEnum::GPT_4_O->value,
                    'messages'          => $history,
                    'temperature'       => 1.0,
                    'frequency_penalty' => 0,
                    'presence_penalty'  => 0,
                    'stream'            => true,
                    'max_tokens'        => 2000,
                ];
                $stream = OpenAI::chat()->createStreamed($options);
            } else {
                $api = ApiHelper::setXAiKey();

                try {
                    $cli = OpenAIMain::factory()->withBaseUri('https://api.x.ai/v1')
                        ->withHttpHeader('Authorization', 'Bearer ' . $api)
                        ->withApiKey($api)
                        ->make();
                    $stream = $cli->chat()->createStreamed([
                        'model'             => $model,
                        'messages'          => $history,
                        'stream'            => true,
                        'temperature'       => 1.0,
                    ]);
                } catch (Exception|Throwable $e) {
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . __('Something went wrong. Please try again later.');
                    echo "\n\n";
                    flush();
                    echo "event: stop\n";
                    echo 'data: [DONE]';
                    echo "\n\n";
                    flush();

                    return null;
                }
            }

            foreach ($stream as $response) {
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);
                    if (connection_aborted()) {
                        break;
                    }
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }
            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();
            $chat->total_credits += $total_used_tokens;
            $chat->save();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());

        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    private function xAiOtherStream(Request $request, $chat_bot): ?StreamedResponse
    {
        $apiKey = ApiHelper::setXAiKey();
        $xai = OpenAIMain::factory()
            ->withApiKey($apiKey)
            ->withBaseUri('https://api.x.ai/v1')
            ->make();

        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');

        $history[] = ['role' => 'user', 'content' => $prompt];
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';
        $user = Auth::user();
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        return response()->stream(static function () use ($user, $driver, $history, &$total_used_tokens, &$output, &$responsedText, $message_id, $title, $openai_id, $prompt) {
            $entry = UserOpenai::find($message_id);
            if (! $entry) {
                $entry = new UserOpenai;
                $entry->user_id = $user->id;
                $entry->input = $prompt;
                $entry->hash = str()->random(256);
                $entry->team_id = $user->team_id;
                $entry->slug = str()->random(7) . str($user?->fullName())->slug() . '-workbook';
                $entry->openai_id = $openai_id ?? 1;
            }

            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $api = ApiHelper::setXAiKey();

            try {
                $cli = OpenAIMain::factory()->withBaseUri('https://api.x.ai/v1')
                    ->withHttpHeader('Authorization', 'Bearer ' . $api)
                    ->withApiKey($api)
                    ->make();
                $stream = $cli->chat()->createStreamed([
                    'model'             => $driver->enum()->value,
                    'messages'          => $history,
                    'stream'            => true,
                    'temperature'       => 1.0,
                ]);
            } catch (Exception|Throwable $e) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('Something went wrong. Please try again later.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            foreach ($stream as $response) {
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);
                    if (connection_aborted()) {
                        break;
                    }
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }
            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $entry->title = $title ?: null;
            $entry->credits = $total_used_tokens;
            $entry->words = $total_used_tokens;
            $entry->response = $responsedText;
            $entry->output = $output;
            $entry->save();

            $driver
                ->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    // OpenAI Stream
    /**
     * @throws Exception
     */
    private function openaiChatStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images): ?StreamedResponse
    {
        // @todo: in beta entites: EntityEnum::fromSlug($chat_bot)->isBetaEntity() then output without stream, stream not working
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        if ($contain_images) {
            $driver = $this->createDriver(EntityEnum::GPT_4_O);
        } else {
            $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        }

        return response()->stream(static function () use ($driver, $history, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {
            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();

            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";
            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $model = $driver->enum()->value;
            $options = [
                'model'             => $model,
                'messages'          => $history,
                'stream'            => true,
            ];

            if (! in_array($model, [EntityEnum::GPT_4_O_MINI_SEARCH_PREVIEW->value, EntityEnum::GPT_4_O_SEARCH_PREVIEW->value], true)) {
                $options['temperature'] = 1.0;
                $options['frequency_penalty'] = 0;
                $options['presence_penalty'] = 0;
            }

            if ($contain_images) {
                $options['max_tokens'] = 2000;
                $options['model'] = EntityEnum::GPT_4_O;
            }
            $stream = OpenAI::chat()->createStreamed($options);
            foreach ($stream as $response) {
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);
                    if (connection_aborted()) {
                        break;
                    }
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }
            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();
            $chat->total_credits += $total_used_tokens;
            $chat->save();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    /**
     * @throws Exception
     */
    private function responsesApiStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images): ?StreamedResponse
    {
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        if ($contain_images) {
            $driver = $this->createDriver(EntityEnum::GPT_4_O);
        } else {
            $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        }

        return response()->stream(static function () use ($driver, $history, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {
            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();

            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";
            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $model = $driver->enum()->value;
            $options = [
                'model'             => $model,
                'messages'          => $history,
                'stream'            => true,
            ];

            if (! in_array($model, [EntityEnum::GPT_4_O_MINI_SEARCH_PREVIEW->value, EntityEnum::GPT_4_O_SEARCH_PREVIEW->value], true)) {
                $options['temperature'] = 1.0;
                $options['frequency_penalty'] = 0;
                $options['presence_penalty'] = 0;
            }

            if ($contain_images) {
                $options['max_tokens'] = 2000;
                $options['model'] = EntityEnum::GPT_4_O;

                $stream = OpenAI::chat()->createStreamed($options);
                foreach ($stream as $response) {
                    if (isset($response->choices[0]->delta->content)) {
                        $text = $response->choices[0]->delta->content;
                        $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                        $output .= $messageFix;
                        $responsedText .= $text;
                        $total_used_tokens += countWords($text);
                        if (connection_aborted()) {
                            break;
                        }
                        echo PHP_EOL;
                        echo "event: data\n";
                        echo 'data: ' . $messageFix;
                        echo "\n\n";
                        flush();
                    }
                }
            } else {
                $fileSearchService = new FileSearchService;
                $responsedText = $output = $fileSearchService->searchInFile($options, $chat);

                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . $responsedText;
                echo "\n\n";
                flush();

                $total_used_tokens = countWords($responsedText);
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();
            $chat->total_credits += $total_used_tokens;
            $chat->save();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    private function openaiOtherStream(Request $request, $chat_bot): ?StreamedResponse
    {
        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');

        $history[] = ['role' => 'user', 'content' => $prompt];
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';
        $user = Auth::user();
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        return response()->stream(static function () use ($user, $driver, $history, &$total_used_tokens, &$output, &$responsedText, $message_id, $title, $openai_id, $prompt) {
            $entry = UserOpenai::find($message_id);
            if (! $entry) {
                $entry = new UserOpenai;
                $entry->user_id = $user->id;
                $entry->input = $prompt;
                $entry->hash = str()->random(256);
                $entry->team_id = $user->team_id;
                $entry->slug = str()->random(7) . str($user?->fullName())->slug() . '-workbook';
                $entry->openai_id = $openai_id ?? 1;
            }

            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $stream = OpenAI::chat()->createStreamed([
                'model'             => $driver->enum()->value,
                'messages'          => $history,
                'temperature'       => 1.0,
                'frequency_penalty' => 0,
                'presence_penalty'  => 0,
                'stream'            => true,
            ]);

            foreach ($stream as $response) {
                if (isset($response->choices[0]->delta->content)) {
                    $text = $response->choices[0]->delta->content;
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);
                    if (connection_aborted()) {
                        break;
                    }
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }
            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $entry->title = $title ?: null;
            $entry->credits = $total_used_tokens;
            $entry->words = $total_used_tokens;
            $entry->response = $responsedText;
            $entry->output = $output;
            $entry->save();

            $driver
                ->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    // AnthropicService Stream
    private function anthropicChatStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images): ?StreamedResponse
    {
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';
        $client = app(AnthropicService::class);
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        return response()->stream(static function () use ($driver, $client, $history, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();

            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";

            if (! $contain_images) {
                $historyMessages = array_filter($history, function ($item) {
                    return $item['role'] !== 'system';
                });
                $system = Arr::first(array_filter($history, function ($item) {
                    return $item['role'] === 'system';
                }));
                $system = data_get($system, 'content');

                if (setting('anthropic_default_model') === BedrockEngine::BEDROCK->value) {
                    $bedrockService = new BedrockRuntimeService([
                        'region'      => config('filesystems.disks.s3.region'),
                        'version'     => 'latest',
                        'credentials' => [
                            'key'    => config('filesystems.disks.s3.key'),
                            'secret' => config('filesystems.disks.s3.secret'),
                        ],
                    ]);
                    $responseBody = $bedrockService->invokeClaude($main_message->input);
                    $driver = $this->createDriver(EntityEnum::CLAUDE_2_1);
                    if (! $driver->hasCreditBalance()) {
                        echo PHP_EOL;
                        echo "event: data\n";
                        echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                        echo "\n\n";
                        flush();
                        echo "event: stop\n";
                        echo 'data: [DONE]';
                        echo "\n\n";
                        flush();

                        return null;
                    }

                    if ($responseBody) {
                        $response = $this->anthropicBedrockResponse($responseBody);
                        $output = $response['output'];
                        $responsedText = $response['responsedText'];
                        $total_used_tokens = $response['total_used_tokens'];
                    }
                } else {
                    $data = $client->setStream(true)
                        ->setSystem($system)
                        ->setMessages(array_values($historyMessages))
                        ->stream()
                        ->body();
                    foreach (explode("\n", $data) as $chunk) {
                        if (strlen($chunk) < 6) {
                            continue;
                        }
                        if (! Str::contains($chunk, 'data: ')) {
                            continue;
                        }
                        $chunk = str_replace('data: {', '{', $chunk);
                        $jsonData = json_decode($chunk, false, 512, JSON_THROW_ON_ERROR);
                        if (isset($jsonData->delta->text)) {
                            $message = $jsonData->delta->text;
                            $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $message);
                            $output .= $messageFix;
                            $responsedText .= $message;
                            $total_used_tokens += countWords($message);

                            echo PHP_EOL;
                            echo "event: data\n";
                            echo 'data: ' . $messageFix;
                            echo "\n\n";
                            flush();
                        }
                        if (connection_aborted()) {
                            break;
                        }
                    }
                }
            } else {
                ApiHelper::setOpenAiKey();
                $driver = $this->createDriver(EntityEnum::GPT_4_O);
                $stream = OpenAI::chat()->createStreamed([
                    'model'             => $driver->enum()->value,
                    'messages'          => $history,
                    'max_tokens'        => 2000,
                    'temperature'       => 1.0,
                    'frequency_penalty' => 0,
                    'presence_penalty'  => 0,
                    'stream'            => true,
                ]);
                foreach ($stream as $response) {
                    if (isset($response->choices[0]->delta->content)) {
                        $text = $response->choices[0]->delta->content;
                        $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                        $output .= $messageFix;
                        $responsedText .= $text;
                        $total_used_tokens += countWords($text);
                        if (connection_aborted()) {
                            break;
                        }
                        echo PHP_EOL;
                        echo "event: data\n";
                        echo 'data: ' . $messageFix;
                        echo "\n\n";
                        flush();
                    }
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();
            $chat->total_credits += $total_used_tokens;
            $chat->save();

            $driver->input($responsedText)->calculateCredit()->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());

        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    private function anthropicOtherStream(Request $request, $chat_bot): StreamedResponse
    {
        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        $history[] = ['role' => 'user', 'content' => $prompt];
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        return response()->stream(static function () use ($driver, $history, &$total_used_tokens, &$output, &$responsedText, $message_id, $title, $openai_id, $prompt) {
            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $user = Auth::user();
            $entry = UserOpenai::find($message_id);
            if (is_null($entry)) {
                $entry = new UserOpenai;
                $entry->user_id = $user?->id;
                $entry->input = $prompt;
                $entry->hash = str()->random(256);
                $entry->team_id = $user?->team_id;
                $entry->slug = str()->random(7) . str($user?->fullName())->slug() . '-workbook';
                $entry->openai_id = $openai_id ?? 1;
            }

            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            $client = app(AnthropicService::class);
            $historyMessages = array_filter($history, function ($item) {
                return $item['role'] !== 'system';
            });
            $system = Arr::first(array_filter($history, function ($item) {
                return $item['role'] === 'system';
            }));

            $system = data_get($system, 'content');
            if (setting('anthropic_default_model') === BedrockEngine::BEDROCK->value) {
                $bedrockService = new BedrockRuntimeService([
                    'region'      => config('filesystems.disks.s3.region'),
                    'version'     => 'latest',
                    'credentials' => [
                        'key'    => config('filesystems.disks.s3.key'),
                        'secret' => config('filesystems.disks.s3.secret'),
                    ],
                ]);
                $driver = $this->createDriver(EntityEnum::CLAUDE_2_1);
                if (! $driver->hasCreditBalance()) {
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                    echo "\n\n";
                    flush();
                    echo "event: stop\n";
                    echo 'data: [DONE]';
                    echo "\n\n";
                    flush();

                    return null;
                }
                $responseBody = $bedrockService->invokeClaude($entry->input);
                if ($responseBody) {
                    $response = self::anthropicBedrockResponse($responseBody);
                    $output = $response['output'];
                    $responsedText = $response['responsedText'];
                    $total_used_tokens = $response['total_used_tokens'];
                    echo "event: stop\n";
                    echo 'data: [DONE]';
                    echo "\n\n";
                    flush();
                }

            } else {
                $data = $client->setStream(true)
                    ->setSystem($system)
                    ->setMessages(array_values($historyMessages))
                    ->stream()
                    ->body();
                foreach (explode("\n", $data) as $chunk) {
                    if (strlen($chunk) < 6) {
                        continue;
                    }
                    if (! Str::contains($chunk, 'data: ')) {
                        continue;
                    }
                    $chunk = str_replace('data: {', '{', $chunk);
                    if (isset(json_decode($chunk, false, 512, JSON_THROW_ON_ERROR)->delta->text)) {
                        $message = json_decode($chunk, false, 512, JSON_THROW_ON_ERROR)->delta->text;
                        $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $message);
                        $output .= $messageFix;
                        $responsedText .= $message;
                        $total_used_tokens += countWords($message);

                        echo PHP_EOL;
                        echo "event: data\n";
                        echo 'data: ' . $messageFix;
                        echo "\n\n";
                        flush();
                    }
                    if (connection_aborted()) {
                        break;
                    }
                }
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

            }

            $entry->title = $title ?: null;
            $entry->credits = $total_used_tokens;
            $entry->words = $total_used_tokens;
            $entry->response = $responsedText;
            $entry->output = $output;
            $entry->save();
            $driver
                ->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    // GeminiService Stream
    private function geminiChatStream(string $chat_bot, $history, $main_message, $chat_type, $contain_images): StreamedResponse
    {
        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';
        $newhistory = convertHistoryToGemini($history);
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));

        if ($contain_images) {
            // I will improve later
            $newhistory = $this->getLastMessageAndImage($newhistory);
            if (count($newhistory['parts']) === 1) {
                $newhistory['parts'][0] = [
                    'text' => $newhistory['parts'][0]['text'],
                ];

                $contain_images = false;
            }

            $newhistory = [$newhistory];
        }

        return response()->stream(static function () use ($driver, $newhistory, &$total_used_tokens, &$output, &$responsedText, $main_message, $contain_images) {

            $chat_id = $main_message->user_openai_chat_id;
            $chat = UserOpenaiChat::whereId($chat_id)->first();
            echo "event: message\n";
            echo 'data: ' . $main_message->id . "\n\n";

            if ($contain_images) {
                $driver = $this->createDriver(EntityEnum::GEMINI_1_5_FLASH);
            }

            if (! $driver->hasCreditBalance()) {
                echo PHP_EOL;
                echo "event: data\n";
                echo 'data: ' . __('You have no credits left. Please buy more credits to continue.');
                echo "\n\n";
                flush();
                echo "event: stop\n";
                echo 'data: [DONE]';
                echo "\n\n";
                flush();

                return null;
            }

            $client = app(GeminiService::class);
            $response = $client
                ->setHistory($newhistory)
                ->streamGenerateContent($driver->enum()->value);

            while (! $response->getBody()->eof()) {

                $line = $client->readLine($response->getBody());

                try {
                    $decodedLine = json_decode($line, true, 512, JSON_THROW_ON_ERROR);

                    if ($decodedLine === null || ! isset($decodedLine['candidates'])) {
                        Log::info('Decoded line does not contain expected data: ' . json_encode($decodedLine));

                        continue;
                    }
                } catch (JsonException $e) {
                    Log::error('JSON decoding error: ' . $e->getMessage());
                    Log::error('Offending line: ' . $line);

                    continue;
                }

                if ($decodedLine === null || ! isset($decodedLine['candidates'])) {
                    continue;
                }

                foreach ($decodedLine['candidates'] as $candidate) {
                    $text = $candidate['content']['parts'][0]['text'];
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);

                    if (connection_aborted()) {
                        break;
                    }

                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $main_message->response = $responsedText;
            $main_message->output = $output;
            $main_message->credits = $total_used_tokens;
            $main_message->words = $total_used_tokens;
            $main_message->save();
            $chat->total_credits += $total_used_tokens;
            $chat->save();
            $driver
                ->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    public function getLastMessageAndImage($newhistory)
    {
        return Arr::last($newhistory);
    }

    private function geminiOtherStream(Request $request, string $chat_bot): StreamedResponse
    {
        $driver = $this->createDriver(EntityEnum::fromSlug($chat_bot));
        $prompt = $request->get('prompt');
        $message_id = $request->get('message_id');
        $openai_id = $request->get('openai_id');
        $title = $request->get('title');

        $history[] = [
            'parts' => [
                [
                    'text' => $prompt,
                ],
            ],
            'role' => 'user',
        ];

        $total_used_tokens = 0;
        $output = '';
        $responsedText = '';

        return response()->stream(static function () use ($driver, $history, &$total_used_tokens, &$output, &$responsedText, $message_id, $title, $openai_id, $prompt) {
            $user = Auth::user();
            $entry = UserOpenai::find($message_id);
            if (is_null($entry)) {
                $entry = new UserOpenai;
                $entry->user_id = $user->id;
                $entry->input = $prompt;
                $entry->hash = str()->random(256);
                $entry->team_id = $user->team_id;
                $entry->slug = str()->random(7) . str($user?->fullName())->slug() . '-workbook';
                $entry->openai_id = $openai_id ?? 1;
            }

            echo "event: message\n";
            echo 'data: ' . $message_id . "\n\n";

            $client = app(GeminiService::class);
            $response = $client
                ->setHistory($history)
                ->streamGenerateContent($driver->enum()->value);

            while (! $response->getBody()->eof()) {

                $line = $client->readLine($response->getBody());

                try {
                    $decodedLine = json_decode($line, true, 512, JSON_THROW_ON_ERROR);

                    if ($decodedLine === null || ! isset($decodedLine['candidates'])) {
                        Log::info('Decoded line does not contain expected data: ' . json_encode($decodedLine));

                        continue;
                    }
                } catch (JsonException $e) {
                    Log::error('JSON decoding error: ' . $e->getMessage());
                    Log::error('Offending line: ' . $line);

                    continue;
                }
                if ($decodedLine === null || ! isset($decodedLine['candidates'])) {
                    continue;
                }

                foreach ($decodedLine['candidates'] as $candidate) {
                    $text = $candidate['content']['parts'][0]['text'];
                    $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $text);
                    $output .= $messageFix;
                    $responsedText .= $text;
                    $total_used_tokens += countWords($text);
                    if (connection_aborted()) {
                        break;
                    }
                    echo PHP_EOL;
                    echo "event: data\n";
                    echo 'data: ' . $messageFix;
                    echo "\n\n";
                    flush();
                }
            }

            echo "event: stop\n";
            echo 'data: [DONE]';
            echo "\n\n";
            flush();

            $entry->title = $title ?: null;
            $entry->credits = $total_used_tokens;
            $entry->words = $total_used_tokens;
            $entry->response = $responsedText;
            $entry->output = $output;
            $entry->save();
            $driver
                ->input($responsedText)
                ->calculateCredit()
                ->decreaseCredit();
            Usage::getSingle()->updateWordCounts($driver->calculate());
        }, 200, [
            'Cache-Control'     => 'no-cache',
            'X-Accel-Buffering' => 'no',
            'Content-Type'      => 'text/event-stream',
        ]);
    }

    private function anthropicBedrockResponse($responseBody): array
    {
        $completion = $responseBody['completion'];
        $parts = explode(':', $completion, 2);
        if (isset($parts[1])) {
            $completion = trim($parts[1]);
        }

        $words = explode(' ', $completion);
        $output = $completion;
        $responsedText = $completion;
        $total_used_tokens = count($words);
        foreach ($words as $word) {
            $messageFix = str_replace(["\r\n", "\r", "\n"], '<br/>', $word) . ' ';

            echo PHP_EOL;
            echo "event: data\n";
            echo 'data: ' . $messageFix;
            echo "\n\n";
            flush();

            if (connection_aborted()) {
                break;
            }
        }

        return [
            'output'            => $output,
            'responsedText'     => $responsedText,
            'total_used_tokens' => $total_used_tokens,
        ];
    }
}