From 91ae61185f97feabc8e3ffe9b1d3088cd487d17c Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sun, 4 Jan 2026 21:41:42 +0800 Subject: [PATCH] 1688 PO Automation Project --- .../Filters/{ChatgptPrompt.php => Prompt.php} | 10 +- ...TLPurchaseOrderTransactionV2CommandJob.php | 2 +- .../Services/CreatesClaudeResponse.php | 62 ++++++ .../CreatesClaudeResponseWithFiles.php | 67 +++++++ .../Anthropic/Services/UploadsClaudeFiles.php | 57 ++++++ .../CreateClaudePromptKVPLogic.php | 68 +++++++ .../DeleteClaudePromptKVPLogic.php | 69 +++++++ ...KVPLogic.php => ListAiPromptsKVPLogic.php} | 24 +-- .../UpdateClaudePromptKVPLogic.php | 69 +++++++ .../CreateClaudePromptDTO.php | 36 ++++ .../UpdateClaudePromptDTO.php | 44 +++++ .../Standards/Rules/CanCreateClaudePrompt.php | 56 ++++++ .../Standards/Rules/CanDeleteClaudePrompt.php | 43 +++++ ...hatGPTPrompts.php => CanListAiPrompts.php} | 2 +- .../Standards/Rules/CanUpdateClaudePrompt.php | 58 ++++++ .../CreateClaudePromptValidation.php | 41 ++++ .../UpdateClaudePromptValidation.php | 40 ++++ .../ETLPurchaseOrderTransactionLogic.php | 17 +- .../ImportPurchaseOrderTransactionLogic.php | 15 +- ...> ETLPDFPurchaseOrderChatGPTProcessor.php} | 5 +- .../ETLPDFPurchaseOrderClaudeProcessor.php | 177 ++++++++++++++++++ .../ETLPurchaseOrderTransactionProcessor.php | 21 ++- app/Classes/ValueObjects/Constants/KVPKey.php | 2 +- .../CreateClaudePromptKVPController.php | 21 +++ .../DeleteClaudePromptKVPController.php | 21 +++ .../ListAiPromptsKVPController.php | 21 +++ .../ListChatGPTPromptsKVPController.php | 21 --- .../UpdateClaudePromptKVPController.php | 21 +++ app/Http/Resources/ClaudePromptResource.php | 26 +++ config/anthropic.php | 8 + config/openai.php | 2 +- ...omponent.vue => SinglePromptComponent.vue} | 35 +++- .../settings/forms/AiPromptFormComponent.vue | 143 ++++++++++++++ .../settings/forms/ChatGptFormComponent.vue | 83 -------- .../forms/DeleteChatGptFormComponent.vue | 2 +- .../forms/DeleteClaudeFormComponent.vue | 32 ++++ resources/views/pages/settings.blade.php | 12 +- routes/key_value_pair.php | 18 +- 38 files changed, 1282 insertions(+), 169 deletions(-) rename app/Classes/General/Eloquent/Filters/{ChatgptPrompt.php => Prompt.php} (54%) create mode 100644 app/Classes/Modules/Anthropic/Services/CreatesClaudeResponse.php create mode 100644 app/Classes/Modules/Anthropic/Services/CreatesClaudeResponseWithFiles.php create mode 100644 app/Classes/Modules/Anthropic/Services/UploadsClaudeFiles.php create mode 100644 app/Classes/Modules/KeyValuePairs/ControllersLogic/CreateClaudePromptKVPLogic.php create mode 100644 app/Classes/Modules/KeyValuePairs/ControllersLogic/DeleteClaudePromptKVPLogic.php rename app/Classes/Modules/KeyValuePairs/ControllersLogic/{ListChatGPTPromptsKVPLogic.php => ListAiPromptsKVPLogic.php} (65%) create mode 100644 app/Classes/Modules/KeyValuePairs/ControllersLogic/UpdateClaudePromptKVPLogic.php create mode 100644 app/Classes/Modules/KeyValuePairs/DataTransferObjects/CreateClaudePromptDTO.php create mode 100644 app/Classes/Modules/KeyValuePairs/DataTransferObjects/UpdateClaudePromptDTO.php create mode 100644 app/Classes/Modules/KeyValuePairs/Standards/Rules/CanCreateClaudePrompt.php create mode 100644 app/Classes/Modules/KeyValuePairs/Standards/Rules/CanDeleteClaudePrompt.php rename app/Classes/Modules/KeyValuePairs/Standards/Rules/{CanListChatGPTPrompts.php => CanListAiPrompts.php} (93%) create mode 100644 app/Classes/Modules/KeyValuePairs/Standards/Rules/CanUpdateClaudePrompt.php create mode 100644 app/Classes/Modules/KeyValuePairs/Standards/Validators/CreateClaudePromptValidation.php create mode 100644 app/Classes/Modules/KeyValuePairs/Standards/Validators/UpdateClaudePromptValidation.php rename app/Classes/Modules/Transactions/Processors/{ETLPDFPurchaseOrderTransactionProcessor.php => ETLPDFPurchaseOrderChatGPTProcessor.php} (98%) create mode 100644 app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderClaudeProcessor.php create mode 100644 app/Http/Controllers/KeyValuePairs/CreateClaudePromptKVPController.php create mode 100644 app/Http/Controllers/KeyValuePairs/DeleteClaudePromptKVPController.php create mode 100644 app/Http/Controllers/KeyValuePairs/ListAiPromptsKVPController.php delete mode 100644 app/Http/Controllers/KeyValuePairs/ListChatGPTPromptsKVPController.php create mode 100644 app/Http/Controllers/KeyValuePairs/UpdateClaudePromptKVPController.php create mode 100644 app/Http/Resources/ClaudePromptResource.php create mode 100644 config/anthropic.php rename resources/assets/vue/components/settings/elements/{SingleChatGptPromptComponent.vue => SinglePromptComponent.vue} (61%) create mode 100644 resources/assets/vue/components/settings/forms/AiPromptFormComponent.vue delete mode 100644 resources/assets/vue/components/settings/forms/ChatGptFormComponent.vue create mode 100644 resources/assets/vue/components/settings/forms/DeleteClaudeFormComponent.vue diff --git a/app/Classes/General/Eloquent/Filters/ChatgptPrompt.php b/app/Classes/General/Eloquent/Filters/Prompt.php similarity index 54% rename from app/Classes/General/Eloquent/Filters/ChatgptPrompt.php rename to app/Classes/General/Eloquent/Filters/Prompt.php index 034319a1..b36ea501 100644 --- a/app/Classes/General/Eloquent/Filters/ChatgptPrompt.php +++ b/app/Classes/General/Eloquent/Filters/Prompt.php @@ -6,16 +6,12 @@ namespace App\Classes\General\Eloquent\Filters; use App\Classes\ValueObjects\Constants\KVPKey; use Illuminate\Database\Eloquent\Builder; -class ChatgptPrompt implements Filter +class Prompt implements Filter { public static function apply(Builder $builder, $value) { - return $builder->where( - 'key', - 'LIKE', - KVPKey::CHATGPT_PROMPT_PREFIX . '%' - ); + return $builder->where('key', 'LIKE', KVPKey::CHATGPT_PROMPT_PREFIX . '%') + ->orWhere('key', 'LIKE', KVPKey::CLAUDE_PROMPT_PREFIX . '%'); } } - diff --git a/app/Classes/Jobs/Commands/V2/ETLPurchaseOrderTransactionV2CommandJob.php b/app/Classes/Jobs/Commands/V2/ETLPurchaseOrderTransactionV2CommandJob.php index 19f6faa6..350faeea 100644 --- a/app/Classes/Jobs/Commands/V2/ETLPurchaseOrderTransactionV2CommandJob.php +++ b/app/Classes/Jobs/Commands/V2/ETLPurchaseOrderTransactionV2CommandJob.php @@ -42,7 +42,7 @@ class ETLPurchaseOrderTransactionV2CommandJob implements ShouldQueue Log::info(Carbon::now() . ': Start job - ETL Purchase Order Transaction.'); $start = new Carbon(); - (App()->make(ETLPurchaseOrderTransactionProcessor::class))->execute($this->products, $this->productsMetadata, $this->bookingId); + // (App()->make(ETLPurchaseOrderTransactionProcessor::class))->execute($this->products, $this->productsMetadata, $this->bookingId); $end = new Carbon(); $elapsedTime = $start->diff($end)->format('%H:%I:%S'); diff --git a/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponse.php b/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponse.php new file mode 100644 index 00000000..2d89daa3 --- /dev/null +++ b/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponse.php @@ -0,0 +1,62 @@ + $modelId, + 'messages' => [ + [ + 'role' => 'user', + 'content' => $userPrompt + ] + ] + ]; + + $response = Http::withHeaders([ + 'x-api-key' => config('anthropic.api_key'), + 'anthropic-version' => config('anthropic.api_version', '2023-06-01'), + ])->post(config('anthropic.base_url') . '/v1/messages', $data); + + if ($response->successful()) { + return (object) $response->json(); + } else { + Log::info('CreatesClaudeResponse error: ' . $response->body()); + return null; + } + } + catch (\Illuminate\Http\Client\ConnectionException $exception) { + Log::info('ConnectionException' . json_encode($exception)); + throw new ConnectionErrorException( + 'Failed to connect to Claude API', + $exception->getMessage(), + $userPrompt, + $exception->getTraceAsString() + ); + } + catch (\Exception $exception) { + Log::info('Exception' . json_encode($exception)); + throw new MalformedRequestException( + 'Unable to get correct response from Claude API: ' . $exception->getMessage() + ); + } + } +} diff --git a/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponseWithFiles.php b/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponseWithFiles.php new file mode 100644 index 00000000..0ffecef6 --- /dev/null +++ b/app/Classes/Modules/Anthropic/Services/CreatesClaudeResponseWithFiles.php @@ -0,0 +1,67 @@ + 'text', + 'text' => $userPrompt, + ]; + + // Attach files + foreach ($fileIds as $fileId) { + $content[] = [ + 'type' => 'document', + 'source' => [ + 'type' => 'file', + 'file_id' => $fileId, + ], + ]; + } + + $response = Http::withHeaders([ + 'x-api-key' => config('anthropic.api_key'), + 'anthropic-version' => config('anthropic.api_version', '2023-06-01'), + 'anthropic-beta' => 'files-api-2025-04-14', + 'Content-Type' => 'application/json', + ])->post(config('anthropic.base_url') . '/v1/messages', [ + 'model' => config('anthropic.default_model', 'claude-sonnet-4-5-20250929'), + 'max_tokens' => 1024, + 'messages' => [ + [ + 'role' => 'user', + 'content' => $content, + ], + ], + ]); + + return $response->json(); + } + catch (\Illuminate\Http\Client\ConnectionException $exception) { + $error = 'Failed to connect to Claude API'; + throw new ConnectionErrorException( + $error, + $exception->getMessage(), + $userPrompt, + $exception->getTraceAsString() + ); + } + catch (\Exception $exception) { + throw new MalformedRequestException( + 'Unable to get correct response from Claude API: ' . $exception->getMessage() + ); + } + } +} diff --git a/app/Classes/Modules/Anthropic/Services/UploadsClaudeFiles.php b/app/Classes/Modules/Anthropic/Services/UploadsClaudeFiles.php new file mode 100644 index 00000000..995ff325 --- /dev/null +++ b/app/Classes/Modules/Anthropic/Services/UploadsClaudeFiles.php @@ -0,0 +1,57 @@ + config('anthropic.api_key'), + 'anthropic-version' => '2023-06-01', + 'anthropic-beta' => 'files-api-2025-04-14', + ])->attach( + 'file', + fopen($path, 'r'), + basename($path) + )->post(config('anthropic.base_url') . '/v1/files'); + + $data = $response->json(); + + if ($response->successful() && isset($data['id'])) { + $ids[] = $data['id']; + } else { + Log::error('Claude file upload failed', [ + 'path' => $path, + 'response' => $data, + ]); + } + } + + return $ids; + } + catch (\Illuminate\Http\Client\ConnectionException $exception) { + $error = 'Failed to connect to Claude API'; + throw new ConnectionErrorException( + $error, + $exception->getMessage(), + $exception->getTraceAsString() + ); + } + catch (\Exception $exception) { + throw new MalformedRequestException( + 'Unable to get correct response from Claude API: ' . $exception->getMessage() + ); + } + } +} diff --git a/app/Classes/Modules/KeyValuePairs/ControllersLogic/CreateClaudePromptKVPLogic.php b/app/Classes/Modules/KeyValuePairs/ControllersLogic/CreateClaudePromptKVPLogic.php new file mode 100644 index 00000000..940b9f8e --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/ControllersLogic/CreateClaudePromptKVPLogic.php @@ -0,0 +1,68 @@ + 'Created Claude Prompt', + 'message' => 'You have successfully created a new Claude Prompt' + ]; + } + + /** @var CanCreateClaudePrompt */ + private $canCreateClaudePrompt; + + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + + /** + * CreateClaudePromptKVPLogic constructor. + * @param CanCreateClaudePrompt $canCreateClaudePrompt + * @param CreatesKeyValuePair $createsKeyValuePair + */ + public function __construct( + CanCreateClaudePrompt $canCreateClaudePrompt, + CreatesKeyValuePair $createsKeyValuePair + ) { + $this->canCreateClaudePrompt = $canCreateClaudePrompt; + $this->createsKeyValuePair = $createsKeyValuePair; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request): JsonResponse + { + $dto = new CreateClaudePromptDTO($request->all()); + + $this->canCreateClaudePrompt->passes($dto); + + $key = KVPKey::CLAUDE_PROMPT_PREFIX . strtoupper(str_replace(' ', '_', $dto->getTitle())); + $keyValuePairObject = new KeyValuePairObject($key, $dto->getPrompt()); + + $kvp = $this->createsKeyValuePair->execute(null, $keyValuePairObject); + + return $this->resourceResponse(new ClaudePromptResource($kvp)); + } +} diff --git a/app/Classes/Modules/KeyValuePairs/ControllersLogic/DeleteClaudePromptKVPLogic.php b/app/Classes/Modules/KeyValuePairs/ControllersLogic/DeleteClaudePromptKVPLogic.php new file mode 100644 index 00000000..b61b11b9 --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/ControllersLogic/DeleteClaudePromptKVPLogic.php @@ -0,0 +1,69 @@ + 'Delete Claude Prompt', + 'message' => 'You have successfully deleted the Claude Prompt' + ]; + } + + /** @var CanDeleteClaudePrompt */ + private $canDeleteClaudePrompt; + + /** @var FetchesKeyValuePair */ + private $fetchesKeyValuePair; + + /** @var DeletesKeyValuePair */ + private $deletesKeyValuePair; + + /** + * DeleteClaudePromptKVPLogic constructor. + * @param CanDeleteClaudePrompt $canDeleteClaudePrompt + * @param FetchesKeyValuePair $fetchesKeyValuePair + * @param DeletesKeyValuePair $deletesKeyValuePair + */ + public function __construct( + CanDeleteClaudePrompt $canDeleteClaudePrompt, + FetchesKeyValuePair $fetchesKeyValuePair, + DeletesKeyValuePair $deletesKeyValuePair + ) { + $this->canDeleteClaudePrompt = $canDeleteClaudePrompt; + $this->fetchesKeyValuePair = $fetchesKeyValuePair; + $this->deletesKeyValuePair = $deletesKeyValuePair; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request): JsonResponse + { + $this->canDeleteClaudePrompt->passes(); + + $kvp = $this->fetchesKeyValuePair->execute(['id' => $request->route('id')]); + + $this->deletesKeyValuePair->execute($kvp); + + return $this->response([]); + } +} diff --git a/app/Classes/Modules/KeyValuePairs/ControllersLogic/ListChatGPTPromptsKVPLogic.php b/app/Classes/Modules/KeyValuePairs/ControllersLogic/ListAiPromptsKVPLogic.php similarity index 65% rename from app/Classes/Modules/KeyValuePairs/ControllersLogic/ListChatGPTPromptsKVPLogic.php rename to app/Classes/Modules/KeyValuePairs/ControllersLogic/ListAiPromptsKVPLogic.php index 54f94196..bc6ab11f 100644 --- a/app/Classes/Modules/KeyValuePairs/ControllersLogic/ListChatGPTPromptsKVPLogic.php +++ b/app/Classes/Modules/KeyValuePairs/ControllersLogic/ListAiPromptsKVPLogic.php @@ -5,12 +5,12 @@ namespace App\Classes\Modules\KeyValuePairs\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\KeyValuePairs\Services\ListsKeyValuePairs; -use App\Classes\Modules\KeyValuePairs\Standards\Rules\CanListChatGPTPrompts; +use App\Classes\Modules\KeyValuePairs\Standards\Rules\CanListAiPrompts; use App\Http\Resources\ChatGPTPromptResource; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -class ListChatGPTPromptsKVPLogic extends AbstractControllerLogic +class ListAiPromptsKVPLogic extends AbstractControllerLogic { /** @@ -19,25 +19,25 @@ class ListChatGPTPromptsKVPLogic extends AbstractControllerLogic protected function notification(): array { return [ - 'title' => 'Retrieve ChatGPT Prompts', - 'message' => 'You have successfully retrieved a list of ChatGPT Prompts' + 'title' => 'Retrieve Prompts', + 'message' => 'You have successfully retrieved a list of Prompts' ]; } - /** @var CanListChatGPTPrompts */ - private $canListChatGPTPrompts; + /** @var CanListAiPrompts */ + private $canListAiPrompts; /** @var ListsKeyValuePairs */ private $listsKeyValuePairs; /** - * ListChatGPTPromptsKVPLogic constructor. - * @param CanListChatGPTPrompts $canListChatGPTPrompts + * ListAiPromptsKVPLogic constructor. + * @param CanListAiPrompts $canListAiPrompts * @param ListsKeyValuePairs $listsKeyValuePairs */ - public function __construct(CanListChatGPTPrompts $canListChatGPTPrompts, ListsKeyValuePairs $listsKeyValuePairs) + public function __construct(CanListAiPrompts $canListAiPrompts, ListsKeyValuePairs $listsKeyValuePairs) { - $this->canListChatGPTPrompts = $canListChatGPTPrompts; + $this->canListAiPrompts = $canListAiPrompts; $this->listsKeyValuePairs = $listsKeyValuePairs; } @@ -51,9 +51,9 @@ class ListChatGPTPromptsKVPLogic extends AbstractControllerLogic */ public function logic(Request $request): JsonResponse { - $this->canListChatGPTPrompts->passes(); + $this->canListAiPrompts->passes(); - $prompts = $this->listsKeyValuePairs->execute(array_merge($this->listsKeyValuePairs->deserializeFilters($request->input('filters')), ['chatgpt_prompt' => false])); + $prompts = $this->listsKeyValuePairs->execute(array_merge($this->listsKeyValuePairs->deserializeFilters($request->input('filters')), ['prompt' => false])); return $this->collectionResponse(ChatGPTPromptResource::collection($prompts)); } diff --git a/app/Classes/Modules/KeyValuePairs/ControllersLogic/UpdateClaudePromptKVPLogic.php b/app/Classes/Modules/KeyValuePairs/ControllersLogic/UpdateClaudePromptKVPLogic.php new file mode 100644 index 00000000..a1fde651 --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/ControllersLogic/UpdateClaudePromptKVPLogic.php @@ -0,0 +1,69 @@ + 'Update Claude Prompt', + 'message' => 'You have successfully updated the Claude prompt' + ]; + } + + /** @var CanUpdateClaudePrompt */ + private $canUpdateClaudePrompt; + + /** @var UpdatesKeyValuePair */ + private $updatesKeyValuePair; + + /** @var FetchesKeyValuePair */ + private $fetchesKeyValuePair; + + /** + * UpdateClaudePromptKVPLogic constructor. + * @param CanUpdateClaudePrompt $canUpdateClaudePrompt + * @param UpdatesKeyValuePair $updatesKeyValuePair + * @param FetchesKeyValuePair $fetchesKeyValuePair + */ + public function __construct(CanUpdateClaudePrompt $canUpdateClaudePrompt, UpdatesKeyValuePair $updatesKeyValuePair, FetchesKeyValuePair $fetchesKeyValuePair) + { + $this->canUpdateClaudePrompt = $canUpdateClaudePrompt; + $this->updatesKeyValuePair = $updatesKeyValuePair; + $this->fetchesKeyValuePair = $fetchesKeyValuePair; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + $dto = new UpdateClaudePromptDTO($request->all()); + $this->canUpdateClaudePrompt->passes($dto); + + $kvp = $this->fetchesKeyValuePair->execute(['id' => $dto->getId()]); + $keyValuePairObject = new KeyValuePairObject($kvp->key, $dto->getPrompt()); + $this->updatesKeyValuePair->execute($kvp, $keyValuePairObject); + + return $this->resourceResponse(new ClaudePromptResource($kvp)); + } +} diff --git a/app/Classes/Modules/KeyValuePairs/DataTransferObjects/CreateClaudePromptDTO.php b/app/Classes/Modules/KeyValuePairs/DataTransferObjects/CreateClaudePromptDTO.php new file mode 100644 index 00000000..cddd5418 --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/DataTransferObjects/CreateClaudePromptDTO.php @@ -0,0 +1,36 @@ +title = (string) ($data['key'] ?? ''); + $this->prompt = (string) ($data['value'] ?? ''); + } + + public function toArray(): array + { + return [ + 'title' => $this->title, + 'prompt' => $this->prompt, + ]; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getPrompt(): string + { + return $this->prompt; + } +} diff --git a/app/Classes/Modules/KeyValuePairs/DataTransferObjects/UpdateClaudePromptDTO.php b/app/Classes/Modules/KeyValuePairs/DataTransferObjects/UpdateClaudePromptDTO.php new file mode 100644 index 00000000..0bb98daa --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/DataTransferObjects/UpdateClaudePromptDTO.php @@ -0,0 +1,44 @@ +id = (int) ($data['id'] ?? 0); + $this->title = (string) ($data['key'] ?? ''); + $this->prompt = (string) ($data['value'] ?? ''); + } + + public function toArray(): array + { + return [ + 'id' => $this->id, + 'title' => $this->title, + 'prompt' => $this->prompt, + ]; + } + + public function getId(): int + { + return $this->id; + } + + public function getTitle(): string + { + return $this->title; + } + + public function getPrompt(): string + { + return $this->prompt; + } +} diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanCreateClaudePrompt.php b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanCreateClaudePrompt.php new file mode 100644 index 00000000..b9c6ec5c --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanCreateClaudePrompt.php @@ -0,0 +1,56 @@ +validation = $validation; + } + + /** + * @return bool + */ + protected function authorized($object): bool + { + if (in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)) { + return true; + } + return false; + } + + /** + * @param CreateClaudePromptDTO $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->validation->validate($object); + } + + /** + * @param CreateChatGPTPromptDTO $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } +} diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanDeleteClaudePrompt.php b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanDeleteClaudePrompt.php new file mode 100644 index 00000000..7d534242 --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanDeleteClaudePrompt.php @@ -0,0 +1,43 @@ +type, RoleTypes::ADMIN_ROLES)) { + return true; + } + return false; + } + + /** + * @param $object + * @return bool + */ + protected function validators($object): bool + { + return true; + + } + + + /** + * @param $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListChatGPTPrompts.php b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListAiPrompts.php similarity index 93% rename from app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListChatGPTPrompts.php rename to app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListAiPrompts.php index ace670a9..9eabb19e 100644 --- a/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListChatGPTPrompts.php +++ b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanListAiPrompts.php @@ -7,7 +7,7 @@ use App\Classes\General\Abstracts\AbstractRule; use App\Classes\ValueObjects\Constants\RoleTypes; use Illuminate\Support\Facades\Auth; -class CanListChatGPTPrompts extends AbstractRule +class CanListAiPrompts extends AbstractRule { /** diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanUpdateClaudePrompt.php b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanUpdateClaudePrompt.php new file mode 100644 index 00000000..46f980df --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/Standards/Rules/CanUpdateClaudePrompt.php @@ -0,0 +1,58 @@ +validation = $validation; + } + + /** + * @return bool + */ + protected function authorized($object): bool + { + if (in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)) { + return true; + } + return false; + } + + /** + * @param UpdateClaudePromptDTO $object + * @return bool + * @throws \App\Classes\Exceptions\RequestValidationException + */ + protected function validators($object): bool + { + return $this->validation->validate($object); + } + + /** + * @param UpdateClaudePromptDTO $object + * @return bool + */ + protected function criteria($object): bool + { + return true; + } + +} diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Validators/CreateClaudePromptValidation.php b/app/Classes/Modules/KeyValuePairs/Standards/Validators/CreateClaudePromptValidation.php new file mode 100644 index 00000000..e7176039 --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/Standards/Validators/CreateClaudePromptValidation.php @@ -0,0 +1,41 @@ + $object->getTitle(), + 'prompt' => $object->getPrompt(), + ]; + } + + /** + * @return array + */ + protected function rules(): array + { + return [ + 'title' => 'required', + 'prompt' => 'required', + ]; + } + + /** + * @return array + */ + protected function messages(): array + { + return []; + } +} diff --git a/app/Classes/Modules/KeyValuePairs/Standards/Validators/UpdateClaudePromptValidation.php b/app/Classes/Modules/KeyValuePairs/Standards/Validators/UpdateClaudePromptValidation.php new file mode 100644 index 00000000..1608123e --- /dev/null +++ b/app/Classes/Modules/KeyValuePairs/Standards/Validators/UpdateClaudePromptValidation.php @@ -0,0 +1,40 @@ + $object->getTitle(), + 'prompt' => $object->getPrompt(), + ]; + } + + /** + * @return array + */ + protected function rules(): array + { + return [ + 'prompt' => 'required', + ]; + } + + /** + * @return array + */ + protected function messages(): array + { + return []; + } +} diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ETLPurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ETLPurchaseOrderTransactionLogic.php index a43895cc..3d44b84b 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/ETLPurchaseOrderTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/ETLPurchaseOrderTransactionLogic.php @@ -3,11 +3,9 @@ namespace App\Classes\Modules\Transactions\ControllersLogic; -use App\Classes\Exceptions\InternalServerErrorException; use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Transactions\Processors\ETLPDFPurchaseOrderTransactionProcessor; +use App\Classes\Modules\Transactions\Processors\ETLPDFPurchaseOrderClaudeProcessor; use App\Classes\Modules\Transactions\Standards\Rules\CanETLPurchaseOrder; -use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -29,18 +27,18 @@ class ETLPurchaseOrderTransactionLogic extends AbstractControllerLogic /** @var CanETLPurchaseOrder */ private $canETLPurchaseOrder; - /** @var ETLPDFPurchaseOrderTransactionProcessor */ - private $etlPDFPurchaseOrderTransactionProcessor; + /** @var ETLPDFPurchaseOrderClaudeProcessor */ + private $eTLPDFPurchaseOrderClaudeProcessor; /** * ETLPurchaseOrderTransactionLogic constructor. * @param CanETLPurchaseOrder $canETLPurchaseOrder - * @param ETLPDFPurchaseOrderTransactionProcessor $etlPDFPurchaseOrderTransactionProcessor + * @param ETLPDFPurchaseOrderClaudeProcessor $eTLPDFPurchaseOrderClaudeProcessor */ - public function __construct(CanETLPurchaseOrder $canETLPurchaseOrder, ETLPDFPurchaseOrderTransactionProcessor $etlPDFPurchaseOrderTransactionProcessor) + public function __construct(CanETLPurchaseOrder $canETLPurchaseOrder, ETLPDFPurchaseOrderClaudeProcessor $eTLPDFPurchaseOrderClaudeProcessor) { $this->canETLPurchaseOrder = $canETLPurchaseOrder; - $this->etlPDFPurchaseOrderTransactionProcessor = $etlPDFPurchaseOrderTransactionProcessor; + $this->eTLPDFPurchaseOrderClaudeProcessor = $eTLPDFPurchaseOrderClaudeProcessor; } /** @@ -62,11 +60,12 @@ class ETLPurchaseOrderTransactionLogic extends AbstractControllerLogic // try{ // $products = $this->etlPDFPurchaseOrderTransactionProcessor->execute($products, $productsMetadata); // } catch (\Exception $exception) { + // Log::info('Exception: ' .json_encode($exception)); // throw new InternalServerErrorException('Something went wrong!'); // } $files = $request->input('files'); - $result = $this->etlPDFPurchaseOrderTransactionProcessor->execute($files); + $result = $this->eTLPDFPurchaseOrderClaudeProcessor->execute($files); return $this->response($result); } } diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php index 15796728..e0dfb081 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php @@ -4,12 +4,11 @@ namespace App\Classes\Modules\Transactions\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Jobs\Commands\V2\ETLPurchaseOrderTransactionV2CommandJob; use App\Classes\Modules\Bookings\Services\FetchesBooking; use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor; -use App\Classes\Modules\Transactions\Processors\ETLPDFPurchaseOrderTransactionProcessor; +use App\Classes\Modules\Transactions\Processors\ETLPDFPurchaseOrderClaudeProcessor; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\Modules\Transactions\Standards\Rules\CanETLPurchaseOrder; use App\Classes\ValueObjects\Constants\ApprovalStatus; @@ -47,8 +46,8 @@ class ImportPurchaseOrderTransactionLogic extends AbstractControllerLogic /** @var CreatePurchaseOrderTransactionProcessor */ private $createPurchaseOrderTransactionProcessor; - /** @var ETLPDFPurchaseOrderTransactionProcessor */ - private $etlPDFPurchaseOrderTransactionProcessor; + /** @var ETLPDFPurchaseOrderClaudeProcessor */ + private $eTLPDFPurchaseOrderClaudeProcessor; /** @var CanETLPurchaseOrder */ private $canETLPurchaseOrder; @@ -58,15 +57,15 @@ class ImportPurchaseOrderTransactionLogic extends AbstractControllerLogic * @param FetchesBooking $fetchesBooking * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor - * @param ETLPDFPurchaseOrderTransactionProcessor $etlPDFPurchaseOrderTransactionProcessor + * @param ETLPDFPurchaseOrderClaudeProcessor $eTLPDFPurchaseOrderClaudeProcessor * @param CanETLPurchaseOrder $canETLPurchaseOrder */ - public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, ETLPDFPurchaseOrderTransactionProcessor $etlPDFPurchaseOrderTransactionProcessor, CanETLPurchaseOrder $canETLPurchaseOrder) + public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, ETLPDFPurchaseOrderClaudeProcessor $eTLPDFPurchaseOrderClaudeProcessor, CanETLPurchaseOrder $canETLPurchaseOrder) { $this->fetchesBooking = $fetchesBooking; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor; - $this->etlPDFPurchaseOrderTransactionProcessor = $etlPDFPurchaseOrderTransactionProcessor; + $this->eTLPDFPurchaseOrderClaudeProcessor = $eTLPDFPurchaseOrderClaudeProcessor; $this->canETLPurchaseOrder = $canETLPurchaseOrder; } @@ -86,7 +85,7 @@ class ImportPurchaseOrderTransactionLogic extends AbstractControllerLogic if(empty($products)){ $files = $request->input('files'); - $products = $this->etlPDFPurchaseOrderTransactionProcessor->execute($files); + $products = $this->eTLPDFPurchaseOrderClaudeProcessor->execute($files); } } else { diff --git a/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderChatGPTProcessor.php similarity index 98% rename from app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderTransactionProcessor.php rename to app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderChatGPTProcessor.php index cc3fb832..d1ce881b 100644 --- a/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderChatGPTProcessor.php @@ -2,6 +2,7 @@ namespace App\Classes\Modules\Transactions\Processors; + use App\Classes\Modules\OpenAI\Services\UploadsOpenAIFiles; use App\Classes\Modules\OpenAI\Services\CreatesChatGPTResponseWithFiles; use App\Classes\Exceptions\ResourceNotFoundException; @@ -19,7 +20,7 @@ use Illuminate\Support\Facades\Log; use Illuminate\Http\UploadedFile; use Illuminate\Support\Facades\Storage; -class ETLPDFPurchaseOrderTransactionProcessor +class ETLPDFPurchaseOrderChatGPTProcessor { /** @var FetchesBooking */ private $fetchesBooking; @@ -37,7 +38,7 @@ class ETLPDFPurchaseOrderTransactionProcessor private $createsChatGPTResponseWithFiles; /** - * ETLPDFPurchaseOrderTransactionProcessor constructor. + * ETLPDFPurchaseOrderChatGPTProcessor constructor. * @param FetchesBooking $fetchesBooking * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor diff --git a/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderClaudeProcessor.php b/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderClaudeProcessor.php new file mode 100644 index 00000000..9c227307 --- /dev/null +++ b/app/Classes/Modules/Transactions/Processors/ETLPDFPurchaseOrderClaudeProcessor.php @@ -0,0 +1,177 @@ +fetchesBooking = $fetchesBooking; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor; + $this->uploadsClaudeFiles = $uploadsClaudeFiles; + $this->createsClaudeResponseWithFiles = $createsClaudeResponseWithFiles; + } + + /** + * @param UploadedFile[] $files + * @param int|null $bookingId + * @return array|null + */ + public function execute(array $files, ?int $bookingId = null): ?array + { + $tempPaths = []; + + try { + foreach ($files as $index => $fileBase64) { + if (preg_match('/^data:application\/pdf;base64,/', $fileBase64)) { + $fileBase64 = preg_replace('/^data:application\/pdf;base64,/', '', $fileBase64); + } + + $fileContent = base64_decode($fileBase64); + if ($fileContent === false) { + Log::warning("Invalid Base64 for file index {$index}"); + continue; + } + + $tempDir = storage_path('app/documents'); + if (!file_exists($tempDir)) { + mkdir($tempDir, 0755, true); + } + + $filePath = $tempDir . '/' . uniqid("file_{$index}_") . '.pdf'; + file_put_contents($filePath, $fileContent); + + $tempPaths[] = $filePath; + } + + Log::info('Claude tempPaths', $tempPaths); + + // Upload PDFs to Claude + $fileIds = $this->uploadsClaudeFiles->execute($tempPaths); + + $kvp = KeyValuePair::where( + 'key', + KVPKey::CLAUDE_PROMPT_PREFIX . 'EXTRACT_1' + )->first(); + + if (!$kvp) { + throw new ResourceNotFoundException('AI Setup incomplete!'); + } + + $userPrompt = $kvp->value; + $response = $this->createsClaudeResponseWithFiles->execute($userPrompt, $fileIds); + + $textContent = $response['content'][0]['text'] ?? '[]'; + + // Strip ```json fences + if (preg_match('/```json\s*(.*?)\s*```/s', $textContent, $matches)) { + $jsonString = $matches[1]; + } else { + $jsonString = $textContent; + } + + $data = json_decode($jsonString, true); + + if (json_last_error() !== JSON_ERROR_NONE) { + Log::error('Failed to decode Claude JSON response', [ + 'error' => json_last_error_msg(), + 'textContent' => $textContent, + ]); + $data = []; + } + + // Normalize keys to snake_case + $data = $this->convertKeysToSnakeCase($data); + + if ($bookingId) { + /** @var Booking $booking */ + $booking = $this->fetchesBooking->execute(['id' => $bookingId]); + + $billNumber = $this->generatesTransactionBillNumber->execute('PO-'); + + $total = collect($data)->sum(function ($product) { + return $product['quantity'] + * floatval(str_replace(',', '', $product['unit_price'])); + }); + + $object = new TransactionObject( + $billNumber, + TransactionType::PURCHASE_ORDER, + $booking->company->id, + 1, + 1, + PaymentMethodType::CASH, + $total, + $total, + $booking->fix_currency_id, + $booking->fix_currency_id, + 1, + 0, + 0, + null, + ApprovalStatus::PENDING_SUBMISSION, + $data + ); + + $this->createPurchaseOrderTransactionProcessor + ->execute($booking, $object); + } + + return $data; + + } catch (\Exception $e) { + Log::error('Error processing PDF files with Claude', [ + 'message' => $e->getMessage(), + 'trace' => $e->getTraceAsString(), + ]); + throw $e; + } finally { + foreach ($tempPaths as $path) { + if (file_exists($path)) { + unlink($path); + } + } + } + } + + private function convertKeysToSnakeCase(array $items): array + { + return array_map(function ($item) { + $newItem = []; + foreach ($item as $key => $value) { + $newKey = strtolower(str_replace(' ', '_', $key)); + $newItem[$newKey] = $value; + } + return $newItem; + }, $items); + } +} diff --git a/app/Classes/Modules/Transactions/Processors/ETLPurchaseOrderTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/ETLPurchaseOrderTransactionProcessor.php index 45592b81..e7169e51 100644 --- a/app/Classes/Modules/Transactions/Processors/ETLPurchaseOrderTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/ETLPurchaseOrderTransactionProcessor.php @@ -4,6 +4,7 @@ namespace App\Classes\Modules\Transactions\Processors; use App\Classes\Exceptions\ResourceNotFoundException; +use App\Classes\Modules\Anthropic\Services\CreatesClaudeResponse; use App\Classes\Modules\Bookings\Services\FetchesBooking; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor; @@ -17,6 +18,7 @@ use App\Models\KeyValuePair; use App\Models\Booking; use Illuminate\Support\Facades\Log; +//This solution has partial dependency on pdf table extractor on front end (output not ideal) class ETLPurchaseOrderTransactionProcessor { /** @var CreatesChatGPTResponse */ @@ -31,19 +33,24 @@ class ETLPurchaseOrderTransactionProcessor /** @var CreatePurchaseOrderTransactionProcessor */ private $createPurchaseOrderTransactionProcessor; + /** @var CreatesClaudeResponse */ + private $createsClaudeResponse; + /** * ETLPurchaseOrderTransactionProcessor constructor. * @param FetchesBooking $fetchesBooking * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor * @param CreatesChatGPTResponse $createsChatGPTResponse + * @param CreatesClaudeResponse $createsClaudeResponse */ - public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, CreatesChatGPTResponse $createsChatGPTResponse) + public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, CreatesChatGPTResponse $createsChatGPTResponse, CreatesClaudeResponse $createsClaudeResponse) { $this->fetchesBooking = $fetchesBooking; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor; $this->createsChatGPTResponse = $createsChatGPTResponse; + $this->createsClaudeResponse = $createsClaudeResponse; } /** @@ -65,7 +72,7 @@ class ETLPurchaseOrderTransactionProcessor // Translate descriptions if they contain Chinese characters $products = collect($products)->map(function ($product) { if (isset($product['description']) && preg_match("/\p{Han}+/u", $product['description'])) { - $kvp = KeyValuePair::where('key', KVPKey::CHATGPT_PROMPT_PREFIX . "TRANSLATE_1")->first(); + $kvp = KeyValuePair::where('key', KVPKey::CLAUDE_PROMPT_PREFIX . "TRANSLATE_1")->first(); $userPrompt = ''; if($kvp){ $templateFromDb = $kvp->value; @@ -76,7 +83,8 @@ class ETLPurchaseOrderTransactionProcessor throw new ResourceNotFoundException('AI Setup incomplete!'); } - $result = $this->createsChatGPTResponse->execute($userPrompt); + // $result = $this->createsChatGPTResponse->execute($userPrompt); + $result = $this->createsClaudeResponse->execute($userPrompt); $content = $result['choices'][0]['message']['content'] ?? null; // 1. Try raw JSON @@ -89,7 +97,7 @@ class ETLPurchaseOrderTransactionProcessor $json = $matches[1]; } else { - Log::warning('No JSON found in ChatGPT response', ['content' => $content]); + Log::warning('No JSON found in AI service response', ['content' => $content]); return; } @@ -103,7 +111,7 @@ class ETLPurchaseOrderTransactionProcessor })->toArray(); if (is_array($productsMetadata) && count($productsMetadata) > 0) { - $kvp = KeyValuePair::where('key', KVPKey::CHATGPT_PROMPT_PREFIX . "EXTRACT_1")->first(); + $kvp = KeyValuePair::where('key', KVPKey::CLAUDE_PROMPT_PREFIX . "EXTRACT_1")->first(); $prompt = ''; if($kvp){ $templateFromDb = $kvp->value; @@ -114,7 +122,8 @@ class ETLPurchaseOrderTransactionProcessor throw new ResourceNotFoundException('AI Setup incomplete!'); } - $result = $this->createsChatGPTResponse->execute($prompt); + // $result = $this->createsChatGPTResponse->execute($prompt); + $result = $this->createsClaudeResponse->execute($prompt); $content = $result['choices'][0]['message']['content'] ?? null; $freight = 0; diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index 644d6283..bc889729 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -29,5 +29,5 @@ class KVPKey public const AUTOCOUNT_DOCNO_SALES_DEPOSIT_BY_WALLET_REFUND = 'AUTOCOUNT_DOCNO_SALES_DEPOSIT_BY_WALLET_RF'; public const CHATGPT_PROMPT_PREFIX = 'CHATGPT_PROMPT_'; - + public const CLAUDE_PROMPT_PREFIX = 'CLAUDE_PROMPT_'; } diff --git a/app/Http/Controllers/KeyValuePairs/CreateClaudePromptKVPController.php b/app/Http/Controllers/KeyValuePairs/CreateClaudePromptKVPController.php new file mode 100644 index 00000000..1b625e28 --- /dev/null +++ b/app/Http/Controllers/KeyValuePairs/CreateClaudePromptKVPController.php @@ -0,0 +1,21 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/KeyValuePairs/DeleteClaudePromptKVPController.php b/app/Http/Controllers/KeyValuePairs/DeleteClaudePromptKVPController.php new file mode 100644 index 00000000..34b34236 --- /dev/null +++ b/app/Http/Controllers/KeyValuePairs/DeleteClaudePromptKVPController.php @@ -0,0 +1,21 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/KeyValuePairs/ListAiPromptsKVPController.php b/app/Http/Controllers/KeyValuePairs/ListAiPromptsKVPController.php new file mode 100644 index 00000000..93b03195 --- /dev/null +++ b/app/Http/Controllers/KeyValuePairs/ListAiPromptsKVPController.php @@ -0,0 +1,21 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/KeyValuePairs/ListChatGPTPromptsKVPController.php b/app/Http/Controllers/KeyValuePairs/ListChatGPTPromptsKVPController.php deleted file mode 100644 index a132550f..00000000 --- a/app/Http/Controllers/KeyValuePairs/ListChatGPTPromptsKVPController.php +++ /dev/null @@ -1,21 +0,0 @@ -execute($request); - } -} diff --git a/app/Http/Controllers/KeyValuePairs/UpdateClaudePromptKVPController.php b/app/Http/Controllers/KeyValuePairs/UpdateClaudePromptKVPController.php new file mode 100644 index 00000000..bbc4691f --- /dev/null +++ b/app/Http/Controllers/KeyValuePairs/UpdateClaudePromptKVPController.php @@ -0,0 +1,21 @@ +execute($request); + } +} diff --git a/app/Http/Resources/ClaudePromptResource.php b/app/Http/Resources/ClaudePromptResource.php new file mode 100644 index 00000000..d95e7533 --- /dev/null +++ b/app/Http/Resources/ClaudePromptResource.php @@ -0,0 +1,26 @@ + $this->id, + 'key' => $this->key, + 'value' => $this->value, + 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'), + ]; + } +} diff --git a/config/anthropic.php b/config/anthropic.php new file mode 100644 index 00000000..19a929de --- /dev/null +++ b/config/anthropic.php @@ -0,0 +1,8 @@ + env('ANTHROPIC_BASE_URL', 'https://api.anthropic.com'), + 'api_key' => env('ANTHROPIC_API_KEY', ''), + 'api_version' => env('ANTHROPIC_API_VERSION', '2023-06-01'), + // 'is_enabled' => env('OPENAI_IS_ENABLED', 'true'), +]; diff --git a/config/openai.php b/config/openai.php index 027f5a11..a506c68a 100644 --- a/config/openai.php +++ b/config/openai.php @@ -3,5 +3,5 @@ return [ 'base_url' => env('OPENAI_BASE_URL', 'https://api.openai.com'), 'api_key' => env('OPENAI_API_KEY', ''), - 'is_enabled' => env('OPENAI_IS_ENABLED', 'true'), + // 'is_enabled' => env('OPENAI_IS_ENABLED', 'true'), ]; diff --git a/resources/assets/vue/components/settings/elements/SingleChatGptPromptComponent.vue b/resources/assets/vue/components/settings/elements/SinglePromptComponent.vue similarity index 61% rename from resources/assets/vue/components/settings/elements/SingleChatGptPromptComponent.vue rename to resources/assets/vue/components/settings/elements/SinglePromptComponent.vue index 76ee4931..bbcc93f0 100644 --- a/resources/assets/vue/components/settings/elements/SingleChatGptPromptComponent.vue +++ b/resources/assets/vue/components/settings/elements/SinglePromptComponent.vue @@ -38,7 +38,7 @@ -
+
- + - + + +
+
+
+ +
+ + + + + +
diff --git a/resources/assets/vue/components/settings/forms/AiPromptFormComponent.vue b/resources/assets/vue/components/settings/forms/AiPromptFormComponent.vue new file mode 100644 index 00000000..69706f8b --- /dev/null +++ b/resources/assets/vue/components/settings/forms/AiPromptFormComponent.vue @@ -0,0 +1,143 @@ + + diff --git a/resources/assets/vue/components/settings/forms/ChatGptFormComponent.vue b/resources/assets/vue/components/settings/forms/ChatGptFormComponent.vue deleted file mode 100644 index fcb347db..00000000 --- a/resources/assets/vue/components/settings/forms/ChatGptFormComponent.vue +++ /dev/null @@ -1,83 +0,0 @@ - - diff --git a/resources/assets/vue/components/settings/forms/DeleteChatGptFormComponent.vue b/resources/assets/vue/components/settings/forms/DeleteChatGptFormComponent.vue index bb74e9ff..92f7e979 100644 --- a/resources/assets/vue/components/settings/forms/DeleteChatGptFormComponent.vue +++ b/resources/assets/vue/components/settings/forms/DeleteChatGptFormComponent.vue @@ -15,7 +15,7 @@
Cancel
-
Delete
+
Delete
diff --git a/resources/assets/vue/components/settings/forms/DeleteClaudeFormComponent.vue b/resources/assets/vue/components/settings/forms/DeleteClaudeFormComponent.vue new file mode 100644 index 00000000..b836fe93 --- /dev/null +++ b/resources/assets/vue/components/settings/forms/DeleteClaudeFormComponent.vue @@ -0,0 +1,32 @@ + + diff --git a/resources/views/pages/settings.blade.php b/resources/views/pages/settings.blade.php index cee897e7..3cd6ee99 100644 --- a/resources/views/pages/settings.blade.php +++ b/resources/views/pages/settings.blade.php @@ -687,26 +687,26 @@
- ChatGPT Prompts + AI Prompts
- +
- +
diff --git a/routes/key_value_pair.php b/routes/key_value_pair.php index a0da677d..277f7b30 100644 --- a/routes/key_value_pair.php +++ b/routes/key_value_pair.php @@ -1,14 +1,22 @@ 'kvp', 'as' => 'kvp.', 'namespace' => 'KeyValuePairs'], function () { - Route::get('/prompts/list', [ListChatGPTPromptsKVPController::class, 'list'])->name('prompts.list'); - Route::put('/prompt/update/{id}', [UpdateChatGPTPromptKVPController::class, 'update'])->name('prompt.update'); - Route::post('/prompt/create', [CreateChatGPTPromptKVPController::class, 'create'])->name('prompt.create'); - Route::delete('/prompt/delete/{id}', [DeleteChatGPTPromptKVPController::class, 'delete'])->name('prompt.delete'); + Route::get('/prompts/list', [ListAiPromptsKVPController::class, 'list'])->name('prompts.list'); + + Route::put('/chatgpt/prompt/update/{id}', [UpdateChatGPTPromptKVPController::class, 'update'])->name('chatgpt.prompt.update'); + Route::post('/chatgpt/prompt/create', [CreateChatGPTPromptKVPController::class, 'create'])->name('chatgpt.prompt.create'); + Route::delete('/chatgpt/prompt/delete/{id}', [DeleteChatGPTPromptKVPController::class, 'delete'])->name('chatgpt.prompt.delete'); + + Route::put('/claude/prompt/update/{id}', [UpdateClaudePromptKVPController::class, 'update'])->name('claude.prompt.update'); + Route::post('/claude/prompt/create', [CreateClaudePromptKVPController::class, 'create'])->name('claude.prompt.create'); + Route::delete('/claude/prompt/delete/{id}', [DeleteClaudePromptKVPController::class, 'delete'])->name('claude.prompt.delete'); });