refactor(core): restructure chat models and services, integrate route-based chat IDs

- Updated `Chat` and `ChatMessage` models for new table structures with UUIDs and attributes.
- Integrated `ChatPolicy` for authorization checks.
- Updated `ChatMessageController` with authorization and refined logic.
- Adjusted routes and state in the frontend to handle chat IDs from the URL.
- Enhanced `SocialMediaService` for handling chat-specific user prompts.
- Removed unused migrations related to chats and chat messages.
This commit is contained in:
kushal-saha 2026-04-29 15:36:56 +00:00
parent 6bd105632a
commit d818c5f05d
16 changed files with 238 additions and 245 deletions

2
.idea/.gitignore generated vendored
View File

@ -8,3 +8,5 @@
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
/laravel-idea-personal.xml
/jsLibraryMappings.xml

240
.idea/php.xml generated
View File

@ -3,6 +3,9 @@
<component name="LaravelPint">
<laravel_pint_settings>
<LaravelPintConfiguration tool_path="$PROJECT_DIR$/../.config/composer/vendor/bin/pint" />
<laravel_pint_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" tool_path="/home/krbfx/.config/composer/vendor/bin/pint">
<option name="timeout" value="30000" />
</laravel_pint_by_interpreter>
</laravel_pint_settings>
</component>
<component name="MessDetectorOptionsConfiguration">
@ -15,149 +18,159 @@
<option name="highlightLevel" value="WARNING" />
<option name="transferred" value="true" />
</component>
<component name="PhpCodeSniffer">
<phpcs_settings>
<phpcs_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="30000" />
</phpcs_settings>
</component>
<component name="PhpExternalFormatter">
<option name="externalFormatter" value="LARAVEL_PINT" />
</component>
<component name="PhpIncludePathManager">
<include_path>
<path value="$PROJECT_DIR$/backend/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-sdk-php" />
<path value="$PROJECT_DIR$/backend/vendor/bacon/bacon-qr-code" />
<path value="$PROJECT_DIR$/backend/vendor/brianium/paratest" />
<path value="$PROJECT_DIR$/backend/vendor/brick/math" />
<path value="$PROJECT_DIR$/backend/vendor/carbonphp/carbon-doctrine-types" />
<path value="$PROJECT_DIR$/backend/vendor/composer" />
<path value="$PROJECT_DIR$/backend/vendor/dasprid/enum" />
<path value="$PROJECT_DIR$/backend/vendor/dflydev/dot-access-data" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/backend/vendor/dragonmantank/cron-expression" />
<path value="$PROJECT_DIR$/backend/vendor/egulias/email-validator" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/collection" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/uuid" />
<path value="$PROJECT_DIR$/backend/vendor/mockery/mockery" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/collision" />
<path value="$PROJECT_DIR$/backend/vendor/fakerphp/faker" />
<path value="$PROJECT_DIR$/backend/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/backend/vendor/filp/whoops" />
<path value="$PROJECT_DIR$/backend/vendor/fruitcake/php-cors" />
<path value="$PROJECT_DIR$/backend/vendor/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/uri-template" />
<path value="$PROJECT_DIR$/backend/vendor/hamcrest/hamcrest-php" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/termwind" />
<path value="$PROJECT_DIR$/backend/vendor/jean85/pretty-package-versions" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/backend/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem" />
<path value="$PROJECT_DIR$/backend/vendor/league/uri-interfaces" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/ai" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/fortify" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/framework" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/pail" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/prompts" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/sanctum" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/serializable-closure" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/tinker" />
<path value="$PROJECT_DIR$/backend/vendor/league/commonmark" />
<path value="$PROJECT_DIR$/backend/vendor/league/config" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem-local" />
<path value="$PROJECT_DIR$/backend/vendor/league/mime-type-detection" />
<path value="$PROJECT_DIR$/backend/vendor/league/uri" />
<path value="$PROJECT_DIR$/backend/vendor/league/config" />
<path value="$PROJECT_DIR$/backend/vendor/league/flysystem-local" />
<path value="$PROJECT_DIR$/backend/vendor/brianium/paratest" />
<path value="$PROJECT_DIR$/backend/vendor/league/uri-interfaces" />
<path value="$PROJECT_DIR$/backend/vendor/mockery/mockery" />
<path value="$PROJECT_DIR$/backend/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/backend/vendor/mtdowling/jmespath.php" />
<path value="$PROJECT_DIR$/backend/vendor/myclabs/deep-copy" />
<path value="$PROJECT_DIR$/backend/vendor/composer" />
<path value="$PROJECT_DIR$/backend/vendor/nesbot/carbon" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/pail" />
<path value="$PROJECT_DIR$/backend/vendor/filp/whoops" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/tinker" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/serializable-closure" />
<path value="$PROJECT_DIR$/backend/vendor/brick/math" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/prompts" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/framework" />
<path value="$PROJECT_DIR$/backend/vendor/graham-campbell/result-type" />
<path value="$PROJECT_DIR$/backend/vendor/ta-tikoma/phpunit-architecture-test" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/deprecations" />
<path value="$PROJECT_DIR$/backend/vendor/psr/container" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/lexer" />
<path value="$PROJECT_DIR$/backend/vendor/doctrine/inflector" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/backend/vendor/nette/schema" />
<path value="$PROJECT_DIR$/backend/vendor/nette/utils" />
<path value="$PROJECT_DIR$/backend/vendor/nikic/php-parser" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/collision" />
<path value="$PROJECT_DIR$/backend/vendor/nunomaduro/termwind" />
<path value="$PROJECT_DIR$/backend/vendor/paragonie/constant_time_encoding" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin" />
<path value="$PROJECT_DIR$/backend/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-arch" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-laravel" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-mutate" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-profanity" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/manifest" />
<path value="$PROJECT_DIR$/backend/vendor/phar-io/version" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/backend/vendor/phpoption/phpoption" />
<path value="$PROJECT_DIR$/backend/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-code-coverage" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-file-iterator" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-invoker" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-text-template" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/php-timer" />
<path value="$PROJECT_DIR$/backend/vendor/phpunit/phpunit" />
<path value="$PROJECT_DIR$/backend/vendor/pragmarx/google2fa" />
<path value="$PROJECT_DIR$/backend/vendor/psr/clock" />
<path value="$PROJECT_DIR$/backend/vendor/psr/container" />
<path value="$PROJECT_DIR$/backend/vendor/psr/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-client" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-factory" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest" />
<path value="$PROJECT_DIR$/backend/vendor/psr/clock" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-profanity" />
<path value="$PROJECT_DIR$/backend/vendor/psr/http-message" />
<path value="$PROJECT_DIR$/backend/vendor/psr/log" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-mutate" />
<path value="$PROJECT_DIR$/backend/vendor/psr/simple-cache" />
<path value="$PROJECT_DIR$/backend/vendor/pestphp/pest-plugin-laravel" />
<path value="$PROJECT_DIR$/backend/vendor/fidry/cpu-core-counter" />
<path value="$PROJECT_DIR$/backend/vendor/tijsverkoyen/css-to-inline-styles" />
<path value="$PROJECT_DIR$/backend/vendor/carbonphp/carbon-doctrine-types" />
<path value="$PROJECT_DIR$/backend/vendor/fruitcake/php-cors" />
<path value="$PROJECT_DIR$/backend/vendor/dragonmantank/cron-expression" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/string" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/backend/vendor/phpoption/phpoption" />
<path value="$PROJECT_DIR$/backend/vendor/webmozart/assert" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/backend/vendor/voku/portable-ascii" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php85" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/uid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/psr7" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-common" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/console" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/promises" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/backend/vendor/psy/psysh" />
<path value="$PROJECT_DIR$/backend/vendor/ralouphie/getallheaders" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/uri-template" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/reflection-docblock" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/backend/vendor/guzzlehttp/guzzle" />
<path value="$PROJECT_DIR$/backend/vendor/phpdocumentor/type-resolver" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/backend/vendor/nette/schema" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/process" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/collection" />
<path value="$PROJECT_DIR$/backend/vendor/ramsey/uuid" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/cli-parser" />
<path value="$PROJECT_DIR$/backend/vendor/nette/utils" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mailer" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/complexity" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/global-state" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/object-enumerator" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/object-reflector" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/recursion-context" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/type" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/version" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/diff" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/lines-of-code" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/environment" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/comparator" />
<path value="$PROJECT_DIR$/backend/vendor/sebastian/exporter" />
<path value="$PROJECT_DIR$/backend/vendor/staabm/side-effects-detector" />
<path value="$PROJECT_DIR$/backend/vendor/fakerphp/faker" />
<path value="$PROJECT_DIR$/backend/vendor/monolog/monolog" />
<path value="$PROJECT_DIR$/backend/vendor/vlucas/phpdotenv" />
<path value="$PROJECT_DIR$/backend/vendor/phpstan/phpdoc-parser" />
<path value="$PROJECT_DIR$/backend/vendor/psy/psysh" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/sanctum" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/clock" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/console" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/css-selector" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/deprecation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/error-handler" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/event-dispatcher-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/filesystem" />
<path value="$PROJECT_DIR$/backend/vendor/mtdowling/jmespath.php" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/ai" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-sdk-php" />
<path value="$PROJECT_DIR$/backend/vendor/aws/aws-crt-php" />
<path value="$PROJECT_DIR$/backend/vendor/laravel/fortify" />
<path value="$PROJECT_DIR$/backend/vendor/dasprid/enum" />
<path value="$PROJECT_DIR$/backend/vendor/paragonie/constant_time_encoding" />
<path value="$PROJECT_DIR$/backend/vendor/pragmarx/google2fa" />
<path value="$PROJECT_DIR$/backend/vendor/bacon/bacon-qr-code" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/finder" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-foundation" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/http-kernel" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mailer" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/mime" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-ctype" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-grapheme" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-idn" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-intl-normalizer" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-mbstring" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php80" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php84" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-php85" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/polyfill-uuid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/process" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/routing" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/service-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/string" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/translation-contracts" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/uid" />
<path value="$PROJECT_DIR$/backend/vendor/symfony/var-dumper" />
<path value="$PROJECT_DIR$/backend/vendor/ta-tikoma/phpunit-architecture-test" />
<path value="$PROJECT_DIR$/backend/vendor/theseer/tokenizer" />
<path value="$PROJECT_DIR$/backend/vendor/tijsverkoyen/css-to-inline-styles" />
<path value="$PROJECT_DIR$/backend/vendor/vlucas/phpdotenv" />
<path value="$PROJECT_DIR$/backend/vendor/voku/portable-ascii" />
<path value="$PROJECT_DIR$/backend/vendor/webmozart/assert" />
</include_path>
</component>
<component name="PhpProjectSharedConfiguration" php_language_level="8.3">
<option name="suggestChangeDefaultLanguageLevel" value="false" />
</component>
<component name="PhpStan">
<PhpStan_settings>
<phpstan_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="60000" />
</PhpStan_settings>
</component>
<component name="PhpStanOptionsConfiguration">
<option name="transferred" value="true" />
</component>
@ -166,6 +179,11 @@
<PhpUnitSettings configuration_file_path="$PROJECT_DIR$/backend/phpunit.xml" custom_loader_path="$PROJECT_DIR$/backend/vendor/autoload.php" paratest_path="$PROJECT_DIR$/backend/vendor/bin/paratest_for_phpstorm" use_configuration_file="true" />
</phpunit_settings>
</component>
<component name="Psalm">
<Psalm_settings>
<psalm_fixer_by_interpreter asDefaultInterpreter="true" interpreter_id="ce695bc7-773a-489c-8c49-3627cdd86679" timeout="60000" />
</Psalm_settings>
</component>
<component name="PsalmOptionsConfiguration">
<option name="transferred" value="true" />
</component>

