fix:formatting for AI generated responses
This commit is contained in:
Generated
+1
-347
@@ -4,7 +4,7 @@
|
|||||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||||
"This file is @generated automatically"
|
"This file is @generated automatically"
|
||||||
],
|
],
|
||||||
"content-hash": "5db6b7e4a69c3e4bfc31d7d4f2bde9cd",
|
"content-hash": "455407a01daeb19b75bf4d7e31868f85",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "aws/aws-crt-php",
|
"name": "aws/aws-crt-php",
|
||||||
@@ -1727,56 +1727,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2023-12-03T19:50:20+00:00"
|
"time": "2023-12-03T19:50:20+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "hollodotme/fast-cgi-client",
|
|
||||||
"version": "v3.1.7",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/hollodotme/fast-cgi-client.git",
|
|
||||||
"reference": "062182d4eda73c161cc2839783acc83096ec0f37"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/hollodotme/fast-cgi-client/zipball/062182d4eda73c161cc2839783acc83096ec0f37",
|
|
||||||
"reference": "062182d4eda73c161cc2839783acc83096ec0f37",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-json": "*",
|
|
||||||
"php": ">=7.1"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-xdebug": ">=2.6.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"hollodotme\\FastCGI\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Holger Woltersdorf",
|
|
||||||
"email": "hw@hollo.me"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "A PHP fast CGI client to send requests (a)synchronously to PHP-FPM.",
|
|
||||||
"keywords": [
|
|
||||||
"Socket",
|
|
||||||
"async",
|
|
||||||
"fastcgi",
|
|
||||||
"php-fpm"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/hollodotme/fast-cgi-client/issues",
|
|
||||||
"source": "https://github.com/hollodotme/fast-cgi-client/tree/v3.1.7"
|
|
||||||
},
|
|
||||||
"time": "2021-12-07T10:10:20+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "jfcherng/php-color-output",
|
"name": "jfcherng/php-color-output",
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
@@ -2677,85 +2627,6 @@
|
|||||||
},
|
},
|
||||||
"time": "2024-09-23T13:32:56+00:00"
|
"time": "2024-09-23T13:32:56+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "laravel/vapor-core",
|
|
||||||
"version": "v2.37.1",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/laravel/vapor-core.git",
|
|
||||||
"reference": "9fac8cd0f9b6979887253dd676e04ecb868be615"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/laravel/vapor-core/zipball/9fac8cd0f9b6979887253dd676e04ecb868be615",
|
|
||||||
"reference": "9fac8cd0f9b6979887253dd676e04ecb868be615",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"aws/aws-sdk-php": "^3.80",
|
|
||||||
"guzzlehttp/guzzle": "^6.3|^7.0",
|
|
||||||
"guzzlehttp/promises": "^1.4|^2.0",
|
|
||||||
"hollodotme/fast-cgi-client": "^3.0",
|
|
||||||
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
|
|
||||||
"illuminate/http": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
|
|
||||||
"illuminate/queue": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
|
|
||||||
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0",
|
|
||||||
"monolog/monolog": "^1.12|^2.0|^3.2",
|
|
||||||
"nyholm/psr7": "^1.0",
|
|
||||||
"php": "^7.2|^8.0",
|
|
||||||
"riverline/multipart-parser": "^2.0.9",
|
|
||||||
"symfony/process": "^4.3|^5.0|^6.0|^7.0",
|
|
||||||
"symfony/psr-http-message-bridge": "^1.0|^2.0|^6.4|^7.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"mockery/mockery": "^1.2",
|
|
||||||
"orchestra/testbench": "^4.0|^5.0|^6.0|^7.0|^8.0|^9.0",
|
|
||||||
"phpstan/phpstan": "^1.10",
|
|
||||||
"phpunit/phpunit": "^8.0|^9.0|^10.4"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "2.0-dev"
|
|
||||||
},
|
|
||||||
"laravel": {
|
|
||||||
"providers": [
|
|
||||||
"Laravel\\Vapor\\VaporServiceProvider"
|
|
||||||
],
|
|
||||||
"aliases": {
|
|
||||||
"Vapor": "Laravel\\Vapor\\Vapor"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"files": [
|
|
||||||
"src/debug.php"
|
|
||||||
],
|
|
||||||
"psr-4": {
|
|
||||||
"Laravel\\Vapor\\": "src"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Taylor Otwell",
|
|
||||||
"email": "taylor@laravel.com"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "The kernel and invocation handlers for Laravel Vapor",
|
|
||||||
"homepage": "https://github.com/laravel/vapor-core",
|
|
||||||
"keywords": [
|
|
||||||
"laravel",
|
|
||||||
"vapor"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/laravel/vapor-core/tree/v2.37.1"
|
|
||||||
},
|
|
||||||
"time": "2024-03-26T16:55:06+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "league/commonmark",
|
"name": "league/commonmark",
|
||||||
"version": "2.5.3",
|
"version": "2.5.3",
|
||||||
@@ -4306,84 +4177,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-10-15T16:15:16+00:00"
|
"time": "2024-10-15T16:15:16+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "nyholm/psr7",
|
|
||||||
"version": "1.8.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Nyholm/psr7.git",
|
|
||||||
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/Nyholm/psr7/zipball/a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
|
|
||||||
"reference": "a71f2b11690f4b24d099d6b16690a90ae14fc6f3",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=7.2",
|
|
||||||
"psr/http-factory": "^1.0",
|
|
||||||
"psr/http-message": "^1.1 || ^2.0"
|
|
||||||
},
|
|
||||||
"provide": {
|
|
||||||
"php-http/message-factory-implementation": "1.0",
|
|
||||||
"psr/http-factory-implementation": "1.0",
|
|
||||||
"psr/http-message-implementation": "1.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"http-interop/http-factory-tests": "^0.9",
|
|
||||||
"php-http/message-factory": "^1.0",
|
|
||||||
"php-http/psr7-integration-tests": "^1.0",
|
|
||||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.4",
|
|
||||||
"symfony/error-handler": "^4.4"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "1.8-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Nyholm\\Psr7\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Tobias Nyholm",
|
|
||||||
"email": "tobias.nyholm@gmail.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Martijn van der Ven",
|
|
||||||
"email": "martijn@vanderven.se"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "A fast PHP7 implementation of PSR-7",
|
|
||||||
"homepage": "https://tnyholm.se",
|
|
||||||
"keywords": [
|
|
||||||
"psr-17",
|
|
||||||
"psr-7"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/Nyholm/psr7/issues",
|
|
||||||
"source": "https://github.com/Nyholm/psr7/tree/1.8.2"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://github.com/Zegnat",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/nyholm",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2024-09-09T07:06:30+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "openai-php/client",
|
"name": "openai-php/client",
|
||||||
"version": "v0.10.2",
|
"version": "v0.10.2",
|
||||||
@@ -5936,62 +5729,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-04-27T21:32:50+00:00"
|
"time": "2024-04-27T21:32:50+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "riverline/multipart-parser",
|
|
||||||
"version": "2.1.2",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/Riverline/multipart-parser.git",
|
|
||||||
"reference": "7a9f4646db5181516c61b8e0225a343189beedcd"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/Riverline/multipart-parser/zipball/7a9f4646db5181516c61b8e0225a343189beedcd",
|
|
||||||
"reference": "7a9f4646db5181516c61b8e0225a343189beedcd",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"ext-mbstring": "*",
|
|
||||||
"php": ">=5.6.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"laminas/laminas-diactoros": "^1.8.7 || ^2.11.1",
|
|
||||||
"phpunit/phpunit": "^5.7 || ^9.0",
|
|
||||||
"psr/http-message": "^1.0",
|
|
||||||
"symfony/psr-http-message-bridge": "^1.1 || ^2.0"
|
|
||||||
},
|
|
||||||
"type": "library",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Riverline\\MultiPartParser\\": "src/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Romain Cambien",
|
|
||||||
"email": "romain@cambien.net"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Riverline",
|
|
||||||
"homepage": "http://www.riverline.fr"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "One class library to parse multipart content with encoding and charset support.",
|
|
||||||
"keywords": [
|
|
||||||
"http",
|
|
||||||
"multipart",
|
|
||||||
"parser"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"issues": "https://github.com/Riverline/multipart-parser/issues",
|
|
||||||
"source": "https://github.com/Riverline/multipart-parser/tree/2.1.2"
|
|
||||||
},
|
|
||||||
"time": "2024-03-12T16:46:05+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "robsontenorio/mary",
|
"name": "robsontenorio/mary",
|
||||||
"version": "1.41.2",
|
"version": "1.41.2",
|
||||||
@@ -7948,89 +7685,6 @@
|
|||||||
],
|
],
|
||||||
"time": "2024-09-25T14:20:29+00:00"
|
"time": "2024-09-25T14:20:29+00:00"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "symfony/psr-http-message-bridge",
|
|
||||||
"version": "v7.1.6",
|
|
||||||
"source": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/symfony/psr-http-message-bridge.git",
|
|
||||||
"reference": "f16471bb19f6685b9ccf0a2c03c213840ae68cd6"
|
|
||||||
},
|
|
||||||
"dist": {
|
|
||||||
"type": "zip",
|
|
||||||
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/f16471bb19f6685b9ccf0a2c03c213840ae68cd6",
|
|
||||||
"reference": "f16471bb19f6685b9ccf0a2c03c213840ae68cd6",
|
|
||||||
"shasum": ""
|
|
||||||
},
|
|
||||||
"require": {
|
|
||||||
"php": ">=8.2",
|
|
||||||
"psr/http-message": "^1.0|^2.0",
|
|
||||||
"symfony/http-foundation": "^6.4|^7.0"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"php-http/discovery": "<1.15",
|
|
||||||
"symfony/http-kernel": "<6.4"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"nyholm/psr7": "^1.1",
|
|
||||||
"php-http/discovery": "^1.15",
|
|
||||||
"psr/log": "^1.1.4|^2|^3",
|
|
||||||
"symfony/browser-kit": "^6.4|^7.0",
|
|
||||||
"symfony/config": "^6.4|^7.0",
|
|
||||||
"symfony/event-dispatcher": "^6.4|^7.0",
|
|
||||||
"symfony/framework-bundle": "^6.4|^7.0",
|
|
||||||
"symfony/http-kernel": "^6.4|^7.0"
|
|
||||||
},
|
|
||||||
"type": "symfony-bridge",
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Symfony\\Bridge\\PsrHttpMessage\\": ""
|
|
||||||
},
|
|
||||||
"exclude-from-classmap": [
|
|
||||||
"/Tests/"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"notification-url": "https://packagist.org/downloads/",
|
|
||||||
"license": [
|
|
||||||
"MIT"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Fabien Potencier",
|
|
||||||
"email": "fabien@symfony.com"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Symfony Community",
|
|
||||||
"homepage": "https://symfony.com/contributors"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"description": "PSR HTTP message bridge",
|
|
||||||
"homepage": "https://symfony.com",
|
|
||||||
"keywords": [
|
|
||||||
"http",
|
|
||||||
"http-message",
|
|
||||||
"psr-17",
|
|
||||||
"psr-7"
|
|
||||||
],
|
|
||||||
"support": {
|
|
||||||
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v7.1.6"
|
|
||||||
},
|
|
||||||
"funding": [
|
|
||||||
{
|
|
||||||
"url": "https://symfony.com/sponsor",
|
|
||||||
"type": "custom"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://github.com/fabpot",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
|
||||||
"type": "tidelift"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"time": "2024-09-25T14:20:29+00:00"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "symfony/routing",
|
"name": "symfony/routing",
|
||||||
"version": "v7.1.6",
|
"version": "v7.1.6",
|
||||||
|
|||||||
@@ -5,3 +5,16 @@
|
|||||||
[x-cloak] {
|
[x-cloak] {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ai-chat ul {
|
||||||
|
margin-left: 1.1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat ul li {
|
||||||
|
padding-left: 1.1rem;
|
||||||
|
list-style-type: disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ai-chat li, .ai-chat p {
|
||||||
|
padding-bottom: .25em;
|
||||||
|
}
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
|
|
||||||
Based on this current market data, quantity owned, and average cost basis, you should determine if the {$holding->symbol} holding is making or losing money.
|
Based on this current market data, quantity owned, and average cost basis, you should determine if the {$holding->symbol} holding is making or losing money.
|
||||||
|
|
||||||
Below is the question from the investor. Considering these facts, provide a concise response to the following question (give a direct response). Limit your response to no more than 75 words and consider using a common decision framework:"
|
Below is the question from the investor. Considering these facts, provide a concise response to the following question (give a direct response). Limit your response to no more than 75 words and consider using a common decision framework. Use github style markdown for any formatting:"
|
||||||
])
|
])
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,232 +1,209 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Mary\Traits\Toast;
|
use Mary\Traits\Toast;
|
||||||
use App\Models\AiChat;
|
use App\Models\AiChat;
|
||||||
use App\Models\Holding;
|
use App\Models\Holding;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
use Livewire\Volt\Component;
|
use Livewire\Volt\Component;
|
||||||
use OpenAI\Laravel\Facades\OpenAI;
|
use OpenAI\Laravel\Facades\OpenAI;
|
||||||
use OpenAI\Responses\StreamResponse;
|
use OpenAI\Responses\StreamResponse;
|
||||||
|
|
||||||
new class extends Component {
|
new class extends Component {
|
||||||
|
|
||||||
use Toast;
|
use Toast;
|
||||||
|
|
||||||
// props
|
// props
|
||||||
public Model $chatable;
|
public Model $chatable;
|
||||||
public string $system_prompt = '';
|
public string $system_prompt = 'You are an investment portfolio assistant providing advice to an investor. Use the following information to provide relevant recommendations. Use the words \'likely\' or \'may\' instead of concrete statements (except for obvious statements of fact or common sense). Use github style markdown for any formatting.';
|
||||||
public array $suggested_prompts = [];
|
public array $suggested_prompts = [];
|
||||||
|
|
||||||
public array $messages = [];
|
public array $messages = [];
|
||||||
public ?string $prompt = null;
|
public ?string $prompt = null;
|
||||||
public ?string $answer = null;
|
public ?string $answer = null;
|
||||||
public bool $streaming = false;
|
public bool $streaming = false;
|
||||||
|
|
||||||
// methods
|
// methods
|
||||||
public function mount()
|
public function mount()
|
||||||
{
|
{
|
||||||
$this->messages = $this->chatable->chats()->orderByRaw('created_at, id')->get(['role', 'content'])->toArray();
|
$this->messages = $this->chatable->chats()->orderByRaw('created_at, id')->limit(25)->get(['role', 'content'])->toArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function startCompletion($suggestedPrompt = null)
|
||||||
|
{
|
||||||
|
// prevent spam
|
||||||
|
if ($this->isRateLimited() || $this->streaming) {
|
||||||
|
array_push($this->messages, [
|
||||||
|
'role' => 'assistant',
|
||||||
|
'content' => __('Hang on! You\'re doing that too much.')
|
||||||
|
]);
|
||||||
|
$this->js('scrollChatWindow(250)');
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function startCompletion($suggestedPrompt = null)
|
if ($suggestedPrompt) {
|
||||||
{
|
$this->prompt = $suggestedPrompt;
|
||||||
// prevent spam
|
}
|
||||||
if ($this->isRateLimited() || $this->streaming) {
|
|
||||||
array_push($this->messages, [
|
|
||||||
'role' => 'assistant',
|
|
||||||
'content' => __('Hang on! You\'re doing that too much.')
|
|
||||||
]);
|
|
||||||
$this->js('scrollChatWindow(250)');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($suggestedPrompt) {
|
if (empty(trim($this->prompt))) {
|
||||||
$this->prompt = $suggestedPrompt;
|
$this->resetPrompt();
|
||||||
}
|
|
||||||
|
|
||||||
if (empty(trim($this->prompt))) {
|
array_push($this->messages, ['role' => 'assistant', 'content' => __('Feel free to ask me a question!')]);
|
||||||
$this->resetPrompt();
|
|
||||||
|
|
||||||
array_push($this->messages, ['role' => 'assistant', 'content' => __('Feel free to ask me a question!')]);
|
|
||||||
$this->js('scrollChatWindow(250)');
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->chatable->chats()->save(new AiChat(['role' => 'user', 'content' => $this->prompt]));
|
|
||||||
array_push($this->messages, ['role' => 'user', 'content' => $this->prompt]);
|
|
||||||
$this->js('scrollChatWindow(250)');
|
$this->js('scrollChatWindow(250)');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->chatable->chats()->save(new AiChat(['role' => 'user', 'content' => $this->prompt]));
|
||||||
|
array_push($this->messages, ['role' => 'user', 'content' => $this->prompt]);
|
||||||
|
$this->js('scrollChatWindow(250)');
|
||||||
|
|
||||||
|
$this->resetPrompt();
|
||||||
|
|
||||||
|
$this->streaming = true;
|
||||||
|
$this->js('$wire.generate()');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function generate(): void
|
||||||
|
{
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stream = OpenAI::chat()->createStreamed([
|
||||||
|
'model' => config('openai.model'),
|
||||||
|
'messages' => [
|
||||||
|
['role' => 'system', 'content' => $this->system_prompt],
|
||||||
|
...array_slice($this->messages, -10)
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
|
||||||
|
$this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $e->getMessage()]));
|
||||||
|
array_push($this->messages, ['role' => 'assistant', 'content' => $e->getMessage()]);
|
||||||
$this->resetPrompt();
|
$this->resetPrompt();
|
||||||
|
return;
|
||||||
$this->streaming = true;
|
|
||||||
$this->js('$wire.generate()');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function generate(): void
|
$this->stream(to: "answer", content: '', replace: true);
|
||||||
{
|
|
||||||
|
|
||||||
try {
|
foreach($stream as $response){
|
||||||
$stream = OpenAI::chat()->createStreamed([
|
|
||||||
'model' => config('openai.model'),
|
|
||||||
'messages' => [
|
|
||||||
['role' => 'system', 'content' => $this->system_prompt],
|
|
||||||
...array_slice($this->messages, -10)
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
|
|
||||||
$this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $e->getMessage()]));
|
if(!empty($response->choices[0]->delta->content)) {
|
||||||
array_push($this->messages, ['role' => 'assistant', 'content' => $e->getMessage()]);
|
$this->stream(to: 'answer', content: $response->choices[0]->delta->content, replace: false);
|
||||||
$this->resetPrompt();
|
$this->answer .= $response->choices[0]->delta->content;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
$this->js('scrollChatWindow()');
|
||||||
$this->stream(to: "answer", content: '', replace: true);
|
|
||||||
|
|
||||||
foreach($stream as $response){
|
|
||||||
|
|
||||||
if(!empty($response->choices[0]->delta->content)) {
|
|
||||||
$this->stream(to: 'answer', content: $response->choices[0]->delta->content, replace: false);
|
|
||||||
$this->answer .= $response->choices[0]->delta->content;
|
|
||||||
}
|
|
||||||
$this->js('scrollChatWindow()');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $this->answer]));
|
|
||||||
array_push($this->messages, ['role' => 'assistant', 'content' => $this->answer]);
|
|
||||||
$this->resetPrompt();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function resetPrompt(): void
|
$this->chatable->chats()->save(new AiChat(['role' => 'assistant', 'content' => $this->answer]));
|
||||||
{
|
array_push($this->messages, ['role' => 'assistant', 'content' => $this->answer]);
|
||||||
$this->answer = null;
|
$this->resetPrompt();
|
||||||
$this->prompt = null;
|
}
|
||||||
$this->streaming = false;
|
|
||||||
|
public function resetPrompt(): void
|
||||||
|
{
|
||||||
|
$this->answer = null;
|
||||||
|
$this->prompt = null;
|
||||||
|
$this->streaming = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRateLimited(): bool
|
||||||
|
{
|
||||||
|
$rateLimitKey = auth()->id() . '/' . $this->chatable->id;
|
||||||
|
|
||||||
|
if (RateLimiter::tooManyAttempts($rateLimitKey, 20)) {
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isRateLimited(): bool
|
RateLimiter::hit($rateLimitKey, 60);
|
||||||
{
|
|
||||||
$rateLimitKey = auth()->id() . '/' . $this->chatable->id;
|
|
||||||
|
|
||||||
if (RateLimiter::tooManyAttempts($rateLimitKey, 20)) {
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
}; ?>
|
||||||
}
|
|
||||||
|
|
||||||
RateLimiter::hit($rateLimitKey, 60);
|
<div
|
||||||
|
x-data="{
|
||||||
return false;
|
open: false,
|
||||||
|
async scrollChatWindow(delay = 0) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, delay));
|
||||||
|
this.$refs.chatWindow.scrollBy({
|
||||||
|
top: this.$refs.chatWindow.scrollHeight,
|
||||||
|
behavior: 'smooth'
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
}"
|
||||||
}; ?>
|
class="flex flex-col"
|
||||||
|
>
|
||||||
|
<x-button
|
||||||
|
@click="$dispatch('toggle-ai-chat')"
|
||||||
|
class="btn btn-circle btn-lg btn-primary fixed bottom-10 right-10"
|
||||||
|
>
|
||||||
|
<x-slot:label>
|
||||||
|
<x-icon name="o-sparkles" class="w-8 h-8"></x-icon>
|
||||||
|
</x-slot:label>
|
||||||
|
</x-button>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
x-data="{
|
x-on:toggle-ai-chat.window="open = !open"
|
||||||
open: false,
|
x-show="open"
|
||||||
async scrollChatWindow(delay = 0) {
|
x-trap="open"
|
||||||
await new Promise(resolve => setTimeout(resolve, delay));
|
x-bind:inert="!open"
|
||||||
this.$refs.chatWindow.scrollBy({
|
x-transition.opacity
|
||||||
top: this.$refs.chatWindow.scrollHeight,
|
x-cloak
|
||||||
behavior: 'smooth'
|
key="ai-chat"
|
||||||
});
|
class="fixed
|
||||||
}
|
bottom-0 right-0 w-full h-screen
|
||||||
}"
|
md:bottom-[7rem] md:right-10 md:w-[35rem] md:h-auto"
|
||||||
class="flex flex-col"
|
|
||||||
>
|
>
|
||||||
<x-button
|
|
||||||
@click="$dispatch('toggle-ai-chat')"
|
|
||||||
class="btn btn-circle btn-lg btn-primary fixed bottom-10 right-10"
|
|
||||||
>
|
|
||||||
<x-slot:label>
|
|
||||||
<x-icon name="o-sparkles" class="w-8 h-8"></x-icon>
|
|
||||||
</x-slot:label>
|
|
||||||
</x-button>
|
|
||||||
|
|
||||||
<div
|
<x-card class="shadow-2xl" title="{{ __('AI Chat') }}" x-intersect="scrollChatWindow()">
|
||||||
x-on:toggle-ai-chat.window="open = !open"
|
{{-- close button --}}
|
||||||
x-show="open"
|
<x-button
|
||||||
x-trap="open"
|
icon="o-x-mark"
|
||||||
x-bind:inert="!open"
|
class="absolute top-5 right-4 btn-ghost btn-circle btn-sm"
|
||||||
x-transition.opacity
|
title="{{ __('Close') }}"
|
||||||
x-cloak
|
@click="open = false"
|
||||||
key="ai-chat"
|
/>
|
||||||
class="fixed
|
|
||||||
bottom-0 right-0 w-full h-screen
|
|
||||||
md:bottom-[7rem] md:right-10 md:w-[35rem] md:h-auto"
|
|
||||||
>
|
|
||||||
|
|
||||||
<x-card class="shadow-2xl" title="{{ __('AI Chat') }}" x-intersect="scrollChatWindow()">
|
{{-- chat window --}}
|
||||||
{{-- close button --}}
|
<div class="h-[25rem] overflow-y-scroll ai-chat" x-ref="chatWindow">
|
||||||
<x-button
|
|
||||||
icon="o-x-mark"
|
|
||||||
class="absolute top-5 right-4 btn-ghost btn-circle btn-sm"
|
|
||||||
title="{{ __('Close') }}"
|
|
||||||
@click="open = false"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{{-- chat window --}}
|
<div class="flex gap-3 mb-5 flex-1">
|
||||||
<div class="h-[25rem] overflow-y-scroll" x-ref="chatWindow">
|
<span class="
|
||||||
|
flex
|
||||||
|
rounded-full
|
||||||
|
w-10 h-10
|
||||||
|
border border-gray-600
|
||||||
|
dark:border-gray-400
|
||||||
|
text-gray-600
|
||||||
|
dark:text-gray-400
|
||||||
|
bg-slate-200
|
||||||
|
dark:bg-slate-800
|
||||||
|
">
|
||||||
|
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
||||||
|
</span>
|
||||||
|
<p class="leading-relaxed w-full">
|
||||||
|
<span class="block font-bold">AI</span> {{ __('Hi, how can I help?') }}
|
||||||
|
|
||||||
<div class="flex gap-3 mb-5 flex-1">
|
</p>
|
||||||
<span class="
|
</div>
|
||||||
flex
|
|
||||||
rounded-full
|
|
||||||
w-10 h-10
|
|
||||||
border border-gray-600
|
|
||||||
dark:border-gray-400
|
|
||||||
text-gray-600
|
|
||||||
dark:text-gray-400
|
|
||||||
bg-slate-200
|
|
||||||
dark:bg-slate-800
|
|
||||||
">
|
|
||||||
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
|
||||||
</span>
|
|
||||||
<p class="leading-relaxed w-full">
|
|
||||||
<span class="block font-bold">AI</span> {{ __('Hi, how can I help?') }}
|
|
||||||
|
|
||||||
</p>
|
@foreach($messages as $message)
|
||||||
</div>
|
|
||||||
|
|
||||||
@foreach($messages as $message)
|
@if ($message['role'] == 'user')
|
||||||
|
<div class="flex gap-3 mb-5 flex-1">
|
||||||
|
<span class="relative flex shrink-0 overflow-hidden rounded-full w-10 h-10">
|
||||||
|
|
||||||
@if ($message['role'] == 'user')
|
<x-avatar :image="auth()->user()->profile_photo_url" class="!w-10" />
|
||||||
<div class="flex gap-3 mb-5 flex-1">
|
|
||||||
<span class="relative flex shrink-0 overflow-hidden rounded-full w-10 h-10">
|
|
||||||
|
|
||||||
<x-avatar :image="auth()->user()->profile_photo_url" class="!w-10" />
|
</span>
|
||||||
|
<p class="leading-relaxed">
|
||||||
|
<span class="block font-bold ">{{ __('You') }} </span> {{ $message['content'] }}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</span>
|
@else
|
||||||
<p class="leading-relaxed">
|
<div class="flex gap-3 mb-5 flex-1">
|
||||||
<span class="block font-bold ">{{ __('You') }} </span> {{ $message['content'] }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@else
|
|
||||||
<div class="flex gap-3 mb-5 flex-1">
|
|
||||||
<span class="
|
|
||||||
flex
|
|
||||||
rounded-full
|
|
||||||
w-10 h-10
|
|
||||||
border border-gray-600
|
|
||||||
dark:border-gray-400
|
|
||||||
text-gray-600
|
|
||||||
dark:text-gray-400
|
|
||||||
bg-slate-200
|
|
||||||
dark:bg-slate-800
|
|
||||||
">
|
|
||||||
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
|
||||||
</span>
|
|
||||||
<p class="leading-relaxed" >
|
|
||||||
<span class="block font-bold ">AI </span> {{ $message['content'] }}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
@endif
|
|
||||||
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
@if($streaming)
|
|
||||||
<div class="flex gap-3 mb-10 flex-1">
|
|
||||||
<span class="
|
<span class="
|
||||||
flex
|
flex
|
||||||
rounded-full
|
rounded-full
|
||||||
@@ -240,51 +217,73 @@
|
|||||||
">
|
">
|
||||||
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
||||||
</span>
|
</span>
|
||||||
<p class="leading-relaxed" >
|
<div class="leading-relaxed" >
|
||||||
<span class="block font-bold ">AI </span> <span wire:stream="answer">{{ $answer }}</span>
|
<span class="block font-bold ">AI </span> {!! Str::markdown($message['content']) !!}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@endforeach
|
||||||
|
|
||||||
|
@if($streaming)
|
||||||
|
<div class="flex gap-3 mb-10 flex-1">
|
||||||
|
<span class="
|
||||||
|
flex
|
||||||
|
rounded-full
|
||||||
|
w-10 h-10
|
||||||
|
border border-gray-600
|
||||||
|
dark:border-gray-400
|
||||||
|
text-gray-600
|
||||||
|
dark:text-gray-400
|
||||||
|
bg-slate-200
|
||||||
|
dark:bg-slate-800
|
||||||
|
">
|
||||||
|
<x-icon name="o-sparkles" class="h-auto p-1 w-10" />
|
||||||
|
</span>
|
||||||
|
<p class="leading-relaxed" >
|
||||||
|
<span class="block font-bold ">AI </span> <span wire:stream="answer">{{ $answer }}</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- prompt input --}}
|
||||||
|
<form submit="startCompletion" class="mt-3">
|
||||||
|
<div class="">
|
||||||
|
@foreach($suggested_prompts as $prompt)
|
||||||
|
<x-button
|
||||||
|
class="btn-xs btn-primary btn-outline mr-1 mb-2"
|
||||||
|
label="{{ $prompt['text'] }}"
|
||||||
|
wire:click="startCompletion('{{ $prompt['value'] }}')"
|
||||||
|
/>
|
||||||
|
@endforeach
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{{-- prompt input --}}
|
<div class="flex justify-between align-bottom space-x-2 mt-1">
|
||||||
<form submit="startCompletion" class="mt-3">
|
|
||||||
<div class="">
|
|
||||||
@foreach($suggested_prompts as $prompt)
|
|
||||||
<x-button
|
|
||||||
class="btn-xs btn-primary btn-outline mr-1 mb-2"
|
|
||||||
label="{{ $prompt['text'] }}"
|
|
||||||
wire:click="startCompletion('{{ $prompt['value'] }}')"
|
|
||||||
/>
|
|
||||||
@endforeach
|
|
||||||
|
|
||||||
|
<div class="w-full">
|
||||||
|
|
||||||
|
<x-textarea
|
||||||
|
wire:model="prompt"
|
||||||
|
class="h-24 resize-none "
|
||||||
|
placeholder="{{ __('Have a question? AI might be able to help...') }}"
|
||||||
|
wire:keydown.enter.prevent="startCompletion"
|
||||||
|
></x-textarea>
|
||||||
</div>
|
</div>
|
||||||
|
<x-button
|
||||||
|
spinner="generate"
|
||||||
|
wire:click="startCompletion"
|
||||||
|
class="btn btn-ghost h-24"
|
||||||
|
icon="o-paper-airplane"
|
||||||
|
></x-button>
|
||||||
|
|
||||||
<div class="flex justify-between align-bottom space-x-2 mt-1">
|
</div>
|
||||||
|
|
||||||
<div class="w-full">
|
<div class="w-full mt-2">
|
||||||
|
<p class="text-xs text-secondary leading-tight">{{ __('Advice generated by AI may contain errors. Use at your own risk. Always consult a licensed investment advisor.') }} </p>
|
||||||
<x-textarea
|
</div>
|
||||||
wire:model="prompt"
|
</form>
|
||||||
class="h-24 resize-none "
|
</x-card>
|
||||||
placeholder="{{ __('Have a question? AI might be able to help...') }}"
|
|
||||||
wire:keydown.enter.prevent="startCompletion"
|
|
||||||
></x-textarea>
|
|
||||||
</div>
|
|
||||||
<x-button
|
|
||||||
spinner="generate"
|
|
||||||
wire:click="startCompletion"
|
|
||||||
class="btn btn-ghost h-24"
|
|
||||||
icon="o-paper-airplane"
|
|
||||||
></x-button>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="w-full mt-2">
|
|
||||||
<p class="text-xs text-secondary leading-tight">{{ __('Advice generated by AI may contain errors. Use at your own risk. Always consult a licensed investment advisor.') }} </p>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</x-card>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -174,7 +174,7 @@
|
|||||||
|
|
||||||
Based on the current market data, quantity owned, and average cost basis, you can determine the performance of any holding.
|
Based on the current market data, quantity owned, and average cost basis, you can determine the performance of any holding.
|
||||||
|
|
||||||
Below is the question from the investor. Considering these facts, provide a concise response to the following question (give a direct response). Limit your response to no more than 75 words and consider using a common decision framework:"
|
Below is the question from the investor. Considering these facts, provide a concise response to the following question (give a direct response). Limit your response to no more than 75 words and consider using a common decision framework. Use github style markdown for any formatting:"
|
||||||
])
|
])
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user