Beartropy Logo

Beyond Chatbots: Building a 'Magic Rewriter' using the Beartropy Chat Input

Repurposing UI components is a superpower. Learn how to use the Beartropy Chat Input to create an AI-powered 'Magic Rewrite' field for your forms.

Guides 12 Jan, 2026 Beartropy Team

Adding a chat bubble to the bottom right of your screen is easy. But truly integrating AI means making it invisible. It means helping your users do their job faster without them realizing they are talking to a robot.

Today, we are going to build a 'Magic Rewriter'.

We will take the versatile x-bt-chat-input component—normally used for chat apps—and repurpose it as a supercharged text field for your forms. By injecting an AI action into its slots, we create a seamless "Draft-to-Professional" workflow.


🧠 Phase 1: The AI Service

First, we need a robust service to handle communication with the LLM. We don't want OpenAI code scattered inside our Livewire components.

Create app/Services/AiEditor.php. We will use Laravel's native HTTP client.

1namespace App\Services;
2 
3use Illuminate\Support\Facades\Http;
4use Illuminate\Support\Facades\Log;
5 
6class AiEditor
7{
8 public function refine(string $text, string $tone = 'professional'): string
9 {
10 if (empty($text)) return '';
11 
12 $prompt = match ($tone) {
13 'casual' => "Rewrite the following text to be friendly, engaging, and concise.",
14 'sales' => "Rewrite the following text to be persuasive, action-oriented, and exciting.",
15 default => "Rewrite the following text to be professional, clear, and grammatically correct.",
16 };
17 
18 try {
19 $response = Http::withToken(config('services.openai.api_key'))
20 ->timeout(15)
21 ->post('[https://api.openai.com/v1/chat/completions](https://api.openai.com/v1/chat/completions)', [
22 'model' => 'gpt-4o',
23 'messages' => [
24 ['role' => 'system', 'content' => "You are an expert copyeditor. {$prompt} Only output the rewritten text, no explanations."],
25 ['role' => 'user', 'content' => $text],
26 ],
27 'temperature' => 0.7,
28 ]);
29 
30 return $response->json('choices.0.message.content') ?? $text;
31 
32 } catch (\Exception $e) {
33 Log::error('AI Error: ' . $e->getMessage());
34 return $text; // Fallback: return original text on failure
35 }
36 }
37}

🔌 Phase 2: The Reusable Trait

We want to add this magic to any component (ProductCreate, UserProfile, PostEdit) without duplicating code. Let's create a Trait.

Create app/Traits/WithAiAssistance.php:

1namespace App\Traits;
2 
3use App\Services\AiEditor;
4use Livewire\Attributes\Renderless;
5 
6trait WithAiAssistance
7{
8 #[Renderless]
9 public function refineText(string $property, string $tone = 'professional')
10 {
11 // Security: Ensure the property exists to prevent injection
12 if (!property_exists($this, $property)) {
13 return;
14 }
15 
16 $currentText = $this->{$property};
17 
18 // Call the service
19 $refined = app(AiEditor::class)->refine($currentText, $tone);
20 
21 // Update the Livewire property with the polished version
22 $this->{$property} = str_replace('"', '', $refined);
23 
24 $this->dispatch('notify', [
25 'type' => 'success',
26 'message' => 'Text improved successfully!'
27 ]);
28 }
29}

🎨 Phase 3: The UI (Repurposing x-bt-chat-input)

Here is the trick. The x-bt-chat-input is perfect because it already has a slot for actions (suffix or actions) and handles auto-growing text height.

Instead of a "Send" button, we will place our "Magic Wand" button inside the input group.

1<form wire:submit="save" class="space-y-6 max-w-2xl mx-auto">
2 
3 <x-bt-input label="Product Name" wire:model="name" />
4 
5 
6 <div class="space-y-2">
7 <label class="text-sm font-medium text-gray-700">Product Description</label>
8 
9 <x-bt-chat-input
10 wire:model="description"
11 placeholder="Jot down a rough draft... AI will fix it."
12 rows="4"
13 >
14 
15 <x-slot:actions>
16 <div class="flex items-center gap-2">
17 
18 
19 <select
20 x-data="{ tone: 'sales' }"
21 x-model="tone"
22 @change="$wire.set('tone', tone)"
23 class="text-xs border-none bg-gray-50 rounded text-gray-500 focus:ring-0 cursor-pointer"
24 >
25 <option value="professional">Professional</option>
26 <option value="sales">Sales</option>
27 <option value="casual">Casual</option>
28 </select>
29 
30 
31 <button
32 type="button"
33 wire:click="refineText('description', $refs.toneSelector?.value ?? 'sales')"
34 wire:loading.attr="disabled"
35 wire:target="refineText"
36 class="p-2 text-purple-600 hover:bg-purple-50 rounded-full transition-colors relative group"
37 title="Rewrite with AI"
38 >
39 
40 <svg wire:loading.remove wire:target="refineText" class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
41 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z" />
42 </svg>
43 
44 
45 <svg wire:loading wire:target="refineText" class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24">
46 <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
47 <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"></path>
48 </svg>
49 </button>
50 </div>
51 </x-slot:actions>
52 </x-bt-chat-input>
53 
54 <p class="text-xs text-gray-500">
55 Tip: Write fast, click the sparkles, and watch the magic happen.
56 </p>
57 </div>
58 
59 <div class="flex justify-end pt-4">
60 <x-bt-button type="submit" primary>Save Product</x-bt-button>
61 </div>
62</form>

Why x-bt-chat-input works better here

  1. Cleaner UI: No need for complex CSS positioning. The component manages the button layout for us.
  2. Interactive Feel: It frames the input as a dynamic area, encouraging the user to "interact" with the field rather than just filling it out.
  3. Extensible: The <x-slot:actions> allows us to add not just the AI button, but also tone selectors or file attachments easily.

Stop building static forms. Start building intelligent interfaces.

Tags

#ai #openai #laravel #livewire #ux #beartropy #chat-input

Comments

Leave a comment

0

No comments yet. Be the first to share your thoughts!

Share this post