1
backend/.gitignore vendored
View File

@ -24,3 +24,4 @@ _ide_helper.php
Homestead.json
Homestead.yaml
Thumbs.db
.idea/

View File

@ -3,19 +3,17 @@
namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable;
use Stringable;
#[Provider(Lab::Groq)]
class ContentWriterAgent implements Agent, Conversational, HasTools
class ContentWriterAgent implements Agent, Conversational
{
use Promptable;
use Promptable, RemembersConversations;
/**
* Get the instructions that the agent should follow.
@ -53,24 +51,4 @@ public function instructions(): Stringable|string
- Do not include a platform label (e.g. "For Instagram:").
INSTRUCTIONS;
}
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
}

View File

@ -3,19 +3,17 @@
namespace App\Ai\Agents;
use Laravel\Ai\Attributes\Provider;
use Laravel\Ai\Concerns\RemembersConversations;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\Conversational;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Enums\Lab;
use Laravel\Ai\Messages\Message;
use Laravel\Ai\Promptable;
use Stringable;
#[Provider(Lab::Groq)]
class CreativeDirectorAgent implements Agent, Conversational, HasTools
class CreativeDirectorAgent implements Agent, Conversational
{
use Promptable;
use Promptable, RemembersConversations;
/**
* Get the instructions that the agent should follow.
@ -27,24 +25,4 @@ public function instructions(): Stringable|string
'AI image generator. The scene must be visually compelling and directly '.
"relevant to the post's topic. Return ONLY the image prompt — nothing else.";
}
/**
* Get the list of messages comprising the conversation so far.
*
* @return Message[]
*/
public function messages(): iterable
{
return [];
}
/**
* Get the tools available to the agent.
*
* @return Tool[]
*/
public function tools(): iterable
{
return [];
}
}

