Add AI photo import via Ollama Vision

Users can upload a photo of a nail polish bottle; a background queue
job sends it to Ollama (llama3.2-vision at 192.168.30.172:11434),
extracts name, number and manufacturer, then creates the nail polish
and adds it to the user's collection automatically.

- ProcessNailPolishImage job (180s timeout, 2 tries)
- NailPolishImport model + migration (status tracking)
- AiSetting model + migration (Ollama URL + model, admin-configurable)
- NailPolishImportController: upload, status page (auto-refresh every 5s)
- Admin\AiSettingController: configure Ollama connection
- Views: drag-drop upload form, live status page, import history
- Navbar: "Foto importieren" link for all users
- Admin dropdown: "KI-Einstellungen"
- neonail-worker.conf: Supervisor config for the queue worker

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Housemann
2026-06-13 17:37:26 +02:00
co-authored by Claude Sonnet 4.6
parent 7a24e554b0
commit f715bc4552
15 changed files with 738 additions and 0 deletions
@@ -0,0 +1,27 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('nail_polish_imports', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->cascadeOnDelete();
$table->string('image_path');
$table->enum('status', ['pending', 'processing', 'done', 'failed'])->default('pending');
$table->json('result')->nullable();
$table->foreignId('nail_polish_id')->nullable()->constrained('nail_polishes')->nullOnDelete();
$table->text('error_message')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('nail_polish_imports');
}
};
@@ -0,0 +1,30 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('ai_settings', function (Blueprint $table) {
$table->id();
$table->string('ollama_url')->default('http://192.168.30.172:11434');
$table->string('ollama_model')->default('llama3.2-vision');
$table->timestamps();
});
DB::table('ai_settings')->insert([
'ollama_url' => 'http://192.168.30.172:11434',
'ollama_model' => 'llama3.2-vision',
'created_at' => now(),
'updated_at' => now(),
]);
}
public function down(): void
{
Schema::dropIfExists('ai_settings');
}
};