Build an AI-Powered Todo List with Laravel 11, Livewire 3, and OpenAI
Learn how to create a dynamic, AI-enhanced Todo List application using Laravel 11, Livewire 3, and OpenAI. Perfect for beginners and intermediate developers looking to integrate AI into web applications.
Hey there, future AI-powered web developers! 👋 Today, we’re going to take our Laravel and Livewire skills to the next level by integrating OpenAI’s powerful language model into our Todo List application. We’ll create a smart todo list that can understand natural language, suggest task improvements, and even generate new tasks based on your existing ones. Excited? Let’s dive in!
Prerequisites
Before we start, make sure you have:
- PHP 8.2 or higher installed
- Composer installed
- Node.js and NPM installed
- Basic knowledge of Laravel and Livewire
- An OpenAI API key (sign up at https://openai.com/ if you haven’t already)
Step 1: Setting Up the Project
Let’s start by creating a new Laravel project and installing Livewire:
composer create-project laravel/laravel ai-todo-list
cd ai-todo-list
composer require livewire/livewire
Next, let’s install the OpenAI PHP client:
composer require openai-php/client
Step 2: Configure OpenAI API Key
Add your OpenAI API key to the .env
file:
OPENAI_API_KEY=your_api_key_here
Step 3: Create the Task Model and Migration
Let’s create our Task model and migration:
php artisan make:model Task -m
Edit the migration file (database/migrations/xxxx_xx_xx_create_tasks_table.php
):
public function up()
{
Schema::create('tasks', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('description')->nullable();
$table->boolean('is_completed')->default(false);
$table->timestamps();
});
}
Run the migration:
php artisan migrate
Step 4: Create the Livewire Component
Create a Livewire component for our AI-enhanced Todo list:
php artisan make:livewire AiTodoList
Edit the app/Http/Livewire/AiTodoList.php
file:
<?php
namespace App\Http\Livewire;use Livewire\Component;
use App\Models\Task;
use OpenAI\Client;class AiTodoList extends Component
{
public $tasks;
public $newTaskTitle = '';
public $newTaskDescription = '';
public $editingTaskId;
public $editingTaskTitle;
public $editingTaskDescription;
public $aiSuggestion = ''; protected $rules = [
'newTaskTitle' => 'required|min:3',
'newTaskDescription' => 'nullable',
]; public function mount()
{
$this->tasks = Task::all();
} public function render()
{
return view('livewire.ai-todo-list');
} public function addTask()
{
$this->validate(); Task::create([
'title' => $this->newTaskTitle,
'description' => $this->newTaskDescription,
]); $this->newTaskTitle = '';
$this->newTaskDescription = '';
$this->tasks = Task::all();
} public function toggleComplete($taskId)
{
$task = Task::find($taskId);
$task->is_completed = !$task->is_completed;
$task->save(); $this->tasks = Task::all();
} public function editTask($taskId)
{
$this->editingTaskId = $taskId;
$task = Task::find($taskId);
$this->editingTaskTitle = $task->title;
$this->editingTaskDescription = $task->description;
} public function updateTask()
{
$this->validate([
'editingTaskTitle' => 'required|min:3',
'editingTaskDescription' => 'nullable',
]); $task = Task::find($this->editingTaskId);
$task->title = $this->editingTaskTitle;
$task->description = $this->editingTaskDescription;
$task->save(); $this->editingTaskId = null;
$this->tasks = Task::all();
} public function deleteTask($taskId)
{
Task::destroy($taskId);
$this->tasks = Task::all();
} public function getAiSuggestion()
{
$client = OpenAI::client(env('OPENAI_API_KEY')); $existingTasks = $this->tasks->pluck('title')->implode(', '); $response = $client->chat()->create([
'model' => 'gpt-3.5-turbo',
'messages' => [
['role' => 'system', 'content' => 'You are a helpful assistant that suggests tasks based on existing ones.'],
['role' => 'user', 'content' => "Based on these existing tasks: $existingTasks, suggest a new relevant task."],
],
]); $this->aiSuggestion = $response->choices[0]->message->content;
} public function improveTaskDescription($taskId)
{
$task = Task::find($taskId);
$client = OpenAI::client(env('OPENAI_API_KEY')); $response = $client->chat()->create([
'model' => 'gpt-3.5-turbo',
'messages' => [
['role' => 'system', 'content' => 'You are a helpful assistant that improves task descriptions.'],
['role' => 'user', 'content' => "Improve this task description: {$task->description}"],
],
]); $task->description = $response->choices[0]->message->content;
$task->save(); $this->tasks = Task::all();
}
}
Step 5: Create the Livewire Component View
Edit the resources/views/livewire/ai-todo-list.blade.php
file:
<div>
<h1 class="text-3xl font-bold mb-4">AI-Enhanced Todo List</h1>
<form wire:submit.prevent="addTask" class="mb-4">
<input type="text" wire:model="newTaskTitle" placeholder="Add a new task" class="border p-2 mr-2">
<textarea wire:model="newTaskDescription" placeholder="Task description (optional)" class="border p-2 mr-2"></textarea>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded">Add</button>
</form> <button wire:click="getAiSuggestion" class="bg-green-500 text-white px-4 py-2 rounded mb-4">Get AI Suggestion</button> @if($aiSuggestion)
<div class="bg-yellow-100 p-4 mb-4 rounded">
<h3 class="font-bold">AI Suggestion:</h3>
<p>{{ $aiSuggestion }}</p>
</div>
@endif <ul>
@foreach($tasks as $task)
<li class="mb-4 p-4 border rounded">
@if($editingTaskId === $task->id)
<input type="text" wire:model="editingTaskTitle" class="border p-2 mb-2 w-full">
<textarea wire:model="editingTaskDescription" class="border p-2 mb-2 w-full"></textarea>
<button wire:click="updateTask" class="bg-blue-500 text-white px-4 py-2 rounded mr-2">Save</button>
@else
<h3 class="font-bold {{ $task->is_completed ? 'line-through' : '' }}">{{ $task->title }}</h3>
<p>{{ $task->description }}</p>
<div class="mt-2">
<button wire:click="toggleComplete({{ $task->id }})" class="bg-green-500 text-white px-4 py-2 rounded mr-2">
{{ $task->is_completed ? 'Undo' : 'Complete' }}
</button>
<button wire:click="editTask({{ $task->id }})" class="bg-yellow-500 text-white px-4 py-2 rounded mr-2">Edit</button>
<button wire:click="deleteTask({{ $task->id }})" class="bg-red-500 text-white px-4 py-2 rounded mr-2">Delete</button>
<button wire:click="improveTaskDescription({{ $task->id }})" class="bg-purple-500 text-white px-4 py-2 rounded">Improve Description</button>
</div>
@endif
</li>
@endforeach
</ul>
</div>
Step 6: Update the Route
Edit the routes/web.php
file to use our new Livewire component:
use App\Http\Livewire\AiTodoList;
Route::get('/', AiTodoList::class);
Step 7: Add Tailwind CSS (Optional)
For better styling, let’s add Tailwind CSS:
npm install -D tailwindcss@latest postcss@latest autoprefixer@latest
npx tailwindcss init -p
Update the tailwind.config.js
file:
module.exports = {
content: [
"./resources/**/*.blade.php",
"./resources/**/*.js",
"./resources/**/*.vue",
],
theme: {
extend: {},
},
plugins: [],
}
Create a new CSS file at resources/css/app.css
:
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import 'tailwindcss/utilities';
Update your resources/views/welcome.blade.php
to include the compiled CSS:
<!DOCTYPE html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>AI-Enhanced Todo List</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet">
@livewireStyles
</head>
<body class="antialiased">
<div class="container mx-auto mt-8">
@livewire('ai-todo-list')
</div>
@livewireScripts
</body>
</html>
Compile the assets:
npm run dev
Conclusion
Congratulations! You’ve just built an AI-enhanced Todo List application using Laravel 11, Livewire 3, and OpenAI. This app demonstrates how to:
- Create, read, update, and delete tasks using Livewire
- Use OpenAI to generate task suggestions based on existing tasks
- Improve task descriptions using AI
This is just the beginning of what you can do with AI in web applications. You could expand this further by:
- Using AI to categorize tasks automatically
- Generating entire task lists based on a project description
- Analyzing task completion patterns and suggesting productivity improvements
Remember, when working with AI, always review the generated content to ensure it meets your needs and standards. Happy coding, and enjoy your new AI-powered productivity tool! 🚀🤖📝