View File

@ -5,7 +5,7 @@
use App\Actions\Chats\CreateChatAction;
use App\Http\Requests\CreateChatRequest;
use App\Http\Resources\ChatResponseResource;
use Illuminate\Http\Request;
use App\Models\Chat;
class ChatController extends Controller
{
@ -14,7 +14,7 @@ public function index(Request $request) {}
public function store(CreateChatRequest $request, CreateChatAction $createChatAction)
{
return new ChatResponseResource(
$createChatAction->create($request->user(), $request->input('title', null))
$createChatAction->create($request->user(), $request->input('title', 'New Chat'))
);
}
}

View File

@ -6,9 +6,12 @@
use App\Http\Resources\GeneratedPostResource;
use App\Models\Chat;
use App\Services\SocialMediaService;
use Illuminate\Http\Request;
use Illuminate\Routing\Attributes\Controllers\Authorize;
class ChatMessageController extends Controller
{
#[Authorize('update', 'chat')]
public function store(GeneratePostRequest $request, Chat $chat, SocialMediaService $socialMediaService)
{
return new GeneratedPostResource(

View File

@ -3,20 +3,25 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable(['user_id', 'title'])]
#[Table('agent_conversations')]
class Chat extends Model
{
use HasUuids;
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
return $this->belongsTo(User::class, 'user_id');
}
public function messages(): HasMany
{
return $this->hasMany(ChatMessage::class);
return $this->hasMany(ChatMessage::class, 'conversation_id', 'id')->orderBy('created_at', 'asc');
}
}

View File

@ -3,14 +3,19 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Table;
use Illuminate\Database\Eloquent\Concerns\HasUuids;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[Fillable(['chat_id', 'role', 'content', 'user_id'])]
#[Fillable(['conversation_id', 'agent_id', 'role', 'content', 'attachment', 'tool_calls', 'tool_results', 'usage', 'meta', 'content', 'user_id'])]
#[Table('agent_conversation_messages')]
class ChatMessage extends Model
{
use HasUuids;
public function chat(): BelongsTo
{
return $this->belongsTo(Chat::class);
return $this->belongsTo(Chat::class, 'conversation_id', 'id');
}
}

View File

@ -0,0 +1,47 @@
<?php
namespace App\Policies;
use App\Models\Chat;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class ChatPolicy
{
use HandlesAuthorization;
public function viewAny(User $user): bool
{
return false;
}
public function view(User $user, Chat $chat): bool
{
return $chat->user()->is($user);
}
public function create(User $user): bool
{
return false;
}
public function update(User $user, Chat $chat): bool
{
return $chat->user()->is($user);
}
public function delete(User $user, Chat $chat): bool
{
return false;
}
public function restore(User $user, Chat $chat): bool
{
return false;
}
public function forceDelete(User $user, Chat $chat): bool
{
return false;
}
}

View File

@ -6,9 +6,7 @@
use App\Ai\Agents\ContentWriterAgent;
use App\Ai\Agents\CreativeDirectorAgent;
use App\Data\SocialMediaPostResponseDto;
use App\Enums\Chats\ChatRoles;
use App\Models\Chat;
use App\Models\ChatMessage;
readonly class SocialMediaService
{
@ -25,17 +23,13 @@ public function __construct(
*/
public function generatePostWithImage(string $prompt, Chat $chat): SocialMediaPostResponseDto
{
$this->chatMessage->store($chat, ChatRoles::USER, $prompt);
$socialMediaResponse = $this->contentWriterAgent->prompt($prompt);
$socialMediaResponse = $this->contentWriterAgent->forUser($chat->user)->prompt($prompt);
$postText = $socialMediaResponse->text;
/* @var ChatMessage $aiChat */
$aiChat = $this->chatMessage->store($chat, ChatRoles::AI, $postText);
// Generate image prompt via creative director agent
$imagePromptResponse = $this->creativeDirectorAgent->prompt($postText);
$imagePrompt = $imagePromptResponse->text;
return new SocialMediaPostResponseDto($aiChat->id, $postText, $imagePrompt, now());
return new SocialMediaPostResponseDto($socialMediaResponse->conversationId, $postText, $imagePrompt, now());
}
}

View File

@ -1,30 +0,0 @@
<?php
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chats', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(User::class, 'user_id')->constrained()->cascadeOnDelete();
$table->string('title')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chats');
}
};

