From 381824183c2f63794a9380f6c3daa3fba27d5f76 Mon Sep 17 00:00:00 2001 From: Julien Nahum Date: Mon, 29 Jan 2024 10:25:00 +0100 Subject: [PATCH] Fix form AI creation bug + use gpt4 turbo with Json mode --- app/Console/Commands/GenerateTemplate.php | 9 ++++--- app/Jobs/Form/GenerateAiForm.php | 3 ++- app/Service/OpenAi/GptCompleter.php | 26 +++++++++++++++++-- .../open/forms/components/FormEditor.vue | 9 ++----- client/composables/useCrisp.js | 2 +- 5 files changed, 35 insertions(+), 14 deletions(-) diff --git a/app/Console/Commands/GenerateTemplate.php b/app/Console/Commands/GenerateTemplate.php index 193f2ce..1ceca00 100644 --- a/app/Console/Commands/GenerateTemplate.php +++ b/app/Console/Commands/GenerateTemplate.php @@ -227,11 +227,12 @@ class GenerateTemplate extends Command ->setAiModel('gpt-3.5-turbo-16k') ->useStreaming() ->setSystemMessage('You are an assistant helping to generate forms.'); - $completer->completeChat([ + $completer->expectsJson()->completeChat([ ["role" => "user", "content" => Str::of(self::FORM_STRUCTURE_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()] ], 6000); $formData = $completer->getArray(); + $completer->doesNotExpectJson(); $formDescriptionPrompt = Str::of(self::FORM_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString(); $formShortDescription = $completer->completeChat([ ["role" => "user", "content" => Str::of(self::FORM_SHORT_DESCRIPTION_PROMPT)->replace('[REPLACE]', $this->argument('prompt'))->toString()] @@ -240,6 +241,7 @@ class GenerateTemplate extends Command $formShortDescription = Str::of($formShortDescription)->replaceMatches('/^"(.*)"$/', '$1')->toString(); // Get industry & types + $completer->expectsJson(); $industry = $this->getIndustries($completer, $this->argument('prompt')); $types = $this->getTypes($completer, $this->argument('prompt')); @@ -247,10 +249,12 @@ class GenerateTemplate extends Command $relatedTemplates = $this->getRelatedTemplates($industry, $types); // Now get description and QAs + $completer->doesNotExpectJson(); $formDescription = $completer->completeChat([ ["role" => "user", "content" => $formDescriptionPrompt] ])->getHtml(); + $completer->expectsJson(); $formCoverKeywords = $completer->completeChat([ ["role" => "user", "content" => $formDescriptionPrompt], ["role" => "assistant", "content" => $formDescription], @@ -263,6 +267,7 @@ class GenerateTemplate extends Command ["role" => "assistant", "content" => $formDescription], ["role" => "user", "content" => self::FORM_QAS_PROMPT] ])->getArray(); + $completer->doesNotExpectJson(); $formTitle = $completer->completeChat([ ["role" => "user", "content" => $formDescriptionPrompt], ["role" => "assistant", "content" => $formDescription], @@ -306,7 +311,6 @@ class GenerateTemplate extends Command private function getIndustries(GptCompleter $completer, string $formPrompt): array { $industriesString = Template::getAllIndustries()->pluck('slug')->join(', '); - return $completer->completeChat([ ["role" => "user", "content" => Str::of(self::FORM_INDUSTRY_PROMPT) ->replace('[REPLACE]', $formPrompt) @@ -318,7 +322,6 @@ class GenerateTemplate extends Command private function getTypes(GptCompleter $completer, string $formPrompt): array { $typesString = Template::getAllTypes()->pluck('slug')->join(', '); - return $completer->completeChat([ ["role" => "user", "content" => Str::of(self::FORM_TYPES_PROMPT) ->replace('[REPLACE]', $formPrompt) diff --git a/app/Jobs/Form/GenerateAiForm.php b/app/Jobs/Form/GenerateAiForm.php index 86125f4..e9a745c 100644 --- a/app/Jobs/Form/GenerateAiForm.php +++ b/app/Jobs/Form/GenerateAiForm.php @@ -39,7 +39,8 @@ class GenerateAiForm implements ShouldQueue $completer = (new GptCompleter(config('services.openai.api_key'))) ->useStreaming() - ->setSystemMessage('You are a robot helping to generate forms.'); + ->setSystemMessage('You are a robot helping to generate forms.') + ->expectsJson(); try { $completer->completeChat([ diff --git a/app/Service/OpenAi/GptCompleter.php b/app/Service/OpenAi/GptCompleter.php index b15bfb1..ad4f1ad 100644 --- a/app/Service/OpenAi/GptCompleter.php +++ b/app/Service/OpenAi/GptCompleter.php @@ -14,13 +14,14 @@ use OpenAI\Exceptions\ErrorException; */ class GptCompleter { - const AI_MODEL = 'gpt-4'; + const AI_MODEL = 'gpt-4-turbo-preview'; protected Client $openAi; protected mixed $result; protected array $completionInput; protected ?string $systemMessage; + protected bool $expectsJson = false; protected int $tokenUsed = 0; protected bool $useStreaming = false; @@ -47,8 +48,23 @@ class GptCompleter return $this; } - public function completeChat(array $messages, int $maxTokens = 4096, float $temperature = 0.81): self + public function expectsJson(): self { + $this->expectsJson = true; + return $this; + } + + public function doesNotExpectJson(): self + { + $this->expectsJson = false; + return $this; + } + + public function completeChat(array $messages, int $maxTokens = 4096, float $temperature = 0.81, ?bool $exceptJson = null): self + { + if (!is_null($exceptJson)) { + $this->expectsJson = $exceptJson; + } $this->computeChatCompletion($messages, $maxTokens, $temperature) ->queryCompletion(); @@ -129,6 +145,12 @@ class GptCompleter 'temperature' => $temperature ]; + if ($this->expectsJson) { + $completionInput['response_format'] = [ + 'type' => 'json_object' + ]; + } + $this->completionInput = $completionInput; return $this; } diff --git a/client/components/open/forms/components/FormEditor.vue b/client/components/open/forms/components/FormEditor.vue index 84ee158..3b59848 100644 --- a/client/components/open/forms/components/FormEditor.vue +++ b/client/components/open/forms/components/FormEditor.vue @@ -280,14 +280,9 @@ export default { form_slug: response.form.slug }) this.displayFormModificationAlert(response) - useRouter().push({ - name: 'forms-show', - params: { - slug: this.createdForm.slug, - new_form: response.users_first_form - } - }) + useRouter().push({ name: 'forms-slug-show-share', params: { slug: this.createdFormSlug, new_form: response.users_first_form } }) }).catch((error) => { + console.error(error) if (error.response && error.response.status === 422) { this.validationErrorResponse = error.response this.showValidationErrors() diff --git a/client/composables/useCrisp.js b/client/composables/useCrisp.js index 47ac053..90244e4 100644 --- a/client/composables/useCrisp.js +++ b/client/composables/useCrisp.js @@ -64,7 +64,7 @@ export const useCrisp = () => { function pushEvent(event, data = {}) { if (!crisp) return - crisp.pushEvent(event, data) + crisp.session.pushEvent(event, data) } function setSegments(segments, overwrite = false) {