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>
116 lines
4.5 KiB
PHP
116 lines
4.5 KiB
PHP
@extends('layouts.app')
|
||
|
||
@section('title', 'Import-Status – NeoNail DB')
|
||
|
||
@php $pending = $import->isPending(); @endphp
|
||
|
||
@if($pending)
|
||
<meta http-equiv="refresh" content="5">
|
||
@endif
|
||
|
||
@section('content')
|
||
|
||
<div class="page-hero mb-4">
|
||
<h1><i class="fas fa-magic me-2"></i>KI-Analyse</h1>
|
||
<p>
|
||
<span class="badge bg-{{ $import->statusColor() }} fs-6">
|
||
{{ $import->statusLabel() }}
|
||
</span>
|
||
</p>
|
||
</div>
|
||
|
||
<div class="row g-4 justify-content-center">
|
||
|
||
{{-- Bild --}}
|
||
<div class="col-md-4">
|
||
<div class="card">
|
||
<div class="card-body p-3 text-center">
|
||
<img src="{{ Storage::url($import->image_path) }}"
|
||
alt="Importiertes Bild"
|
||
style="max-width:100%; border-radius:12px; max-height:320px; object-fit:contain;">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
{{-- Status / Ergebnis --}}
|
||
<div class="col-md-6">
|
||
<div class="card">
|
||
<div class="card-header">
|
||
@if($pending)
|
||
<i class="fas fa-spinner fa-spin me-2"></i>KI analysiert das Bild…
|
||
@elseif($import->status === 'done')
|
||
<i class="fas fa-check-circle text-success me-2"></i>Ergebnis
|
||
@else
|
||
<i class="fas fa-exclamation-circle text-danger me-2"></i>Fehler
|
||
@endif
|
||
</div>
|
||
<div class="card-body p-4">
|
||
|
||
@if($pending)
|
||
<p style="color:#6b7280;">
|
||
Ollama verarbeitet das Bild gerade. Diese Seite aktualisiert sich automatisch alle 5 Sekunden.
|
||
</p>
|
||
<div class="progress" style="height:6px; border-radius:3px;">
|
||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||
style="width:100%; background: linear-gradient(135deg,#7c3aed,#ec4899);"></div>
|
||
</div>
|
||
|
||
@elseif($import->status === 'done')
|
||
@php $result = $import->result; @endphp
|
||
<table class="table table-borderless mb-0">
|
||
<tr>
|
||
<th style="width:130px; color:#6b7280; font-size:.85rem;">Name</th>
|
||
<td style="font-weight:600;">{{ $result['name'] ?? '—' }}</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="color:#6b7280; font-size:.85rem;">Nummer</th>
|
||
<td>{{ $result['number'] ?? '—' }}</td>
|
||
</tr>
|
||
<tr>
|
||
<th style="color:#6b7280; font-size:.85rem;">Hersteller</th>
|
||
<td>{{ $result['manufacturer'] ?? '—' }}</td>
|
||
</tr>
|
||
@if($import->nailPolish)
|
||
<tr>
|
||
<th style="color:#6b7280; font-size:.85rem;">In Sammlung</th>
|
||
<td>
|
||
<span class="badge" style="background:linear-gradient(135deg,#7c3aed,#ec4899);">
|
||
<i class="fas fa-check me-1"></i>Hinzugefügt
|
||
</span>
|
||
</td>
|
||
</tr>
|
||
@endif
|
||
</table>
|
||
|
||
@if($import->nailPolish)
|
||
<div class="mt-3">
|
||
<a href="{{ route('user-nail-polishes.index') }}" class="btn btn-primary btn-sm">
|
||
<i class="fas fa-home me-1"></i>Zur Sammlung
|
||
</a>
|
||
</div>
|
||
@endif
|
||
|
||
@else
|
||
<div class="alert alert-danger mb-3">
|
||
<i class="fas fa-exclamation-circle me-2"></i>
|
||
{{ $import->error_message ?? 'Unbekannter Fehler' }}
|
||
</div>
|
||
<a href="{{ route('nail-polish-imports.create') }}" class="btn btn-primary btn-sm">
|
||
<i class="fas fa-redo me-1"></i>Nochmal versuchen
|
||
</a>
|
||
@endif
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<div class="mt-3">
|
||
<a href="{{ route('nail-polish-imports.index') }}" style="color:rgba(255,255,255,.65); font-size:.85rem;">
|
||
<i class="fas fa-arrow-left me-1"></i>Alle Importe
|
||
</a>
|
||
</div>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
@endsection
|