View File

@ -1,31 +0,0 @@
<?php
use App\Models\Chat;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('chat_messages', function (Blueprint $table) {
$table->id();
$table->foreignIdFor(Chat::class, 'chat_id')->constrained()->cascadeOnDelete();
$table->string('role');
$table->text('content');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('chat_messages');
}
};

View File

@ -3,10 +3,14 @@ import { Routes } from '@angular/router';
export const routes: Routes = [
{
path: '',
loadComponent: () => import('./chat/chat').then(m => m.Chat)
loadComponent: () => import('./chat/chat').then((m) => m.Chat),
},
{
path: ':id',
loadComponent: () => import('./chat/chat').then((m) => m.Chat),
},
{
path: 'user',
loadChildren: () => import('./auth/auth.routes').then(m => m.authRoutes)
}
loadChildren: () => import('./auth/auth.routes').then((m) => m.authRoutes),
},
];

View File

@ -4,6 +4,7 @@ import { HttpErrorResponse } from '@angular/common/http';
import { ChatService } from './chat-service';
import { ChatState, Message } from './chat.types';
import { lastValueFrom } from 'rxjs';
import { Router } from '@angular/router';
const initialState: ChatState = {
messages: [
@ -23,12 +24,16 @@ export const ChatStore = signalStore(
withState(initialState),
withMethods((store) => {
const chatService = inject(ChatService);
const router = inject(Router);
const newChat = async () => {
try {
const response = await lastValueFrom(chatService.newChat());
patchState(store, { id: response.data.id });
return response.data.id;
const chatId = response.data.id;
patchState(store, { id: chatId });
await router.navigate(['/', chatId], { replaceUrl: true });
return chatId;
} catch (error) {
console.error('Failed to create a new chat:', error);
throw error;
@ -37,7 +42,9 @@ export const ChatStore = signalStore(
return {
newChat,
setChatId: (chatId: string) => {
patchState(store, { id: chatId });
},
sendMessage: async (content: string) => {
if (!store.id()) {
try {

View File

@ -2,16 +2,18 @@ import { Component, ElementRef, ViewChild, effect, inject } from '@angular/core'
import { CommonModule } from '@angular/common';
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { ChatStore } from './chat.store';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-chat',
standalone: true,
imports: [CommonModule, ReactiveFormsModule],
templateUrl: './chat.html',
styleUrl: './chat.css'
styleUrl: './chat.css',
})
export class Chat {
readonly chatStore = inject(ChatStore);
private route = inject(ActivatedRoute);
@ViewChild('scrollContainer') private scrollContainer!: ElementRef;
@ -30,6 +32,16 @@ export class Chat {
});
}
ngOnInit() {
this.route.paramMap.subscribe((params) => {
const urlId = params.get('id');
if (urlId) {
// If an ID exists in the URL, populate it in the store
this.chatStore.setChatId(urlId);
}
});
}
errorMessage = '';
sendMessage() {